chain-insights 0.3.9 → 0.3.18
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 +49 -52
- package/dist/{active-ByNgjuAg.mjs → active-BQopLul8.mjs} +6 -8
- package/dist/active-BQopLul8.mjs.map +1 -0
- package/dist/{active-BVr55kvW.cjs → active-XWv72R1X.cjs} +4 -12
- package/dist/{app-BxojXjtB.cjs → app-DBrqk_iP.cjs} +12 -28
- package/dist/{app-CRd39JJ8.mjs → app-DXwILI_a.mjs} +13 -28
- package/dist/app-DXwILI_a.mjs.map +1 -0
- package/dist/{artifact-server-CP6LXQ9d.mjs → artifact-server-CcmLBv1j.mjs} +2 -2
- package/dist/{artifact-server-CP6LXQ9d.mjs.map → artifact-server-CcmLBv1j.mjs.map} +1 -1
- package/dist/{artifact-server-XbN16DwU.cjs → artifact-server-v0WgTPFT.cjs} +1 -1
- package/dist/{capabilities-BCvkTkIu.mjs → capabilities-CM72SErE.mjs} +2 -2
- package/dist/{capabilities-BCvkTkIu.mjs.map → capabilities-CM72SErE.mjs.map} +1 -1
- package/dist/{capabilities-DOa6EFO-.cjs → capabilities-DGeF-oHc.cjs} +1 -1
- package/dist/cli.cjs +149 -405
- package/dist/cli.mjs +149 -405
- package/dist/cli.mjs.map +1 -1
- package/dist/{client-Y_zqKqJT.cjs → client-BY-56ojr.cjs} +0 -17
- package/dist/{client-BgmHjBHQ.mjs → client-ytTO0mcZ.mjs} +2 -13
- package/dist/{client-BgmHjBHQ.mjs.map → client-ytTO0mcZ.mjs.map} +1 -1
- package/dist/{config-Drgc2HuF.mjs → config-C6zM8Xir.mjs} +3 -3
- package/dist/{config-Drgc2HuF.mjs.map → config-C6zM8Xir.mjs.map} +1 -1
- package/dist/{config-BwVx19Og.cjs → config-CkW404Cs.cjs} +2 -2
- package/dist/{graph-reports-BDELxmpi.mjs → graph-reports-CEq-Mvx0.mjs} +2 -2
- package/dist/{graph-reports-BDELxmpi.mjs.map → graph-reports-CEq-Mvx0.mjs.map} +1 -1
- package/dist/{graph-reports-B3mkLP8Z.cjs → graph-reports-CkglRtg4.cjs} +1 -1
- package/dist/{html-generator-Bx3UcLTB.cjs → html-generator-BFKafL8y.cjs} +5 -6
- package/dist/{html-generator-AowOmzyi.mjs → html-generator-D4fX71hI.mjs} +6 -6
- package/dist/html-generator-D4fX71hI.mjs.map +1 -0
- package/dist/index.cjs +5 -5
- package/dist/index.d.cts +1 -2
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +1 -2
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +5 -5
- package/dist/{init-CKQ6F07J.mjs → init-BGDvGreX.mjs} +52 -55
- package/dist/init-BGDvGreX.mjs.map +1 -0
- package/dist/{init-Dhw8F23z.cjs → init-Cuw9TznI.cjs} +51 -54
- package/dist/{mcp-endpoint-DHs1cRFH.mjs → mcp-endpoint-QQ5Lbqc2.mjs} +5 -2
- package/dist/mcp-endpoint-QQ5Lbqc2.mjs.map +1 -0
- package/dist/{mcp-endpoint-BaV8h_lq.cjs → mcp-endpoint-cQIZSjkK.cjs} +4 -1
- package/dist/mcp-proxy.cjs +650 -771
- package/dist/mcp-proxy.d.cts.map +1 -1
- package/dist/mcp-proxy.d.mts.map +1 -1
- package/dist/mcp-proxy.mjs +651 -772
- package/dist/mcp-proxy.mjs.map +1 -1
- package/dist/{output-root-BRhzhhXZ.mjs → output-root-BK4pdjyz.mjs} +6 -3
- package/dist/output-root-BK4pdjyz.mjs.map +1 -0
- package/dist/{output-root-YIbl6PwF.cjs → output-root-DI0tzA0X.cjs} +5 -2
- package/dist/{public-tools-BY3PTw6x.cjs → public-tools-BREojpU7.cjs} +1244 -426
- package/dist/{public-tools-CvlZcysd.mjs → public-tools-brHmHGYm.mjs} +1240 -428
- package/dist/public-tools-brHmHGYm.mjs.map +1 -0
- package/dist/{schema-BFEWhzg7.mjs → schema-D_qwaQA5.mjs} +2 -2
- package/dist/{schema-BFEWhzg7.mjs.map → schema-D_qwaQA5.mjs.map} +1 -1
- package/dist/{schema-Vl9yuOFO.cjs → schema-Dr6JXSOF.cjs} +1 -1
- package/dist/{server-BXLX2j_A.mjs → server-BK4bfOiv.mjs} +2 -2
- package/dist/{server-BXLX2j_A.mjs.map → server-BK4bfOiv.mjs.map} +1 -1
- package/dist/{server-BqVdWath.cjs → server-ColyTG1t.cjs} +1 -1
- package/dist/templates/graph.html +1 -1
- package/dist/{tool-visibility-Buq7YdUZ.cjs → tool-visibility--QPgrRE5.cjs} +5 -1
- package/dist/{tool-visibility-BpyZHRBi.mjs → tool-visibility-nr6XqO1F.mjs} +6 -2
- package/dist/tool-visibility-nr6XqO1F.mjs.map +1 -0
- package/dist/viz-BBvY-wXz.cjs +210 -0
- package/dist/viz-D8umSF-t.mjs +199 -0
- package/dist/viz-D8umSF-t.mjs.map +1 -0
- package/docs/architecture.md +4 -3
- package/docs/contributing.md +12 -6
- package/docs/graph-tools.md +93 -68
- package/docs/investigation-workspaces.md +38 -124
- package/docs/mcp-proxy.md +23 -34
- package/package.json +2 -2
- package/skills/chain-insights-address-risk/SKILL.md +92 -0
- package/skills/chain-insights-bittensor-cypher/SKILL.md +2 -22
- package/skills/chain-insights-developer-experience/SKILL.md +8 -28
- package/skills/chain-insights-exposure-analysis/SKILL.md +83 -0
- package/skills/chain-insights-investigation/SKILL.md +59 -211
- package/skills/chain-insights-investigation/agents/openai.yaml +1 -1
- package/skills/chain-insights-investigation/scripts/run-target-uat.sh +37 -55
- package/skills/chain-insights-trace-funds/SKILL.md +14 -14
- package/skills/ci-status/SKILL.md +9 -15
- package/skills/test-chain-insights-graphrag-mcp/SKILL.md +5 -4
- package/skills/test-chain-insights-graphrag-mcp/scripts/run-uat.sh +272 -18
- package/dist/active-ByNgjuAg.mjs.map +0 -1
- package/dist/app-CRd39JJ8.mjs.map +0 -1
- package/dist/canvas-Cn-maEIh.mjs +0 -203
- package/dist/canvas-Cn-maEIh.mjs.map +0 -1
- package/dist/canvas-p-oKCMjc.cjs +0 -251
- package/dist/cases-Bz_9XKEw.cjs +0 -19
- package/dist/cases-TVcAifxu.mjs +0 -16
- package/dist/cases-TVcAifxu.mjs.map +0 -1
- package/dist/data-extractor-B4nHw1wZ.mjs +0 -336
- package/dist/data-extractor-B4nHw1wZ.mjs.map +0 -1
- package/dist/data-extractor-DS4rzy3M.cjs +0 -353
- package/dist/dossier-BXy57V4-.cjs +0 -88
- package/dist/dossier-Bjpcbcxa.mjs +0 -78
- package/dist/dossier-Bjpcbcxa.mjs.map +0 -1
- package/dist/evidence-CvEesemA.cjs +0 -200
- package/dist/evidence-D96PTzOQ.mjs +0 -195
- package/dist/evidence-D96PTzOQ.mjs.map +0 -1
- package/dist/export-CBhcJuZ6.mjs +0 -394
- package/dist/export-CBhcJuZ6.mjs.map +0 -1
- package/dist/export-D4v4-6F4.cjs +0 -394
- package/dist/frontmatter-D0ccQnUM.mjs +0 -26
- package/dist/frontmatter-D0ccQnUM.mjs.map +0 -1
- package/dist/frontmatter-Dvqa5HX6.cjs +0 -35
- package/dist/html-generator-AowOmzyi.mjs.map +0 -1
- package/dist/init-CKQ6F07J.mjs.map +0 -1
- package/dist/mcp-endpoint-DHs1cRFH.mjs.map +0 -1
- package/dist/output-root-BRhzhhXZ.mjs.map +0 -1
- package/dist/parser-BXLAHYnZ.cjs +0 -182
- package/dist/parser-CJfMsOl6.mjs +0 -182
- package/dist/parser-CJfMsOl6.mjs.map +0 -1
- package/dist/public-tools-CvlZcysd.mjs.map +0 -1
- package/dist/resolver-2jXNtWQO.mjs +0 -184
- package/dist/resolver-2jXNtWQO.mjs.map +0 -1
- package/dist/resolver-CZdQwKvh.cjs +0 -186
- package/dist/runner-CVnjpqc-.mjs +0 -149
- package/dist/runner-CVnjpqc-.mjs.map +0 -1
- package/dist/runner-bLy0pTr_.cjs +0 -147
- package/dist/selector-BvXM9jbe.mjs +0 -12
- package/dist/selector-BvXM9jbe.mjs.map +0 -1
- package/dist/selector-Dps_ZFxq.cjs +0 -10
- package/dist/session-BT7VpbAd.cjs +0 -127
- package/dist/session-DROyhebe.mjs +0 -117
- package/dist/session-DROyhebe.mjs.map +0 -1
- package/dist/store-C2B_AssI.mjs +0 -231
- package/dist/store-C2B_AssI.mjs.map +0 -1
- package/dist/store-CQhU8dz8.cjs +0 -242
- package/dist/tool-visibility-BpyZHRBi.mjs.map +0 -1
- package/dist/vault-B2y78Ypu.cjs +0 -560
- package/dist/vault-z35Dohdq.mjs +0 -560
- package/dist/vault-z35Dohdq.mjs.map +0 -1
- package/dist/viz-D1620cBX.cjs +0 -44
- package/dist/viz-DB5XFG1z.mjs +0 -35
- package/dist/viz-DB5XFG1z.mjs.map +0 -1
- package/docs/knowledge-exports.md +0 -204
- package/docs/obsidian-vault.md +0 -130
- package/skills/ci-case/SKILL.md +0 -43
package/dist/cli.cjs
CHANGED
|
@@ -29,34 +29,6 @@ if (rawArgs[0] === "mcp" && [
|
|
|
29
29
|
console.error(`error: unknown command '${rawArgs[1]}'`);
|
|
30
30
|
process.exit(1);
|
|
31
31
|
}
|
|
32
|
-
async function resolveCaseSelector(input) {
|
|
33
|
-
const { resolveCaseSelector } = await Promise.resolve().then(() => require("./selector-Dps_ZFxq.cjs"));
|
|
34
|
-
return resolveCaseSelector(input);
|
|
35
|
-
}
|
|
36
|
-
async function scopeCasesToInvocationDir() {
|
|
37
|
-
if (process.env["CHAIN_INSIGHTS_CASES_ROOT"]?.trim()) return;
|
|
38
|
-
const { activeCasesRoot } = await Promise.resolve().then(() => require("./active-BVr55kvW.cjs")).then((n) => n.active_exports);
|
|
39
|
-
process.env["CHAIN_INSIGHTS_CASES_ROOT"] = activeCasesRoot();
|
|
40
|
-
}
|
|
41
|
-
async function showCaseContext(caseSelector) {
|
|
42
|
-
const { CaseStore } = await Promise.resolve().then(() => require("./cases-Bz_9XKEw.cjs")).then((n) => n.cases_exports);
|
|
43
|
-
const caseId = await resolveCaseSelector(caseSelector);
|
|
44
|
-
const ctx = await CaseStore.loadContext(caseId);
|
|
45
|
-
console.log(`\n=== Case: ${ctx.case.id} ===`);
|
|
46
|
-
console.log(`Name: ${ctx.case.name}`);
|
|
47
|
-
console.log(`Status: ${ctx.case.status}`);
|
|
48
|
-
console.log(`Tags: ${ctx.case.tags.join(", ") || "none"}`);
|
|
49
|
-
console.log(`Evidence files: ${ctx.evidenceCount}`);
|
|
50
|
-
console.log(`Dossiers: ${ctx.dossierSummaries.length}`);
|
|
51
|
-
if (ctx.lastSession) {
|
|
52
|
-
console.log(`\n--- Last Session (${ctx.lastSession.sessionId}) ---`);
|
|
53
|
-
console.log(ctx.lastSession.body.slice(0, 500));
|
|
54
|
-
} else console.log("\nNo previous sessions.");
|
|
55
|
-
if (ctx.dossierSummaries.length > 0) {
|
|
56
|
-
console.log("\n--- Entity Dossiers ---");
|
|
57
|
-
for (const d of ctx.dossierSummaries) console.log(` ${d.address} [${d.type}] tags: ${d.riskTags || "none"}`);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
32
|
function optionalNumber(value) {
|
|
61
33
|
if (value === void 0) return void 0;
|
|
62
34
|
const parsed = Number(value);
|
|
@@ -70,9 +42,9 @@ function optionalNumberArg(value, name) {
|
|
|
70
42
|
throw new Error(`Invalid number for ${name}: ${String(value)}`);
|
|
71
43
|
}
|
|
72
44
|
async function withGraphMcpClient(name, fn) {
|
|
73
|
-
const { loadConfig } = await Promise.resolve().then(() => require("./config-
|
|
45
|
+
const { loadConfig } = await Promise.resolve().then(() => require("./config-CkW404Cs.cjs")).then((n) => n.config_exports);
|
|
74
46
|
const config = await loadConfig();
|
|
75
|
-
const { createConfiguredGraphMcpFetch, resolveGraphMcpEndpoint } = await Promise.resolve().then(() => require("./client-
|
|
47
|
+
const { createConfiguredGraphMcpFetch, resolveGraphMcpEndpoint } = await Promise.resolve().then(() => require("./client-BY-56ojr.cjs")).then((n) => n.client_exports);
|
|
76
48
|
const paymentFetch = await createConfiguredGraphMcpFetch(config);
|
|
77
49
|
const { Client } = await import("@modelcontextprotocol/sdk/client/index.js");
|
|
78
50
|
const { StreamableHTTPClientTransport } = await import("@modelcontextprotocol/sdk/client/streamableHttp.js");
|
|
@@ -90,9 +62,51 @@ async function withGraphMcpClient(name, fn) {
|
|
|
90
62
|
function printMcpTextContent(result) {
|
|
91
63
|
for (const item of result.content ?? []) if (item.type === "text") console.log(item.text);
|
|
92
64
|
}
|
|
65
|
+
function addExposureSubjectOptions(command) {
|
|
66
|
+
return command.requiredOption("--network <network>", "Network to query. Run `cia mcp networks` for supported networks.").option("--account <address>", "Account address to inspect").option("--owner <address>", "Owner address to inspect").option("--counterparty <address>", "Counterparty address to inspect").option("--venue <name>", "Optional venue filter, for example Bittensor or Hyperliquid").option("--instrument <id>", "Optional instrument filter, for example a subnet lifecycle id or BTC-PERP").option("--instrument-type <type>", "Optional instrument type filter, for example subnet, perp, spot, vault, or staking").option("--start-timestamp-ms <milliseconds>", "Optional inclusive lower activity timestamp bound").option("--end-timestamp-ms <milliseconds>", "Optional inclusive upper activity timestamp bound").option("--limit <number>", "Maximum exposure rows, default 100, max 500");
|
|
67
|
+
}
|
|
68
|
+
function addExposureMarketOptions(command, requiredInstrument, includeNetwork = true) {
|
|
69
|
+
let configured = command.option("--venue <name>", "Optional venue filter, for example Bittensor or Hyperliquid").option("--market <id>", "Alias for --instrument when using market language").option("--instrument-type <type>", "Optional instrument type filter, for example subnet, perp, spot, vault, or staking").option("--start-timestamp-ms <milliseconds>", "Optional inclusive lower activity timestamp bound").option("--end-timestamp-ms <milliseconds>", "Optional inclusive upper activity timestamp bound").option("--limit <number>", "Maximum exposure rows, default 100, max 500");
|
|
70
|
+
if (includeNetwork) configured = configured.requiredOption("--network <network>", "Network to query. Run `cia mcp networks` for supported networks.");
|
|
71
|
+
return requiredInstrument ? configured.requiredOption("--instrument <id>", "Instrument, market, subnet, hotkey, vault, or durable exposure target identifier to inspect") : configured.option("--instrument <id>", "Instrument, market, subnet, hotkey, vault, or durable exposure target identifier to inspect");
|
|
72
|
+
}
|
|
73
|
+
function buildExposureInsightCommand(name, tool, description) {
|
|
74
|
+
const command = new commander.Command(name).description(description);
|
|
75
|
+
const configured = tool === "exposure_crowding" ? addExposureMarketOptions(command, true) : tool === "exposure_exit_pressure" ? addExposureSubjectOptions(command).option("--market <id>", "Alias for --instrument when using market language") : addExposureSubjectOptions(command);
|
|
76
|
+
if (tool === "exposure_correlation") configured.option("--candidate-accounts <addresses>", "Comma-separated candidate accounts to compare against");
|
|
77
|
+
if (tool === "exposure_explain") configured.option("--market <id>", "Alias for --instrument when using market language").option("--position-id <id>", "Optional venue-native position, trade, stake, rotation, or lifecycle identifier");
|
|
78
|
+
return configured.action(async (opts) => {
|
|
79
|
+
try {
|
|
80
|
+
await withGraphMcpClient(`chain-insights-cli-${name}`, async (client) => {
|
|
81
|
+
const { exposureCarry, exposureCorrelation, exposureCrowding, exposureExitPressure, exposureExplain, exposureQuality } = await Promise.resolve().then(() => require("./public-tools-BREojpU7.cjs"));
|
|
82
|
+
const args = {
|
|
83
|
+
network: opts.network,
|
|
84
|
+
account: opts.account,
|
|
85
|
+
owner: opts.owner,
|
|
86
|
+
counterparty: opts.counterparty,
|
|
87
|
+
venue: opts.venue,
|
|
88
|
+
instrument: opts.instrument,
|
|
89
|
+
market: opts.market,
|
|
90
|
+
instrumentType: opts.instrumentType,
|
|
91
|
+
startTimestampMs: optionalNumber(opts.startTimestampMs),
|
|
92
|
+
endTimestampMs: optionalNumber(opts.endTimestampMs),
|
|
93
|
+
limit: optionalNumber(opts.limit),
|
|
94
|
+
candidateAccounts: opts.candidateAccounts,
|
|
95
|
+
positionId: opts.positionId
|
|
96
|
+
};
|
|
97
|
+
const result = tool === "exposure_quality" ? await exposureQuality(client, args) : tool === "exposure_carry" ? await exposureCarry(client, args) : tool === "exposure_crowding" ? await exposureCrowding(client, args) : tool === "exposure_exit_pressure" ? await exposureExitPressure(client, args) : tool === "exposure_correlation" ? await exposureCorrelation(client, args) : await exposureExplain(client, args);
|
|
98
|
+
console.log(result.summaryText);
|
|
99
|
+
console.log(JSON.stringify(result.structuredContent, null, 2));
|
|
100
|
+
});
|
|
101
|
+
} catch (err) {
|
|
102
|
+
console.error(err.message);
|
|
103
|
+
process.exit(1);
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
}
|
|
93
107
|
async function printNetworkCapabilities(opts) {
|
|
94
|
-
const { loadConfig } = await Promise.resolve().then(() => require("./config-
|
|
95
|
-
const { fetchNetworkCapabilities, formatNetworkCapabilities } = await Promise.resolve().then(() => require("./capabilities-
|
|
108
|
+
const { loadConfig } = await Promise.resolve().then(() => require("./config-CkW404Cs.cjs")).then((n) => n.config_exports);
|
|
109
|
+
const { fetchNetworkCapabilities, formatNetworkCapabilities } = await Promise.resolve().then(() => require("./capabilities-DGeF-oHc.cjs"));
|
|
96
110
|
const document = await fetchNetworkCapabilities(await loadConfig());
|
|
97
111
|
if (opts.json) console.log(JSON.stringify(document, null, 2));
|
|
98
112
|
else console.log(formatNetworkCapabilities(document));
|
|
@@ -107,9 +121,9 @@ program.command("networks").alias("network").description("List supported graph n
|
|
|
107
121
|
});
|
|
108
122
|
program.command("serve").description("Start local visualization server").option("-p, --port <number>", "Port to bind (default: 4321)", "4321").action(async (opts) => {
|
|
109
123
|
try {
|
|
110
|
-
const { requireWorkspaceRoot } = await Promise.resolve().then(() => require("./output-root-
|
|
124
|
+
const { requireWorkspaceRoot } = await Promise.resolve().then(() => require("./output-root-DI0tzA0X.cjs")).then((n) => n.output_root_exports);
|
|
111
125
|
const workspaceRoot = requireWorkspaceRoot();
|
|
112
|
-
const { startServer } = await Promise.resolve().then(() => require("./server-
|
|
126
|
+
const { startServer } = await Promise.resolve().then(() => require("./server-ColyTG1t.cjs")).then((n) => n.server_exports);
|
|
113
127
|
console.log(`Workspace: ${workspaceRoot}`);
|
|
114
128
|
startServer(parseInt(opts.port, 10));
|
|
115
129
|
} catch (err) {
|
|
@@ -118,8 +132,8 @@ program.command("serve").description("Start local visualization server").option(
|
|
|
118
132
|
}
|
|
119
133
|
});
|
|
120
134
|
program.command("status").description("Show toolkit status and configuration").action(async () => {
|
|
121
|
-
const { loadConfig } = await Promise.resolve().then(() => require("./config-
|
|
122
|
-
const { findActiveWorkspace, activeDataDir } = await Promise.resolve().then(() => require("./active-
|
|
135
|
+
const { loadConfig } = await Promise.resolve().then(() => require("./config-CkW404Cs.cjs")).then((n) => n.config_exports);
|
|
136
|
+
const { findActiveWorkspace, activeDataDir } = await Promise.resolve().then(() => require("./active-XWv72R1X.cjs")).then((n) => n.active_exports);
|
|
123
137
|
const config = await loadConfig();
|
|
124
138
|
const workspace = findActiveWorkspace();
|
|
125
139
|
const graphMcpStatus = config.graphMcpMode === "debug" && config.graphMcpAuthToken?.trim() ? "bearer access mode" : `${config.graphMcpMode} mode`;
|
|
@@ -154,28 +168,9 @@ program.command("update").description("Check npmjs for a newer Chain Insights re
|
|
|
154
168
|
process.exit(1);
|
|
155
169
|
}
|
|
156
170
|
});
|
|
157
|
-
program.command("obsidian").description("Manage the local Obsidian investigation vault").addCommand(new commander.Command("open").description("Open the current Chain Insights vault in Obsidian").argument("[path]", "Workspace path to open as an Obsidian vault").action(async (workspacePath) => {
|
|
158
|
-
try {
|
|
159
|
-
const { findActiveWorkspace } = await Promise.resolve().then(() => require("./active-BVr55kvW.cjs")).then((n) => n.active_exports);
|
|
160
|
-
const workspace = workspacePath ? node_path.default.resolve(workspacePath) : findActiveWorkspace()?.root;
|
|
161
|
-
if (!workspace) {
|
|
162
|
-
console.error("No Chain Insights workspace found. Run: cia init .");
|
|
163
|
-
process.exit(1);
|
|
164
|
-
}
|
|
165
|
-
const open = (await import("open")).default;
|
|
166
|
-
await open(workspace, {
|
|
167
|
-
app: { name: "obsidian" },
|
|
168
|
-
wait: false
|
|
169
|
-
});
|
|
170
|
-
} catch (err) {
|
|
171
|
-
console.error(err.message);
|
|
172
|
-
console.error("Open Obsidian manually and choose \"Open folder as vault\" for this workspace.");
|
|
173
|
-
process.exit(1);
|
|
174
|
-
}
|
|
175
|
-
}));
|
|
176
171
|
program.command("debug").description("Configure Graph MCP debug mode").addCommand(new commander.Command("on").description("Enable Graph MCP debug mode without x402 payments").requiredOption("--token <token>", "Debug bearer token").option("--endpoint <url>", "Graph MCP endpoint").action(async (opts) => {
|
|
177
172
|
try {
|
|
178
|
-
const { saveConfig } = await Promise.resolve().then(() => require("./config-
|
|
173
|
+
const { saveConfig } = await Promise.resolve().then(() => require("./config-CkW404Cs.cjs")).then((n) => n.config_exports);
|
|
179
174
|
await saveConfig({
|
|
180
175
|
graphMcpMode: "debug",
|
|
181
176
|
graphMcpAuthToken: opts.token,
|
|
@@ -190,7 +185,7 @@ program.command("debug").description("Configure Graph MCP debug mode").addComman
|
|
|
190
185
|
}
|
|
191
186
|
})).addCommand(new commander.Command("off").description("Disable Graph MCP debug mode and use paid x402 calls").action(async () => {
|
|
192
187
|
try {
|
|
193
|
-
const { saveConfig } = await Promise.resolve().then(() => require("./config-
|
|
188
|
+
const { saveConfig } = await Promise.resolve().then(() => require("./config-CkW404Cs.cjs")).then((n) => n.config_exports);
|
|
194
189
|
await saveConfig({
|
|
195
190
|
graphMcpMode: "paid",
|
|
196
191
|
graphMcpAuthToken: ""
|
|
@@ -203,7 +198,7 @@ program.command("debug").description("Configure Graph MCP debug mode").addComman
|
|
|
203
198
|
}
|
|
204
199
|
})).addCommand(new commander.Command("status").description("Show Graph MCP payment/debug mode").action(async () => {
|
|
205
200
|
try {
|
|
206
|
-
const { loadConfig } = await Promise.resolve().then(() => require("./config-
|
|
201
|
+
const { loadConfig } = await Promise.resolve().then(() => require("./config-CkW404Cs.cjs")).then((n) => n.config_exports);
|
|
207
202
|
const config = await loadConfig();
|
|
208
203
|
console.log(`Graph MCP mode: ${config.graphMcpMode}`);
|
|
209
204
|
console.log(`Graph endpoint: ${config.graphMcpEndpoint}`);
|
|
@@ -218,7 +213,7 @@ program.command("access-key").description("Configure Graph MCP test access key m
|
|
|
218
213
|
try {
|
|
219
214
|
const normalizedKey = key.trim();
|
|
220
215
|
if (!normalizedKey) throw new Error("Test access key is required");
|
|
221
|
-
const { saveConfig } = await Promise.resolve().then(() => require("./config-
|
|
216
|
+
const { saveConfig } = await Promise.resolve().then(() => require("./config-CkW404Cs.cjs")).then((n) => n.config_exports);
|
|
222
217
|
await saveConfig({
|
|
223
218
|
graphMcpMode: "debug",
|
|
224
219
|
graphMcpAuthToken: normalizedKey,
|
|
@@ -233,7 +228,7 @@ program.command("access-key").description("Configure Graph MCP test access key m
|
|
|
233
228
|
}
|
|
234
229
|
})).addCommand(new commander.Command("clear").description("Remove the Graph MCP test access key and use paid x402 calls").action(async () => {
|
|
235
230
|
try {
|
|
236
|
-
const { saveConfig } = await Promise.resolve().then(() => require("./config-
|
|
231
|
+
const { saveConfig } = await Promise.resolve().then(() => require("./config-CkW404Cs.cjs")).then((n) => n.config_exports);
|
|
237
232
|
await saveConfig({
|
|
238
233
|
graphMcpMode: "paid",
|
|
239
234
|
graphMcpAuthToken: ""
|
|
@@ -246,7 +241,7 @@ program.command("access-key").description("Configure Graph MCP test access key m
|
|
|
246
241
|
}
|
|
247
242
|
})).addCommand(new commander.Command("status").description("Show Graph MCP test access key status").action(async () => {
|
|
248
243
|
try {
|
|
249
|
-
const { loadConfig } = await Promise.resolve().then(() => require("./config-
|
|
244
|
+
const { loadConfig } = await Promise.resolve().then(() => require("./config-CkW404Cs.cjs")).then((n) => n.config_exports);
|
|
250
245
|
const config = await loadConfig();
|
|
251
246
|
console.log(`Graph endpoint: ${config.graphMcpEndpoint}`);
|
|
252
247
|
console.log(`Access key: ${config.graphMcpAuthToken?.trim() ? "configured" : "not configured"}`);
|
|
@@ -258,7 +253,7 @@ program.command("access-key").description("Configure Graph MCP test access key m
|
|
|
258
253
|
}));
|
|
259
254
|
program.command("init").description("Initialize an investigation workspace").argument("[dir]", "Workspace directory to initialize", ".").option("--force", "Overwrite existing workspace files").action(async (dir, opts) => {
|
|
260
255
|
try {
|
|
261
|
-
const { initWorkspace } = await Promise.resolve().then(() => require("./init-
|
|
256
|
+
const { initWorkspace } = await Promise.resolve().then(() => require("./init-Cuw9TznI.cjs"));
|
|
262
257
|
const result = await initWorkspace({
|
|
263
258
|
targetDir: dir,
|
|
264
259
|
force: opts.force
|
|
@@ -295,8 +290,8 @@ program.command("setup").description("Configure external MCP clients").addComman
|
|
|
295
290
|
}
|
|
296
291
|
}));
|
|
297
292
|
program.command("config").description("Read or write configuration values").addCommand(new commander.Command("get").argument("<key>", "Config key to read").action(async (key) => {
|
|
298
|
-
const { loadConfig } = await Promise.resolve().then(() => require("./config-
|
|
299
|
-
const { CONFIG_KEYS } = await Promise.resolve().then(() => require("./schema-
|
|
293
|
+
const { loadConfig } = await Promise.resolve().then(() => require("./config-CkW404Cs.cjs")).then((n) => n.config_exports);
|
|
294
|
+
const { CONFIG_KEYS } = await Promise.resolve().then(() => require("./schema-Dr6JXSOF.cjs")).then((n) => n.schema_exports);
|
|
300
295
|
if (!CONFIG_KEYS.includes(key)) {
|
|
301
296
|
console.error(`Unknown config key: ${key}`);
|
|
302
297
|
process.exit(1);
|
|
@@ -316,8 +311,8 @@ program.command("config").description("Read or write configuration values").addC
|
|
|
316
311
|
}
|
|
317
312
|
return;
|
|
318
313
|
}
|
|
319
|
-
const { loadConfig, saveConfig } = await Promise.resolve().then(() => require("./config-
|
|
320
|
-
const { CONFIG_KEYS, DEFAULT_CONFIG } = await Promise.resolve().then(() => require("./schema-
|
|
314
|
+
const { loadConfig, saveConfig } = await Promise.resolve().then(() => require("./config-CkW404Cs.cjs")).then((n) => n.config_exports);
|
|
315
|
+
const { CONFIG_KEYS, DEFAULT_CONFIG } = await Promise.resolve().then(() => require("./schema-Dr6JXSOF.cjs")).then((n) => n.schema_exports);
|
|
321
316
|
const current = await loadConfig();
|
|
322
317
|
if (!CONFIG_KEYS.includes(key)) {
|
|
323
318
|
console.error(`Unknown config key: ${key}`);
|
|
@@ -408,9 +403,9 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
|
|
|
408
403
|
try {
|
|
409
404
|
const { loadSchema, saveSchema } = await Promise.resolve().then(() => require("./schema-cache-CJk1EL3L.cjs"));
|
|
410
405
|
const { formatToolsTable } = await Promise.resolve().then(() => require("./format-9NLBykEL.cjs"));
|
|
411
|
-
const { visibleRemoteTools } = await Promise.resolve().then(() => require("./tool-visibility
|
|
412
|
-
const { loadConfig } = await Promise.resolve().then(() => require("./config-
|
|
413
|
-
const { createConfiguredGraphMcpFetch, resolveGraphMcpEndpoint } = await Promise.resolve().then(() => require("./client-
|
|
406
|
+
const { visibleRemoteTools } = await Promise.resolve().then(() => require("./tool-visibility--QPgrRE5.cjs")).then((n) => n.tool_visibility_exports);
|
|
407
|
+
const { loadConfig } = await Promise.resolve().then(() => require("./config-CkW404Cs.cjs")).then((n) => n.config_exports);
|
|
408
|
+
const { createConfiguredGraphMcpFetch, resolveGraphMcpEndpoint } = await Promise.resolve().then(() => require("./client-BY-56ojr.cjs")).then((n) => n.client_exports);
|
|
414
409
|
const config = await loadConfig();
|
|
415
410
|
const graphMcpEndpoint = resolveGraphMcpEndpoint(config);
|
|
416
411
|
let tools = opts.refresh ? null : await loadSchema(graphMcpEndpoint);
|
|
@@ -435,12 +430,12 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
|
|
|
435
430
|
console.error(err.message);
|
|
436
431
|
process.exit(1);
|
|
437
432
|
}
|
|
438
|
-
})).addCommand(new commander.Command("address-risk").description("Screen an address for risk, exchange behavior, and optional compare_address connection risk").requiredOption("--address <address>", "Full blockchain address to screen").requiredOption("--network <network>", "Network to query. Run `cia mcp networks` for supported networks.").option("--compare-address <address>", "Optional second address for connection-risk compare mode").option("--remote", "Force remote MCP tool call instead of local Chain Insights recipe").action(async (opts) => {
|
|
433
|
+
})).addCommand(new commander.Command("aml-address-risk").description("Screen an address for risk, exchange behavior, and optional compare_address connection risk").requiredOption("--address <address>", "Full blockchain address to screen").requiredOption("--network <network>", "Network to query. Run `cia mcp networks` for supported networks.").option("--compare-address <address>", "Optional second address for connection-risk compare mode").option("--remote", "Force remote MCP tool call instead of local Chain Insights recipe").action(async (opts) => {
|
|
439
434
|
try {
|
|
440
|
-
await withGraphMcpClient("chain-insights-cli-address-risk", async (client) => {
|
|
435
|
+
await withGraphMcpClient("chain-insights-cli-aml-address-risk", async (client) => {
|
|
441
436
|
if (opts.remote) {
|
|
442
437
|
printMcpTextContent(await client.callTool({
|
|
443
|
-
name: "
|
|
438
|
+
name: "aml_address_risk",
|
|
444
439
|
arguments: {
|
|
445
440
|
address: opts.address,
|
|
446
441
|
network: opts.network,
|
|
@@ -449,7 +444,7 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
|
|
|
449
444
|
}));
|
|
450
445
|
return;
|
|
451
446
|
}
|
|
452
|
-
const { addressRisk } = await Promise.resolve().then(() => require("./public-tools-
|
|
447
|
+
const { addressRisk } = await Promise.resolve().then(() => require("./public-tools-BREojpU7.cjs"));
|
|
453
448
|
const result = await addressRisk(client, {
|
|
454
449
|
address: opts.address,
|
|
455
450
|
network: opts.network,
|
|
@@ -461,14 +456,14 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
|
|
|
461
456
|
console.error(err.message);
|
|
462
457
|
process.exit(1);
|
|
463
458
|
}
|
|
464
|
-
})).addCommand(new commander.Command("trace-victim-funds").description("Trace victim/source addresses forward to exchange deposit candidates").requiredOption("--victim-addresses <addresses>", "Comma-separated full victim/source addresses, max 5").requiredOption("--network <network>", "Network to query. Run `cia mcp networks` for supported networks.").option("--known-suspect-addresses <addresses>", "Optional known suspect addresses for context only, max 5").option("--
|
|
459
|
+
})).addCommand(new commander.Command("aml-trace-victim-funds").description("Trace victim/source addresses forward to exchange deposit candidates").requiredOption("--victim-addresses <addresses>", "Comma-separated full victim/source addresses, max 5").requiredOption("--network <network>", "Network to query. Run `cia mcp networks` for supported networks.").option("--known-suspect-addresses <addresses>", "Optional known suspect addresses for context only, max 5").option("--incident-timestamp-ms <milliseconds>", "Optional incident timestamp in milliseconds").option("--max-hops <number>", "Maximum trace hops, 1-5").option("--per-address-limit <number>", "Maximum exchange paths/results per address, 1-10").option("--min-amount-sum <number>", "Minimum r.amount_sum for traced edges").option("--remote", "Force remote MCP tool call instead of local Chain Insights recipe").action(async (opts) => {
|
|
465
460
|
try {
|
|
466
|
-
const { requireWorkspaceRoot } = await Promise.resolve().then(() => require("./output-root-
|
|
461
|
+
const { requireWorkspaceRoot } = await Promise.resolve().then(() => require("./output-root-DI0tzA0X.cjs")).then((n) => n.output_root_exports);
|
|
467
462
|
requireWorkspaceRoot();
|
|
468
|
-
await withGraphMcpClient("chain-insights-cli-trace-victim-funds", async (client, config) => {
|
|
463
|
+
await withGraphMcpClient("chain-insights-cli-aml-trace-victim-funds", async (client, config) => {
|
|
469
464
|
if (opts.remote) {
|
|
470
465
|
printMcpTextContent(await client.callTool({
|
|
471
|
-
name: "
|
|
466
|
+
name: "aml_trace_victim_funds",
|
|
472
467
|
arguments: {
|
|
473
468
|
victim_addresses: opts.victimAddresses,
|
|
474
469
|
network: opts.network,
|
|
@@ -477,13 +472,11 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
|
|
|
477
472
|
}));
|
|
478
473
|
return;
|
|
479
474
|
}
|
|
480
|
-
const { traceVictimFunds } = await Promise.resolve().then(() => require("./public-tools-
|
|
481
|
-
const caseId = opts.case ? await resolveCaseSelector(opts.case) : void 0;
|
|
475
|
+
const { traceVictimFunds } = await Promise.resolve().then(() => require("./public-tools-BREojpU7.cjs"));
|
|
482
476
|
const result = await traceVictimFunds(client, config, {
|
|
483
477
|
victimAddresses: opts.victimAddresses,
|
|
484
478
|
knownSuspectAddresses: opts.knownSuspectAddresses,
|
|
485
479
|
network: opts.network,
|
|
486
|
-
caseId,
|
|
487
480
|
incidentTimestampMs: optionalNumber(opts.incidentTimestampMs),
|
|
488
481
|
maxHops: optionalNumber(opts.maxHops),
|
|
489
482
|
perAddressLimit: optionalNumber(opts.perAddressLimit),
|
|
@@ -496,21 +489,19 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
|
|
|
496
489
|
console.error(err.message);
|
|
497
490
|
process.exit(1);
|
|
498
491
|
}
|
|
499
|
-
})).addCommand(new commander.Command("trace-suspect-funds").description("Trace suspected scammer, mule, operator, or laundering-ring addresses forward to cashout topology").requiredOption("--network <network>", "Network to query. Run `cia mcp networks` for supported networks.").requiredOption("--suspect-addresses <addresses>", "Comma-separated full suspect-controlled addresses, max 5").option("--incident-timestamp-ms <milliseconds>", "Optional incident timestamp in milliseconds").option("--max-hops <number>", "Maximum trace hops, default 3, max 5").option("--per-address-limit <number>", "Maximum exchange paths/results per address, 1-10").option("--min-amount-sum <number>", "Minimum r.amount_sum for traced edges").
|
|
492
|
+
})).addCommand(new commander.Command("aml-trace-suspect-funds").description("Trace suspected scammer, mule, operator, or laundering-ring addresses forward to cashout topology").requiredOption("--network <network>", "Network to query. Run `cia mcp networks` for supported networks.").requiredOption("--suspect-addresses <addresses>", "Comma-separated full suspect-controlled addresses, max 5").option("--incident-timestamp-ms <milliseconds>", "Optional incident timestamp in milliseconds").option("--max-hops <number>", "Maximum trace hops, default 3, max 5").option("--per-address-limit <number>", "Maximum exchange paths/results per address, 1-10").option("--min-amount-sum <number>", "Minimum r.amount_sum for traced edges").action(async (opts) => {
|
|
500
493
|
try {
|
|
501
|
-
const { requireWorkspaceRoot } = await Promise.resolve().then(() => require("./output-root-
|
|
494
|
+
const { requireWorkspaceRoot } = await Promise.resolve().then(() => require("./output-root-DI0tzA0X.cjs")).then((n) => n.output_root_exports);
|
|
502
495
|
requireWorkspaceRoot();
|
|
503
|
-
await withGraphMcpClient("chain-insights-cli-trace-suspect-funds", async (client, config) => {
|
|
504
|
-
const { traceSuspectFunds } = await Promise.resolve().then(() => require("./public-tools-
|
|
505
|
-
const caseId = opts.case ? await resolveCaseSelector(opts.case) : void 0;
|
|
496
|
+
await withGraphMcpClient("chain-insights-cli-aml-trace-suspect-funds", async (client, config) => {
|
|
497
|
+
const { traceSuspectFunds } = await Promise.resolve().then(() => require("./public-tools-BREojpU7.cjs"));
|
|
506
498
|
const result = await traceSuspectFunds(client, config, {
|
|
507
499
|
suspectAddresses: opts.suspectAddresses,
|
|
508
500
|
network: opts.network,
|
|
509
501
|
maxHops: optionalNumber(opts.maxHops),
|
|
510
502
|
perAddressLimit: optionalNumber(opts.perAddressLimit),
|
|
511
503
|
minAmountSum: optionalNumber(opts.minAmountSum),
|
|
512
|
-
incidentTimestampMs: optionalNumber(opts.incidentTimestampMs)
|
|
513
|
-
caseId
|
|
504
|
+
incidentTimestampMs: optionalNumber(opts.incidentTimestampMs)
|
|
514
505
|
});
|
|
515
506
|
console.log(result.summaryText);
|
|
516
507
|
console.log(JSON.stringify(result.structuredContent, null, 2));
|
|
@@ -519,18 +510,16 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
|
|
|
519
510
|
console.error(err.message);
|
|
520
511
|
process.exit(1);
|
|
521
512
|
}
|
|
522
|
-
})).addCommand(new commander.Command("trace-deposit-sources").description("Trace backward from suspected deposit/cashout addresses to upstream sources and convergence").requiredOption("--network <network>", "Network to query. Run `cia mcp networks` for supported networks.").requiredOption("--deposit-addresses <addresses>", "Comma-separated full suspected deposit/cashout addresses, max 5").option("--max-hops <number>", "Maximum reverse traceback hops, default 2, max 5").
|
|
513
|
+
})).addCommand(new commander.Command("aml-trace-deposit-sources").description("Trace backward from suspected deposit/cashout addresses to upstream sources and convergence").requiredOption("--network <network>", "Network to query. Run `cia mcp networks` for supported networks.").requiredOption("--deposit-addresses <addresses>", "Comma-separated full suspected deposit/cashout addresses, max 5").option("--max-hops <number>", "Maximum reverse traceback hops, default 2, max 5").action(async (opts) => {
|
|
523
514
|
try {
|
|
524
|
-
const { requireWorkspaceRoot } = await Promise.resolve().then(() => require("./output-root-
|
|
515
|
+
const { requireWorkspaceRoot } = await Promise.resolve().then(() => require("./output-root-DI0tzA0X.cjs")).then((n) => n.output_root_exports);
|
|
525
516
|
requireWorkspaceRoot();
|
|
526
|
-
await withGraphMcpClient("chain-insights-cli-trace-deposit-sources", async (client, config) => {
|
|
527
|
-
const { traceDepositSources } = await Promise.resolve().then(() => require("./public-tools-
|
|
528
|
-
const caseId = opts.case ? await resolveCaseSelector(opts.case) : void 0;
|
|
517
|
+
await withGraphMcpClient("chain-insights-cli-aml-trace-deposit-sources", async (client, config) => {
|
|
518
|
+
const { traceDepositSources } = await Promise.resolve().then(() => require("./public-tools-BREojpU7.cjs"));
|
|
529
519
|
const result = await traceDepositSources(client, config, {
|
|
530
520
|
depositAddresses: opts.depositAddresses,
|
|
531
521
|
network: opts.network,
|
|
532
|
-
maxHops: optionalNumber(opts.maxHops)
|
|
533
|
-
caseId
|
|
522
|
+
maxHops: optionalNumber(opts.maxHops)
|
|
534
523
|
});
|
|
535
524
|
console.log(result.summaryText);
|
|
536
525
|
console.log(JSON.stringify(result.structuredContent, null, 2));
|
|
@@ -539,21 +528,21 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
|
|
|
539
528
|
console.error(err.message);
|
|
540
529
|
process.exit(1);
|
|
541
530
|
}
|
|
542
|
-
})).addCommand(new commander.Command("
|
|
531
|
+
})).addCommand(new commander.Command("exposure-profile").description("Explain staking or trading exposure around one account, owner, or counterparty").requiredOption("--network <network>", "Network to query. Run `cia mcp networks` for supported networks.").option("--account <address>", "Account address to inspect").option("--owner <address>", "Owner address to inspect").option("--counterparty <address>", "Counterparty address to inspect").option("--venue <name>", "Optional venue filter, for example Bittensor or Hyperliquid").option("--instrument <id>", "Optional instrument filter, for example a subnet lifecycle id or BTC-PERP").option("--instrument-type <type>", "Optional instrument type filter, for example subnet, perp, spot, vault, or staking").option("--start-timestamp-ms <milliseconds>", "Optional inclusive lower activity timestamp bound").option("--end-timestamp-ms <milliseconds>", "Optional inclusive upper activity timestamp bound").option("--limit <number>", "Maximum exposure rows, default 100, max 500").action(async (opts) => {
|
|
543
532
|
try {
|
|
544
|
-
await withGraphMcpClient("chain-insights-cli-
|
|
545
|
-
const {
|
|
546
|
-
const result = await
|
|
533
|
+
await withGraphMcpClient("chain-insights-cli-exposure-profile", async (client) => {
|
|
534
|
+
const { exposureProfile } = await Promise.resolve().then(() => require("./public-tools-BREojpU7.cjs"));
|
|
535
|
+
const result = await exposureProfile(client, {
|
|
547
536
|
network: opts.network,
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
537
|
+
account: opts.account,
|
|
538
|
+
owner: opts.owner,
|
|
539
|
+
counterparty: opts.counterparty,
|
|
540
|
+
venue: opts.venue,
|
|
541
|
+
instrument: opts.instrument,
|
|
542
|
+
instrumentType: opts.instrumentType,
|
|
552
543
|
startTimestampMs: optionalNumber(opts.startTimestampMs),
|
|
553
544
|
endTimestampMs: optionalNumber(opts.endTimestampMs),
|
|
554
|
-
|
|
555
|
-
endBlock: optionalNumber(opts.endBlock),
|
|
556
|
-
depth: optionalNumber(opts.depth)
|
|
545
|
+
limit: optionalNumber(opts.limit)
|
|
557
546
|
});
|
|
558
547
|
console.log(result.summaryText);
|
|
559
548
|
console.log(JSON.stringify(result.structuredContent, null, 2));
|
|
@@ -562,15 +551,15 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
|
|
|
562
551
|
console.error(err.message);
|
|
563
552
|
process.exit(1);
|
|
564
553
|
}
|
|
565
|
-
})).addCommand(new commander.Command("call").description("Call an MCP tool directly (debug)").argument("<tool>", "Tool name to call").argument("[args...]", "Key=value arguments (e.g. address=0x1234 chain=ethereum)").action(async (tool, rawArgs) => {
|
|
554
|
+
})).addCommand(buildExposureInsightCommand("exposure-quality", "exposure_quality", "Score whether exposure behavior looks disciplined, fragile, lucky, or noisy")).addCommand(buildExposureInsightCommand("exposure-carry", "exposure_carry", "Explain carry earned or paid by staking, trading, funding, fees, emissions, or dividends")).addCommand(buildExposureInsightCommand("exposure-crowding", "exposure_crowding", "Measure crowding and side concentration for a market, subnet, hotkey, vault, or strategy")).addCommand(buildExposureInsightCommand("exposure-exit-pressure", "exposure_exit_pressure", "Explain liquidation, slippage, funding pain, unstake, or other exit pressure")).addCommand(buildExposureInsightCommand("exposure-correlation", "exposure_correlation", "Compare accounts for possible copy, overlap, or strategy-cluster exposure behavior")).addCommand(buildExposureInsightCommand("exposure-explain", "exposure_explain", "Explain a specific exposure lifecycle, trade, position, stake, rotation, or incident")).addCommand(new commander.Command("call").description("Call an MCP tool directly (debug)").argument("<tool>", "Tool name to call").argument("[args...]", "Key=value arguments (e.g. address=0x1234 chain=ethereum)").action(async (tool, rawArgs) => {
|
|
566
555
|
try {
|
|
567
556
|
const { parseMcpCallArgs } = await Promise.resolve().then(() => require("./call-args-CcUV6gFS.cjs"));
|
|
568
|
-
const { assertPublicMcpToolName } = await Promise.resolve().then(() => require("./tool-visibility
|
|
557
|
+
const { assertPublicMcpToolName } = await Promise.resolve().then(() => require("./tool-visibility--QPgrRE5.cjs")).then((n) => n.tool_visibility_exports);
|
|
569
558
|
const args = parseMcpCallArgs(rawArgs);
|
|
570
559
|
assertPublicMcpToolName(tool);
|
|
571
560
|
await withGraphMcpClient("chain-insights-cli-call", async (client, config) => {
|
|
572
|
-
if (tool === "
|
|
573
|
-
const { addressRisk } = await Promise.resolve().then(() => require("./public-tools-
|
|
561
|
+
if (tool === "aml_address_risk") {
|
|
562
|
+
const { addressRisk } = await Promise.resolve().then(() => require("./public-tools-BREojpU7.cjs"));
|
|
574
563
|
const result = await addressRisk(client, {
|
|
575
564
|
address: String(args["address"] ?? ""),
|
|
576
565
|
network: String(args["network"] ?? ""),
|
|
@@ -579,13 +568,12 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
|
|
|
579
568
|
console.log(result.summaryText);
|
|
580
569
|
return;
|
|
581
570
|
}
|
|
582
|
-
if (tool === "
|
|
583
|
-
const { traceVictimFunds } = await Promise.resolve().then(() => require("./public-tools-
|
|
571
|
+
if (tool === "aml_trace_victim_funds") {
|
|
572
|
+
const { traceVictimFunds } = await Promise.resolve().then(() => require("./public-tools-BREojpU7.cjs"));
|
|
584
573
|
const result = await traceVictimFunds(client, config, {
|
|
585
574
|
victimAddresses: args["victim_addresses"] ?? "",
|
|
586
575
|
knownSuspectAddresses: args["known_suspect_addresses"],
|
|
587
576
|
network: String(args["network"] ?? ""),
|
|
588
|
-
caseId: args["case_id"] === void 0 ? void 0 : String(args["case_id"]),
|
|
589
577
|
incidentTimestampMs: optionalNumberArg(args["incident_timestamp_ms"], "incident_timestamp_ms"),
|
|
590
578
|
maxHops: typeof args["max_hops"] === "number" ? args["max_hops"] : void 0,
|
|
591
579
|
perAddressLimit: typeof args["per_address_limit"] === "number" ? args["per_address_limit"] : void 0,
|
|
@@ -595,12 +583,11 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
|
|
|
595
583
|
console.log(JSON.stringify(result.structuredContent, null, 2));
|
|
596
584
|
return;
|
|
597
585
|
}
|
|
598
|
-
if (tool === "
|
|
599
|
-
const { traceSuspectFunds } = await Promise.resolve().then(() => require("./public-tools-
|
|
586
|
+
if (tool === "aml_trace_suspect_funds") {
|
|
587
|
+
const { traceSuspectFunds } = await Promise.resolve().then(() => require("./public-tools-BREojpU7.cjs"));
|
|
600
588
|
const result = await traceSuspectFunds(client, config, {
|
|
601
589
|
suspectAddresses: args["suspect_addresses"] ?? "",
|
|
602
590
|
network: String(args["network"] ?? ""),
|
|
603
|
-
caseId: args["case_id"] === void 0 ? void 0 : String(args["case_id"]),
|
|
604
591
|
maxHops: typeof args["max_hops"] === "number" ? args["max_hops"] : void 0,
|
|
605
592
|
perAddressLimit: typeof args["per_address_limit"] === "number" ? args["per_address_limit"] : void 0,
|
|
606
593
|
minAmountSum: typeof args["min_amount_sum"] === "number" ? args["min_amount_sum"] : void 0,
|
|
@@ -610,36 +597,64 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
|
|
|
610
597
|
console.log(JSON.stringify(result.structuredContent, null, 2));
|
|
611
598
|
return;
|
|
612
599
|
}
|
|
613
|
-
if (tool === "
|
|
614
|
-
const { traceDepositSources } = await Promise.resolve().then(() => require("./public-tools-
|
|
600
|
+
if (tool === "aml_trace_deposit_sources") {
|
|
601
|
+
const { traceDepositSources } = await Promise.resolve().then(() => require("./public-tools-BREojpU7.cjs"));
|
|
615
602
|
const result = await traceDepositSources(client, config, {
|
|
616
603
|
depositAddresses: args["deposit_addresses"] ?? "",
|
|
617
604
|
network: String(args["network"] ?? ""),
|
|
618
|
-
caseId: args["case_id"] === void 0 ? void 0 : String(args["case_id"]),
|
|
619
605
|
maxHops: typeof args["max_hops"] === "number" ? args["max_hops"] : void 0
|
|
620
606
|
});
|
|
621
607
|
console.log(result.summaryText);
|
|
622
608
|
console.log(JSON.stringify(result.structuredContent, null, 2));
|
|
623
609
|
return;
|
|
624
610
|
}
|
|
625
|
-
if (tool === "
|
|
626
|
-
const {
|
|
627
|
-
const result = await
|
|
611
|
+
if (tool === "exposure_profile") {
|
|
612
|
+
const { exposureProfile } = await Promise.resolve().then(() => require("./public-tools-BREojpU7.cjs"));
|
|
613
|
+
const result = await exposureProfile(client, {
|
|
628
614
|
network: String(args["network"] ?? ""),
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
615
|
+
account: args["account"] === void 0 ? void 0 : String(args["account"]),
|
|
616
|
+
owner: args["owner"] === void 0 ? void 0 : String(args["owner"]),
|
|
617
|
+
counterparty: args["counterparty"] === void 0 ? void 0 : String(args["counterparty"]),
|
|
618
|
+
venue: args["venue"] === void 0 ? void 0 : String(args["venue"]),
|
|
619
|
+
instrument: args["instrument"] === void 0 ? void 0 : String(args["instrument"]),
|
|
620
|
+
instrumentType: args["instrument_type"] === void 0 ? void 0 : String(args["instrument_type"]),
|
|
633
621
|
startTimestampMs: optionalNumberArg(args["start_timestamp_ms"], "start_timestamp_ms"),
|
|
634
622
|
endTimestampMs: optionalNumberArg(args["end_timestamp_ms"], "end_timestamp_ms"),
|
|
635
|
-
|
|
636
|
-
endBlock: optionalNumberArg(args["end_block"], "end_block"),
|
|
637
|
-
depth: optionalNumberArg(args["depth"] ?? args["max_hops"], "depth")
|
|
623
|
+
limit: optionalNumberArg(args["limit"], "limit")
|
|
638
624
|
});
|
|
639
625
|
console.log(result.summaryText);
|
|
640
626
|
console.log(JSON.stringify(result.structuredContent, null, 2));
|
|
641
627
|
return;
|
|
642
628
|
}
|
|
629
|
+
if ([
|
|
630
|
+
"exposure_quality",
|
|
631
|
+
"exposure_carry",
|
|
632
|
+
"exposure_crowding",
|
|
633
|
+
"exposure_exit_pressure",
|
|
634
|
+
"exposure_correlation",
|
|
635
|
+
"exposure_explain"
|
|
636
|
+
].includes(tool)) {
|
|
637
|
+
const { exposureCarry, exposureCorrelation, exposureCrowding, exposureExitPressure, exposureExplain, exposureQuality } = await Promise.resolve().then(() => require("./public-tools-BREojpU7.cjs"));
|
|
638
|
+
const exposureArgs = {
|
|
639
|
+
network: String(args["network"] ?? ""),
|
|
640
|
+
account: args["account"] === void 0 ? void 0 : String(args["account"]),
|
|
641
|
+
owner: args["owner"] === void 0 ? void 0 : String(args["owner"]),
|
|
642
|
+
counterparty: args["counterparty"] === void 0 ? void 0 : String(args["counterparty"]),
|
|
643
|
+
venue: args["venue"] === void 0 ? void 0 : String(args["venue"]),
|
|
644
|
+
instrument: args["instrument"] === void 0 ? void 0 : String(args["instrument"]),
|
|
645
|
+
market: args["market"] === void 0 ? void 0 : String(args["market"]),
|
|
646
|
+
instrumentType: args["instrument_type"] === void 0 ? void 0 : String(args["instrument_type"]),
|
|
647
|
+
startTimestampMs: optionalNumberArg(args["start_timestamp_ms"], "start_timestamp_ms"),
|
|
648
|
+
endTimestampMs: optionalNumberArg(args["end_timestamp_ms"], "end_timestamp_ms"),
|
|
649
|
+
limit: optionalNumberArg(args["limit"], "limit"),
|
|
650
|
+
candidateAccounts: args["candidate_accounts"],
|
|
651
|
+
positionId: args["position_id"] === void 0 ? void 0 : String(args["position_id"])
|
|
652
|
+
};
|
|
653
|
+
const result = tool === "exposure_quality" ? await exposureQuality(client, exposureArgs) : tool === "exposure_carry" ? await exposureCarry(client, exposureArgs) : tool === "exposure_crowding" ? await exposureCrowding(client, exposureArgs) : tool === "exposure_exit_pressure" ? await exposureExitPressure(client, exposureArgs) : tool === "exposure_correlation" ? await exposureCorrelation(client, exposureArgs) : await exposureExplain(client, exposureArgs);
|
|
654
|
+
console.log(result.summaryText);
|
|
655
|
+
console.log(JSON.stringify(result.structuredContent, null, 2));
|
|
656
|
+
return;
|
|
657
|
+
}
|
|
643
658
|
printMcpTextContent(await client.callTool({
|
|
644
659
|
name: tool,
|
|
645
660
|
arguments: args
|
|
@@ -650,289 +665,18 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
|
|
|
650
665
|
process.exit(1);
|
|
651
666
|
}
|
|
652
667
|
}));
|
|
653
|
-
|
|
654
|
-
await scopeCasesToInvocationDir();
|
|
655
|
-
}).addCommand(new commander.Command("open").description("Open a new investigation case").argument("<name>", "Case name (e.g. \"Tornado Mixer Investigation\")").option("--tags <tags>", "Comma-separated tags (e.g. aml,mixer,defi)", "").option("--description <desc>", "Brief description of the investigation", "").action(async (name, opts) => {
|
|
656
|
-
try {
|
|
657
|
-
if (/^[1-9]\d*$/.test(name.trim())) throw new Error("Numeric case names look like list selectors. Use a descriptive case name, e.g. `cia case open \"Tracking stolen funds from <address>\"`.");
|
|
658
|
-
const { CaseStore } = await Promise.resolve().then(() => require("./cases-Bz_9XKEw.cjs")).then((n) => n.cases_exports);
|
|
659
|
-
const tags = opts.tags ? opts.tags.split(",").map((t) => t.trim()).filter(Boolean) : [];
|
|
660
|
-
const c = await CaseStore.create({
|
|
661
|
-
name,
|
|
662
|
-
tags,
|
|
663
|
-
description: opts.description
|
|
664
|
-
});
|
|
665
|
-
const { casesRoot } = await Promise.resolve().then(() => require("./store-CQhU8dz8.cjs")).then((n) => n.store_exports);
|
|
666
|
-
console.log(`Case opened: ${c.id}`);
|
|
667
|
-
console.log(`Directory: ${node_path.default.join(casesRoot(), c.id)}/`);
|
|
668
|
-
console.log(`Status: ${c.status}`);
|
|
669
|
-
const { findActiveWorkspace } = await Promise.resolve().then(() => require("./active-BVr55kvW.cjs")).then((n) => n.active_exports);
|
|
670
|
-
if (findActiveWorkspace()) try {
|
|
671
|
-
const { refreshCaseVault } = await Promise.resolve().then(() => require("./vault-B2y78Ypu.cjs"));
|
|
672
|
-
const result = await refreshCaseVault({
|
|
673
|
-
caseId: c.id,
|
|
674
|
-
force: true
|
|
675
|
-
});
|
|
676
|
-
console.log(`Open first: ${result.nextFile}`);
|
|
677
|
-
} catch (refreshErr) {
|
|
678
|
-
console.error(`Warning: live vault refresh failed: ${refreshErr.message}`);
|
|
679
|
-
console.error(`Run: cia case vault refresh ${c.id} --force`);
|
|
680
|
-
}
|
|
681
|
-
} catch (err) {
|
|
682
|
-
console.error(err.message);
|
|
683
|
-
process.exit(1);
|
|
684
|
-
}
|
|
685
|
-
})).addCommand(new commander.Command("activate").description("Activate a case (set status to active)").argument("<case-id>", "Case ID to activate").action(async (caseSelector) => {
|
|
686
|
-
try {
|
|
687
|
-
const { CaseStore } = await Promise.resolve().then(() => require("./cases-Bz_9XKEw.cjs")).then((n) => n.cases_exports);
|
|
688
|
-
const caseId = await resolveCaseSelector(caseSelector);
|
|
689
|
-
const c = await CaseStore.setStatus(caseId, "active");
|
|
690
|
-
console.log(`Case ${c.id} is now: active`);
|
|
691
|
-
} catch (err) {
|
|
692
|
-
console.error(err.message);
|
|
693
|
-
process.exit(1);
|
|
694
|
-
}
|
|
695
|
-
})).addCommand(new commander.Command("suspend").description("Suspend a case (set status to suspended)").argument("<case-id>", "Case ID to suspend").action(async (caseSelector) => {
|
|
696
|
-
try {
|
|
697
|
-
const { CaseStore } = await Promise.resolve().then(() => require("./cases-Bz_9XKEw.cjs")).then((n) => n.cases_exports);
|
|
698
|
-
const caseId = await resolveCaseSelector(caseSelector);
|
|
699
|
-
const c = await CaseStore.setStatus(caseId, "suspended");
|
|
700
|
-
console.log(`Case ${c.id} is now: suspended`);
|
|
701
|
-
} catch (err) {
|
|
702
|
-
console.error(err.message);
|
|
703
|
-
process.exit(1);
|
|
704
|
-
}
|
|
705
|
-
})).addCommand(new commander.Command("close").description("Close a case permanently").argument("<case-id>", "Case ID to close").action(async (caseSelector) => {
|
|
706
|
-
try {
|
|
707
|
-
const { CaseStore } = await Promise.resolve().then(() => require("./cases-Bz_9XKEw.cjs")).then((n) => n.cases_exports);
|
|
708
|
-
const caseId = await resolveCaseSelector(caseSelector);
|
|
709
|
-
const c = await CaseStore.setStatus(caseId, "closed");
|
|
710
|
-
console.log(`Case ${c.id} is now: closed`);
|
|
711
|
-
} catch (err) {
|
|
712
|
-
console.error(err.message);
|
|
713
|
-
process.exit(1);
|
|
714
|
-
}
|
|
715
|
-
})).addCommand(new commander.Command("list").description("List all investigation cases").option("--status <status>", "Filter by status (open|active|suspended|closed)").action(async (opts) => {
|
|
716
|
-
try {
|
|
717
|
-
const { CaseStore } = await Promise.resolve().then(() => require("./cases-Bz_9XKEw.cjs")).then((n) => n.cases_exports);
|
|
718
|
-
const cases = await CaseStore.list();
|
|
719
|
-
const filtered = opts.status ? cases.filter((c) => c.status === opts.status) : cases;
|
|
720
|
-
if (filtered.length === 0) {
|
|
721
|
-
console.log("No cases found.");
|
|
722
|
-
return;
|
|
723
|
-
}
|
|
724
|
-
for (const [index, c] of filtered.entries()) console.log(`${index + 1}. ${c.id} [${c.status}] ${c.name}`);
|
|
725
|
-
} catch (err) {
|
|
726
|
-
console.error(err.message);
|
|
727
|
-
process.exit(1);
|
|
728
|
-
}
|
|
729
|
-
})).addCommand(new commander.Command("evidence").description("Manage case evidence").addCommand(new commander.Command("add").description("Add evidence to a case from an MCP query result").argument("<case-id>", "Case ID to add evidence to").option("--source <tool>", "MCP tool name that produced this evidence", "manual").option("--content <text>", "Evidence content (MCP response or notes)", "").option("--query-params <params>", "Query parameters used (e.g. address=0x1234)", "").action(async (caseSelector, opts) => {
|
|
730
|
-
try {
|
|
731
|
-
const { EvidenceStore } = await Promise.resolve().then(() => require("./cases-Bz_9XKEw.cjs")).then((n) => n.cases_exports);
|
|
732
|
-
const caseId = await resolveCaseSelector(caseSelector);
|
|
733
|
-
const result = await EvidenceStore.append(caseId, {
|
|
734
|
-
source: opts.source,
|
|
735
|
-
content: opts.content,
|
|
736
|
-
queryParams: opts.queryParams
|
|
737
|
-
});
|
|
738
|
-
console.log(`Evidence saved: ${result.filename}`);
|
|
739
|
-
console.log(`SHA-256: ${result.sha256}`);
|
|
740
|
-
} catch (err) {
|
|
741
|
-
console.error(err.message);
|
|
742
|
-
process.exit(1);
|
|
743
|
-
}
|
|
744
|
-
})).addCommand(new commander.Command("verify").description("Verify evidence manifest integrity for a case").argument("<case-id>", "Case ID to verify").action(async (caseSelector) => {
|
|
745
|
-
try {
|
|
746
|
-
const { EvidenceStore } = await Promise.resolve().then(() => require("./cases-Bz_9XKEw.cjs")).then((n) => n.cases_exports);
|
|
747
|
-
const caseId = await resolveCaseSelector(caseSelector);
|
|
748
|
-
const result = await EvidenceStore.verifyManifest(caseId);
|
|
749
|
-
if (result.ok) console.log(`Manifest OK — ${result.count} evidence file(s) verified`);
|
|
750
|
-
else {
|
|
751
|
-
console.error(`Manifest FAILED — tampered files: ${(result.tampered ?? []).join(", ")}`);
|
|
752
|
-
process.exit(1);
|
|
753
|
-
}
|
|
754
|
-
} catch (err) {
|
|
755
|
-
console.error(err.message);
|
|
756
|
-
process.exit(1);
|
|
757
|
-
}
|
|
758
|
-
}))).addCommand(new commander.Command("dossier").description("Manage entity dossiers for a case").addCommand(new commander.Command("update").description("Append a finding to an entity dossier").argument("<case-id>", "Case ID").argument("<address>", "Entity address or identifier").option("--finding <text>", "Finding to append to the dossier", "").option("--type <type>", "Entity type (eoa|contract|exchange|mixer|unknown)", "unknown").action(async (caseSelector, address, opts) => {
|
|
759
|
-
try {
|
|
760
|
-
const { DossierStore } = await Promise.resolve().then(() => require("./cases-Bz_9XKEw.cjs")).then((n) => n.cases_exports);
|
|
761
|
-
const caseId = await resolveCaseSelector(caseSelector);
|
|
762
|
-
const entityType = [
|
|
763
|
-
"eoa",
|
|
764
|
-
"contract",
|
|
765
|
-
"exchange",
|
|
766
|
-
"mixer",
|
|
767
|
-
"unknown"
|
|
768
|
-
].includes(opts.type) ? opts.type : "unknown";
|
|
769
|
-
await DossierStore.appendFinding(caseId, address, opts.finding, entityType);
|
|
770
|
-
console.log(`Dossier updated for ${address}`);
|
|
771
|
-
} catch (err) {
|
|
772
|
-
console.error(err.message);
|
|
773
|
-
process.exit(1);
|
|
774
|
-
}
|
|
775
|
-
}))).addCommand(new commander.Command("session").description("Manage investigation sessions").addCommand(new commander.Command("start").description("Start a new investigation session for a case").argument("<case-id>", "Case ID").argument("[title...]", "Optional session title").action(async (caseSelector, titleParts) => {
|
|
776
|
-
try {
|
|
777
|
-
const { SessionStore } = await Promise.resolve().then(() => require("./cases-Bz_9XKEw.cjs")).then((n) => n.cases_exports);
|
|
778
|
-
const caseId = await resolveCaseSelector(caseSelector);
|
|
779
|
-
const title = titleParts.join(" ").trim();
|
|
780
|
-
const s = await SessionStore.start(caseId, title ? { title } : {});
|
|
781
|
-
console.log(`Session started: ${s.sessionId}`);
|
|
782
|
-
} catch (err) {
|
|
783
|
-
console.error(err.message);
|
|
784
|
-
process.exit(1);
|
|
785
|
-
}
|
|
786
|
-
})).addCommand(new commander.Command("end").description("End the current session with findings and next steps").argument("<case-id>", "Case ID").option("--findings <text>", "Key findings from this session", "").option("--next-steps <text>", "Next steps for the investigation", "").action(async (caseSelector, opts) => {
|
|
787
|
-
try {
|
|
788
|
-
const { SessionStore } = await Promise.resolve().then(() => require("./cases-Bz_9XKEw.cjs")).then((n) => n.cases_exports);
|
|
789
|
-
const caseId = await resolveCaseSelector(caseSelector);
|
|
790
|
-
await SessionStore.end(caseId, {
|
|
791
|
-
findings: opts.findings,
|
|
792
|
-
nextSteps: opts.nextSteps
|
|
793
|
-
});
|
|
794
|
-
await SessionStore.archiveOldSessions(caseId);
|
|
795
|
-
console.log(`Session ended for case ${caseId}`);
|
|
796
|
-
} catch (err) {
|
|
797
|
-
console.error(err.message);
|
|
798
|
-
process.exit(1);
|
|
799
|
-
}
|
|
800
|
-
}))).addCommand(new commander.Command("vault").description("Manage live Obsidian case vault notes").addCommand(new commander.Command("refresh").description("Refresh Obsidian vault notes for a case").argument("<case-id-or-selector>", "Case ID or case list number to refresh").option("--force", "Overwrite existing generated case vault files").action(async (caseSelector, opts) => {
|
|
801
|
-
try {
|
|
802
|
-
const caseId = await resolveCaseSelector(caseSelector);
|
|
803
|
-
const { refreshCaseVault } = await Promise.resolve().then(() => require("./vault-B2y78Ypu.cjs"));
|
|
804
|
-
const result = await refreshCaseVault({
|
|
805
|
-
caseId,
|
|
806
|
-
force: opts.force === true
|
|
807
|
-
});
|
|
808
|
-
console.log(`Case vault refreshed: ${caseId}`);
|
|
809
|
-
console.log(`Files: ${result.filesWritten.length}`);
|
|
810
|
-
console.log(`Open first: ${result.nextFile}`);
|
|
811
|
-
} catch (err) {
|
|
812
|
-
console.error(err.message);
|
|
813
|
-
process.exit(1);
|
|
814
|
-
}
|
|
815
|
-
}))).addCommand(new commander.Command("export").description("Export a case for Obsidian, LLM Wiki, and agents").argument("<case-id>", "Case ID or case list number to export").option("--target <target>", "Export target: obsidian-llmwiki", "obsidian-llmwiki").option("--mode <mode>", "Redaction mode: private|partner|public", "private").option("--out <directory>", "Output directory. Defaults to published/<case-slug>").action(async (caseSelector, opts) => {
|
|
816
|
-
try {
|
|
817
|
-
const target = opts.target === "obsidian-llmwiki" ? opts.target : void 0;
|
|
818
|
-
const mode = [
|
|
819
|
-
"private",
|
|
820
|
-
"partner",
|
|
821
|
-
"public"
|
|
822
|
-
].includes(opts.mode) ? opts.mode : void 0;
|
|
823
|
-
if (!target) throw new Error(`Unsupported export target: ${opts.target}`);
|
|
824
|
-
if (!mode) throw new Error(`Unsupported export mode: ${opts.mode}`);
|
|
825
|
-
const caseId = await resolveCaseSelector(caseSelector);
|
|
826
|
-
const { exportCase } = await Promise.resolve().then(() => require("./export-D4v4-6F4.cjs"));
|
|
827
|
-
const result = await exportCase({
|
|
828
|
-
caseId,
|
|
829
|
-
target,
|
|
830
|
-
mode,
|
|
831
|
-
outputDir: opts.out
|
|
832
|
-
});
|
|
833
|
-
console.log(`Case exported: ${result.outputDir}`);
|
|
834
|
-
console.log(`Manifest: ${result.manifestPath}`);
|
|
835
|
-
console.log(`Files: ${result.fileCount}`);
|
|
836
|
-
console.log(`Open first: ${result.nextFile}`);
|
|
837
|
-
for (const warning of result.warnings) console.warn(`Warning: ${warning}`);
|
|
838
|
-
} catch (err) {
|
|
839
|
-
console.error(err.message);
|
|
840
|
-
process.exit(1);
|
|
841
|
-
}
|
|
842
|
-
})).addCommand(new commander.Command("show").description("Show saved case context").argument("<case-id>", "Case ID or case list number to show").action(async (caseSelector) => {
|
|
843
|
-
try {
|
|
844
|
-
await showCaseContext(caseSelector);
|
|
845
|
-
} catch (err) {
|
|
846
|
-
console.error(err.message);
|
|
847
|
-
process.exit(1);
|
|
848
|
-
}
|
|
849
|
-
}));
|
|
850
|
-
program.addCommand(caseCommand);
|
|
851
|
-
program.command("playbook").description("Run and manage investigation playbooks").addCommand(new commander.Command("run").description("Execute a playbook by name").argument("<name>", "Playbook name (e.g. trace-funds, risk-check, entity-profile)").option("--case <id>", "Case ID to attach evidence to (auto-created if omitted)").option("--from <n>", "Resume from step N (1-based)", "1").option("--dry-run", "Show steps without executing").option("-p, --param <kv...>", "Parameters as key=value pairs (repeatable, e.g. -p address=0x1 -p hops=3)").action(async (name, opts) => {
|
|
852
|
-
try {
|
|
853
|
-
const resolvedParams = {};
|
|
854
|
-
for (const kv of opts.param ?? []) {
|
|
855
|
-
const eq = kv.indexOf("=");
|
|
856
|
-
if (eq === -1) {
|
|
857
|
-
console.error(`Invalid param format: "${kv}". Use key=value`);
|
|
858
|
-
process.exit(1);
|
|
859
|
-
}
|
|
860
|
-
const key = kv.slice(0, eq);
|
|
861
|
-
if (!key) {
|
|
862
|
-
console.error(`Invalid param format: "${kv}". Key must be non-empty`);
|
|
863
|
-
process.exit(1);
|
|
864
|
-
}
|
|
865
|
-
resolvedParams[key] = kv.slice(eq + 1);
|
|
866
|
-
}
|
|
867
|
-
const { resolvePlaybookContent } = await Promise.resolve().then(() => require("./resolver-CZdQwKvh.cjs"));
|
|
868
|
-
const markdown = await resolvePlaybookContent(name);
|
|
869
|
-
const { PlaybookParser } = await Promise.resolve().then(() => require("./parser-BXLAHYnZ.cjs"));
|
|
870
|
-
const definition = PlaybookParser.parse(markdown, resolvedParams);
|
|
871
|
-
for (const spec of definition.params) if (spec.required && !resolvedParams[spec.name] && !spec.default) {
|
|
872
|
-
console.error(`Missing required param: ${spec.name}. Pass with: -p ${spec.name}=<value>`);
|
|
873
|
-
process.exit(1);
|
|
874
|
-
}
|
|
875
|
-
const fromN = parseInt(opts.from, 10);
|
|
876
|
-
if (isNaN(fromN) || fromN < 1) {
|
|
877
|
-
console.error(`Invalid --from value: "${opts.from}". Must be a positive integer.`);
|
|
878
|
-
process.exit(1);
|
|
879
|
-
}
|
|
880
|
-
const { PlaybookRunner } = await Promise.resolve().then(() => require("./runner-bLy0pTr_.cjs"));
|
|
881
|
-
await PlaybookRunner.run(definition, {
|
|
882
|
-
caseId: opts.case,
|
|
883
|
-
from: fromN,
|
|
884
|
-
dryRun: opts.dryRun,
|
|
885
|
-
params: resolvedParams
|
|
886
|
-
});
|
|
887
|
-
} catch (err) {
|
|
888
|
-
console.error(err.message);
|
|
889
|
-
process.exit(1);
|
|
890
|
-
}
|
|
891
|
-
})).addCommand(new commander.Command("list").description("List available playbooks (built-in and user-defined)").action(async () => {
|
|
892
|
-
try {
|
|
893
|
-
const { listPlaybooks } = await Promise.resolve().then(() => require("./resolver-CZdQwKvh.cjs"));
|
|
894
|
-
const playbooks = await listPlaybooks();
|
|
895
|
-
if (playbooks.length === 0) {
|
|
896
|
-
console.log("No playbooks found.");
|
|
897
|
-
return;
|
|
898
|
-
}
|
|
899
|
-
for (const p of playbooks) console.log(` ${p.name.padEnd(20)} [${p.source}]`);
|
|
900
|
-
} catch (err) {
|
|
901
|
-
console.error(err.message);
|
|
902
|
-
process.exit(1);
|
|
903
|
-
}
|
|
904
|
-
})).addCommand(new commander.Command("show").description("Show steps for a playbook without executing").argument("<name>", "Playbook name").action(async (name) => {
|
|
905
|
-
try {
|
|
906
|
-
const { resolvePlaybookContent } = await Promise.resolve().then(() => require("./resolver-CZdQwKvh.cjs"));
|
|
907
|
-
const { PlaybookParser } = await Promise.resolve().then(() => require("./parser-BXLAHYnZ.cjs"));
|
|
908
|
-
const markdown = await resolvePlaybookContent(name);
|
|
909
|
-
const definition = PlaybookParser.parse(markdown, {});
|
|
910
|
-
console.log(`Playbook: ${definition.name} v${definition.version}`);
|
|
911
|
-
console.log(`${definition.description}\n`);
|
|
912
|
-
console.log(`Parameters:`);
|
|
913
|
-
for (const p of definition.params) {
|
|
914
|
-
const req = p.required ? "(required)" : `(optional, default: ${p.default ?? "none"})`;
|
|
915
|
-
console.log(` ${p.name}: ${p.type} ${req}`);
|
|
916
|
-
}
|
|
917
|
-
console.log(`\nSteps:`);
|
|
918
|
-
for (const step of definition.steps) console.log(` ${step.index}. ${step.label} → tool: ${step.tool}`);
|
|
919
|
-
} catch (err) {
|
|
920
|
-
console.error(err.message);
|
|
921
|
-
process.exit(1);
|
|
922
|
-
}
|
|
923
|
-
}));
|
|
924
|
-
program.command("viz").description("Generate money flow visualization").argument("[case-id]", "Case ID to visualize").option("--data <file>", "Raw transaction JSON file for ad-hoc visualization").option("-p, --port <number>", "Server port", "4321").action(async (caseId, opts) => {
|
|
668
|
+
program.command("viz").description("Generate a workspace visualization").argument("[source-id]", "Workspace graph report ID to render").option("--data <file>", "Raw transaction JSON file for ad-hoc visualization").option("-p, --port <number>", "Server port", "4321").action(async (sourceId, opts) => {
|
|
925
669
|
try {
|
|
926
|
-
if (!
|
|
927
|
-
console.error("Provide either a
|
|
670
|
+
if (!sourceId && !opts.data) {
|
|
671
|
+
console.error("Provide either a visualization source ID or --data <file.json>");
|
|
928
672
|
process.exit(1);
|
|
929
673
|
}
|
|
930
|
-
const { generateVisualization } = await Promise.resolve().then(() => require("./viz-
|
|
674
|
+
const { generateVisualization } = await Promise.resolve().then(() => require("./viz-BBvY-wXz.cjs")).then((n) => n.viz_exports);
|
|
931
675
|
const result = await generateVisualization({
|
|
932
|
-
|
|
676
|
+
sourceId,
|
|
933
677
|
dataFile: opts.data
|
|
934
678
|
});
|
|
935
|
-
const { startServer } = await Promise.resolve().then(() => require("./server-
|
|
679
|
+
const { startServer } = await Promise.resolve().then(() => require("./server-ColyTG1t.cjs")).then((n) => n.server_exports);
|
|
936
680
|
const port = parseInt(opts.port, 10);
|
|
937
681
|
startServer(port);
|
|
938
682
|
const url = `http://127.0.0.1:${port}/viz/${result.vizId}`;
|