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.mjs
CHANGED
|
@@ -27,34 +27,6 @@ if (rawArgs[0] === "mcp" && [
|
|
|
27
27
|
console.error(`error: unknown command '${rawArgs[1]}'`);
|
|
28
28
|
process.exit(1);
|
|
29
29
|
}
|
|
30
|
-
async function resolveCaseSelector(input) {
|
|
31
|
-
const { resolveCaseSelector } = await import("./selector-BvXM9jbe.mjs");
|
|
32
|
-
return resolveCaseSelector(input);
|
|
33
|
-
}
|
|
34
|
-
async function scopeCasesToInvocationDir() {
|
|
35
|
-
if (process.env["CHAIN_INSIGHTS_CASES_ROOT"]?.trim()) return;
|
|
36
|
-
const { activeCasesRoot } = await import("./active-ByNgjuAg.mjs").then((n) => n.n);
|
|
37
|
-
process.env["CHAIN_INSIGHTS_CASES_ROOT"] = activeCasesRoot();
|
|
38
|
-
}
|
|
39
|
-
async function showCaseContext(caseSelector) {
|
|
40
|
-
const { CaseStore } = await import("./cases-TVcAifxu.mjs").then((n) => n.t);
|
|
41
|
-
const caseId = await resolveCaseSelector(caseSelector);
|
|
42
|
-
const ctx = await CaseStore.loadContext(caseId);
|
|
43
|
-
console.log(`\n=== Case: ${ctx.case.id} ===`);
|
|
44
|
-
console.log(`Name: ${ctx.case.name}`);
|
|
45
|
-
console.log(`Status: ${ctx.case.status}`);
|
|
46
|
-
console.log(`Tags: ${ctx.case.tags.join(", ") || "none"}`);
|
|
47
|
-
console.log(`Evidence files: ${ctx.evidenceCount}`);
|
|
48
|
-
console.log(`Dossiers: ${ctx.dossierSummaries.length}`);
|
|
49
|
-
if (ctx.lastSession) {
|
|
50
|
-
console.log(`\n--- Last Session (${ctx.lastSession.sessionId}) ---`);
|
|
51
|
-
console.log(ctx.lastSession.body.slice(0, 500));
|
|
52
|
-
} else console.log("\nNo previous sessions.");
|
|
53
|
-
if (ctx.dossierSummaries.length > 0) {
|
|
54
|
-
console.log("\n--- Entity Dossiers ---");
|
|
55
|
-
for (const d of ctx.dossierSummaries) console.log(` ${d.address} [${d.type}] tags: ${d.riskTags || "none"}`);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
30
|
function optionalNumber(value) {
|
|
59
31
|
if (value === void 0) return void 0;
|
|
60
32
|
const parsed = Number(value);
|
|
@@ -68,9 +40,9 @@ function optionalNumberArg(value, name) {
|
|
|
68
40
|
throw new Error(`Invalid number for ${name}: ${String(value)}`);
|
|
69
41
|
}
|
|
70
42
|
async function withGraphMcpClient(name, fn) {
|
|
71
|
-
const { loadConfig } = await import("./config-
|
|
43
|
+
const { loadConfig } = await import("./config-C6zM8Xir.mjs").then((n) => n.t);
|
|
72
44
|
const config = await loadConfig();
|
|
73
|
-
const { createConfiguredGraphMcpFetch, resolveGraphMcpEndpoint } = await import("./client-
|
|
45
|
+
const { createConfiguredGraphMcpFetch, resolveGraphMcpEndpoint } = await import("./client-ytTO0mcZ.mjs").then((n) => n.r);
|
|
74
46
|
const paymentFetch = await createConfiguredGraphMcpFetch(config);
|
|
75
47
|
const { Client } = await import("@modelcontextprotocol/sdk/client/index.js");
|
|
76
48
|
const { StreamableHTTPClientTransport } = await import("@modelcontextprotocol/sdk/client/streamableHttp.js");
|
|
@@ -88,9 +60,51 @@ async function withGraphMcpClient(name, fn) {
|
|
|
88
60
|
function printMcpTextContent(result) {
|
|
89
61
|
for (const item of result.content ?? []) if (item.type === "text") console.log(item.text);
|
|
90
62
|
}
|
|
63
|
+
function addExposureSubjectOptions(command) {
|
|
64
|
+
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");
|
|
65
|
+
}
|
|
66
|
+
function addExposureMarketOptions(command, requiredInstrument, includeNetwork = true) {
|
|
67
|
+
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");
|
|
68
|
+
if (includeNetwork) configured = configured.requiredOption("--network <network>", "Network to query. Run `cia mcp networks` for supported networks.");
|
|
69
|
+
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");
|
|
70
|
+
}
|
|
71
|
+
function buildExposureInsightCommand(name, tool, description) {
|
|
72
|
+
const command = new Command(name).description(description);
|
|
73
|
+
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);
|
|
74
|
+
if (tool === "exposure_correlation") configured.option("--candidate-accounts <addresses>", "Comma-separated candidate accounts to compare against");
|
|
75
|
+
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");
|
|
76
|
+
return configured.action(async (opts) => {
|
|
77
|
+
try {
|
|
78
|
+
await withGraphMcpClient(`chain-insights-cli-${name}`, async (client) => {
|
|
79
|
+
const { exposureCarry, exposureCorrelation, exposureCrowding, exposureExitPressure, exposureExplain, exposureQuality } = await import("./public-tools-brHmHGYm.mjs");
|
|
80
|
+
const args = {
|
|
81
|
+
network: opts.network,
|
|
82
|
+
account: opts.account,
|
|
83
|
+
owner: opts.owner,
|
|
84
|
+
counterparty: opts.counterparty,
|
|
85
|
+
venue: opts.venue,
|
|
86
|
+
instrument: opts.instrument,
|
|
87
|
+
market: opts.market,
|
|
88
|
+
instrumentType: opts.instrumentType,
|
|
89
|
+
startTimestampMs: optionalNumber(opts.startTimestampMs),
|
|
90
|
+
endTimestampMs: optionalNumber(opts.endTimestampMs),
|
|
91
|
+
limit: optionalNumber(opts.limit),
|
|
92
|
+
candidateAccounts: opts.candidateAccounts,
|
|
93
|
+
positionId: opts.positionId
|
|
94
|
+
};
|
|
95
|
+
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);
|
|
96
|
+
console.log(result.summaryText);
|
|
97
|
+
console.log(JSON.stringify(result.structuredContent, null, 2));
|
|
98
|
+
});
|
|
99
|
+
} catch (err) {
|
|
100
|
+
console.error(err.message);
|
|
101
|
+
process.exit(1);
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
}
|
|
91
105
|
async function printNetworkCapabilities(opts) {
|
|
92
|
-
const { loadConfig } = await import("./config-
|
|
93
|
-
const { fetchNetworkCapabilities, formatNetworkCapabilities } = await import("./capabilities-
|
|
106
|
+
const { loadConfig } = await import("./config-C6zM8Xir.mjs").then((n) => n.t);
|
|
107
|
+
const { fetchNetworkCapabilities, formatNetworkCapabilities } = await import("./capabilities-CM72SErE.mjs");
|
|
94
108
|
const document = await fetchNetworkCapabilities(await loadConfig());
|
|
95
109
|
if (opts.json) console.log(JSON.stringify(document, null, 2));
|
|
96
110
|
else console.log(formatNetworkCapabilities(document));
|
|
@@ -105,9 +119,9 @@ program.command("networks").alias("network").description("List supported graph n
|
|
|
105
119
|
});
|
|
106
120
|
program.command("serve").description("Start local visualization server").option("-p, --port <number>", "Port to bind (default: 4321)", "4321").action(async (opts) => {
|
|
107
121
|
try {
|
|
108
|
-
const { requireWorkspaceRoot } = await import("./output-root-
|
|
122
|
+
const { requireWorkspaceRoot } = await import("./output-root-BK4pdjyz.mjs").then((n) => n.t);
|
|
109
123
|
const workspaceRoot = requireWorkspaceRoot();
|
|
110
|
-
const { startServer } = await import("./server-
|
|
124
|
+
const { startServer } = await import("./server-BK4bfOiv.mjs").then((n) => n.t);
|
|
111
125
|
console.log(`Workspace: ${workspaceRoot}`);
|
|
112
126
|
startServer(parseInt(opts.port, 10));
|
|
113
127
|
} catch (err) {
|
|
@@ -116,8 +130,8 @@ program.command("serve").description("Start local visualization server").option(
|
|
|
116
130
|
}
|
|
117
131
|
});
|
|
118
132
|
program.command("status").description("Show toolkit status and configuration").action(async () => {
|
|
119
|
-
const { loadConfig } = await import("./config-
|
|
120
|
-
const { findActiveWorkspace, activeDataDir } = await import("./active-
|
|
133
|
+
const { loadConfig } = await import("./config-C6zM8Xir.mjs").then((n) => n.t);
|
|
134
|
+
const { findActiveWorkspace, activeDataDir } = await import("./active-BQopLul8.mjs").then((n) => n.t);
|
|
121
135
|
const config = await loadConfig();
|
|
122
136
|
const workspace = findActiveWorkspace();
|
|
123
137
|
const graphMcpStatus = config.graphMcpMode === "debug" && config.graphMcpAuthToken?.trim() ? "bearer access mode" : `${config.graphMcpMode} mode`;
|
|
@@ -152,28 +166,9 @@ program.command("update").description("Check npmjs for a newer Chain Insights re
|
|
|
152
166
|
process.exit(1);
|
|
153
167
|
}
|
|
154
168
|
});
|
|
155
|
-
program.command("obsidian").description("Manage the local Obsidian investigation vault").addCommand(new Command("open").description("Open the current Chain Insights vault in Obsidian").argument("[path]", "Workspace path to open as an Obsidian vault").action(async (workspacePath) => {
|
|
156
|
-
try {
|
|
157
|
-
const { findActiveWorkspace } = await import("./active-ByNgjuAg.mjs").then((n) => n.n);
|
|
158
|
-
const workspace = workspacePath ? path.resolve(workspacePath) : findActiveWorkspace()?.root;
|
|
159
|
-
if (!workspace) {
|
|
160
|
-
console.error("No Chain Insights workspace found. Run: cia init .");
|
|
161
|
-
process.exit(1);
|
|
162
|
-
}
|
|
163
|
-
const open = (await import("open")).default;
|
|
164
|
-
await open(workspace, {
|
|
165
|
-
app: { name: "obsidian" },
|
|
166
|
-
wait: false
|
|
167
|
-
});
|
|
168
|
-
} catch (err) {
|
|
169
|
-
console.error(err.message);
|
|
170
|
-
console.error("Open Obsidian manually and choose \"Open folder as vault\" for this workspace.");
|
|
171
|
-
process.exit(1);
|
|
172
|
-
}
|
|
173
|
-
}));
|
|
174
169
|
program.command("debug").description("Configure Graph MCP debug mode").addCommand(new 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) => {
|
|
175
170
|
try {
|
|
176
|
-
const { saveConfig } = await import("./config-
|
|
171
|
+
const { saveConfig } = await import("./config-C6zM8Xir.mjs").then((n) => n.t);
|
|
177
172
|
await saveConfig({
|
|
178
173
|
graphMcpMode: "debug",
|
|
179
174
|
graphMcpAuthToken: opts.token,
|
|
@@ -188,7 +183,7 @@ program.command("debug").description("Configure Graph MCP debug mode").addComman
|
|
|
188
183
|
}
|
|
189
184
|
})).addCommand(new Command("off").description("Disable Graph MCP debug mode and use paid x402 calls").action(async () => {
|
|
190
185
|
try {
|
|
191
|
-
const { saveConfig } = await import("./config-
|
|
186
|
+
const { saveConfig } = await import("./config-C6zM8Xir.mjs").then((n) => n.t);
|
|
192
187
|
await saveConfig({
|
|
193
188
|
graphMcpMode: "paid",
|
|
194
189
|
graphMcpAuthToken: ""
|
|
@@ -201,7 +196,7 @@ program.command("debug").description("Configure Graph MCP debug mode").addComman
|
|
|
201
196
|
}
|
|
202
197
|
})).addCommand(new Command("status").description("Show Graph MCP payment/debug mode").action(async () => {
|
|
203
198
|
try {
|
|
204
|
-
const { loadConfig } = await import("./config-
|
|
199
|
+
const { loadConfig } = await import("./config-C6zM8Xir.mjs").then((n) => n.t);
|
|
205
200
|
const config = await loadConfig();
|
|
206
201
|
console.log(`Graph MCP mode: ${config.graphMcpMode}`);
|
|
207
202
|
console.log(`Graph endpoint: ${config.graphMcpEndpoint}`);
|
|
@@ -216,7 +211,7 @@ program.command("access-key").description("Configure Graph MCP test access key m
|
|
|
216
211
|
try {
|
|
217
212
|
const normalizedKey = key.trim();
|
|
218
213
|
if (!normalizedKey) throw new Error("Test access key is required");
|
|
219
|
-
const { saveConfig } = await import("./config-
|
|
214
|
+
const { saveConfig } = await import("./config-C6zM8Xir.mjs").then((n) => n.t);
|
|
220
215
|
await saveConfig({
|
|
221
216
|
graphMcpMode: "debug",
|
|
222
217
|
graphMcpAuthToken: normalizedKey,
|
|
@@ -231,7 +226,7 @@ program.command("access-key").description("Configure Graph MCP test access key m
|
|
|
231
226
|
}
|
|
232
227
|
})).addCommand(new Command("clear").description("Remove the Graph MCP test access key and use paid x402 calls").action(async () => {
|
|
233
228
|
try {
|
|
234
|
-
const { saveConfig } = await import("./config-
|
|
229
|
+
const { saveConfig } = await import("./config-C6zM8Xir.mjs").then((n) => n.t);
|
|
235
230
|
await saveConfig({
|
|
236
231
|
graphMcpMode: "paid",
|
|
237
232
|
graphMcpAuthToken: ""
|
|
@@ -244,7 +239,7 @@ program.command("access-key").description("Configure Graph MCP test access key m
|
|
|
244
239
|
}
|
|
245
240
|
})).addCommand(new Command("status").description("Show Graph MCP test access key status").action(async () => {
|
|
246
241
|
try {
|
|
247
|
-
const { loadConfig } = await import("./config-
|
|
242
|
+
const { loadConfig } = await import("./config-C6zM8Xir.mjs").then((n) => n.t);
|
|
248
243
|
const config = await loadConfig();
|
|
249
244
|
console.log(`Graph endpoint: ${config.graphMcpEndpoint}`);
|
|
250
245
|
console.log(`Access key: ${config.graphMcpAuthToken?.trim() ? "configured" : "not configured"}`);
|
|
@@ -256,7 +251,7 @@ program.command("access-key").description("Configure Graph MCP test access key m
|
|
|
256
251
|
}));
|
|
257
252
|
program.command("init").description("Initialize an investigation workspace").argument("[dir]", "Workspace directory to initialize", ".").option("--force", "Overwrite existing workspace files").action(async (dir, opts) => {
|
|
258
253
|
try {
|
|
259
|
-
const { initWorkspace } = await import("./init-
|
|
254
|
+
const { initWorkspace } = await import("./init-BGDvGreX.mjs");
|
|
260
255
|
const result = await initWorkspace({
|
|
261
256
|
targetDir: dir,
|
|
262
257
|
force: opts.force
|
|
@@ -293,8 +288,8 @@ program.command("setup").description("Configure external MCP clients").addComman
|
|
|
293
288
|
}
|
|
294
289
|
}));
|
|
295
290
|
program.command("config").description("Read or write configuration values").addCommand(new Command("get").argument("<key>", "Config key to read").action(async (key) => {
|
|
296
|
-
const { loadConfig } = await import("./config-
|
|
297
|
-
const { CONFIG_KEYS } = await import("./schema-
|
|
291
|
+
const { loadConfig } = await import("./config-C6zM8Xir.mjs").then((n) => n.t);
|
|
292
|
+
const { CONFIG_KEYS } = await import("./schema-D_qwaQA5.mjs").then((n) => n.r);
|
|
298
293
|
if (!CONFIG_KEYS.includes(key)) {
|
|
299
294
|
console.error(`Unknown config key: ${key}`);
|
|
300
295
|
process.exit(1);
|
|
@@ -314,8 +309,8 @@ program.command("config").description("Read or write configuration values").addC
|
|
|
314
309
|
}
|
|
315
310
|
return;
|
|
316
311
|
}
|
|
317
|
-
const { loadConfig, saveConfig } = await import("./config-
|
|
318
|
-
const { CONFIG_KEYS, DEFAULT_CONFIG } = await import("./schema-
|
|
312
|
+
const { loadConfig, saveConfig } = await import("./config-C6zM8Xir.mjs").then((n) => n.t);
|
|
313
|
+
const { CONFIG_KEYS, DEFAULT_CONFIG } = await import("./schema-D_qwaQA5.mjs").then((n) => n.r);
|
|
319
314
|
const current = await loadConfig();
|
|
320
315
|
if (!CONFIG_KEYS.includes(key)) {
|
|
321
316
|
console.error(`Unknown config key: ${key}`);
|
|
@@ -406,9 +401,9 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
|
|
|
406
401
|
try {
|
|
407
402
|
const { loadSchema, saveSchema } = await import("./schema-cache-DwDvPy4e.mjs");
|
|
408
403
|
const { formatToolsTable } = await import("./format-Bq94jSyw.mjs");
|
|
409
|
-
const { visibleRemoteTools } = await import("./tool-visibility-
|
|
410
|
-
const { loadConfig } = await import("./config-
|
|
411
|
-
const { createConfiguredGraphMcpFetch, resolveGraphMcpEndpoint } = await import("./client-
|
|
404
|
+
const { visibleRemoteTools } = await import("./tool-visibility-nr6XqO1F.mjs").then((n) => n.n);
|
|
405
|
+
const { loadConfig } = await import("./config-C6zM8Xir.mjs").then((n) => n.t);
|
|
406
|
+
const { createConfiguredGraphMcpFetch, resolveGraphMcpEndpoint } = await import("./client-ytTO0mcZ.mjs").then((n) => n.r);
|
|
412
407
|
const config = await loadConfig();
|
|
413
408
|
const graphMcpEndpoint = resolveGraphMcpEndpoint(config);
|
|
414
409
|
let tools = opts.refresh ? null : await loadSchema(graphMcpEndpoint);
|
|
@@ -433,12 +428,12 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
|
|
|
433
428
|
console.error(err.message);
|
|
434
429
|
process.exit(1);
|
|
435
430
|
}
|
|
436
|
-
})).addCommand(new 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) => {
|
|
431
|
+
})).addCommand(new 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) => {
|
|
437
432
|
try {
|
|
438
|
-
await withGraphMcpClient("chain-insights-cli-address-risk", async (client) => {
|
|
433
|
+
await withGraphMcpClient("chain-insights-cli-aml-address-risk", async (client) => {
|
|
439
434
|
if (opts.remote) {
|
|
440
435
|
printMcpTextContent(await client.callTool({
|
|
441
|
-
name: "
|
|
436
|
+
name: "aml_address_risk",
|
|
442
437
|
arguments: {
|
|
443
438
|
address: opts.address,
|
|
444
439
|
network: opts.network,
|
|
@@ -447,7 +442,7 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
|
|
|
447
442
|
}));
|
|
448
443
|
return;
|
|
449
444
|
}
|
|
450
|
-
const { addressRisk } = await import("./public-tools-
|
|
445
|
+
const { addressRisk } = await import("./public-tools-brHmHGYm.mjs");
|
|
451
446
|
const result = await addressRisk(client, {
|
|
452
447
|
address: opts.address,
|
|
453
448
|
network: opts.network,
|
|
@@ -459,14 +454,14 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
|
|
|
459
454
|
console.error(err.message);
|
|
460
455
|
process.exit(1);
|
|
461
456
|
}
|
|
462
|
-
})).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("--
|
|
457
|
+
})).addCommand(new 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) => {
|
|
463
458
|
try {
|
|
464
|
-
const { requireWorkspaceRoot } = await import("./output-root-
|
|
459
|
+
const { requireWorkspaceRoot } = await import("./output-root-BK4pdjyz.mjs").then((n) => n.t);
|
|
465
460
|
requireWorkspaceRoot();
|
|
466
|
-
await withGraphMcpClient("chain-insights-cli-trace-victim-funds", async (client, config) => {
|
|
461
|
+
await withGraphMcpClient("chain-insights-cli-aml-trace-victim-funds", async (client, config) => {
|
|
467
462
|
if (opts.remote) {
|
|
468
463
|
printMcpTextContent(await client.callTool({
|
|
469
|
-
name: "
|
|
464
|
+
name: "aml_trace_victim_funds",
|
|
470
465
|
arguments: {
|
|
471
466
|
victim_addresses: opts.victimAddresses,
|
|
472
467
|
network: opts.network,
|
|
@@ -475,13 +470,11 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
|
|
|
475
470
|
}));
|
|
476
471
|
return;
|
|
477
472
|
}
|
|
478
|
-
const { traceVictimFunds } = await import("./public-tools-
|
|
479
|
-
const caseId = opts.case ? await resolveCaseSelector(opts.case) : void 0;
|
|
473
|
+
const { traceVictimFunds } = await import("./public-tools-brHmHGYm.mjs");
|
|
480
474
|
const result = await traceVictimFunds(client, config, {
|
|
481
475
|
victimAddresses: opts.victimAddresses,
|
|
482
476
|
knownSuspectAddresses: opts.knownSuspectAddresses,
|
|
483
477
|
network: opts.network,
|
|
484
|
-
caseId,
|
|
485
478
|
incidentTimestampMs: optionalNumber(opts.incidentTimestampMs),
|
|
486
479
|
maxHops: optionalNumber(opts.maxHops),
|
|
487
480
|
perAddressLimit: optionalNumber(opts.perAddressLimit),
|
|
@@ -494,21 +487,19 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
|
|
|
494
487
|
console.error(err.message);
|
|
495
488
|
process.exit(1);
|
|
496
489
|
}
|
|
497
|
-
})).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").
|
|
490
|
+
})).addCommand(new 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) => {
|
|
498
491
|
try {
|
|
499
|
-
const { requireWorkspaceRoot } = await import("./output-root-
|
|
492
|
+
const { requireWorkspaceRoot } = await import("./output-root-BK4pdjyz.mjs").then((n) => n.t);
|
|
500
493
|
requireWorkspaceRoot();
|
|
501
|
-
await withGraphMcpClient("chain-insights-cli-trace-suspect-funds", async (client, config) => {
|
|
502
|
-
const { traceSuspectFunds } = await import("./public-tools-
|
|
503
|
-
const caseId = opts.case ? await resolveCaseSelector(opts.case) : void 0;
|
|
494
|
+
await withGraphMcpClient("chain-insights-cli-aml-trace-suspect-funds", async (client, config) => {
|
|
495
|
+
const { traceSuspectFunds } = await import("./public-tools-brHmHGYm.mjs");
|
|
504
496
|
const result = await traceSuspectFunds(client, config, {
|
|
505
497
|
suspectAddresses: opts.suspectAddresses,
|
|
506
498
|
network: opts.network,
|
|
507
499
|
maxHops: optionalNumber(opts.maxHops),
|
|
508
500
|
perAddressLimit: optionalNumber(opts.perAddressLimit),
|
|
509
501
|
minAmountSum: optionalNumber(opts.minAmountSum),
|
|
510
|
-
incidentTimestampMs: optionalNumber(opts.incidentTimestampMs)
|
|
511
|
-
caseId
|
|
502
|
+
incidentTimestampMs: optionalNumber(opts.incidentTimestampMs)
|
|
512
503
|
});
|
|
513
504
|
console.log(result.summaryText);
|
|
514
505
|
console.log(JSON.stringify(result.structuredContent, null, 2));
|
|
@@ -517,18 +508,16 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
|
|
|
517
508
|
console.error(err.message);
|
|
518
509
|
process.exit(1);
|
|
519
510
|
}
|
|
520
|
-
})).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").
|
|
511
|
+
})).addCommand(new 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) => {
|
|
521
512
|
try {
|
|
522
|
-
const { requireWorkspaceRoot } = await import("./output-root-
|
|
513
|
+
const { requireWorkspaceRoot } = await import("./output-root-BK4pdjyz.mjs").then((n) => n.t);
|
|
523
514
|
requireWorkspaceRoot();
|
|
524
|
-
await withGraphMcpClient("chain-insights-cli-trace-deposit-sources", async (client, config) => {
|
|
525
|
-
const { traceDepositSources } = await import("./public-tools-
|
|
526
|
-
const caseId = opts.case ? await resolveCaseSelector(opts.case) : void 0;
|
|
515
|
+
await withGraphMcpClient("chain-insights-cli-aml-trace-deposit-sources", async (client, config) => {
|
|
516
|
+
const { traceDepositSources } = await import("./public-tools-brHmHGYm.mjs");
|
|
527
517
|
const result = await traceDepositSources(client, config, {
|
|
528
518
|
depositAddresses: opts.depositAddresses,
|
|
529
519
|
network: opts.network,
|
|
530
|
-
maxHops: optionalNumber(opts.maxHops)
|
|
531
|
-
caseId
|
|
520
|
+
maxHops: optionalNumber(opts.maxHops)
|
|
532
521
|
});
|
|
533
522
|
console.log(result.summaryText);
|
|
534
523
|
console.log(JSON.stringify(result.structuredContent, null, 2));
|
|
@@ -537,21 +526,21 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
|
|
|
537
526
|
console.error(err.message);
|
|
538
527
|
process.exit(1);
|
|
539
528
|
}
|
|
540
|
-
})).addCommand(new Command("
|
|
529
|
+
})).addCommand(new 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) => {
|
|
541
530
|
try {
|
|
542
|
-
await withGraphMcpClient("chain-insights-cli-
|
|
543
|
-
const {
|
|
544
|
-
const result = await
|
|
531
|
+
await withGraphMcpClient("chain-insights-cli-exposure-profile", async (client) => {
|
|
532
|
+
const { exposureProfile } = await import("./public-tools-brHmHGYm.mjs");
|
|
533
|
+
const result = await exposureProfile(client, {
|
|
545
534
|
network: opts.network,
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
535
|
+
account: opts.account,
|
|
536
|
+
owner: opts.owner,
|
|
537
|
+
counterparty: opts.counterparty,
|
|
538
|
+
venue: opts.venue,
|
|
539
|
+
instrument: opts.instrument,
|
|
540
|
+
instrumentType: opts.instrumentType,
|
|
550
541
|
startTimestampMs: optionalNumber(opts.startTimestampMs),
|
|
551
542
|
endTimestampMs: optionalNumber(opts.endTimestampMs),
|
|
552
|
-
|
|
553
|
-
endBlock: optionalNumber(opts.endBlock),
|
|
554
|
-
depth: optionalNumber(opts.depth)
|
|
543
|
+
limit: optionalNumber(opts.limit)
|
|
555
544
|
});
|
|
556
545
|
console.log(result.summaryText);
|
|
557
546
|
console.log(JSON.stringify(result.structuredContent, null, 2));
|
|
@@ -560,15 +549,15 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
|
|
|
560
549
|
console.error(err.message);
|
|
561
550
|
process.exit(1);
|
|
562
551
|
}
|
|
563
|
-
})).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) => {
|
|
552
|
+
})).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 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) => {
|
|
564
553
|
try {
|
|
565
554
|
const { parseMcpCallArgs } = await import("./call-args-DPXdX3_D.mjs");
|
|
566
|
-
const { assertPublicMcpToolName } = await import("./tool-visibility-
|
|
555
|
+
const { assertPublicMcpToolName } = await import("./tool-visibility-nr6XqO1F.mjs").then((n) => n.n);
|
|
567
556
|
const args = parseMcpCallArgs(rawArgs);
|
|
568
557
|
assertPublicMcpToolName(tool);
|
|
569
558
|
await withGraphMcpClient("chain-insights-cli-call", async (client, config) => {
|
|
570
|
-
if (tool === "
|
|
571
|
-
const { addressRisk } = await import("./public-tools-
|
|
559
|
+
if (tool === "aml_address_risk") {
|
|
560
|
+
const { addressRisk } = await import("./public-tools-brHmHGYm.mjs");
|
|
572
561
|
const result = await addressRisk(client, {
|
|
573
562
|
address: String(args["address"] ?? ""),
|
|
574
563
|
network: String(args["network"] ?? ""),
|
|
@@ -577,13 +566,12 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
|
|
|
577
566
|
console.log(result.summaryText);
|
|
578
567
|
return;
|
|
579
568
|
}
|
|
580
|
-
if (tool === "
|
|
581
|
-
const { traceVictimFunds } = await import("./public-tools-
|
|
569
|
+
if (tool === "aml_trace_victim_funds") {
|
|
570
|
+
const { traceVictimFunds } = await import("./public-tools-brHmHGYm.mjs");
|
|
582
571
|
const result = await traceVictimFunds(client, config, {
|
|
583
572
|
victimAddresses: args["victim_addresses"] ?? "",
|
|
584
573
|
knownSuspectAddresses: args["known_suspect_addresses"],
|
|
585
574
|
network: String(args["network"] ?? ""),
|
|
586
|
-
caseId: args["case_id"] === void 0 ? void 0 : String(args["case_id"]),
|
|
587
575
|
incidentTimestampMs: optionalNumberArg(args["incident_timestamp_ms"], "incident_timestamp_ms"),
|
|
588
576
|
maxHops: typeof args["max_hops"] === "number" ? args["max_hops"] : void 0,
|
|
589
577
|
perAddressLimit: typeof args["per_address_limit"] === "number" ? args["per_address_limit"] : void 0,
|
|
@@ -593,12 +581,11 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
|
|
|
593
581
|
console.log(JSON.stringify(result.structuredContent, null, 2));
|
|
594
582
|
return;
|
|
595
583
|
}
|
|
596
|
-
if (tool === "
|
|
597
|
-
const { traceSuspectFunds } = await import("./public-tools-
|
|
584
|
+
if (tool === "aml_trace_suspect_funds") {
|
|
585
|
+
const { traceSuspectFunds } = await import("./public-tools-brHmHGYm.mjs");
|
|
598
586
|
const result = await traceSuspectFunds(client, config, {
|
|
599
587
|
suspectAddresses: args["suspect_addresses"] ?? "",
|
|
600
588
|
network: String(args["network"] ?? ""),
|
|
601
|
-
caseId: args["case_id"] === void 0 ? void 0 : String(args["case_id"]),
|
|
602
589
|
maxHops: typeof args["max_hops"] === "number" ? args["max_hops"] : void 0,
|
|
603
590
|
perAddressLimit: typeof args["per_address_limit"] === "number" ? args["per_address_limit"] : void 0,
|
|
604
591
|
minAmountSum: typeof args["min_amount_sum"] === "number" ? args["min_amount_sum"] : void 0,
|
|
@@ -608,36 +595,64 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
|
|
|
608
595
|
console.log(JSON.stringify(result.structuredContent, null, 2));
|
|
609
596
|
return;
|
|
610
597
|
}
|
|
611
|
-
if (tool === "
|
|
612
|
-
const { traceDepositSources } = await import("./public-tools-
|
|
598
|
+
if (tool === "aml_trace_deposit_sources") {
|
|
599
|
+
const { traceDepositSources } = await import("./public-tools-brHmHGYm.mjs");
|
|
613
600
|
const result = await traceDepositSources(client, config, {
|
|
614
601
|
depositAddresses: args["deposit_addresses"] ?? "",
|
|
615
602
|
network: String(args["network"] ?? ""),
|
|
616
|
-
caseId: args["case_id"] === void 0 ? void 0 : String(args["case_id"]),
|
|
617
603
|
maxHops: typeof args["max_hops"] === "number" ? args["max_hops"] : void 0
|
|
618
604
|
});
|
|
619
605
|
console.log(result.summaryText);
|
|
620
606
|
console.log(JSON.stringify(result.structuredContent, null, 2));
|
|
621
607
|
return;
|
|
622
608
|
}
|
|
623
|
-
if (tool === "
|
|
624
|
-
const {
|
|
625
|
-
const result = await
|
|
609
|
+
if (tool === "exposure_profile") {
|
|
610
|
+
const { exposureProfile } = await import("./public-tools-brHmHGYm.mjs");
|
|
611
|
+
const result = await exposureProfile(client, {
|
|
626
612
|
network: String(args["network"] ?? ""),
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
613
|
+
account: args["account"] === void 0 ? void 0 : String(args["account"]),
|
|
614
|
+
owner: args["owner"] === void 0 ? void 0 : String(args["owner"]),
|
|
615
|
+
counterparty: args["counterparty"] === void 0 ? void 0 : String(args["counterparty"]),
|
|
616
|
+
venue: args["venue"] === void 0 ? void 0 : String(args["venue"]),
|
|
617
|
+
instrument: args["instrument"] === void 0 ? void 0 : String(args["instrument"]),
|
|
618
|
+
instrumentType: args["instrument_type"] === void 0 ? void 0 : String(args["instrument_type"]),
|
|
631
619
|
startTimestampMs: optionalNumberArg(args["start_timestamp_ms"], "start_timestamp_ms"),
|
|
632
620
|
endTimestampMs: optionalNumberArg(args["end_timestamp_ms"], "end_timestamp_ms"),
|
|
633
|
-
|
|
634
|
-
endBlock: optionalNumberArg(args["end_block"], "end_block"),
|
|
635
|
-
depth: optionalNumberArg(args["depth"] ?? args["max_hops"], "depth")
|
|
621
|
+
limit: optionalNumberArg(args["limit"], "limit")
|
|
636
622
|
});
|
|
637
623
|
console.log(result.summaryText);
|
|
638
624
|
console.log(JSON.stringify(result.structuredContent, null, 2));
|
|
639
625
|
return;
|
|
640
626
|
}
|
|
627
|
+
if ([
|
|
628
|
+
"exposure_quality",
|
|
629
|
+
"exposure_carry",
|
|
630
|
+
"exposure_crowding",
|
|
631
|
+
"exposure_exit_pressure",
|
|
632
|
+
"exposure_correlation",
|
|
633
|
+
"exposure_explain"
|
|
634
|
+
].includes(tool)) {
|
|
635
|
+
const { exposureCarry, exposureCorrelation, exposureCrowding, exposureExitPressure, exposureExplain, exposureQuality } = await import("./public-tools-brHmHGYm.mjs");
|
|
636
|
+
const exposureArgs = {
|
|
637
|
+
network: String(args["network"] ?? ""),
|
|
638
|
+
account: args["account"] === void 0 ? void 0 : String(args["account"]),
|
|
639
|
+
owner: args["owner"] === void 0 ? void 0 : String(args["owner"]),
|
|
640
|
+
counterparty: args["counterparty"] === void 0 ? void 0 : String(args["counterparty"]),
|
|
641
|
+
venue: args["venue"] === void 0 ? void 0 : String(args["venue"]),
|
|
642
|
+
instrument: args["instrument"] === void 0 ? void 0 : String(args["instrument"]),
|
|
643
|
+
market: args["market"] === void 0 ? void 0 : String(args["market"]),
|
|
644
|
+
instrumentType: args["instrument_type"] === void 0 ? void 0 : String(args["instrument_type"]),
|
|
645
|
+
startTimestampMs: optionalNumberArg(args["start_timestamp_ms"], "start_timestamp_ms"),
|
|
646
|
+
endTimestampMs: optionalNumberArg(args["end_timestamp_ms"], "end_timestamp_ms"),
|
|
647
|
+
limit: optionalNumberArg(args["limit"], "limit"),
|
|
648
|
+
candidateAccounts: args["candidate_accounts"],
|
|
649
|
+
positionId: args["position_id"] === void 0 ? void 0 : String(args["position_id"])
|
|
650
|
+
};
|
|
651
|
+
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);
|
|
652
|
+
console.log(result.summaryText);
|
|
653
|
+
console.log(JSON.stringify(result.structuredContent, null, 2));
|
|
654
|
+
return;
|
|
655
|
+
}
|
|
641
656
|
printMcpTextContent(await client.callTool({
|
|
642
657
|
name: tool,
|
|
643
658
|
arguments: args
|
|
@@ -648,289 +663,18 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
|
|
|
648
663
|
process.exit(1);
|
|
649
664
|
}
|
|
650
665
|
}));
|
|
651
|
-
|
|
652
|
-
await scopeCasesToInvocationDir();
|
|
653
|
-
}).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) => {
|
|
654
|
-
try {
|
|
655
|
-
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>\"`.");
|
|
656
|
-
const { CaseStore } = await import("./cases-TVcAifxu.mjs").then((n) => n.t);
|
|
657
|
-
const tags = opts.tags ? opts.tags.split(",").map((t) => t.trim()).filter(Boolean) : [];
|
|
658
|
-
const c = await CaseStore.create({
|
|
659
|
-
name,
|
|
660
|
-
tags,
|
|
661
|
-
description: opts.description
|
|
662
|
-
});
|
|
663
|
-
const { casesRoot } = await import("./store-C2B_AssI.mjs").then((n) => n.n);
|
|
664
|
-
console.log(`Case opened: ${c.id}`);
|
|
665
|
-
console.log(`Directory: ${path.join(casesRoot(), c.id)}/`);
|
|
666
|
-
console.log(`Status: ${c.status}`);
|
|
667
|
-
const { findActiveWorkspace } = await import("./active-ByNgjuAg.mjs").then((n) => n.n);
|
|
668
|
-
if (findActiveWorkspace()) try {
|
|
669
|
-
const { refreshCaseVault } = await import("./vault-z35Dohdq.mjs");
|
|
670
|
-
const result = await refreshCaseVault({
|
|
671
|
-
caseId: c.id,
|
|
672
|
-
force: true
|
|
673
|
-
});
|
|
674
|
-
console.log(`Open first: ${result.nextFile}`);
|
|
675
|
-
} catch (refreshErr) {
|
|
676
|
-
console.error(`Warning: live vault refresh failed: ${refreshErr.message}`);
|
|
677
|
-
console.error(`Run: cia case vault refresh ${c.id} --force`);
|
|
678
|
-
}
|
|
679
|
-
} catch (err) {
|
|
680
|
-
console.error(err.message);
|
|
681
|
-
process.exit(1);
|
|
682
|
-
}
|
|
683
|
-
})).addCommand(new Command("activate").description("Activate a case (set status to active)").argument("<case-id>", "Case ID to activate").action(async (caseSelector) => {
|
|
684
|
-
try {
|
|
685
|
-
const { CaseStore } = await import("./cases-TVcAifxu.mjs").then((n) => n.t);
|
|
686
|
-
const caseId = await resolveCaseSelector(caseSelector);
|
|
687
|
-
const c = await CaseStore.setStatus(caseId, "active");
|
|
688
|
-
console.log(`Case ${c.id} is now: active`);
|
|
689
|
-
} catch (err) {
|
|
690
|
-
console.error(err.message);
|
|
691
|
-
process.exit(1);
|
|
692
|
-
}
|
|
693
|
-
})).addCommand(new Command("suspend").description("Suspend a case (set status to suspended)").argument("<case-id>", "Case ID to suspend").action(async (caseSelector) => {
|
|
694
|
-
try {
|
|
695
|
-
const { CaseStore } = await import("./cases-TVcAifxu.mjs").then((n) => n.t);
|
|
696
|
-
const caseId = await resolveCaseSelector(caseSelector);
|
|
697
|
-
const c = await CaseStore.setStatus(caseId, "suspended");
|
|
698
|
-
console.log(`Case ${c.id} is now: suspended`);
|
|
699
|
-
} catch (err) {
|
|
700
|
-
console.error(err.message);
|
|
701
|
-
process.exit(1);
|
|
702
|
-
}
|
|
703
|
-
})).addCommand(new Command("close").description("Close a case permanently").argument("<case-id>", "Case ID to close").action(async (caseSelector) => {
|
|
704
|
-
try {
|
|
705
|
-
const { CaseStore } = await import("./cases-TVcAifxu.mjs").then((n) => n.t);
|
|
706
|
-
const caseId = await resolveCaseSelector(caseSelector);
|
|
707
|
-
const c = await CaseStore.setStatus(caseId, "closed");
|
|
708
|
-
console.log(`Case ${c.id} is now: closed`);
|
|
709
|
-
} catch (err) {
|
|
710
|
-
console.error(err.message);
|
|
711
|
-
process.exit(1);
|
|
712
|
-
}
|
|
713
|
-
})).addCommand(new Command("list").description("List all investigation cases").option("--status <status>", "Filter by status (open|active|suspended|closed)").action(async (opts) => {
|
|
714
|
-
try {
|
|
715
|
-
const { CaseStore } = await import("./cases-TVcAifxu.mjs").then((n) => n.t);
|
|
716
|
-
const cases = await CaseStore.list();
|
|
717
|
-
const filtered = opts.status ? cases.filter((c) => c.status === opts.status) : cases;
|
|
718
|
-
if (filtered.length === 0) {
|
|
719
|
-
console.log("No cases found.");
|
|
720
|
-
return;
|
|
721
|
-
}
|
|
722
|
-
for (const [index, c] of filtered.entries()) console.log(`${index + 1}. ${c.id} [${c.status}] ${c.name}`);
|
|
723
|
-
} catch (err) {
|
|
724
|
-
console.error(err.message);
|
|
725
|
-
process.exit(1);
|
|
726
|
-
}
|
|
727
|
-
})).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) => {
|
|
728
|
-
try {
|
|
729
|
-
const { EvidenceStore } = await import("./cases-TVcAifxu.mjs").then((n) => n.t);
|
|
730
|
-
const caseId = await resolveCaseSelector(caseSelector);
|
|
731
|
-
const result = await EvidenceStore.append(caseId, {
|
|
732
|
-
source: opts.source,
|
|
733
|
-
content: opts.content,
|
|
734
|
-
queryParams: opts.queryParams
|
|
735
|
-
});
|
|
736
|
-
console.log(`Evidence saved: ${result.filename}`);
|
|
737
|
-
console.log(`SHA-256: ${result.sha256}`);
|
|
738
|
-
} catch (err) {
|
|
739
|
-
console.error(err.message);
|
|
740
|
-
process.exit(1);
|
|
741
|
-
}
|
|
742
|
-
})).addCommand(new Command("verify").description("Verify evidence manifest integrity for a case").argument("<case-id>", "Case ID to verify").action(async (caseSelector) => {
|
|
743
|
-
try {
|
|
744
|
-
const { EvidenceStore } = await import("./cases-TVcAifxu.mjs").then((n) => n.t);
|
|
745
|
-
const caseId = await resolveCaseSelector(caseSelector);
|
|
746
|
-
const result = await EvidenceStore.verifyManifest(caseId);
|
|
747
|
-
if (result.ok) console.log(`Manifest OK — ${result.count} evidence file(s) verified`);
|
|
748
|
-
else {
|
|
749
|
-
console.error(`Manifest FAILED — tampered files: ${(result.tampered ?? []).join(", ")}`);
|
|
750
|
-
process.exit(1);
|
|
751
|
-
}
|
|
752
|
-
} catch (err) {
|
|
753
|
-
console.error(err.message);
|
|
754
|
-
process.exit(1);
|
|
755
|
-
}
|
|
756
|
-
}))).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) => {
|
|
757
|
-
try {
|
|
758
|
-
const { DossierStore } = await import("./cases-TVcAifxu.mjs").then((n) => n.t);
|
|
759
|
-
const caseId = await resolveCaseSelector(caseSelector);
|
|
760
|
-
const entityType = [
|
|
761
|
-
"eoa",
|
|
762
|
-
"contract",
|
|
763
|
-
"exchange",
|
|
764
|
-
"mixer",
|
|
765
|
-
"unknown"
|
|
766
|
-
].includes(opts.type) ? opts.type : "unknown";
|
|
767
|
-
await DossierStore.appendFinding(caseId, address, opts.finding, entityType);
|
|
768
|
-
console.log(`Dossier updated for ${address}`);
|
|
769
|
-
} catch (err) {
|
|
770
|
-
console.error(err.message);
|
|
771
|
-
process.exit(1);
|
|
772
|
-
}
|
|
773
|
-
}))).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) => {
|
|
774
|
-
try {
|
|
775
|
-
const { SessionStore } = await import("./cases-TVcAifxu.mjs").then((n) => n.t);
|
|
776
|
-
const caseId = await resolveCaseSelector(caseSelector);
|
|
777
|
-
const title = titleParts.join(" ").trim();
|
|
778
|
-
const s = await SessionStore.start(caseId, title ? { title } : {});
|
|
779
|
-
console.log(`Session started: ${s.sessionId}`);
|
|
780
|
-
} catch (err) {
|
|
781
|
-
console.error(err.message);
|
|
782
|
-
process.exit(1);
|
|
783
|
-
}
|
|
784
|
-
})).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) => {
|
|
785
|
-
try {
|
|
786
|
-
const { SessionStore } = await import("./cases-TVcAifxu.mjs").then((n) => n.t);
|
|
787
|
-
const caseId = await resolveCaseSelector(caseSelector);
|
|
788
|
-
await SessionStore.end(caseId, {
|
|
789
|
-
findings: opts.findings,
|
|
790
|
-
nextSteps: opts.nextSteps
|
|
791
|
-
});
|
|
792
|
-
await SessionStore.archiveOldSessions(caseId);
|
|
793
|
-
console.log(`Session ended for case ${caseId}`);
|
|
794
|
-
} catch (err) {
|
|
795
|
-
console.error(err.message);
|
|
796
|
-
process.exit(1);
|
|
797
|
-
}
|
|
798
|
-
}))).addCommand(new Command("vault").description("Manage live Obsidian case vault notes").addCommand(new 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) => {
|
|
799
|
-
try {
|
|
800
|
-
const caseId = await resolveCaseSelector(caseSelector);
|
|
801
|
-
const { refreshCaseVault } = await import("./vault-z35Dohdq.mjs");
|
|
802
|
-
const result = await refreshCaseVault({
|
|
803
|
-
caseId,
|
|
804
|
-
force: opts.force === true
|
|
805
|
-
});
|
|
806
|
-
console.log(`Case vault refreshed: ${caseId}`);
|
|
807
|
-
console.log(`Files: ${result.filesWritten.length}`);
|
|
808
|
-
console.log(`Open first: ${result.nextFile}`);
|
|
809
|
-
} catch (err) {
|
|
810
|
-
console.error(err.message);
|
|
811
|
-
process.exit(1);
|
|
812
|
-
}
|
|
813
|
-
}))).addCommand(new 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) => {
|
|
814
|
-
try {
|
|
815
|
-
const target = opts.target === "obsidian-llmwiki" ? opts.target : void 0;
|
|
816
|
-
const mode = [
|
|
817
|
-
"private",
|
|
818
|
-
"partner",
|
|
819
|
-
"public"
|
|
820
|
-
].includes(opts.mode) ? opts.mode : void 0;
|
|
821
|
-
if (!target) throw new Error(`Unsupported export target: ${opts.target}`);
|
|
822
|
-
if (!mode) throw new Error(`Unsupported export mode: ${opts.mode}`);
|
|
823
|
-
const caseId = await resolveCaseSelector(caseSelector);
|
|
824
|
-
const { exportCase } = await import("./export-CBhcJuZ6.mjs");
|
|
825
|
-
const result = await exportCase({
|
|
826
|
-
caseId,
|
|
827
|
-
target,
|
|
828
|
-
mode,
|
|
829
|
-
outputDir: opts.out
|
|
830
|
-
});
|
|
831
|
-
console.log(`Case exported: ${result.outputDir}`);
|
|
832
|
-
console.log(`Manifest: ${result.manifestPath}`);
|
|
833
|
-
console.log(`Files: ${result.fileCount}`);
|
|
834
|
-
console.log(`Open first: ${result.nextFile}`);
|
|
835
|
-
for (const warning of result.warnings) console.warn(`Warning: ${warning}`);
|
|
836
|
-
} catch (err) {
|
|
837
|
-
console.error(err.message);
|
|
838
|
-
process.exit(1);
|
|
839
|
-
}
|
|
840
|
-
})).addCommand(new Command("show").description("Show saved case context").argument("<case-id>", "Case ID or case list number to show").action(async (caseSelector) => {
|
|
841
|
-
try {
|
|
842
|
-
await showCaseContext(caseSelector);
|
|
843
|
-
} catch (err) {
|
|
844
|
-
console.error(err.message);
|
|
845
|
-
process.exit(1);
|
|
846
|
-
}
|
|
847
|
-
}));
|
|
848
|
-
program.addCommand(caseCommand);
|
|
849
|
-
program.command("playbook").description("Run and manage investigation playbooks").addCommand(new 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) => {
|
|
850
|
-
try {
|
|
851
|
-
const resolvedParams = {};
|
|
852
|
-
for (const kv of opts.param ?? []) {
|
|
853
|
-
const eq = kv.indexOf("=");
|
|
854
|
-
if (eq === -1) {
|
|
855
|
-
console.error(`Invalid param format: "${kv}". Use key=value`);
|
|
856
|
-
process.exit(1);
|
|
857
|
-
}
|
|
858
|
-
const key = kv.slice(0, eq);
|
|
859
|
-
if (!key) {
|
|
860
|
-
console.error(`Invalid param format: "${kv}". Key must be non-empty`);
|
|
861
|
-
process.exit(1);
|
|
862
|
-
}
|
|
863
|
-
resolvedParams[key] = kv.slice(eq + 1);
|
|
864
|
-
}
|
|
865
|
-
const { resolvePlaybookContent } = await import("./resolver-2jXNtWQO.mjs");
|
|
866
|
-
const markdown = await resolvePlaybookContent(name);
|
|
867
|
-
const { PlaybookParser } = await import("./parser-CJfMsOl6.mjs");
|
|
868
|
-
const definition = PlaybookParser.parse(markdown, resolvedParams);
|
|
869
|
-
for (const spec of definition.params) if (spec.required && !resolvedParams[spec.name] && !spec.default) {
|
|
870
|
-
console.error(`Missing required param: ${spec.name}. Pass with: -p ${spec.name}=<value>`);
|
|
871
|
-
process.exit(1);
|
|
872
|
-
}
|
|
873
|
-
const fromN = parseInt(opts.from, 10);
|
|
874
|
-
if (isNaN(fromN) || fromN < 1) {
|
|
875
|
-
console.error(`Invalid --from value: "${opts.from}". Must be a positive integer.`);
|
|
876
|
-
process.exit(1);
|
|
877
|
-
}
|
|
878
|
-
const { PlaybookRunner } = await import("./runner-CVnjpqc-.mjs");
|
|
879
|
-
await PlaybookRunner.run(definition, {
|
|
880
|
-
caseId: opts.case,
|
|
881
|
-
from: fromN,
|
|
882
|
-
dryRun: opts.dryRun,
|
|
883
|
-
params: resolvedParams
|
|
884
|
-
});
|
|
885
|
-
} catch (err) {
|
|
886
|
-
console.error(err.message);
|
|
887
|
-
process.exit(1);
|
|
888
|
-
}
|
|
889
|
-
})).addCommand(new Command("list").description("List available playbooks (built-in and user-defined)").action(async () => {
|
|
890
|
-
try {
|
|
891
|
-
const { listPlaybooks } = await import("./resolver-2jXNtWQO.mjs");
|
|
892
|
-
const playbooks = await listPlaybooks();
|
|
893
|
-
if (playbooks.length === 0) {
|
|
894
|
-
console.log("No playbooks found.");
|
|
895
|
-
return;
|
|
896
|
-
}
|
|
897
|
-
for (const p of playbooks) console.log(` ${p.name.padEnd(20)} [${p.source}]`);
|
|
898
|
-
} catch (err) {
|
|
899
|
-
console.error(err.message);
|
|
900
|
-
process.exit(1);
|
|
901
|
-
}
|
|
902
|
-
})).addCommand(new Command("show").description("Show steps for a playbook without executing").argument("<name>", "Playbook name").action(async (name) => {
|
|
903
|
-
try {
|
|
904
|
-
const { resolvePlaybookContent } = await import("./resolver-2jXNtWQO.mjs");
|
|
905
|
-
const { PlaybookParser } = await import("./parser-CJfMsOl6.mjs");
|
|
906
|
-
const markdown = await resolvePlaybookContent(name);
|
|
907
|
-
const definition = PlaybookParser.parse(markdown, {});
|
|
908
|
-
console.log(`Playbook: ${definition.name} v${definition.version}`);
|
|
909
|
-
console.log(`${definition.description}\n`);
|
|
910
|
-
console.log(`Parameters:`);
|
|
911
|
-
for (const p of definition.params) {
|
|
912
|
-
const req = p.required ? "(required)" : `(optional, default: ${p.default ?? "none"})`;
|
|
913
|
-
console.log(` ${p.name}: ${p.type} ${req}`);
|
|
914
|
-
}
|
|
915
|
-
console.log(`\nSteps:`);
|
|
916
|
-
for (const step of definition.steps) console.log(` ${step.index}. ${step.label} → tool: ${step.tool}`);
|
|
917
|
-
} catch (err) {
|
|
918
|
-
console.error(err.message);
|
|
919
|
-
process.exit(1);
|
|
920
|
-
}
|
|
921
|
-
}));
|
|
922
|
-
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) => {
|
|
666
|
+
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) => {
|
|
923
667
|
try {
|
|
924
|
-
if (!
|
|
925
|
-
console.error("Provide either a
|
|
668
|
+
if (!sourceId && !opts.data) {
|
|
669
|
+
console.error("Provide either a visualization source ID or --data <file.json>");
|
|
926
670
|
process.exit(1);
|
|
927
671
|
}
|
|
928
|
-
const { generateVisualization } = await import("./viz-
|
|
672
|
+
const { generateVisualization } = await import("./viz-D8umSF-t.mjs").then((n) => n.n);
|
|
929
673
|
const result = await generateVisualization({
|
|
930
|
-
|
|
674
|
+
sourceId,
|
|
931
675
|
dataFile: opts.data
|
|
932
676
|
});
|
|
933
|
-
const { startServer } = await import("./server-
|
|
677
|
+
const { startServer } = await import("./server-BK4bfOiv.mjs").then((n) => n.t);
|
|
934
678
|
const port = parseInt(opts.port, 10);
|
|
935
679
|
startServer(port);
|
|
936
680
|
const url = `http://127.0.0.1:${port}/viz/${result.vizId}`;
|