@datasynx/agentic-ai-cartography 0.2.5 → 0.2.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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/exporter.ts"],"sourcesContent":["import { mkdirSync, writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport type { CartographyDB } from './db.js';\nimport type { NodeRow, EdgeRow, SOP } from './types.js';\n\n// ── Layer assignment ─────────────────────────────────────────────────────────\n\nfunction nodeLayer(type: string): string {\n if (type === 'saas_tool') return 'saas';\n if (['web_service', 'api_endpoint'].includes(type)) return 'web';\n if (['database_server', 'database', 'table', 'cache_server'].includes(type)) return 'data';\n if (['message_broker', 'queue', 'topic'].includes(type)) return 'messaging';\n if (['host', 'container', 'pod', 'k8s_cluster'].includes(type)) return 'infra';\n if (type === 'config_file') return 'config';\n return 'other';\n}\n\nconst LAYER_LABELS: Record<string, string> = {\n saas: '☁ SaaS Tools',\n web: '🌐 Web / API',\n data: '🗄 Data Layer',\n messaging: '📨 Messaging',\n infra: '🖥 Infrastructure',\n config: '📄 Config',\n other: '❓ Other',\n};\n\nconst LAYER_ORDER = ['saas', 'web', 'data', 'messaging', 'infra', 'config', 'other'];\n\n// ── Icons & Labels ───────────────────────────────────────────────────────────\n\nconst MERMAID_ICONS: Record<string, string> = {\n host: '🖥',\n database_server: '🗄',\n database: '🗄',\n table: '📋',\n web_service: '🌐',\n api_endpoint: '🔌',\n cache_server: '⚡',\n message_broker: '📨',\n queue: '📬',\n topic: '📢',\n container: '📦',\n pod: '☸',\n k8s_cluster: '☸',\n config_file: '📄',\n saas_tool: '☁',\n unknown: '❓',\n};\n\nconst EDGE_LABELS: Record<string, string> = {\n connects_to: '→',\n reads_from: 'reads',\n writes_to: 'writes',\n calls: 'calls',\n contains: 'contains',\n depends_on: 'depends on',\n};\n\n// Class colors per type (dark-theme friendly)\nconst MERMAID_CLASSES: Record<string, string> = {\n host: 'fill:#1e3352,stroke:#4a82c4,color:#cce',\n database_server:'fill:#1e3352,stroke:#4a82c4,color:#cce',\n database: 'fill:#163352,stroke:#3a8ad4,color:#bdf',\n table: 'fill:#0f2a40,stroke:#2a6090,color:#9bd',\n web_service: 'fill:#1a3a1a,stroke:#3a9a3a,color:#bfb',\n api_endpoint: 'fill:#0f2a0f,stroke:#2a7a2a,color:#9d9',\n cache_server: 'fill:#3a2a0a,stroke:#ca8a0a,color:#fda',\n message_broker: 'fill:#2a1a3a,stroke:#7a3aaa,color:#daf',\n queue: 'fill:#1f1030,stroke:#5a2a8a,color:#caf',\n topic: 'fill:#1f1030,stroke:#5a2a8a,color:#caf',\n container: 'fill:#1a2a3a,stroke:#3a6a9a,color:#acd',\n pod: 'fill:#0f1f2f,stroke:#2a5a8a,color:#8bc',\n k8s_cluster: 'fill:#0a1520,stroke:#1a4a7a,color:#7ab',\n config_file: 'fill:#2a2a1a,stroke:#7a7a2a,color:#ddc',\n saas_tool: 'fill:#2a1a2a,stroke:#9a3a9a,color:#daf',\n unknown: 'fill:#2a2a2a,stroke:#5a5a5a,color:#aaa',\n};\n\n// ── Mermaid ──────────────────────────────────────────────────────────────────\n\nfunction sanitize(id: string): string {\n return id.replace(/[^a-zA-Z0-9_]/g, '_');\n}\n\nfunction nodeLabel(node: NodeRow): string {\n const icon = MERMAID_ICONS[node.type] ?? '?';\n const parts = node.id.split(':');\n const location = parts.length >= 3 ? `${parts[1]}:${parts[2]}` : parts[1] ?? '';\n const conf = `${Math.round(node.confidence * 100)}%`;\n\n // Pull 1-2 key metadata fields (no credentials)\n const meta = node.metadata as Record<string, unknown>;\n const extras: string[] = [];\n for (const key of ['category', 'version', 'description']) {\n const v = meta[key];\n if (typeof v === 'string' && v.length > 0) {\n extras.push(v.substring(0, 28));\n break; // max 1 extra line for readability\n }\n }\n\n const locLine = location ? `<br/><small>${location}</small>` : '';\n const extraLine = extras.length ? `<br/><small>${extras[0]}</small>` : '';\n return `[\"${icon} <b>${node.name}</b>${locLine}${extraLine}<br/><small>${node.type} · ${conf}</small>\"]`;\n}\n\nexport function generateTopologyMermaid(nodes: NodeRow[], edges: EdgeRow[]): string {\n if (nodes.length === 0) return 'graph TB\\n empty[\"No nodes discovered yet\"]';\n\n const lines: string[] = ['graph TB'];\n\n // classDef per used type\n const usedTypes = new Set(nodes.map(n => n.type));\n for (const type of usedTypes) {\n const style = MERMAID_CLASSES[type] ?? MERMAID_CLASSES['unknown']!;\n lines.push(` classDef ${type.replace(/_/g, '')} ${style}`);\n }\n lines.push('');\n\n // Group by semantic layer (ordered top→bottom)\n const layerMap = new Map<string, NodeRow[]>();\n for (const node of nodes) {\n const layer = nodeLayer(node.type);\n if (!layerMap.has(layer)) layerMap.set(layer, []);\n layerMap.get(layer)!.push(node);\n }\n\n for (const layerKey of LAYER_ORDER) {\n const layerNodes = layerMap.get(layerKey);\n if (!layerNodes || layerNodes.length === 0) continue;\n const label = LAYER_LABELS[layerKey] ?? layerKey;\n lines.push(` subgraph ${layerKey}[\"${label}\"]`);\n for (const node of layerNodes) {\n lines.push(` ${sanitize(node.id)}${nodeLabel(node)}:::${node.type.replace(/_/g, '')}`);\n }\n lines.push(' end');\n lines.push('');\n }\n\n // Edges: dashed for low-confidence (<0.6), solid otherwise\n for (const edge of edges) {\n const src = sanitize(edge.sourceId);\n const tgt = sanitize(edge.targetId);\n const label = EDGE_LABELS[edge.relationship] ?? edge.relationship;\n const arrow = edge.confidence < 0.6 ? `-. \"${label}\" .->` : `-->|\"${label}\"|`;\n lines.push(` ${src} ${arrow} ${tgt}`);\n }\n\n return lines.join('\\n');\n}\n\nexport function generateDependencyMermaid(nodes: NodeRow[], edges: EdgeRow[]): string {\n const depEdges = edges.filter(e =>\n ['calls', 'reads_from', 'writes_to', 'depends_on'].includes(e.relationship)\n );\n\n if (depEdges.length === 0) return 'graph LR\\n empty[\"No dependency edges found\"]';\n\n const lines: string[] = ['graph LR'];\n\n const usedIds = new Set<string>();\n for (const edge of depEdges) {\n usedIds.add(edge.sourceId);\n usedIds.add(edge.targetId);\n }\n\n const usedNodes = nodes.filter(n => usedIds.has(n.id));\n const usedTypes = new Set(usedNodes.map(n => n.type));\n for (const type of usedTypes) {\n const style = MERMAID_CLASSES[type] ?? MERMAID_CLASSES['unknown']!;\n lines.push(` classDef ${type.replace(/_/g, '')} ${style}`);\n }\n lines.push('');\n\n for (const node of usedNodes) {\n lines.push(` ${sanitize(node.id)}${nodeLabel(node)}:::${node.type.replace(/_/g, '')}`);\n }\n lines.push('');\n\n for (const edge of depEdges) {\n const label = EDGE_LABELS[edge.relationship] ?? edge.relationship;\n lines.push(` ${sanitize(edge.sourceId)} -->|\"${label}\"| ${sanitize(edge.targetId)}`);\n }\n\n return lines.join('\\n');\n}\n\nexport function generateWorkflowMermaid(sop: SOP): string {\n const lines: string[] = ['flowchart TD'];\n\n for (const step of sop.steps) {\n const nodeId = `S${step.order}`;\n const label = `${step.order}. ${step.instruction.substring(0, 60)}`;\n lines.push(` ${nodeId}[\"${label}\"]`);\n\n if (step.order > 1) {\n lines.push(` S${step.order - 1} --> ${nodeId}`);\n }\n }\n\n return lines.join('\\n');\n}\n\n// ── Backstage YAML ───────────────────────────────────────────────────────────\n\nexport function exportBackstageYAML(nodes: NodeRow[], edges: EdgeRow[], org?: string): string {\n const owner = org ?? 'unknown';\n const docs: string[] = [];\n\n for (const node of nodes) {\n const isComponent = ['web_service', 'container', 'pod'].includes(node.type);\n const isAPI = node.type === 'api_endpoint';\n const kind = isComponent ? 'Component' : isAPI ? 'API' : 'Resource';\n\n const deps = edges\n .filter(e => e.sourceId === node.id)\n .map(e => ` - resource:default/${sanitize(e.targetId)}`);\n\n const doc = [\n `apiVersion: backstage.io/v1alpha1`,\n `kind: ${kind}`,\n `metadata:`,\n ` name: ${sanitize(node.id)}`,\n ` annotations:`,\n ` cartography/discovered-at: \"${node.discoveredAt}\"`,\n ` cartography/confidence: \"${node.confidence}\"`,\n `spec:`,\n ` type: ${node.type}`,\n ` lifecycle: production`,\n ` owner: ${owner}`,\n ...(deps.length > 0 ? [' dependsOn:', ...deps] : []),\n ].join('\\n');\n\n docs.push(doc);\n }\n\n return docs.join('\\n---\\n');\n}\n\n// ── JSON ─────────────────────────────────────────────────────────────────────\n\nexport function exportJSON(db: CartographyDB, sessionId: string): string {\n const nodes = db.getNodes(sessionId);\n const edges = db.getEdges(sessionId);\n const events = db.getEvents(sessionId);\n const tasks = db.getTasks(sessionId);\n const sops = db.getSOPs(sessionId);\n const stats = db.getStats(sessionId);\n\n return JSON.stringify({\n sessionId,\n exportedAt: new Date().toISOString(),\n stats,\n nodes,\n edges,\n events,\n tasks,\n sops,\n }, null, 2);\n}\n\n// ── HTML (D3.js Hexagonal Cartography Map) ────────────────────────────────────\n\nexport function exportHTML(nodes: NodeRow[], edges: EdgeRow[]): string {\n const graphData = JSON.stringify({\n nodes: nodes.map(n => ({\n id: n.id,\n name: n.name,\n type: n.type,\n layer: nodeLayer(n.type),\n confidence: n.confidence,\n discoveredVia: n.discoveredVia,\n discoveredAt: n.discoveredAt,\n tags: n.tags,\n metadata: n.metadata,\n })),\n links: edges.map(e => ({\n source: e.sourceId,\n target: e.targetId,\n relationship: e.relationship,\n confidence: e.confidence,\n evidence: e.evidence,\n })),\n });\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <title>Cartography — Infrastructure Map</title>\n <script src=\"https://d3js.org/d3.v7.min.js\"></script>\n <style>\n * { box-sizing: border-box; margin: 0; padding: 0; }\n body { background: #0a0e14; color: #e6edf3; font-family: 'SF Mono','Fira Code','Cascadia Code',monospace; display: flex; overflow: hidden; height: 100vh; }\n\n /* ── Left node panel ─────────────────────────────── */\n #node-panel {\n width: 220px; min-width: 220px; height: 100vh; overflow: hidden;\n background: #0d1117; border-right: 1px solid #1b2028;\n display: flex; flex-direction: column;\n }\n #node-panel-header {\n padding: 10px 12px 8px; border-bottom: 1px solid #1b2028;\n font-size: 11px; color: #6e7681; text-transform: uppercase; letter-spacing: 0.6px;\n }\n #node-search {\n width: calc(100% - 16px); margin: 8px; padding: 5px 8px;\n background: #161b22; border: 1px solid #30363d; border-radius: 5px;\n color: #e6edf3; font-size: 11px; font-family: inherit; outline: none;\n }\n #node-search:focus { border-color: #58a6ff; }\n #node-list { flex: 1; overflow-y: auto; padding-bottom: 8px; }\n .node-list-item {\n padding: 5px 12px; cursor: pointer; font-size: 11px;\n display: flex; align-items: center; gap: 6px; border-left: 2px solid transparent;\n }\n .node-list-item:hover { background: #161b22; }\n .node-list-item.active { background: #1a2436; border-left-color: #58a6ff; }\n .node-list-dot { width: 7px; height: 7px; border-radius: 2px; flex-shrink: 0; }\n .node-list-name { color: #c9d1d9; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1; }\n .node-list-type { color: #484f58; font-size: 9px; flex-shrink: 0; }\n\n /* ── Center graph ────────────────────────────────── */\n #graph { flex: 1; height: 100vh; position: relative; }\n svg { width: 100%; height: 100%; }\n .hull { opacity: 0.12; stroke-width: 1.5; stroke-opacity: 0.25; }\n .hull-label { font-size: 13px; font-weight: 700; letter-spacing: 1px; text-transform: uppercase; fill-opacity: 0.5; pointer-events: none; }\n .link { stroke-opacity: 0.4; }\n .link-label { font-size: 8px; fill: #6e7681; pointer-events: none; opacity: 0; }\n .node-hex { stroke-width: 1.8; cursor: pointer; transition: opacity 0.15s; }\n .node-hex:hover { filter: brightness(1.3); stroke-width: 3; }\n .node-hex.selected { stroke-width: 3.5; filter: brightness(1.5); }\n .node-label { font-size: 10px; fill: #c9d1d9; pointer-events: none; opacity: 0; }\n\n /* ── Right sidebar ───────────────────────────────── */\n #sidebar {\n width: 300px; min-width: 300px; height: 100vh; overflow-y: auto;\n background: #0d1117; border-left: 1px solid #1b2028;\n padding: 16px; font-size: 12px; line-height: 1.6;\n }\n #sidebar h2 { margin: 0 0 8px; font-size: 14px; color: #58a6ff; }\n #sidebar .meta-table { width: 100%; border-collapse: collapse; }\n #sidebar .meta-table td { padding: 3px 6px; border-bottom: 1px solid #161b22; vertical-align: top; }\n #sidebar .meta-table td:first-child { color: #6e7681; white-space: nowrap; width: 90px; }\n #sidebar .tag { display: inline-block; background: #161b22; border-radius: 3px; padding: 1px 5px; margin: 1px; font-size: 10px; }\n #sidebar .conf-bar { height: 5px; border-radius: 3px; background: #161b22; margin-top: 3px; }\n #sidebar .conf-fill { height: 100%; border-radius: 3px; }\n #sidebar .edges-list { margin-top: 12px; }\n #sidebar .edge-item { padding: 4px 0; border-bottom: 1px solid #161b22; color: #6e7681; font-size: 11px; }\n #sidebar .edge-item span { color: #c9d1d9; }\n #sidebar .action-row { display: flex; gap: 6px; margin-top: 14px; }\n .btn-delete {\n flex: 1; padding: 6px 10px; background: transparent; border: 1px solid #6e191d;\n color: #f85149; border-radius: 5px; font-size: 11px; font-family: inherit;\n cursor: pointer; text-align: center;\n }\n .btn-delete:hover { background: #3d0c0c; }\n .hint { color: #3d434b; font-size: 11px; margin-top: 8px; }\n\n /* ── HUD ─────────────────────────────────────────── */\n #hud { position: absolute; top: 10px; left: 10px; background: rgba(10,14,20,0.88);\n padding: 10px 14px; border-radius: 8px; font-size: 12px; border: 1px solid #1b2028; pointer-events: none; }\n #hud strong { color: #58a6ff; }\n #hud .stats { color: #6e7681; }\n #hud .zoom-level { color: #3d434b; font-size: 10px; margin-top: 2px; }\n\n /* ── Toolbar (filters + JGF export) ─────────────── */\n #toolbar { position: absolute; top: 10px; right: 10px; display: flex; flex-wrap: wrap; gap: 4px; pointer-events: auto; align-items: center; }\n .filter-btn {\n background: rgba(10,14,20,0.85); border: 1px solid #1b2028; border-radius: 6px;\n color: #c9d1d9; padding: 4px 10px; font-size: 11px; cursor: pointer;\n font-family: inherit; display: flex; align-items: center; gap: 5px;\n }\n .filter-btn:hover { border-color: #30363d; }\n .filter-btn.off { opacity: 0.35; }\n .filter-dot { width: 8px; height: 8px; border-radius: 2px; display: inline-block; }\n .export-btn {\n background: rgba(10,14,20,0.85); border: 1px solid #1b2028; border-radius: 6px;\n color: #58a6ff; padding: 4px 12px; font-size: 11px; cursor: pointer;\n font-family: inherit;\n }\n .export-btn:hover { border-color: #58a6ff; background: rgba(88,166,255,0.08); }\n </style>\n</head>\n<body>\n\n<!-- Left: node list panel -->\n<div id=\"node-panel\">\n <div id=\"node-panel-header\">Nodes (${nodes.length})</div>\n <input id=\"node-search\" type=\"text\" placeholder=\"Search nodes…\" autocomplete=\"off\" spellcheck=\"false\">\n <div id=\"node-list\"></div>\n</div>\n\n<!-- Center: graph -->\n<div id=\"graph\">\n <div id=\"hud\">\n <strong>Cartography</strong> &nbsp;\n <span class=\"stats\" id=\"hud-stats\">${nodes.length} nodes · ${edges.length} edges</span><br>\n <span class=\"zoom-level\">Scroll = zoom · Drag = pan · Click = details</span>\n </div>\n <div id=\"toolbar\"></div>\n <svg></svg>\n</div>\n\n<!-- Right: detail sidebar -->\n<div id=\"sidebar\">\n <h2>Infrastructure Map</h2>\n <p class=\"hint\">Click a node to view details.</p>\n</div>\n\n<script>\nconst data = ${graphData};\n\n// ── Color palette per node type ───────────────────────────────────────────\nconst TYPE_COLORS = {\n host: '#4a9eff', database_server: '#ff6b6b', database: '#ff8c42',\n web_service: '#6bcb77', api_endpoint: '#4d96ff', cache_server: '#ffd93d',\n message_broker: '#c77dff', queue: '#e0aaff', topic: '#9d4edd',\n container: '#48cae4', pod: '#00b4d8', k8s_cluster: '#0077b6',\n config_file: '#adb5bd', saas_tool: '#c084fc', table: '#f97316', unknown: '#6c757d',\n};\n\nconst LAYER_COLORS = {\n saas: '#c084fc', web: '#6bcb77', data: '#ff6b6b',\n messaging: '#c77dff', infra: '#4a9eff', config: '#adb5bd', other: '#6c757d',\n};\nconst LAYER_NAMES = {\n saas: 'SaaS Tools', web: 'Web / API', data: 'Data Layer',\n messaging: 'Messaging', infra: 'Infrastructure', config: 'Config', other: 'Other',\n};\n\n// ── Hexagon path ──────────────────────────────────────────────────────────\nconst HEX_SIZE = { saas_tool: 16, host: 18, database_server: 18, k8s_cluster: 20, default: 14 };\nfunction hexSize(d) { return HEX_SIZE[d.type] || HEX_SIZE.default; }\nfunction hexPath(size) {\n const pts = [];\n for (let i = 0; i < 6; i++) {\n const angle = (Math.PI / 3) * i - Math.PI / 6;\n pts.push([size * Math.cos(angle), size * Math.sin(angle)]);\n }\n return 'M' + pts.map(p => p.join(',')).join('L') + 'Z';\n}\n\n// ── Left panel ────────────────────────────────────────────────────────────\nconst nodeListEl = document.getElementById('node-list');\nconst nodeSearchEl = document.getElementById('node-search');\nlet selectedNodeId = null;\n\nfunction buildNodeList(filter) {\n const q = (filter || '').toLowerCase();\n nodeListEl.innerHTML = '';\n const sorted = [...data.nodes].sort((a, b) => a.name.localeCompare(b.name));\n for (const d of sorted) {\n if (q && !d.name.toLowerCase().includes(q) && !d.type.includes(q) && !d.id.toLowerCase().includes(q)) continue;\n const item = document.createElement('div');\n item.className = 'node-list-item' + (d.id === selectedNodeId ? ' active' : '');\n item.dataset.id = d.id;\n const color = TYPE_COLORS[d.type] || '#aaa';\n item.innerHTML = \\`<span class=\"node-list-dot\" style=\"background:\\${color}\"></span>\n <span class=\"node-list-name\" title=\"\\${d.id}\">\\${d.name}</span>\n <span class=\"node-list-type\">\\${d.type.replace(/_/g,' ')}</span>\\`;\n item.onclick = () => { selectNode(d); focusNode(d); };\n nodeListEl.appendChild(item);\n }\n}\n\nnodeSearchEl.addEventListener('input', e => buildNodeList(e.target.value));\n\n// ── Sidebar detail view ───────────────────────────────────────────────────\nconst sidebar = document.getElementById('sidebar');\n\nfunction selectNode(d) {\n selectedNodeId = d.id;\n buildNodeList(nodeSearchEl.value);\n showNode(d);\n // highlight hex\n d3.selectAll('.node-hex').classed('selected', nd => nd.id === d.id);\n}\n\nfunction showNode(d) {\n const c = TYPE_COLORS[d.type] || '#aaa';\n const confPct = Math.round(d.confidence * 100);\n const tags = (d.tags || []).map(t => \\`<span class=\"tag\">\\${t}</span>\\`).join('');\n const metaRows = Object.entries(d.metadata || {})\n .filter(([,v]) => v !== null && v !== undefined && String(v).length > 0)\n .map(([k,v]) => \\`<tr><td>\\${k}</td><td>\\${JSON.stringify(v)}</td></tr>\\`)\n .join('');\n const related = data.links.filter(l =>\n (l.source.id||l.source) === d.id || (l.target.id||l.target) === d.id\n );\n const edgeItems = related.map(l => {\n const isOut = (l.source.id||l.source) === d.id;\n const other = isOut ? (l.target.id||l.target) : (l.source.id||l.source);\n return \\`<div class=\"edge-item\">\\${isOut ? '→' : '←'} <span>\\${other}</span> <small>[\\${l.relationship}]</small></div>\\`;\n }).join('');\n\n sidebar.innerHTML = \\`\n <h2>\\${d.name}</h2>\n <table class=\"meta-table\">\n <tr><td>ID</td><td style=\"font-size:10px;word-break:break-all\">\\${d.id}</td></tr>\n <tr><td>Type</td><td><span style=\"color:\\${c}\">\\${d.type}</span></td></tr>\n <tr><td>Layer</td><td>\\${d.layer}</td></tr>\n <tr><td>Confidence</td><td>\n \\${confPct}%\n <div class=\"conf-bar\"><div class=\"conf-fill\" style=\"width:\\${confPct}%;background:\\${c}\"></div></div>\n </td></tr>\n <tr><td>Discovered via</td><td>\\${d.discoveredVia || '—'}</td></tr>\n <tr><td>Timestamp</td><td>\\${d.discoveredAt ? d.discoveredAt.substring(0,19).replace('T',' ') : '—'}</td></tr>\n \\${tags ? '<tr><td>Tags</td><td>'+tags+'</td></tr>' : ''}\n \\${metaRows}\n </table>\n \\${related.length > 0 ? '<div class=\"edges-list\"><strong>Connections (' + related.length + '):</strong>'+edgeItems+'</div>' : ''}\n <div class=\"action-row\">\n <button class=\"btn-delete\" onclick=\"deleteNode('\\${d.id}')\">🗑 Delete node</button>\n </div>\n \\`;\n}\n\n// ── Delete node ───────────────────────────────────────────────────────────\nfunction deleteNode(id) {\n const idx = data.nodes.findIndex(n => n.id === id);\n if (idx === -1) return;\n data.nodes.splice(idx, 1);\n data.links = data.links.filter(l =>\n (l.source.id || l.source) !== id && (l.target.id || l.target) !== id\n );\n selectedNodeId = null;\n sidebar.innerHTML = '<h2>Infrastructure Map</h2><p class=\"hint\">Node deleted.</p>';\n document.getElementById('hud-stats').textContent =\n data.nodes.length + ' nodes · ' + data.links.length + ' edges';\n rebuildGraph();\n buildNodeList(nodeSearchEl.value);\n}\n\n// ── SVG setup ─────────────────────────────────────────────────────────────\nconst svgEl = d3.select('svg');\nconst graphDiv = document.getElementById('graph');\nconst W = () => graphDiv.clientWidth;\nconst H = () => graphDiv.clientHeight;\nconst g = svgEl.append('g');\n\nsvgEl.append('defs').append('marker')\n .attr('id', 'arrow').attr('viewBox', '0 0 10 6')\n .attr('refX', 10).attr('refY', 3)\n .attr('markerWidth', 8).attr('markerHeight', 6)\n .attr('orient', 'auto')\n .append('path').attr('d', 'M0,0 L10,3 L0,6 Z').attr('fill', '#555');\n\nlet currentZoom = 1;\nconst zoomBehavior = d3.zoom().scaleExtent([0.08, 6]).on('zoom', e => {\n g.attr('transform', e.transform);\n currentZoom = e.transform.k;\n updateLOD(currentZoom);\n});\nsvgEl.call(zoomBehavior);\n\n// ── Layer filter state ────────────────────────────────────────────────────\nconst layers = [...new Set(data.nodes.map(d => d.layer))];\nconst layerVisible = {};\nlayers.forEach(l => layerVisible[l] = true);\n\nconst toolbarEl = document.getElementById('toolbar');\n\n// Filter buttons\nlayers.forEach(layer => {\n const btn = document.createElement('button');\n btn.className = 'filter-btn';\n btn.innerHTML = \\`<span class=\"filter-dot\" style=\"background:\\${LAYER_COLORS[layer]||'#666'}\"></span>\\${LAYER_NAMES[layer]||layer}\\`;\n btn.onclick = () => {\n layerVisible[layer] = !layerVisible[layer];\n btn.classList.toggle('off', !layerVisible[layer]);\n updateVisibility();\n };\n toolbarEl.appendChild(btn);\n});\n\n// JGF export button\nconst jgfBtn = document.createElement('button');\njgfBtn.className = 'export-btn';\njgfBtn.textContent = '↓ JGF';\njgfBtn.title = 'Export JSON Graph Format';\njgfBtn.onclick = exportJGF;\ntoolbarEl.appendChild(jgfBtn);\n\n// ── JGF export ────────────────────────────────────────────────────────────\nfunction exportJGF() {\n const jgf = {\n graph: {\n directed: true,\n type: 'cartography',\n label: 'Infrastructure Map',\n metadata: { exportedAt: new Date().toISOString() },\n nodes: Object.fromEntries(data.nodes.map(n => [n.id, {\n label: n.name,\n metadata: { type: n.type, layer: n.layer, confidence: n.confidence,\n discoveredVia: n.discoveredVia, discoveredAt: n.discoveredAt,\n tags: n.tags, ...n.metadata }\n }])),\n edges: data.links.map(l => ({\n source: l.source.id || l.source,\n target: l.target.id || l.target,\n relation: l.relationship,\n metadata: { confidence: l.confidence, evidence: l.evidence }\n })),\n }\n };\n const blob = new Blob([JSON.stringify(jgf, null, 2)], { type: 'application/json' });\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url; a.download = 'cartography-graph.jgf.json'; a.click();\n URL.revokeObjectURL(url);\n}\n\n// ── Cluster force ─────────────────────────────────────────────────────────\nfunction clusterForce(alpha) {\n const centroids = {};\n const counts = {};\n data.nodes.forEach(d => {\n if (!centroids[d.layer]) { centroids[d.layer] = { x: 0, y: 0 }; counts[d.layer] = 0; }\n centroids[d.layer].x += d.x || 0;\n centroids[d.layer].y += d.y || 0;\n counts[d.layer]++;\n });\n for (const l in centroids) { centroids[l].x /= counts[l]; centroids[l].y /= counts[l]; }\n const strength = alpha * 0.15;\n data.nodes.forEach(d => {\n const c = centroids[d.layer];\n if (c) { d.vx += (c.x - d.x) * strength; d.vy += (c.y - d.y) * strength; }\n });\n}\n\n// ── Hull group ────────────────────────────────────────────────────────────\nconst hullGroup = g.append('g').attr('class', 'hulls');\nconst hullPaths = {};\nconst hullLabels = {};\nlayers.forEach(layer => {\n hullPaths[layer] = hullGroup.append('path').attr('class', 'hull')\n .attr('fill', LAYER_COLORS[layer] || '#666').attr('stroke', LAYER_COLORS[layer] || '#666');\n hullLabels[layer] = hullGroup.append('text').attr('class', 'hull-label')\n .attr('fill', LAYER_COLORS[layer] || '#666').text(LAYER_NAMES[layer] || layer);\n});\n\nfunction updateHulls() {\n layers.forEach(layer => {\n if (!layerVisible[layer]) { hullPaths[layer].attr('d', null); hullLabels[layer].attr('x', -9999); return; }\n const pts = data.nodes.filter(d => d.layer === layer && layerVisible[d.layer]).map(d => [d.x, d.y]);\n if (pts.length < 3) {\n hullPaths[layer].attr('d', null);\n if (pts.length > 0) hullLabels[layer].attr('x', pts[0][0]).attr('y', pts[0][1] - 30);\n else hullLabels[layer].attr('x', -9999);\n return;\n }\n const hull = d3.polygonHull(pts);\n if (!hull) { hullPaths[layer].attr('d', null); return; }\n const cx = d3.mean(hull, p => p[0]);\n const cy = d3.mean(hull, p => p[1]);\n const padded = hull.map(p => {\n const dx = p[0] - cx, dy = p[1] - cy;\n const len = Math.sqrt(dx*dx + dy*dy) || 1;\n return [p[0] + dx/len * 40, p[1] + dy/len * 40];\n });\n hullPaths[layer].attr('d', 'M' + padded.join('L') + 'Z');\n hullLabels[layer].attr('x', cx).attr('y', cy - d3.max(hull, p => Math.abs(p[1] - cy)) - 30);\n });\n}\n\n// ── Graph rendering (rebuildable after delete) ────────────────────────────\nlet linkSel, linkLabelSel, nodeSel, nodeLabelSel, sim;\nconst linkGroup = g.append('g');\nconst nodeGroup = g.append('g');\n\nfunction focusNode(d) {\n if (!d.x || !d.y) return;\n const w = W(), h = H();\n svgEl.transition().duration(500).call(\n zoomBehavior.transform,\n d3.zoomIdentity.translate(w / 2, h / 2).scale(Math.min(3, currentZoom < 1 ? 1.5 : currentZoom)).translate(-d.x, -d.y)\n );\n}\n\nfunction rebuildGraph() {\n if (sim) sim.stop();\n\n // Links\n linkSel = linkGroup.selectAll('line').data(data.links, d => \\`\\${d.source.id||d.source}>\\${d.target.id||d.target}\\`);\n linkSel.exit().remove();\n const linkEnter = linkSel.enter().append('line').attr('class', 'link');\n linkSel = linkEnter.merge(linkSel)\n .attr('stroke', d => d.confidence < 0.6 ? '#2a2e35' : '#3d434b')\n .attr('stroke-dasharray', d => d.confidence < 0.6 ? '4 3' : null)\n .attr('stroke-width', d => d.confidence < 0.6 ? 0.8 : 1.2)\n .attr('marker-end', 'url(#arrow)');\n linkSel.select('title').remove();\n linkSel.append('title').text(d => \\`\\${d.relationship} (\\${Math.round(d.confidence*100)}%)\\n\\${d.evidence||''}\\`);\n\n // Link labels\n linkLabelSel = linkGroup.selectAll('text').data(data.links, d => \\`\\${d.source.id||d.source}>\\${d.target.id||d.target}\\`);\n linkLabelSel.exit().remove();\n linkLabelSel = linkLabelSel.enter().append('text').attr('class', 'link-label').merge(linkLabelSel)\n .text(d => d.relationship);\n\n // Nodes\n nodeSel = nodeGroup.selectAll('g').data(data.nodes, d => d.id);\n nodeSel.exit().remove();\n const nodeEnter = nodeSel.enter().append('g')\n .call(d3.drag()\n .on('start', (e, d) => { if (!e.active) sim.alphaTarget(0.3).restart(); d.fx = d.x; d.fy = d.y; })\n .on('drag', (e, d) => { d.fx = e.x; d.fy = e.y; })\n .on('end', (e, d) => { if (!e.active) sim.alphaTarget(0); d.fx = null; d.fy = null; })\n )\n .on('click', (e, d) => { e.stopPropagation(); selectNode(d); });\n nodeEnter.append('path').attr('class', 'node-hex');\n nodeEnter.append('title');\n nodeEnter.append('text').attr('class', 'node-label').attr('text-anchor', 'middle');\n\n nodeSel = nodeEnter.merge(nodeSel);\n nodeSel.select('.node-hex')\n .attr('d', d => hexPath(hexSize(d)))\n .attr('fill', d => TYPE_COLORS[d.type] || '#aaa')\n .attr('stroke', d => { const c = d3.color(TYPE_COLORS[d.type] || '#aaa'); return c ? c.brighter(0.8).formatHex() : '#ccc'; })\n .attr('fill-opacity', d => 0.6 + d.confidence * 0.4)\n .classed('selected', d => d.id === selectedNodeId);\n nodeSel.select('title').text(d => \\`\\${d.name} (\\${d.type})\\nconf: \\${Math.round(d.confidence*100)}%\\`);\n nodeLabelSel = nodeSel.select('.node-label')\n .attr('dy', d => hexSize(d) + 13)\n .text(d => d.name.length > 20 ? d.name.substring(0, 18) + '…' : d.name);\n\n // Simulation\n sim = d3.forceSimulation(data.nodes)\n .force('link', d3.forceLink(data.links).id(d => d.id).distance(d => d.relationship === 'contains' ? 50 : 100).strength(0.4))\n .force('charge', d3.forceManyBody().strength(-280))\n .force('center', d3.forceCenter(W() / 2, H() / 2))\n .force('collision', d3.forceCollide().radius(d => hexSize(d) + 10))\n .force('cluster', clusterForce)\n .on('tick', () => {\n updateHulls();\n linkSel.attr('x1', d => d.source.x).attr('y1', d => d.source.y)\n .attr('x2', d => d.target.x).attr('y2', d => d.target.y);\n linkLabelSel.attr('x', d => (d.source.x + d.target.x) / 2)\n .attr('y', d => (d.source.y + d.target.y) / 2 - 4);\n nodeSel.attr('transform', d => \\`translate(\\${d.x},\\${d.y})\\`);\n });\n}\n\n// ── LOD & visibility ──────────────────────────────────────────────────────\nfunction updateLOD(k) {\n if (nodeLabelSel) nodeLabelSel.style('opacity', k > 0.5 ? Math.min(1, (k - 0.5) * 2) : 0);\n if (linkLabelSel) linkLabelSel.style('opacity', k > 1.2 ? Math.min(1, (k - 1.2) * 3) : 0);\n d3.selectAll('.hull-label').style('font-size', k < 0.4 ? '18px' : '13px');\n}\n\nfunction updateVisibility() {\n if (!nodeSel) return;\n nodeSel.style('display', d => layerVisible[d.layer] ? null : 'none');\n linkSel.style('display', d => {\n const s = data.nodes.find(n => n.id === (d.source.id||d.source));\n const t = data.nodes.find(n => n.id === (d.target.id||d.target));\n return (s && layerVisible[s.layer]) && (t && layerVisible[t.layer]) ? null : 'none';\n });\n linkLabelSel.style('display', d => {\n const s = data.nodes.find(n => n.id === (d.source.id||d.source));\n const t = data.nodes.find(n => n.id === (d.target.id||d.target));\n return (s && layerVisible[s.layer]) && (t && layerVisible[t.layer]) ? null : 'none';\n });\n}\n\n// ── Init ──────────────────────────────────────────────────────────────────\nrebuildGraph();\nbuildNodeList();\nupdateLOD(1);\n\nsvgEl.on('click', () => {\n selectedNodeId = null;\n d3.selectAll('.node-hex').classed('selected', false);\n buildNodeList(nodeSearchEl.value);\n sidebar.innerHTML = '<h2>Infrastructure Map</h2><p class=\"hint\">Click a node to view details.</p>';\n});\n</script>\n</body>\n</html>`;\n}\n\n// ── SOP Markdown ─────────────────────────────────────────────────────────────\n\nexport function exportSOPMarkdown(sop: SOP): string {\n const lines: string[] = [\n `# ${sop.title}`,\n '',\n `**Description:** ${sop.description}`,\n `**Systems:** ${sop.involvedSystems.join(', ')}`,\n `**Duration:** ${sop.estimatedDuration}`,\n `**Frequency:** ${sop.frequency}`,\n `**Confidence:** ${sop.confidence.toFixed(2)}`,\n '',\n '## Steps',\n '',\n ];\n\n for (const step of sop.steps) {\n lines.push(`${step.order}. **${step.tool}**${step.target ? ` → \\`${step.target}\\`` : ''}`);\n lines.push(` ${step.instruction}`);\n if (step.notes) lines.push(` _${step.notes}_`);\n lines.push('');\n }\n\n return lines.join('\\n');\n}\n\n// ── SOP Dashboard HTML ───────────────────────────────────────────────────────\n\nexport function exportSOPDashboard(sops: Array<SOP & { id: string; workflowId: string; generatedAt?: string }>): string {\n const sopsJson = JSON.stringify(sops.map(s => ({\n id: s.id,\n title: s.title,\n description: s.description,\n steps: s.steps,\n systems: s.involvedSystems,\n duration: s.estimatedDuration,\n frequency: s.frequency,\n confidence: s.confidence,\n generatedAt: s.generatedAt ?? new Date().toISOString(),\n })));\n\n // System frequency: how many SOPs reference each system\n const systemCount: Record<string, number> = {};\n for (const sop of sops) {\n for (const sys of sop.involvedSystems) {\n systemCount[sys] = (systemCount[sys] ?? 0) + 1;\n }\n }\n const systemsJson = JSON.stringify(\n Object.entries(systemCount).sort((a, b) => b[1] - a[1])\n );\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <title>Cartography — SOP Dashboard</title>\n <style>\n * { box-sizing: border-box; margin: 0; padding: 0; }\n body {\n background: #0d1117; color: #e6edf3;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, monospace;\n padding: 0; line-height: 1.6;\n }\n .header {\n background: linear-gradient(135deg, #161b22 0%, #1a1f2e 100%);\n border-bottom: 1px solid #30363d; padding: 32px 40px;\n }\n .header h1 { font-size: 24px; color: #58a6ff; margin-bottom: 8px; }\n .header .subtitle { color: #8b949e; font-size: 14px; }\n .stats-row {\n display: flex; gap: 24px; margin-top: 16px; flex-wrap: wrap;\n }\n .stat-card {\n background: #21262d; border: 1px solid #30363d; border-radius: 8px;\n padding: 12px 20px; min-width: 140px;\n }\n .stat-card .value { font-size: 28px; font-weight: 700; color: #58a6ff; }\n .stat-card .label { font-size: 11px; color: #8b949e; text-transform: uppercase; letter-spacing: 0.5px; }\n .container { max-width: 1200px; margin: 0 auto; padding: 24px 40px; }\n .section-title { font-size: 18px; color: #c9d1d9; margin: 32px 0 16px; border-bottom: 1px solid #21262d; padding-bottom: 8px; }\n /* Systems bar chart */\n .systems-grid { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 24px; }\n .sys-tag {\n background: #21262d; border: 1px solid #30363d; border-radius: 6px;\n padding: 6px 12px; font-size: 12px; cursor: default;\n }\n .sys-tag .count { color: #58a6ff; font-weight: 600; margin-left: 4px; }\n /* SOP cards */\n .sop-card {\n background: #161b22; border: 1px solid #30363d; border-radius: 8px;\n margin-bottom: 16px; overflow: hidden; transition: border-color 0.2s;\n }\n .sop-card:hover { border-color: #58a6ff; }\n .sop-header {\n padding: 16px 20px; cursor: pointer; display: flex;\n justify-content: space-between; align-items: center;\n }\n .sop-header h3 { font-size: 16px; color: #e6edf3; }\n .sop-meta { display: flex; gap: 16px; align-items: center; font-size: 12px; color: #8b949e; }\n .sop-meta .freq { color: #3fb950; font-weight: 600; }\n .sop-meta .dur { color: #d29922; }\n .sop-meta .conf {\n display: inline-flex; align-items: center; gap: 4px;\n }\n .conf-dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; }\n .sop-body { display: none; padding: 0 20px 20px; border-top: 1px solid #21262d; }\n .sop-body.open { display: block; padding-top: 16px; }\n .sop-desc { color: #8b949e; font-size: 13px; margin-bottom: 12px; }\n .sop-systems { margin-bottom: 12px; }\n .sop-systems span { background: #0d419d33; color: #58a6ff; border-radius: 4px; padding: 2px 8px; font-size: 11px; margin-right: 4px; }\n .steps-list { list-style: none; counter-reset: step; }\n .steps-list li {\n counter-increment: step; position: relative;\n padding: 10px 12px 10px 44px; border-left: 2px solid #30363d;\n margin-left: 14px; font-size: 13px;\n }\n .steps-list li:last-child { border-left-color: transparent; }\n .steps-list li::before {\n content: counter(step);\n position: absolute; left: -14px; top: 8px;\n width: 26px; height: 26px; border-radius: 50%;\n background: #21262d; border: 2px solid #30363d;\n display: flex; align-items: center; justify-content: center;\n font-size: 12px; font-weight: 600; color: #58a6ff;\n }\n .step-tool { color: #d2a8ff; font-weight: 600; }\n .step-target { color: #7ee787; font-size: 12px; }\n .step-notes { color: #8b949e; font-style: italic; font-size: 12px; margin-top: 2px; }\n .step-instr { color: #c9d1d9; }\n .toggle-icon { color: #8b949e; font-size: 18px; transition: transform 0.2s; }\n .toggle-icon.open { transform: rotate(90deg); }\n .empty { color: #484f58; font-size: 14px; padding: 40px; text-align: center; }\n .gen-time { color: #484f58; font-size: 11px; margin-top: 8px; }\n </style>\n</head>\n<body>\n<div class=\"header\">\n <h1>SOP Dashboard</h1>\n <div class=\"subtitle\">Datasynx Cartography — Standard Operating Procedures</div>\n <div class=\"stats-row\">\n <div class=\"stat-card\"><div class=\"value\" id=\"sop-count\">0</div><div class=\"label\">SOPs</div></div>\n <div class=\"stat-card\"><div class=\"value\" id=\"step-count\">0</div><div class=\"label\">Total Steps</div></div>\n <div class=\"stat-card\"><div class=\"value\" id=\"sys-count\">0</div><div class=\"label\">Systems</div></div>\n <div class=\"stat-card\"><div class=\"value\" id=\"avg-conf\">—</div><div class=\"label\">Avg Confidence</div></div>\n </div>\n</div>\n<div class=\"container\">\n <h2 class=\"section-title\">Involved Systems</h2>\n <div class=\"systems-grid\" id=\"systems\"></div>\n\n <h2 class=\"section-title\">SOPs</h2>\n <div id=\"sop-list\"></div>\n</div>\n<script>\nconst sops = ${sopsJson};\nconst systems = ${systemsJson};\n\ndocument.getElementById('sop-count').textContent = sops.length;\ndocument.getElementById('step-count').textContent = sops.reduce((a, s) => a + s.steps.length, 0);\ndocument.getElementById('sys-count').textContent = systems.length;\nconst avgConf = sops.length > 0\n ? (sops.reduce((a, s) => a + s.confidence, 0) / sops.length * 100).toFixed(0) + '%'\n : '—';\ndocument.getElementById('avg-conf').textContent = avgConf;\n\nconst sysDiv = document.getElementById('systems');\nsystems.forEach(([name, count]) => {\n const el = document.createElement('div');\n el.className = 'sys-tag';\n el.innerHTML = name + '<span class=\"count\">x' + count + '</span>';\n sysDiv.appendChild(el);\n});\n\nconst listDiv = document.getElementById('sop-list');\nif (sops.length === 0) {\n listDiv.innerHTML = '<div class=\"empty\">No SOPs found. Start the shadow daemon and observe workflows.</div>';\n}\n\nsops.forEach((sop, i) => {\n const confColor = sop.confidence >= 0.8 ? '#3fb950' : sop.confidence >= 0.5 ? '#d29922' : '#f85149';\n const card = document.createElement('div');\n card.className = 'sop-card';\n card.innerHTML = \\`\n <div class=\"sop-header\" onclick=\"toggle(\\${i})\">\n <h3>\\${sop.title}</h3>\n <div class=\"sop-meta\">\n <span class=\"freq\">\\${sop.frequency}</span>\n <span class=\"dur\">\\${sop.duration}</span>\n <span class=\"conf\"><span class=\"conf-dot\" style=\"background:\\${confColor}\"></span>\\${Math.round(sop.confidence*100)}%</span>\n <span class=\"toggle-icon\" id=\"icon-\\${i}\">▸</span>\n </div>\n </div>\n <div class=\"sop-body\" id=\"body-\\${i}\">\n <div class=\"sop-desc\">\\${sop.description}</div>\n <div class=\"sop-systems\">\\${sop.systems.map(s => '<span>'+s+'</span>').join('')}</div>\n <ol class=\"steps-list\">\n \\${sop.steps.map(st => \\`\n <li>\n <span class=\"step-tool\">\\${st.tool}</span>\n \\${st.target ? '<span class=\"step-target\"> → '+st.target+'</span>' : ''}\n <div class=\"step-instr\">\\${st.instruction}</div>\n \\${st.notes ? '<div class=\"step-notes\">'+st.notes+'</div>' : ''}\n </li>\n \\`).join('')}\n </ol>\n <div class=\"gen-time\">Generated: \\${sop.generatedAt ? sop.generatedAt.substring(0,19).replace('T',' ') : '—'}</div>\n </div>\n \\`;\n listDiv.appendChild(card);\n});\n\nfunction toggle(i) {\n const body = document.getElementById('body-'+i);\n const icon = document.getElementById('icon-'+i);\n body.classList.toggle('open');\n icon.classList.toggle('open');\n}\n</script>\n</body>\n</html>`;\n}\n\n// ── exportAll ─────────────────────────────────────────────────────────────────\n\nexport function exportAll(\n db: CartographyDB,\n sessionId: string,\n outputDir: string,\n formats: string[] = ['mermaid', 'json', 'yaml', 'html', 'sops'],\n): void {\n mkdirSync(outputDir, { recursive: true });\n mkdirSync(join(outputDir, 'sops'), { recursive: true });\n mkdirSync(join(outputDir, 'workflows'), { recursive: true });\n\n const nodes = db.getNodes(sessionId);\n const edges = db.getEdges(sessionId);\n\n if (formats.includes('mermaid')) {\n writeFileSync(join(outputDir, 'topology.mermaid'), generateTopologyMermaid(nodes, edges));\n writeFileSync(join(outputDir, 'dependencies.mermaid'), generateDependencyMermaid(nodes, edges));\n process.stderr.write('✓ topology.mermaid, dependencies.mermaid\\n');\n }\n\n if (formats.includes('json')) {\n writeFileSync(join(outputDir, 'catalog.json'), exportJSON(db, sessionId));\n process.stderr.write('✓ catalog.json\\n');\n }\n\n if (formats.includes('yaml')) {\n writeFileSync(join(outputDir, 'catalog-info.yaml'), exportBackstageYAML(nodes, edges));\n process.stderr.write('✓ catalog-info.yaml\\n');\n }\n\n if (formats.includes('html')) {\n writeFileSync(join(outputDir, 'topology.html'), exportHTML(nodes, edges));\n process.stderr.write('✓ topology.html\\n');\n }\n\n if (formats.includes('sops')) {\n const sops = db.getSOPs(sessionId);\n for (const sop of sops) {\n const filename = sop.title.toLowerCase().replace(/[^a-z0-9]+/g, '-') + '.md';\n writeFileSync(join(outputDir, 'sops', filename), exportSOPMarkdown(sop));\n\n const wfFilename = `workflow-${sop.workflowId.substring(0, 8)}.mermaid`;\n writeFileSync(join(outputDir, 'workflows', wfFilename), generateWorkflowMermaid(sop));\n }\n if (sops.length > 0) {\n process.stderr.write(`✓ ${sops.length} SOPs + workflow diagrams\\n`);\n }\n }\n}\n"],"mappings":"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AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,uCAuG8B,MAAM,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,yCASV,MAAM,MAAM,eAAY,MAAM,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,eAc9D,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;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","names":[]}
package/dist/cli.js CHANGED
@@ -10,10 +10,10 @@ import {
10
10
  import {
11
11
  scanAllBookmarks,
12
12
  scanAllHistory
13
- } from "./chunk-MZUF7KGX.js";
13
+ } from "./chunk-2VIAXA5T.js";
14
14
  import {
15
15
  exportAll
16
- } from "./chunk-NEB52VYQ.js";
16
+ } from "./chunk-LNMM7BTH.js";
17
17
 
18
18
  // src/cli.ts
19
19
  import { Command } from "commander";
@@ -2239,7 +2239,7 @@ function main() {
2239
2239
  `);
2240
2240
  }
2241
2241
  }
2242
- const { exportSOPMarkdown, exportSOPDashboard } = await import("./exporter-LRHXMSKN.js");
2242
+ const { exportSOPMarkdown, exportSOPDashboard } = await import("./exporter-PWVD7Y6T.js");
2243
2243
  const sops = db.getSOPs(session.id);
2244
2244
  if (sops.length > 0) {
2245
2245
  w(bold(" SOPs for review:\n\n"));
@@ -2703,7 +2703,7 @@ ${infraSummary.substring(0, 12e3)}`;
2703
2703
  out("\n");
2704
2704
  });
2705
2705
  program.command("bookmarks").description("View all browser bookmarks (Chrome, Chromium, Edge, Brave, Vivaldi, Opera, Firefox)").action(async () => {
2706
- const { scanAllBookmarks: scanAllBookmarks2 } = await import("./bookmarks-B2LUZQGG.js");
2706
+ const { scanAllBookmarks: scanAllBookmarks2 } = await import("./bookmarks-ITLW7U5D.js");
2707
2707
  const out = (s) => process.stdout.write(s);
2708
2708
  process.stderr.write(" Scanning bookmarks...\n\n");
2709
2709
  const hosts = await scanAllBookmarks2();
@@ -9,7 +9,7 @@ import {
9
9
  generateDependencyMermaid,
10
10
  generateTopologyMermaid,
11
11
  generateWorkflowMermaid
12
- } from "./chunk-NEB52VYQ.js";
12
+ } from "./chunk-LNMM7BTH.js";
13
13
  export {
14
14
  exportAll,
15
15
  exportBackstageYAML,
@@ -21,4 +21,4 @@ export {
21
21
  generateTopologyMermaid,
22
22
  generateWorkflowMermaid
23
23
  };
24
- //# sourceMappingURL=exporter-LRHXMSKN.js.map
24
+ //# sourceMappingURL=exporter-PWVD7Y6T.js.map