chain-insights 0.22.2 → 0.22.3
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 +8 -7
- package/dist/{app-l9JE6bt3.cjs → app-BHRl5oDo.cjs} +1 -1
- package/dist/{app-7NRCqx_Q.mjs → app-BeZyCVuz.mjs} +2 -2
- package/dist/{app-7NRCqx_Q.mjs.map → app-BeZyCVuz.mjs.map} +1 -1
- package/dist/{artifact-server-CH-asxF5.cjs → artifact-server-B8WKXtXr.cjs} +1 -1
- package/dist/{artifact-server-DoxJr0z8.mjs → artifact-server-C1fETWsc.mjs} +2 -2
- package/dist/{artifact-server-DoxJr0z8.mjs.map → artifact-server-C1fETWsc.mjs.map} +1 -1
- package/dist/cli.cjs +19 -19
- package/dist/cli.mjs +19 -19
- package/dist/{config-BVFf3v8-.cjs → config-DYiUgdzg.cjs} +2 -2
- package/dist/{config-CnNMdt4M.mjs → config-DiQs0rQX.mjs} +3 -3
- package/dist/{config-CnNMdt4M.mjs.map → config-DiQs0rQX.mjs.map} +1 -1
- package/dist/index.cjs +3 -3
- package/dist/index.mjs +3 -3
- package/dist/{init-DvrKxK15.cjs → init-C3AVZHFb.cjs} +2 -2
- package/dist/{init-Djhml4ih.mjs → init-CO-PRYhT.mjs} +3 -3
- package/dist/init-CO-PRYhT.mjs.map +1 -0
- package/dist/{mcp-endpoint-DbWtLcba.mjs → mcp-endpoint-Bd3SvCkg.mjs} +3 -3
- package/dist/mcp-endpoint-Bd3SvCkg.mjs.map +1 -0
- package/dist/{mcp-endpoint-BIWrUOFG.cjs → mcp-endpoint-DdIVQKW5.cjs} +3 -3
- package/dist/mcp-proxy.cjs +3 -3
- package/dist/mcp-proxy.mjs +3 -3
- package/dist/{schema-BpeV3xDV.cjs → schema-DepyuUEP.cjs} +2 -2
- package/dist/{schema-DOJA2nNi.mjs → schema-v5cwychf.mjs} +3 -3
- package/dist/schema-v5cwychf.mjs.map +1 -0
- package/dist/{server-mDSRgk1X.mjs → server-BDmHAF1w.mjs} +2 -2
- package/dist/{server-mDSRgk1X.mjs.map → server-BDmHAF1w.mjs.map} +1 -1
- package/dist/{server-CmvzYu7v.cjs → server-BjprY9Ef.cjs} +1 -1
- package/docs/architecture.md +3 -2
- package/docs/mcp-proxy.md +7 -9
- package/package.json +1 -1
- package/dist/init-Djhml4ih.mjs.map +0 -1
- package/dist/mcp-endpoint-DbWtLcba.mjs.map +0 -1
- package/dist/schema-DOJA2nNi.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -80,8 +80,8 @@ Never touches:
|
|
|
80
80
|
Upstream:
|
|
81
81
|
|
|
82
82
|
- **Chain Insights Graph MCP endpoint** — all graph queries and AML
|
|
83
|
-
primitives. Configured via `graphMcpEndpoint`; defaults to
|
|
84
|
-
endpoint.
|
|
83
|
+
primitives. Configured via `graphMcpEndpoint`; defaults to the public
|
|
84
|
+
production endpoint `https://mcp.chain-insights.ai/`.
|
|
85
85
|
- **Base mainnet RPC** — wallet balance and payment only
|
|
86
86
|
(`BASE_RPC_URL` override). Not a graph-support claim.
|
|
87
87
|
|
|
@@ -253,16 +253,17 @@ More query examples (manual fund-flow reads, pagination):
|
|
|
253
253
|
## Configure
|
|
254
254
|
|
|
255
255
|
`cia` uses `graphMcpEndpoint` for all Chain Insights Graph calls. The npm
|
|
256
|
-
package
|
|
256
|
+
package uses the public production endpoint by default, so a fresh install can
|
|
257
|
+
run `cia networks` immediately.
|
|
257
258
|
|
|
258
|
-
|
|
259
|
+
For local development, override the default explicitly:
|
|
259
260
|
|
|
260
261
|
```bash
|
|
261
262
|
cia config set graphMcpEndpoint http://127.0.0.1:8012/mcp
|
|
262
263
|
```
|
|
263
264
|
|
|
264
|
-
|
|
265
|
-
|
|
265
|
+
The public production Graph is already the default. Use the host root. Do not
|
|
266
|
+
add `/mcp`.
|
|
266
267
|
|
|
267
268
|
```bash
|
|
268
269
|
cia config set graphMcpEndpoint https://mcp.chain-insights.ai/
|
|
@@ -279,7 +280,7 @@ Configuration precedence:
|
|
|
279
280
|
1. `CHAIN_INSIGHTS_GRAPH_MCP_ENDPOINT` env var (`GRAPH_MCP_ENDPOINT`
|
|
280
281
|
legacy alias also supported).
|
|
281
282
|
2. `cia config set graphMcpEndpoint ...` saved value.
|
|
282
|
-
3.
|
|
283
|
+
3. Public production default `https://mcp.chain-insights.ai/`.
|
|
283
284
|
|
|
284
285
|
Validation rules:
|
|
285
286
|
|
|
@@ -84,7 +84,7 @@ function createApp() {
|
|
|
84
84
|
ts: Date.now()
|
|
85
85
|
}));
|
|
86
86
|
app.get("/status", async (c) => {
|
|
87
|
-
const { loadConfig } = await Promise.resolve().then(() => require("./config-
|
|
87
|
+
const { loadConfig } = await Promise.resolve().then(() => require("./config-DYiUgdzg.cjs")).then((n) => n.config_exports);
|
|
88
88
|
const config = await loadConfig();
|
|
89
89
|
return c.json({
|
|
90
90
|
dataDir: config.dataDir,
|
|
@@ -82,7 +82,7 @@ function createApp() {
|
|
|
82
82
|
ts: Date.now()
|
|
83
83
|
}));
|
|
84
84
|
app.get("/status", async (c) => {
|
|
85
|
-
const { loadConfig } = await import("./config-
|
|
85
|
+
const { loadConfig } = await import("./config-DiQs0rQX.mjs").then((n) => n.t);
|
|
86
86
|
const config = await loadConfig();
|
|
87
87
|
return c.json({
|
|
88
88
|
dataDir: config.dataDir,
|
|
@@ -137,4 +137,4 @@ function createApp() {
|
|
|
137
137
|
//#endregion
|
|
138
138
|
export { createApp as t };
|
|
139
139
|
|
|
140
|
-
//# sourceMappingURL=app-
|
|
140
|
+
//# sourceMappingURL=app-BeZyCVuz.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-
|
|
1
|
+
{"version":3,"file":"app-BeZyCVuz.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 { workspaceOutputPaths } from '../workspace/output-root.js'\n\nconst WORKSPACE_TREE_ROOTS = [\n 'artifacts',\n 'entities',\n 'reports',\n 'sessions',\n '.chain-insights/schema',\n]\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()\n ? 'symlink'\n : info.isDirectory()\n ? 'directory'\n : info.isFile()\n ? 'file'\n : 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 filename = `${vizId}.html`\n const paths = workspaceOutputPaths()\n const vizPath = path.join(paths.publishedRoot, 'viz', filename)\n try {\n return await readFile(vizPath, 'utf-8')\n } catch {\n return null\n }\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":";;;;;AAKA,MAAM,uBAAuB;CAC3B;CACA;CACA;CACA;CACA;AACF;AACA,MAAM,2BAA2B;AAQjC,SAAS,WAAW,MAAc,QAAyB;CACzD,MAAM,WAAW,KAAK,SAAS,KAAK,QAAQ,IAAI,GAAG,KAAK,QAAQ,MAAM,CAAC;CACvE,OAAO,aAAa,MAAO,CAAC,SAAS,WAAW,IAAI,KAAK,CAAC,KAAK,WAAW,QAAQ;AACpF;AAEA,eAAe,mBAAmB,MAAc,QAAkC;CAChF,IAAI;EACF,MAAM,CAAC,UAAU,cAAc,MAAM,QAAQ,IAAI,CAAC,SAAS,IAAI,GAAG,SAAS,MAAM,CAAC,CAAC;EACnF,OAAO,WAAW,UAAU,UAAU;CACxC,QAAQ;EACN,OAAO;CACT;AACF;AAEA,SAAS,oBAAoB,MAAc,QAAwB;CACjE,OAAO,KAAK,SAAS,MAAM,MAAM,CAAC,CAAC,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,GAAG;AAC7D;AAEA,eAAe,qBACb,eACA,QAAQ,sBACR,WAAW,0BACoB;CAC/B,MAAM,UAAgC,CAAC;CACvC,MAAM,OAAO,KAAK,QAAQ,aAAa;CAEvC,eAAe,MAAM,QAAgB,OAA8B;EACjE,MAAM,WAAW,KAAK,QAAQ,MAAM;EACpC,IAAI,CAAC,WAAW,MAAM,QAAQ,GAAG;EAEjC,IAAI;EACJ,IAAI;GACF,OAAO,MAAM,MAAM,QAAQ;EAC7B,QAAQ;GACN;EACF;EAEA,MAAM,OAAO,KAAK,eAAe,IAC7B,YACA,KAAK,YAAY,IACf,cACA,KAAK,OAAO,IACV,SACA;EACR,IAAI,CAAC,MAAM;EAEX,MAAM,QAA4B;GAChC,MAAM,oBAAoB,MAAM,QAAQ;GACxC;EACF;EACA,IAAI,SAAS,QAAQ,MAAM,OAAO,KAAK;EACvC,QAAQ,KAAK,KAAK;EAElB,IAAI,SAAS,eAAe,SAAS,UAAU;EAC/C,IAAI,CAAE,MAAM,mBAAmB,MAAM,QAAQ,GAAI;EAEjD,IAAI;EACJ,IAAI;GACF,WAAW,MAAM,QAAQ,QAAQ;EACnC,QAAQ;GACN;EACF;EAEA,KAAK,MAAM,SAAS,SAAS,KAAK,GAChC,MAAM,MAAM,KAAK,KAAK,UAAU,KAAK,GAAG,QAAQ,CAAC;CAErD;CAEA,KAAK,MAAM,YAAY,OAAO;EAC5B,MAAM,SAAS,KAAK,QAAQ,MAAM,QAAQ;EAC1C,IAAI,WAAW,MAAM,MAAM,GAAG,MAAM,MAAM,QAAQ,CAAC;CACrD;CAEA,OAAO;AACT;AAEA,eAAe,YAAY,OAAuC;CAChE,MAAM,WAAW,GAAG,MAAM;CAC1B,MAAM,QAAQ,qBAAqB;CACnC,MAAM,UAAU,KAAK,KAAK,MAAM,eAAe,OAAO,QAAQ;CAC9D,IAAI;EACF,OAAO,MAAM,SAAS,SAAS,OAAO;CACxC,QAAQ;EACN,OAAO;CACT;AACF;AAEA,SAAS,0BAA0B,UAA2B;CAC5D,OACE,SAAS,SAAS,aAAa,KAC/B,oBAAoB,KAAK,QAAQ,KACjC,CAAC,SAAS,SAAS,IAAI,KACvB,CAAC,SAAS,SAAS,GAAG,KACtB,CAAC,SAAS,SAAS,IAAI;AAE3B;AAEA,SAAgB,YAAkB;CAChC,MAAM,MAAM,IAAI,KAAK;CAErB,IAAI,IAAI,YAAY,MAAM,EAAE,KAAK;EAAE,IAAI;EAAM,IAAI,KAAK,IAAI;CAAE,CAAC,CAAC;CAE9D,IAAI,IAAI,WAAW,OAAO,MAAM;EAC9B,MAAM,EAAE,eAAe,MAAM,OAAO,wBAAqB,CAAA,MAAA,MAAA,EAAA,CAAA;EACzD,MAAM,SAAS,MAAM,WAAW;EAChC,OAAO,EAAE,KAAK;GACZ,SAAS,OAAO;GAChB,cAAc,OAAO;GACrB,QAAQ;EACV,CAAC;CACH,CAAC;CAED,IAAI,IAAI,YAAY,OAAO,MAAM;EAC/B,MAAM,KAAK,EAAE,IAAI,MAAM,IAAI;EAC3B,IAAI,CAAC,mBAAmB,KAAK,EAAE,GAC7B,OAAO,EAAE,KAAK,EAAE,OAAO,2BAA2B,GAAG,GAAG;EAE1D,MAAM,OAAO,MAAM,YAAY,EAAE;EACjC,IAAI,CAAC,MACH,OAAO,EAAE,KAAK,EAAE,OAAO,0BAA0B,GAAG,GAAG;EAEzD,OAAO,EAAE,KAAK,IAAI;CACpB,CAAC;CAED,IAAI,IAAI,4BAA4B,OAAO,MAAM;EAC/C,MAAM,WAAW,EAAE,IAAI,MAAM,UAAU;EACvC,IAAI,CAAC,0BAA0B,QAAQ,GACrC,OAAO,EAAE,KAAK,EAAE,OAAO,gCAAgC,GAAG,GAAG;EAG/D,MAAM,EAAE,yBAAyB,MAAM,OAAO,6BAA8B,CAAA,MAAA,MAAA,EAAA,CAAA;EAC5E,MAAM,QAAQ,qBAAqB;EACnC,MAAM,YAAY,KAAK,QAAQ,MAAM,kBAAkB,QAAQ;EAC/D,IAAI,CAAC,WAAW,MAAM,kBAAkB,SAAS,GAC/C,OAAO,EAAE,KAAK,EAAE,OAAO,gCAAgC,GAAG,GAAG;EAE/D,IAAI,CAAE,MAAM,mBAAmB,MAAM,kBAAkB,SAAS,GAC9D,OAAO,EAAE,KAAK,EAAE,OAAO,yBAAyB,GAAG,GAAG;EAGxD,IAAI;GACF,MAAM,QAAQ,MAAM,SAAS,WAAW,OAAO;GAC/C,OAAO,EAAE,KAAK,OAAO,KAAK;IACxB,gBAAgB;IAChB,+BAA+B;GACjC,CAAC;EACH,QAAQ;GACN,OAAO,EAAE,KAAK,EAAE,OAAO,yBAAyB,GAAG,GAAG;EACxD;CACF,CAAC;CAED,IAAI,IAAI,qBAAqB,MAAM;EACjC,OAAO,EAAE,KAAK,EAAE,OAAO,gCAAgC,GAAG,GAAG;CAC/D,CAAC;CAED,IAAI,IAAI,mBAAmB,OAAO,MAAM;EACtC,MAAM,EAAE,yBAAyB,MAAM,OAAO,6BAA8B,CAAA,MAAA,MAAA,EAAA,CAAA;EAC5E,MAAM,QAAQ,qBAAqB;EACnC,MAAM,UAAU,MAAM,qBAAqB,MAAM,MAAM,oBAAoB;EAC3E,OAAO,EAAE,KAAK;GACZ,QAAQ;GACR,MAAM,MAAM;GACZ;EACF,CAAC;CACH,CAAC;CAED,IAAI,SAAS,KAAK,MAAM;EACtB,QAAQ,MAAM,GAAG;EACjB,OAAO,EAAE,KAAK,EAAE,OAAO,wBAAwB,GAAG,GAAG;CACvD,CAAC;CAED,OAAO;AACT"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as createApp } from "./app-
|
|
1
|
+
import { t as createApp } from "./app-BeZyCVuz.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
|
|
@@ -46,4 +46,4 @@ async function ensureArtifactServer(port) {
|
|
|
46
46
|
//#endregion
|
|
47
47
|
export { ensureArtifactServer };
|
|
48
48
|
|
|
49
|
-
//# sourceMappingURL=artifact-server-
|
|
49
|
+
//# sourceMappingURL=artifact-server-C1fETWsc.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"artifact-server-
|
|
1
|
+
{"version":3,"file":"artifact-server-C1fETWsc.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(\n `Chain Insights graph report server failed on 127.0.0.1:${port}: ${(err as Error).message}\\n`\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,EAAA,CACe;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;CAE3B,MAAM,MAAM,UAAU;CACtB,MAAM,SAAS,MAAM;EACnB,OAAO,IAAI;EACX,UAAU;EACV;CACF,CAAC;CACD,QAAQ,IAAI,MAAM,MAAM;CACxB,OAAO,GAAG,UAAU,QAAQ;EAC1B,QAAQ,OAAO,IAAI;EACnB,QAAQ,OAAO,MACb,0DAA0D,KAAK,IAAK,IAAc,QAAQ,GAC5F;CACF,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
|
@@ -50,7 +50,7 @@ function runInstaller(flag) {
|
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
52
|
async function withGraphMcpClient(name, fn) {
|
|
53
|
-
const { loadConfig } = await Promise.resolve().then(() => require("./config-
|
|
53
|
+
const { loadConfig } = await Promise.resolve().then(() => require("./config-DYiUgdzg.cjs")).then((n) => n.config_exports);
|
|
54
54
|
const config = await loadConfig();
|
|
55
55
|
const { createConfiguredGraphMcpFetch, resolveGraphMcpEndpoint } = await Promise.resolve().then(() => require("./client-CqAzD519.cjs")).then((n) => n.client_exports);
|
|
56
56
|
const paymentFetch = await createConfiguredGraphMcpFetch(config);
|
|
@@ -70,7 +70,7 @@ async function withGraphMcpClient(name, fn) {
|
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
72
|
async function printNetworkCapabilities(opts) {
|
|
73
|
-
const { loadConfig } = await Promise.resolve().then(() => require("./config-
|
|
73
|
+
const { loadConfig } = await Promise.resolve().then(() => require("./config-DYiUgdzg.cjs")).then((n) => n.config_exports);
|
|
74
74
|
const { fetchNetworkCapabilities, formatNetworkCapabilities } = await Promise.resolve().then(() => require("./capabilities-CPcrxodx.cjs")).then((n) => n.capabilities_exports);
|
|
75
75
|
const document = await fetchNetworkCapabilities(await loadConfig());
|
|
76
76
|
if (opts.json) console.log(JSON.stringify(document, null, 2));
|
|
@@ -88,11 +88,11 @@ program.command("serve").description("Start local visualization server").option(
|
|
|
88
88
|
try {
|
|
89
89
|
const { requireWorkspaceRoot } = await Promise.resolve().then(() => require("./output-root-BewoQaTx.cjs")).then((n) => n.output_root_exports);
|
|
90
90
|
const workspaceRoot = requireWorkspaceRoot();
|
|
91
|
-
const { loadConfig } = await Promise.resolve().then(() => require("./config-
|
|
91
|
+
const { loadConfig } = await Promise.resolve().then(() => require("./config-DYiUgdzg.cjs")).then((n) => n.config_exports);
|
|
92
92
|
const { resolveServerPort } = await Promise.resolve().then(() => require("./resolve-port-CbaEoODz.cjs"));
|
|
93
93
|
const config = await loadConfig();
|
|
94
94
|
const port = resolveServerPort(opts.port, config.serverPort);
|
|
95
|
-
const { startServer } = await Promise.resolve().then(() => require("./server-
|
|
95
|
+
const { startServer } = await Promise.resolve().then(() => require("./server-BjprY9Ef.cjs")).then((n) => n.server_exports);
|
|
96
96
|
console.log(`Workspace: ${workspaceRoot}`);
|
|
97
97
|
startServer(port);
|
|
98
98
|
} catch (err) {
|
|
@@ -101,7 +101,7 @@ program.command("serve").description("Start local visualization server").option(
|
|
|
101
101
|
}
|
|
102
102
|
});
|
|
103
103
|
program.command("status").description("Show toolkit status and configuration").action(async () => {
|
|
104
|
-
const { loadConfig } = await Promise.resolve().then(() => require("./config-
|
|
104
|
+
const { loadConfig } = await Promise.resolve().then(() => require("./config-DYiUgdzg.cjs")).then((n) => n.config_exports);
|
|
105
105
|
const { findActiveWorkspace, activeDataDir } = await Promise.resolve().then(() => require("./active-Bc13hJIm.cjs")).then((n) => n.active_exports);
|
|
106
106
|
const config = await loadConfig();
|
|
107
107
|
const workspace = findActiveWorkspace();
|
|
@@ -139,7 +139,7 @@ program.command("update").description("Check npmjs for a newer Chain Insights re
|
|
|
139
139
|
});
|
|
140
140
|
program.command("debug").description("Configure Chain Insights Graph debug mode").addCommand(new commander.Command("on").description("Enable Chain Insights Graph debug mode without x402 payments").requiredOption("--token <token>", "Debug bearer token").option("--endpoint <url>", "Chain Insights Graph endpoint").action(async (opts) => {
|
|
141
141
|
try {
|
|
142
|
-
const { saveConfig } = await Promise.resolve().then(() => require("./config-
|
|
142
|
+
const { saveConfig } = await Promise.resolve().then(() => require("./config-DYiUgdzg.cjs")).then((n) => n.config_exports);
|
|
143
143
|
await saveConfig({
|
|
144
144
|
graphMcpMode: "debug",
|
|
145
145
|
graphMcpAuthToken: opts.token,
|
|
@@ -154,7 +154,7 @@ program.command("debug").description("Configure Chain Insights Graph debug mode"
|
|
|
154
154
|
}
|
|
155
155
|
})).addCommand(new commander.Command("off").description("Disable Chain Insights Graph debug mode and use paid x402 calls").action(async () => {
|
|
156
156
|
try {
|
|
157
|
-
const { saveConfig } = await Promise.resolve().then(() => require("./config-
|
|
157
|
+
const { saveConfig } = await Promise.resolve().then(() => require("./config-DYiUgdzg.cjs")).then((n) => n.config_exports);
|
|
158
158
|
await saveConfig({
|
|
159
159
|
graphMcpMode: "paid",
|
|
160
160
|
graphMcpAuthToken: ""
|
|
@@ -167,7 +167,7 @@ program.command("debug").description("Configure Chain Insights Graph debug mode"
|
|
|
167
167
|
}
|
|
168
168
|
})).addCommand(new commander.Command("status").description("Show Chain Insights Graph payment/debug mode").action(async () => {
|
|
169
169
|
try {
|
|
170
|
-
const { loadConfig } = await Promise.resolve().then(() => require("./config-
|
|
170
|
+
const { loadConfig } = await Promise.resolve().then(() => require("./config-DYiUgdzg.cjs")).then((n) => n.config_exports);
|
|
171
171
|
const config = await loadConfig();
|
|
172
172
|
console.log(`Chain Insights Graph mode: ${config.graphMcpMode}`);
|
|
173
173
|
console.log(`Graph endpoint: ${config.graphMcpEndpoint}`);
|
|
@@ -182,7 +182,7 @@ program.command("access-key").description("Configure Chain Insights Graph test a
|
|
|
182
182
|
try {
|
|
183
183
|
const normalizedKey = key.trim();
|
|
184
184
|
if (!normalizedKey) throw new Error("Test access key is required");
|
|
185
|
-
const { saveConfig } = await Promise.resolve().then(() => require("./config-
|
|
185
|
+
const { saveConfig } = await Promise.resolve().then(() => require("./config-DYiUgdzg.cjs")).then((n) => n.config_exports);
|
|
186
186
|
await saveConfig({
|
|
187
187
|
graphMcpMode: "debug",
|
|
188
188
|
graphMcpAuthToken: normalizedKey,
|
|
@@ -197,7 +197,7 @@ program.command("access-key").description("Configure Chain Insights Graph test a
|
|
|
197
197
|
}
|
|
198
198
|
})).addCommand(new commander.Command("clear").description("Remove the Chain Insights Graph test access key and use paid x402 calls").action(async () => {
|
|
199
199
|
try {
|
|
200
|
-
const { saveConfig } = await Promise.resolve().then(() => require("./config-
|
|
200
|
+
const { saveConfig } = await Promise.resolve().then(() => require("./config-DYiUgdzg.cjs")).then((n) => n.config_exports);
|
|
201
201
|
await saveConfig({
|
|
202
202
|
graphMcpMode: "paid",
|
|
203
203
|
graphMcpAuthToken: ""
|
|
@@ -210,7 +210,7 @@ program.command("access-key").description("Configure Chain Insights Graph test a
|
|
|
210
210
|
}
|
|
211
211
|
})).addCommand(new commander.Command("status").description("Show Chain Insights Graph test access key status").action(async () => {
|
|
212
212
|
try {
|
|
213
|
-
const { loadConfig } = await Promise.resolve().then(() => require("./config-
|
|
213
|
+
const { loadConfig } = await Promise.resolve().then(() => require("./config-DYiUgdzg.cjs")).then((n) => n.config_exports);
|
|
214
214
|
const config = await loadConfig();
|
|
215
215
|
console.log(`Graph endpoint: ${config.graphMcpEndpoint}`);
|
|
216
216
|
console.log(`Access key: ${config.graphMcpAuthToken?.trim() ? "configured" : "not configured"}`);
|
|
@@ -222,7 +222,7 @@ program.command("access-key").description("Configure Chain Insights Graph test a
|
|
|
222
222
|
}));
|
|
223
223
|
program.command("init").description("Initialize an investigation workspace").argument("[dir]", "Workspace directory to initialize", ".").option("--force", "Overwrite existing workspace files").action(async (dir, opts) => {
|
|
224
224
|
try {
|
|
225
|
-
const { initWorkspace } = await Promise.resolve().then(() => require("./init-
|
|
225
|
+
const { initWorkspace } = await Promise.resolve().then(() => require("./init-C3AVZHFb.cjs"));
|
|
226
226
|
const result = await initWorkspace({
|
|
227
227
|
targetDir: dir,
|
|
228
228
|
force: opts.force
|
|
@@ -244,8 +244,8 @@ program.command("setup").description("Configure external MCP clients").addComman
|
|
|
244
244
|
runInstaller("--hermes");
|
|
245
245
|
}));
|
|
246
246
|
program.command("config").description("Read or write configuration values").addCommand(new commander.Command("get").argument("<key>", "Config key to read").action(async (key) => {
|
|
247
|
-
const { loadConfig } = await Promise.resolve().then(() => require("./config-
|
|
248
|
-
const { CONFIG_KEYS } = await Promise.resolve().then(() => require("./schema-
|
|
247
|
+
const { loadConfig } = await Promise.resolve().then(() => require("./config-DYiUgdzg.cjs")).then((n) => n.config_exports);
|
|
248
|
+
const { CONFIG_KEYS } = await Promise.resolve().then(() => require("./schema-DepyuUEP.cjs")).then((n) => n.schema_exports);
|
|
249
249
|
if (!CONFIG_KEYS.includes(key)) {
|
|
250
250
|
console.error(`Unknown config key: ${key}`);
|
|
251
251
|
process.exit(1);
|
|
@@ -265,8 +265,8 @@ program.command("config").description("Read or write configuration values").addC
|
|
|
265
265
|
}
|
|
266
266
|
return;
|
|
267
267
|
}
|
|
268
|
-
const { loadConfig, saveConfig } = await Promise.resolve().then(() => require("./config-
|
|
269
|
-
const { CONFIG_KEYS, DEFAULT_CONFIG } = await Promise.resolve().then(() => require("./schema-
|
|
268
|
+
const { loadConfig, saveConfig } = await Promise.resolve().then(() => require("./config-DYiUgdzg.cjs")).then((n) => n.config_exports);
|
|
269
|
+
const { CONFIG_KEYS, DEFAULT_CONFIG } = await Promise.resolve().then(() => require("./schema-DepyuUEP.cjs")).then((n) => n.schema_exports);
|
|
270
270
|
const current = await loadConfig();
|
|
271
271
|
if (!CONFIG_KEYS.includes(key)) {
|
|
272
272
|
console.error(`Unknown config key: ${key}`);
|
|
@@ -360,7 +360,7 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
|
|
|
360
360
|
const { loadSchema, saveSchema } = await Promise.resolve().then(() => require("./schema-cache-n7Gbhvsj.cjs"));
|
|
361
361
|
const { formatToolsTable } = await Promise.resolve().then(() => require("./format-9NLBykEL.cjs"));
|
|
362
362
|
const { visibleRemoteTools } = await Promise.resolve().then(() => require("./tool-visibility-DZBAP62b.cjs")).then((n) => n.tool_visibility_exports);
|
|
363
|
-
const { loadConfig } = await Promise.resolve().then(() => require("./config-
|
|
363
|
+
const { loadConfig } = await Promise.resolve().then(() => require("./config-DYiUgdzg.cjs")).then((n) => n.config_exports);
|
|
364
364
|
const { createConfiguredGraphMcpFetch, resolveGraphMcpEndpoint } = await Promise.resolve().then(() => require("./client-CqAzD519.cjs")).then((n) => n.client_exports);
|
|
365
365
|
const config = await loadConfig();
|
|
366
366
|
const graphMcpEndpoint = resolveGraphMcpEndpoint(config);
|
|
@@ -462,7 +462,7 @@ program.command("viz").description("Generate a workspace visualization").argumen
|
|
|
462
462
|
console.error("Provide either a visualization source ID or --data <file.json>");
|
|
463
463
|
process.exit(1);
|
|
464
464
|
}
|
|
465
|
-
const { loadConfig } = await Promise.resolve().then(() => require("./config-
|
|
465
|
+
const { loadConfig } = await Promise.resolve().then(() => require("./config-DYiUgdzg.cjs")).then((n) => n.config_exports);
|
|
466
466
|
const { resolveServerPort } = await Promise.resolve().then(() => require("./resolve-port-CbaEoODz.cjs"));
|
|
467
467
|
const config = await loadConfig();
|
|
468
468
|
const port = resolveServerPort(opts.port, config.serverPort);
|
|
@@ -471,7 +471,7 @@ program.command("viz").description("Generate a workspace visualization").argumen
|
|
|
471
471
|
sourceId,
|
|
472
472
|
dataFile: opts.data
|
|
473
473
|
});
|
|
474
|
-
const { startServer } = await Promise.resolve().then(() => require("./server-
|
|
474
|
+
const { startServer } = await Promise.resolve().then(() => require("./server-BjprY9Ef.cjs")).then((n) => n.server_exports);
|
|
475
475
|
startServer(port);
|
|
476
476
|
const url = `http://127.0.0.1:${port}/viz/${result.vizId}`;
|
|
477
477
|
console.log(`Visualization: ${url}`);
|
package/dist/cli.mjs
CHANGED
|
@@ -48,7 +48,7 @@ function runInstaller(flag) {
|
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
async function withGraphMcpClient(name, fn) {
|
|
51
|
-
const { loadConfig } = await import("./config-
|
|
51
|
+
const { loadConfig } = await import("./config-DiQs0rQX.mjs").then((n) => n.t);
|
|
52
52
|
const config = await loadConfig();
|
|
53
53
|
const { createConfiguredGraphMcpFetch, resolveGraphMcpEndpoint } = await import("./client-D4aM4bzP.mjs").then((n) => n.r);
|
|
54
54
|
const paymentFetch = await createConfiguredGraphMcpFetch(config);
|
|
@@ -68,7 +68,7 @@ async function withGraphMcpClient(name, fn) {
|
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
70
|
async function printNetworkCapabilities(opts) {
|
|
71
|
-
const { loadConfig } = await import("./config-
|
|
71
|
+
const { loadConfig } = await import("./config-DiQs0rQX.mjs").then((n) => n.t);
|
|
72
72
|
const { fetchNetworkCapabilities, formatNetworkCapabilities } = await import("./capabilities-BZI6qROg.mjs").then((n) => n.t);
|
|
73
73
|
const document = await fetchNetworkCapabilities(await loadConfig());
|
|
74
74
|
if (opts.json) console.log(JSON.stringify(document, null, 2));
|
|
@@ -86,11 +86,11 @@ program.command("serve").description("Start local visualization server").option(
|
|
|
86
86
|
try {
|
|
87
87
|
const { requireWorkspaceRoot } = await import("./output-root-BK4pdjyz.mjs").then((n) => n.t);
|
|
88
88
|
const workspaceRoot = requireWorkspaceRoot();
|
|
89
|
-
const { loadConfig } = await import("./config-
|
|
89
|
+
const { loadConfig } = await import("./config-DiQs0rQX.mjs").then((n) => n.t);
|
|
90
90
|
const { resolveServerPort } = await import("./resolve-port-DxPK7Ipx.mjs");
|
|
91
91
|
const config = await loadConfig();
|
|
92
92
|
const port = resolveServerPort(opts.port, config.serverPort);
|
|
93
|
-
const { startServer } = await import("./server-
|
|
93
|
+
const { startServer } = await import("./server-BDmHAF1w.mjs").then((n) => n.t);
|
|
94
94
|
console.log(`Workspace: ${workspaceRoot}`);
|
|
95
95
|
startServer(port);
|
|
96
96
|
} catch (err) {
|
|
@@ -99,7 +99,7 @@ program.command("serve").description("Start local visualization server").option(
|
|
|
99
99
|
}
|
|
100
100
|
});
|
|
101
101
|
program.command("status").description("Show toolkit status and configuration").action(async () => {
|
|
102
|
-
const { loadConfig } = await import("./config-
|
|
102
|
+
const { loadConfig } = await import("./config-DiQs0rQX.mjs").then((n) => n.t);
|
|
103
103
|
const { findActiveWorkspace, activeDataDir } = await import("./active-BQopLul8.mjs").then((n) => n.t);
|
|
104
104
|
const config = await loadConfig();
|
|
105
105
|
const workspace = findActiveWorkspace();
|
|
@@ -137,7 +137,7 @@ program.command("update").description("Check npmjs for a newer Chain Insights re
|
|
|
137
137
|
});
|
|
138
138
|
program.command("debug").description("Configure Chain Insights Graph debug mode").addCommand(new Command("on").description("Enable Chain Insights Graph debug mode without x402 payments").requiredOption("--token <token>", "Debug bearer token").option("--endpoint <url>", "Chain Insights Graph endpoint").action(async (opts) => {
|
|
139
139
|
try {
|
|
140
|
-
const { saveConfig } = await import("./config-
|
|
140
|
+
const { saveConfig } = await import("./config-DiQs0rQX.mjs").then((n) => n.t);
|
|
141
141
|
await saveConfig({
|
|
142
142
|
graphMcpMode: "debug",
|
|
143
143
|
graphMcpAuthToken: opts.token,
|
|
@@ -152,7 +152,7 @@ program.command("debug").description("Configure Chain Insights Graph debug mode"
|
|
|
152
152
|
}
|
|
153
153
|
})).addCommand(new Command("off").description("Disable Chain Insights Graph debug mode and use paid x402 calls").action(async () => {
|
|
154
154
|
try {
|
|
155
|
-
const { saveConfig } = await import("./config-
|
|
155
|
+
const { saveConfig } = await import("./config-DiQs0rQX.mjs").then((n) => n.t);
|
|
156
156
|
await saveConfig({
|
|
157
157
|
graphMcpMode: "paid",
|
|
158
158
|
graphMcpAuthToken: ""
|
|
@@ -165,7 +165,7 @@ program.command("debug").description("Configure Chain Insights Graph debug mode"
|
|
|
165
165
|
}
|
|
166
166
|
})).addCommand(new Command("status").description("Show Chain Insights Graph payment/debug mode").action(async () => {
|
|
167
167
|
try {
|
|
168
|
-
const { loadConfig } = await import("./config-
|
|
168
|
+
const { loadConfig } = await import("./config-DiQs0rQX.mjs").then((n) => n.t);
|
|
169
169
|
const config = await loadConfig();
|
|
170
170
|
console.log(`Chain Insights Graph mode: ${config.graphMcpMode}`);
|
|
171
171
|
console.log(`Graph endpoint: ${config.graphMcpEndpoint}`);
|
|
@@ -180,7 +180,7 @@ program.command("access-key").description("Configure Chain Insights Graph test a
|
|
|
180
180
|
try {
|
|
181
181
|
const normalizedKey = key.trim();
|
|
182
182
|
if (!normalizedKey) throw new Error("Test access key is required");
|
|
183
|
-
const { saveConfig } = await import("./config-
|
|
183
|
+
const { saveConfig } = await import("./config-DiQs0rQX.mjs").then((n) => n.t);
|
|
184
184
|
await saveConfig({
|
|
185
185
|
graphMcpMode: "debug",
|
|
186
186
|
graphMcpAuthToken: normalizedKey,
|
|
@@ -195,7 +195,7 @@ program.command("access-key").description("Configure Chain Insights Graph test a
|
|
|
195
195
|
}
|
|
196
196
|
})).addCommand(new Command("clear").description("Remove the Chain Insights Graph test access key and use paid x402 calls").action(async () => {
|
|
197
197
|
try {
|
|
198
|
-
const { saveConfig } = await import("./config-
|
|
198
|
+
const { saveConfig } = await import("./config-DiQs0rQX.mjs").then((n) => n.t);
|
|
199
199
|
await saveConfig({
|
|
200
200
|
graphMcpMode: "paid",
|
|
201
201
|
graphMcpAuthToken: ""
|
|
@@ -208,7 +208,7 @@ program.command("access-key").description("Configure Chain Insights Graph test a
|
|
|
208
208
|
}
|
|
209
209
|
})).addCommand(new Command("status").description("Show Chain Insights Graph test access key status").action(async () => {
|
|
210
210
|
try {
|
|
211
|
-
const { loadConfig } = await import("./config-
|
|
211
|
+
const { loadConfig } = await import("./config-DiQs0rQX.mjs").then((n) => n.t);
|
|
212
212
|
const config = await loadConfig();
|
|
213
213
|
console.log(`Graph endpoint: ${config.graphMcpEndpoint}`);
|
|
214
214
|
console.log(`Access key: ${config.graphMcpAuthToken?.trim() ? "configured" : "not configured"}`);
|
|
@@ -220,7 +220,7 @@ program.command("access-key").description("Configure Chain Insights Graph test a
|
|
|
220
220
|
}));
|
|
221
221
|
program.command("init").description("Initialize an investigation workspace").argument("[dir]", "Workspace directory to initialize", ".").option("--force", "Overwrite existing workspace files").action(async (dir, opts) => {
|
|
222
222
|
try {
|
|
223
|
-
const { initWorkspace } = await import("./init-
|
|
223
|
+
const { initWorkspace } = await import("./init-CO-PRYhT.mjs");
|
|
224
224
|
const result = await initWorkspace({
|
|
225
225
|
targetDir: dir,
|
|
226
226
|
force: opts.force
|
|
@@ -242,8 +242,8 @@ program.command("setup").description("Configure external MCP clients").addComman
|
|
|
242
242
|
runInstaller("--hermes");
|
|
243
243
|
}));
|
|
244
244
|
program.command("config").description("Read or write configuration values").addCommand(new Command("get").argument("<key>", "Config key to read").action(async (key) => {
|
|
245
|
-
const { loadConfig } = await import("./config-
|
|
246
|
-
const { CONFIG_KEYS } = await import("./schema-
|
|
245
|
+
const { loadConfig } = await import("./config-DiQs0rQX.mjs").then((n) => n.t);
|
|
246
|
+
const { CONFIG_KEYS } = await import("./schema-v5cwychf.mjs").then((n) => n.r);
|
|
247
247
|
if (!CONFIG_KEYS.includes(key)) {
|
|
248
248
|
console.error(`Unknown config key: ${key}`);
|
|
249
249
|
process.exit(1);
|
|
@@ -263,8 +263,8 @@ program.command("config").description("Read or write configuration values").addC
|
|
|
263
263
|
}
|
|
264
264
|
return;
|
|
265
265
|
}
|
|
266
|
-
const { loadConfig, saveConfig } = await import("./config-
|
|
267
|
-
const { CONFIG_KEYS, DEFAULT_CONFIG } = await import("./schema-
|
|
266
|
+
const { loadConfig, saveConfig } = await import("./config-DiQs0rQX.mjs").then((n) => n.t);
|
|
267
|
+
const { CONFIG_KEYS, DEFAULT_CONFIG } = await import("./schema-v5cwychf.mjs").then((n) => n.r);
|
|
268
268
|
const current = await loadConfig();
|
|
269
269
|
if (!CONFIG_KEYS.includes(key)) {
|
|
270
270
|
console.error(`Unknown config key: ${key}`);
|
|
@@ -358,7 +358,7 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
|
|
|
358
358
|
const { loadSchema, saveSchema } = await import("./schema-cache-DJdU4MIP.mjs");
|
|
359
359
|
const { formatToolsTable } = await import("./format-Bq94jSyw.mjs");
|
|
360
360
|
const { visibleRemoteTools } = await import("./tool-visibility-C0ALejXI.mjs").then((n) => n.i);
|
|
361
|
-
const { loadConfig } = await import("./config-
|
|
361
|
+
const { loadConfig } = await import("./config-DiQs0rQX.mjs").then((n) => n.t);
|
|
362
362
|
const { createConfiguredGraphMcpFetch, resolveGraphMcpEndpoint } = await import("./client-D4aM4bzP.mjs").then((n) => n.r);
|
|
363
363
|
const config = await loadConfig();
|
|
364
364
|
const graphMcpEndpoint = resolveGraphMcpEndpoint(config);
|
|
@@ -460,7 +460,7 @@ program.command("viz").description("Generate a workspace visualization").argumen
|
|
|
460
460
|
console.error("Provide either a visualization source ID or --data <file.json>");
|
|
461
461
|
process.exit(1);
|
|
462
462
|
}
|
|
463
|
-
const { loadConfig } = await import("./config-
|
|
463
|
+
const { loadConfig } = await import("./config-DiQs0rQX.mjs").then((n) => n.t);
|
|
464
464
|
const { resolveServerPort } = await import("./resolve-port-DxPK7Ipx.mjs");
|
|
465
465
|
const config = await loadConfig();
|
|
466
466
|
const port = resolveServerPort(opts.port, config.serverPort);
|
|
@@ -469,7 +469,7 @@ program.command("viz").description("Generate a workspace visualization").argumen
|
|
|
469
469
|
sourceId,
|
|
470
470
|
dataFile: opts.data
|
|
471
471
|
});
|
|
472
|
-
const { startServer } = await import("./server-
|
|
472
|
+
const { startServer } = await import("./server-BDmHAF1w.mjs").then((n) => n.t);
|
|
473
473
|
startServer(port);
|
|
474
474
|
const url = `http://127.0.0.1:${port}/viz/${result.vizId}`;
|
|
475
475
|
console.log(`Visualization: ${url}`);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const require_rolldown_runtime = require("./rolldown-runtime-C0BPl7ul.cjs");
|
|
2
|
-
const require_mcp_endpoint = require("./mcp-endpoint-
|
|
3
|
-
const require_schema = require("./schema-
|
|
2
|
+
const require_mcp_endpoint = require("./mcp-endpoint-DdIVQKW5.cjs");
|
|
3
|
+
const require_schema = require("./schema-DepyuUEP.cjs");
|
|
4
4
|
let node_path = require("node:path");
|
|
5
5
|
node_path = require_rolldown_runtime.__toESM(node_path, 1);
|
|
6
6
|
let node_fs_promises = require("node:fs/promises");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
|
|
2
|
-
import { n as graphMcpEndpointEnvOverride } from "./mcp-endpoint-
|
|
3
|
-
import { n as parseInvestigatorConfig, t as DEFAULT_CONFIG } from "./schema-
|
|
2
|
+
import { n as graphMcpEndpointEnvOverride } from "./mcp-endpoint-Bd3SvCkg.mjs";
|
|
3
|
+
import { n as parseInvestigatorConfig, t as DEFAULT_CONFIG } from "./schema-v5cwychf.mjs";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
6
6
|
import os from "node:os";
|
|
@@ -74,4 +74,4 @@ async function resetConfigCache() {
|
|
|
74
74
|
//#endregion
|
|
75
75
|
export { saveConfig as i, loadConfig as n, resetConfigCache as r, config_exports as t };
|
|
76
76
|
|
|
77
|
-
//# sourceMappingURL=config-
|
|
77
|
+
//# sourceMappingURL=config-DiQs0rQX.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-
|
|
1
|
+
{"version":3,"file":"config-DiQs0rQX.mjs","names":[],"sources":["../src/config/index.ts"],"sourcesContent":["import { readFile, writeFile, mkdir } from 'node:fs/promises'\nimport path from 'node:path'\nimport os from 'node:os'\nimport { DEFAULT_CONFIG, parseInvestigatorConfig, type InvestigatorConfig } from './schema.js'\nimport { graphMcpEndpointEnvOverride } from './mcp-endpoint.js'\n\n// Config path derived from HOME at call time so tests can override HOME.\nfunction configPath(): string {\n return path.join(os.homedir(), '.chain-insights', 'config.json')\n}\n\nlet _cached: InvestigatorConfig | null = null\n\nfunction applyRuntimeEnvOverrides(config: InvestigatorConfig): InvestigatorConfig {\n let graphMcpEndpoint: string | undefined\n try {\n graphMcpEndpoint = graphMcpEndpointEnvOverride()\n } catch (err) {\n throw new Error(`Invalid configuration in environment: ${(err as Error).message}`)\n }\n return graphMcpEndpoint ? parseInvestigatorConfig({ ...config, graphMcpEndpoint }) : config\n}\n\nasync function loadStoredConfig(): Promise<InvestigatorConfig> {\n const cfgPath = configPath()\n let raw: string\n try {\n raw = await readFile(cfgPath, 'utf8')\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n return DEFAULT_CONFIG\n }\n throw new Error(`Unable to read config ${cfgPath}: ${(err as Error).message}`)\n }\n\n let parsedJson: unknown\n try {\n parsedJson = JSON.parse(raw) as unknown\n } catch (err) {\n throw new Error(`Invalid JSON in ${cfgPath}: ${(err as Error).message}`)\n }\n\n try {\n return parseInvestigatorConfig(parsedJson)\n } catch (err) {\n throw new Error(`Invalid configuration in ${cfgPath}: ${(err as Error).message}`)\n }\n}\n\nexport async function loadConfig(): Promise<InvestigatorConfig> {\n if (_cached) return _cached\n _cached = applyRuntimeEnvOverrides(await loadStoredConfig())\n return _cached\n}\n\nexport async function saveConfig(updates: Partial<InvestigatorConfig>): Promise<void> {\n const current = await loadStoredConfig()\n let next: InvestigatorConfig\n try {\n next = parseInvestigatorConfig({ ...current, ...updates })\n } catch (err) {\n throw new Error(`Invalid configuration update: ${(err as Error).message}`)\n }\n const p = configPath()\n await mkdir(path.dirname(p), { recursive: true })\n await writeFile(p, JSON.stringify(next, null, 2) + '\\n', { mode: 0o600 })\n _cached = applyRuntimeEnvOverrides(next)\n}\n\nexport async function resetConfigCache(): Promise<void> {\n _cached = null\n}\n"],"mappings":";;;;;;;;;;;;AAOA,SAAS,aAAqB;CAC5B,OAAO,KAAK,KAAK,GAAG,QAAQ,GAAG,mBAAmB,aAAa;AACjE;AAEA,IAAI,UAAqC;AAEzC,SAAS,yBAAyB,QAAgD;CAChF,IAAI;CACJ,IAAI;EACF,mBAAmB,4BAA4B;CACjD,SAAS,KAAK;EACZ,MAAM,IAAI,MAAM,yCAA0C,IAAc,SAAS;CACnF;CACA,OAAO,mBAAmB,wBAAwB;EAAE,GAAG;EAAQ;CAAiB,CAAC,IAAI;AACvF;AAEA,eAAe,mBAAgD;CAC7D,MAAM,UAAU,WAAW;CAC3B,IAAI;CACJ,IAAI;EACF,MAAM,MAAM,SAAS,SAAS,MAAM;CACtC,SAAS,KAAK;EACZ,IAAK,IAA8B,SAAS,UAC1C,OAAO;EAET,MAAM,IAAI,MAAM,yBAAyB,QAAQ,IAAK,IAAc,SAAS;CAC/E;CAEA,IAAI;CACJ,IAAI;EACF,aAAa,KAAK,MAAM,GAAG;CAC7B,SAAS,KAAK;EACZ,MAAM,IAAI,MAAM,mBAAmB,QAAQ,IAAK,IAAc,SAAS;CACzE;CAEA,IAAI;EACF,OAAO,wBAAwB,UAAU;CAC3C,SAAS,KAAK;EACZ,MAAM,IAAI,MAAM,4BAA4B,QAAQ,IAAK,IAAc,SAAS;CAClF;AACF;AAEA,eAAsB,aAA0C;CAC9D,IAAI,SAAS,OAAO;CACpB,UAAU,yBAAyB,MAAM,iBAAiB,CAAC;CAC3D,OAAO;AACT;AAEA,eAAsB,WAAW,SAAqD;CACpF,MAAM,UAAU,MAAM,iBAAiB;CACvC,IAAI;CACJ,IAAI;EACF,OAAO,wBAAwB;GAAE,GAAG;GAAS,GAAG;EAAQ,CAAC;CAC3D,SAAS,KAAK;EACZ,MAAM,IAAI,MAAM,iCAAkC,IAAc,SAAS;CAC3E;CACA,MAAM,IAAI,WAAW;CACrB,MAAM,MAAM,KAAK,QAAQ,CAAC,GAAG,EAAE,WAAW,KAAK,CAAC;CAChD,MAAM,UAAU,GAAG,KAAK,UAAU,MAAM,MAAM,CAAC,IAAI,MAAM,EAAE,MAAM,IAAM,CAAC;CACxE,UAAU,yBAAyB,IAAI;AACzC;AAEA,eAAsB,mBAAkC;CACtD,UAAU;AACZ"}
|
package/dist/index.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_config = require("./config-
|
|
3
|
-
const require_app = require("./app-
|
|
4
|
-
const require_server = require("./server-
|
|
2
|
+
const require_config = require("./config-DYiUgdzg.cjs");
|
|
3
|
+
const require_app = require("./app-BHRl5oDo.cjs");
|
|
4
|
+
const require_server = require("./server-BjprY9Ef.cjs");
|
|
5
5
|
const require_wallet = require("./wallet-BEvHrHi3.cjs");
|
|
6
6
|
const require_tools = require("./tools-lPY6k-vJ.cjs");
|
|
7
7
|
const require_topup_server = require("./topup-server-DAqmAuu1.cjs");
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { i as saveConfig, n as loadConfig, r as resetConfigCache } from "./config-
|
|
2
|
-
import { t as createApp } from "./app-
|
|
3
|
-
import { n as startServer } from "./server-
|
|
1
|
+
import { i as saveConfig, n as loadConfig, r as resetConfigCache } from "./config-DiQs0rQX.mjs";
|
|
2
|
+
import { t as createApp } from "./app-BeZyCVuz.mjs";
|
|
3
|
+
import { n as startServer } from "./server-BDmHAF1w.mjs";
|
|
4
4
|
import { a as setWalletPrivateKey, i as normalizeWalletPrivateKey, n as encryptKey, o as walletAddressFromPrivateKey, r as isWalletConfigured, t as decryptKey } from "./wallet-fMbhvKXT.mjs";
|
|
5
5
|
import { a as formatWalletBalanceResult, c as getWalletAccount, i as formatWalletBalance, l as getWalletBalanceResult, o as getBalanceEth, r as buildTopupInfo, s as getBalanceUsdc, u as getWalletBalanceText } from "./tools-BKLnlBG1.mjs";
|
|
6
6
|
import { i as generateArtifactHtml, n as startTopupServer, t as getTopupUrl } from "./topup-server-rqI7bqem.mjs";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const require_rolldown_runtime = require("./rolldown-runtime-C0BPl7ul.cjs");
|
|
2
|
-
const require_mcp_endpoint = require("./mcp-endpoint-
|
|
2
|
+
const require_mcp_endpoint = require("./mcp-endpoint-DdIVQKW5.cjs");
|
|
3
3
|
let node_path = require("node:path");
|
|
4
4
|
node_path = require_rolldown_runtime.__toESM(node_path, 1);
|
|
5
5
|
let node_fs_promises = require("node:fs/promises");
|
|
@@ -30,7 +30,7 @@ function workspaceJson(workspaceRoot) {
|
|
|
30
30
|
name: "Chain Insights Workspace",
|
|
31
31
|
workspace_root: workspaceRoot,
|
|
32
32
|
default_network: "robinhood",
|
|
33
|
-
graph_mcp_endpoint: require_mcp_endpoint.
|
|
33
|
+
graph_mcp_endpoint: require_mcp_endpoint.DEFAULT_GRAPH_MCP_ENDPOINT,
|
|
34
34
|
artifacts_dir: "artifacts",
|
|
35
35
|
imports_dir: "imports",
|
|
36
36
|
reports_dir: "reports",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as
|
|
1
|
+
import { t as DEFAULT_GRAPH_MCP_ENDPOINT } from "./mcp-endpoint-Bd3SvCkg.mjs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { access, mkdir, writeFile } from "node:fs/promises";
|
|
4
4
|
//#region src/workspace/init.ts
|
|
@@ -28,7 +28,7 @@ function workspaceJson(workspaceRoot) {
|
|
|
28
28
|
name: "Chain Insights Workspace",
|
|
29
29
|
workspace_root: workspaceRoot,
|
|
30
30
|
default_network: "robinhood",
|
|
31
|
-
graph_mcp_endpoint:
|
|
31
|
+
graph_mcp_endpoint: DEFAULT_GRAPH_MCP_ENDPOINT,
|
|
32
32
|
artifacts_dir: "artifacts",
|
|
33
33
|
imports_dir: "imports",
|
|
34
34
|
reports_dir: "reports",
|
|
@@ -316,4 +316,4 @@ async function initWorkspace(options) {
|
|
|
316
316
|
//#endregion
|
|
317
317
|
export { initWorkspace };
|
|
318
318
|
|
|
319
|
-
//# sourceMappingURL=init-
|
|
319
|
+
//# sourceMappingURL=init-CO-PRYhT.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init-CO-PRYhT.mjs","names":[],"sources":["../src/workspace/init.ts"],"sourcesContent":["import { access, mkdir, writeFile } from 'node:fs/promises'\nimport path from 'node:path'\nimport { DEFAULT_GRAPH_MCP_ENDPOINT } from '../config/mcp-endpoint.js'\n\nexport interface InitWorkspaceOptions {\n targetDir: string\n force?: boolean\n}\n\nexport interface InitWorkspaceResult {\n workspaceRoot: string\n filesWritten: string[]\n}\n\nconst WORKSPACE_DIRS = [\n '.chain-insights',\n '.chain-insights/schema',\n '.chain-insights/runtime',\n '.chain-insights/runtime/logs',\n '.chain-insights/runtime-skill',\n 'artifacts',\n 'entities',\n 'imports',\n 'reports',\n 'reports/graphs',\n 'reports/tables',\n 'sessions',\n 'templates',\n 'published',\n]\n\nconst DEFAULT_DOMAIN_HINTS = ['aml']\n\nfunction todayIso(): string {\n return new Date().toISOString().slice(0, 10)\n}\n\nfunction workspaceJson(workspaceRoot: string): string {\n return (\n JSON.stringify(\n {\n schema: 'chain-insights.workspace.v1',\n name: 'Chain Insights Workspace',\n workspace_root: workspaceRoot,\n default_network: 'robinhood',\n graph_mcp_endpoint: DEFAULT_GRAPH_MCP_ENDPOINT,\n artifacts_dir: 'artifacts',\n imports_dir: 'imports',\n reports_dir: 'reports',\n templates_dir: 'templates',\n domain_hints: DEFAULT_DOMAIN_HINTS,\n created_at: todayIso(),\n },\n null,\n 2\n ) + '\\n'\n )\n}\n\nconst README = `# Chain Insights Workspace\n\nThis is a generic Chain Insights workspace.\nUse any editor or agent tooling you want to review reports, artifacts, entity\nnotes, graphs, and published bundles alongside the Chain Insights runtime\nmetadata.\n\n## Start\n\n\\`\\`\\`bash\nchain-insights mcp tools --refresh\nchain-insights wallet ready --check-only\n\\`\\`\\`\n\n## Layout\n\n\\`\\`\\`text\n.chain-insights/ Workspace metadata\nartifacts/ Tool-generated artifacts and durable workspace records\nentities/ Entity notes and indexes\nimports/ External reports, CSVs, screenshots, raw notes\nreports/ Final or interim analyst reports\nreports/graphs/ Graph JSON for visualization\nreports/tables/ Compact tabular extracts\nsessions/ Optional session notes\ntemplates/ Reusable workspace templates\npublished/ Published bundles and handoff-ready exports\n.chain-insights/schema/ Runtime graph schema captures\n.chain-insights/runtime/ Workspace-local runtime process state and debug logs\n.chain-insights/runtime-skill/ Workspace-specific agent schema notes\n\\`\\`\\`\n`\n\nconst AGENTS = `# Agent Instructions\n\nYou are operating inside a Chain Insights workspace.\n\n- Read README.md first.\n- If this directory is not initialized, run \\`cia init .\\` before persistence-producing commands.\n- Do not rerun init in an existing workspace unless replacing scaffolding with \\`--force\\`.\n- Read .chain-insights/runtime-skill/SKILL.md before graph queries.\n- Preserve full blockchain addresses exactly.\n- Do not guess the network for graph queries.\n- Capture or refresh graph schema before the first graph workflow.\n- \\`domain_hints\\` in \\`.chain-insights/workspace.json\\` are optional advisory workflow\n preferences (for example \\`[\"aml\"]\\`) and should guide, not constrain,\n tool selection.\n- Save compact artifacts with original graph field names.\n- Put canonical graph JSON in reports/graphs/ and analyst tables in reports/tables/.\n- Markdown reports should summarize and point to graph/table outputs; do not paste large raw JSON blobs into reports.\n- Workspace output must stay in this initialized workspace.\n- Never write artifacts, reports, graph JSON, HTML, schema captures, or logs to ~/.chain-insights.\n- Keep theories lightweight until evidence supports them.\n`\n\nconst CLAUDE = AGENTS\n\nconst CASE_BRIEF = `# Workspace Brief\n\n## Summary\n\nStatus:\nNetwork:\nCurrent Assessment:\n\n## Known Addresses\n\n## Claims To Validate\n\n## Evidence\n\n## Next Steps\n`\n\nconst IMPORTS_README = `# External Investigation Inputs\n\nPut user-provided or third-party material here before turning it into durable\nworkspace outputs.\n\nExamples:\n\n- Exchange support exports\n- CSV extracts\n- Screenshots\n- Raw notes\n- Partner reports\n\nFiles in this directory are inputs, not verified evidence. When an import\nsupports a claim, summarize it into a workspace report or artifact note and\nreference the original file path.\n`\n\nconst TEMPLATES_README = `# Reusable Workspace Templates\n\nStore local report, prompt, artifact, and note templates here.\n\nTemplates are optional workspace helpers. They are not evidence and should not\nbe treated as durable workspace state until copied into an artifact, report,\nentity note, or session note.\n`\n\nconst RUNTIME_SKILL = `---\nname: chain-insights-runtime-schema\ndescription: Workspace-local Chain Insights runtime schema notes. Refresh this after connecting to a graph MCP endpoint.\n---\n\n# Runtime Graph Schema\n\nBefore the first investigation query, capture the live graph schema into:\n\n\\`\\`\\`text\n.chain-insights/schema/<network>.graph-schema.json\n\\`\\`\\`\n\nUse \\`graph_query_batch\\` for schema capture. Prefix topology reads with\n\\`USE topology\\` (address/FLOWS_TO/LINKED graph, unified recent+historical)\nand fact reads with \\`USE facts\\`, for example:\n\n\\`\\`\\`bash\ncia mcp call graph_query_batch network=<network> 'queries=[{\"id\":\"node_labels\",\"query\":\"USE topology MATCH (n:Address) RETURN \\\"Address\\\" AS node_label, count(n) AS sample_count LIMIT 1\"},{\"id\":\"flow_sample\",\"query\":\"USE topology MATCH (:Address)-[f:FLOWS_TO]->(:Address) RETURN f.amount_usd_sum AS amount_usd_sum, f.tx_count AS tx_count LIMIT 20\"},{\"id\":\"linked_sample\",\"query\":\"USE topology MATCH (a:Address)-[l:LINKED]-(b:Address) RETURN a.address AS address, b.address AS linked_address, l.basis AS basis, l.confidence AS confidence LIMIT 20\"}]'\n\\`\\`\\`\n\nThen update this file with observed labels, relationship types, and allowed\nproperty names for the active network.\n\nThe address-grain graph schema:\n\n- Call \\`meta_network_capabilities\\` first. Pass \\`network=\\` exactly as\n GraphRAG advertised it. CIA does not pick a default network.\n Address format follows that network. Every topology node is\n \\`(:Address {address, network})\\`, keyed by the raw chain-native\n \\`address\\`. There is no separate identity key and no member-address\n satellite: the address IS the graph node.\n- \\`(:Address)-[:LINKED]-(:Address)\\` is an **undirected** ownership-overlay\n edge (\\`basis\\` \\`derived\\`/\\`associated\\`, plus \\`confidence\\`,\n \\`source_event\\`, \\`declared_owner\\`) asserting the two addresses are\n controlled by the same actor. \\`LINKED\\` is the ownership edge within the\n advertised network — a same-network query traces\n (\\`LINKED\\` or \\`FLOWS_TO\\`) with no network switch. Walk\n one visible \\`LINKED\\` hop to surface actor-level exposure; never treat\n linked addresses\n as a single collapsed node. \\`LINKED\\` is served on the topology graph\n only.\n- Other Address properties: \\`labels\\` (array) and \\`is_exchange\\`\n (sparse true/null traversal hint). Labels and per-label risk live on the\n address node: \\`label_risk\\` is a list of \\`{label, risk_level,\n updated_timestamp}\\` maps, one per current label row.\n- Address nodes carry a risk verdict for quick triage\n (\\`risk_score\\` float, \\`risk_level\\` string) plus base activity rollups:\n \\`degree_in\\`/\\`degree_out\\`/\\`degree_total\\` (distinct counterparty\n addresses), \\`tx_in_count\\`/\\`tx_out_count\\`/\\`tx_total_count\\`,\n \\`total_in_usd\\`/\\`total_out_usd\\`/\\`total_volume_usd\\`, \\`net_flow_usd\\`\n (in minus out; positive = net receiver) — all computed from external\n flows only — and \\`first_activity_timestamp\\`/\n \\`last_activity_timestamp\\`/\\`activity_span_days\\`, which include all\n flows (self-loops included). FLOWS_TO edges carry \\`tx_count\\`,\n \\`amount_usd_sum\\`, \\`avg_tx_size_usd\\` (understates when\n \\`price_coverage_ratio\\` < 1), \\`first_seen_timestamp\\`/\n \\`last_seen_timestamp\\`, \\`first_tx_id\\`/\\`last_tx_id\\`, and\n \\`price_coverage_ratio\\`.\n Lifetime aggregates are the only serving window.\n- Money flow is \\`(:Address)-[:FLOWS_TO]->(:Address)\\`. Public AML tools\n accept the raw blockchain address directly — there is no resolution step.\n- The risk verdict lives on topology nodes (\\`risk_score\\`/\\`risk_level\\`),\n and labels and per-label risk live on the address node (\\`labels\\` array\n + \\`label_risk\\` entries). \\`USE facts\\` serves bounded individual\n transfer rows and, until P3, address features. Facts address keys match\n topology \\`address\\` values exactly. Do not read \\`ml_*\\`,\n \\`confluence_score\\`, or \\`pattern_flags\\` off topology nodes — those\n properties do not exist.\n- \\`(from:Address)-[t:TRANSFER]->(to:Address)\\` on \\`USE facts\\` returns\n individual transfer rows (not aggregates) from \\`facts_transfers_view\\`,\n with edge properties \\`amount\\`, \\`amount_usd\\`, \\`asset_symbol\\`,\n \\`asset_contract\\`, \\`tx_id\\`, \\`block_height\\`, \\`block_timestamp\\`,\n \\`event_index\\`, \\`edge_index\\`, \\`price_usd\\`, and \\`price_missing\\`.\n Every TRANSFER query (row-select or a \\`count()\\`/\\`sum()\\` aggregate)\n requires an indexed predicate — address equality on either endpoint or\n \\`WHERE t.tx_id = \"...\"\\` — a bare \\`LIMIT\\` alone is rejected. Lifetime\n address metrics (degrees, totals, activity window) are node properties on\n \\`USE topology\\`.\n\nRules:\n\n- Prefer \\`graph_query\\` and \\`graph_query_batch\\` for graph-language reads.\n- The graph choice stays inside the query via \\`USE ...\\`; there is no\n tool argument to select a graph.\n- Use \\`USE topology\\` for topology (the address/FLOWS_TO/LINKED graph,\n covering unified recent and full historical activity in one graph, plus\n the node \\`risk_score\\`/\\`risk_level\\` verdict, and labels + per-label\n risk) and \\`USE facts\\` for features, assets, and enrichment.\n The \\`LINKED\\` ownership overlay is served on the topology graph only.\n- Preserve source schema field names in generated data files.\n- Do not rename, reinterpret, or add unit labels to graph fields unless the\n schema or query result explicitly supports that interpretation.\n- Keep persisted outputs compact: select only the fields needed to support the claim.\n Avoid storing whole node or relationship property blobs unless\n the purpose of the query is schema discovery or debugging.\n- When using BFS, fixed-depth traversal fallbacks, or any manual \\`FLOWS_TO\\`\n traversal, treat exchange hot wallets as terminal endpoints only. Do not\n expand from, through, or classify exchange nodes as deposit, suspect, or\n intermediate candidates. In Cypher, require every non-terminal traversal node\n to satisfy \\`is_exchange IS NULL\\`; only the final exchange endpoint should\n satisfy \\`is_exchange IS NOT NULL\\`.\n- Keep analysis products separate from summary notes: graph JSON belongs under\n \\`reports/graphs/\\`, tabular extracts under \\`reports/tables/\\`, and analyst\n narrative under \\`reports/\\`.\n- Markdown reports should be short provenance records with key facts and\n pointers. Large JSON belongs in \\`reports/tables/\\`, not inline in reports.\n\nAML tool guidance:\n\n1. Use \\`aml_address_risk\\` for single-address enrichment and optional\n comparison with another address.\n2. Use \\`graph_query_batch\\` only when the high-level tools do not answer the\n exact question, and \\`graph_query\\` for single read-only queries.\n\n\\`aml_address_risk\\` takes a raw blockchain address as input directly — there\nis no identity-resolution step — and returns \\`chain-insights.result.v1\\`. Preserve\nfull blockchain addresses in the summary and all workspace artifacts.\n`\n\nconst SCHEMA_README = `# Runtime Schema Captures\n\nStore graph schema captures here, for example:\n\n\\`\\`\\`text\nrobinhood.graph-schema.json\n\\`\\`\\`\n\nSchema captures should be generated before the first graph workflow in a fresh\nworkspace, then referenced by artifacts, reports, and runtime skill notes.\n`\n\nfunction workspaceFiles(workspaceRoot: string): Array<[string, string]> {\n return [\n ['.chain-insights/workspace.json', workspaceJson(workspaceRoot)],\n ['README.md', README],\n ['AGENTS.md', AGENTS],\n ['CLAUDE.md', CLAUDE],\n ['imports/README.md', IMPORTS_README],\n ['templates/README.md', TEMPLATES_README],\n ['templates/workspace-brief.md', CASE_BRIEF],\n ['.chain-insights/runtime-skill/SKILL.md', RUNTIME_SKILL],\n ['.chain-insights/schema/README.md', SCHEMA_README],\n ['.chain-insights/runtime/.keep', ''],\n ['.chain-insights/runtime/logs/.keep', ''],\n ]\n}\n\nasync function assertNoFileCollisions(workspaceRoot: string): Promise<void> {\n for (const [relativePath] of workspaceFiles(workspaceRoot)) {\n const filePath = path.join(workspaceRoot, relativePath)\n try {\n await access(filePath)\n throw new Error(\n `Refusing to overwrite ${filePath}. Re-run with --force to replace workspace files.`\n )\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n continue\n }\n throw err\n }\n }\n}\n\nexport async function initWorkspace(options: InitWorkspaceOptions): Promise<InitWorkspaceResult> {\n const workspaceRoot = path.resolve(options.targetDir)\n if (!options.force) {\n await assertNoFileCollisions(workspaceRoot)\n }\n\n for (const dir of WORKSPACE_DIRS) {\n await mkdir(path.join(workspaceRoot, dir), { recursive: true })\n }\n\n const filesWritten: string[] = []\n const flag = options.force ? 'w' : 'wx'\n for (const [relativePath, content] of workspaceFiles(workspaceRoot)) {\n const filePath = path.join(workspaceRoot, relativePath)\n try {\n await writeFile(filePath, content, { mode: 0o600, flag })\n filesWritten.push(relativePath)\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'EEXIST') {\n throw new Error(\n `Refusing to overwrite ${filePath}. Re-run with --force to replace workspace files.`\n )\n }\n throw err\n }\n }\n\n return { workspaceRoot, filesWritten }\n}\n"],"mappings":";;;;AAcA,MAAM,iBAAiB;CACrB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;AAEA,MAAM,uBAAuB,CAAC,KAAK;AAEnC,SAAS,WAAmB;CAC1B,wBAAO,IAAI,KAAK,EAAA,CAAE,YAAY,CAAC,CAAC,MAAM,GAAG,EAAE;AAC7C;AAEA,SAAS,cAAc,eAA+B;CACpD,OACE,KAAK,UACH;EACE,QAAQ;EACR,MAAM;EACN,gBAAgB;EAChB,iBAAiB;EACjB,oBAAoB;EACpB,eAAe;EACf,aAAa;EACb,aAAa;EACb,eAAe;EACf,cAAc;EACd,YAAY,SAAS;CACvB,GACA,MACA,CACF,IAAI;AAER;AAEA,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiCf,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;AAsBf,MAAM,SAAS;AAEf,MAAM,aAAa;;;;;;;;;;;;;;;;AAiBnB,MAAM,iBAAiB;;;;;;;;;;;;;;;;;AAkBvB,MAAM,mBAAmB;;;;;;;;AASzB,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwHtB,MAAM,gBAAgB;;;;;;;;;;;AAYtB,SAAS,eAAe,eAAgD;CACtE,OAAO;EACL,CAAC,kCAAkC,cAAc,aAAa,CAAC;EAC/D,CAAC,aAAa,MAAM;EACpB,CAAC,aAAa,MAAM;EACpB,CAAC,aAAa,MAAM;EACpB,CAAC,qBAAqB,cAAc;EACpC,CAAC,uBAAuB,gBAAgB;EACxC,CAAC,gCAAgC,UAAU;EAC3C,CAAC,0CAA0C,aAAa;EACxD,CAAC,oCAAoC,aAAa;EAClD,CAAC,iCAAiC,EAAE;EACpC,CAAC,sCAAsC,EAAE;CAC3C;AACF;AAEA,eAAe,uBAAuB,eAAsC;CAC1E,KAAK,MAAM,CAAC,iBAAiB,eAAe,aAAa,GAAG;EAC1D,MAAM,WAAW,KAAK,KAAK,eAAe,YAAY;EACtD,IAAI;GACF,MAAM,OAAO,QAAQ;GACrB,MAAM,IAAI,MACR,yBAAyB,SAAS,kDACpC;EACF,SAAS,KAAK;GACZ,IAAK,IAA8B,SAAS,UAC1C;GAEF,MAAM;EACR;CACF;AACF;AAEA,eAAsB,cAAc,SAA6D;CAC/F,MAAM,gBAAgB,KAAK,QAAQ,QAAQ,SAAS;CACpD,IAAI,CAAC,QAAQ,OACX,MAAM,uBAAuB,aAAa;CAG5C,KAAK,MAAM,OAAO,gBAChB,MAAM,MAAM,KAAK,KAAK,eAAe,GAAG,GAAG,EAAE,WAAW,KAAK,CAAC;CAGhE,MAAM,eAAyB,CAAC;CAChC,MAAM,OAAO,QAAQ,QAAQ,MAAM;CACnC,KAAK,MAAM,CAAC,cAAc,YAAY,eAAe,aAAa,GAAG;EACnE,MAAM,WAAW,KAAK,KAAK,eAAe,YAAY;EACtD,IAAI;GACF,MAAM,UAAU,UAAU,SAAS;IAAE,MAAM;IAAO;GAAK,CAAC;GACxD,aAAa,KAAK,YAAY;EAChC,SAAS,KAAK;GACZ,IAAK,IAA8B,SAAS,UAC1C,MAAM,IAAI,MACR,yBAAyB,SAAS,kDACpC;GAEF,MAAM;EACR;CACF;CAEA,OAAO;EAAE;EAAe;CAAa;AACvC"}
|
|
@@ -6,7 +6,7 @@ const LOOPBACK_HOSTS = /* @__PURE__ */ new Set([
|
|
|
6
6
|
"::1",
|
|
7
7
|
"[::1]"
|
|
8
8
|
]);
|
|
9
|
-
const
|
|
9
|
+
const DEFAULT_GRAPH_MCP_ENDPOINT = "https://mcp.chain-insights.ai/";
|
|
10
10
|
function isLoopbackHost(hostname) {
|
|
11
11
|
const normalized = hostname.toLowerCase().replace(/^\[(.*)\]$/, "$1");
|
|
12
12
|
if (LOOPBACK_HOSTS.has(normalized)) return true;
|
|
@@ -36,6 +36,6 @@ function validateMcpEndpoint(value, key) {
|
|
|
36
36
|
return trimmed;
|
|
37
37
|
}
|
|
38
38
|
//#endregion
|
|
39
|
-
export { graphMcpEndpointEnvOverride as n, validateMcpEndpoint as r,
|
|
39
|
+
export { graphMcpEndpointEnvOverride as n, validateMcpEndpoint as r, DEFAULT_GRAPH_MCP_ENDPOINT as t };
|
|
40
40
|
|
|
41
|
-
//# sourceMappingURL=mcp-endpoint-
|
|
41
|
+
//# sourceMappingURL=mcp-endpoint-Bd3SvCkg.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-endpoint-Bd3SvCkg.mjs","names":[],"sources":["../src/config/mcp-endpoint.ts"],"sourcesContent":["import { isIP } from 'node:net'\n\nconst LOOPBACK_HOSTS = new Set(['localhost', '127.0.0.1', '::1', '[::1]'])\n\nexport const LOCAL_GRAPH_MCP_ENDPOINT = 'http://127.0.0.1:8012/mcp'\nexport const DEFAULT_GRAPH_MCP_ENDPOINT = 'https://mcp.chain-insights.ai/'\n\nfunction isLoopbackHost(hostname: string): boolean {\n const normalized = hostname.toLowerCase().replace(/^\\[(.*)\\]$/, '$1')\n if (LOOPBACK_HOSTS.has(normalized)) return true\n if (isIP(normalized) !== 4) return false\n return normalized.split('.')[0] === '127'\n}\n\nfunction isKubernetesServiceHost(hostname: string): boolean {\n return hostname.toLowerCase().endsWith('.svc.cluster.local')\n}\n\nexport function graphMcpEndpointEnvOverride(): string | undefined {\n const envEndpoint =\n process.env.CHAIN_INSIGHTS_GRAPH_MCP_ENDPOINT?.trim() || process.env.GRAPH_MCP_ENDPOINT?.trim()\n return envEndpoint ? validateMcpEndpoint(envEndpoint, 'graphMcpEndpoint') : undefined\n}\n\nexport function validateMcpEndpoint(value: string, key: string): string {\n const trimmed = value.trim()\n if (!trimmed) {\n throw new Error(`${key} must be a non-empty absolute URL.`)\n }\n\n let parsed: URL\n try {\n parsed = new URL(trimmed)\n } catch {\n throw new Error(\n `${key} must be an absolute URL (example: https://mcp.example.com/mcp or http://127.0.0.1:8012/mcp).`\n )\n }\n\n if (parsed.username || parsed.password) {\n throw new Error(`${key} must not include URL credentials.`)\n }\n if (parsed.search || parsed.hash) {\n throw new Error(`${key} must not include query parameters or URL fragments.`)\n }\n if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:') {\n throw new Error(`${key} must use either https:// or http://.`)\n }\n if (\n parsed.protocol === 'http:' &&\n !isLoopbackHost(parsed.hostname) &&\n !isKubernetesServiceHost(parsed.hostname)\n ) {\n throw new Error(\n `${key} must use https:// for remote hosts. http:// is allowed only for localhost, loopback addresses, or Kubernetes *.svc.cluster.local service DNS.`\n )\n }\n\n return trimmed\n}\n"],"mappings":";;AAEA,MAAM,iCAAiB,IAAI,IAAI;CAAC;CAAa;CAAa;CAAO;AAAO,CAAC;AAGzE,MAAa,6BAA6B;AAE1C,SAAS,eAAe,UAA2B;CACjD,MAAM,aAAa,SAAS,YAAY,CAAC,CAAC,QAAQ,cAAc,IAAI;CACpE,IAAI,eAAe,IAAI,UAAU,GAAG,OAAO;CAC3C,IAAI,KAAK,UAAU,MAAM,GAAG,OAAO;CACnC,OAAO,WAAW,MAAM,GAAG,CAAC,CAAC,OAAO;AACtC;AAEA,SAAS,wBAAwB,UAA2B;CAC1D,OAAO,SAAS,YAAY,CAAC,CAAC,SAAS,oBAAoB;AAC7D;AAEA,SAAgB,8BAAkD;CAChE,MAAM,cACJ,QAAQ,IAAI,mCAAmC,KAAK,KAAK,QAAQ,IAAI,oBAAoB,KAAK;CAChG,OAAO,cAAc,oBAAoB,aAAa,kBAAkB,IAAI,KAAA;AAC9E;AAEA,SAAgB,oBAAoB,OAAe,KAAqB;CACtE,MAAM,UAAU,MAAM,KAAK;CAC3B,IAAI,CAAC,SACH,MAAM,IAAI,MAAM,GAAG,IAAI,mCAAmC;CAG5D,IAAI;CACJ,IAAI;EACF,SAAS,IAAI,IAAI,OAAO;CAC1B,QAAQ;EACN,MAAM,IAAI,MACR,GAAG,IAAI,8FACT;CACF;CAEA,IAAI,OAAO,YAAY,OAAO,UAC5B,MAAM,IAAI,MAAM,GAAG,IAAI,mCAAmC;CAE5D,IAAI,OAAO,UAAU,OAAO,MAC1B,MAAM,IAAI,MAAM,GAAG,IAAI,qDAAqD;CAE9E,IAAI,OAAO,aAAa,YAAY,OAAO,aAAa,SACtD,MAAM,IAAI,MAAM,GAAG,IAAI,sCAAsC;CAE/D,IACE,OAAO,aAAa,WACpB,CAAC,eAAe,OAAO,QAAQ,KAC/B,CAAC,wBAAwB,OAAO,QAAQ,GAExC,MAAM,IAAI,MACR,GAAG,IAAI,+IACT;CAGF,OAAO;AACT"}
|
|
@@ -6,7 +6,7 @@ const LOOPBACK_HOSTS = /* @__PURE__ */ new Set([
|
|
|
6
6
|
"::1",
|
|
7
7
|
"[::1]"
|
|
8
8
|
]);
|
|
9
|
-
const
|
|
9
|
+
const DEFAULT_GRAPH_MCP_ENDPOINT = "https://mcp.chain-insights.ai/";
|
|
10
10
|
function isLoopbackHost(hostname) {
|
|
11
11
|
const normalized = hostname.toLowerCase().replace(/^\[(.*)\]$/, "$1");
|
|
12
12
|
if (LOOPBACK_HOSTS.has(normalized)) return true;
|
|
@@ -36,10 +36,10 @@ function validateMcpEndpoint(value, key) {
|
|
|
36
36
|
return trimmed;
|
|
37
37
|
}
|
|
38
38
|
//#endregion
|
|
39
|
-
Object.defineProperty(exports, "
|
|
39
|
+
Object.defineProperty(exports, "DEFAULT_GRAPH_MCP_ENDPOINT", {
|
|
40
40
|
enumerable: true,
|
|
41
41
|
get: function() {
|
|
42
|
-
return
|
|
42
|
+
return DEFAULT_GRAPH_MCP_ENDPOINT;
|
|
43
43
|
}
|
|
44
44
|
});
|
|
45
45
|
Object.defineProperty(exports, "graphMcpEndpointEnvOverride", {
|
package/dist/mcp-proxy.cjs
CHANGED
|
@@ -482,7 +482,7 @@ async function normalizeRemoteToolResult(result, config, toolName = "remote-grap
|
|
|
482
482
|
const meta = { ...result._meta ?? {} };
|
|
483
483
|
if (graphPayload && includeAttachments) {
|
|
484
484
|
const { writeGraphReport } = await Promise.resolve().then(() => require("./graph-reports-_gqzxvvs.cjs"));
|
|
485
|
-
const { ensureArtifactServer } = await Promise.resolve().then(() => require("./artifact-server-
|
|
485
|
+
const { ensureArtifactServer } = await Promise.resolve().then(() => require("./artifact-server-B8WKXtXr.cjs"));
|
|
486
486
|
const report = await writeGraphReport(graphPayload, {
|
|
487
487
|
serverPort: config.serverPort,
|
|
488
488
|
slug: toolName || "remote-graph"
|
|
@@ -509,7 +509,7 @@ function shouldIncludeAttachments(args, workspaceArtifactsEnabled) {
|
|
|
509
509
|
async function writeLocalGraphMeta(graphData, config, slug, includeAttachments) {
|
|
510
510
|
if (!includeAttachments) return void 0;
|
|
511
511
|
const { writeGraphReport } = await Promise.resolve().then(() => require("./graph-reports-_gqzxvvs.cjs"));
|
|
512
|
-
const { ensureArtifactServer } = await Promise.resolve().then(() => require("./artifact-server-
|
|
512
|
+
const { ensureArtifactServer } = await Promise.resolve().then(() => require("./artifact-server-B8WKXtXr.cjs"));
|
|
513
513
|
const report = await writeGraphReport(graphData, {
|
|
514
514
|
serverPort: config.serverPort,
|
|
515
515
|
slug
|
|
@@ -553,7 +553,7 @@ function jsonTextResult(structuredContent) {
|
|
|
553
553
|
* All diagnostic output goes to console.error() or process.stderr.write().
|
|
554
554
|
*/
|
|
555
555
|
async function createProxy() {
|
|
556
|
-
const { loadConfig } = await Promise.resolve().then(() => require("./config-
|
|
556
|
+
const { loadConfig } = await Promise.resolve().then(() => require("./config-DYiUgdzg.cjs")).then((n) => n.config_exports);
|
|
557
557
|
const { activeDataDir, findActiveWorkspace } = await Promise.resolve().then(() => require("./active-Bc13hJIm.cjs")).then((n) => n.active_exports);
|
|
558
558
|
const { createConfiguredGraphMcpFetch, resolveGraphMcpEndpoint } = await Promise.resolve().then(() => require("./client-CqAzD519.cjs")).then((n) => n.client_exports);
|
|
559
559
|
const { loadSchema, saveSchema } = await Promise.resolve().then(() => require("./schema-cache-n7Gbhvsj.cjs"));
|
package/dist/mcp-proxy.mjs
CHANGED
|
@@ -478,7 +478,7 @@ async function normalizeRemoteToolResult(result, config, toolName = "remote-grap
|
|
|
478
478
|
const meta = { ...result._meta ?? {} };
|
|
479
479
|
if (graphPayload && includeAttachments) {
|
|
480
480
|
const { writeGraphReport } = await import("./graph-reports-B6yoYbPq.mjs");
|
|
481
|
-
const { ensureArtifactServer } = await import("./artifact-server-
|
|
481
|
+
const { ensureArtifactServer } = await import("./artifact-server-C1fETWsc.mjs");
|
|
482
482
|
const report = await writeGraphReport(graphPayload, {
|
|
483
483
|
serverPort: config.serverPort,
|
|
484
484
|
slug: toolName || "remote-graph"
|
|
@@ -505,7 +505,7 @@ function shouldIncludeAttachments(args, workspaceArtifactsEnabled) {
|
|
|
505
505
|
async function writeLocalGraphMeta(graphData, config, slug, includeAttachments) {
|
|
506
506
|
if (!includeAttachments) return void 0;
|
|
507
507
|
const { writeGraphReport } = await import("./graph-reports-B6yoYbPq.mjs");
|
|
508
|
-
const { ensureArtifactServer } = await import("./artifact-server-
|
|
508
|
+
const { ensureArtifactServer } = await import("./artifact-server-C1fETWsc.mjs");
|
|
509
509
|
const report = await writeGraphReport(graphData, {
|
|
510
510
|
serverPort: config.serverPort,
|
|
511
511
|
slug
|
|
@@ -549,7 +549,7 @@ function jsonTextResult(structuredContent) {
|
|
|
549
549
|
* All diagnostic output goes to console.error() or process.stderr.write().
|
|
550
550
|
*/
|
|
551
551
|
async function createProxy() {
|
|
552
|
-
const { loadConfig } = await import("./config-
|
|
552
|
+
const { loadConfig } = await import("./config-DiQs0rQX.mjs").then((n) => n.t);
|
|
553
553
|
const { activeDataDir, findActiveWorkspace } = await import("./active-BQopLul8.mjs").then((n) => n.t);
|
|
554
554
|
const { createConfiguredGraphMcpFetch, resolveGraphMcpEndpoint } = await import("./client-D4aM4bzP.mjs").then((n) => n.r);
|
|
555
555
|
const { loadSchema, saveSchema } = await import("./schema-cache-DJdU4MIP.mjs");
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const require_rolldown_runtime = require("./rolldown-runtime-C0BPl7ul.cjs");
|
|
2
|
-
const require_mcp_endpoint = require("./mcp-endpoint-
|
|
2
|
+
const require_mcp_endpoint = require("./mcp-endpoint-DdIVQKW5.cjs");
|
|
3
3
|
const require_limits = require("./limits-km3pmmL3.cjs");
|
|
4
4
|
let node_path = require("node:path");
|
|
5
5
|
node_path = require_rolldown_runtime.__toESM(node_path, 1);
|
|
@@ -61,7 +61,7 @@ function endpointSchema(key) {
|
|
|
61
61
|
});
|
|
62
62
|
}
|
|
63
63
|
const ConfigSchema = zod.object({
|
|
64
|
-
graphMcpEndpoint: endpointSchema("graphMcpEndpoint").default(require_mcp_endpoint.
|
|
64
|
+
graphMcpEndpoint: endpointSchema("graphMcpEndpoint").default(require_mcp_endpoint.DEFAULT_GRAPH_MCP_ENDPOINT),
|
|
65
65
|
graphMcpAuthToken: zod.string().optional(),
|
|
66
66
|
graphMcpMode: zod.enum(["paid", "debug"]).default("paid"),
|
|
67
67
|
walletAddress: zod.string().optional(),
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
|
|
2
|
-
import { r as validateMcpEndpoint, t as
|
|
2
|
+
import { r as validateMcpEndpoint, t as DEFAULT_GRAPH_MCP_ENDPOINT } from "./mcp-endpoint-Bd3SvCkg.mjs";
|
|
3
3
|
import { n as isLimitKey, r as limitCeiling, t as LIMIT_SPECS } from "./limits-D3Mn-gig.mjs";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import os from "node:os";
|
|
@@ -58,7 +58,7 @@ function endpointSchema(key) {
|
|
|
58
58
|
});
|
|
59
59
|
}
|
|
60
60
|
const ConfigSchema = z.object({
|
|
61
|
-
graphMcpEndpoint: endpointSchema("graphMcpEndpoint").default(
|
|
61
|
+
graphMcpEndpoint: endpointSchema("graphMcpEndpoint").default(DEFAULT_GRAPH_MCP_ENDPOINT),
|
|
62
62
|
graphMcpAuthToken: z.string().optional(),
|
|
63
63
|
graphMcpMode: z.enum(["paid", "debug"]).default("paid"),
|
|
64
64
|
walletAddress: z.string().optional(),
|
|
@@ -92,4 +92,4 @@ const CONFIG_KEYS = [
|
|
|
92
92
|
//#endregion
|
|
93
93
|
export { parseInvestigatorConfig as n, schema_exports as r, DEFAULT_CONFIG as t };
|
|
94
94
|
|
|
95
|
-
//# sourceMappingURL=schema-
|
|
95
|
+
//# sourceMappingURL=schema-v5cwychf.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-v5cwychf.mjs","names":[],"sources":["../src/config/schema.ts"],"sourcesContent":["import * as z from 'zod'\nimport os from 'node:os'\nimport path from 'node:path'\nimport { DEFAULT_GRAPH_MCP_ENDPOINT, validateMcpEndpoint } from './mcp-endpoint.js'\nimport { LIMIT_SPECS, isLimitKey, limitCeiling, type LimitKey } from './limits.js'\n\n// Config-file layer for the tunable search bounds (see config/limits.ts).\n// `limits` applies to every network; `networkLimits.<network>` is more\n// specific and wins over it. Both are validated here so a bad value fails at\n// config load rather than mid-investigation, and an unknown key is rejected\n// outright — a silently ignored knob is indistinguishable from one that had\n// no effect.\nfunction limitBagSchema(network?: string) {\n return z.record(z.string(), z.number()).superRefine((bag, ctx) => {\n for (const [key, value] of Object.entries(bag)) {\n const where = network ? `networkLimits.${network}.${key}` : `limits.${key}`\n if (!isLimitKey(key)) {\n ctx.addIssue({ code: z.ZodIssueCode.custom, message: `${where}: unknown limit key` })\n continue\n }\n const spec = LIMIT_SPECS[key as LimitKey]\n const ceiling = limitCeiling(key as LimitKey, network)\n if (!Number.isInteger(value) || value < spec.min || value > ceiling) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: `${where}: must be an integer between ${spec.min} and ${ceiling} (got ${value})`,\n })\n }\n }\n })\n}\n\nexport const LimitsSchema = limitBagSchema()\n\nexport const NetworkLimitsSchema = z\n .record(z.string(), z.record(z.string(), z.number()))\n .superRefine((byNetwork, ctx) => {\n for (const [network, bag] of Object.entries(byNetwork)) {\n const parsed = limitBagSchema(network).safeParse(bag)\n if (parsed.success) continue\n for (const issue of parsed.error.issues) {\n ctx.addIssue({ code: z.ZodIssueCode.custom, message: issue.message })\n }\n }\n })\n\nfunction endpointSchema(key: 'graphMcpEndpoint') {\n return z.string().transform((value, ctx) => {\n try {\n return validateMcpEndpoint(value, key)\n } catch (err) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: (err as Error).message,\n })\n return z.NEVER\n }\n })\n}\n\nexport const ConfigSchema = z.object({\n graphMcpEndpoint: endpointSchema('graphMcpEndpoint').default(DEFAULT_GRAPH_MCP_ENDPOINT),\n graphMcpAuthToken: z.string().optional(),\n graphMcpMode: z.enum(['paid', 'debug']).default('paid'),\n walletAddress: z.string().optional(),\n serverPort: z.number().int().min(1024).max(65535).default(4321),\n dataDir: z.string().default(path.join(os.homedir(), '.chain-insights')),\n version: z.string().default('1'),\n limits: LimitsSchema.optional(),\n networkLimits: NetworkLimitsSchema.optional(),\n // Paths only. Never store or log certificate or key bytes.\n truthIngressCertPath: z.string().min(1).optional(),\n truthIngressKeyPath: z.string().min(1).optional(),\n truthIngressCaPath: z.string().min(1).optional(),\n})\n\nexport type InvestigatorConfig = z.infer<typeof ConfigSchema>\n\nfunction formatConfigValidationError(error: z.ZodError): string {\n return error.issues.map((issue) => issue.message).join('\\n')\n}\n\nexport function parseInvestigatorConfig(input: unknown): InvestigatorConfig {\n const parsed = ConfigSchema.safeParse(input)\n if (parsed.success) return parsed.data\n throw new Error(formatConfigValidationError(parsed.error))\n}\n\nexport const DEFAULT_CONFIG: InvestigatorConfig = parseInvestigatorConfig({})\n\nexport const CONFIG_KEYS = [\n 'graphMcpEndpoint',\n 'graphMcpAuthToken',\n 'graphMcpMode',\n 'walletAddress',\n 'serverPort',\n 'dataDir',\n 'version',\n // `limits` / `networkLimits` are nested objects, not scalar `cia config set`\n // targets, so they are deliberately absent from CONFIG_KEYS. Edit them in\n // ~/.chain-insights/config.json; they are validated on load.\n] as const\n\nexport type ConfigKey = (typeof CONFIG_KEYS)[number]\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
|
|
2
|
-
import { t as createApp } from "./app-
|
|
2
|
+
import { t as createApp } from "./app-BeZyCVuz.mjs";
|
|
3
3
|
import { serve } from "@hono/node-server";
|
|
4
4
|
//#region src/server/index.ts
|
|
5
5
|
var server_exports = /* @__PURE__ */ __exportAll({ startServer: () => startServer });
|
|
@@ -43,4 +43,4 @@ function startServer(port = 4321) {
|
|
|
43
43
|
//#endregion
|
|
44
44
|
export { startServer as n, server_exports as t };
|
|
45
45
|
|
|
46
|
-
//# sourceMappingURL=server-
|
|
46
|
+
//# sourceMappingURL=server-BDmHAF1w.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server-
|
|
1
|
+
{"version":3,"file":"server-BDmHAF1w.mjs","names":[],"sources":["../src/server/index.ts"],"sourcesContent":["import { serve } from '@hono/node-server'\nimport { createApp } from './app.js'\n\nexport function startServer(port = 4321): () => void {\n const app = createApp()\n const server = serve({\n fetch: app.fetch,\n hostname: '127.0.0.1', // localhost-only — REQUIRED (default 0.0.0.0 is insecure)\n port,\n })\n\n server.on('listening', () => {\n console.log(`Chain Insights server running on http://127.0.0.1:${port}`)\n })\n server.on('error', (err: NodeJS.ErrnoException) => {\n if (err.code === 'EADDRINUSE') {\n process.stderr.write(`Port already in use: 127.0.0.1:${port}\\n`)\n } else {\n process.stderr.write(`Chain Insights server failed: ${err.message}\\n`)\n }\n process.exitCode = 1\n })\n\n let stopped = false\n const stop = (callback?: () => void): void => {\n if (stopped) {\n callback?.()\n return\n }\n stopped = true\n process.off('SIGINT', onSigint)\n process.off('SIGTERM', onSigterm)\n server.close(callback)\n }\n const onSigint = () => {\n stop()\n process.exit(0)\n }\n const onSigterm = () => {\n stop(() => process.exit(0))\n }\n\n process.on('SIGINT', onSigint)\n process.on('SIGTERM', onSigterm)\n\n return stop\n}\n"],"mappings":";;;;;AAGA,SAAgB,YAAY,OAAO,MAAkB;CACnD,MAAM,MAAM,UAAU;CACtB,MAAM,SAAS,MAAM;EACnB,OAAO,IAAI;EACX,UAAU;EACV;CACF,CAAC;CAED,OAAO,GAAG,mBAAmB;EAC3B,QAAQ,IAAI,qDAAqD,MAAM;CACzE,CAAC;CACD,OAAO,GAAG,UAAU,QAA+B;EACjD,IAAI,IAAI,SAAS,cACf,QAAQ,OAAO,MAAM,kCAAkC,KAAK,GAAG;OAE/D,QAAQ,OAAO,MAAM,iCAAiC,IAAI,QAAQ,GAAG;EAEvE,QAAQ,WAAW;CACrB,CAAC;CAED,IAAI,UAAU;CACd,MAAM,QAAQ,aAAgC;EAC5C,IAAI,SAAS;GACX,WAAW;GACX;EACF;EACA,UAAU;EACV,QAAQ,IAAI,UAAU,QAAQ;EAC9B,QAAQ,IAAI,WAAW,SAAS;EAChC,OAAO,MAAM,QAAQ;CACvB;CACA,MAAM,iBAAiB;EACrB,KAAK;EACL,QAAQ,KAAK,CAAC;CAChB;CACA,MAAM,kBAAkB;EACtB,WAAW,QAAQ,KAAK,CAAC,CAAC;CAC5B;CAEA,QAAQ,GAAG,UAAU,QAAQ;CAC7B,QAAQ,GAAG,WAAW,SAAS;CAE/B,OAAO;AACT"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const require_rolldown_runtime = require("./rolldown-runtime-C0BPl7ul.cjs");
|
|
2
|
-
const require_app = require("./app-
|
|
2
|
+
const require_app = require("./app-BHRl5oDo.cjs");
|
|
3
3
|
let _hono_node_server = require("@hono/node-server");
|
|
4
4
|
//#region src/server/index.ts
|
|
5
5
|
var server_exports = /* @__PURE__ */ require_rolldown_runtime.__exportAll({ startServer: () => startServer });
|
package/docs/architecture.md
CHANGED
|
@@ -60,8 +60,9 @@ chain-insights config set graphMcpEndpoint https://mcp.chain-insights.ai/
|
|
|
60
60
|
export CHAIN_INSIGHTS_GRAPH_MCP_ENDPOINT=https://mcp.chain-insights.ai/
|
|
61
61
|
```
|
|
62
62
|
|
|
63
|
-
The runtime default is
|
|
64
|
-
|
|
63
|
+
The runtime default is the hosted production endpoint
|
|
64
|
+
`https://mcp.chain-insights.ai/`. Local loopback
|
|
65
|
+
`http://127.0.0.1:8012/mcp` remains available through explicit configuration.
|
|
65
66
|
|
|
66
67
|
Supported config keys:
|
|
67
68
|
|
package/docs/mcp-proxy.md
CHANGED
|
@@ -27,11 +27,10 @@ The proxy reads the same local Chain Insights config as the CLI.
|
|
|
27
27
|
## Chain Insights Graph Endpoint Configuration
|
|
28
28
|
|
|
29
29
|
The endpoint lives in Chain Insights config, not in the MCP client registration.
|
|
30
|
-
The npm package
|
|
31
|
-
`
|
|
32
|
-
`
|
|
33
|
-
|
|
34
|
-
workspace templates.
|
|
30
|
+
The npm package defaults to public production:
|
|
31
|
+
`https://mcp.chain-insights.ai/` (host root, no `/mcp` path). A fresh install
|
|
32
|
+
can use `cia networks` without endpoint setup. MCP client JSON does not carry
|
|
33
|
+
the endpoint; use Chain Insights config for the default or an override.
|
|
35
34
|
|
|
36
35
|
Set local development:
|
|
37
36
|
|
|
@@ -56,7 +55,7 @@ Configuration precedence:
|
|
|
56
55
|
1. `CHAIN_INSIGHTS_GRAPH_MCP_ENDPOINT`
|
|
57
56
|
2. `GRAPH_MCP_ENDPOINT` legacy alias
|
|
58
57
|
3. saved `graphMcpEndpoint`
|
|
59
|
-
4.
|
|
58
|
+
4. hosted production default `https://mcp.chain-insights.ai/`
|
|
60
59
|
|
|
61
60
|
Validation rules:
|
|
62
61
|
|
|
@@ -64,9 +63,8 @@ Validation rules:
|
|
|
64
63
|
- remote endpoints must use `https://`
|
|
65
64
|
- endpoint URLs with credentials, query strings, or fragments are rejected
|
|
66
65
|
|
|
67
|
-
Keep
|
|
68
|
-
|
|
69
|
-
templates.
|
|
66
|
+
Keep endpoint overrides in operator config or environment variables. Do not
|
|
67
|
+
put endpoint configuration in MCP client JSON.
|
|
70
68
|
|
|
71
69
|
## Behavior
|
|
72
70
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "chain-insights",
|
|
3
|
-
"version": "0.22.
|
|
3
|
+
"version": "0.22.3",
|
|
4
4
|
"description": "AML investigation CLI and MCP proxy for blockchain risk screening, case tracking, workspace reports, and Chain Insights Graph access",
|
|
5
5
|
"homepage": "https://chain-insights.ai",
|
|
6
6
|
"repository": {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"init-Djhml4ih.mjs","names":[],"sources":["../src/workspace/init.ts"],"sourcesContent":["import { access, mkdir, writeFile } from 'node:fs/promises'\nimport path from 'node:path'\nimport { LOCAL_GRAPH_MCP_ENDPOINT } from '../config/mcp-endpoint.js'\n\nexport interface InitWorkspaceOptions {\n targetDir: string\n force?: boolean\n}\n\nexport interface InitWorkspaceResult {\n workspaceRoot: string\n filesWritten: string[]\n}\n\nconst WORKSPACE_DIRS = [\n '.chain-insights',\n '.chain-insights/schema',\n '.chain-insights/runtime',\n '.chain-insights/runtime/logs',\n '.chain-insights/runtime-skill',\n 'artifacts',\n 'entities',\n 'imports',\n 'reports',\n 'reports/graphs',\n 'reports/tables',\n 'sessions',\n 'templates',\n 'published',\n]\n\nconst DEFAULT_DOMAIN_HINTS = ['aml']\n\nfunction todayIso(): string {\n return new Date().toISOString().slice(0, 10)\n}\n\nfunction workspaceJson(workspaceRoot: string): string {\n return (\n JSON.stringify(\n {\n schema: 'chain-insights.workspace.v1',\n name: 'Chain Insights Workspace',\n workspace_root: workspaceRoot,\n default_network: 'robinhood',\n graph_mcp_endpoint: LOCAL_GRAPH_MCP_ENDPOINT,\n artifacts_dir: 'artifacts',\n imports_dir: 'imports',\n reports_dir: 'reports',\n templates_dir: 'templates',\n domain_hints: DEFAULT_DOMAIN_HINTS,\n created_at: todayIso(),\n },\n null,\n 2\n ) + '\\n'\n )\n}\n\nconst README = `# Chain Insights Workspace\n\nThis is a generic Chain Insights workspace.\nUse any editor or agent tooling you want to review reports, artifacts, entity\nnotes, graphs, and published bundles alongside the Chain Insights runtime\nmetadata.\n\n## Start\n\n\\`\\`\\`bash\nchain-insights mcp tools --refresh\nchain-insights wallet ready --check-only\n\\`\\`\\`\n\n## Layout\n\n\\`\\`\\`text\n.chain-insights/ Workspace metadata\nartifacts/ Tool-generated artifacts and durable workspace records\nentities/ Entity notes and indexes\nimports/ External reports, CSVs, screenshots, raw notes\nreports/ Final or interim analyst reports\nreports/graphs/ Graph JSON for visualization\nreports/tables/ Compact tabular extracts\nsessions/ Optional session notes\ntemplates/ Reusable workspace templates\npublished/ Published bundles and handoff-ready exports\n.chain-insights/schema/ Runtime graph schema captures\n.chain-insights/runtime/ Workspace-local runtime process state and debug logs\n.chain-insights/runtime-skill/ Workspace-specific agent schema notes\n\\`\\`\\`\n`\n\nconst AGENTS = `# Agent Instructions\n\nYou are operating inside a Chain Insights workspace.\n\n- Read README.md first.\n- If this directory is not initialized, run \\`cia init .\\` before persistence-producing commands.\n- Do not rerun init in an existing workspace unless replacing scaffolding with \\`--force\\`.\n- Read .chain-insights/runtime-skill/SKILL.md before graph queries.\n- Preserve full blockchain addresses exactly.\n- Do not guess the network for graph queries.\n- Capture or refresh graph schema before the first graph workflow.\n- \\`domain_hints\\` in \\`.chain-insights/workspace.json\\` are optional advisory workflow\n preferences (for example \\`[\"aml\"]\\`) and should guide, not constrain,\n tool selection.\n- Save compact artifacts with original graph field names.\n- Put canonical graph JSON in reports/graphs/ and analyst tables in reports/tables/.\n- Markdown reports should summarize and point to graph/table outputs; do not paste large raw JSON blobs into reports.\n- Workspace output must stay in this initialized workspace.\n- Never write artifacts, reports, graph JSON, HTML, schema captures, or logs to ~/.chain-insights.\n- Keep theories lightweight until evidence supports them.\n`\n\nconst CLAUDE = AGENTS\n\nconst CASE_BRIEF = `# Workspace Brief\n\n## Summary\n\nStatus:\nNetwork:\nCurrent Assessment:\n\n## Known Addresses\n\n## Claims To Validate\n\n## Evidence\n\n## Next Steps\n`\n\nconst IMPORTS_README = `# External Investigation Inputs\n\nPut user-provided or third-party material here before turning it into durable\nworkspace outputs.\n\nExamples:\n\n- Exchange support exports\n- CSV extracts\n- Screenshots\n- Raw notes\n- Partner reports\n\nFiles in this directory are inputs, not verified evidence. When an import\nsupports a claim, summarize it into a workspace report or artifact note and\nreference the original file path.\n`\n\nconst TEMPLATES_README = `# Reusable Workspace Templates\n\nStore local report, prompt, artifact, and note templates here.\n\nTemplates are optional workspace helpers. They are not evidence and should not\nbe treated as durable workspace state until copied into an artifact, report,\nentity note, or session note.\n`\n\nconst RUNTIME_SKILL = `---\nname: chain-insights-runtime-schema\ndescription: Workspace-local Chain Insights runtime schema notes. Refresh this after connecting to a graph MCP endpoint.\n---\n\n# Runtime Graph Schema\n\nBefore the first investigation query, capture the live graph schema into:\n\n\\`\\`\\`text\n.chain-insights/schema/<network>.graph-schema.json\n\\`\\`\\`\n\nUse \\`graph_query_batch\\` for schema capture. Prefix topology reads with\n\\`USE topology\\` (address/FLOWS_TO/LINKED graph, unified recent+historical)\nand fact reads with \\`USE facts\\`, for example:\n\n\\`\\`\\`bash\ncia mcp call graph_query_batch network=<network> 'queries=[{\"id\":\"node_labels\",\"query\":\"USE topology MATCH (n:Address) RETURN \\\"Address\\\" AS node_label, count(n) AS sample_count LIMIT 1\"},{\"id\":\"flow_sample\",\"query\":\"USE topology MATCH (:Address)-[f:FLOWS_TO]->(:Address) RETURN f.amount_usd_sum AS amount_usd_sum, f.tx_count AS tx_count LIMIT 20\"},{\"id\":\"linked_sample\",\"query\":\"USE topology MATCH (a:Address)-[l:LINKED]-(b:Address) RETURN a.address AS address, b.address AS linked_address, l.basis AS basis, l.confidence AS confidence LIMIT 20\"}]'\n\\`\\`\\`\n\nThen update this file with observed labels, relationship types, and allowed\nproperty names for the active network.\n\nThe address-grain graph schema:\n\n- Call \\`meta_network_capabilities\\` first. Pass \\`network=\\` exactly as\n GraphRAG advertised it. CIA does not pick a default network.\n Address format follows that network. Every topology node is\n \\`(:Address {address, network})\\`, keyed by the raw chain-native\n \\`address\\`. There is no separate identity key and no member-address\n satellite: the address IS the graph node.\n- \\`(:Address)-[:LINKED]-(:Address)\\` is an **undirected** ownership-overlay\n edge (\\`basis\\` \\`derived\\`/\\`associated\\`, plus \\`confidence\\`,\n \\`source_event\\`, \\`declared_owner\\`) asserting the two addresses are\n controlled by the same actor. \\`LINKED\\` is the ownership edge within the\n advertised network — a same-network query traces\n (\\`LINKED\\` or \\`FLOWS_TO\\`) with no network switch. Walk\n one visible \\`LINKED\\` hop to surface actor-level exposure; never treat\n linked addresses\n as a single collapsed node. \\`LINKED\\` is served on the topology graph\n only.\n- Other Address properties: \\`labels\\` (array) and \\`is_exchange\\`\n (sparse true/null traversal hint). Labels and per-label risk live on the\n address node: \\`label_risk\\` is a list of \\`{label, risk_level,\n updated_timestamp}\\` maps, one per current label row.\n- Address nodes carry a risk verdict for quick triage\n (\\`risk_score\\` float, \\`risk_level\\` string) plus base activity rollups:\n \\`degree_in\\`/\\`degree_out\\`/\\`degree_total\\` (distinct counterparty\n addresses), \\`tx_in_count\\`/\\`tx_out_count\\`/\\`tx_total_count\\`,\n \\`total_in_usd\\`/\\`total_out_usd\\`/\\`total_volume_usd\\`, \\`net_flow_usd\\`\n (in minus out; positive = net receiver) — all computed from external\n flows only — and \\`first_activity_timestamp\\`/\n \\`last_activity_timestamp\\`/\\`activity_span_days\\`, which include all\n flows (self-loops included). FLOWS_TO edges carry \\`tx_count\\`,\n \\`amount_usd_sum\\`, \\`avg_tx_size_usd\\` (understates when\n \\`price_coverage_ratio\\` < 1), \\`first_seen_timestamp\\`/\n \\`last_seen_timestamp\\`, \\`first_tx_id\\`/\\`last_tx_id\\`, and\n \\`price_coverage_ratio\\`.\n Lifetime aggregates are the only serving window.\n- Money flow is \\`(:Address)-[:FLOWS_TO]->(:Address)\\`. Public AML tools\n accept the raw blockchain address directly — there is no resolution step.\n- The risk verdict lives on topology nodes (\\`risk_score\\`/\\`risk_level\\`),\n and labels and per-label risk live on the address node (\\`labels\\` array\n + \\`label_risk\\` entries). \\`USE facts\\` serves bounded individual\n transfer rows and, until P3, address features. Facts address keys match\n topology \\`address\\` values exactly. Do not read \\`ml_*\\`,\n \\`confluence_score\\`, or \\`pattern_flags\\` off topology nodes — those\n properties do not exist.\n- \\`(from:Address)-[t:TRANSFER]->(to:Address)\\` on \\`USE facts\\` returns\n individual transfer rows (not aggregates) from \\`facts_transfers_view\\`,\n with edge properties \\`amount\\`, \\`amount_usd\\`, \\`asset_symbol\\`,\n \\`asset_contract\\`, \\`tx_id\\`, \\`block_height\\`, \\`block_timestamp\\`,\n \\`event_index\\`, \\`edge_index\\`, \\`price_usd\\`, and \\`price_missing\\`.\n Every TRANSFER query (row-select or a \\`count()\\`/\\`sum()\\` aggregate)\n requires an indexed predicate — address equality on either endpoint or\n \\`WHERE t.tx_id = \"...\"\\` — a bare \\`LIMIT\\` alone is rejected. Lifetime\n address metrics (degrees, totals, activity window) are node properties on\n \\`USE topology\\`.\n\nRules:\n\n- Prefer \\`graph_query\\` and \\`graph_query_batch\\` for graph-language reads.\n- The graph choice stays inside the query via \\`USE ...\\`; there is no\n tool argument to select a graph.\n- Use \\`USE topology\\` for topology (the address/FLOWS_TO/LINKED graph,\n covering unified recent and full historical activity in one graph, plus\n the node \\`risk_score\\`/\\`risk_level\\` verdict, and labels + per-label\n risk) and \\`USE facts\\` for features, assets, and enrichment.\n The \\`LINKED\\` ownership overlay is served on the topology graph only.\n- Preserve source schema field names in generated data files.\n- Do not rename, reinterpret, or add unit labels to graph fields unless the\n schema or query result explicitly supports that interpretation.\n- Keep persisted outputs compact: select only the fields needed to support the claim.\n Avoid storing whole node or relationship property blobs unless\n the purpose of the query is schema discovery or debugging.\n- When using BFS, fixed-depth traversal fallbacks, or any manual \\`FLOWS_TO\\`\n traversal, treat exchange hot wallets as terminal endpoints only. Do not\n expand from, through, or classify exchange nodes as deposit, suspect, or\n intermediate candidates. In Cypher, require every non-terminal traversal node\n to satisfy \\`is_exchange IS NULL\\`; only the final exchange endpoint should\n satisfy \\`is_exchange IS NOT NULL\\`.\n- Keep analysis products separate from summary notes: graph JSON belongs under\n \\`reports/graphs/\\`, tabular extracts under \\`reports/tables/\\`, and analyst\n narrative under \\`reports/\\`.\n- Markdown reports should be short provenance records with key facts and\n pointers. Large JSON belongs in \\`reports/tables/\\`, not inline in reports.\n\nAML tool guidance:\n\n1. Use \\`aml_address_risk\\` for single-address enrichment and optional\n comparison with another address.\n2. Use \\`graph_query_batch\\` only when the high-level tools do not answer the\n exact question, and \\`graph_query\\` for single read-only queries.\n\n\\`aml_address_risk\\` takes a raw blockchain address as input directly — there\nis no identity-resolution step — and returns \\`chain-insights.result.v1\\`. Preserve\nfull blockchain addresses in the summary and all workspace artifacts.\n`\n\nconst SCHEMA_README = `# Runtime Schema Captures\n\nStore graph schema captures here, for example:\n\n\\`\\`\\`text\nrobinhood.graph-schema.json\n\\`\\`\\`\n\nSchema captures should be generated before the first graph workflow in a fresh\nworkspace, then referenced by artifacts, reports, and runtime skill notes.\n`\n\nfunction workspaceFiles(workspaceRoot: string): Array<[string, string]> {\n return [\n ['.chain-insights/workspace.json', workspaceJson(workspaceRoot)],\n ['README.md', README],\n ['AGENTS.md', AGENTS],\n ['CLAUDE.md', CLAUDE],\n ['imports/README.md', IMPORTS_README],\n ['templates/README.md', TEMPLATES_README],\n ['templates/workspace-brief.md', CASE_BRIEF],\n ['.chain-insights/runtime-skill/SKILL.md', RUNTIME_SKILL],\n ['.chain-insights/schema/README.md', SCHEMA_README],\n ['.chain-insights/runtime/.keep', ''],\n ['.chain-insights/runtime/logs/.keep', ''],\n ]\n}\n\nasync function assertNoFileCollisions(workspaceRoot: string): Promise<void> {\n for (const [relativePath] of workspaceFiles(workspaceRoot)) {\n const filePath = path.join(workspaceRoot, relativePath)\n try {\n await access(filePath)\n throw new Error(\n `Refusing to overwrite ${filePath}. Re-run with --force to replace workspace files.`\n )\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n continue\n }\n throw err\n }\n }\n}\n\nexport async function initWorkspace(options: InitWorkspaceOptions): Promise<InitWorkspaceResult> {\n const workspaceRoot = path.resolve(options.targetDir)\n if (!options.force) {\n await assertNoFileCollisions(workspaceRoot)\n }\n\n for (const dir of WORKSPACE_DIRS) {\n await mkdir(path.join(workspaceRoot, dir), { recursive: true })\n }\n\n const filesWritten: string[] = []\n const flag = options.force ? 'w' : 'wx'\n for (const [relativePath, content] of workspaceFiles(workspaceRoot)) {\n const filePath = path.join(workspaceRoot, relativePath)\n try {\n await writeFile(filePath, content, { mode: 0o600, flag })\n filesWritten.push(relativePath)\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'EEXIST') {\n throw new Error(\n `Refusing to overwrite ${filePath}. Re-run with --force to replace workspace files.`\n )\n }\n throw err\n }\n }\n\n return { workspaceRoot, filesWritten }\n}\n"],"mappings":";;;;AAcA,MAAM,iBAAiB;CACrB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;AAEA,MAAM,uBAAuB,CAAC,KAAK;AAEnC,SAAS,WAAmB;CAC1B,wBAAO,IAAI,KAAK,EAAA,CAAE,YAAY,CAAC,CAAC,MAAM,GAAG,EAAE;AAC7C;AAEA,SAAS,cAAc,eAA+B;CACpD,OACE,KAAK,UACH;EACE,QAAQ;EACR,MAAM;EACN,gBAAgB;EAChB,iBAAiB;EACjB,oBAAoB;EACpB,eAAe;EACf,aAAa;EACb,aAAa;EACb,eAAe;EACf,cAAc;EACd,YAAY,SAAS;CACvB,GACA,MACA,CACF,IAAI;AAER;AAEA,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiCf,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;AAsBf,MAAM,SAAS;AAEf,MAAM,aAAa;;;;;;;;;;;;;;;;AAiBnB,MAAM,iBAAiB;;;;;;;;;;;;;;;;;AAkBvB,MAAM,mBAAmB;;;;;;;;AASzB,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwHtB,MAAM,gBAAgB;;;;;;;;;;;AAYtB,SAAS,eAAe,eAAgD;CACtE,OAAO;EACL,CAAC,kCAAkC,cAAc,aAAa,CAAC;EAC/D,CAAC,aAAa,MAAM;EACpB,CAAC,aAAa,MAAM;EACpB,CAAC,aAAa,MAAM;EACpB,CAAC,qBAAqB,cAAc;EACpC,CAAC,uBAAuB,gBAAgB;EACxC,CAAC,gCAAgC,UAAU;EAC3C,CAAC,0CAA0C,aAAa;EACxD,CAAC,oCAAoC,aAAa;EAClD,CAAC,iCAAiC,EAAE;EACpC,CAAC,sCAAsC,EAAE;CAC3C;AACF;AAEA,eAAe,uBAAuB,eAAsC;CAC1E,KAAK,MAAM,CAAC,iBAAiB,eAAe,aAAa,GAAG;EAC1D,MAAM,WAAW,KAAK,KAAK,eAAe,YAAY;EACtD,IAAI;GACF,MAAM,OAAO,QAAQ;GACrB,MAAM,IAAI,MACR,yBAAyB,SAAS,kDACpC;EACF,SAAS,KAAK;GACZ,IAAK,IAA8B,SAAS,UAC1C;GAEF,MAAM;EACR;CACF;AACF;AAEA,eAAsB,cAAc,SAA6D;CAC/F,MAAM,gBAAgB,KAAK,QAAQ,QAAQ,SAAS;CACpD,IAAI,CAAC,QAAQ,OACX,MAAM,uBAAuB,aAAa;CAG5C,KAAK,MAAM,OAAO,gBAChB,MAAM,MAAM,KAAK,KAAK,eAAe,GAAG,GAAG,EAAE,WAAW,KAAK,CAAC;CAGhE,MAAM,eAAyB,CAAC;CAChC,MAAM,OAAO,QAAQ,QAAQ,MAAM;CACnC,KAAK,MAAM,CAAC,cAAc,YAAY,eAAe,aAAa,GAAG;EACnE,MAAM,WAAW,KAAK,KAAK,eAAe,YAAY;EACtD,IAAI;GACF,MAAM,UAAU,UAAU,SAAS;IAAE,MAAM;IAAO;GAAK,CAAC;GACxD,aAAa,KAAK,YAAY;EAChC,SAAS,KAAK;GACZ,IAAK,IAA8B,SAAS,UAC1C,MAAM,IAAI,MACR,yBAAyB,SAAS,kDACpC;GAEF,MAAM;EACR;CACF;CAEA,OAAO;EAAE;EAAe;CAAa;AACvC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-endpoint-DbWtLcba.mjs","names":[],"sources":["../src/config/mcp-endpoint.ts"],"sourcesContent":["import { isIP } from 'node:net'\n\nconst LOOPBACK_HOSTS = new Set(['localhost', '127.0.0.1', '::1', '[::1]'])\n\nexport const LOCAL_GRAPH_MCP_ENDPOINT = 'http://127.0.0.1:8012/mcp'\n\nfunction isLoopbackHost(hostname: string): boolean {\n const normalized = hostname.toLowerCase().replace(/^\\[(.*)\\]$/, '$1')\n if (LOOPBACK_HOSTS.has(normalized)) return true\n if (isIP(normalized) !== 4) return false\n return normalized.split('.')[0] === '127'\n}\n\nfunction isKubernetesServiceHost(hostname: string): boolean {\n return hostname.toLowerCase().endsWith('.svc.cluster.local')\n}\n\nexport function graphMcpEndpointEnvOverride(): string | undefined {\n const envEndpoint =\n process.env.CHAIN_INSIGHTS_GRAPH_MCP_ENDPOINT?.trim() || process.env.GRAPH_MCP_ENDPOINT?.trim()\n return envEndpoint ? validateMcpEndpoint(envEndpoint, 'graphMcpEndpoint') : undefined\n}\n\nexport function validateMcpEndpoint(value: string, key: string): string {\n const trimmed = value.trim()\n if (!trimmed) {\n throw new Error(`${key} must be a non-empty absolute URL.`)\n }\n\n let parsed: URL\n try {\n parsed = new URL(trimmed)\n } catch {\n throw new Error(\n `${key} must be an absolute URL (example: https://mcp.example.com/mcp or http://127.0.0.1:8012/mcp).`\n )\n }\n\n if (parsed.username || parsed.password) {\n throw new Error(`${key} must not include URL credentials.`)\n }\n if (parsed.search || parsed.hash) {\n throw new Error(`${key} must not include query parameters or URL fragments.`)\n }\n if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:') {\n throw new Error(`${key} must use either https:// or http://.`)\n }\n if (\n parsed.protocol === 'http:' &&\n !isLoopbackHost(parsed.hostname) &&\n !isKubernetesServiceHost(parsed.hostname)\n ) {\n throw new Error(\n `${key} must use https:// for remote hosts. http:// is allowed only for localhost, loopback addresses, or Kubernetes *.svc.cluster.local service DNS.`\n )\n }\n\n return trimmed\n}\n"],"mappings":";;AAEA,MAAM,iCAAiB,IAAI,IAAI;CAAC;CAAa;CAAa;CAAO;AAAO,CAAC;AAEzE,MAAa,2BAA2B;AAExC,SAAS,eAAe,UAA2B;CACjD,MAAM,aAAa,SAAS,YAAY,CAAC,CAAC,QAAQ,cAAc,IAAI;CACpE,IAAI,eAAe,IAAI,UAAU,GAAG,OAAO;CAC3C,IAAI,KAAK,UAAU,MAAM,GAAG,OAAO;CACnC,OAAO,WAAW,MAAM,GAAG,CAAC,CAAC,OAAO;AACtC;AAEA,SAAS,wBAAwB,UAA2B;CAC1D,OAAO,SAAS,YAAY,CAAC,CAAC,SAAS,oBAAoB;AAC7D;AAEA,SAAgB,8BAAkD;CAChE,MAAM,cACJ,QAAQ,IAAI,mCAAmC,KAAK,KAAK,QAAQ,IAAI,oBAAoB,KAAK;CAChG,OAAO,cAAc,oBAAoB,aAAa,kBAAkB,IAAI,KAAA;AAC9E;AAEA,SAAgB,oBAAoB,OAAe,KAAqB;CACtE,MAAM,UAAU,MAAM,KAAK;CAC3B,IAAI,CAAC,SACH,MAAM,IAAI,MAAM,GAAG,IAAI,mCAAmC;CAG5D,IAAI;CACJ,IAAI;EACF,SAAS,IAAI,IAAI,OAAO;CAC1B,QAAQ;EACN,MAAM,IAAI,MACR,GAAG,IAAI,8FACT;CACF;CAEA,IAAI,OAAO,YAAY,OAAO,UAC5B,MAAM,IAAI,MAAM,GAAG,IAAI,mCAAmC;CAE5D,IAAI,OAAO,UAAU,OAAO,MAC1B,MAAM,IAAI,MAAM,GAAG,IAAI,qDAAqD;CAE9E,IAAI,OAAO,aAAa,YAAY,OAAO,aAAa,SACtD,MAAM,IAAI,MAAM,GAAG,IAAI,sCAAsC;CAE/D,IACE,OAAO,aAAa,WACpB,CAAC,eAAe,OAAO,QAAQ,KAC/B,CAAC,wBAAwB,OAAO,QAAQ,GAExC,MAAM,IAAI,MACR,GAAG,IAAI,+IACT;CAGF,OAAO;AACT"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"schema-DOJA2nNi.mjs","names":[],"sources":["../src/config/schema.ts"],"sourcesContent":["import * as z from 'zod'\nimport os from 'node:os'\nimport path from 'node:path'\nimport { LOCAL_GRAPH_MCP_ENDPOINT, validateMcpEndpoint } from './mcp-endpoint.js'\nimport { LIMIT_SPECS, isLimitKey, limitCeiling, type LimitKey } from './limits.js'\n\n// Config-file layer for the tunable search bounds (see config/limits.ts).\n// `limits` applies to every network; `networkLimits.<network>` is more\n// specific and wins over it. Both are validated here so a bad value fails at\n// config load rather than mid-investigation, and an unknown key is rejected\n// outright — a silently ignored knob is indistinguishable from one that had\n// no effect.\nfunction limitBagSchema(network?: string) {\n return z.record(z.string(), z.number()).superRefine((bag, ctx) => {\n for (const [key, value] of Object.entries(bag)) {\n const where = network ? `networkLimits.${network}.${key}` : `limits.${key}`\n if (!isLimitKey(key)) {\n ctx.addIssue({ code: z.ZodIssueCode.custom, message: `${where}: unknown limit key` })\n continue\n }\n const spec = LIMIT_SPECS[key as LimitKey]\n const ceiling = limitCeiling(key as LimitKey, network)\n if (!Number.isInteger(value) || value < spec.min || value > ceiling) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: `${where}: must be an integer between ${spec.min} and ${ceiling} (got ${value})`,\n })\n }\n }\n })\n}\n\nexport const LimitsSchema = limitBagSchema()\n\nexport const NetworkLimitsSchema = z\n .record(z.string(), z.record(z.string(), z.number()))\n .superRefine((byNetwork, ctx) => {\n for (const [network, bag] of Object.entries(byNetwork)) {\n const parsed = limitBagSchema(network).safeParse(bag)\n if (parsed.success) continue\n for (const issue of parsed.error.issues) {\n ctx.addIssue({ code: z.ZodIssueCode.custom, message: issue.message })\n }\n }\n })\n\nfunction endpointSchema(key: 'graphMcpEndpoint') {\n return z.string().transform((value, ctx) => {\n try {\n return validateMcpEndpoint(value, key)\n } catch (err) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: (err as Error).message,\n })\n return z.NEVER\n }\n })\n}\n\nexport const ConfigSchema = z.object({\n graphMcpEndpoint: endpointSchema('graphMcpEndpoint').default(LOCAL_GRAPH_MCP_ENDPOINT),\n graphMcpAuthToken: z.string().optional(),\n graphMcpMode: z.enum(['paid', 'debug']).default('paid'),\n walletAddress: z.string().optional(),\n serverPort: z.number().int().min(1024).max(65535).default(4321),\n dataDir: z.string().default(path.join(os.homedir(), '.chain-insights')),\n version: z.string().default('1'),\n limits: LimitsSchema.optional(),\n networkLimits: NetworkLimitsSchema.optional(),\n // Paths only. Never store or log certificate or key bytes.\n truthIngressCertPath: z.string().min(1).optional(),\n truthIngressKeyPath: z.string().min(1).optional(),\n truthIngressCaPath: z.string().min(1).optional(),\n})\n\nexport type InvestigatorConfig = z.infer<typeof ConfigSchema>\n\nfunction formatConfigValidationError(error: z.ZodError): string {\n return error.issues.map((issue) => issue.message).join('\\n')\n}\n\nexport function parseInvestigatorConfig(input: unknown): InvestigatorConfig {\n const parsed = ConfigSchema.safeParse(input)\n if (parsed.success) return parsed.data\n throw new Error(formatConfigValidationError(parsed.error))\n}\n\nexport const DEFAULT_CONFIG: InvestigatorConfig = parseInvestigatorConfig({})\n\nexport const CONFIG_KEYS = [\n 'graphMcpEndpoint',\n 'graphMcpAuthToken',\n 'graphMcpMode',\n 'walletAddress',\n 'serverPort',\n 'dataDir',\n 'version',\n // `limits` / `networkLimits` are nested objects, not scalar `cia config set`\n // targets, so they are deliberately absent from CONFIG_KEYS. Edit them in\n // ~/.chain-insights/config.json; they are validated on load.\n] as const\n\nexport type ConfigKey = (typeof CONFIG_KEYS)[number]\n"],"mappings":";;;;;;;;;;;;;;;AAYA,SAAS,eAAe,SAAkB;CACxC,OAAO,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,aAAa,KAAK,QAAQ;EAChE,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,GAAG,GAAG;GAC9C,MAAM,QAAQ,UAAU,iBAAiB,QAAQ,GAAG,QAAQ,UAAU;GACtE,IAAI,CAAC,WAAW,GAAG,GAAG;IACpB,IAAI,SAAS;KAAE,MAAM,EAAE,aAAa;KAAQ,SAAS,GAAG,MAAM;IAAqB,CAAC;IACpF;GACF;GACA,MAAM,OAAO,YAAY;GACzB,MAAM,UAAU,aAAa,KAAiB,OAAO;GACrD,IAAI,CAAC,OAAO,UAAU,KAAK,KAAK,QAAQ,KAAK,OAAO,QAAQ,SAC1D,IAAI,SAAS;IACX,MAAM,EAAE,aAAa;IACrB,SAAS,GAAG,MAAM,+BAA+B,KAAK,IAAI,OAAO,QAAQ,QAAQ,MAAM;GACzF,CAAC;EAEL;CACF,CAAC;AACH;AAEA,MAAa,eAAe,eAAe;AAE3C,MAAa,sBAAsB,EAChC,OAAO,EAAE,OAAO,GAAG,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,CACpD,aAAa,WAAW,QAAQ;CAC/B,KAAK,MAAM,CAAC,SAAS,QAAQ,OAAO,QAAQ,SAAS,GAAG;EACtD,MAAM,SAAS,eAAe,OAAO,CAAC,CAAC,UAAU,GAAG;EACpD,IAAI,OAAO,SAAS;EACpB,KAAK,MAAM,SAAS,OAAO,MAAM,QAC/B,IAAI,SAAS;GAAE,MAAM,EAAE,aAAa;GAAQ,SAAS,MAAM;EAAQ,CAAC;CAExE;AACF,CAAC;AAEH,SAAS,eAAe,KAAyB;CAC/C,OAAO,EAAE,OAAO,CAAC,CAAC,WAAW,OAAO,QAAQ;EAC1C,IAAI;GACF,OAAO,oBAAoB,OAAO,GAAG;EACvC,SAAS,KAAK;GACZ,IAAI,SAAS;IACX,MAAM,EAAE,aAAa;IACrB,SAAU,IAAc;GAC1B,CAAC;GACD,OAAO,EAAE;EACX;CACF,CAAC;AACH;AAEA,MAAa,eAAe,EAAE,OAAO;CACnC,kBAAkB,eAAe,kBAAkB,CAAC,CAAC,QAAQ,wBAAwB;CACrF,mBAAmB,EAAE,OAAO,CAAC,CAAC,SAAS;CACvC,cAAc,EAAE,KAAK,CAAC,QAAQ,OAAO,CAAC,CAAC,CAAC,QAAQ,MAAM;CACtD,eAAe,EAAE,OAAO,CAAC,CAAC,SAAS;CACnC,YAAY,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,QAAQ,IAAI;CAC9D,SAAS,EAAE,OAAO,CAAC,CAAC,QAAQ,KAAK,KAAK,GAAG,QAAQ,GAAG,iBAAiB,CAAC;CACtE,SAAS,EAAE,OAAO,CAAC,CAAC,QAAQ,GAAG;CAC/B,QAAQ,aAAa,SAAS;CAC9B,eAAe,oBAAoB,SAAS;CAE5C,sBAAsB,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;CACjD,qBAAqB,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;CAChD,oBAAoB,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;AACjD,CAAC;AAID,SAAS,4BAA4B,OAA2B;CAC9D,OAAO,MAAM,OAAO,KAAK,UAAU,MAAM,OAAO,CAAC,CAAC,KAAK,IAAI;AAC7D;AAEA,SAAgB,wBAAwB,OAAoC;CAC1E,MAAM,SAAS,aAAa,UAAU,KAAK;CAC3C,IAAI,OAAO,SAAS,OAAO,OAAO;CAClC,MAAM,IAAI,MAAM,4BAA4B,OAAO,KAAK,CAAC;AAC3D;AAEA,MAAa,iBAAqC,wBAAwB,CAAC,CAAC;AAE5E,MAAa,cAAc;CACzB;CACA;CACA;CACA;CACA;CACA;CACA;AAIF"}
|