chain-insights 0.2.16

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.
Files changed (153) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +165 -0
  3. package/bin/cli.js +10 -0
  4. package/bin/install.cjs +252 -0
  5. package/bin/mcp-proxy.cjs +10 -0
  6. package/dist/active-BSrxLKwn.mjs +50 -0
  7. package/dist/active-BSrxLKwn.mjs.map +1 -0
  8. package/dist/active-Dv7Tu-O4.cjs +68 -0
  9. package/dist/app-BjjuQM0B.mjs +155 -0
  10. package/dist/app-BjjuQM0B.mjs.map +1 -0
  11. package/dist/app-Dq1TdB6p.cjs +161 -0
  12. package/dist/artifact-server-DoxJ7fCx.cjs +47 -0
  13. package/dist/artifact-server-Dxz5YbuQ.mjs +48 -0
  14. package/dist/artifact-server-Dxz5YbuQ.mjs.map +1 -0
  15. package/dist/assets/bg-pattern.png +0 -0
  16. package/dist/assets/logo.png +0 -0
  17. package/dist/call-args-DQA2QcRA.cjs +27 -0
  18. package/dist/call-args-Lk_wOJxd.mjs +29 -0
  19. package/dist/call-args-Lk_wOJxd.mjs.map +1 -0
  20. package/dist/capabilities-CB97WMA5.cjs +83 -0
  21. package/dist/capabilities-DliMBim-.mjs +84 -0
  22. package/dist/capabilities-DliMBim-.mjs.map +1 -0
  23. package/dist/cases-By7INiOa.mjs +6 -0
  24. package/dist/cases-CDcNU91B.cjs +9 -0
  25. package/dist/chunk-CZWwpsFl.cjs +43 -0
  26. package/dist/cli.cjs +752 -0
  27. package/dist/cli.d.cts +1 -0
  28. package/dist/cli.d.mts +1 -0
  29. package/dist/cli.mjs +753 -0
  30. package/dist/cli.mjs.map +1 -0
  31. package/dist/client-D4Bq0rp9.mjs +111 -0
  32. package/dist/client-D4Bq0rp9.mjs.map +1 -0
  33. package/dist/client-D4fZgIaO.cjs +132 -0
  34. package/dist/config-Bmdl5hdk.cjs +67 -0
  35. package/dist/config-BwrBYmiC.mjs +44 -0
  36. package/dist/config-BwrBYmiC.mjs.map +1 -0
  37. package/dist/data-extractor-BNGj7ECT.cjs +347 -0
  38. package/dist/data-extractor-DFzsa5CS.mjs +336 -0
  39. package/dist/data-extractor-DFzsa5CS.mjs.map +1 -0
  40. package/dist/dossier-BsroDgD3.mjs +76 -0
  41. package/dist/dossier-BsroDgD3.mjs.map +1 -0
  42. package/dist/dossier-DtxREpPm.cjs +76 -0
  43. package/dist/evidence-BGcdKxuV.cjs +200 -0
  44. package/dist/evidence-BhvFW-y_.mjs +195 -0
  45. package/dist/evidence-BhvFW-y_.mjs.map +1 -0
  46. package/dist/format-Ce1RObVl.mjs +22 -0
  47. package/dist/format-Ce1RObVl.mjs.map +1 -0
  48. package/dist/format-DOrPvXEr.cjs +20 -0
  49. package/dist/frontmatter-D8wWCeOa.mjs +26 -0
  50. package/dist/frontmatter-D8wWCeOa.mjs.map +1 -0
  51. package/dist/frontmatter-DgAuai7E.cjs +35 -0
  52. package/dist/graph-normalizer-Cv9yK9Pg.mjs +130 -0
  53. package/dist/graph-normalizer-Cv9yK9Pg.mjs.map +1 -0
  54. package/dist/graph-normalizer-DeIj6Ses.cjs +133 -0
  55. package/dist/graph-reports-C4TBjCkM.mjs +63 -0
  56. package/dist/graph-reports-C4TBjCkM.mjs.map +1 -0
  57. package/dist/graph-reports-DU05YCei.cjs +64 -0
  58. package/dist/html-generator-CAv81IWH.cjs +85 -0
  59. package/dist/html-generator-V6Bp0uRb.mjs +68 -0
  60. package/dist/html-generator-V6Bp0uRb.mjs.map +1 -0
  61. package/dist/index.cjs +31 -0
  62. package/dist/index.d.cts +187 -0
  63. package/dist/index.d.cts.map +1 -0
  64. package/dist/index.d.mts +187 -0
  65. package/dist/index.d.mts.map +1 -0
  66. package/dist/index.mjs +9 -0
  67. package/dist/init-BjuFt54X.cjs +232 -0
  68. package/dist/init-CaOsHTIo.mjs +232 -0
  69. package/dist/init-CaOsHTIo.mjs.map +1 -0
  70. package/dist/mcp-proxy.cjs +1257 -0
  71. package/dist/mcp-proxy.d.cts +12 -0
  72. package/dist/mcp-proxy.d.cts.map +1 -0
  73. package/dist/mcp-proxy.d.mts +12 -0
  74. package/dist/mcp-proxy.d.mts.map +1 -0
  75. package/dist/mcp-proxy.mjs +1255 -0
  76. package/dist/mcp-proxy.mjs.map +1 -0
  77. package/dist/output-root-CFYms3ad.cjs +43 -0
  78. package/dist/output-root-CmWM7aV2.mjs +33 -0
  79. package/dist/output-root-CmWM7aV2.mjs.map +1 -0
  80. package/dist/parser-BUIWW1OH.cjs +182 -0
  81. package/dist/parser-DO0_SssG.mjs +182 -0
  82. package/dist/parser-DO0_SssG.mjs.map +1 -0
  83. package/dist/public-tools-D4UI-Zb0.mjs +2554 -0
  84. package/dist/public-tools-D4UI-Zb0.mjs.map +1 -0
  85. package/dist/public-tools-XSpkz2ky.cjs +2556 -0
  86. package/dist/resolver-C2ZS7oC8.mjs +201 -0
  87. package/dist/resolver-C2ZS7oC8.mjs.map +1 -0
  88. package/dist/resolver-zYbu4wDV.cjs +203 -0
  89. package/dist/rolldown-runtime-wcPFST8Q.mjs +13 -0
  90. package/dist/runner-1Eq55OYb.cjs +148 -0
  91. package/dist/runner-BhUHbiHG.mjs +149 -0
  92. package/dist/runner-BhUHbiHG.mjs.map +1 -0
  93. package/dist/schema-4XpzDFQM.cjs +55 -0
  94. package/dist/schema-8d0rVIdZ.mjs +37 -0
  95. package/dist/schema-8d0rVIdZ.mjs.map +1 -0
  96. package/dist/schema-cache-9CksD7tX.mjs +34 -0
  97. package/dist/schema-cache-9CksD7tX.mjs.map +1 -0
  98. package/dist/schema-cache-CgWRCN2N.cjs +36 -0
  99. package/dist/selector-CkFcTXzz.cjs +10 -0
  100. package/dist/selector-xjm6NTHI.mjs +12 -0
  101. package/dist/selector-xjm6NTHI.mjs.map +1 -0
  102. package/dist/server-BkM5xrXb.mjs +45 -0
  103. package/dist/server-BkM5xrXb.mjs.map +1 -0
  104. package/dist/server-DXowbpfi.cjs +54 -0
  105. package/dist/session-BpNylyuJ.cjs +115 -0
  106. package/dist/session-CcTgYxsj.mjs +115 -0
  107. package/dist/session-CcTgYxsj.mjs.map +1 -0
  108. package/dist/setup-DOpKPrlx.cjs +81 -0
  109. package/dist/setup-DyrWHuwQ.mjs +80 -0
  110. package/dist/setup-DyrWHuwQ.mjs.map +1 -0
  111. package/dist/store-BiUhQOIf.cjs +230 -0
  112. package/dist/store-BoWE-Gtl.mjs +225 -0
  113. package/dist/store-BoWE-Gtl.mjs.map +1 -0
  114. package/dist/templates/graph.html +1406 -0
  115. package/dist/tool-visibility-3Z_KvO9Q.mjs +28 -0
  116. package/dist/tool-visibility-3Z_KvO9Q.mjs.map +1 -0
  117. package/dist/tool-visibility-CwgY205r.cjs +36 -0
  118. package/dist/tools-Cp2jAAAb.mjs +100 -0
  119. package/dist/tools-Cp2jAAAb.mjs.map +1 -0
  120. package/dist/tools-f_vJUZAF.cjs +139 -0
  121. package/dist/topup-server-BZuQifvh.cjs +940 -0
  122. package/dist/topup-server-DUjyFftI.mjs +919 -0
  123. package/dist/topup-server-DUjyFftI.mjs.map +1 -0
  124. package/dist/version-1gP19Lhi.mjs +8 -0
  125. package/dist/version-1gP19Lhi.mjs.map +1 -0
  126. package/dist/version-BNGtdpmH.cjs +18 -0
  127. package/dist/viz-BlCJe6Tk.mjs +35 -0
  128. package/dist/viz-BlCJe6Tk.mjs.map +1 -0
  129. package/dist/viz-ClezVXrJ.cjs +44 -0
  130. package/dist/wallet-BMelXBYP.mjs +104 -0
  131. package/dist/wallet-BMelXBYP.mjs.map +1 -0
  132. package/dist/wallet-RnvvSpV2.cjs +146 -0
  133. package/docs/architecture.md +145 -0
  134. package/docs/contributing.md +68 -0
  135. package/docs/debugging.md +68 -0
  136. package/docs/development.md +44 -0
  137. package/docs/graph-tools.md +251 -0
  138. package/docs/images/graph-mcp-iframe.png +0 -0
  139. package/docs/images/graph-visualization.png +0 -0
  140. package/docs/images/topup-page.png +0 -0
  141. package/docs/investigation-workspaces.md +151 -0
  142. package/docs/mcp-proxy.md +180 -0
  143. package/package.json +59 -0
  144. package/skills/chain-insights-developer-experience/SKILL.md +101 -0
  145. package/skills/chain-insights-investigation/SKILL.md +285 -0
  146. package/skills/chain-insights-investigation/agents/openai.yaml +4 -0
  147. package/skills/chain-insights-investigation/scripts/run-target-uat.sh +197 -0
  148. package/skills/chain-insights-trace-funds/SKILL.md +249 -0
  149. package/skills/ci-case/SKILL.md +43 -0
  150. package/skills/ci-status/SKILL.md +45 -0
  151. package/skills/test-chain-insights-graphrag-mcp/SKILL.md +75 -0
  152. package/skills/test-chain-insights-graphrag-mcp/agents/openai.yaml +4 -0
  153. package/skills/test-chain-insights-graphrag-mcp/scripts/run-uat.sh +414 -0
@@ -0,0 +1,232 @@
1
+ const require_chunk = require("./chunk-CZWwpsFl.cjs");
2
+ let node_path = require("node:path");
3
+ node_path = require_chunk.__toESM(node_path, 1);
4
+ let node_fs_promises = require("node:fs/promises");
5
+ //#region src/workspace/init.ts
6
+ const WORKSPACE_DIRS = [
7
+ ".chain-insights",
8
+ ".chain-insights/schema",
9
+ ".chain-insights/runtime",
10
+ ".chain-insights/runtime/logs",
11
+ ".chain-insights/runtime-skill",
12
+ "cases",
13
+ "imports",
14
+ "reports",
15
+ "reports/graphs",
16
+ "reports/tables",
17
+ "templates"
18
+ ];
19
+ function todayIso() {
20
+ return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
21
+ }
22
+ function workspaceJson(workspaceRoot) {
23
+ return JSON.stringify({
24
+ schema: "chain-insights.workspace.v1",
25
+ name: "Chain Insights Investigations",
26
+ workspace_root: workspaceRoot,
27
+ default_network: "bittensor",
28
+ graph_mcp_endpoint: "https://staging-mcp.chain-insights.ai/mcp",
29
+ cases_dir: "cases",
30
+ imports_dir: "imports",
31
+ reports_dir: "reports",
32
+ templates_dir: "templates",
33
+ created_at: todayIso()
34
+ }, null, 2) + "\n";
35
+ }
36
+ const README = `# Chain Insights Investigations
37
+
38
+ This is a workspace for Chain Insights AML investigations.
39
+
40
+ ## Start
41
+
42
+ \`\`\`bash
43
+ chain-insights mcp tools --refresh
44
+ chain-insights wallet balance
45
+ \`\`\`
46
+
47
+ ## Layout
48
+
49
+ \`\`\`text
50
+ .chain-insights/ Workspace metadata
51
+ cases/ Case exports and notes
52
+ imports/ External reports, CSVs, screenshots, raw notes
53
+ reports/ Final or interim analyst reports
54
+ reports/graphs/ Graph JSON for visualization
55
+ reports/tables/ Compact tabular extracts
56
+ templates/ Reusable case/report templates
57
+ .chain-insights/schema/ Runtime graph schema captures
58
+ .chain-insights/runtime/ Workspace-local runtime process state and debug logs
59
+ .chain-insights/runtime-skill/ Workspace-specific agent schema notes
60
+ \`\`\`
61
+ `;
62
+ const AGENTS = `# Agent Instructions
63
+
64
+ You are operating inside a Chain Insights investigation workspace.
65
+
66
+ - Read README.md first.
67
+ - If this directory is not initialized, run \`cia init .\` before investigation-producing commands.
68
+ - Do not rerun init in an existing workspace unless replacing scaffolding with \`--force\`.
69
+ - Read .chain-insights/runtime-skill/SKILL.md before graph queries.
70
+ - Preserve full blockchain addresses exactly.
71
+ - Do not guess the network for graph queries.
72
+ - Capture or refresh graph schema before the first case query.
73
+ - Save compact evidence with original graph field names.
74
+ - Put canonical graph JSON in reports/graphs/ and analyst tables in reports/tables/.
75
+ - Evidence files should summarize and point to graph/table outputs; do not paste large raw JSON blobs into evidence Markdown.
76
+ - Investigation output must stay in this initialized workspace.
77
+ - Never write cases, evidence, reports, graph JSON, HTML, schema captures, or logs to ~/.chain-insights.
78
+ - Keep theories lightweight until evidence supports them.
79
+ `;
80
+ const CLAUDE = AGENTS;
81
+ const CASE_BRIEF = `# Case Brief
82
+
83
+ ## Summary
84
+
85
+ Status:
86
+ Network:
87
+ Current Assessment:
88
+
89
+ ## Known Addresses
90
+
91
+ ## Claims To Validate
92
+
93
+ ## Evidence
94
+
95
+ ## Next Steps
96
+ `;
97
+ const IMPORTS_README = `# External Investigation Inputs
98
+
99
+ Put user-provided or third-party investigation material here before turning it
100
+ into case evidence.
101
+
102
+ Examples:
103
+
104
+ - Exchange support exports
105
+ - CSV extracts
106
+ - Screenshots
107
+ - Raw notes
108
+ - Partner reports
109
+
110
+ Files in this directory are inputs, not verified evidence. When an import
111
+ supports a claim, summarize it into the case evidence manifest and reference
112
+ the original file path.
113
+ `;
114
+ const TEMPLATES_README = `# Reusable Workspace Templates
115
+
116
+ Store local report, case, prompt, and evidence templates here.
117
+
118
+ Templates are optional workspace helpers. They are not evidence and should not
119
+ be treated as case state until copied into a case, evidence file, dossier, or
120
+ report.
121
+ `;
122
+ const RUNTIME_SKILL = `---
123
+ name: chain-insights-runtime-schema
124
+ description: Workspace-local Chain Insights runtime schema notes. Refresh this after connecting to a graph MCP endpoint.
125
+ ---
126
+
127
+ # Runtime Graph Schema
128
+
129
+ Before the first investigation query, capture the live graph schema into:
130
+
131
+ \`\`\`text
132
+ .chain-insights/schema/<network>.graph-schema.json
133
+ \`\`\`
134
+
135
+ Use \`graph_query_batch\` for schema capture. Prefix current topology reads
136
+ with \`USE live_topology\`, historical topology reads with
137
+ \`USE archive_topology\`, and fact reads with \`USE facts\`, for example:
138
+
139
+ \`\`\`bash
140
+ cia mcp call graph_query_batch network=<network> 'queries=[{"id":"node_labels","query":"USE live_topology MATCH (n:Address) RETURN \"Address\" AS node_label, count(n) AS sample_count LIMIT 1"},{"id":"archive_flow_sample","query":"USE archive_topology MATCH (:Address)-[f:FLOWS_TO]->(:Address) RETURN f.period_granularity AS granularity, f.amount_sum AS amount_sum LIMIT 20"}]'
141
+ \`\`\`
142
+
143
+ Then update this file with observed labels, relationship types, and allowed
144
+ property names for the active network.
145
+
146
+ Rules:
147
+
148
+ - Prefer \`graph_query\` and \`graph_query_batch\` for graph-language reads.
149
+ - Use \`USE live_topology\` for Memgraph RAM topology, \`USE archive_topology\`
150
+ for StarRocks historical topology, and \`USE facts\` for StarRocks fact
151
+ labels such as \`AddressLabel\`, \`AddressFeature\`,
152
+ \`RiskScore\`, and \`Asset\`. Address facts can be reached through
153
+ relationships such as \`(:Address)-[:HAS_FEATURE]->(:AddressFeature)\`.
154
+ Archived money-flow topology is exposed as
155
+ \`(:Address)-[:FLOWS_TO]->(:Address)\` with \`period_granularity\`,
156
+ \`period_start_date\`, and \`period_end_date\` on the relationship.
157
+ - Preserve source schema field names in evidence and generated data files.
158
+ - Do not rename, reinterpret, or add unit labels to graph fields unless the
159
+ schema or query result explicitly supports that interpretation.
160
+ - Keep evidence compact: select only the fields needed to support the claim.
161
+ Avoid storing whole node or relationship property blobs in evidence unless
162
+ the purpose of the query is schema discovery or debugging.
163
+ - Keep analysis products separate from evidence: graph JSON belongs under
164
+ \`reports/graphs/\`, tabular extracts under \`reports/tables/\`, and analyst
165
+ narrative under \`reports/\`.
166
+ - Evidence Markdown should be a short provenance record with key facts and
167
+ pointers. Large JSON belongs in \`reports/tables/\`, not inline in evidence.
168
+ `;
169
+ const SCHEMA_README = `# Runtime Schema Captures
170
+
171
+ Store graph schema captures here, for example:
172
+
173
+ \`\`\`text
174
+ bittensor.graph-schema.json
175
+ \`\`\`
176
+
177
+ Schema captures should be generated before the first case query in a fresh
178
+ workspace, then referenced by evidence, reports, and runtime skill notes.
179
+ `;
180
+ function workspaceFiles(workspaceRoot) {
181
+ return [
182
+ [".chain-insights/workspace.json", workspaceJson(workspaceRoot)],
183
+ ["README.md", README],
184
+ ["AGENTS.md", AGENTS],
185
+ ["CLAUDE.md", CLAUDE],
186
+ ["imports/README.md", IMPORTS_README],
187
+ ["templates/README.md", TEMPLATES_README],
188
+ ["templates/case-brief.md", CASE_BRIEF],
189
+ [".chain-insights/runtime-skill/SKILL.md", RUNTIME_SKILL],
190
+ [".chain-insights/schema/README.md", SCHEMA_README],
191
+ [".chain-insights/runtime/.keep", ""],
192
+ [".chain-insights/runtime/logs/.keep", ""]
193
+ ];
194
+ }
195
+ async function assertNoFileCollisions(workspaceRoot) {
196
+ for (const [relativePath] of workspaceFiles(workspaceRoot)) {
197
+ const filePath = node_path.default.join(workspaceRoot, relativePath);
198
+ try {
199
+ await (0, node_fs_promises.access)(filePath);
200
+ throw new Error(`Refusing to overwrite ${filePath}. Re-run with --force to replace workspace files.`);
201
+ } catch (err) {
202
+ if (err.code === "ENOENT") continue;
203
+ throw err;
204
+ }
205
+ }
206
+ }
207
+ async function initWorkspace(options) {
208
+ const workspaceRoot = node_path.default.resolve(options.targetDir);
209
+ if (!options.force) await assertNoFileCollisions(workspaceRoot);
210
+ for (const dir of WORKSPACE_DIRS) await (0, node_fs_promises.mkdir)(node_path.default.join(workspaceRoot, dir), { recursive: true });
211
+ const filesWritten = [];
212
+ const flag = options.force ? "w" : "wx";
213
+ for (const [relativePath, content] of workspaceFiles(workspaceRoot)) {
214
+ const filePath = node_path.default.join(workspaceRoot, relativePath);
215
+ try {
216
+ await (0, node_fs_promises.writeFile)(filePath, content, {
217
+ mode: 384,
218
+ flag
219
+ });
220
+ filesWritten.push(relativePath);
221
+ } catch (err) {
222
+ if (err.code === "EEXIST") throw new Error(`Refusing to overwrite ${filePath}. Re-run with --force to replace workspace files.`);
223
+ throw err;
224
+ }
225
+ }
226
+ return {
227
+ workspaceRoot,
228
+ filesWritten
229
+ };
230
+ }
231
+ //#endregion
232
+ exports.initWorkspace = initWorkspace;
@@ -0,0 +1,232 @@
1
+ import path from "node:path";
2
+ import { access, mkdir, writeFile } from "node:fs/promises";
3
+ //#region src/workspace/init.ts
4
+ const WORKSPACE_DIRS = [
5
+ ".chain-insights",
6
+ ".chain-insights/schema",
7
+ ".chain-insights/runtime",
8
+ ".chain-insights/runtime/logs",
9
+ ".chain-insights/runtime-skill",
10
+ "cases",
11
+ "imports",
12
+ "reports",
13
+ "reports/graphs",
14
+ "reports/tables",
15
+ "templates"
16
+ ];
17
+ function todayIso() {
18
+ return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
19
+ }
20
+ function workspaceJson(workspaceRoot) {
21
+ return JSON.stringify({
22
+ schema: "chain-insights.workspace.v1",
23
+ name: "Chain Insights Investigations",
24
+ workspace_root: workspaceRoot,
25
+ default_network: "bittensor",
26
+ graph_mcp_endpoint: "https://staging-mcp.chain-insights.ai/mcp",
27
+ cases_dir: "cases",
28
+ imports_dir: "imports",
29
+ reports_dir: "reports",
30
+ templates_dir: "templates",
31
+ created_at: todayIso()
32
+ }, null, 2) + "\n";
33
+ }
34
+ const README = `# Chain Insights Investigations
35
+
36
+ This is a workspace for Chain Insights AML investigations.
37
+
38
+ ## Start
39
+
40
+ \`\`\`bash
41
+ chain-insights mcp tools --refresh
42
+ chain-insights wallet balance
43
+ \`\`\`
44
+
45
+ ## Layout
46
+
47
+ \`\`\`text
48
+ .chain-insights/ Workspace metadata
49
+ cases/ Case exports and notes
50
+ imports/ External reports, CSVs, screenshots, raw notes
51
+ reports/ Final or interim analyst reports
52
+ reports/graphs/ Graph JSON for visualization
53
+ reports/tables/ Compact tabular extracts
54
+ templates/ Reusable case/report templates
55
+ .chain-insights/schema/ Runtime graph schema captures
56
+ .chain-insights/runtime/ Workspace-local runtime process state and debug logs
57
+ .chain-insights/runtime-skill/ Workspace-specific agent schema notes
58
+ \`\`\`
59
+ `;
60
+ const AGENTS = `# Agent Instructions
61
+
62
+ You are operating inside a Chain Insights investigation workspace.
63
+
64
+ - Read README.md first.
65
+ - If this directory is not initialized, run \`cia init .\` before investigation-producing commands.
66
+ - Do not rerun init in an existing workspace unless replacing scaffolding with \`--force\`.
67
+ - Read .chain-insights/runtime-skill/SKILL.md before graph queries.
68
+ - Preserve full blockchain addresses exactly.
69
+ - Do not guess the network for graph queries.
70
+ - Capture or refresh graph schema before the first case query.
71
+ - Save compact evidence with original graph field names.
72
+ - Put canonical graph JSON in reports/graphs/ and analyst tables in reports/tables/.
73
+ - Evidence files should summarize and point to graph/table outputs; do not paste large raw JSON blobs into evidence Markdown.
74
+ - Investigation output must stay in this initialized workspace.
75
+ - Never write cases, evidence, reports, graph JSON, HTML, schema captures, or logs to ~/.chain-insights.
76
+ - Keep theories lightweight until evidence supports them.
77
+ `;
78
+ const CLAUDE = AGENTS;
79
+ const CASE_BRIEF = `# Case Brief
80
+
81
+ ## Summary
82
+
83
+ Status:
84
+ Network:
85
+ Current Assessment:
86
+
87
+ ## Known Addresses
88
+
89
+ ## Claims To Validate
90
+
91
+ ## Evidence
92
+
93
+ ## Next Steps
94
+ `;
95
+ const IMPORTS_README = `# External Investigation Inputs
96
+
97
+ Put user-provided or third-party investigation material here before turning it
98
+ into case evidence.
99
+
100
+ Examples:
101
+
102
+ - Exchange support exports
103
+ - CSV extracts
104
+ - Screenshots
105
+ - Raw notes
106
+ - Partner reports
107
+
108
+ Files in this directory are inputs, not verified evidence. When an import
109
+ supports a claim, summarize it into the case evidence manifest and reference
110
+ the original file path.
111
+ `;
112
+ const TEMPLATES_README = `# Reusable Workspace Templates
113
+
114
+ Store local report, case, prompt, and evidence templates here.
115
+
116
+ Templates are optional workspace helpers. They are not evidence and should not
117
+ be treated as case state until copied into a case, evidence file, dossier, or
118
+ report.
119
+ `;
120
+ const RUNTIME_SKILL = `---
121
+ name: chain-insights-runtime-schema
122
+ description: Workspace-local Chain Insights runtime schema notes. Refresh this after connecting to a graph MCP endpoint.
123
+ ---
124
+
125
+ # Runtime Graph Schema
126
+
127
+ Before the first investigation query, capture the live graph schema into:
128
+
129
+ \`\`\`text
130
+ .chain-insights/schema/<network>.graph-schema.json
131
+ \`\`\`
132
+
133
+ Use \`graph_query_batch\` for schema capture. Prefix current topology reads
134
+ with \`USE live_topology\`, historical topology reads with
135
+ \`USE archive_topology\`, and fact reads with \`USE facts\`, for example:
136
+
137
+ \`\`\`bash
138
+ cia mcp call graph_query_batch network=<network> 'queries=[{"id":"node_labels","query":"USE live_topology MATCH (n:Address) RETURN \"Address\" AS node_label, count(n) AS sample_count LIMIT 1"},{"id":"archive_flow_sample","query":"USE archive_topology MATCH (:Address)-[f:FLOWS_TO]->(:Address) RETURN f.period_granularity AS granularity, f.amount_sum AS amount_sum LIMIT 20"}]'
139
+ \`\`\`
140
+
141
+ Then update this file with observed labels, relationship types, and allowed
142
+ property names for the active network.
143
+
144
+ Rules:
145
+
146
+ - Prefer \`graph_query\` and \`graph_query_batch\` for graph-language reads.
147
+ - Use \`USE live_topology\` for Memgraph RAM topology, \`USE archive_topology\`
148
+ for StarRocks historical topology, and \`USE facts\` for StarRocks fact
149
+ labels such as \`AddressLabel\`, \`AddressFeature\`,
150
+ \`RiskScore\`, and \`Asset\`. Address facts can be reached through
151
+ relationships such as \`(:Address)-[:HAS_FEATURE]->(:AddressFeature)\`.
152
+ Archived money-flow topology is exposed as
153
+ \`(:Address)-[:FLOWS_TO]->(:Address)\` with \`period_granularity\`,
154
+ \`period_start_date\`, and \`period_end_date\` on the relationship.
155
+ - Preserve source schema field names in evidence and generated data files.
156
+ - Do not rename, reinterpret, or add unit labels to graph fields unless the
157
+ schema or query result explicitly supports that interpretation.
158
+ - Keep evidence compact: select only the fields needed to support the claim.
159
+ Avoid storing whole node or relationship property blobs in evidence unless
160
+ the purpose of the query is schema discovery or debugging.
161
+ - Keep analysis products separate from evidence: graph JSON belongs under
162
+ \`reports/graphs/\`, tabular extracts under \`reports/tables/\`, and analyst
163
+ narrative under \`reports/\`.
164
+ - Evidence Markdown should be a short provenance record with key facts and
165
+ pointers. Large JSON belongs in \`reports/tables/\`, not inline in evidence.
166
+ `;
167
+ const SCHEMA_README = `# Runtime Schema Captures
168
+
169
+ Store graph schema captures here, for example:
170
+
171
+ \`\`\`text
172
+ bittensor.graph-schema.json
173
+ \`\`\`
174
+
175
+ Schema captures should be generated before the first case query in a fresh
176
+ workspace, then referenced by evidence, reports, and runtime skill notes.
177
+ `;
178
+ function workspaceFiles(workspaceRoot) {
179
+ return [
180
+ [".chain-insights/workspace.json", workspaceJson(workspaceRoot)],
181
+ ["README.md", README],
182
+ ["AGENTS.md", AGENTS],
183
+ ["CLAUDE.md", CLAUDE],
184
+ ["imports/README.md", IMPORTS_README],
185
+ ["templates/README.md", TEMPLATES_README],
186
+ ["templates/case-brief.md", CASE_BRIEF],
187
+ [".chain-insights/runtime-skill/SKILL.md", RUNTIME_SKILL],
188
+ [".chain-insights/schema/README.md", SCHEMA_README],
189
+ [".chain-insights/runtime/.keep", ""],
190
+ [".chain-insights/runtime/logs/.keep", ""]
191
+ ];
192
+ }
193
+ async function assertNoFileCollisions(workspaceRoot) {
194
+ for (const [relativePath] of workspaceFiles(workspaceRoot)) {
195
+ const filePath = path.join(workspaceRoot, relativePath);
196
+ try {
197
+ await access(filePath);
198
+ throw new Error(`Refusing to overwrite ${filePath}. Re-run with --force to replace workspace files.`);
199
+ } catch (err) {
200
+ if (err.code === "ENOENT") continue;
201
+ throw err;
202
+ }
203
+ }
204
+ }
205
+ async function initWorkspace(options) {
206
+ const workspaceRoot = path.resolve(options.targetDir);
207
+ if (!options.force) await assertNoFileCollisions(workspaceRoot);
208
+ for (const dir of WORKSPACE_DIRS) await mkdir(path.join(workspaceRoot, dir), { recursive: true });
209
+ const filesWritten = [];
210
+ const flag = options.force ? "w" : "wx";
211
+ for (const [relativePath, content] of workspaceFiles(workspaceRoot)) {
212
+ const filePath = path.join(workspaceRoot, relativePath);
213
+ try {
214
+ await writeFile(filePath, content, {
215
+ mode: 384,
216
+ flag
217
+ });
218
+ filesWritten.push(relativePath);
219
+ } catch (err) {
220
+ if (err.code === "EEXIST") throw new Error(`Refusing to overwrite ${filePath}. Re-run with --force to replace workspace files.`);
221
+ throw err;
222
+ }
223
+ }
224
+ return {
225
+ workspaceRoot,
226
+ filesWritten
227
+ };
228
+ }
229
+ //#endregion
230
+ export { initWorkspace };
231
+
232
+ //# sourceMappingURL=init-CaOsHTIo.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init-CaOsHTIo.mjs","names":[],"sources":["../src/workspace/init.ts"],"sourcesContent":["import { access, mkdir, writeFile } from 'node:fs/promises'\nimport path from 'node:path'\n\nexport interface InitWorkspaceOptions {\n targetDir: string\n force?: boolean\n}\n\nexport interface InitWorkspaceResult {\n workspaceRoot: string\n filesWritten: string[]\n}\n\nconst WORKSPACE_DIRS = [\n '.chain-insights',\n '.chain-insights/schema',\n '.chain-insights/runtime',\n '.chain-insights/runtime/logs',\n '.chain-insights/runtime-skill',\n 'cases',\n 'imports',\n 'reports',\n 'reports/graphs',\n 'reports/tables',\n 'templates',\n]\n\nfunction todayIso(): string {\n return new Date().toISOString().slice(0, 10)\n}\n\nfunction workspaceJson(workspaceRoot: string): string {\n return JSON.stringify({\n schema: 'chain-insights.workspace.v1',\n name: 'Chain Insights Investigations',\n workspace_root: workspaceRoot,\n default_network: 'bittensor',\n graph_mcp_endpoint: 'https://staging-mcp.chain-insights.ai/mcp',\n cases_dir: 'cases',\n imports_dir: 'imports',\n reports_dir: 'reports',\n templates_dir: 'templates',\n created_at: todayIso(),\n }, null, 2) + '\\n'\n}\n\nconst README = `# Chain Insights Investigations\n\nThis is a workspace for Chain Insights AML investigations.\n\n## Start\n\n\\`\\`\\`bash\nchain-insights mcp tools --refresh\nchain-insights wallet balance\n\\`\\`\\`\n\n## Layout\n\n\\`\\`\\`text\n.chain-insights/ Workspace metadata\ncases/ Case exports and notes\nimports/ External reports, CSVs, screenshots, raw notes\nreports/ Final or interim analyst reports\nreports/graphs/ Graph JSON for visualization\nreports/tables/ Compact tabular extracts\ntemplates/ Reusable case/report templates\n.chain-insights/schema/ Runtime graph schema captures\n.chain-insights/runtime/ Workspace-local runtime process state and debug logs\n.chain-insights/runtime-skill/ Workspace-specific agent schema notes\n\\`\\`\\`\n`\n\nconst AGENTS = `# Agent Instructions\n\nYou are operating inside a Chain Insights investigation workspace.\n\n- Read README.md first.\n- If this directory is not initialized, run \\`cia init .\\` before investigation-producing commands.\n- Do not rerun init in an existing workspace unless replacing scaffolding with \\`--force\\`.\n- Read .chain-insights/runtime-skill/SKILL.md before graph queries.\n- Preserve full blockchain addresses exactly.\n- Do not guess the network for graph queries.\n- Capture or refresh graph schema before the first case query.\n- Save compact evidence with original graph field names.\n- Put canonical graph JSON in reports/graphs/ and analyst tables in reports/tables/.\n- Evidence files should summarize and point to graph/table outputs; do not paste large raw JSON blobs into evidence Markdown.\n- Investigation output must stay in this initialized workspace.\n- Never write cases, evidence, reports, graph JSON, HTML, schema captures, or logs to ~/.chain-insights.\n- Keep theories lightweight until evidence supports them.\n`\n\nconst CLAUDE = AGENTS\n\nconst CASE_BRIEF = `# Case Brief\n\n## Summary\n\nStatus:\nNetwork:\nCurrent Assessment:\n\n## Known Addresses\n\n## Claims To Validate\n\n## Evidence\n\n## Next Steps\n`\n\nconst IMPORTS_README = `# External Investigation Inputs\n\nPut user-provided or third-party investigation material here before turning it\ninto case evidence.\n\nExamples:\n\n- Exchange support exports\n- CSV extracts\n- Screenshots\n- Raw notes\n- Partner reports\n\nFiles in this directory are inputs, not verified evidence. When an import\nsupports a claim, summarize it into the case evidence manifest and reference\nthe original file path.\n`\n\nconst TEMPLATES_README = `# Reusable Workspace Templates\n\nStore local report, case, prompt, and evidence templates here.\n\nTemplates are optional workspace helpers. They are not evidence and should not\nbe treated as case state until copied into a case, evidence file, dossier, or\nreport.\n`\n\nconst RUNTIME_SKILL = `---\nname: chain-insights-runtime-schema\ndescription: Workspace-local Chain Insights runtime schema notes. Refresh this after connecting to a graph MCP endpoint.\n---\n\n# Runtime Graph Schema\n\nBefore the first investigation query, capture the live graph schema into:\n\n\\`\\`\\`text\n.chain-insights/schema/<network>.graph-schema.json\n\\`\\`\\`\n\nUse \\`graph_query_batch\\` for schema capture. Prefix current topology reads\nwith \\`USE live_topology\\`, historical topology reads with\n\\`USE archive_topology\\`, and fact reads with \\`USE facts\\`, for example:\n\n\\`\\`\\`bash\ncia mcp call graph_query_batch network=<network> 'queries=[{\"id\":\"node_labels\",\"query\":\"USE live_topology MATCH (n:Address) RETURN \\\"Address\\\" AS node_label, count(n) AS sample_count LIMIT 1\"},{\"id\":\"archive_flow_sample\",\"query\":\"USE archive_topology MATCH (:Address)-[f:FLOWS_TO]->(:Address) RETURN f.period_granularity AS granularity, f.amount_sum AS amount_sum LIMIT 20\"}]'\n\\`\\`\\`\n\nThen update this file with observed labels, relationship types, and allowed\nproperty names for the active network.\n\nRules:\n\n- Prefer \\`graph_query\\` and \\`graph_query_batch\\` for graph-language reads.\n- Use \\`USE live_topology\\` for Memgraph RAM topology, \\`USE archive_topology\\`\n for StarRocks historical topology, and \\`USE facts\\` for StarRocks fact\n labels such as \\`AddressLabel\\`, \\`AddressFeature\\`,\n \\`RiskScore\\`, and \\`Asset\\`. Address facts can be reached through\n relationships such as \\`(:Address)-[:HAS_FEATURE]->(:AddressFeature)\\`.\n Archived money-flow topology is exposed as\n \\`(:Address)-[:FLOWS_TO]->(:Address)\\` with \\`period_granularity\\`,\n \\`period_start_date\\`, and \\`period_end_date\\` on the relationship.\n- Preserve source schema field names in evidence and generated data files.\n- Do not rename, reinterpret, or add unit labels to graph fields unless the\n schema or query result explicitly supports that interpretation.\n- Keep evidence compact: select only the fields needed to support the claim.\n Avoid storing whole node or relationship property blobs in evidence unless\n the purpose of the query is schema discovery or debugging.\n- Keep analysis products separate from evidence: graph JSON belongs under\n \\`reports/graphs/\\`, tabular extracts under \\`reports/tables/\\`, and analyst\n narrative under \\`reports/\\`.\n- Evidence Markdown should be a short provenance record with key facts and\n pointers. Large JSON belongs in \\`reports/tables/\\`, not inline in evidence.\n`\n\nconst SCHEMA_README = `# Runtime Schema Captures\n\nStore graph schema captures here, for example:\n\n\\`\\`\\`text\nbittensor.graph-schema.json\n\\`\\`\\`\n\nSchema captures should be generated before the first case query in a fresh\nworkspace, then referenced by evidence, reports, and runtime skill notes.\n`\n\nfunction workspaceFiles(workspaceRoot: string): Array<[string, string]> {\n return [\n ['.chain-insights/workspace.json', workspaceJson(workspaceRoot)],\n ['README.md', README],\n ['AGENTS.md', AGENTS],\n ['CLAUDE.md', CLAUDE],\n ['imports/README.md', IMPORTS_README],\n ['templates/README.md', TEMPLATES_README],\n ['templates/case-brief.md', CASE_BRIEF],\n ['.chain-insights/runtime-skill/SKILL.md', RUNTIME_SKILL],\n ['.chain-insights/schema/README.md', SCHEMA_README],\n ['.chain-insights/runtime/.keep', ''],\n ['.chain-insights/runtime/logs/.keep', ''],\n ]\n}\n\nasync function assertNoFileCollisions(workspaceRoot: string): Promise<void> {\n for (const [relativePath] of workspaceFiles(workspaceRoot)) {\n const filePath = path.join(workspaceRoot, relativePath)\n try {\n await access(filePath)\n throw new Error(`Refusing to overwrite ${filePath}. Re-run with --force to replace workspace files.`)\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n continue\n }\n throw err\n }\n }\n}\n\nexport async function initWorkspace(options: InitWorkspaceOptions): Promise<InitWorkspaceResult> {\n const workspaceRoot = path.resolve(options.targetDir)\n if (!options.force) {\n await assertNoFileCollisions(workspaceRoot)\n }\n\n for (const dir of WORKSPACE_DIRS) {\n await mkdir(path.join(workspaceRoot, dir), { recursive: true })\n }\n\n const filesWritten: string[] = []\n const flag = options.force ? 'w' : 'wx'\n for (const [relativePath, content] of workspaceFiles(workspaceRoot)) {\n const filePath = path.join(workspaceRoot, relativePath)\n try {\n await writeFile(filePath, content, { mode: 0o600, flag })\n filesWritten.push(relativePath)\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'EEXIST') {\n throw new Error(`Refusing to overwrite ${filePath}. Re-run with --force to replace workspace files.`)\n }\n throw err\n }\n }\n\n return { workspaceRoot, filesWritten }\n}\n"],"mappings":";;;AAaA,MAAM,iBAAiB;CACrB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;AAED,SAAS,WAAmB;AAC1B,yBAAO,IAAI,MAAM,EAAC,aAAa,CAAC,MAAM,GAAG,GAAG;;AAG9C,SAAS,cAAc,eAA+B;AACpD,QAAO,KAAK,UAAU;EACpB,QAAQ;EACR,MAAM;EACN,gBAAgB;EAChB,iBAAiB;EACjB,oBAAoB;EACpB,WAAW;EACX,aAAa;EACb,aAAa;EACb,eAAe;EACf,YAAY,UAAU;EACvB,EAAE,MAAM,EAAE,GAAG;;AAGhB,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;AA2Bf,MAAM,SAAS;;;;;;;;;;;;;;;;;;AAmBf,MAAM,SAAS;AAEf,MAAM,aAAa;;;;;;;;;;;;;;;;AAiBnB,MAAM,iBAAiB;;;;;;;;;;;;;;;;;AAkBvB,MAAM,mBAAmB;;;;;;;;AASzB,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgDtB,MAAM,gBAAgB;;;;;;;;;;;AAYtB,SAAS,eAAe,eAAgD;AACtE,QAAO;EACL,CAAC,kCAAkC,cAAc,cAAc,CAAC;EAChE,CAAC,aAAa,OAAO;EACrB,CAAC,aAAa,OAAO;EACrB,CAAC,aAAa,OAAO;EACrB,CAAC,qBAAqB,eAAe;EACrC,CAAC,uBAAuB,iBAAiB;EACzC,CAAC,2BAA2B,WAAW;EACvC,CAAC,0CAA0C,cAAc;EACzD,CAAC,oCAAoC,cAAc;EACnD,CAAC,iCAAiC,GAAG;EACrC,CAAC,sCAAsC,GAAG;EAC3C;;AAGH,eAAe,uBAAuB,eAAsC;AAC1E,MAAK,MAAM,CAAC,iBAAiB,eAAe,cAAc,EAAE;EAC1D,MAAM,WAAW,KAAK,KAAK,eAAe,aAAa;AACvD,MAAI;AACF,SAAM,OAAO,SAAS;AACtB,SAAM,IAAI,MAAM,yBAAyB,SAAS,mDAAmD;WAC9F,KAAK;AACZ,OAAK,IAA8B,SAAS,SAC1C;AAEF,SAAM;;;;AAKZ,eAAsB,cAAc,SAA6D;CAC/F,MAAM,gBAAgB,KAAK,QAAQ,QAAQ,UAAU;AACrD,KAAI,CAAC,QAAQ,MACX,OAAM,uBAAuB,cAAc;AAG7C,MAAK,MAAM,OAAO,eAChB,OAAM,MAAM,KAAK,KAAK,eAAe,IAAI,EAAE,EAAE,WAAW,MAAM,CAAC;CAGjE,MAAM,eAAyB,EAAE;CACjC,MAAM,OAAO,QAAQ,QAAQ,MAAM;AACnC,MAAK,MAAM,CAAC,cAAc,YAAY,eAAe,cAAc,EAAE;EACnE,MAAM,WAAW,KAAK,KAAK,eAAe,aAAa;AACvD,MAAI;AACF,SAAM,UAAU,UAAU,SAAS;IAAE,MAAM;IAAO;IAAM,CAAC;AACzD,gBAAa,KAAK,aAAa;WACxB,KAAK;AACZ,OAAK,IAA8B,SAAS,SAC1C,OAAM,IAAI,MAAM,yBAAyB,SAAS,mDAAmD;AAEvG,SAAM;;;AAIV,QAAO;EAAE;EAAe;EAAc"}