chain-insights 0.2.32 → 0.3.4
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 +43 -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 +126 -117
- package/docs/investigation-workspaces.md +17 -0
- package/docs/knowledge-exports.md +200 -0
- package/docs/mcp-proxy.md +16 -2
- package/package.json +1 -1
- package/skills/chain-insights-cypher/SKILL.md +6 -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/README.md
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
[Website](https://chain-insights.ai) | [GitHub](https://github.com/chainswarm/chain-insights) | [npm](https://www.npmjs.com/package/chain-insights)
|
|
4
4
|
|
|
5
5
|
Chain Insights is an open-source AML investigation toolkit for AI agents and
|
|
6
|
-
analysts. Install it from npm to screen blockchain addresses, trace
|
|
7
|
-
|
|
6
|
+
analysts. Install it from npm to screen blockchain addresses, trace role-specific
|
|
7
|
+
fund flows, manage case evidence, and generate graph reports.
|
|
8
8
|
|
|
9
9
|
Graph access is configuration-driven. The package defaults to a local GraphRAG
|
|
10
10
|
MCP endpoint for development; hosted endpoints are set explicitly with
|
|
@@ -16,8 +16,9 @@ MCP endpoint for development; hosted endpoints are set explicitly with
|
|
|
16
16
|
| --- | --- |
|
|
17
17
|
| `address_risk` | Screen one address for risk, behavior, neighborhood context, and exchange exposure |
|
|
18
18
|
| `stake_insights` | Explain Bittensor staking relationships, net stake movement, and counterparties |
|
|
19
|
-
| `
|
|
20
|
-
| `
|
|
19
|
+
| `trace_victim_funds` | Trace victim/source funds forward to exchange deposit candidates |
|
|
20
|
+
| `trace_deposit_sources` | Trace backward from suspected deposit/cashout addresses to upstream sources and convergence |
|
|
21
|
+
| `trace_suspect_funds` | Trace suspected scammer, mule, operator, or laundering-ring funds forward to cashout topology |
|
|
21
22
|
| `usage_status` | Check the caller's public free graph query quota for today |
|
|
22
23
|
| `graph_query` | Run one read-only GQL/Cypher query against a GraphRAG MCP graph layer |
|
|
23
24
|
| `graph_query_batch` | Run related read-only graph queries as one MCP call |
|
|
@@ -123,9 +124,9 @@ cia case open "First Chain Insights investigation" \
|
|
|
123
124
|
--tags aml,bittensor \
|
|
124
125
|
--description "Screen and trace a known source address"
|
|
125
126
|
|
|
126
|
-
cia mcp
|
|
127
|
+
cia mcp trace-victim-funds \
|
|
127
128
|
--network bittensor \
|
|
128
|
-
--
|
|
129
|
+
--victim-addresses 5GTjfJaLpBNrgybhY24NqhDnKW9r94z72RSYLxeodxJfSkj5 \
|
|
129
130
|
--case 1
|
|
130
131
|
```
|
|
131
132
|
|
|
@@ -136,6 +137,24 @@ cia case show 1
|
|
|
136
137
|
find reports cases -maxdepth 3 -type f | sort
|
|
137
138
|
```
|
|
138
139
|
|
|
140
|
+
## Export To Obsidian, LLM Wiki, And Agents
|
|
141
|
+
|
|
142
|
+
After a case has evidence, export a local knowledge bundle:
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
cia case evidence verify 1
|
|
146
|
+
cia case export 1 --target obsidian-llmwiki --mode private
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
The export writes Markdown notes, `manifest.chain-insights.json`,
|
|
150
|
+
`graph.chain-insights.json`, `Graph.canvas`, LLM Wiki entrypoints, and prompts
|
|
151
|
+
for Codex, Claude Code, and ChatGPT under `published/<case-slug>/`.
|
|
152
|
+
|
|
153
|
+
Private exports may include full addresses. Use `--mode public` only for
|
|
154
|
+
shareable demos; public mode aliases addresses and removes secrets by default.
|
|
155
|
+
Install and opening steps live in
|
|
156
|
+
[Knowledge exports](docs/knowledge-exports.md).
|
|
157
|
+
|
|
139
158
|
## Demo
|
|
140
159
|
|
|
141
160
|
Run a direct live topology query:
|
|
@@ -154,13 +173,12 @@ cia mcp call graph_query_batch \
|
|
|
154
173
|
'queries=[{"id":"count","query":"USE live_topology MATCH (n) RETURN count(n) AS count LIMIT 1"},{"id":"archive_flows","query":"USE archive_topology MATCH (src:Address)-[f:FLOWS_TO]->(dst:Address) RETURN f.period_granularity AS granularity, src.address AS source, dst.address AS target LIMIT 3"},{"id":"facts_sample","query":"USE facts MATCH (a:Address)-[:HAS_FEATURE]->(f:AddressFeature) RETURN a.address AS address, f.sent_count AS sent_count LIMIT 3"}]'
|
|
155
174
|
```
|
|
156
175
|
|
|
157
|
-
Run
|
|
176
|
+
Run suspect topology without requiring an incident timestamp:
|
|
158
177
|
|
|
159
178
|
```bash
|
|
160
|
-
cia mcp
|
|
179
|
+
cia mcp trace-suspect-funds \
|
|
161
180
|
--network bittensor \
|
|
162
|
-
--
|
|
163
|
-
--incident-timestamp-ms 1715532228001 \
|
|
181
|
+
--suspect-addresses 5... \
|
|
164
182
|
--max-hops 16 \
|
|
165
183
|
--case 1
|
|
166
184
|
```
|
|
@@ -208,10 +226,20 @@ and local case state:
|
|
|
208
226
|
- `stake_insights` explains Bittensor coldkey-hotkey-netuid staking
|
|
209
227
|
relationships, aggregate stake movement amounts, top counterparties, first
|
|
210
228
|
and last activity, and source backend evidence.
|
|
211
|
-
- `
|
|
212
|
-
exchange deposit candidates.
|
|
213
|
-
- `
|
|
214
|
-
|
|
229
|
+
- `trace_victim_funds` traces victim/source funds forward through
|
|
230
|
+
intermediaries to exchange deposit candidates.
|
|
231
|
+
- `trace_deposit_sources` traces backward from suspected deposit/cashout
|
|
232
|
+
addresses to upstream sources and shared-source convergence.
|
|
233
|
+
- `trace_suspect_funds` traces suspected scammer, mule, operator, or
|
|
234
|
+
laundering-ring funds forward to cashout topology.
|
|
235
|
+
|
|
236
|
+
The three trace tools share `chain-insights.trace.v1` and return compact,
|
|
237
|
+
chainable results. Full graph/table/report artifacts remain on disk under the
|
|
238
|
+
workspace, with pointers in the tool result and case evidence.
|
|
239
|
+
|
|
240
|
+
Trace traversal treats exchange hot wallets as terminal endpoints only. Tools do
|
|
241
|
+
not expand through exchange nodes or classify them as deposit, suspect, or
|
|
242
|
+
intermediate candidates.
|
|
215
243
|
|
|
216
244
|
When a case is provided, tools can save compact evidence pointers and graph
|
|
217
245
|
reports under the workspace instead of embedding large payloads in case notes.
|
|
@@ -222,6 +250,7 @@ reports under the workspace instead of embedding large payloads in case notes.
|
|
|
222
250
|
| --- | --- |
|
|
223
251
|
| [Graph tools](docs/graph-tools.md) | GraphRAG MCP layers, `graph_query`, `graph_query_batch`, AML tool contracts, graph reports, evidence pointers |
|
|
224
252
|
| [Investigation workspaces](docs/investigation-workspaces.md) | `cia init`, case layout, evidence, dossiers, imports, templates, sessions, reports |
|
|
253
|
+
| [Knowledge exports](docs/knowledge-exports.md) | Install Obsidian and LLM Wiki, export verified cases, open vaults, ingest agent-ready Markdown and graph JSON |
|
|
225
254
|
| [MCP proxy](docs/mcp-proxy.md) | Stdio proxy behavior, endpoint configuration, agent installers, local tools, auth modes, Inspector validation |
|
|
226
255
|
| [Architecture](docs/architecture.md) | Product layers, data flow, local storage, security model, config keys |
|
|
227
256
|
| [Development](docs/development.md) | Build, test, and local install commands |
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import "./frontmatter-D0ccQnUM.mjs";
|
|
2
|
+
import { t as DossierStore } from "./dossier-Bjpcbcxa.mjs";
|
|
3
|
+
import { t as CaseStore } from "./store-CTtqQtaE.mjs";
|
|
4
|
+
import { t as EvidenceStore } from "./evidence-D96PTzOQ.mjs";
|
|
5
|
+
import { t as SessionStore } from "./session-DROyhebe.mjs";
|
|
6
|
+
export { CaseStore, DossierStore, EvidenceStore, SessionStore };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
require("./frontmatter-Dvqa5HX6.cjs");
|
|
2
|
-
const require_dossier = require("./dossier-
|
|
3
|
-
const require_store = require("./store-
|
|
2
|
+
const require_dossier = require("./dossier-BXy57V4-.cjs");
|
|
3
|
+
const require_store = require("./store-CqPfs47P.cjs");
|
|
4
4
|
const require_evidence = require("./evidence-CvEesemA.cjs");
|
|
5
|
-
const require_session = require("./session-
|
|
5
|
+
const require_session = require("./session-BT7VpbAd.cjs");
|
|
6
6
|
exports.CaseStore = require_store.CaseStore;
|
|
7
7
|
exports.DossierStore = require_dossier.DossierStore;
|
|
8
8
|
exports.EvidenceStore = require_evidence.EvidenceStore;
|
package/dist/cli.cjs
CHANGED
|
@@ -21,12 +21,16 @@ if (installerFlags.length > 0 && !rawArgs.some((a) => !a.startsWith("-"))) {
|
|
|
21
21
|
}
|
|
22
22
|
process.exit(0);
|
|
23
23
|
}
|
|
24
|
-
if (rawArgs[0] === "mcp" &&
|
|
25
|
-
|
|
24
|
+
if (rawArgs[0] === "mcp" && [
|
|
25
|
+
"trace-funds",
|
|
26
|
+
"track-funds",
|
|
27
|
+
"scam-topology"
|
|
28
|
+
].includes(rawArgs[1] ?? "")) {
|
|
29
|
+
console.error(`error: unknown command '${rawArgs[1]}'`);
|
|
26
30
|
process.exit(1);
|
|
27
31
|
}
|
|
28
32
|
async function resolveCaseSelector(input) {
|
|
29
|
-
const { resolveCaseSelector } = await Promise.resolve().then(() => require("./selector-
|
|
33
|
+
const { resolveCaseSelector } = await Promise.resolve().then(() => require("./selector-DfAMZEC9.cjs"));
|
|
30
34
|
return resolveCaseSelector(input);
|
|
31
35
|
}
|
|
32
36
|
async function scopeCasesToInvocationDir() {
|
|
@@ -35,7 +39,7 @@ async function scopeCasesToInvocationDir() {
|
|
|
35
39
|
process.env["CHAIN_INSIGHTS_CASES_ROOT"] = activeCasesRoot();
|
|
36
40
|
}
|
|
37
41
|
async function showCaseContext(caseSelector) {
|
|
38
|
-
const { CaseStore } = await Promise.resolve().then(() => require("./cases-
|
|
42
|
+
const { CaseStore } = await Promise.resolve().then(() => require("./cases-sTY5aXav.cjs"));
|
|
39
43
|
const caseId = await resolveCaseSelector(caseSelector);
|
|
40
44
|
const ctx = await CaseStore.loadContext(caseId);
|
|
41
45
|
console.log(`\n=== Case: ${ctx.case.id} ===`);
|
|
@@ -65,11 +69,6 @@ function optionalNumberArg(value, name) {
|
|
|
65
69
|
if (typeof value === "string") return optionalNumber(value);
|
|
66
70
|
throw new Error(`Invalid number for ${name}: ${String(value)}`);
|
|
67
71
|
}
|
|
68
|
-
function optionalScamTopologyActivityPolicy(value) {
|
|
69
|
-
if (value === void 0 || value === null || value === "") return void 0;
|
|
70
|
-
if (value === "node_relative_only" || value === "global_incident_only") return value;
|
|
71
|
-
throw new Error("activity_policy must be one of: node_relative_only, global_incident_only");
|
|
72
|
-
}
|
|
73
72
|
async function withGraphMcpClient(name, fn) {
|
|
74
73
|
const { loadConfig } = await Promise.resolve().then(() => require("./config-BwVx19Og.cjs")).then((n) => n.config_exports);
|
|
75
74
|
const config = await loadConfig();
|
|
@@ -215,7 +214,7 @@ program.command("access-key").description("Configure Graph MCP test access key m
|
|
|
215
214
|
}));
|
|
216
215
|
program.command("init").description("Initialize an investigation workspace").argument("[dir]", "Workspace directory to initialize", ".").option("--force", "Overwrite existing workspace files").action(async (dir, opts) => {
|
|
217
216
|
try {
|
|
218
|
-
const { initWorkspace } = await Promise.resolve().then(() => require("./init-
|
|
217
|
+
const { initWorkspace } = await Promise.resolve().then(() => require("./init-zqbd7i-_.cjs"));
|
|
219
218
|
const result = await initWorkspace({
|
|
220
219
|
targetDir: dir,
|
|
221
220
|
force: opts.force
|
|
@@ -363,7 +362,7 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
|
|
|
363
362
|
try {
|
|
364
363
|
const { loadSchema, saveSchema } = await Promise.resolve().then(() => require("./schema-cache-CJk1EL3L.cjs"));
|
|
365
364
|
const { formatToolsTable } = await Promise.resolve().then(() => require("./format-9NLBykEL.cjs"));
|
|
366
|
-
const { visibleRemoteTools } = await Promise.resolve().then(() => require("./tool-visibility-
|
|
365
|
+
const { visibleRemoteTools } = await Promise.resolve().then(() => require("./tool-visibility-Buq7YdUZ.cjs")).then((n) => n.tool_visibility_exports);
|
|
367
366
|
const { loadConfig } = await Promise.resolve().then(() => require("./config-BwVx19Og.cjs")).then((n) => n.config_exports);
|
|
368
367
|
const { createConfiguredGraphMcpFetch, resolveGraphMcpEndpoint } = await Promise.resolve().then(() => require("./client-Db6IV1tv.cjs")).then((n) => n.client_exports);
|
|
369
368
|
const config = await loadConfig();
|
|
@@ -404,7 +403,7 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
|
|
|
404
403
|
}));
|
|
405
404
|
return;
|
|
406
405
|
}
|
|
407
|
-
const { addressRisk } = await Promise.resolve().then(() => require("./public-tools-
|
|
406
|
+
const { addressRisk } = await Promise.resolve().then(() => require("./public-tools-BvMb3H2P.cjs"));
|
|
408
407
|
const result = await addressRisk(client, {
|
|
409
408
|
address: opts.address,
|
|
410
409
|
network: opts.network,
|
|
@@ -416,29 +415,30 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
|
|
|
416
415
|
console.error(err.message);
|
|
417
416
|
process.exit(1);
|
|
418
417
|
}
|
|
419
|
-
})).addCommand(new commander.Command("
|
|
418
|
+
})).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("--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) => {
|
|
420
419
|
try {
|
|
421
420
|
const { requireWorkspaceRoot } = await Promise.resolve().then(() => require("./output-root-YIbl6PwF.cjs")).then((n) => n.output_root_exports);
|
|
422
421
|
requireWorkspaceRoot();
|
|
423
|
-
await withGraphMcpClient("chain-insights-cli-
|
|
422
|
+
await withGraphMcpClient("chain-insights-cli-trace-victim-funds", async (client, config) => {
|
|
424
423
|
if (opts.remote) {
|
|
425
424
|
printMcpTextContent(await client.callTool({
|
|
426
|
-
name: "
|
|
425
|
+
name: "trace_victim_funds",
|
|
427
426
|
arguments: {
|
|
428
|
-
|
|
427
|
+
victim_addresses: opts.victimAddresses,
|
|
429
428
|
network: opts.network,
|
|
430
|
-
...opts.
|
|
429
|
+
...opts.knownSuspectAddresses ? { known_suspect_addresses: opts.knownSuspectAddresses } : {}
|
|
431
430
|
}
|
|
432
431
|
}));
|
|
433
432
|
return;
|
|
434
433
|
}
|
|
435
|
-
const {
|
|
434
|
+
const { traceVictimFunds } = await Promise.resolve().then(() => require("./public-tools-BvMb3H2P.cjs"));
|
|
436
435
|
const caseId = opts.case ? await resolveCaseSelector(opts.case) : void 0;
|
|
437
|
-
const result = await
|
|
438
|
-
|
|
439
|
-
|
|
436
|
+
const result = await traceVictimFunds(client, config, {
|
|
437
|
+
victimAddresses: opts.victimAddresses,
|
|
438
|
+
knownSuspectAddresses: opts.knownSuspectAddresses,
|
|
440
439
|
network: opts.network,
|
|
441
440
|
caseId,
|
|
441
|
+
incidentTimestampMs: optionalNumber(opts.incidentTimestampMs),
|
|
442
442
|
maxHops: optionalNumber(opts.maxHops),
|
|
443
443
|
perAddressLimit: optionalNumber(opts.perAddressLimit),
|
|
444
444
|
minAmountSum: optionalNumber(opts.minAmountSum)
|
|
@@ -450,21 +450,40 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
|
|
|
450
450
|
console.error(err.message);
|
|
451
451
|
process.exit(1);
|
|
452
452
|
}
|
|
453
|
-
})).addCommand(new commander.Command("
|
|
453
|
+
})).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").option("--case <id>", "Case ID to attach compact evidence pointers").action(async (opts) => {
|
|
454
|
+
try {
|
|
455
|
+
const { requireWorkspaceRoot } = await Promise.resolve().then(() => require("./output-root-YIbl6PwF.cjs")).then((n) => n.output_root_exports);
|
|
456
|
+
requireWorkspaceRoot();
|
|
457
|
+
await withGraphMcpClient("chain-insights-cli-trace-suspect-funds", async (client, config) => {
|
|
458
|
+
const { traceSuspectFunds } = await Promise.resolve().then(() => require("./public-tools-BvMb3H2P.cjs"));
|
|
459
|
+
const caseId = opts.case ? await resolveCaseSelector(opts.case) : void 0;
|
|
460
|
+
const result = await traceSuspectFunds(client, config, {
|
|
461
|
+
suspectAddresses: opts.suspectAddresses,
|
|
462
|
+
network: opts.network,
|
|
463
|
+
maxHops: optionalNumber(opts.maxHops),
|
|
464
|
+
perAddressLimit: optionalNumber(opts.perAddressLimit),
|
|
465
|
+
minAmountSum: optionalNumber(opts.minAmountSum),
|
|
466
|
+
incidentTimestampMs: optionalNumber(opts.incidentTimestampMs),
|
|
467
|
+
caseId
|
|
468
|
+
});
|
|
469
|
+
console.log(result.summaryText);
|
|
470
|
+
console.log(JSON.stringify(result.structuredContent, null, 2));
|
|
471
|
+
});
|
|
472
|
+
} catch (err) {
|
|
473
|
+
console.error(err.message);
|
|
474
|
+
process.exit(1);
|
|
475
|
+
}
|
|
476
|
+
})).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").option("--case <id>", "Case ID to attach compact evidence pointers").action(async (opts) => {
|
|
454
477
|
try {
|
|
455
478
|
const { requireWorkspaceRoot } = await Promise.resolve().then(() => require("./output-root-YIbl6PwF.cjs")).then((n) => n.output_root_exports);
|
|
456
479
|
requireWorkspaceRoot();
|
|
457
|
-
await withGraphMcpClient("chain-insights-cli-
|
|
458
|
-
const {
|
|
459
|
-
const incidentTimestampMs = optionalNumber(opts.incidentTimestampMs);
|
|
460
|
-
if (incidentTimestampMs === void 0) throw new Error("incident-timestamp-ms is required");
|
|
480
|
+
await withGraphMcpClient("chain-insights-cli-trace-deposit-sources", async (client, config) => {
|
|
481
|
+
const { traceDepositSources } = await Promise.resolve().then(() => require("./public-tools-BvMb3H2P.cjs"));
|
|
461
482
|
const caseId = opts.case ? await resolveCaseSelector(opts.case) : void 0;
|
|
462
|
-
const result = await
|
|
463
|
-
|
|
483
|
+
const result = await traceDepositSources(client, config, {
|
|
484
|
+
depositAddresses: opts.depositAddresses,
|
|
464
485
|
network: opts.network,
|
|
465
486
|
maxHops: optionalNumber(opts.maxHops),
|
|
466
|
-
incidentTimestampMs,
|
|
467
|
-
activityPolicyMode: optionalScamTopologyActivityPolicy(opts.activityPolicy),
|
|
468
487
|
caseId
|
|
469
488
|
});
|
|
470
489
|
console.log(result.summaryText);
|
|
@@ -477,7 +496,7 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
|
|
|
477
496
|
})).addCommand(new commander.Command("stake-insights").description("Explain Bittensor staking behavior around an address, coldkey, or hotkey").requiredOption("--network <network>", "Network to query. Run `cia mcp networks` for supported networks.").option("--address <address>", "Full Bittensor address to inspect as either coldkey or hotkey").option("--coldkey <address>", "Full Bittensor coldkey address to inspect").option("--hotkey <address>", "Full Bittensor hotkey address to inspect").option("--netuid <number>", "Optional subnet netuid filter").option("--start-timestamp-ms <milliseconds>", "Optional inclusive lower activity timestamp bound").option("--end-timestamp-ms <milliseconds>", "Optional inclusive upper activity timestamp bound").option("--start-block <number>", "Optional start block. Current stake graph parity may require timestamp windows instead.").option("--end-block <number>", "Optional end block. Current stake graph parity may require timestamp windows instead.").option("--depth <number>", "Optional expansion depth limit, default 1, max 3").action(async (opts) => {
|
|
478
497
|
try {
|
|
479
498
|
await withGraphMcpClient("chain-insights-cli-stake-insights", async (client) => {
|
|
480
|
-
const { stakeInsights } = await Promise.resolve().then(() => require("./public-tools-
|
|
499
|
+
const { stakeInsights } = await Promise.resolve().then(() => require("./public-tools-BvMb3H2P.cjs"));
|
|
481
500
|
const result = await stakeInsights(client, {
|
|
482
501
|
network: opts.network,
|
|
483
502
|
address: opts.address,
|
|
@@ -500,12 +519,12 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
|
|
|
500
519
|
})).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) => {
|
|
501
520
|
try {
|
|
502
521
|
const { parseMcpCallArgs } = await Promise.resolve().then(() => require("./call-args-CcUV6gFS.cjs"));
|
|
503
|
-
const { assertPublicMcpToolName } = await Promise.resolve().then(() => require("./tool-visibility-
|
|
522
|
+
const { assertPublicMcpToolName } = await Promise.resolve().then(() => require("./tool-visibility-Buq7YdUZ.cjs")).then((n) => n.tool_visibility_exports);
|
|
504
523
|
const args = parseMcpCallArgs(rawArgs);
|
|
505
524
|
assertPublicMcpToolName(tool);
|
|
506
525
|
await withGraphMcpClient("chain-insights-cli-call", async (client, config) => {
|
|
507
526
|
if (tool === "address_risk") {
|
|
508
|
-
const { addressRisk } = await Promise.resolve().then(() => require("./public-tools-
|
|
527
|
+
const { addressRisk } = await Promise.resolve().then(() => require("./public-tools-BvMb3H2P.cjs"));
|
|
509
528
|
const result = await addressRisk(client, {
|
|
510
529
|
address: String(args["address"] ?? ""),
|
|
511
530
|
network: String(args["network"] ?? ""),
|
|
@@ -514,13 +533,14 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
|
|
|
514
533
|
console.log(result.summaryText);
|
|
515
534
|
return;
|
|
516
535
|
}
|
|
517
|
-
if (tool === "
|
|
518
|
-
const {
|
|
519
|
-
const result = await
|
|
520
|
-
|
|
521
|
-
|
|
536
|
+
if (tool === "trace_victim_funds") {
|
|
537
|
+
const { traceVictimFunds } = await Promise.resolve().then(() => require("./public-tools-BvMb3H2P.cjs"));
|
|
538
|
+
const result = await traceVictimFunds(client, config, {
|
|
539
|
+
victimAddresses: args["victim_addresses"] ?? "",
|
|
540
|
+
knownSuspectAddresses: args["known_suspect_addresses"],
|
|
522
541
|
network: String(args["network"] ?? ""),
|
|
523
542
|
caseId: args["case_id"] === void 0 ? void 0 : String(args["case_id"]),
|
|
543
|
+
incidentTimestampMs: optionalNumberArg(args["incident_timestamp_ms"], "incident_timestamp_ms"),
|
|
524
544
|
maxHops: typeof args["max_hops"] === "number" ? args["max_hops"] : void 0,
|
|
525
545
|
perAddressLimit: typeof args["per_address_limit"] === "number" ? args["per_address_limit"] : void 0,
|
|
526
546
|
minAmountSum: typeof args["min_amount_sum"] === "number" ? args["min_amount_sum"] : void 0
|
|
@@ -529,26 +549,35 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
|
|
|
529
549
|
console.log(JSON.stringify(result.structuredContent, null, 2));
|
|
530
550
|
return;
|
|
531
551
|
}
|
|
532
|
-
if (tool === "
|
|
533
|
-
const {
|
|
534
|
-
const
|
|
535
|
-
|
|
536
|
-
const incidentTimestampMs = optionalNumberArg(args["incident_timestamp_ms"], "incident_timestamp_ms");
|
|
537
|
-
if (incidentTimestampMs === void 0) throw new Error("incident_timestamp_ms is required");
|
|
538
|
-
const result = await scamTopology(client, config, {
|
|
539
|
-
victimAddress,
|
|
552
|
+
if (tool === "trace_suspect_funds") {
|
|
553
|
+
const { traceSuspectFunds } = await Promise.resolve().then(() => require("./public-tools-BvMb3H2P.cjs"));
|
|
554
|
+
const result = await traceSuspectFunds(client, config, {
|
|
555
|
+
suspectAddresses: args["suspect_addresses"] ?? "",
|
|
540
556
|
network: String(args["network"] ?? ""),
|
|
541
557
|
caseId: args["case_id"] === void 0 ? void 0 : String(args["case_id"]),
|
|
542
558
|
maxHops: typeof args["max_hops"] === "number" ? args["max_hops"] : void 0,
|
|
543
|
-
|
|
544
|
-
|
|
559
|
+
perAddressLimit: typeof args["per_address_limit"] === "number" ? args["per_address_limit"] : void 0,
|
|
560
|
+
minAmountSum: typeof args["min_amount_sum"] === "number" ? args["min_amount_sum"] : void 0,
|
|
561
|
+
incidentTimestampMs: optionalNumberArg(args["incident_timestamp_ms"], "incident_timestamp_ms")
|
|
562
|
+
});
|
|
563
|
+
console.log(result.summaryText);
|
|
564
|
+
console.log(JSON.stringify(result.structuredContent, null, 2));
|
|
565
|
+
return;
|
|
566
|
+
}
|
|
567
|
+
if (tool === "trace_deposit_sources") {
|
|
568
|
+
const { traceDepositSources } = await Promise.resolve().then(() => require("./public-tools-BvMb3H2P.cjs"));
|
|
569
|
+
const result = await traceDepositSources(client, config, {
|
|
570
|
+
depositAddresses: args["deposit_addresses"] ?? "",
|
|
571
|
+
network: String(args["network"] ?? ""),
|
|
572
|
+
caseId: args["case_id"] === void 0 ? void 0 : String(args["case_id"]),
|
|
573
|
+
maxHops: typeof args["max_hops"] === "number" ? args["max_hops"] : void 0
|
|
545
574
|
});
|
|
546
575
|
console.log(result.summaryText);
|
|
547
576
|
console.log(JSON.stringify(result.structuredContent, null, 2));
|
|
548
577
|
return;
|
|
549
578
|
}
|
|
550
579
|
if (tool === "stake_insights") {
|
|
551
|
-
const { stakeInsights } = await Promise.resolve().then(() => require("./public-tools-
|
|
580
|
+
const { stakeInsights } = await Promise.resolve().then(() => require("./public-tools-BvMb3H2P.cjs"));
|
|
552
581
|
const result = await stakeInsights(client, {
|
|
553
582
|
network: String(args["network"] ?? ""),
|
|
554
583
|
address: args["address"] === void 0 ? void 0 : String(args["address"]),
|
|
@@ -580,14 +609,14 @@ const caseCommand = new commander.Command("case").description("Manage investigat
|
|
|
580
609
|
}).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) => {
|
|
581
610
|
try {
|
|
582
611
|
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>\"`.");
|
|
583
|
-
const { CaseStore } = await Promise.resolve().then(() => require("./cases-
|
|
612
|
+
const { CaseStore } = await Promise.resolve().then(() => require("./cases-sTY5aXav.cjs"));
|
|
584
613
|
const tags = opts.tags ? opts.tags.split(",").map((t) => t.trim()).filter(Boolean) : [];
|
|
585
614
|
const c = await CaseStore.create({
|
|
586
615
|
name,
|
|
587
616
|
tags,
|
|
588
617
|
description: opts.description
|
|
589
618
|
});
|
|
590
|
-
const { casesRoot } = await Promise.resolve().then(() => require("./store-
|
|
619
|
+
const { casesRoot } = await Promise.resolve().then(() => require("./store-CqPfs47P.cjs")).then((n) => n.store_exports);
|
|
591
620
|
console.log(`Case opened: ${c.id}`);
|
|
592
621
|
console.log(`Directory: ${node_path.default.join(casesRoot(), c.id)}/`);
|
|
593
622
|
console.log(`Status: ${c.status}`);
|
|
@@ -597,7 +626,7 @@ const caseCommand = new commander.Command("case").description("Manage investigat
|
|
|
597
626
|
}
|
|
598
627
|
})).addCommand(new commander.Command("activate").description("Activate a case (set status to active)").argument("<case-id>", "Case ID to activate").action(async (caseSelector) => {
|
|
599
628
|
try {
|
|
600
|
-
const { CaseStore } = await Promise.resolve().then(() => require("./cases-
|
|
629
|
+
const { CaseStore } = await Promise.resolve().then(() => require("./cases-sTY5aXav.cjs"));
|
|
601
630
|
const caseId = await resolveCaseSelector(caseSelector);
|
|
602
631
|
const c = await CaseStore.setStatus(caseId, "active");
|
|
603
632
|
console.log(`Case ${c.id} is now: active`);
|
|
@@ -607,7 +636,7 @@ const caseCommand = new commander.Command("case").description("Manage investigat
|
|
|
607
636
|
}
|
|
608
637
|
})).addCommand(new commander.Command("suspend").description("Suspend a case (set status to suspended)").argument("<case-id>", "Case ID to suspend").action(async (caseSelector) => {
|
|
609
638
|
try {
|
|
610
|
-
const { CaseStore } = await Promise.resolve().then(() => require("./cases-
|
|
639
|
+
const { CaseStore } = await Promise.resolve().then(() => require("./cases-sTY5aXav.cjs"));
|
|
611
640
|
const caseId = await resolveCaseSelector(caseSelector);
|
|
612
641
|
const c = await CaseStore.setStatus(caseId, "suspended");
|
|
613
642
|
console.log(`Case ${c.id} is now: suspended`);
|
|
@@ -617,7 +646,7 @@ const caseCommand = new commander.Command("case").description("Manage investigat
|
|
|
617
646
|
}
|
|
618
647
|
})).addCommand(new commander.Command("close").description("Close a case permanently").argument("<case-id>", "Case ID to close").action(async (caseSelector) => {
|
|
619
648
|
try {
|
|
620
|
-
const { CaseStore } = await Promise.resolve().then(() => require("./cases-
|
|
649
|
+
const { CaseStore } = await Promise.resolve().then(() => require("./cases-sTY5aXav.cjs"));
|
|
621
650
|
const caseId = await resolveCaseSelector(caseSelector);
|
|
622
651
|
const c = await CaseStore.setStatus(caseId, "closed");
|
|
623
652
|
console.log(`Case ${c.id} is now: closed`);
|
|
@@ -627,7 +656,7 @@ const caseCommand = new commander.Command("case").description("Manage investigat
|
|
|
627
656
|
}
|
|
628
657
|
})).addCommand(new commander.Command("list").description("List all investigation cases").option("--status <status>", "Filter by status (open|active|suspended|closed)").action(async (opts) => {
|
|
629
658
|
try {
|
|
630
|
-
const { CaseStore } = await Promise.resolve().then(() => require("./cases-
|
|
659
|
+
const { CaseStore } = await Promise.resolve().then(() => require("./cases-sTY5aXav.cjs"));
|
|
631
660
|
const cases = await CaseStore.list();
|
|
632
661
|
const filtered = opts.status ? cases.filter((c) => c.status === opts.status) : cases;
|
|
633
662
|
if (filtered.length === 0) {
|
|
@@ -641,7 +670,7 @@ const caseCommand = new commander.Command("case").description("Manage investigat
|
|
|
641
670
|
}
|
|
642
671
|
})).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) => {
|
|
643
672
|
try {
|
|
644
|
-
const { EvidenceStore } = await Promise.resolve().then(() => require("./cases-
|
|
673
|
+
const { EvidenceStore } = await Promise.resolve().then(() => require("./cases-sTY5aXav.cjs"));
|
|
645
674
|
const caseId = await resolveCaseSelector(caseSelector);
|
|
646
675
|
const result = await EvidenceStore.append(caseId, {
|
|
647
676
|
source: opts.source,
|
|
@@ -656,7 +685,7 @@ const caseCommand = new commander.Command("case").description("Manage investigat
|
|
|
656
685
|
}
|
|
657
686
|
})).addCommand(new commander.Command("verify").description("Verify evidence manifest integrity for a case").argument("<case-id>", "Case ID to verify").action(async (caseSelector) => {
|
|
658
687
|
try {
|
|
659
|
-
const { EvidenceStore } = await Promise.resolve().then(() => require("./cases-
|
|
688
|
+
const { EvidenceStore } = await Promise.resolve().then(() => require("./cases-sTY5aXav.cjs"));
|
|
660
689
|
const caseId = await resolveCaseSelector(caseSelector);
|
|
661
690
|
const result = await EvidenceStore.verifyManifest(caseId);
|
|
662
691
|
if (result.ok) console.log(`Manifest OK — ${result.count} evidence file(s) verified`);
|
|
@@ -670,7 +699,7 @@ const caseCommand = new commander.Command("case").description("Manage investigat
|
|
|
670
699
|
}
|
|
671
700
|
}))).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) => {
|
|
672
701
|
try {
|
|
673
|
-
const { DossierStore } = await Promise.resolve().then(() => require("./cases-
|
|
702
|
+
const { DossierStore } = await Promise.resolve().then(() => require("./cases-sTY5aXav.cjs"));
|
|
674
703
|
const caseId = await resolveCaseSelector(caseSelector);
|
|
675
704
|
const entityType = [
|
|
676
705
|
"eoa",
|
|
@@ -687,7 +716,7 @@ const caseCommand = new commander.Command("case").description("Manage investigat
|
|
|
687
716
|
}
|
|
688
717
|
}))).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) => {
|
|
689
718
|
try {
|
|
690
|
-
const { SessionStore } = await Promise.resolve().then(() => require("./cases-
|
|
719
|
+
const { SessionStore } = await Promise.resolve().then(() => require("./cases-sTY5aXav.cjs"));
|
|
691
720
|
const caseId = await resolveCaseSelector(caseSelector);
|
|
692
721
|
const title = titleParts.join(" ").trim();
|
|
693
722
|
const s = await SessionStore.start(caseId, title ? { title } : {});
|
|
@@ -698,7 +727,7 @@ const caseCommand = new commander.Command("case").description("Manage investigat
|
|
|
698
727
|
}
|
|
699
728
|
})).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) => {
|
|
700
729
|
try {
|
|
701
|
-
const { SessionStore } = await Promise.resolve().then(() => require("./cases-
|
|
730
|
+
const { SessionStore } = await Promise.resolve().then(() => require("./cases-sTY5aXav.cjs"));
|
|
702
731
|
const caseId = await resolveCaseSelector(caseSelector);
|
|
703
732
|
await SessionStore.end(caseId, {
|
|
704
733
|
findings: opts.findings,
|
|
@@ -710,7 +739,34 @@ const caseCommand = new commander.Command("case").description("Manage investigat
|
|
|
710
739
|
console.error(err.message);
|
|
711
740
|
process.exit(1);
|
|
712
741
|
}
|
|
713
|
-
}))).addCommand(new commander.Command("
|
|
742
|
+
}))).addCommand(new commander.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) => {
|
|
743
|
+
try {
|
|
744
|
+
const target = opts.target === "obsidian-llmwiki" ? opts.target : void 0;
|
|
745
|
+
const mode = [
|
|
746
|
+
"private",
|
|
747
|
+
"partner",
|
|
748
|
+
"public"
|
|
749
|
+
].includes(opts.mode) ? opts.mode : void 0;
|
|
750
|
+
if (!target) throw new Error(`Unsupported export target: ${opts.target}`);
|
|
751
|
+
if (!mode) throw new Error(`Unsupported export mode: ${opts.mode}`);
|
|
752
|
+
const caseId = await resolveCaseSelector(caseSelector);
|
|
753
|
+
const { exportCase } = await Promise.resolve().then(() => require("./export-DsXgtCwO.cjs"));
|
|
754
|
+
const result = await exportCase({
|
|
755
|
+
caseId,
|
|
756
|
+
target,
|
|
757
|
+
mode,
|
|
758
|
+
outputDir: opts.out
|
|
759
|
+
});
|
|
760
|
+
console.log(`Case exported: ${result.outputDir}`);
|
|
761
|
+
console.log(`Manifest: ${result.manifestPath}`);
|
|
762
|
+
console.log(`Files: ${result.fileCount}`);
|
|
763
|
+
console.log(`Open first: ${result.nextFile}`);
|
|
764
|
+
for (const warning of result.warnings) console.warn(`Warning: ${warning}`);
|
|
765
|
+
} catch (err) {
|
|
766
|
+
console.error(err.message);
|
|
767
|
+
process.exit(1);
|
|
768
|
+
}
|
|
769
|
+
})).addCommand(new commander.Command("show").description("Show saved case context").argument("<case-id>", "Case ID or case list number to show").action(async (caseSelector) => {
|
|
714
770
|
try {
|
|
715
771
|
await showCaseContext(caseSelector);
|
|
716
772
|
} catch (err) {
|
|
@@ -735,7 +791,7 @@ program.command("playbook").description("Run and manage investigation playbooks"
|
|
|
735
791
|
}
|
|
736
792
|
resolvedParams[key] = kv.slice(eq + 1);
|
|
737
793
|
}
|
|
738
|
-
const { resolvePlaybookContent } = await Promise.resolve().then(() => require("./resolver-
|
|
794
|
+
const { resolvePlaybookContent } = await Promise.resolve().then(() => require("./resolver-CZdQwKvh.cjs"));
|
|
739
795
|
const markdown = await resolvePlaybookContent(name);
|
|
740
796
|
const { PlaybookParser } = await Promise.resolve().then(() => require("./parser-BXLAHYnZ.cjs"));
|
|
741
797
|
const definition = PlaybookParser.parse(markdown, resolvedParams);
|
|
@@ -748,7 +804,7 @@ program.command("playbook").description("Run and manage investigation playbooks"
|
|
|
748
804
|
console.error(`Invalid --from value: "${opts.from}". Must be a positive integer.`);
|
|
749
805
|
process.exit(1);
|
|
750
806
|
}
|
|
751
|
-
const { PlaybookRunner } = await Promise.resolve().then(() => require("./runner-
|
|
807
|
+
const { PlaybookRunner } = await Promise.resolve().then(() => require("./runner-BhZ4lnF1.cjs"));
|
|
752
808
|
await PlaybookRunner.run(definition, {
|
|
753
809
|
caseId: opts.case,
|
|
754
810
|
from: fromN,
|
|
@@ -761,7 +817,7 @@ program.command("playbook").description("Run and manage investigation playbooks"
|
|
|
761
817
|
}
|
|
762
818
|
})).addCommand(new commander.Command("list").description("List available playbooks (built-in and user-defined)").action(async () => {
|
|
763
819
|
try {
|
|
764
|
-
const { listPlaybooks } = await Promise.resolve().then(() => require("./resolver-
|
|
820
|
+
const { listPlaybooks } = await Promise.resolve().then(() => require("./resolver-CZdQwKvh.cjs"));
|
|
765
821
|
const playbooks = await listPlaybooks();
|
|
766
822
|
if (playbooks.length === 0) {
|
|
767
823
|
console.log("No playbooks found.");
|
|
@@ -774,7 +830,7 @@ program.command("playbook").description("Run and manage investigation playbooks"
|
|
|
774
830
|
}
|
|
775
831
|
})).addCommand(new commander.Command("show").description("Show steps for a playbook without executing").argument("<name>", "Playbook name").action(async (name) => {
|
|
776
832
|
try {
|
|
777
|
-
const { resolvePlaybookContent } = await Promise.resolve().then(() => require("./resolver-
|
|
833
|
+
const { resolvePlaybookContent } = await Promise.resolve().then(() => require("./resolver-CZdQwKvh.cjs"));
|
|
778
834
|
const { PlaybookParser } = await Promise.resolve().then(() => require("./parser-BXLAHYnZ.cjs"));
|
|
779
835
|
const markdown = await resolvePlaybookContent(name);
|
|
780
836
|
const definition = PlaybookParser.parse(markdown, {});
|
|
@@ -798,7 +854,7 @@ program.command("viz").description("Generate money flow visualization").argument
|
|
|
798
854
|
console.error("Provide either a case ID or --data <file.json>");
|
|
799
855
|
process.exit(1);
|
|
800
856
|
}
|
|
801
|
-
const { generateVisualization } = await Promise.resolve().then(() => require("./viz-
|
|
857
|
+
const { generateVisualization } = await Promise.resolve().then(() => require("./viz-Dqp3C5kb.cjs")).then((n) => n.viz_exports);
|
|
802
858
|
const result = await generateVisualization({
|
|
803
859
|
caseId,
|
|
804
860
|
dataFile: opts.data
|