chain-insights 0.3.4 → 0.3.6

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 (54) hide show
  1. package/README.md +28 -11
  2. package/dist/canvas-Cn-maEIh.mjs +203 -0
  3. package/dist/canvas-Cn-maEIh.mjs.map +1 -0
  4. package/dist/canvas-p-oKCMjc.cjs +251 -0
  5. package/dist/cases-Bz_9XKEw.cjs +19 -0
  6. package/dist/cases-TVcAifxu.mjs +16 -0
  7. package/dist/cases-TVcAifxu.mjs.map +1 -0
  8. package/dist/cli.cjs +74 -28
  9. package/dist/cli.mjs +74 -28
  10. package/dist/cli.mjs.map +1 -1
  11. package/dist/{data-extractor-DZUJu1Bz.mjs → data-extractor-B4nHw1wZ.mjs} +2 -2
  12. package/dist/{data-extractor-DZUJu1Bz.mjs.map → data-extractor-B4nHw1wZ.mjs.map} +1 -1
  13. package/dist/{data-extractor-Cavd7wHk.cjs → data-extractor-DS4rzy3M.cjs} +1 -1
  14. package/dist/{export-BqTCO9lP.mjs → export-CBhcJuZ6.mjs} +8 -205
  15. package/dist/export-CBhcJuZ6.mjs.map +1 -0
  16. package/dist/{export-DsXgtCwO.cjs → export-D4v4-6F4.cjs} +16 -214
  17. package/dist/index.cjs +1 -1
  18. package/dist/index.mjs +1 -1
  19. package/dist/{init-DLBL_nVG.mjs → init-CKQ6F07J.mjs} +22 -5
  20. package/dist/init-CKQ6F07J.mjs.map +1 -0
  21. package/dist/{init-zqbd7i-_.cjs → init-Dhw8F23z.cjs} +21 -4
  22. package/dist/mcp-proxy.cjs +20 -20
  23. package/dist/mcp-proxy.mjs +20 -20
  24. package/dist/mcp-proxy.mjs.map +1 -1
  25. package/dist/{public-tools-wJoAFDFa.mjs → public-tools-CyUZEz9B.mjs} +3 -3
  26. package/dist/{public-tools-wJoAFDFa.mjs.map → public-tools-CyUZEz9B.mjs.map} +1 -1
  27. package/dist/{public-tools-BvMb3H2P.cjs → public-tools-xfVNz9NE.cjs} +2 -2
  28. package/dist/{runner-BhZ4lnF1.cjs → runner-CVo41fjz.cjs} +2 -2
  29. package/dist/{runner-DIJSbkjc.mjs → runner-DWuSy1Se.mjs} +3 -3
  30. package/dist/{runner-DIJSbkjc.mjs.map → runner-DWuSy1Se.mjs.map} +1 -1
  31. package/dist/{selector-CF2o5gxN.mjs → selector-BvXM9jbe.mjs} +2 -2
  32. package/dist/{selector-CF2o5gxN.mjs.map → selector-BvXM9jbe.mjs.map} +1 -1
  33. package/dist/{selector-DfAMZEC9.cjs → selector-Dps_ZFxq.cjs} +1 -1
  34. package/dist/{store-CTtqQtaE.mjs → store-C2B_AssI.mjs} +2 -2
  35. package/dist/{store-CTtqQtaE.mjs.map → store-C2B_AssI.mjs.map} +1 -1
  36. package/dist/{store-CqPfs47P.cjs → store-CQhU8dz8.cjs} +0 -18
  37. package/dist/vault-B2y78Ypu.cjs +560 -0
  38. package/dist/vault-z35Dohdq.mjs +560 -0
  39. package/dist/vault-z35Dohdq.mjs.map +1 -0
  40. package/dist/{viz-Dqp3C5kb.cjs → viz-D1620cBX.cjs} +3 -3
  41. package/dist/{viz-5y24S5X1.mjs → viz-DB5XFG1z.mjs} +4 -4
  42. package/dist/{viz-5y24S5X1.mjs.map → viz-DB5XFG1z.mjs.map} +1 -1
  43. package/docs/graph-tools.md +24 -8
  44. package/docs/investigation-workspaces.md +36 -10
  45. package/docs/knowledge-exports.md +6 -2
  46. package/docs/mcp-proxy.md +29 -7
  47. package/docs/obsidian-vault.md +130 -0
  48. package/package.json +1 -1
  49. package/skills/chain-insights-developer-experience/SKILL.md +2 -2
  50. package/skills/chain-insights-investigation/SKILL.md +1 -1
  51. package/dist/cases-Cp9DUbEV.mjs +0 -6
  52. package/dist/cases-sTY5aXav.cjs +0 -9
  53. package/dist/export-BqTCO9lP.mjs.map +0 -1
  54. package/dist/init-DLBL_nVG.mjs.map +0 -1
@@ -882,7 +882,7 @@ async function runFundFlowProbe(remoteClient, _config, options) {
882
882
  await (0, node_fs_promises.writeFile)(tableHtmlPath, buildTableHtml(seedAddress, network, flows, deposits, sourceMatches, reverseLeads), { mode: 384 });
883
883
  await (0, node_fs_promises.writeFile)(reportPath, buildMarkdownReport(seedAddress, network, flows, deposits, sourceMatches, reverseLeads, aliases, graphPath, schemaResult.filePath), { mode: 384 });
884
884
  if (options.caseId) {
885
- const { EvidenceStore } = await Promise.resolve().then(() => require("./cases-sTY5aXav.cjs"));
885
+ const { EvidenceStore } = await Promise.resolve().then(() => require("./cases-Bz_9XKEw.cjs")).then((n) => n.cases_exports);
886
886
  await EvidenceStore.append(options.caseId, {
887
887
  source: evidenceSource,
888
888
  queryParams: `network=${network} seed_address=${seedAddress} max_hops=${maxHops} per_address_limit=${perAddressLimit} min_amount_sum=${minAmountSum}`,
@@ -2321,7 +2321,7 @@ async function traceDepositSources(remoteClient, _config, options) {
2321
2321
  const artifacts = await writeTraceSourceArtifacts("trace_deposit_sources", network, graphData, rows, summaryText);
2322
2322
  const evidence = artifactEvidence(artifacts);
2323
2323
  if (options.caseId) {
2324
- const { EvidenceStore } = await Promise.resolve().then(() => require("./cases-sTY5aXav.cjs"));
2324
+ const { EvidenceStore } = await Promise.resolve().then(() => require("./cases-Bz_9XKEw.cjs")).then((n) => n.cases_exports);
2325
2325
  await EvidenceStore.append(options.caseId, {
2326
2326
  source: "trace_deposit_sources",
2327
2327
  queryParams: `network=${network} deposit_addresses=${deposits.join(",")} max_hops=${maxHops}`,
@@ -1,8 +1,8 @@
1
1
  const require_version = require("./version-CO9Or_YV.cjs");
2
2
  const require_config = require("./config-BwVx19Og.cjs");
3
3
  const require_client = require("./client-Db6IV1tv.cjs");
4
- const require_viz = require("./viz-Dqp3C5kb.cjs");
5
- const require_store = require("./store-CqPfs47P.cjs");
4
+ const require_viz = require("./viz-D1620cBX.cjs");
5
+ const require_store = require("./store-CQhU8dz8.cjs");
6
6
  const require_evidence = require("./evidence-CvEesemA.cjs");
7
7
  let _modelcontextprotocol_sdk_client_index_js = require("@modelcontextprotocol/sdk/client/index.js");
8
8
  let _modelcontextprotocol_sdk_client_streamableHttp_js = require("@modelcontextprotocol/sdk/client/streamableHttp.js");
@@ -1,8 +1,8 @@
1
1
  import { n as PACKAGE_VERSION } from "./version-BA3J8hu4.mjs";
2
2
  import { n as loadConfig } from "./config-Drgc2HuF.mjs";
3
3
  import { r as createConfiguredMcpFetch } from "./client-D4JE7fFF.mjs";
4
- import { t as generateVisualization } from "./viz-5y24S5X1.mjs";
5
- import { t as CaseStore } from "./store-CTtqQtaE.mjs";
4
+ import { t as generateVisualization } from "./viz-DB5XFG1z.mjs";
5
+ import { t as CaseStore } from "./store-C2B_AssI.mjs";
6
6
  import { t as EvidenceStore } from "./evidence-D96PTzOQ.mjs";
7
7
  import { Client } from "@modelcontextprotocol/sdk/client/index.js";
8
8
  import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
@@ -146,4 +146,4 @@ async run(playbook, opts) {
146
146
  //#endregion
147
147
  export { PlaybookRunner };
148
148
 
149
- //# sourceMappingURL=runner-DIJSbkjc.mjs.map
149
+ //# sourceMappingURL=runner-DWuSy1Se.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"runner-DIJSbkjc.mjs","names":[],"sources":["../src/playbooks/runner.ts"],"sourcesContent":["import { Client } from '@modelcontextprotocol/sdk/client/index.js'\nimport { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js'\nimport { CaseStore } from '../cases/store.js'\nimport { EvidenceStore } from '../cases/evidence.js'\nimport { loadConfig } from '../config/index.js'\nimport { createConfiguredMcpFetch } from '../mcp/client.js'\nimport { generateVisualization } from '../viz/index.js'\nimport { PACKAGE_VERSION } from '../version.js'\nimport type { PlaybookDefinition } from './schema.js'\n\nexport interface RunnerOptions {\n caseId?: string // attach to existing case; omit for quick-case auto-creation\n from?: number // 1-based step to resume from (default: 1)\n dryRun?: boolean // print steps, no MCP calls\n params?: Record<string, string>\n}\n\n/** Sleep for ms milliseconds. */\nfunction sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms))\n}\n\n/** Check if an error is a timeout/abort error. */\nfunction isTimeoutError(err: unknown): boolean {\n if (!(err instanceof Error)) return false\n return err.name === 'AbortError' || (err as NodeJS.ErrnoException).code === 'ECONNRESET'\n}\n\n/** Check if an error is a payment failure. */\nfunction isPaymentError(err: unknown): boolean {\n if (!(err instanceof Error)) return false\n const msg = err.message.toLowerCase()\n // Match HTTP 402 status more precisely, or x402-specific error signals\n return msg.includes('http 402') ||\n msg.includes('status 402') ||\n msg.includes('payment required') ||\n msg.includes('x402')\n}\n\n/**\n * Call an MCP tool with retry logic on timeout (up to 3 total attempts).\n * Returns the text result or throws on non-retryable error.\n */\nasync function callWithRetry(\n client: Client,\n toolName: string,\n params: Record<string, string>\n): Promise<string> {\n const MAX_ATTEMPTS = 3\n let lastErr: unknown\n\n for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {\n try {\n const result = await client.callTool({ name: toolName, arguments: params })\n const content = result.content as Array<{ type: string; text?: string }>\n return content.filter(c => c.type === 'text').map(c => c.text ?? '').join('\\n')\n } catch (err) {\n if (isTimeoutError(err) && attempt < MAX_ATTEMPTS) {\n lastErr = err\n await sleep(1000)\n continue\n }\n throw err\n }\n }\n\n throw lastErr\n}\n\nasync function validateStepTools(client: Client, steps: PlaybookDefinition['steps']): Promise<void> {\n const result = await client.listTools()\n const available = new Set(result.tools.map(tool => tool.name))\n const missing = [...new Set(steps.map(step => step.tool).filter(tool => !available.has(tool)))]\n if (missing.length === 0) return\n\n const availableList = [...available].sort().join(', ') || 'none'\n throw new Error(\n `Unknown MCP tool(s) in playbook: ${missing.join(', ')}. ` +\n `Available tools: ${availableList}. Run \\`chain-insights mcp tools --refresh\\` to inspect the live MCP schema.`\n )\n}\n\nexport const PlaybookRunner = {\n /**\n * Execute a playbook definition step-by-step against the live MCP.\n *\n * @param playbook - Parsed and validated PlaybookDefinition\n * @param opts - Runner options (caseId, from, dryRun, params)\n */\n async run(playbook: PlaybookDefinition, opts: RunnerOptions): Promise<void> {\n const startIndex = (opts.from ?? 1) - 1 // convert 1-based to 0-based\n const stepsToRun = playbook.steps.slice(startIndex)\n const totalSteps = playbook.steps.length\n\n // --- DRY RUN ---\n if (opts.dryRun) {\n console.log(`Playbook: ${playbook.name} (dry run — no MCP calls)`)\n console.log(`Steps: ${totalSteps} total, starting from ${startIndex + 1}`)\n console.log('')\n for (const step of stepsToRun) {\n console.log(`Step ${step.index}/${totalSteps}: ${step.tool} (params: ${JSON.stringify(step.params)})`)\n }\n console.log('')\n console.log('Cost: unknown (MCP pricing not available without live connection)')\n return\n }\n\n // --- MCP AUTH CHECK (before case creation to avoid orphan cases) ---\n const config = await loadConfig()\n const mcpFetch = await createConfiguredMcpFetch(config)\n\n // --- CASE RESOLUTION ---\n let caseId: string\n if (opts.caseId) {\n const existingCase = await CaseStore.get(opts.caseId)\n caseId = existingCase.id\n } else {\n const newCase = await CaseStore.create({\n name: `quick-${playbook.name}-${Date.now()}`,\n tags: ['quick', 'playbook', playbook.name],\n description: `Auto-created for one-off playbook run: ${playbook.name}`,\n })\n caseId = newCase.id\n console.log(`Created quick case: ${caseId}`)\n }\n\n // --- MCP CONNECTION ---\n const client = new Client({ name: 'chain-insights-playbook', version: PACKAGE_VERSION })\n await client.connect(\n new StreamableHTTPClientTransport(new URL(config.mcpEndpoint), { fetch: mcpFetch })\n )\n\n let evidenceCount = 0\n\n try {\n await validateStepTools(client, stepsToRun)\n\n // --- STEP LOOP ---\n for (const step of stepsToRun) {\n console.log(`Step ${step.index}/${totalSteps}: ${step.label}...`)\n\n let result: string\n try {\n result = await callWithRetry(client, step.tool, step.params)\n } catch (err) {\n if (isPaymentError(err)) {\n if (process.stdin.isTTY) {\n // Interactive: prompt user\n const { createInterface } = await import('node:readline')\n const rl = createInterface({ input: process.stdin, output: process.stdout })\n const answer = await new Promise<string>(resolve => {\n rl.question(`Payment required for step ${step.index}. (retry/skip/abort): `, resolve)\n })\n rl.close()\n\n if (answer.trim().toLowerCase() === 'retry') {\n result = await callWithRetry(client, step.tool, step.params)\n } else if (answer.trim().toLowerCase() === 'skip') {\n console.log(`Step ${step.index} skipped.`)\n continue\n } else {\n throw new Error(`Aborted at step ${step.index} due to payment failure.`)\n }\n } else {\n // Non-TTY: abort\n throw new Error(\n `Payment required for step ${step.index} but no interactive terminal available. ` +\n `Configure wallet with \\`chain-insights wallet import <private-key>\\`, then run \\`chain-insights wallet ready\\`. Aborting.`\n )\n }\n } else {\n // Non-payment, non-timeout MCP error — stop and report\n const completedSteps = step.index - 1 - startIndex\n const completedMsg = completedSteps > 0\n ? `Completed: steps ${startIndex + 1}..${step.index - 1}.`\n : 'No steps completed before failure.'\n console.error(\n `Step ${step.index} failed: ${(err as Error).message}. ` +\n `${completedMsg} Run with --from ${step.index} to resume.`\n )\n throw err\n }\n }\n\n // --- STORE EVIDENCE ---\n await EvidenceStore.append(caseId, {\n source: step.tool,\n content: result,\n queryParams: JSON.stringify(step.params),\n })\n evidenceCount++\n console.log(` (${result.length} chars stored)`)\n }\n\n // --- AUTO-VIZ for trace-funds ---\n if (playbook.name === 'trace-funds') {\n try {\n const viz = await generateVisualization({ caseId })\n console.log(`Visualization generated: ${viz.htmlPath}`)\n } catch {\n console.log('No transaction data to visualize.')\n }\n }\n\n // --- FINAL SUMMARY ---\n console.log(`Playbook complete. Case: ${caseId}. Evidence: ${evidenceCount} entries.`)\n } finally {\n await client.close()\n }\n },\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"runner-DWuSy1Se.mjs","names":[],"sources":["../src/playbooks/runner.ts"],"sourcesContent":["import { Client } from '@modelcontextprotocol/sdk/client/index.js'\nimport { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js'\nimport { CaseStore } from '../cases/store.js'\nimport { EvidenceStore } from '../cases/evidence.js'\nimport { loadConfig } from '../config/index.js'\nimport { createConfiguredMcpFetch } from '../mcp/client.js'\nimport { generateVisualization } from '../viz/index.js'\nimport { PACKAGE_VERSION } from '../version.js'\nimport type { PlaybookDefinition } from './schema.js'\n\nexport interface RunnerOptions {\n caseId?: string // attach to existing case; omit for quick-case auto-creation\n from?: number // 1-based step to resume from (default: 1)\n dryRun?: boolean // print steps, no MCP calls\n params?: Record<string, string>\n}\n\n/** Sleep for ms milliseconds. */\nfunction sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms))\n}\n\n/** Check if an error is a timeout/abort error. */\nfunction isTimeoutError(err: unknown): boolean {\n if (!(err instanceof Error)) return false\n return err.name === 'AbortError' || (err as NodeJS.ErrnoException).code === 'ECONNRESET'\n}\n\n/** Check if an error is a payment failure. */\nfunction isPaymentError(err: unknown): boolean {\n if (!(err instanceof Error)) return false\n const msg = err.message.toLowerCase()\n // Match HTTP 402 status more precisely, or x402-specific error signals\n return msg.includes('http 402') ||\n msg.includes('status 402') ||\n msg.includes('payment required') ||\n msg.includes('x402')\n}\n\n/**\n * Call an MCP tool with retry logic on timeout (up to 3 total attempts).\n * Returns the text result or throws on non-retryable error.\n */\nasync function callWithRetry(\n client: Client,\n toolName: string,\n params: Record<string, string>\n): Promise<string> {\n const MAX_ATTEMPTS = 3\n let lastErr: unknown\n\n for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {\n try {\n const result = await client.callTool({ name: toolName, arguments: params })\n const content = result.content as Array<{ type: string; text?: string }>\n return content.filter(c => c.type === 'text').map(c => c.text ?? '').join('\\n')\n } catch (err) {\n if (isTimeoutError(err) && attempt < MAX_ATTEMPTS) {\n lastErr = err\n await sleep(1000)\n continue\n }\n throw err\n }\n }\n\n throw lastErr\n}\n\nasync function validateStepTools(client: Client, steps: PlaybookDefinition['steps']): Promise<void> {\n const result = await client.listTools()\n const available = new Set(result.tools.map(tool => tool.name))\n const missing = [...new Set(steps.map(step => step.tool).filter(tool => !available.has(tool)))]\n if (missing.length === 0) return\n\n const availableList = [...available].sort().join(', ') || 'none'\n throw new Error(\n `Unknown MCP tool(s) in playbook: ${missing.join(', ')}. ` +\n `Available tools: ${availableList}. Run \\`chain-insights mcp tools --refresh\\` to inspect the live MCP schema.`\n )\n}\n\nexport const PlaybookRunner = {\n /**\n * Execute a playbook definition step-by-step against the live MCP.\n *\n * @param playbook - Parsed and validated PlaybookDefinition\n * @param opts - Runner options (caseId, from, dryRun, params)\n */\n async run(playbook: PlaybookDefinition, opts: RunnerOptions): Promise<void> {\n const startIndex = (opts.from ?? 1) - 1 // convert 1-based to 0-based\n const stepsToRun = playbook.steps.slice(startIndex)\n const totalSteps = playbook.steps.length\n\n // --- DRY RUN ---\n if (opts.dryRun) {\n console.log(`Playbook: ${playbook.name} (dry run — no MCP calls)`)\n console.log(`Steps: ${totalSteps} total, starting from ${startIndex + 1}`)\n console.log('')\n for (const step of stepsToRun) {\n console.log(`Step ${step.index}/${totalSteps}: ${step.tool} (params: ${JSON.stringify(step.params)})`)\n }\n console.log('')\n console.log('Cost: unknown (MCP pricing not available without live connection)')\n return\n }\n\n // --- MCP AUTH CHECK (before case creation to avoid orphan cases) ---\n const config = await loadConfig()\n const mcpFetch = await createConfiguredMcpFetch(config)\n\n // --- CASE RESOLUTION ---\n let caseId: string\n if (opts.caseId) {\n const existingCase = await CaseStore.get(opts.caseId)\n caseId = existingCase.id\n } else {\n const newCase = await CaseStore.create({\n name: `quick-${playbook.name}-${Date.now()}`,\n tags: ['quick', 'playbook', playbook.name],\n description: `Auto-created for one-off playbook run: ${playbook.name}`,\n })\n caseId = newCase.id\n console.log(`Created quick case: ${caseId}`)\n }\n\n // --- MCP CONNECTION ---\n const client = new Client({ name: 'chain-insights-playbook', version: PACKAGE_VERSION })\n await client.connect(\n new StreamableHTTPClientTransport(new URL(config.mcpEndpoint), { fetch: mcpFetch })\n )\n\n let evidenceCount = 0\n\n try {\n await validateStepTools(client, stepsToRun)\n\n // --- STEP LOOP ---\n for (const step of stepsToRun) {\n console.log(`Step ${step.index}/${totalSteps}: ${step.label}...`)\n\n let result: string\n try {\n result = await callWithRetry(client, step.tool, step.params)\n } catch (err) {\n if (isPaymentError(err)) {\n if (process.stdin.isTTY) {\n // Interactive: prompt user\n const { createInterface } = await import('node:readline')\n const rl = createInterface({ input: process.stdin, output: process.stdout })\n const answer = await new Promise<string>(resolve => {\n rl.question(`Payment required for step ${step.index}. (retry/skip/abort): `, resolve)\n })\n rl.close()\n\n if (answer.trim().toLowerCase() === 'retry') {\n result = await callWithRetry(client, step.tool, step.params)\n } else if (answer.trim().toLowerCase() === 'skip') {\n console.log(`Step ${step.index} skipped.`)\n continue\n } else {\n throw new Error(`Aborted at step ${step.index} due to payment failure.`)\n }\n } else {\n // Non-TTY: abort\n throw new Error(\n `Payment required for step ${step.index} but no interactive terminal available. ` +\n `Configure wallet with \\`chain-insights wallet import <private-key>\\`, then run \\`chain-insights wallet ready\\`. Aborting.`\n )\n }\n } else {\n // Non-payment, non-timeout MCP error — stop and report\n const completedSteps = step.index - 1 - startIndex\n const completedMsg = completedSteps > 0\n ? `Completed: steps ${startIndex + 1}..${step.index - 1}.`\n : 'No steps completed before failure.'\n console.error(\n `Step ${step.index} failed: ${(err as Error).message}. ` +\n `${completedMsg} Run with --from ${step.index} to resume.`\n )\n throw err\n }\n }\n\n // --- STORE EVIDENCE ---\n await EvidenceStore.append(caseId, {\n source: step.tool,\n content: result,\n queryParams: JSON.stringify(step.params),\n })\n evidenceCount++\n console.log(` (${result.length} chars stored)`)\n }\n\n // --- AUTO-VIZ for trace-funds ---\n if (playbook.name === 'trace-funds') {\n try {\n const viz = await generateVisualization({ caseId })\n console.log(`Visualization generated: ${viz.htmlPath}`)\n } catch {\n console.log('No transaction data to visualize.')\n }\n }\n\n // --- FINAL SUMMARY ---\n console.log(`Playbook complete. Case: ${caseId}. Evidence: ${evidenceCount} entries.`)\n } finally {\n await client.close()\n }\n },\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { t as CaseStore } from "./store-CTtqQtaE.mjs";
1
+ import { t as CaseStore } from "./store-C2B_AssI.mjs";
2
2
  //#region src/cases/selector.ts
3
3
  async function resolveCaseSelector(input) {
4
4
  if (!/^[1-9]\d*$/.test(input)) return input;
@@ -9,4 +9,4 @@ async function resolveCaseSelector(input) {
9
9
  //#endregion
10
10
  export { resolveCaseSelector };
11
11
 
12
- //# sourceMappingURL=selector-CF2o5gxN.mjs.map
12
+ //# sourceMappingURL=selector-BvXM9jbe.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"selector-CF2o5gxN.mjs","names":[],"sources":["../src/cases/selector.ts"],"sourcesContent":["import { CaseStore } from './store.js'\n\nexport async function resolveCaseSelector(input: string): Promise<string> {\n if (!/^[1-9]\\d*$/.test(input)) return input\n\n const cases = await CaseStore.list()\n const index = Number(input) - 1\n const selected = cases[index]\n if (!selected) {\n throw new Error(`No case numbered ${input}. Run \\`cia case list\\` to see available cases.`)\n }\n return selected.id\n}\n"],"mappings":";;AAEA,eAAsB,oBAAoB,OAAgC;CACxE,IAAI,CAAC,aAAa,KAAK,KAAK,GAAG,OAAO;CAItC,MAAM,YAAW,MAFG,UAAU,KAAK,GACrB,OAAO,KAAK,IAAI;CAE9B,IAAI,CAAC,UACH,MAAM,IAAI,MAAM,oBAAoB,MAAM,gDAAgD;CAE5F,OAAO,SAAS;AAClB"}
1
+ {"version":3,"file":"selector-BvXM9jbe.mjs","names":[],"sources":["../src/cases/selector.ts"],"sourcesContent":["import { CaseStore } from './store.js'\n\nexport async function resolveCaseSelector(input: string): Promise<string> {\n if (!/^[1-9]\\d*$/.test(input)) return input\n\n const cases = await CaseStore.list()\n const index = Number(input) - 1\n const selected = cases[index]\n if (!selected) {\n throw new Error(`No case numbered ${input}. Run \\`cia case list\\` to see available cases.`)\n }\n return selected.id\n}\n"],"mappings":";;AAEA,eAAsB,oBAAoB,OAAgC;CACxE,IAAI,CAAC,aAAa,KAAK,KAAK,GAAG,OAAO;CAItC,MAAM,YAAW,MAFG,UAAU,KAAK,GACrB,OAAO,KAAK,IAAI;CAE9B,IAAI,CAAC,UACH,MAAM,IAAI,MAAM,oBAAoB,MAAM,gDAAgD;CAE5F,OAAO,SAAS;AAClB"}
@@ -1,4 +1,4 @@
1
- const require_store = require("./store-CqPfs47P.cjs");
1
+ const require_store = require("./store-CQhU8dz8.cjs");
2
2
  //#region src/cases/selector.ts
3
3
  async function resolveCaseSelector(input) {
4
4
  if (!/^[1-9]\d*$/.test(input)) return input;
@@ -226,6 +226,6 @@ const CaseStore = {
226
226
  }
227
227
  };
228
228
  //#endregion
229
- export { CaseStatusEnum as a, CaseSchema as i, generateCaseId as n, store_exports as r, CaseStore as t };
229
+ export { store_exports as n, CaseStore as t };
230
230
 
231
- //# sourceMappingURL=store-CTtqQtaE.mjs.map
231
+ //# sourceMappingURL=store-C2B_AssI.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"store-CTtqQtaE.mjs","names":["nodeErr"],"sources":["../src/cases/schema.ts","../src/cases/store.ts"],"sourcesContent":["import * as z from 'zod'\n\n// Case ID format: YYYYMMDD_NNN_slug (e.g. 20260511_001_tornado-mixer)\n// Regex rejects path traversal chars (../, shell chars) per T-03-01 threat model.\nconst caseIdRegex = /^\\d{8}_\\d{3}_[a-z0-9][a-z0-9-]*$/\n\nexport const CaseStatusEnum = z.enum(['open', 'active', 'suspended', 'closed'])\nexport type CaseStatus = z.infer<typeof CaseStatusEnum>\n\nexport const CaseSchema = z.object({\n id: z.string().regex(caseIdRegex, 'Invalid case ID format'),\n name: z.string().min(1).max(200),\n status: CaseStatusEnum.default('open'),\n created: z.string().datetime(),\n updated: z.string().datetime(),\n tags: z.array(z.string()).default([]),\n description: z.string().default(''),\n slug: z.string().optional(),\n})\nexport type Case = z.infer<typeof CaseSchema>\n\nexport const EvidenceSchema = z.object({\n id: z.string().min(1),\n caseId: z.string().regex(caseIdRegex),\n source: z.string().min(1),\n timestamp: z.string().datetime(),\n queryParams: z.string().default(''),\n})\nexport type Evidence = z.infer<typeof EvidenceSchema>\n\nexport const DossierSchema = z.object({\n address: z.string().min(1).max(100),\n type: z.enum(['eoa', 'contract', 'exchange', 'mixer', 'unknown']).default('unknown'),\n firstSeen: z.string().datetime(),\n lastSeen: z.string().datetime(),\n riskTags: z.string().default(''),\n})\nexport type Dossier = z.infer<typeof DossierSchema>\n\nexport const SessionSchema = z.object({\n sessionId: z.string().min(1),\n caseId: z.string().regex(caseIdRegex),\n startTime: z.string().datetime(),\n endTime: z.string().optional(),\n status: z.enum(['active', 'ended']).default('active'),\n})\nexport type Session = z.infer<typeof SessionSchema>\n","import { readFile, writeFile, mkdir, readdir } from 'node:fs/promises'\nimport path from 'node:path'\nimport { workspaceOutputPaths } from '../workspace/output-root.js'\nimport { parseFrontmatter, serializeFrontmatter } from './frontmatter.js'\nimport { CaseSchema, type Case, type CaseStatus } from './schema.js'\n\nexport const casesRoot = () => workspaceOutputPaths().casesRoot\n\nfunction caseDir(id: string): string {\n return path.join(casesRoot(), id)\n}\n\nexport function generateCaseId(name: string, existingIds: string[]): string {\n const date = new Date().toISOString().slice(0, 10).replace(/-/g, '')\n const slug = name.toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/(^-|-$)/g, '')\n .slice(0, 40)\n const todayNums = existingIds\n .filter(id => id.startsWith(date + '_'))\n .map(id => parseInt(id.split('_')[1] ?? '0', 10))\n .filter(n => !isNaN(n))\n const next = todayNums.length > 0 ? Math.max(...todayNums) + 1 : 1\n return `${date}_${String(next).padStart(3, '0')}_${slug}`\n}\n\nexport const CaseStore = {\n async create(input: { name: string; tags: string[]; description: string }): Promise<Case> {\n const root = casesRoot()\n await mkdir(root, { recursive: true })\n const existingIds = await readdir(root).catch(() => [])\n const id = generateCaseId(input.name, existingIds)\n const slug = id.split('_').slice(2).join('_')\n const now = new Date().toISOString()\n const tags = input.tags\n\n const dir = caseDir(id)\n await mkdir(path.join(dir, 'evidence'), { recursive: true })\n await mkdir(path.join(dir, 'dossiers'), { recursive: true })\n\n const fm: Record<string, string> = {\n id,\n name: input.name,\n status: 'open',\n created: now,\n updated: now,\n tags: tags.join(','),\n description: input.description,\n slug,\n }\n const body = [\n `# ${input.name}`,\n '',\n `Opened: ${now}`,\n `Status: open`,\n '',\n '## Question',\n '',\n input.description || 'TBD',\n '',\n '## Current Assessment',\n '',\n 'TBD',\n '',\n '## Top Findings',\n '',\n '| Finding | Confidence | Evidence |',\n '|---|---:|---|',\n '',\n '## Next Actions',\n '',\n '- TBD',\n '',\n '## Reports',\n '',\n ].join('\\n')\n await writeFile(path.join(dir, 'case.md'), serializeFrontmatter(fm, body), { mode: 0o600 })\n\n const manifest = JSON.stringify({ caseId: id, entries: [] }, null, 2) + '\\n'\n await writeFile(path.join(dir, 'manifest.json'), manifest, { mode: 0o600 })\n\n return CaseSchema.parse({ id, name: input.name, status: 'open', created: now, updated: now, tags, description: input.description, slug })\n },\n\n async setStatus(id: string, status: CaseStatus): Promise<Case> {\n const dir = caseDir(id)\n const filePath = path.join(dir, 'case.md')\n const raw = await readFile(filePath, 'utf8')\n const { frontmatter, body } = parseFrontmatter(raw)\n const now = new Date().toISOString()\n frontmatter['status'] = status\n frontmatter['updated'] = now\n await writeFile(filePath, serializeFrontmatter(frontmatter, body), { mode: 0o600 })\n\n const tags = (frontmatter['tags'] ?? '').split(',').filter(Boolean)\n return CaseSchema.parse({\n id,\n name: frontmatter['name'] ?? '',\n status,\n created: frontmatter['created'] ?? now,\n updated: now,\n tags,\n description: frontmatter['description'] ?? '',\n })\n },\n\n async list(): Promise<Array<{ id: string; name: string; status: string }>> {\n const root = casesRoot()\n try {\n const ids = await readdir(root)\n const cases: Array<{ id: string; name: string; status: string; created: string }> = []\n for (const id of ids) {\n try {\n const raw = await readFile(path.join(caseDir(id), 'case.md'), 'utf8')\n const { frontmatter } = parseFrontmatter(raw)\n cases.push({\n id,\n name: frontmatter['name'] ?? id,\n status: frontmatter['status'] ?? 'open',\n created: frontmatter['created'] ?? '',\n })\n } catch (err: unknown) {\n const nodeErr = err as NodeJS.ErrnoException\n if (nodeErr.code !== 'ENOENT' && nodeErr.code !== 'ENOTDIR') throw err\n }\n }\n return cases\n .sort((a, b) => b.created.localeCompare(a.created) || b.id.localeCompare(a.id))\n .map(({ id, name, status }) => ({ id, name, status }))\n } catch (err: unknown) {\n const nodeErr = err as NodeJS.ErrnoException\n if (nodeErr.code === 'ENOENT') return []\n throw err\n }\n },\n\n async get(id: string): Promise<Case> {\n const dir = caseDir(id)\n const raw = await readFile(path.join(dir, 'case.md'), 'utf8')\n const { frontmatter } = parseFrontmatter(raw)\n const tags = (frontmatter['tags'] ?? '').split(',').filter(Boolean)\n return CaseSchema.parse({\n id,\n name: frontmatter['name'] ?? '',\n status: frontmatter['status'] ?? 'open',\n created: frontmatter['created'] ?? new Date().toISOString(),\n updated: frontmatter['updated'] ?? new Date().toISOString(),\n tags,\n description: frontmatter['description'] ?? '',\n })\n },\n\n async loadContext(id: string): Promise<{\n case: { id: string; name: string; status: string; created: string; updated: string; tags: string[] };\n lastSession: { sessionId: string; startTime: string; endTime?: string; body: string } | null;\n dossierSummaries: Array<{ address: string; type: string; riskTags: string; firstSeen: string; lastSeen: string }>;\n evidenceCount: number;\n }> {\n const dir = caseDir(id)\n\n // Read case.md\n const raw = await readFile(path.join(dir, 'case.md'), 'utf8')\n const { frontmatter } = parseFrontmatter(raw)\n const tags = (frontmatter['tags'] ?? '').split(',').filter(Boolean)\n\n // Lazy imports to avoid circular deps\n const { SessionStore } = await import('./session.js')\n const { DossierStore } = await import('./dossier.js')\n\n const [latestSession, dossierSummaries, manifest] = await Promise.all([\n SessionStore.getLatest(id),\n DossierStore.listSummaries(id),\n readFile(path.join(dir, 'manifest.json'), 'utf8').catch(() => '{\"entries\":[]}'),\n ])\n\n const manifestData = JSON.parse(manifest) as { entries: unknown[] }\n const evidenceCount = manifestData.entries.length\n\n const lastSession = latestSession\n ? {\n sessionId: latestSession.frontmatter['sessionId'] ?? '',\n startTime: latestSession.frontmatter['startTime'] ?? '',\n endTime: latestSession.frontmatter['endTime'] || undefined,\n body: latestSession.body,\n }\n : null\n\n return {\n case: {\n id,\n name: frontmatter['name'] ?? '',\n status: frontmatter['status'] ?? 'open',\n created: frontmatter['created'] ?? '',\n updated: frontmatter['updated'] ?? '',\n tags,\n },\n lastSession,\n dossierSummaries,\n evidenceCount,\n }\n },\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"store-C2B_AssI.mjs","names":["nodeErr"],"sources":["../src/cases/schema.ts","../src/cases/store.ts"],"sourcesContent":["import * as z from 'zod'\n\n// Case ID format: YYYYMMDD_NNN_slug (e.g. 20260511_001_tornado-mixer)\n// Regex rejects path traversal chars (../, shell chars) per T-03-01 threat model.\nconst caseIdRegex = /^\\d{8}_\\d{3}_[a-z0-9][a-z0-9-]*$/\n\nexport const CaseStatusEnum = z.enum(['open', 'active', 'suspended', 'closed'])\nexport type CaseStatus = z.infer<typeof CaseStatusEnum>\n\nexport const CaseSchema = z.object({\n id: z.string().regex(caseIdRegex, 'Invalid case ID format'),\n name: z.string().min(1).max(200),\n status: CaseStatusEnum.default('open'),\n created: z.string().datetime(),\n updated: z.string().datetime(),\n tags: z.array(z.string()).default([]),\n description: z.string().default(''),\n slug: z.string().optional(),\n})\nexport type Case = z.infer<typeof CaseSchema>\n\nexport const EvidenceSchema = z.object({\n id: z.string().min(1),\n caseId: z.string().regex(caseIdRegex),\n source: z.string().min(1),\n timestamp: z.string().datetime(),\n queryParams: z.string().default(''),\n})\nexport type Evidence = z.infer<typeof EvidenceSchema>\n\nexport const DossierSchema = z.object({\n address: z.string().min(1).max(100),\n type: z.enum(['eoa', 'contract', 'exchange', 'mixer', 'unknown']).default('unknown'),\n firstSeen: z.string().datetime(),\n lastSeen: z.string().datetime(),\n riskTags: z.string().default(''),\n})\nexport type Dossier = z.infer<typeof DossierSchema>\n\nexport const SessionSchema = z.object({\n sessionId: z.string().min(1),\n caseId: z.string().regex(caseIdRegex),\n startTime: z.string().datetime(),\n endTime: z.string().optional(),\n status: z.enum(['active', 'ended']).default('active'),\n})\nexport type Session = z.infer<typeof SessionSchema>\n","import { readFile, writeFile, mkdir, readdir } from 'node:fs/promises'\nimport path from 'node:path'\nimport { workspaceOutputPaths } from '../workspace/output-root.js'\nimport { parseFrontmatter, serializeFrontmatter } from './frontmatter.js'\nimport { CaseSchema, type Case, type CaseStatus } from './schema.js'\n\nexport const casesRoot = () => workspaceOutputPaths().casesRoot\n\nfunction caseDir(id: string): string {\n return path.join(casesRoot(), id)\n}\n\nexport function generateCaseId(name: string, existingIds: string[]): string {\n const date = new Date().toISOString().slice(0, 10).replace(/-/g, '')\n const slug = name.toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/(^-|-$)/g, '')\n .slice(0, 40)\n const todayNums = existingIds\n .filter(id => id.startsWith(date + '_'))\n .map(id => parseInt(id.split('_')[1] ?? '0', 10))\n .filter(n => !isNaN(n))\n const next = todayNums.length > 0 ? Math.max(...todayNums) + 1 : 1\n return `${date}_${String(next).padStart(3, '0')}_${slug}`\n}\n\nexport const CaseStore = {\n async create(input: { name: string; tags: string[]; description: string }): Promise<Case> {\n const root = casesRoot()\n await mkdir(root, { recursive: true })\n const existingIds = await readdir(root).catch(() => [])\n const id = generateCaseId(input.name, existingIds)\n const slug = id.split('_').slice(2).join('_')\n const now = new Date().toISOString()\n const tags = input.tags\n\n const dir = caseDir(id)\n await mkdir(path.join(dir, 'evidence'), { recursive: true })\n await mkdir(path.join(dir, 'dossiers'), { recursive: true })\n\n const fm: Record<string, string> = {\n id,\n name: input.name,\n status: 'open',\n created: now,\n updated: now,\n tags: tags.join(','),\n description: input.description,\n slug,\n }\n const body = [\n `# ${input.name}`,\n '',\n `Opened: ${now}`,\n `Status: open`,\n '',\n '## Question',\n '',\n input.description || 'TBD',\n '',\n '## Current Assessment',\n '',\n 'TBD',\n '',\n '## Top Findings',\n '',\n '| Finding | Confidence | Evidence |',\n '|---|---:|---|',\n '',\n '## Next Actions',\n '',\n '- TBD',\n '',\n '## Reports',\n '',\n ].join('\\n')\n await writeFile(path.join(dir, 'case.md'), serializeFrontmatter(fm, body), { mode: 0o600 })\n\n const manifest = JSON.stringify({ caseId: id, entries: [] }, null, 2) + '\\n'\n await writeFile(path.join(dir, 'manifest.json'), manifest, { mode: 0o600 })\n\n return CaseSchema.parse({ id, name: input.name, status: 'open', created: now, updated: now, tags, description: input.description, slug })\n },\n\n async setStatus(id: string, status: CaseStatus): Promise<Case> {\n const dir = caseDir(id)\n const filePath = path.join(dir, 'case.md')\n const raw = await readFile(filePath, 'utf8')\n const { frontmatter, body } = parseFrontmatter(raw)\n const now = new Date().toISOString()\n frontmatter['status'] = status\n frontmatter['updated'] = now\n await writeFile(filePath, serializeFrontmatter(frontmatter, body), { mode: 0o600 })\n\n const tags = (frontmatter['tags'] ?? '').split(',').filter(Boolean)\n return CaseSchema.parse({\n id,\n name: frontmatter['name'] ?? '',\n status,\n created: frontmatter['created'] ?? now,\n updated: now,\n tags,\n description: frontmatter['description'] ?? '',\n })\n },\n\n async list(): Promise<Array<{ id: string; name: string; status: string }>> {\n const root = casesRoot()\n try {\n const ids = await readdir(root)\n const cases: Array<{ id: string; name: string; status: string; created: string }> = []\n for (const id of ids) {\n try {\n const raw = await readFile(path.join(caseDir(id), 'case.md'), 'utf8')\n const { frontmatter } = parseFrontmatter(raw)\n cases.push({\n id,\n name: frontmatter['name'] ?? id,\n status: frontmatter['status'] ?? 'open',\n created: frontmatter['created'] ?? '',\n })\n } catch (err: unknown) {\n const nodeErr = err as NodeJS.ErrnoException\n if (nodeErr.code !== 'ENOENT' && nodeErr.code !== 'ENOTDIR') throw err\n }\n }\n return cases\n .sort((a, b) => b.created.localeCompare(a.created) || b.id.localeCompare(a.id))\n .map(({ id, name, status }) => ({ id, name, status }))\n } catch (err: unknown) {\n const nodeErr = err as NodeJS.ErrnoException\n if (nodeErr.code === 'ENOENT') return []\n throw err\n }\n },\n\n async get(id: string): Promise<Case> {\n const dir = caseDir(id)\n const raw = await readFile(path.join(dir, 'case.md'), 'utf8')\n const { frontmatter } = parseFrontmatter(raw)\n const tags = (frontmatter['tags'] ?? '').split(',').filter(Boolean)\n return CaseSchema.parse({\n id,\n name: frontmatter['name'] ?? '',\n status: frontmatter['status'] ?? 'open',\n created: frontmatter['created'] ?? new Date().toISOString(),\n updated: frontmatter['updated'] ?? new Date().toISOString(),\n tags,\n description: frontmatter['description'] ?? '',\n })\n },\n\n async loadContext(id: string): Promise<{\n case: { id: string; name: string; status: string; created: string; updated: string; tags: string[] };\n lastSession: { sessionId: string; startTime: string; endTime?: string; body: string } | null;\n dossierSummaries: Array<{ address: string; type: string; riskTags: string; firstSeen: string; lastSeen: string }>;\n evidenceCount: number;\n }> {\n const dir = caseDir(id)\n\n // Read case.md\n const raw = await readFile(path.join(dir, 'case.md'), 'utf8')\n const { frontmatter } = parseFrontmatter(raw)\n const tags = (frontmatter['tags'] ?? '').split(',').filter(Boolean)\n\n // Lazy imports to avoid circular deps\n const { SessionStore } = await import('./session.js')\n const { DossierStore } = await import('./dossier.js')\n\n const [latestSession, dossierSummaries, manifest] = await Promise.all([\n SessionStore.getLatest(id),\n DossierStore.listSummaries(id),\n readFile(path.join(dir, 'manifest.json'), 'utf8').catch(() => '{\"entries\":[]}'),\n ])\n\n const manifestData = JSON.parse(manifest) as { entries: unknown[] }\n const evidenceCount = manifestData.entries.length\n\n const lastSession = latestSession\n ? {\n sessionId: latestSession.frontmatter['sessionId'] ?? '',\n startTime: latestSession.frontmatter['startTime'] ?? '',\n endTime: latestSession.frontmatter['endTime'] || undefined,\n body: latestSession.body,\n }\n : null\n\n return {\n case: {\n id,\n name: frontmatter['name'] ?? '',\n status: frontmatter['status'] ?? 'open',\n created: frontmatter['created'] ?? '',\n updated: frontmatter['updated'] ?? '',\n tags,\n },\n lastSession,\n dossierSummaries,\n evidenceCount,\n }\n },\n}\n"],"mappings":"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"}
@@ -228,30 +228,12 @@ const CaseStore = {
228
228
  }
229
229
  };
230
230
  //#endregion
231
- Object.defineProperty(exports, "CaseSchema", {
232
- enumerable: true,
233
- get: function() {
234
- return CaseSchema;
235
- }
236
- });
237
- Object.defineProperty(exports, "CaseStatusEnum", {
238
- enumerable: true,
239
- get: function() {
240
- return CaseStatusEnum;
241
- }
242
- });
243
231
  Object.defineProperty(exports, "CaseStore", {
244
232
  enumerable: true,
245
233
  get: function() {
246
234
  return CaseStore;
247
235
  }
248
236
  });
249
- Object.defineProperty(exports, "generateCaseId", {
250
- enumerable: true,
251
- get: function() {
252
- return generateCaseId;
253
- }
254
- });
255
237
  Object.defineProperty(exports, "store_exports", {
256
238
  enumerable: true,
257
239
  get: function() {