chain-insights 0.2.31 → 0.3.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 +40 -14
- package/dist/cases-Cp9DUbEV.mjs +6 -0
- package/dist/{cases-c0iV-XLI.cjs → cases-sTY5aXav.cjs} +3 -3
- package/dist/cli.cjs +122 -66
- package/dist/cli.mjs +122 -66
- package/dist/cli.mjs.map +1 -1
- package/dist/{viz-Da9YWN_I.cjs → data-extractor-Cavd7wHk.cjs} +11 -34
- package/dist/{viz-DkJyqlUu.mjs → data-extractor-DZUJu1Bz.mjs} +3 -32
- package/dist/data-extractor-DZUJu1Bz.mjs.map +1 -0
- package/dist/{dossier-Br62hCG7.cjs → dossier-BXy57V4-.cjs} +13 -1
- package/dist/{dossier-Bl0NkJKC.mjs → dossier-Bjpcbcxa.mjs} +4 -2
- package/dist/{dossier-Bl0NkJKC.mjs.map → dossier-Bjpcbcxa.mjs.map} +1 -1
- package/dist/export-BqTCO9lP.mjs +591 -0
- package/dist/export-BqTCO9lP.mjs.map +1 -0
- package/dist/export-DsXgtCwO.cjs +592 -0
- package/dist/index.cjs +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{init-DBC9Ml33.mjs → init-DLBL_nVG.mjs} +27 -1
- package/dist/{init-DBC9Ml33.mjs.map → init-DLBL_nVG.mjs.map} +1 -1
- package/dist/{init-CFaUWgjK.cjs → init-zqbd7i-_.cjs} +26 -0
- package/dist/mcp-proxy.cjs +215 -77
- package/dist/mcp-proxy.d.cts.map +1 -1
- package/dist/mcp-proxy.d.mts.map +1 -1
- package/dist/mcp-proxy.mjs +215 -77
- package/dist/mcp-proxy.mjs.map +1 -1
- package/dist/{public-tools-BwguvIsf.cjs → public-tools-BvMb3H2P.cjs} +701 -1479
- package/dist/{public-tools-DoRNhMn9.mjs → public-tools-wJoAFDFa.mjs} +700 -1479
- package/dist/public-tools-wJoAFDFa.mjs.map +1 -0
- package/dist/{resolver-D7VBb0uB.mjs → resolver-2jXNtWQO.mjs} +12 -29
- package/dist/resolver-2jXNtWQO.mjs.map +1 -0
- package/dist/{resolver-BUU7ZgW-.cjs → resolver-CZdQwKvh.cjs} +11 -28
- package/dist/{runner-BCDeBYsR.cjs → runner-BhZ4lnF1.cjs} +2 -2
- package/dist/{runner-CTFK0Qcg.mjs → runner-DIJSbkjc.mjs} +3 -3
- package/dist/{runner-CTFK0Qcg.mjs.map → runner-DIJSbkjc.mjs.map} +1 -1
- package/dist/{selector-CTUiQrzI.mjs → selector-CF2o5gxN.mjs} +2 -2
- package/dist/{selector-CTUiQrzI.mjs.map → selector-CF2o5gxN.mjs.map} +1 -1
- package/dist/{selector-DBS2jYH4.cjs → selector-DfAMZEC9.cjs} +1 -1
- package/dist/{session-DwyikazY.cjs → session-BT7VpbAd.cjs} +13 -1
- package/dist/{session-Bha3zFrx.mjs → session-DROyhebe.mjs} +4 -2
- package/dist/{session-Bha3zFrx.mjs.map → session-DROyhebe.mjs.map} +1 -1
- package/dist/{store-BT2SCcQr.mjs → store-CTtqQtaE.mjs} +10 -4
- package/dist/{store-BT2SCcQr.mjs.map → store-CTtqQtaE.mjs.map} +1 -1
- package/dist/{store-DogLawSj.cjs → store-CqPfs47P.cjs} +37 -7
- package/dist/{tool-visibility-BHRFLXuU.mjs → tool-visibility-BpyZHRBi.mjs} +4 -2
- package/dist/tool-visibility-BpyZHRBi.mjs.map +1 -0
- package/dist/{tool-visibility-iAVQV3t0.cjs → tool-visibility-Buq7YdUZ.cjs} +3 -1
- package/dist/viz-5y24S5X1.mjs +35 -0
- package/dist/viz-5y24S5X1.mjs.map +1 -0
- package/dist/viz-Dqp3C5kb.cjs +44 -0
- package/docs/contributing.md +3 -2
- package/docs/graph-tools.md +129 -118
- package/docs/investigation-workspaces.md +14 -0
- package/docs/mcp-proxy.md +20 -2
- package/package.json +1 -1
- package/skills/chain-insights-bittensor-cypher/SKILL.md +24 -0
- package/skills/chain-insights-cypher/SKILL.md +16 -1
- package/skills/chain-insights-cypher/references/memgraph-examples.md +193 -0
- package/skills/chain-insights-developer-experience/SKILL.md +26 -6
- package/skills/chain-insights-investigation/SKILL.md +64 -48
- package/skills/chain-insights-trace-funds/SKILL.md +80 -197
- package/skills/test-chain-insights-graphrag-mcp/SKILL.md +1 -1
- package/skills/test-chain-insights-graphrag-mcp/scripts/run-uat.sh +4 -4
- package/dist/cases-qjPtbnUd.mjs +0 -6
- package/dist/public-tools-DoRNhMn9.mjs.map +0 -1
- package/dist/resolver-D7VBb0uB.mjs.map +0 -1
- package/dist/tool-visibility-BHRFLXuU.mjs.map +0 -1
- package/dist/viz-DkJyqlUu.mjs.map +0 -1
package/dist/cli.mjs
CHANGED
|
@@ -19,12 +19,16 @@ if (installerFlags.length > 0 && !rawArgs.some((a) => !a.startsWith("-"))) {
|
|
|
19
19
|
}
|
|
20
20
|
process.exit(0);
|
|
21
21
|
}
|
|
22
|
-
if (rawArgs[0] === "mcp" &&
|
|
23
|
-
|
|
22
|
+
if (rawArgs[0] === "mcp" && [
|
|
23
|
+
"trace-funds",
|
|
24
|
+
"track-funds",
|
|
25
|
+
"scam-topology"
|
|
26
|
+
].includes(rawArgs[1] ?? "")) {
|
|
27
|
+
console.error(`error: unknown command '${rawArgs[1]}'`);
|
|
24
28
|
process.exit(1);
|
|
25
29
|
}
|
|
26
30
|
async function resolveCaseSelector(input) {
|
|
27
|
-
const { resolveCaseSelector } = await import("./selector-
|
|
31
|
+
const { resolveCaseSelector } = await import("./selector-CF2o5gxN.mjs");
|
|
28
32
|
return resolveCaseSelector(input);
|
|
29
33
|
}
|
|
30
34
|
async function scopeCasesToInvocationDir() {
|
|
@@ -33,7 +37,7 @@ async function scopeCasesToInvocationDir() {
|
|
|
33
37
|
process.env["CHAIN_INSIGHTS_CASES_ROOT"] = activeCasesRoot();
|
|
34
38
|
}
|
|
35
39
|
async function showCaseContext(caseSelector) {
|
|
36
|
-
const { CaseStore } = await import("./cases-
|
|
40
|
+
const { CaseStore } = await import("./cases-Cp9DUbEV.mjs");
|
|
37
41
|
const caseId = await resolveCaseSelector(caseSelector);
|
|
38
42
|
const ctx = await CaseStore.loadContext(caseId);
|
|
39
43
|
console.log(`\n=== Case: ${ctx.case.id} ===`);
|
|
@@ -63,11 +67,6 @@ function optionalNumberArg(value, name) {
|
|
|
63
67
|
if (typeof value === "string") return optionalNumber(value);
|
|
64
68
|
throw new Error(`Invalid number for ${name}: ${String(value)}`);
|
|
65
69
|
}
|
|
66
|
-
function optionalScamTopologyActivityPolicy(value) {
|
|
67
|
-
if (value === void 0 || value === null || value === "") return void 0;
|
|
68
|
-
if (value === "node_relative_only" || value === "global_incident_only") return value;
|
|
69
|
-
throw new Error("activity_policy must be one of: node_relative_only, global_incident_only");
|
|
70
|
-
}
|
|
71
70
|
async function withGraphMcpClient(name, fn) {
|
|
72
71
|
const { loadConfig } = await import("./config-Drgc2HuF.mjs").then((n) => n.t);
|
|
73
72
|
const config = await loadConfig();
|
|
@@ -213,7 +212,7 @@ program.command("access-key").description("Configure Graph MCP test access key m
|
|
|
213
212
|
}));
|
|
214
213
|
program.command("init").description("Initialize an investigation workspace").argument("[dir]", "Workspace directory to initialize", ".").option("--force", "Overwrite existing workspace files").action(async (dir, opts) => {
|
|
215
214
|
try {
|
|
216
|
-
const { initWorkspace } = await import("./init-
|
|
215
|
+
const { initWorkspace } = await import("./init-DLBL_nVG.mjs");
|
|
217
216
|
const result = await initWorkspace({
|
|
218
217
|
targetDir: dir,
|
|
219
218
|
force: opts.force
|
|
@@ -361,7 +360,7 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
|
|
|
361
360
|
try {
|
|
362
361
|
const { loadSchema, saveSchema } = await import("./schema-cache-DwDvPy4e.mjs");
|
|
363
362
|
const { formatToolsTable } = await import("./format-Bq94jSyw.mjs");
|
|
364
|
-
const { visibleRemoteTools } = await import("./tool-visibility-
|
|
363
|
+
const { visibleRemoteTools } = await import("./tool-visibility-BpyZHRBi.mjs").then((n) => n.n);
|
|
365
364
|
const { loadConfig } = await import("./config-Drgc2HuF.mjs").then((n) => n.t);
|
|
366
365
|
const { createConfiguredGraphMcpFetch, resolveGraphMcpEndpoint } = await import("./client-D4JE7fFF.mjs").then((n) => n.n);
|
|
367
366
|
const config = await loadConfig();
|
|
@@ -402,7 +401,7 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
|
|
|
402
401
|
}));
|
|
403
402
|
return;
|
|
404
403
|
}
|
|
405
|
-
const { addressRisk } = await import("./public-tools-
|
|
404
|
+
const { addressRisk } = await import("./public-tools-wJoAFDFa.mjs");
|
|
406
405
|
const result = await addressRisk(client, {
|
|
407
406
|
address: opts.address,
|
|
408
407
|
network: opts.network,
|
|
@@ -414,29 +413,30 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
|
|
|
414
413
|
console.error(err.message);
|
|
415
414
|
process.exit(1);
|
|
416
415
|
}
|
|
417
|
-
})).addCommand(new Command("
|
|
416
|
+
})).addCommand(new 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("--case <id>", "Case ID to attach compact evidence pointers").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) => {
|
|
418
417
|
try {
|
|
419
418
|
const { requireWorkspaceRoot } = await import("./output-root-BRhzhhXZ.mjs").then((n) => n.t);
|
|
420
419
|
requireWorkspaceRoot();
|
|
421
|
-
await withGraphMcpClient("chain-insights-cli-
|
|
420
|
+
await withGraphMcpClient("chain-insights-cli-trace-victim-funds", async (client, config) => {
|
|
422
421
|
if (opts.remote) {
|
|
423
422
|
printMcpTextContent(await client.callTool({
|
|
424
|
-
name: "
|
|
423
|
+
name: "trace_victim_funds",
|
|
425
424
|
arguments: {
|
|
426
|
-
|
|
425
|
+
victim_addresses: opts.victimAddresses,
|
|
427
426
|
network: opts.network,
|
|
428
|
-
...opts.
|
|
427
|
+
...opts.knownSuspectAddresses ? { known_suspect_addresses: opts.knownSuspectAddresses } : {}
|
|
429
428
|
}
|
|
430
429
|
}));
|
|
431
430
|
return;
|
|
432
431
|
}
|
|
433
|
-
const {
|
|
432
|
+
const { traceVictimFunds } = await import("./public-tools-wJoAFDFa.mjs");
|
|
434
433
|
const caseId = opts.case ? await resolveCaseSelector(opts.case) : void 0;
|
|
435
|
-
const result = await
|
|
436
|
-
|
|
437
|
-
|
|
434
|
+
const result = await traceVictimFunds(client, config, {
|
|
435
|
+
victimAddresses: opts.victimAddresses,
|
|
436
|
+
knownSuspectAddresses: opts.knownSuspectAddresses,
|
|
438
437
|
network: opts.network,
|
|
439
438
|
caseId,
|
|
439
|
+
incidentTimestampMs: optionalNumber(opts.incidentTimestampMs),
|
|
440
440
|
maxHops: optionalNumber(opts.maxHops),
|
|
441
441
|
perAddressLimit: optionalNumber(opts.perAddressLimit),
|
|
442
442
|
minAmountSum: optionalNumber(opts.minAmountSum)
|
|
@@ -448,21 +448,40 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
|
|
|
448
448
|
console.error(err.message);
|
|
449
449
|
process.exit(1);
|
|
450
450
|
}
|
|
451
|
-
})).addCommand(new Command("
|
|
451
|
+
})).addCommand(new 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").option("--case <id>", "Case ID to attach compact evidence pointers").action(async (opts) => {
|
|
452
|
+
try {
|
|
453
|
+
const { requireWorkspaceRoot } = await import("./output-root-BRhzhhXZ.mjs").then((n) => n.t);
|
|
454
|
+
requireWorkspaceRoot();
|
|
455
|
+
await withGraphMcpClient("chain-insights-cli-trace-suspect-funds", async (client, config) => {
|
|
456
|
+
const { traceSuspectFunds } = await import("./public-tools-wJoAFDFa.mjs");
|
|
457
|
+
const caseId = opts.case ? await resolveCaseSelector(opts.case) : void 0;
|
|
458
|
+
const result = await traceSuspectFunds(client, config, {
|
|
459
|
+
suspectAddresses: opts.suspectAddresses,
|
|
460
|
+
network: opts.network,
|
|
461
|
+
maxHops: optionalNumber(opts.maxHops),
|
|
462
|
+
perAddressLimit: optionalNumber(opts.perAddressLimit),
|
|
463
|
+
minAmountSum: optionalNumber(opts.minAmountSum),
|
|
464
|
+
incidentTimestampMs: optionalNumber(opts.incidentTimestampMs),
|
|
465
|
+
caseId
|
|
466
|
+
});
|
|
467
|
+
console.log(result.summaryText);
|
|
468
|
+
console.log(JSON.stringify(result.structuredContent, null, 2));
|
|
469
|
+
});
|
|
470
|
+
} catch (err) {
|
|
471
|
+
console.error(err.message);
|
|
472
|
+
process.exit(1);
|
|
473
|
+
}
|
|
474
|
+
})).addCommand(new 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").option("--case <id>", "Case ID to attach compact evidence pointers").action(async (opts) => {
|
|
452
475
|
try {
|
|
453
476
|
const { requireWorkspaceRoot } = await import("./output-root-BRhzhhXZ.mjs").then((n) => n.t);
|
|
454
477
|
requireWorkspaceRoot();
|
|
455
|
-
await withGraphMcpClient("chain-insights-cli-
|
|
456
|
-
const {
|
|
457
|
-
const incidentTimestampMs = optionalNumber(opts.incidentTimestampMs);
|
|
458
|
-
if (incidentTimestampMs === void 0) throw new Error("incident-timestamp-ms is required");
|
|
478
|
+
await withGraphMcpClient("chain-insights-cli-trace-deposit-sources", async (client, config) => {
|
|
479
|
+
const { traceDepositSources } = await import("./public-tools-wJoAFDFa.mjs");
|
|
459
480
|
const caseId = opts.case ? await resolveCaseSelector(opts.case) : void 0;
|
|
460
|
-
const result = await
|
|
461
|
-
|
|
481
|
+
const result = await traceDepositSources(client, config, {
|
|
482
|
+
depositAddresses: opts.depositAddresses,
|
|
462
483
|
network: opts.network,
|
|
463
484
|
maxHops: optionalNumber(opts.maxHops),
|
|
464
|
-
incidentTimestampMs,
|
|
465
|
-
activityPolicyMode: optionalScamTopologyActivityPolicy(opts.activityPolicy),
|
|
466
485
|
caseId
|
|
467
486
|
});
|
|
468
487
|
console.log(result.summaryText);
|
|
@@ -475,7 +494,7 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
|
|
|
475
494
|
})).addCommand(new Command("stake-insights").description("Explain Bittensor staking behavior around an address, coldkey, or hotkey").requiredOption("--network <network>", "Network to query. Run `cia mcp networks` for supported networks.").option("--address <address>", "Full Bittensor address to inspect as either coldkey or hotkey").option("--coldkey <address>", "Full Bittensor coldkey address to inspect").option("--hotkey <address>", "Full Bittensor hotkey address to inspect").option("--netuid <number>", "Optional subnet netuid filter").option("--start-timestamp-ms <milliseconds>", "Optional inclusive lower activity timestamp bound").option("--end-timestamp-ms <milliseconds>", "Optional inclusive upper activity timestamp bound").option("--start-block <number>", "Optional start block. Current stake graph parity may require timestamp windows instead.").option("--end-block <number>", "Optional end block. Current stake graph parity may require timestamp windows instead.").option("--depth <number>", "Optional expansion depth limit, default 1, max 3").action(async (opts) => {
|
|
476
495
|
try {
|
|
477
496
|
await withGraphMcpClient("chain-insights-cli-stake-insights", async (client) => {
|
|
478
|
-
const { stakeInsights } = await import("./public-tools-
|
|
497
|
+
const { stakeInsights } = await import("./public-tools-wJoAFDFa.mjs");
|
|
479
498
|
const result = await stakeInsights(client, {
|
|
480
499
|
network: opts.network,
|
|
481
500
|
address: opts.address,
|
|
@@ -498,12 +517,12 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
|
|
|
498
517
|
})).addCommand(new 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) => {
|
|
499
518
|
try {
|
|
500
519
|
const { parseMcpCallArgs } = await import("./call-args-DPXdX3_D.mjs");
|
|
501
|
-
const { assertPublicMcpToolName } = await import("./tool-visibility-
|
|
520
|
+
const { assertPublicMcpToolName } = await import("./tool-visibility-BpyZHRBi.mjs").then((n) => n.n);
|
|
502
521
|
const args = parseMcpCallArgs(rawArgs);
|
|
503
522
|
assertPublicMcpToolName(tool);
|
|
504
523
|
await withGraphMcpClient("chain-insights-cli-call", async (client, config) => {
|
|
505
524
|
if (tool === "address_risk") {
|
|
506
|
-
const { addressRisk } = await import("./public-tools-
|
|
525
|
+
const { addressRisk } = await import("./public-tools-wJoAFDFa.mjs");
|
|
507
526
|
const result = await addressRisk(client, {
|
|
508
527
|
address: String(args["address"] ?? ""),
|
|
509
528
|
network: String(args["network"] ?? ""),
|
|
@@ -512,13 +531,14 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
|
|
|
512
531
|
console.log(result.summaryText);
|
|
513
532
|
return;
|
|
514
533
|
}
|
|
515
|
-
if (tool === "
|
|
516
|
-
const {
|
|
517
|
-
const result = await
|
|
518
|
-
|
|
519
|
-
|
|
534
|
+
if (tool === "trace_victim_funds") {
|
|
535
|
+
const { traceVictimFunds } = await import("./public-tools-wJoAFDFa.mjs");
|
|
536
|
+
const result = await traceVictimFunds(client, config, {
|
|
537
|
+
victimAddresses: args["victim_addresses"] ?? "",
|
|
538
|
+
knownSuspectAddresses: args["known_suspect_addresses"],
|
|
520
539
|
network: String(args["network"] ?? ""),
|
|
521
540
|
caseId: args["case_id"] === void 0 ? void 0 : String(args["case_id"]),
|
|
541
|
+
incidentTimestampMs: optionalNumberArg(args["incident_timestamp_ms"], "incident_timestamp_ms"),
|
|
522
542
|
maxHops: typeof args["max_hops"] === "number" ? args["max_hops"] : void 0,
|
|
523
543
|
perAddressLimit: typeof args["per_address_limit"] === "number" ? args["per_address_limit"] : void 0,
|
|
524
544
|
minAmountSum: typeof args["min_amount_sum"] === "number" ? args["min_amount_sum"] : void 0
|
|
@@ -527,26 +547,35 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
|
|
|
527
547
|
console.log(JSON.stringify(result.structuredContent, null, 2));
|
|
528
548
|
return;
|
|
529
549
|
}
|
|
530
|
-
if (tool === "
|
|
531
|
-
const {
|
|
532
|
-
const
|
|
533
|
-
|
|
534
|
-
const incidentTimestampMs = optionalNumberArg(args["incident_timestamp_ms"], "incident_timestamp_ms");
|
|
535
|
-
if (incidentTimestampMs === void 0) throw new Error("incident_timestamp_ms is required");
|
|
536
|
-
const result = await scamTopology(client, config, {
|
|
537
|
-
victimAddress,
|
|
550
|
+
if (tool === "trace_suspect_funds") {
|
|
551
|
+
const { traceSuspectFunds } = await import("./public-tools-wJoAFDFa.mjs");
|
|
552
|
+
const result = await traceSuspectFunds(client, config, {
|
|
553
|
+
suspectAddresses: args["suspect_addresses"] ?? "",
|
|
538
554
|
network: String(args["network"] ?? ""),
|
|
539
555
|
caseId: args["case_id"] === void 0 ? void 0 : String(args["case_id"]),
|
|
540
556
|
maxHops: typeof args["max_hops"] === "number" ? args["max_hops"] : void 0,
|
|
541
|
-
|
|
542
|
-
|
|
557
|
+
perAddressLimit: typeof args["per_address_limit"] === "number" ? args["per_address_limit"] : void 0,
|
|
558
|
+
minAmountSum: typeof args["min_amount_sum"] === "number" ? args["min_amount_sum"] : void 0,
|
|
559
|
+
incidentTimestampMs: optionalNumberArg(args["incident_timestamp_ms"], "incident_timestamp_ms")
|
|
560
|
+
});
|
|
561
|
+
console.log(result.summaryText);
|
|
562
|
+
console.log(JSON.stringify(result.structuredContent, null, 2));
|
|
563
|
+
return;
|
|
564
|
+
}
|
|
565
|
+
if (tool === "trace_deposit_sources") {
|
|
566
|
+
const { traceDepositSources } = await import("./public-tools-wJoAFDFa.mjs");
|
|
567
|
+
const result = await traceDepositSources(client, config, {
|
|
568
|
+
depositAddresses: args["deposit_addresses"] ?? "",
|
|
569
|
+
network: String(args["network"] ?? ""),
|
|
570
|
+
caseId: args["case_id"] === void 0 ? void 0 : String(args["case_id"]),
|
|
571
|
+
maxHops: typeof args["max_hops"] === "number" ? args["max_hops"] : void 0
|
|
543
572
|
});
|
|
544
573
|
console.log(result.summaryText);
|
|
545
574
|
console.log(JSON.stringify(result.structuredContent, null, 2));
|
|
546
575
|
return;
|
|
547
576
|
}
|
|
548
577
|
if (tool === "stake_insights") {
|
|
549
|
-
const { stakeInsights } = await import("./public-tools-
|
|
578
|
+
const { stakeInsights } = await import("./public-tools-wJoAFDFa.mjs");
|
|
550
579
|
const result = await stakeInsights(client, {
|
|
551
580
|
network: String(args["network"] ?? ""),
|
|
552
581
|
address: args["address"] === void 0 ? void 0 : String(args["address"]),
|
|
@@ -578,14 +607,14 @@ const caseCommand = new Command("case").description("Manage investigation cases"
|
|
|
578
607
|
}).addCommand(new 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) => {
|
|
579
608
|
try {
|
|
580
609
|
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>\"`.");
|
|
581
|
-
const { CaseStore } = await import("./cases-
|
|
610
|
+
const { CaseStore } = await import("./cases-Cp9DUbEV.mjs");
|
|
582
611
|
const tags = opts.tags ? opts.tags.split(",").map((t) => t.trim()).filter(Boolean) : [];
|
|
583
612
|
const c = await CaseStore.create({
|
|
584
613
|
name,
|
|
585
614
|
tags,
|
|
586
615
|
description: opts.description
|
|
587
616
|
});
|
|
588
|
-
const { casesRoot } = await import("./store-
|
|
617
|
+
const { casesRoot } = await import("./store-CTtqQtaE.mjs").then((n) => n.r);
|
|
589
618
|
console.log(`Case opened: ${c.id}`);
|
|
590
619
|
console.log(`Directory: ${path.join(casesRoot(), c.id)}/`);
|
|
591
620
|
console.log(`Status: ${c.status}`);
|
|
@@ -595,7 +624,7 @@ const caseCommand = new Command("case").description("Manage investigation cases"
|
|
|
595
624
|
}
|
|
596
625
|
})).addCommand(new Command("activate").description("Activate a case (set status to active)").argument("<case-id>", "Case ID to activate").action(async (caseSelector) => {
|
|
597
626
|
try {
|
|
598
|
-
const { CaseStore } = await import("./cases-
|
|
627
|
+
const { CaseStore } = await import("./cases-Cp9DUbEV.mjs");
|
|
599
628
|
const caseId = await resolveCaseSelector(caseSelector);
|
|
600
629
|
const c = await CaseStore.setStatus(caseId, "active");
|
|
601
630
|
console.log(`Case ${c.id} is now: active`);
|
|
@@ -605,7 +634,7 @@ const caseCommand = new Command("case").description("Manage investigation cases"
|
|
|
605
634
|
}
|
|
606
635
|
})).addCommand(new Command("suspend").description("Suspend a case (set status to suspended)").argument("<case-id>", "Case ID to suspend").action(async (caseSelector) => {
|
|
607
636
|
try {
|
|
608
|
-
const { CaseStore } = await import("./cases-
|
|
637
|
+
const { CaseStore } = await import("./cases-Cp9DUbEV.mjs");
|
|
609
638
|
const caseId = await resolveCaseSelector(caseSelector);
|
|
610
639
|
const c = await CaseStore.setStatus(caseId, "suspended");
|
|
611
640
|
console.log(`Case ${c.id} is now: suspended`);
|
|
@@ -615,7 +644,7 @@ const caseCommand = new Command("case").description("Manage investigation cases"
|
|
|
615
644
|
}
|
|
616
645
|
})).addCommand(new Command("close").description("Close a case permanently").argument("<case-id>", "Case ID to close").action(async (caseSelector) => {
|
|
617
646
|
try {
|
|
618
|
-
const { CaseStore } = await import("./cases-
|
|
647
|
+
const { CaseStore } = await import("./cases-Cp9DUbEV.mjs");
|
|
619
648
|
const caseId = await resolveCaseSelector(caseSelector);
|
|
620
649
|
const c = await CaseStore.setStatus(caseId, "closed");
|
|
621
650
|
console.log(`Case ${c.id} is now: closed`);
|
|
@@ -625,7 +654,7 @@ const caseCommand = new Command("case").description("Manage investigation cases"
|
|
|
625
654
|
}
|
|
626
655
|
})).addCommand(new Command("list").description("List all investigation cases").option("--status <status>", "Filter by status (open|active|suspended|closed)").action(async (opts) => {
|
|
627
656
|
try {
|
|
628
|
-
const { CaseStore } = await import("./cases-
|
|
657
|
+
const { CaseStore } = await import("./cases-Cp9DUbEV.mjs");
|
|
629
658
|
const cases = await CaseStore.list();
|
|
630
659
|
const filtered = opts.status ? cases.filter((c) => c.status === opts.status) : cases;
|
|
631
660
|
if (filtered.length === 0) {
|
|
@@ -639,7 +668,7 @@ const caseCommand = new Command("case").description("Manage investigation cases"
|
|
|
639
668
|
}
|
|
640
669
|
})).addCommand(new Command("evidence").description("Manage case evidence").addCommand(new 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) => {
|
|
641
670
|
try {
|
|
642
|
-
const { EvidenceStore } = await import("./cases-
|
|
671
|
+
const { EvidenceStore } = await import("./cases-Cp9DUbEV.mjs");
|
|
643
672
|
const caseId = await resolveCaseSelector(caseSelector);
|
|
644
673
|
const result = await EvidenceStore.append(caseId, {
|
|
645
674
|
source: opts.source,
|
|
@@ -654,7 +683,7 @@ const caseCommand = new Command("case").description("Manage investigation cases"
|
|
|
654
683
|
}
|
|
655
684
|
})).addCommand(new Command("verify").description("Verify evidence manifest integrity for a case").argument("<case-id>", "Case ID to verify").action(async (caseSelector) => {
|
|
656
685
|
try {
|
|
657
|
-
const { EvidenceStore } = await import("./cases-
|
|
686
|
+
const { EvidenceStore } = await import("./cases-Cp9DUbEV.mjs");
|
|
658
687
|
const caseId = await resolveCaseSelector(caseSelector);
|
|
659
688
|
const result = await EvidenceStore.verifyManifest(caseId);
|
|
660
689
|
if (result.ok) console.log(`Manifest OK — ${result.count} evidence file(s) verified`);
|
|
@@ -668,7 +697,7 @@ const caseCommand = new Command("case").description("Manage investigation cases"
|
|
|
668
697
|
}
|
|
669
698
|
}))).addCommand(new Command("dossier").description("Manage entity dossiers for a case").addCommand(new 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) => {
|
|
670
699
|
try {
|
|
671
|
-
const { DossierStore } = await import("./cases-
|
|
700
|
+
const { DossierStore } = await import("./cases-Cp9DUbEV.mjs");
|
|
672
701
|
const caseId = await resolveCaseSelector(caseSelector);
|
|
673
702
|
const entityType = [
|
|
674
703
|
"eoa",
|
|
@@ -685,7 +714,7 @@ const caseCommand = new Command("case").description("Manage investigation cases"
|
|
|
685
714
|
}
|
|
686
715
|
}))).addCommand(new Command("session").description("Manage investigation sessions").addCommand(new 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) => {
|
|
687
716
|
try {
|
|
688
|
-
const { SessionStore } = await import("./cases-
|
|
717
|
+
const { SessionStore } = await import("./cases-Cp9DUbEV.mjs");
|
|
689
718
|
const caseId = await resolveCaseSelector(caseSelector);
|
|
690
719
|
const title = titleParts.join(" ").trim();
|
|
691
720
|
const s = await SessionStore.start(caseId, title ? { title } : {});
|
|
@@ -696,7 +725,7 @@ const caseCommand = new Command("case").description("Manage investigation cases"
|
|
|
696
725
|
}
|
|
697
726
|
})).addCommand(new 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) => {
|
|
698
727
|
try {
|
|
699
|
-
const { SessionStore } = await import("./cases-
|
|
728
|
+
const { SessionStore } = await import("./cases-Cp9DUbEV.mjs");
|
|
700
729
|
const caseId = await resolveCaseSelector(caseSelector);
|
|
701
730
|
await SessionStore.end(caseId, {
|
|
702
731
|
findings: opts.findings,
|
|
@@ -708,7 +737,34 @@ const caseCommand = new Command("case").description("Manage investigation cases"
|
|
|
708
737
|
console.error(err.message);
|
|
709
738
|
process.exit(1);
|
|
710
739
|
}
|
|
711
|
-
}))).addCommand(new Command("
|
|
740
|
+
}))).addCommand(new Command("export").description("Export a case for Obsidian, LLMWiki, 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) => {
|
|
741
|
+
try {
|
|
742
|
+
const target = opts.target === "obsidian-llmwiki" ? opts.target : void 0;
|
|
743
|
+
const mode = [
|
|
744
|
+
"private",
|
|
745
|
+
"partner",
|
|
746
|
+
"public"
|
|
747
|
+
].includes(opts.mode) ? opts.mode : void 0;
|
|
748
|
+
if (!target) throw new Error(`Unsupported export target: ${opts.target}`);
|
|
749
|
+
if (!mode) throw new Error(`Unsupported export mode: ${opts.mode}`);
|
|
750
|
+
const caseId = await resolveCaseSelector(caseSelector);
|
|
751
|
+
const { exportCase } = await import("./export-BqTCO9lP.mjs");
|
|
752
|
+
const result = await exportCase({
|
|
753
|
+
caseId,
|
|
754
|
+
target,
|
|
755
|
+
mode,
|
|
756
|
+
outputDir: opts.out
|
|
757
|
+
});
|
|
758
|
+
console.log(`Case exported: ${result.outputDir}`);
|
|
759
|
+
console.log(`Manifest: ${result.manifestPath}`);
|
|
760
|
+
console.log(`Files: ${result.fileCount}`);
|
|
761
|
+
console.log(`Open first: ${result.nextFile}`);
|
|
762
|
+
for (const warning of result.warnings) console.warn(`Warning: ${warning}`);
|
|
763
|
+
} catch (err) {
|
|
764
|
+
console.error(err.message);
|
|
765
|
+
process.exit(1);
|
|
766
|
+
}
|
|
767
|
+
})).addCommand(new Command("show").description("Show saved case context").argument("<case-id>", "Case ID or case list number to show").action(async (caseSelector) => {
|
|
712
768
|
try {
|
|
713
769
|
await showCaseContext(caseSelector);
|
|
714
770
|
} catch (err) {
|
|
@@ -733,7 +789,7 @@ program.command("playbook").description("Run and manage investigation playbooks"
|
|
|
733
789
|
}
|
|
734
790
|
resolvedParams[key] = kv.slice(eq + 1);
|
|
735
791
|
}
|
|
736
|
-
const { resolvePlaybookContent } = await import("./resolver-
|
|
792
|
+
const { resolvePlaybookContent } = await import("./resolver-2jXNtWQO.mjs");
|
|
737
793
|
const markdown = await resolvePlaybookContent(name);
|
|
738
794
|
const { PlaybookParser } = await import("./parser-CJfMsOl6.mjs");
|
|
739
795
|
const definition = PlaybookParser.parse(markdown, resolvedParams);
|
|
@@ -746,7 +802,7 @@ program.command("playbook").description("Run and manage investigation playbooks"
|
|
|
746
802
|
console.error(`Invalid --from value: "${opts.from}". Must be a positive integer.`);
|
|
747
803
|
process.exit(1);
|
|
748
804
|
}
|
|
749
|
-
const { PlaybookRunner } = await import("./runner-
|
|
805
|
+
const { PlaybookRunner } = await import("./runner-DIJSbkjc.mjs");
|
|
750
806
|
await PlaybookRunner.run(definition, {
|
|
751
807
|
caseId: opts.case,
|
|
752
808
|
from: fromN,
|
|
@@ -759,7 +815,7 @@ program.command("playbook").description("Run and manage investigation playbooks"
|
|
|
759
815
|
}
|
|
760
816
|
})).addCommand(new Command("list").description("List available playbooks (built-in and user-defined)").action(async () => {
|
|
761
817
|
try {
|
|
762
|
-
const { listPlaybooks } = await import("./resolver-
|
|
818
|
+
const { listPlaybooks } = await import("./resolver-2jXNtWQO.mjs");
|
|
763
819
|
const playbooks = await listPlaybooks();
|
|
764
820
|
if (playbooks.length === 0) {
|
|
765
821
|
console.log("No playbooks found.");
|
|
@@ -772,7 +828,7 @@ program.command("playbook").description("Run and manage investigation playbooks"
|
|
|
772
828
|
}
|
|
773
829
|
})).addCommand(new Command("show").description("Show steps for a playbook without executing").argument("<name>", "Playbook name").action(async (name) => {
|
|
774
830
|
try {
|
|
775
|
-
const { resolvePlaybookContent } = await import("./resolver-
|
|
831
|
+
const { resolvePlaybookContent } = await import("./resolver-2jXNtWQO.mjs");
|
|
776
832
|
const { PlaybookParser } = await import("./parser-CJfMsOl6.mjs");
|
|
777
833
|
const markdown = await resolvePlaybookContent(name);
|
|
778
834
|
const definition = PlaybookParser.parse(markdown, {});
|
|
@@ -796,7 +852,7 @@ program.command("viz").description("Generate money flow visualization").argument
|
|
|
796
852
|
console.error("Provide either a case ID or --data <file.json>");
|
|
797
853
|
process.exit(1);
|
|
798
854
|
}
|
|
799
|
-
const { generateVisualization } = await import("./viz-
|
|
855
|
+
const { generateVisualization } = await import("./viz-5y24S5X1.mjs").then((n) => n.n);
|
|
800
856
|
const result = await generateVisualization({
|
|
801
857
|
caseId,
|
|
802
858
|
dataFile: opts.data
|