@datasynx/agentic-ai-cartography 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +253 -14
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +200 -12
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/db.ts","../src/tools.ts","../src/types.ts","../src/bookmarks.ts","../src/safety.ts","../src/agent.ts","../src/exporter.ts","../src/preflight.ts"],"sourcesContent":["import Database from 'better-sqlite3';\nimport { mkdirSync } from 'node:fs';\nimport { dirname } from 'node:path';\nimport type {\n CartographyConfig, DiscoveryNode, DiscoveryEdge, ActivityEvent,\n NodeRow, EdgeRow, EventRow, TaskRow, WorkflowRow, SessionRow, SOP,\n} from './types.js';\n\nconst SCHEMA = `\nPRAGMA journal_mode = WAL;\nPRAGMA foreign_keys = ON;\nPRAGMA busy_timeout = 5000;\n\nCREATE TABLE IF NOT EXISTS sessions (\n id TEXT PRIMARY KEY,\n mode TEXT NOT NULL CHECK (mode IN ('discover','shadow')),\n started_at TEXT NOT NULL,\n completed_at TEXT,\n config TEXT NOT NULL DEFAULT '{}'\n);\n\nCREATE TABLE IF NOT EXISTS nodes (\n id TEXT NOT NULL,\n session_id TEXT NOT NULL REFERENCES sessions(id),\n type TEXT NOT NULL,\n name TEXT NOT NULL,\n discovered_via TEXT,\n discovered_at TEXT NOT NULL,\n path_id TEXT,\n depth INTEGER DEFAULT 0,\n confidence REAL DEFAULT 0.5,\n metadata TEXT NOT NULL DEFAULT '{}',\n tags TEXT NOT NULL DEFAULT '[]',\n PRIMARY KEY (id, session_id)\n);\n\nCREATE TABLE IF NOT EXISTS edges (\n id TEXT PRIMARY KEY,\n session_id TEXT NOT NULL REFERENCES sessions(id),\n source_id TEXT NOT NULL,\n target_id TEXT NOT NULL,\n relationship TEXT NOT NULL,\n evidence TEXT,\n confidence REAL DEFAULT 0.5,\n discovered_at TEXT NOT NULL\n);\n\nCREATE TABLE IF NOT EXISTS activity_events (\n id TEXT PRIMARY KEY,\n session_id TEXT NOT NULL REFERENCES sessions(id),\n task_id TEXT,\n timestamp TEXT NOT NULL,\n event_type TEXT NOT NULL,\n process TEXT NOT NULL,\n pid INTEGER NOT NULL,\n target TEXT,\n target_type TEXT,\n port INTEGER,\n duration_ms INTEGER\n);\n\nCREATE TABLE IF NOT EXISTS tasks (\n id TEXT PRIMARY KEY,\n session_id TEXT NOT NULL REFERENCES sessions(id),\n description TEXT,\n started_at TEXT NOT NULL,\n completed_at TEXT,\n steps TEXT NOT NULL DEFAULT '[]',\n involved_services TEXT NOT NULL DEFAULT '[]',\n status TEXT DEFAULT 'active' CHECK (status IN ('active','completed','cancelled')),\n is_sop_candidate INTEGER DEFAULT 0\n);\n\nCREATE TABLE IF NOT EXISTS workflows (\n id TEXT PRIMARY KEY,\n session_id TEXT NOT NULL REFERENCES sessions(id),\n name TEXT,\n pattern TEXT NOT NULL,\n task_ids TEXT NOT NULL DEFAULT '[]',\n occurrences INTEGER DEFAULT 1,\n first_seen TEXT NOT NULL,\n last_seen TEXT NOT NULL,\n avg_duration_ms INTEGER,\n involved_services TEXT NOT NULL DEFAULT '[]'\n);\n\nCREATE TABLE IF NOT EXISTS sops (\n id TEXT PRIMARY KEY,\n workflow_id TEXT NOT NULL,\n title TEXT NOT NULL,\n description TEXT NOT NULL,\n steps TEXT NOT NULL,\n involved_systems TEXT NOT NULL DEFAULT '[]',\n estimated_duration TEXT,\n frequency TEXT,\n generated_at TEXT NOT NULL,\n confidence REAL DEFAULT 0.5\n);\n\nCREATE TABLE IF NOT EXISTS node_approvals (\n pattern TEXT PRIMARY KEY,\n action TEXT NOT NULL CHECK (action IN ('save','ignore','auto')),\n created_at TEXT NOT NULL\n);\n\nCREATE INDEX IF NOT EXISTS idx_nodes_session ON nodes(session_id);\nCREATE INDEX IF NOT EXISTS idx_edges_session ON edges(session_id);\nCREATE INDEX IF NOT EXISTS idx_events_session ON activity_events(session_id);\nCREATE INDEX IF NOT EXISTS idx_events_task ON activity_events(task_id);\nCREATE INDEX IF NOT EXISTS idx_tasks_session ON tasks(session_id);\n`;\n\nexport class CartographyDB {\n private db: Database.Database;\n\n constructor(dbPath: string) {\n mkdirSync(dirname(dbPath), { recursive: true });\n this.db = new Database(dbPath);\n this.db.pragma('journal_mode = WAL');\n this.db.pragma('foreign_keys = ON');\n this.db.pragma('busy_timeout = 5000');\n this.migrate();\n }\n\n private migrate(): void {\n const version = (this.db.pragma('user_version', { simple: true }) as number);\n if (version === 0) {\n this.db.exec(SCHEMA);\n this.db.pragma('user_version = 1');\n }\n }\n\n close(): void {\n this.db.pragma('optimize');\n this.db.close();\n }\n\n // ── Sessions ────────────────────────────\n\n createSession(mode: 'discover' | 'shadow', config: CartographyConfig): string {\n const id = crypto.randomUUID();\n this.db.prepare(\n 'INSERT INTO sessions (id, mode, started_at, config) VALUES (?, ?, ?, ?)'\n ).run(id, mode, new Date().toISOString(), JSON.stringify(config));\n return id;\n }\n\n endSession(id: string): void {\n this.db.prepare('UPDATE sessions SET completed_at = ? WHERE id = ?')\n .run(new Date().toISOString(), id);\n }\n\n getSession(id: string): SessionRow | undefined {\n const row = this.db.prepare('SELECT * FROM sessions WHERE id = ?').get(id) as Record<string, unknown> | undefined;\n return row ? this.mapSession(row) : undefined;\n }\n\n getLatestSession(mode?: string): SessionRow | undefined {\n const row = mode\n ? this.db.prepare('SELECT * FROM sessions WHERE mode = ? ORDER BY rowid DESC LIMIT 1').get(mode) as Record<string, unknown> | undefined\n : this.db.prepare('SELECT * FROM sessions ORDER BY rowid DESC LIMIT 1').get() as Record<string, unknown> | undefined;\n return row ? this.mapSession(row) : undefined;\n }\n\n getSessions(): SessionRow[] {\n const rows = this.db.prepare('SELECT * FROM sessions ORDER BY rowid DESC').all() as Record<string, unknown>[];\n return rows.map(r => this.mapSession(r));\n }\n\n private mapSession(r: Record<string, unknown>): SessionRow {\n return {\n id: r['id'] as string,\n mode: r['mode'] as 'discover' | 'shadow',\n startedAt: r['started_at'] as string,\n completedAt: (r['completed_at'] as string | null) ?? undefined,\n config: r['config'] as string,\n };\n }\n\n // ── Nodes ───────────────────────────────\n\n upsertNode(sessionId: string, node: DiscoveryNode, depth = 0): void {\n this.db.prepare(`\n INSERT OR REPLACE INTO nodes\n (id, session_id, type, name, discovered_via, discovered_at, depth, confidence, metadata, tags)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `).run(\n node.id, sessionId, node.type, node.name, node.discoveredVia,\n new Date().toISOString(), depth, node.confidence,\n JSON.stringify(node.metadata ?? {}),\n JSON.stringify(node.tags ?? []),\n );\n }\n\n getNodes(sessionId: string): NodeRow[] {\n const rows = this.db.prepare('SELECT * FROM nodes WHERE session_id = ?').all(sessionId) as Record<string, unknown>[];\n return rows.map(r => ({\n id: r['id'] as string,\n sessionId: r['session_id'] as string,\n type: r['type'] as NodeRow['type'],\n name: r['name'] as string,\n discoveredVia: r['discovered_via'] as string,\n discoveredAt: r['discovered_at'] as string,\n depth: r['depth'] as number,\n confidence: r['confidence'] as number,\n metadata: JSON.parse(r['metadata'] as string) as Record<string, unknown>,\n tags: JSON.parse(r['tags'] as string) as string[],\n pathId: r['path_id'] as string | undefined,\n }));\n }\n\n deleteNode(sessionId: string, nodeId: string): void {\n this.db.prepare('DELETE FROM nodes WHERE session_id = ? AND id = ?').run(sessionId, nodeId);\n // Remove orphaned edges\n this.db.prepare(\n 'DELETE FROM edges WHERE session_id = ? AND (source_id = ? OR target_id = ?)'\n ).run(sessionId, nodeId, nodeId);\n }\n\n // ── Edges ───────────────────────────────\n\n insertEdge(sessionId: string, edge: DiscoveryEdge): void {\n const id = crypto.randomUUID();\n this.db.prepare(`\n INSERT OR IGNORE INTO edges\n (id, session_id, source_id, target_id, relationship, evidence, confidence, discovered_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?)\n `).run(\n id, sessionId, edge.sourceId, edge.targetId,\n edge.relationship, edge.evidence, edge.confidence,\n new Date().toISOString(),\n );\n }\n\n getEdges(sessionId: string): EdgeRow[] {\n const rows = this.db.prepare('SELECT * FROM edges WHERE session_id = ?').all(sessionId) as Record<string, unknown>[];\n return rows.map(r => ({\n id: r['id'] as string,\n sessionId: r['session_id'] as string,\n sourceId: r['source_id'] as string,\n targetId: r['target_id'] as string,\n relationship: r['relationship'] as EdgeRow['relationship'],\n evidence: r['evidence'] as string,\n confidence: r['confidence'] as number,\n discoveredAt: r['discovered_at'] as string,\n }));\n }\n\n // ── Events ──────────────────────────────\n\n insertEvent(sessionId: string, event: ActivityEvent, taskId?: string): void {\n const id = crypto.randomUUID();\n this.db.prepare(`\n INSERT INTO activity_events\n (id, session_id, task_id, timestamp, event_type, process, pid, target, target_type, port)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `).run(\n id, sessionId, taskId ?? null, new Date().toISOString(),\n event.eventType, event.process, event.pid,\n event.target ?? null, event.targetType ?? null, event.port ?? null,\n );\n }\n\n getEvents(sessionId: string, since?: string): EventRow[] {\n const rows = since\n ? this.db.prepare('SELECT * FROM activity_events WHERE session_id = ? AND timestamp > ? ORDER BY timestamp').all(sessionId, since) as Record<string, unknown>[]\n : this.db.prepare('SELECT * FROM activity_events WHERE session_id = ? ORDER BY timestamp').all(sessionId) as Record<string, unknown>[];\n return rows.map(r => ({\n id: r['id'] as string,\n sessionId: r['session_id'] as string,\n taskId: r['task_id'] as string | undefined,\n timestamp: r['timestamp'] as string,\n eventType: r['event_type'] as EventRow['eventType'],\n process: r['process'] as string,\n pid: r['pid'] as number,\n target: r['target'] as string | undefined,\n targetType: r['target_type'] as EventRow['targetType'],\n port: r['port'] as number | undefined,\n durationMs: r['duration_ms'] as number | undefined,\n }));\n }\n\n // ── Tasks ───────────────────────────────\n\n startTask(sessionId: string, description?: string): string {\n const id = crypto.randomUUID();\n this.db.prepare(`\n INSERT INTO tasks (id, session_id, description, started_at, steps, involved_services, status)\n VALUES (?, ?, ?, ?, '[]', '[]', 'active')\n `).run(id, sessionId, description ?? null, new Date().toISOString());\n return id;\n }\n\n endCurrentTask(sessionId: string): void {\n this.db.prepare(`\n UPDATE tasks SET status = 'completed', completed_at = ?\n WHERE session_id = ? AND status = 'active'\n `).run(new Date().toISOString(), sessionId);\n }\n\n updateTaskDescription(sessionId: string, description: string): void {\n this.db.prepare(`\n UPDATE tasks SET description = ?\n WHERE session_id = ? AND status = 'active'\n `).run(description, sessionId);\n }\n\n getActiveTask(sessionId: string): TaskRow | undefined {\n const row = this.db.prepare(\n \"SELECT * FROM tasks WHERE session_id = ? AND status = 'active' LIMIT 1\"\n ).get(sessionId) as Record<string, unknown> | undefined;\n return row ? this.mapTask(row) : undefined;\n }\n\n getTasks(sessionId: string): TaskRow[] {\n const rows = this.db.prepare('SELECT * FROM tasks WHERE session_id = ? ORDER BY started_at').all(sessionId) as Record<string, unknown>[];\n return rows.map(r => this.mapTask(r));\n }\n\n private mapTask(r: Record<string, unknown>): TaskRow {\n return {\n id: r['id'] as string,\n sessionId: r['session_id'] as string,\n description: r['description'] as string | undefined,\n startedAt: r['started_at'] as string,\n completedAt: r['completed_at'] as string | undefined,\n steps: r['steps'] as string,\n involvedServices: r['involved_services'] as string,\n status: r['status'] as TaskRow['status'],\n isSOPCandidate: Boolean(r['is_sop_candidate']),\n };\n }\n\n // ── Workflows ───────────────────────────\n\n insertWorkflow(sessionId: string, data: Omit<WorkflowRow, 'id'>): void {\n const id = crypto.randomUUID();\n this.db.prepare(`\n INSERT INTO workflows\n (id, session_id, name, pattern, task_ids, occurrences,\n first_seen, last_seen, avg_duration_ms, involved_services)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `).run(\n id, sessionId, data.name ?? null, data.pattern,\n data.taskIds, data.occurrences,\n data.firstSeen, data.lastSeen, data.avgDurationMs,\n data.involvedServices,\n );\n }\n\n getWorkflows(sessionId: string): WorkflowRow[] {\n const rows = this.db.prepare('SELECT * FROM workflows WHERE session_id = ?').all(sessionId) as Record<string, unknown>[];\n return rows.map(r => ({\n id: r['id'] as string,\n sessionId: r['session_id'] as string,\n name: r['name'] as string | undefined,\n pattern: r['pattern'] as string,\n taskIds: r['task_ids'] as string,\n occurrences: r['occurrences'] as number,\n firstSeen: r['first_seen'] as string,\n lastSeen: r['last_seen'] as string,\n avgDurationMs: r['avg_duration_ms'] as number,\n involvedServices: r['involved_services'] as string,\n }));\n }\n\n // ── SOPs ────────────────────────────────\n\n insertSOP(sop: { workflowId: string } & SOP): void {\n const id = crypto.randomUUID();\n this.db.prepare(`\n INSERT INTO sops\n (id, workflow_id, title, description, steps, involved_systems,\n estimated_duration, frequency, generated_at, confidence)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `).run(\n id, sop.workflowId, sop.title, sop.description,\n JSON.stringify(sop.steps),\n JSON.stringify(sop.involvedSystems),\n sop.estimatedDuration, sop.frequency,\n new Date().toISOString(), sop.confidence,\n );\n }\n\n getSOPs(sessionId: string): Array<SOP & { id: string; workflowId: string }> {\n const rows = this.db.prepare(`\n SELECT s.* FROM sops s\n JOIN workflows w ON s.workflow_id = w.id\n WHERE w.session_id = ?\n `).all(sessionId) as Record<string, unknown>[];\n return rows.map(r => ({\n id: r['id'] as string,\n workflowId: r['workflow_id'] as string,\n title: r['title'] as string,\n description: r['description'] as string,\n steps: JSON.parse(r['steps'] as string) as SOP['steps'],\n involvedSystems: JSON.parse(r['involved_systems'] as string) as string[],\n estimatedDuration: r['estimated_duration'] as string,\n frequency: r['frequency'] as string,\n confidence: r['confidence'] as number,\n }));\n }\n\n markTaskAsSOPCandidate(taskId: string): void {\n this.db.prepare('UPDATE tasks SET is_sop_candidate = 1 WHERE id = ?').run(taskId);\n }\n\n getAllSOPs(): Array<SOP & { id: string; workflowId: string; generatedAt: string }> {\n const rows = this.db.prepare('SELECT * FROM sops ORDER BY generated_at DESC').all() as Record<string, unknown>[];\n return rows.map(r => ({\n id: r['id'] as string,\n workflowId: r['workflow_id'] as string,\n title: r['title'] as string,\n description: r['description'] as string,\n steps: JSON.parse(r['steps'] as string) as SOP['steps'],\n involvedSystems: JSON.parse(r['involved_systems'] as string) as string[],\n estimatedDuration: r['estimated_duration'] as string,\n frequency: r['frequency'] as string,\n confidence: r['confidence'] as number,\n generatedAt: r['generated_at'] as string,\n }));\n }\n\n // ── Approvals ───────────────────────────\n\n setApproval(pattern: string, action: 'save' | 'ignore' | 'auto'): void {\n this.db.prepare(`\n INSERT OR REPLACE INTO node_approvals (pattern, action, created_at) VALUES (?, ?, ?)\n `).run(pattern, action, new Date().toISOString());\n }\n\n getApproval(pattern: string): string | undefined {\n const row = this.db.prepare('SELECT action FROM node_approvals WHERE pattern = ?').get(pattern) as { action: string } | undefined;\n return row?.action;\n }\n\n // ── Stats ───────────────────────────────\n\n getStats(sessionId: string): { nodes: number; edges: number; events: number; tasks: number } {\n const nodes = (this.db.prepare('SELECT COUNT(*) as c FROM nodes WHERE session_id = ?').get(sessionId) as { c: number }).c;\n const edges = (this.db.prepare('SELECT COUNT(*) as c FROM edges WHERE session_id = ?').get(sessionId) as { c: number }).c;\n const events = (this.db.prepare('SELECT COUNT(*) as c FROM activity_events WHERE session_id = ?').get(sessionId) as { c: number }).c;\n const tasks = (this.db.prepare('SELECT COUNT(*) as c FROM tasks WHERE session_id = ?').get(sessionId) as { c: number }).c;\n return { nodes, edges, events, tasks };\n }\n}\n","import { z } from 'zod';\nimport type { CartographyDB } from './db.js';\nimport { NODE_TYPES, EDGE_RELATIONSHIPS, EVENT_TYPES, SOPStepSchema } from './types.js';\nimport { scanAllBookmarks } from './bookmarks.js';\n\n// Lazy import to avoid hard-wiring SDK at module parse time\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype McpServer = any;\n\nexport interface CartographyToolsOptions {\n /** Called when the agent needs a human answer. Return the user's response. */\n onAskUser?: (question: string, context?: string) => Promise<string>;\n}\n\nexport function stripSensitive(target: string): string {\n try {\n const url = new URL(target.startsWith('http') ? target : `tcp://${target}`);\n return `${url.hostname}${url.port ? ':' + url.port : ''}`;\n } catch {\n return target\n .replace(/\\/.*$/, '')\n .replace(/\\?.*$/, '')\n .replace(/@.*:/, ':');\n }\n}\n\nexport async function createCartographyTools(\n db: CartographyDB,\n sessionId: string,\n opts: CartographyToolsOptions = {},\n): Promise<McpServer> {\n // Dynamically import the SDK so missing package doesn't crash at load time\n const sdk = await import('@anthropic-ai/claude-code');\n const { tool, createSdkMcpServer } = sdk as {\n tool: (name: string, description: string, schema: z.ZodRawShape, handler: (args: Record<string, unknown>) => Promise<{ content: Array<{ type: string; text: string }> }>) => unknown;\n createSdkMcpServer: (opts: { name: string; version: string; tools: unknown[] }) => McpServer;\n };\n\n const tools = [\n tool('save_node', 'Infrastructure-Node speichern', {\n id: z.string(),\n type: z.enum(NODE_TYPES),\n name: z.string(),\n discoveredVia: z.string(),\n confidence: z.number().min(0).max(1),\n metadata: z.record(z.unknown()).optional(),\n tags: z.array(z.string()).optional(),\n }, async (args) => {\n const node = {\n id: stripSensitive(args['id'] as string),\n type: args['type'] as typeof NODE_TYPES[number],\n name: args['name'] as string,\n discoveredVia: args['discoveredVia'] as string,\n confidence: args['confidence'] as number,\n metadata: (args['metadata'] as Record<string, unknown>) ?? {},\n tags: (args['tags'] as string[]) ?? [],\n };\n db.upsertNode(sessionId, node);\n return { content: [{ type: 'text', text: `✓ Node: ${node.id}` }] };\n }),\n\n tool('save_edge', 'Verbindung zwischen zwei Nodes speichern', {\n sourceId: z.string(),\n targetId: z.string(),\n relationship: z.enum(EDGE_RELATIONSHIPS),\n evidence: z.string(),\n confidence: z.number().min(0).max(1),\n }, async (args) => {\n db.insertEdge(sessionId, {\n sourceId: args['sourceId'] as string,\n targetId: args['targetId'] as string,\n relationship: args['relationship'] as typeof EDGE_RELATIONSHIPS[number],\n evidence: args['evidence'] as string,\n confidence: args['confidence'] as number,\n });\n return { content: [{ type: 'text', text: `✓ ${args['sourceId']}→${args['targetId']}` }] };\n }),\n\n tool('save_event', 'Activity-Event (Prozess/Verbindung) speichern', {\n eventType: z.enum(EVENT_TYPES),\n process: z.string(),\n pid: z.number(),\n target: z.string().optional(),\n targetType: z.enum(NODE_TYPES).optional(),\n port: z.number().optional(),\n }, async (args) => {\n db.insertEvent(sessionId, {\n eventType: args['eventType'] as typeof EVENT_TYPES[number],\n process: args['process'] as string,\n pid: args['pid'] as number,\n target: args['target'] ? stripSensitive(args['target'] as string) : undefined,\n targetType: args['targetType'] as typeof NODE_TYPES[number] | undefined,\n port: args['port'] as number | undefined,\n });\n return { content: [{ type: 'text', text: `✓ ${args['eventType']}` }] };\n }),\n\n tool('get_catalog', 'Aktuellen Katalog abrufen (Duplikat-Check)', {\n includeEdges: z.boolean().default(true),\n }, async (args) => {\n const nodes = db.getNodes(sessionId);\n const edges = (args['includeEdges'] as boolean) ? db.getEdges(sessionId) : [];\n return {\n content: [{\n type: 'text',\n text: JSON.stringify({\n count: { nodes: nodes.length, edges: edges.length },\n nodeIds: nodes.map(n => n.id),\n }),\n }],\n };\n }),\n\n tool('manage_task', 'Task starten, beenden oder beschreiben', {\n action: z.enum(['start', 'end', 'describe']),\n description: z.string().optional(),\n }, async (args) => {\n const action = args['action'] as string;\n if (action === 'start') {\n const id = db.startTask(sessionId, args['description'] as string | undefined);\n return { content: [{ type: 'text', text: `✓ Task gestartet: ${id}` }] };\n }\n if (action === 'end') {\n db.endCurrentTask(sessionId);\n return { content: [{ type: 'text', text: '✓ Task beendet' }] };\n }\n db.updateTaskDescription(sessionId, args['description'] as string);\n return { content: [{ type: 'text', text: '✓ Beschreibung aktualisiert' }] };\n }),\n\n tool('ask_user', 'Rückfrage an den User stellen — bei Unklarheiten, fehlenden Credentials-Hinweisen oder wenn Kontext fehlt', {\n question: z.string().describe('Die Frage an den User (klar und konkret)'),\n context: z.string().optional().describe('Optionaler Zusatzkontext warum die Frage relevant ist'),\n }, async (args) => {\n const question = args['question'] as string;\n const context = args['context'] as string | undefined;\n\n if (opts.onAskUser) {\n const answer = await opts.onAskUser(question, context);\n return { content: [{ type: 'text', text: answer }] };\n }\n\n // Fallback when not interactive (piped input, daemon, etc.)\n return {\n content: [{ type: 'text', text: '(Kein interaktiver Modus — bitte ohne diese Information fortfahren)' }],\n };\n }),\n\n tool('scan_bookmarks', 'Alle Browser-Lesezeichen scannen — nur Hostnamen, keine persönlichen Daten', {\n minConfidence: z.number().min(0).max(1).default(0.5).optional(),\n }, async () => {\n const hosts = await scanAllBookmarks();\n return {\n content: [{\n type: 'text',\n text: JSON.stringify({\n count: hosts.length,\n hosts: hosts.map(h => ({\n hostname: h.hostname,\n port: h.port,\n protocol: h.protocol,\n source: h.source,\n })),\n note: 'Nur Hostnamen — keine Pfade, keine persönlichen Daten. Entscheide selbst welche davon Business-Tools sind.',\n }),\n }],\n };\n }),\n\n tool('scan_k8s_resources', 'Kubernetes-Cluster via kubectl scannen — 100% readonly (get, describe)', {\n namespace: z.string().optional().describe('Namespace filtern — leer = alle Namespaces'),\n }, async (args) => {\n const { execSync } = await import('node:child_process');\n const ns = args['namespace'] as string | undefined;\n const nsFlag = ns ? `-n ${ns}` : '--all-namespaces';\n const run = (cmd: string): string => {\n try {\n return execSync(cmd, { stdio: 'pipe', timeout: 15_000, shell: '/bin/sh' }).toString().trim();\n } catch (e) {\n return `(error: ${e instanceof Error ? e.message.split('\\n')[0] : String(e)})`;\n }\n };\n const sections: [string, string][] = [\n ['CONTEXT', 'kubectl config current-context 2>/dev/null || echo \"(kein Context gesetzt)\"'],\n ['NODES', 'kubectl get nodes -o wide'],\n ['NAMESPACES', 'kubectl get namespaces'],\n ['SERVICES', `kubectl get services ${nsFlag}`],\n ['DEPLOYMENTS', `kubectl get deployments ${nsFlag}`],\n ['STATEFULSETS', `kubectl get statefulsets ${nsFlag}`],\n ['INGRESSES', `kubectl get ingress ${nsFlag} 2>/dev/null || echo \"(keine)\"`],\n ['PODS_RUNNING', `kubectl get pods ${nsFlag} --field-selector=status.phase=Running 2>/dev/null | head -60`],\n ['CONFIGMAPS_SYSTEM', 'kubectl get configmaps -n kube-system 2>/dev/null | head -30'],\n ];\n const out = sections.map(([l, c]) => `=== ${l} ===\\n${run(c)}`).join('\\n\\n');\n return { content: [{ type: 'text', text: out }] };\n }),\n\n tool('scan_aws_resources', 'AWS-Infrastruktur via AWS CLI scannen — 100% readonly (describe, list)', {\n region: z.string().optional().describe('AWS Region — default: AWS_DEFAULT_REGION oder Profil'),\n profile: z.string().optional().describe('AWS CLI Profil'),\n }, async (args) => {\n const { execSync } = await import('node:child_process');\n const region = args['region'] as string | undefined;\n const profile = args['profile'] as string | undefined;\n const env: NodeJS.ProcessEnv = { ...process.env };\n if (region) env['AWS_DEFAULT_REGION'] = region;\n const pf = profile ? `--profile ${profile}` : '';\n const run = (cmd: string): string => {\n try {\n return execSync(cmd, { stdio: 'pipe', timeout: 20_000, shell: '/bin/sh', env }).toString().trim();\n } catch (e) {\n return `(error: ${e instanceof Error ? e.message.split('\\n')[0] : String(e)})`;\n }\n };\n const sections: [string, string][] = [\n ['IDENTITY', `aws sts get-caller-identity ${pf} --output json`],\n ['EC2', `aws ec2 describe-instances ${pf} --query 'Reservations[*].Instances[*].[InstanceId,InstanceType,State.Name,PublicIpAddress,PrivateIpAddress,Tags[?Key==\\`Name\\`].Value|[0]]' --output table`],\n ['RDS', `aws rds describe-db-instances ${pf} --query 'DBInstances[*].[DBInstanceIdentifier,Engine,DBInstanceStatus,Endpoint.Address,Endpoint.Port]' --output table`],\n ['ELB_V2', `aws elbv2 describe-load-balancers ${pf} --query 'LoadBalancers[*].[LoadBalancerName,DNSName,Type,State.Code]' --output table`],\n ['EKS', `aws eks list-clusters ${pf} --output json`],\n ['ELASTICACHE', `aws elasticache describe-cache-clusters ${pf} --query 'CacheClusters[*].[CacheClusterId,Engine,CacheClusterStatus]' --output table 2>/dev/null || echo \"(nicht verfügbar)\"`],\n ['S3', `aws s3 ls ${pf} 2>/dev/null || echo \"(nicht verfügbar)\"`],\n ['VPC', `aws ec2 describe-vpcs ${pf} --query 'Vpcs[*].[VpcId,CidrBlock,IsDefault,Tags[?Key==\\`Name\\`].Value|[0]]' --output table`],\n ];\n const out = sections.map(([l, c]) => `=== ${l} ===\\n${run(c)}`).join('\\n\\n');\n return { content: [{ type: 'text', text: out }] };\n }),\n\n tool('scan_gcp_resources', 'Google Cloud Platform via gcloud CLI scannen — 100% readonly (list, describe)', {\n project: z.string().optional().describe('GCP Project ID — default: aktuelles gcloud-Projekt'),\n }, async (args) => {\n const { execSync } = await import('node:child_process');\n const project = args['project'] as string | undefined;\n const pf = project ? `--project ${project}` : '';\n const run = (cmd: string): string => {\n try {\n return execSync(cmd, { stdio: 'pipe', timeout: 20_000, shell: '/bin/sh' }).toString().trim();\n } catch (e) {\n return `(error: ${e instanceof Error ? e.message.split('\\n')[0] : String(e)})`;\n }\n };\n const sections: [string, string][] = [\n ['IDENTITY', `gcloud config list account --format='value(core.account)' 2>/dev/null; gcloud config get-value project 2>/dev/null`],\n ['COMPUTE_INSTANCES', `gcloud compute instances list ${pf} 2>/dev/null || echo \"(error)\"`],\n ['SQL_INSTANCES', `gcloud sql instances list ${pf} 2>/dev/null || echo \"(error)\"`],\n ['GKE_CLUSTERS', `gcloud container clusters list ${pf} 2>/dev/null || echo \"(error)\"`],\n ['CLOUD_RUN', `gcloud run services list ${pf} --platform managed 2>/dev/null || echo \"(error)\"`],\n ['CLOUD_FUNCTIONS', `gcloud functions list ${pf} 2>/dev/null || echo \"(error)\"`],\n ['REDIS', `gcloud redis instances list ${pf} --regions=- 2>/dev/null || echo \"(error)\"`],\n ['PUBSUB', `gcloud pubsub topics list ${pf} 2>/dev/null || echo \"(error)\"`],\n ['SPANNER', `gcloud spanner instances list ${pf} 2>/dev/null || echo \"(error)\"`],\n ];\n const out = sections.map(([l, c]) => `=== ${l} ===\\n${run(c)}`).join('\\n\\n');\n return { content: [{ type: 'text', text: out }] };\n }),\n\n tool('scan_azure_resources', 'Azure-Infrastruktur via az CLI scannen — 100% readonly (list, show)', {\n subscription: z.string().optional().describe('Azure Subscription ID'),\n resourceGroup: z.string().optional().describe('Resource Group filtern'),\n }, async (args) => {\n const { execSync } = await import('node:child_process');\n const sub = args['subscription'] as string | undefined;\n const rg = args['resourceGroup'] as string | undefined;\n const sf = sub ? `--subscription ${sub}` : '';\n const rf = rg ? `--resource-group ${rg}` : '';\n const run = (cmd: string): string => {\n try {\n return execSync(cmd, { stdio: 'pipe', timeout: 20_000, shell: '/bin/sh' }).toString().trim();\n } catch (e) {\n return `(error: ${e instanceof Error ? e.message.split('\\n')[0] : String(e)})`;\n }\n };\n const sections: [string, string][] = [\n ['IDENTITY', `az account show --output json ${sf} 2>/dev/null || echo \"(nicht eingeloggt — az login)\"`],\n ['VMS', `az vm list ${sf} ${rf} --output table 2>/dev/null || echo \"(error)\"`],\n ['AKS', `az aks list ${sf} ${rf} --output table 2>/dev/null || echo \"(error)\"`],\n ['SQL_SERVERS', `az sql server list ${sf} ${rf} --output table 2>/dev/null || echo \"(error)\"`],\n ['POSTGRES', `az postgres server list ${sf} ${rf} --output table 2>/dev/null || echo \"(error)\"`],\n ['REDIS', `az redis list ${sf} ${rf} --output table 2>/dev/null || echo \"(error)\"`],\n ['WEBAPPS', `az webapp list ${sf} ${rf} --output table 2>/dev/null || echo \"(error)\"`],\n ['CONTAINER_APPS', `az containerapp list ${sf} ${rf} --output table 2>/dev/null || echo \"(error)\"`],\n ['FUNCTIONS', `az functionapp list ${sf} ${rf} --output table 2>/dev/null || echo \"(error)\"`],\n ];\n const out = sections.map(([l, c]) => `=== ${l} ===\\n${run(c)}`).join('\\n\\n');\n return { content: [{ type: 'text', text: out }] };\n }),\n\n tool('save_sop', 'Standard Operating Procedure speichern', {\n workflowId: z.string(),\n title: z.string(),\n description: z.string(),\n steps: z.array(SOPStepSchema),\n involvedSystems: z.array(z.string()),\n estimatedDuration: z.string(),\n frequency: z.string(),\n confidence: z.number().min(0).max(1),\n }, async (args) => {\n db.insertSOP({\n workflowId: args['workflowId'] as string,\n title: args['title'] as string,\n description: args['description'] as string,\n steps: args['steps'] as ReturnType<typeof SOPStepSchema.parse>[],\n involvedSystems: args['involvedSystems'] as string[],\n estimatedDuration: args['estimatedDuration'] as string,\n frequency: args['frequency'] as string,\n confidence: args['confidence'] as number,\n });\n return { content: [{ type: 'text', text: `✓ SOP: ${args['title']}` }] };\n }),\n ];\n\n return createSdkMcpServer({\n name: 'cartography',\n version: '0.1.0',\n tools,\n });\n}\n","import { z } from 'zod';\n\n// ── Enums ────────────────────────────────\n\nexport const NODE_TYPES = [\n 'host', 'database_server', 'database', 'table',\n 'web_service', 'api_endpoint', 'cache_server',\n 'message_broker', 'queue', 'topic',\n 'container', 'pod', 'k8s_cluster',\n 'config_file', 'saas_tool', 'unknown',\n] as const;\nexport type NodeType = typeof NODE_TYPES[number];\n\nexport const EDGE_RELATIONSHIPS = [\n 'connects_to', 'reads_from', 'writes_to',\n 'calls', 'contains', 'depends_on',\n] as const;\nexport type EdgeRelationship = typeof EDGE_RELATIONSHIPS[number];\n\nexport const EVENT_TYPES = [\n 'process_start', 'process_end',\n 'connection_open', 'connection_close',\n 'window_focus', 'tool_switch',\n] as const;\nexport type EventType = typeof EVENT_TYPES[number];\n\n// ── Zod Schemas ──────────────────────────\n\nexport const NodeSchema = z.object({\n id: z.string().describe('Format: \"{type}:{host}:{port}\" oder \"{type}:{name}\"'),\n type: z.enum(NODE_TYPES),\n name: z.string(),\n discoveredVia: z.string(),\n confidence: z.number().min(0).max(1).default(0.5),\n metadata: z.record(z.unknown()).default({}),\n tags: z.array(z.string()).default([]),\n});\nexport type DiscoveryNode = z.infer<typeof NodeSchema>;\n\nexport const EdgeSchema = z.object({\n sourceId: z.string(),\n targetId: z.string(),\n relationship: z.enum(EDGE_RELATIONSHIPS),\n evidence: z.string(),\n confidence: z.number().min(0).max(1).default(0.5),\n});\nexport type DiscoveryEdge = z.infer<typeof EdgeSchema>;\n\nexport const EventSchema = z.object({\n eventType: z.enum(EVENT_TYPES),\n process: z.string(),\n pid: z.number(),\n target: z.string().optional(),\n targetType: z.enum(NODE_TYPES).optional(),\n protocol: z.string().optional(),\n port: z.number().optional(),\n});\nexport type ActivityEvent = z.infer<typeof EventSchema>;\n\nexport const SOPStepSchema = z.object({\n order: z.number(),\n instruction: z.string(),\n tool: z.string(),\n target: z.string().optional(),\n notes: z.string().optional(),\n});\nexport type SOPStep = z.infer<typeof SOPStepSchema>;\n\nexport const SOPSchema = z.object({\n title: z.string(),\n description: z.string(),\n steps: z.array(SOPStepSchema),\n involvedSystems: z.array(z.string()),\n estimatedDuration: z.string(),\n frequency: z.string(),\n confidence: z.number().min(0).max(1),\n});\nexport type SOP = z.infer<typeof SOPSchema>;\n\n// ── DB Row Types ─────────────────────────\n\nexport interface NodeRow extends DiscoveryNode {\n sessionId: string;\n discoveredAt: string;\n depth: number;\n pathId?: string;\n}\n\nexport interface EdgeRow extends DiscoveryEdge {\n id: string;\n sessionId: string;\n discoveredAt: string;\n pathId?: string;\n}\n\nexport interface EventRow {\n id: string;\n sessionId: string;\n taskId?: string;\n timestamp: string;\n eventType: EventType;\n process: string;\n pid: number;\n target?: string;\n targetType?: NodeType;\n port?: number;\n durationMs?: number;\n}\n\nexport interface TaskRow {\n id: string;\n sessionId: string;\n description?: string;\n startedAt: string;\n completedAt?: string;\n steps: string;\n involvedServices: string;\n status: 'active' | 'completed' | 'cancelled';\n isSOPCandidate: boolean;\n}\n\nexport interface WorkflowRow {\n id: string;\n sessionId: string;\n name?: string;\n pattern: string;\n taskIds: string;\n occurrences: number;\n firstSeen: string;\n lastSeen: string;\n avgDurationMs: number;\n involvedServices: string;\n}\n\nexport interface SessionRow {\n id: string;\n mode: 'discover' | 'shadow';\n startedAt: string;\n completedAt?: string;\n config: string;\n}\n\n// ── IPC Protokoll ────────────────────────\n\nexport type DaemonMessage =\n | { type: 'event'; data: EventRow }\n | { type: 'prompt'; id: string; prompt: PendingPrompt }\n | { type: 'status'; data: ShadowStatus }\n | { type: 'agent-output'; text: string }\n | { type: 'info'; message: string };\n\nexport type ClientMessage =\n | { type: 'prompt-response'; id: string; answer: string }\n | { type: 'command'; command: 'new-task' | 'end-task' | 'status' | 'stop' | 'pause' | 'resume' }\n | { type: 'task-description'; description: string };\n\nexport interface PendingPrompt {\n kind: 'node-approval' | 'task-boundary' | 'task-end';\n context: Record<string, unknown>;\n options: string[];\n defaultAnswer: string;\n timeoutMs: number;\n createdAt: string;\n}\n\nexport interface ShadowStatus {\n pid: number;\n uptime: number;\n nodeCount: number;\n eventCount: number;\n taskCount: number;\n sopCount: number;\n pendingPrompts: number;\n autoSave: boolean;\n mode: 'foreground' | 'daemon';\n agentActive: boolean;\n paused: boolean;\n cyclesRun: number;\n cyclesSkipped: number;\n}\n\n// ── Config ───────────────────────────────\n\nexport const MIN_POLL_INTERVAL_MS = 15_000; // 15s Minimum (Agent SDK Overhead)\n\nexport interface CartographyConfig {\n mode: 'discover' | 'shadow';\n maxDepth: number;\n maxTurns: number;\n entryPoints: string[];\n agentModel: string;\n shadowMode: 'foreground' | 'daemon';\n pollIntervalMs: number;\n inactivityTimeoutMs: number;\n promptTimeoutMs: number;\n trackWindowFocus: boolean;\n autoSaveNodes: boolean;\n enableNotifications: boolean;\n shadowModel: string;\n organization?: string;\n outputDir: string;\n dbPath: string;\n socketPath: string;\n pidFile: string;\n verbose: boolean;\n}\n\nexport function defaultConfig(overrides: Partial<CartographyConfig> = {}): CartographyConfig {\n const home = process.env.HOME ?? process.env.USERPROFILE ?? '/tmp';\n return {\n mode: 'discover',\n maxDepth: 8,\n maxTurns: 50,\n entryPoints: ['localhost'],\n agentModel: 'claude-sonnet-4-5-20250929',\n shadowMode: 'daemon',\n pollIntervalMs: 30_000,\n inactivityTimeoutMs: 300_000,\n promptTimeoutMs: 60_000,\n trackWindowFocus: false,\n autoSaveNodes: false,\n enableNotifications: true,\n shadowModel: 'claude-haiku-4-5-20251001',\n outputDir: './cartography-output',\n dbPath: `${home}/.cartography/cartography.db`,\n socketPath: `${home}/.cartography/daemon.sock`,\n pidFile: `${home}/.cartography/daemon.pid`,\n verbose: false,\n ...overrides,\n };\n}\n","import { homedir, tmpdir } from 'node:os';\nimport { existsSync, readFileSync, readdirSync, copyFileSync } from 'node:fs';\nimport { join } from 'node:path';\n\n// ── Types ─────────────────────────────────────────────────────────────────────\n\nexport interface BookmarkHost {\n hostname: string;\n port: number;\n protocol: 'http' | 'https';\n source: string;\n}\n\n// ── Helpers ───────────────────────────────────────────────────────────────────\n\nfunction extractHost(rawUrl: string, source: string): BookmarkHost | null {\n try {\n const u = new URL(rawUrl);\n if (u.protocol !== 'http:' && u.protocol !== 'https:') return null;\n const protocol = u.protocol === 'https:' ? 'https' as const : 'http' as const;\n // Strip: no paths, no params, no credentials — hostname only\n const port = u.port ? parseInt(u.port, 10) : (protocol === 'https' ? 443 : 80);\n const hostname = u.hostname.toLowerCase();\n if (!hostname || hostname === 'localhost' || hostname === '127.0.0.1') return null;\n return { hostname, port, protocol, source };\n } catch {\n return null;\n }\n}\n\n// Chrome/Edge/Brave JSON format\ninterface ChromeNode {\n type?: string;\n url?: string;\n children?: ChromeNode[];\n}\n\nfunction walkChrome(node: ChromeNode, source: string, out: BookmarkHost[]): void {\n if (node.type === 'url' && node.url) {\n const h = extractHost(node.url, source);\n if (h) out.push(h);\n }\n if (node.children) {\n for (const child of node.children) walkChrome(child, source, out);\n }\n}\n\nfunction readChromeLike(filePath: string, source: string): BookmarkHost[] {\n if (!existsSync(filePath)) return [];\n try {\n const raw = JSON.parse(readFileSync(filePath, 'utf8')) as {\n roots: Record<string, ChromeNode>;\n };\n const out: BookmarkHost[] = [];\n for (const root of Object.values(raw.roots)) {\n if (root) walkChrome(root, source, out);\n }\n return out;\n } catch {\n return [];\n }\n}\n\nasync function readFirefox(profileDir: string): Promise<BookmarkHost[]> {\n const src = join(profileDir, 'places.sqlite');\n if (!existsSync(src)) return [];\n const tmp = join(tmpdir(), `cartograph_ff_${Date.now()}.sqlite`);\n try {\n copyFileSync(src, tmp);\n const { default: Database } = await import('better-sqlite3');\n const db = new Database(tmp, { readonly: true, fileMustExist: true });\n const rows = db.prepare(`\n SELECT DISTINCT p.url\n FROM moz_places p\n JOIN moz_bookmarks b ON b.fk = p.id\n WHERE b.type = 1 AND p.url NOT LIKE 'place:%'\n LIMIT 3000\n `).all() as { url: string }[];\n db.close();\n return rows.map(r => extractHost(r.url, 'firefox')).filter((h): h is BookmarkHost => h !== null);\n } catch {\n return [];\n }\n}\n\n// ── Platform paths ────────────────────────────────────────────────────────────\n\nconst HOME = homedir();\nconst IS_MAC = process.platform === 'darwin';\n\nconst CHROME_PATHS = IS_MAC\n ? [`${HOME}/Library/Application Support/Google/Chrome/Default/Bookmarks`]\n : [`${HOME}/.config/google-chrome/Default/Bookmarks`];\n\nconst EDGE_PATHS = IS_MAC\n ? [`${HOME}/Library/Application Support/Microsoft Edge/Default/Bookmarks`]\n : [`${HOME}/.config/microsoft-edge/Default/Bookmarks`];\n\nconst BRAVE_PATHS = IS_MAC\n ? [`${HOME}/Library/Application Support/BraveSoftware/Brave-Browser/Default/Bookmarks`]\n : [`${HOME}/.config/BraveSoftware/Brave-Browser/Default/Bookmarks`];\n\nfunction firefoxProfileDirs(): string[] {\n const base = IS_MAC\n ? `${HOME}/Library/Application Support/Firefox/Profiles`\n : `${HOME}/.mozilla/firefox`;\n if (!existsSync(base)) return [];\n try {\n return readdirSync(base)\n .filter(d => d.includes('.default') || d.includes('-release'))\n .map(d => join(base, d));\n } catch {\n return [];\n }\n}\n\n// ── Public API ────────────────────────────────────────────────────────────────\n\nexport async function scanAllBookmarks(): Promise<BookmarkHost[]> {\n const all: BookmarkHost[] = [];\n\n for (const p of CHROME_PATHS) all.push(...readChromeLike(p, 'chrome'));\n for (const p of EDGE_PATHS) all.push(...readChromeLike(p, 'edge'));\n for (const p of BRAVE_PATHS) all.push(...readChromeLike(p, 'brave'));\n\n for (const dir of firefoxProfileDirs()) {\n all.push(...await readFirefox(dir));\n }\n\n // Deduplicate by hostname (port not included — same host on 80+443 = same service)\n const seen = new Set<string>();\n return all.filter(h => {\n const key = h.hostname;\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n });\n}\n","// PreToolUse Safety Hook — enforces read-only policy on all Bash calls\n\nimport type { HookCallback } from '@anthropic-ai/claude-code';\n\n// Word-boundary matched dangerous commands\nconst BLOCKED_CMDS =\n /\\b(rm|mv|cp|dd|mkfs|chmod|chown|chgrp|kill|killall|pkill|reboot|shutdown|poweroff|halt|systemctl\\s+(start|stop|restart|enable|disable)|service\\s+(start|stop|restart)|docker\\s+(rm|rmi|stop|kill|exec|run|build|push)|kubectl\\s+(delete|apply|edit|exec|run|create|patch)|apt|yum|dnf|pacman|pip\\s+install|npm\\s+(install|uninstall)|curl\\s+.*-X\\s*(POST|PUT|DELETE|PATCH)|wget\\s+-O|tee\\s)\\b/i;\n// Redirect operators (no word boundary needed)\nconst BLOCKED_REDIRECTS = />>|>[^>]/;\n\nexport type { HookCallback };\n\nexport const safetyHook: HookCallback = async (input) => {\n // Only intercept PreToolUse events (other hook events don't have tool_name)\n if (!('tool_name' in input)) return {};\n if ((input as { tool_name: string }).tool_name !== 'Bash') return {};\n\n const cmd = ((input as { tool_input: { command?: string } }).tool_input)?.command ?? '';\n\n if (BLOCKED_CMDS.test(cmd) || BLOCKED_REDIRECTS.test(cmd)) {\n return {\n hookSpecificOutput: {\n hookEventName: 'PreToolUse',\n permissionDecision: 'deny',\n permissionDecisionReason: `BLOCKED: \"${cmd}\" — read-only policy`,\n },\n };\n }\n\n return {\n hookSpecificOutput: {\n hookEventName: 'PreToolUse',\n permissionDecision: 'allow',\n },\n };\n};\n","import type { CartographyDB } from './db.js';\nimport { createCartographyTools } from './tools.js';\nimport { safetyHook } from './safety.js';\nimport type { CartographyConfig, TaskRow } from './types.js';\n\n// ── Discovery Event Types ────────────────────────────────────────────────────\n\nexport type DiscoveryEvent =\n | { kind: 'thinking'; text: string }\n | { kind: 'tool_call'; tool: string; input: Record<string, unknown> }\n | { kind: 'tool_result'; tool: string; output: string }\n | { kind: 'turn'; turn: number }\n | { kind: 'done' };\n\nexport type AskUserFn = (question: string, context?: string) => Promise<string>;\n\n// ── runDiscovery ─────────────────────────────────────────────────────────────\n\nexport async function runDiscovery(\n config: CartographyConfig,\n db: CartographyDB,\n sessionId: string,\n onEvent?: (event: DiscoveryEvent) => void,\n onAskUser?: AskUserFn,\n): Promise<void> {\n const { query } = await import('@anthropic-ai/claude-code');\n const tools = await createCartographyTools(db, sessionId, { onAskUser });\n\n const systemPrompt = `Du bist ein Infrastruktur-Discovery-Agent. Kartographiere die gesamte Systemlandschaft — lokale Services UND SaaS-Tools des Users.\n\n━━ PFLICHT-REIHENFOLGE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\nSCHRITT 1 — Browser-Lesezeichen (IMMER ZUERST):\n scan_bookmarks() aufrufen → jede zurückgegebene Domain klassifizieren:\n • Business-Tools (GitHub, Notion, Jira, Linear, Vercel, AWS, Datadog, etc.) → save_node als saas_tool\n • Interne Hosts (IPs, custom.company.com:PORT) → save_node als web_service\n • Persönliches (Social Media, News, Streaming, Shopping) → IGNORIEREN, NICHT speichern\n\nSCHRITT 2 — Lokale Infrastruktur:\n ss -tlnp && ps aux → alle lauschenden Ports/Prozesse identifizieren\n Jeden Service vertiefen: DB→Schemas, API→Endpoints, Queue→Topics\n\nSCHRITT 3 — Cloud & Kubernetes (falls CLI vorhanden):\n scan_k8s_resources() → Nodes, Services, Pods, Deployments, Ingresses\n scan_aws_resources() → EC2, RDS, ELB, EKS, ElastiCache, S3 (falls AWS CLI + Credentials)\n scan_gcp_resources() → Compute, SQL, GKE, Cloud Run, Functions (falls gcloud + Auth)\n scan_azure_resources() → VMs, AKS, SQL, Redis, WebApps (falls az CLI + Login)\n Fehler / \"nicht verfügbar\" → ignorieren, weiter mit nächstem Tool\n\nSCHRITT 4 — Config-Files:\n .env, docker-compose.yml, application.yml, kubernetes/*.yml\n Nur Host:Port extrahieren — KEINE Credentials\n\nSCHRITT 5 — Rückfragen bei Unklarheit:\n ask_user() nutzen wenn: Dienst unklar ist, Kontext fehlt, oder User Input sinnvoll wäre\n Beispiele: \"Welche Umgebung ist das (dev/staging/prod)?\", \"Ist <host> ein internes Tool?\"\n\nSCHRITT 6 — Fertig wenn alle Spuren erschöpft.\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\nPORT-MAPPING: 5432=postgres, 3306=mysql, 27017=mongodb, 6379=redis,\n9092=kafka, 5672=rabbitmq, 80/443/8080/3000=web_service,\n9090=prometheus, 8500=consul, 8200=vault, 2379=etcd\n\nREGELN:\n• Nur read-only (ss, ps, cat, head, curl -s, docker inspect, kubectl get)\n• Node IDs: \"type:host:port\" oder \"type:name\" — keine Pfade, keine Credentials\n• saas_tool IDs: \"saas_tool:github.com\", \"saas_tool:notion.so\"\n• Confidence: 0.9 direkt gesehen, 0.7 aus Config/Bookmarks, 0.5 Vermutung\n• metadata erlaubt: { description, category, port, version } — keine Passwörter\n• get_catalog vor save_node → Duplikate vermeiden\n• Edges speichern wenn Verbindungen klar erkennbar sind\n\nEntrypoints: ${config.entryPoints.join(', ')}`;\n\n const initialPrompt = `Starte Discovery jetzt.\nFühre SOFORT als erstes scan_bookmarks aus — noch bevor du ss oder ps verwendest.\nDann systematisch lokale Services, dann Config-Files.\nNutze ask_user wenn du Kontext vom User brauchst.`;\n\n let turnCount = 0;\n\n for await (const msg of query({\n prompt: initialPrompt,\n options: {\n model: config.agentModel,\n maxTurns: config.maxTurns,\n customSystemPrompt: systemPrompt,\n mcpServers: { cartography: tools },\n allowedTools: [\n 'Bash',\n 'mcp__cartograph__save_node',\n 'mcp__cartograph__save_edge',\n 'mcp__cartograph__get_catalog',\n 'mcp__cartograph__scan_bookmarks',\n 'mcp__cartograph__scan_k8s_resources',\n 'mcp__cartograph__scan_aws_resources',\n 'mcp__cartograph__scan_gcp_resources',\n 'mcp__cartograph__scan_azure_resources',\n 'mcp__cartograph__ask_user',\n ],\n hooks: {\n PreToolUse: [{ matcher: 'Bash', hooks: [safetyHook] }],\n },\n permissionMode: 'bypassPermissions',\n },\n })) {\n if (!onEvent) continue;\n\n if (msg.type === 'assistant') {\n turnCount++;\n onEvent({ kind: 'turn', turn: turnCount });\n\n for (const block of msg.message.content) {\n if (block.type === 'text') {\n onEvent({ kind: 'thinking', text: block.text });\n }\n if (block.type === 'tool_use') {\n onEvent({\n kind: 'tool_call',\n tool: block.name as string,\n input: block.input as Record<string, unknown>,\n });\n }\n }\n }\n\n if (msg.type === 'user') {\n const content = msg.message?.content;\n if (Array.isArray(content)) {\n for (const block of content) {\n if (typeof block === 'object' && block !== null && 'type' in block && (block as { type: string }).type === 'tool_result') {\n const tb = block as { tool_use_id?: string; content?: unknown };\n const text = typeof tb.content === 'string' ? tb.content : '';\n onEvent({ kind: 'tool_result', tool: tb.tool_use_id ?? '', output: text });\n }\n }\n }\n }\n\n if (msg.type === 'result') {\n onEvent({ kind: 'done' });\n return;\n }\n }\n}\n\n// ── runShadowCycle ───────────────────────────────────────────────────────────\n\nexport async function runShadowCycle(\n config: CartographyConfig,\n db: CartographyDB,\n sessionId: string,\n prevSnapshot: string,\n currSnapshot: string,\n onOutput?: (msg: unknown) => void,\n): Promise<void> {\n const { query } = await import('@anthropic-ai/claude-code');\n const tools = await createCartographyTools(db, sessionId);\n\n const prompt = `Analysiere den Diff zwischen diesen beiden System-Snapshots.\nFinde:\n- Neue/geschlossene TCP-Verbindungen → save_event\n- Neue/beendete Prozesse → save_event\n- Bisher unbekannte Services → get_catalog prüfen, dann save_node\n- Task-Grenzen (Inaktivität, Tool-Wechsel) → manage_task\ntarget = NUR Host:Port. Kurz und effizient.\n\n=== VORHER ===\n${prevSnapshot}\n\n=== JETZT ===\n${currSnapshot}`;\n\n for await (const msg of query({\n prompt,\n options: {\n model: config.shadowModel,\n maxTurns: 5,\n mcpServers: { cartography: tools },\n allowedTools: [\n 'mcp__cartograph__save_event',\n 'mcp__cartograph__save_node',\n 'mcp__cartograph__save_edge',\n 'mcp__cartograph__get_catalog',\n 'mcp__cartograph__manage_task',\n ],\n permissionMode: 'bypassPermissions',\n },\n })) {\n if (onOutput) onOutput(msg);\n }\n}\n\n// ── generateSOPs ─────────────────────────────────────────────────────────────\n\nexport async function generateSOPs(db: CartographyDB, sessionId: string): Promise<number> {\n const Anthropic = (await import('@anthropic-ai/sdk')).default;\n const client = new Anthropic();\n\n const tasks = db.getTasks(sessionId).filter(t => t.status === 'completed');\n if (tasks.length === 0) return 0;\n\n // Cluster tasks by involved services\n const clusters = clusterTasks(tasks);\n let generated = 0;\n\n for (const cluster of clusters) {\n const workflowId = crypto.randomUUID();\n const involved = JSON.parse(cluster[0]?.involvedServices ?? '[]') as string[];\n\n const taskDescriptions = cluster\n .map((t, i) => `Task ${i + 1}: ${t.description ?? 'Unnamed'}\\nSteps: ${t.steps}`)\n .join('\\n\\n');\n\n const response = await client.messages.create({\n model: 'claude-sonnet-4-5-20250929',\n max_tokens: 2048,\n messages: [{\n role: 'user',\n content: `Generiere eine SOP (Standard Operating Procedure) für diesen wiederkehrenden Workflow.\nAntworte NUR mit validen JSON im Format:\n{\n \"title\": \"...\",\n \"description\": \"...\",\n \"steps\": [{\"order\": 1, \"instruction\": \"...\", \"tool\": \"...\", \"target\": \"...\", \"notes\": \"...\"}],\n \"involvedSystems\": [\"...\"],\n \"estimatedDuration\": \"~N Minuten\",\n \"frequency\": \"Xmal täglich\",\n \"confidence\": 0.8\n}\n\nTasks:\n${taskDescriptions}\n\nBeteiligte Services: ${involved.join(', ')}`,\n }],\n });\n\n const text = response.content[0]?.type === 'text' ? response.content[0].text : '';\n\n try {\n const jsonMatch = text.match(/\\{[\\s\\S]*\\}/);\n if (!jsonMatch) continue;\n const parsed = JSON.parse(jsonMatch[0]) as {\n title: string;\n description: string;\n steps: Array<{ order: number; instruction: string; tool: string; target?: string; notes?: string }>;\n involvedSystems: string[];\n estimatedDuration: string;\n frequency: string;\n confidence: number;\n };\n\n db.insertSOP({ workflowId, ...parsed });\n generated++;\n } catch {\n // Skip malformed responses\n }\n }\n\n return generated;\n}\n\nfunction clusterTasks(tasks: TaskRow[]): TaskRow[][] {\n // Simple clustering: group by overlapping involved services\n const clusters: TaskRow[][] = [];\n const assigned = new Set<string>();\n\n for (const task of tasks) {\n if (assigned.has(task.id)) continue;\n\n const cluster = [task];\n assigned.add(task.id);\n\n const taskServices = new Set(JSON.parse(task.involvedServices ?? '[]') as string[]);\n\n for (const other of tasks) {\n if (assigned.has(other.id)) continue;\n const otherServices = new Set(JSON.parse(other.involvedServices ?? '[]') as string[]);\n // Check overlap\n const overlap = [...taskServices].filter(s => otherServices.has(s));\n if (overlap.length > 0) {\n cluster.push(other);\n assigned.add(other.id);\n }\n }\n\n clusters.push(cluster);\n }\n\n return clusters;\n}\n","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: '❓ Sonstige',\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 Force-Graph) ──────────────────────────────────────────────────\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 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=\"de\">\n<head>\n <meta charset=\"UTF-8\">\n <title>Cartography — Topology</title>\n <script src=\"https://d3js.org/d3.v7.min.js\"></script>\n <style>\n * { box-sizing: border-box; }\n body { margin: 0; background: #0d1117; color: #e6edf3; font-family: 'SF Mono', 'Fira Code', monospace; display: flex; }\n #graph { flex: 1; height: 100vh; }\n svg { width: 100%; height: 100%; }\n .link { stroke-opacity: 0.5; }\n .link-label { font-size: 9px; fill: #8b949e; }\n .node circle { stroke-width: 2px; cursor: pointer; transition: r 0.15s; }\n .node circle:hover { r: 14; }\n .node text { font-size: 11px; fill: #c9d1d9; pointer-events: none; }\n /* ── Sidebar ── */\n #sidebar {\n width: 300px; min-width: 300px; height: 100vh; overflow-y: auto;\n background: #161b22; border-left: 1px solid #30363d;\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 #21262d; vertical-align: top; }\n #sidebar .meta-table td:first-child { color: #8b949e; white-space: nowrap; width: 90px; }\n #sidebar .tag { display: inline-block; background: #21262d; border-radius: 3px; padding: 1px 5px; margin: 1px; }\n #sidebar .conf-bar { height: 6px; border-radius: 3px; background: #21262d; 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 #21262d; color: #8b949e; }\n #sidebar .edge-item span { color: #c9d1d9; }\n .hint { color: #484f58; font-size: 11px; margin-top: 8px; }\n #header { position: fixed; top: 10px; left: 10px; background: rgba(13,17,23,0.85);\n padding: 8px 12px; border-radius: 6px; font-size: 12px; border: 1px solid #30363d; }\n #header strong { color: #58a6ff; }\n </style>\n</head>\n<body>\n<div id=\"graph\">\n <div id=\"header\">\n <strong>Cartography</strong> \n <span style=\"color:#8b949e\">${nodes.length} Nodes · ${edges.length} Edges</span><br>\n <span style=\"color:#484f58;font-size:10px\">Scroll=zoom · Drag=pan · Click=details</span>\n </div>\n <svg></svg>\n</div>\n<div id=\"sidebar\">\n <h2>Infrastructure Map</h2>\n <p class=\"hint\">Klicke einen Node um Details anzuzeigen.</p>\n</div>\n<script>\nconst data = ${graphData};\n\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: '#da8bff', unknown: '#6c757d',\n};\n\nconst NODE_RADIUS = { saas_tool: 10, host: 11, database_server: 11, k8s_cluster: 13, default: 8 };\nconst radius = d => NODE_RADIUS[d.type] || NODE_RADIUS.default;\n\nconst sidebar = document.getElementById('sidebar');\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>Typ</td><td><span style=\"color:\\${c}\">\\${d.type}</span></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>Entdeckt via</td><td>\\${d.discoveredVia || '—'}</td></tr>\n <tr><td>Zeitpunkt</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>Verbindungen:</strong>'+edgeItems+'</div>' : ''}\n \\`;\n}\n\nconst svgEl = d3.select('svg');\nconst graphDiv = document.getElementById('graph');\nconst width = () => graphDiv.clientWidth;\nconst height = () => graphDiv.clientHeight;\nconst g = svgEl.append('g');\n\nsvgEl.call(d3.zoom().scaleExtent([0.1, 4]).on('zoom', e => g.attr('transform', e.transform)));\n\nconst sim = d3.forceSimulation(data.nodes)\n .force('link', d3.forceLink(data.links).id(d => d.id).distance(d => d.relationship === 'contains' ? 60 : 120))\n .force('charge', d3.forceManyBody().strength(-320))\n .force('center', d3.forceCenter(width() / 2, height() / 2))\n .force('collision', d3.forceCollide().radius(d => radius(d) + 20));\n\nconst link = g.append('g')\n .selectAll('line').data(data.links).join('line')\n .attr('class', 'link')\n .attr('stroke', d => d.confidence < 0.6 ? '#444' : '#555')\n .attr('stroke-dasharray', d => d.confidence < 0.6 ? '4 3' : null)\n .attr('stroke-width', d => d.confidence < 0.6 ? 1 : 1.5);\n\nlink.append('title').text(d => \\`\\${d.relationship} (conf:\\${d.confidence})\\n\\${d.evidence||''}\\`);\n\nconst node = g.append('g')\n .selectAll('g').data(data.nodes).join('g').attr('class', 'node')\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(); showNode(d); });\n\nnode.append('circle')\n .attr('r', radius)\n .attr('fill', d => TYPE_COLORS[d.type] || '#aaa')\n .attr('stroke', d => d3.color(TYPE_COLORS[d.type] || '#aaa').brighter(1).formatHex())\n .append('title').text(d => \\`\\${d.id}\\nconf:\\${d.confidence}\\`);\n\nnode.append('text').attr('dx', d => radius(d) + 4).attr('dy', '.35em').text(d => d.name);\n\nsim.on('tick', () => {\n link.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 node.attr('transform', d => \\`translate(\\${d.x},\\${d.y})\\`);\n});\n\nsvgEl.on('click', () => {\n sidebar.innerHTML = '<h2>Infrastructure Map</h2><p class=\"hint\">Klicke einen Node um Details anzuzeigen.</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 `**Beschreibung:** ${sop.description}`,\n `**Systeme:** ${sop.involvedSystems.join(', ')}`,\n `**Dauer:** ${sop.estimatedDuration}`,\n `**Häufigkeit:** ${sop.frequency}`,\n `**Confidence:** ${sop.confidence.toFixed(2)}`,\n '',\n '## Schritte',\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=\"de\">\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\">Beteiligte Systeme</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\">Keine SOPs vorhanden. Shadow-Daemon starten und Workflows beobachten.</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\">Generiert: \\${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","import { execSync } from 'node:child_process';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { MIN_POLL_INTERVAL_MS } from './types.js';\n\nfunction isOAuthLoggedIn(): boolean {\n // Claude CLI speichert OAuth-Tokens in ~/.claude/.credentials.json\n const home = process.env.HOME ?? process.env.USERPROFILE ?? '/tmp';\n const credFile = join(home, '.claude', '.credentials.json');\n if (!existsSync(credFile)) return false;\n try {\n const creds = JSON.parse(readFileSync(credFile, 'utf8')) as Record<string, unknown>;\n const oauth = creds['claudeAiOauth'] as Record<string, unknown> | undefined;\n return typeof oauth?.['accessToken'] === 'string' && oauth['accessToken'].length > 0;\n } catch {\n return false;\n }\n}\n\nexport function checkPrerequisites(): void {\n // Claude CLI vorhanden?\n try {\n execSync('claude --version', { stdio: 'pipe' });\n } catch {\n process.stderr.write(\n '\\n❌ Claude CLI nicht gefunden.\\n' +\n ' Datasynx Cartography braucht die Claude CLI als Runtime-Dependency.\\n\\n' +\n ' Installieren:\\n' +\n ' npm install -g @anthropic-ai/claude-code\\n' +\n ' # oder\\n' +\n ' curl -fsSL https://claude.ai/install.sh | bash\\n\\n' +\n ' Danach: claude login\\n\\n'\n );\n process.exitCode = 1;\n throw new Error('Claude CLI not found');\n }\n\n // Auth prüfen: API Key ODER OAuth-Login (claude.ai Subscription)\n const hasApiKey = Boolean(process.env.ANTHROPIC_API_KEY);\n const hasOAuth = isOAuthLoggedIn();\n\n if (!hasApiKey && !hasOAuth) {\n process.stderr.write(\n '⚠ Keine Authentifizierung gefunden. Bitte eine der folgenden Optionen:\\n\\n' +\n ' Option A — claude.ai Subscription (empfohlen):\\n' +\n ' claude login\\n\\n' +\n ' Option B — API Key:\\n' +\n ' export ANTHROPIC_API_KEY=sk-ant-...\\n\\n'\n );\n } else if (hasOAuth && !hasApiKey) {\n process.stderr.write('✓ Eingeloggt via claude login (Subscription)\\n');\n }\n}\n\nexport function checkPollInterval(intervalMs: number): number {\n if (intervalMs < MIN_POLL_INTERVAL_MS) {\n process.stderr.write(\n `⚠ Minimum Shadow-Intervall: ${MIN_POLL_INTERVAL_MS / 1000} Sekunden (Agent SDK Overhead)\\n`\n );\n return MIN_POLL_INTERVAL_MS;\n }\n return intervalMs;\n}\n"],"mappings":"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","names":["z","Database","z","execSync","mkdirSync","join","existsSync","readFileSync","join","join","existsSync","readFileSync"]}
|
|
1
|
+
{"version":3,"sources":["../src/db.ts","../src/tools.ts","../src/types.ts","../src/bookmarks.ts","../src/safety.ts","../src/agent.ts","../src/exporter.ts","../src/preflight.ts"],"sourcesContent":["import Database from 'better-sqlite3';\nimport { mkdirSync } from 'node:fs';\nimport { dirname } from 'node:path';\nimport type {\n CartographyConfig, DiscoveryNode, DiscoveryEdge, ActivityEvent,\n NodeRow, EdgeRow, EventRow, TaskRow, WorkflowRow, SessionRow, SOP,\n} from './types.js';\n\nconst SCHEMA = `\nPRAGMA journal_mode = WAL;\nPRAGMA foreign_keys = ON;\nPRAGMA busy_timeout = 5000;\n\nCREATE TABLE IF NOT EXISTS sessions (\n id TEXT PRIMARY KEY,\n mode TEXT NOT NULL CHECK (mode IN ('discover','shadow')),\n started_at TEXT NOT NULL,\n completed_at TEXT,\n config TEXT NOT NULL DEFAULT '{}'\n);\n\nCREATE TABLE IF NOT EXISTS nodes (\n id TEXT NOT NULL,\n session_id TEXT NOT NULL REFERENCES sessions(id),\n type TEXT NOT NULL,\n name TEXT NOT NULL,\n discovered_via TEXT,\n discovered_at TEXT NOT NULL,\n path_id TEXT,\n depth INTEGER DEFAULT 0,\n confidence REAL DEFAULT 0.5,\n metadata TEXT NOT NULL DEFAULT '{}',\n tags TEXT NOT NULL DEFAULT '[]',\n PRIMARY KEY (id, session_id)\n);\n\nCREATE TABLE IF NOT EXISTS edges (\n id TEXT PRIMARY KEY,\n session_id TEXT NOT NULL REFERENCES sessions(id),\n source_id TEXT NOT NULL,\n target_id TEXT NOT NULL,\n relationship TEXT NOT NULL,\n evidence TEXT,\n confidence REAL DEFAULT 0.5,\n discovered_at TEXT NOT NULL\n);\n\nCREATE TABLE IF NOT EXISTS activity_events (\n id TEXT PRIMARY KEY,\n session_id TEXT NOT NULL REFERENCES sessions(id),\n task_id TEXT,\n timestamp TEXT NOT NULL,\n event_type TEXT NOT NULL,\n process TEXT NOT NULL,\n pid INTEGER NOT NULL,\n target TEXT,\n target_type TEXT,\n port INTEGER,\n duration_ms INTEGER\n);\n\nCREATE TABLE IF NOT EXISTS tasks (\n id TEXT PRIMARY KEY,\n session_id TEXT NOT NULL REFERENCES sessions(id),\n description TEXT,\n started_at TEXT NOT NULL,\n completed_at TEXT,\n steps TEXT NOT NULL DEFAULT '[]',\n involved_services TEXT NOT NULL DEFAULT '[]',\n status TEXT DEFAULT 'active' CHECK (status IN ('active','completed','cancelled')),\n is_sop_candidate INTEGER DEFAULT 0\n);\n\nCREATE TABLE IF NOT EXISTS workflows (\n id TEXT PRIMARY KEY,\n session_id TEXT NOT NULL REFERENCES sessions(id),\n name TEXT,\n pattern TEXT NOT NULL,\n task_ids TEXT NOT NULL DEFAULT '[]',\n occurrences INTEGER DEFAULT 1,\n first_seen TEXT NOT NULL,\n last_seen TEXT NOT NULL,\n avg_duration_ms INTEGER,\n involved_services TEXT NOT NULL DEFAULT '[]'\n);\n\nCREATE TABLE IF NOT EXISTS sops (\n id TEXT PRIMARY KEY,\n workflow_id TEXT NOT NULL,\n title TEXT NOT NULL,\n description TEXT NOT NULL,\n steps TEXT NOT NULL,\n involved_systems TEXT NOT NULL DEFAULT '[]',\n estimated_duration TEXT,\n frequency TEXT,\n generated_at TEXT NOT NULL,\n confidence REAL DEFAULT 0.5\n);\n\nCREATE TABLE IF NOT EXISTS node_approvals (\n pattern TEXT PRIMARY KEY,\n action TEXT NOT NULL CHECK (action IN ('save','ignore','auto')),\n created_at TEXT NOT NULL\n);\n\nCREATE INDEX IF NOT EXISTS idx_nodes_session ON nodes(session_id);\nCREATE INDEX IF NOT EXISTS idx_edges_session ON edges(session_id);\nCREATE INDEX IF NOT EXISTS idx_events_session ON activity_events(session_id);\nCREATE INDEX IF NOT EXISTS idx_events_task ON activity_events(task_id);\nCREATE INDEX IF NOT EXISTS idx_tasks_session ON tasks(session_id);\n`;\n\nexport class CartographyDB {\n private db: Database.Database;\n\n constructor(dbPath: string) {\n mkdirSync(dirname(dbPath), { recursive: true });\n this.db = new Database(dbPath);\n this.db.pragma('journal_mode = WAL');\n this.db.pragma('foreign_keys = ON');\n this.db.pragma('busy_timeout = 5000');\n this.migrate();\n }\n\n private migrate(): void {\n const version = (this.db.pragma('user_version', { simple: true }) as number);\n if (version === 0) {\n this.db.exec(SCHEMA);\n this.db.pragma('user_version = 1');\n }\n }\n\n close(): void {\n this.db.pragma('optimize');\n this.db.close();\n }\n\n // ── Sessions ────────────────────────────\n\n createSession(mode: 'discover' | 'shadow', config: CartographyConfig): string {\n const id = crypto.randomUUID();\n this.db.prepare(\n 'INSERT INTO sessions (id, mode, started_at, config) VALUES (?, ?, ?, ?)'\n ).run(id, mode, new Date().toISOString(), JSON.stringify(config));\n return id;\n }\n\n endSession(id: string): void {\n this.db.prepare('UPDATE sessions SET completed_at = ? WHERE id = ?')\n .run(new Date().toISOString(), id);\n }\n\n getSession(id: string): SessionRow | undefined {\n const row = this.db.prepare('SELECT * FROM sessions WHERE id = ?').get(id) as Record<string, unknown> | undefined;\n return row ? this.mapSession(row) : undefined;\n }\n\n getLatestSession(mode?: string): SessionRow | undefined {\n const row = mode\n ? this.db.prepare('SELECT * FROM sessions WHERE mode = ? ORDER BY rowid DESC LIMIT 1').get(mode) as Record<string, unknown> | undefined\n : this.db.prepare('SELECT * FROM sessions ORDER BY rowid DESC LIMIT 1').get() as Record<string, unknown> | undefined;\n return row ? this.mapSession(row) : undefined;\n }\n\n getSessions(): SessionRow[] {\n const rows = this.db.prepare('SELECT * FROM sessions ORDER BY rowid DESC').all() as Record<string, unknown>[];\n return rows.map(r => this.mapSession(r));\n }\n\n private mapSession(r: Record<string, unknown>): SessionRow {\n return {\n id: r['id'] as string,\n mode: r['mode'] as 'discover' | 'shadow',\n startedAt: r['started_at'] as string,\n completedAt: (r['completed_at'] as string | null) ?? undefined,\n config: r['config'] as string,\n };\n }\n\n // ── Nodes ───────────────────────────────\n\n upsertNode(sessionId: string, node: DiscoveryNode, depth = 0): void {\n this.db.prepare(`\n INSERT OR REPLACE INTO nodes\n (id, session_id, type, name, discovered_via, discovered_at, depth, confidence, metadata, tags)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `).run(\n node.id, sessionId, node.type, node.name, node.discoveredVia,\n new Date().toISOString(), depth, node.confidence,\n JSON.stringify(node.metadata ?? {}),\n JSON.stringify(node.tags ?? []),\n );\n }\n\n getNodes(sessionId: string): NodeRow[] {\n const rows = this.db.prepare('SELECT * FROM nodes WHERE session_id = ?').all(sessionId) as Record<string, unknown>[];\n return rows.map(r => ({\n id: r['id'] as string,\n sessionId: r['session_id'] as string,\n type: r['type'] as NodeRow['type'],\n name: r['name'] as string,\n discoveredVia: r['discovered_via'] as string,\n discoveredAt: r['discovered_at'] as string,\n depth: r['depth'] as number,\n confidence: r['confidence'] as number,\n metadata: JSON.parse(r['metadata'] as string) as Record<string, unknown>,\n tags: JSON.parse(r['tags'] as string) as string[],\n pathId: r['path_id'] as string | undefined,\n }));\n }\n\n deleteNode(sessionId: string, nodeId: string): void {\n this.db.prepare('DELETE FROM nodes WHERE session_id = ? AND id = ?').run(sessionId, nodeId);\n // Remove orphaned edges\n this.db.prepare(\n 'DELETE FROM edges WHERE session_id = ? AND (source_id = ? OR target_id = ?)'\n ).run(sessionId, nodeId, nodeId);\n }\n\n // ── Edges ───────────────────────────────\n\n insertEdge(sessionId: string, edge: DiscoveryEdge): void {\n const id = crypto.randomUUID();\n this.db.prepare(`\n INSERT OR IGNORE INTO edges\n (id, session_id, source_id, target_id, relationship, evidence, confidence, discovered_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?)\n `).run(\n id, sessionId, edge.sourceId, edge.targetId,\n edge.relationship, edge.evidence, edge.confidence,\n new Date().toISOString(),\n );\n }\n\n getEdges(sessionId: string): EdgeRow[] {\n const rows = this.db.prepare('SELECT * FROM edges WHERE session_id = ?').all(sessionId) as Record<string, unknown>[];\n return rows.map(r => ({\n id: r['id'] as string,\n sessionId: r['session_id'] as string,\n sourceId: r['source_id'] as string,\n targetId: r['target_id'] as string,\n relationship: r['relationship'] as EdgeRow['relationship'],\n evidence: r['evidence'] as string,\n confidence: r['confidence'] as number,\n discoveredAt: r['discovered_at'] as string,\n }));\n }\n\n // ── Events ──────────────────────────────\n\n insertEvent(sessionId: string, event: ActivityEvent, taskId?: string): void {\n const id = crypto.randomUUID();\n this.db.prepare(`\n INSERT INTO activity_events\n (id, session_id, task_id, timestamp, event_type, process, pid, target, target_type, port)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `).run(\n id, sessionId, taskId ?? null, new Date().toISOString(),\n event.eventType, event.process, event.pid,\n event.target ?? null, event.targetType ?? null, event.port ?? null,\n );\n }\n\n getEvents(sessionId: string, since?: string): EventRow[] {\n const rows = since\n ? this.db.prepare('SELECT * FROM activity_events WHERE session_id = ? AND timestamp > ? ORDER BY timestamp').all(sessionId, since) as Record<string, unknown>[]\n : this.db.prepare('SELECT * FROM activity_events WHERE session_id = ? ORDER BY timestamp').all(sessionId) as Record<string, unknown>[];\n return rows.map(r => ({\n id: r['id'] as string,\n sessionId: r['session_id'] as string,\n taskId: r['task_id'] as string | undefined,\n timestamp: r['timestamp'] as string,\n eventType: r['event_type'] as EventRow['eventType'],\n process: r['process'] as string,\n pid: r['pid'] as number,\n target: r['target'] as string | undefined,\n targetType: r['target_type'] as EventRow['targetType'],\n port: r['port'] as number | undefined,\n durationMs: r['duration_ms'] as number | undefined,\n }));\n }\n\n // ── Tasks ───────────────────────────────\n\n startTask(sessionId: string, description?: string): string {\n const id = crypto.randomUUID();\n this.db.prepare(`\n INSERT INTO tasks (id, session_id, description, started_at, steps, involved_services, status)\n VALUES (?, ?, ?, ?, '[]', '[]', 'active')\n `).run(id, sessionId, description ?? null, new Date().toISOString());\n return id;\n }\n\n endCurrentTask(sessionId: string): void {\n this.db.prepare(`\n UPDATE tasks SET status = 'completed', completed_at = ?\n WHERE session_id = ? AND status = 'active'\n `).run(new Date().toISOString(), sessionId);\n }\n\n updateTaskDescription(sessionId: string, description: string): void {\n this.db.prepare(`\n UPDATE tasks SET description = ?\n WHERE session_id = ? AND status = 'active'\n `).run(description, sessionId);\n }\n\n getActiveTask(sessionId: string): TaskRow | undefined {\n const row = this.db.prepare(\n \"SELECT * FROM tasks WHERE session_id = ? AND status = 'active' LIMIT 1\"\n ).get(sessionId) as Record<string, unknown> | undefined;\n return row ? this.mapTask(row) : undefined;\n }\n\n getTasks(sessionId: string): TaskRow[] {\n const rows = this.db.prepare('SELECT * FROM tasks WHERE session_id = ? ORDER BY started_at').all(sessionId) as Record<string, unknown>[];\n return rows.map(r => this.mapTask(r));\n }\n\n private mapTask(r: Record<string, unknown>): TaskRow {\n return {\n id: r['id'] as string,\n sessionId: r['session_id'] as string,\n description: r['description'] as string | undefined,\n startedAt: r['started_at'] as string,\n completedAt: r['completed_at'] as string | undefined,\n steps: r['steps'] as string,\n involvedServices: r['involved_services'] as string,\n status: r['status'] as TaskRow['status'],\n isSOPCandidate: Boolean(r['is_sop_candidate']),\n };\n }\n\n // ── Workflows ───────────────────────────\n\n insertWorkflow(sessionId: string, data: Omit<WorkflowRow, 'id'>): void {\n const id = crypto.randomUUID();\n this.db.prepare(`\n INSERT INTO workflows\n (id, session_id, name, pattern, task_ids, occurrences,\n first_seen, last_seen, avg_duration_ms, involved_services)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `).run(\n id, sessionId, data.name ?? null, data.pattern,\n data.taskIds, data.occurrences,\n data.firstSeen, data.lastSeen, data.avgDurationMs,\n data.involvedServices,\n );\n }\n\n getWorkflows(sessionId: string): WorkflowRow[] {\n const rows = this.db.prepare('SELECT * FROM workflows WHERE session_id = ?').all(sessionId) as Record<string, unknown>[];\n return rows.map(r => ({\n id: r['id'] as string,\n sessionId: r['session_id'] as string,\n name: r['name'] as string | undefined,\n pattern: r['pattern'] as string,\n taskIds: r['task_ids'] as string,\n occurrences: r['occurrences'] as number,\n firstSeen: r['first_seen'] as string,\n lastSeen: r['last_seen'] as string,\n avgDurationMs: r['avg_duration_ms'] as number,\n involvedServices: r['involved_services'] as string,\n }));\n }\n\n // ── SOPs ────────────────────────────────\n\n insertSOP(sop: { workflowId: string } & SOP): void {\n const id = crypto.randomUUID();\n this.db.prepare(`\n INSERT INTO sops\n (id, workflow_id, title, description, steps, involved_systems,\n estimated_duration, frequency, generated_at, confidence)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `).run(\n id, sop.workflowId, sop.title, sop.description,\n JSON.stringify(sop.steps),\n JSON.stringify(sop.involvedSystems),\n sop.estimatedDuration, sop.frequency,\n new Date().toISOString(), sop.confidence,\n );\n }\n\n getSOPs(sessionId: string): Array<SOP & { id: string; workflowId: string }> {\n const rows = this.db.prepare(`\n SELECT s.* FROM sops s\n JOIN workflows w ON s.workflow_id = w.id\n WHERE w.session_id = ?\n `).all(sessionId) as Record<string, unknown>[];\n return rows.map(r => ({\n id: r['id'] as string,\n workflowId: r['workflow_id'] as string,\n title: r['title'] as string,\n description: r['description'] as string,\n steps: JSON.parse(r['steps'] as string) as SOP['steps'],\n involvedSystems: JSON.parse(r['involved_systems'] as string) as string[],\n estimatedDuration: r['estimated_duration'] as string,\n frequency: r['frequency'] as string,\n confidence: r['confidence'] as number,\n }));\n }\n\n markTaskAsSOPCandidate(taskId: string): void {\n this.db.prepare('UPDATE tasks SET is_sop_candidate = 1 WHERE id = ?').run(taskId);\n }\n\n getAllSOPs(): Array<SOP & { id: string; workflowId: string; generatedAt: string }> {\n const rows = this.db.prepare('SELECT * FROM sops ORDER BY generated_at DESC').all() as Record<string, unknown>[];\n return rows.map(r => ({\n id: r['id'] as string,\n workflowId: r['workflow_id'] as string,\n title: r['title'] as string,\n description: r['description'] as string,\n steps: JSON.parse(r['steps'] as string) as SOP['steps'],\n involvedSystems: JSON.parse(r['involved_systems'] as string) as string[],\n estimatedDuration: r['estimated_duration'] as string,\n frequency: r['frequency'] as string,\n confidence: r['confidence'] as number,\n generatedAt: r['generated_at'] as string,\n }));\n }\n\n // ── Approvals ───────────────────────────\n\n setApproval(pattern: string, action: 'save' | 'ignore' | 'auto'): void {\n this.db.prepare(`\n INSERT OR REPLACE INTO node_approvals (pattern, action, created_at) VALUES (?, ?, ?)\n `).run(pattern, action, new Date().toISOString());\n }\n\n getApproval(pattern: string): string | undefined {\n const row = this.db.prepare('SELECT action FROM node_approvals WHERE pattern = ?').get(pattern) as { action: string } | undefined;\n return row?.action;\n }\n\n // ── Stats ───────────────────────────────\n\n getStats(sessionId: string): { nodes: number; edges: number; events: number; tasks: number } {\n const nodes = (this.db.prepare('SELECT COUNT(*) as c FROM nodes WHERE session_id = ?').get(sessionId) as { c: number }).c;\n const edges = (this.db.prepare('SELECT COUNT(*) as c FROM edges WHERE session_id = ?').get(sessionId) as { c: number }).c;\n const events = (this.db.prepare('SELECT COUNT(*) as c FROM activity_events WHERE session_id = ?').get(sessionId) as { c: number }).c;\n const tasks = (this.db.prepare('SELECT COUNT(*) as c FROM tasks WHERE session_id = ?').get(sessionId) as { c: number }).c;\n return { nodes, edges, events, tasks };\n }\n}\n","import { z } from 'zod';\nimport type { CartographyDB } from './db.js';\nimport { NODE_TYPES, EDGE_RELATIONSHIPS, EVENT_TYPES, SOPStepSchema } from './types.js';\nimport { scanAllBookmarks } from './bookmarks.js';\n\n// Lazy import to avoid hard-wiring SDK at module parse time\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype McpServer = any;\n\nexport interface CartographyToolsOptions {\n /** Called when the agent needs a human answer. Return the user's response. */\n onAskUser?: (question: string, context?: string) => Promise<string>;\n}\n\nexport function stripSensitive(target: string): string {\n try {\n const url = new URL(target.startsWith('http') ? target : `tcp://${target}`);\n return `${url.hostname}${url.port ? ':' + url.port : ''}`;\n } catch {\n return target\n .replace(/\\/.*$/, '')\n .replace(/\\?.*$/, '')\n .replace(/@.*:/, ':');\n }\n}\n\nexport async function createCartographyTools(\n db: CartographyDB,\n sessionId: string,\n opts: CartographyToolsOptions = {},\n): Promise<McpServer> {\n // Dynamically import the SDK so missing package doesn't crash at load time\n const sdk = await import('@anthropic-ai/claude-code');\n const { tool, createSdkMcpServer } = sdk as {\n tool: (name: string, description: string, schema: z.ZodRawShape, handler: (args: Record<string, unknown>) => Promise<{ content: Array<{ type: string; text: string }> }>) => unknown;\n createSdkMcpServer: (opts: { name: string; version: string; tools: unknown[] }) => McpServer;\n };\n\n const tools = [\n tool('save_node', 'Infrastructure-Node speichern', {\n id: z.string(),\n type: z.enum(NODE_TYPES),\n name: z.string(),\n discoveredVia: z.string(),\n confidence: z.number().min(0).max(1),\n metadata: z.record(z.unknown()).optional(),\n tags: z.array(z.string()).optional(),\n }, async (args) => {\n const node = {\n id: stripSensitive(args['id'] as string),\n type: args['type'] as typeof NODE_TYPES[number],\n name: args['name'] as string,\n discoveredVia: args['discoveredVia'] as string,\n confidence: args['confidence'] as number,\n metadata: (args['metadata'] as Record<string, unknown>) ?? {},\n tags: (args['tags'] as string[]) ?? [],\n };\n db.upsertNode(sessionId, node);\n return { content: [{ type: 'text', text: `✓ Node: ${node.id}` }] };\n }),\n\n tool('save_edge', 'Verbindung zwischen zwei Nodes speichern', {\n sourceId: z.string(),\n targetId: z.string(),\n relationship: z.enum(EDGE_RELATIONSHIPS),\n evidence: z.string(),\n confidence: z.number().min(0).max(1),\n }, async (args) => {\n db.insertEdge(sessionId, {\n sourceId: args['sourceId'] as string,\n targetId: args['targetId'] as string,\n relationship: args['relationship'] as typeof EDGE_RELATIONSHIPS[number],\n evidence: args['evidence'] as string,\n confidence: args['confidence'] as number,\n });\n return { content: [{ type: 'text', text: `✓ ${args['sourceId']}→${args['targetId']}` }] };\n }),\n\n tool('save_event', 'Activity-Event (Prozess/Verbindung) speichern', {\n eventType: z.enum(EVENT_TYPES),\n process: z.string(),\n pid: z.number(),\n target: z.string().optional(),\n targetType: z.enum(NODE_TYPES).optional(),\n port: z.number().optional(),\n }, async (args) => {\n db.insertEvent(sessionId, {\n eventType: args['eventType'] as typeof EVENT_TYPES[number],\n process: args['process'] as string,\n pid: args['pid'] as number,\n target: args['target'] ? stripSensitive(args['target'] as string) : undefined,\n targetType: args['targetType'] as typeof NODE_TYPES[number] | undefined,\n port: args['port'] as number | undefined,\n });\n return { content: [{ type: 'text', text: `✓ ${args['eventType']}` }] };\n }),\n\n tool('get_catalog', 'Aktuellen Katalog abrufen (Duplikat-Check)', {\n includeEdges: z.boolean().default(true),\n }, async (args) => {\n const nodes = db.getNodes(sessionId);\n const edges = (args['includeEdges'] as boolean) ? db.getEdges(sessionId) : [];\n return {\n content: [{\n type: 'text',\n text: JSON.stringify({\n count: { nodes: nodes.length, edges: edges.length },\n nodeIds: nodes.map(n => n.id),\n }),\n }],\n };\n }),\n\n tool('manage_task', 'Task starten, beenden oder beschreiben', {\n action: z.enum(['start', 'end', 'describe']),\n description: z.string().optional(),\n }, async (args) => {\n const action = args['action'] as string;\n if (action === 'start') {\n const id = db.startTask(sessionId, args['description'] as string | undefined);\n return { content: [{ type: 'text', text: `✓ Task gestartet: ${id}` }] };\n }\n if (action === 'end') {\n db.endCurrentTask(sessionId);\n return { content: [{ type: 'text', text: '✓ Task beendet' }] };\n }\n db.updateTaskDescription(sessionId, args['description'] as string);\n return { content: [{ type: 'text', text: '✓ Beschreibung aktualisiert' }] };\n }),\n\n tool('ask_user', 'Rückfrage an den User stellen — bei Unklarheiten, fehlenden Credentials-Hinweisen oder wenn Kontext fehlt', {\n question: z.string().describe('Die Frage an den User (klar und konkret)'),\n context: z.string().optional().describe('Optionaler Zusatzkontext warum die Frage relevant ist'),\n }, async (args) => {\n const question = args['question'] as string;\n const context = args['context'] as string | undefined;\n\n if (opts.onAskUser) {\n const answer = await opts.onAskUser(question, context);\n return { content: [{ type: 'text', text: answer }] };\n }\n\n // Fallback when not interactive (piped input, daemon, etc.)\n return {\n content: [{ type: 'text', text: '(Kein interaktiver Modus — bitte ohne diese Information fortfahren)' }],\n };\n }),\n\n tool('scan_bookmarks', 'Alle Browser-Lesezeichen scannen — nur Hostnamen, keine persönlichen Daten', {\n minConfidence: z.number().min(0).max(1).default(0.5).optional(),\n }, async () => {\n const hosts = await scanAllBookmarks();\n return {\n content: [{\n type: 'text',\n text: JSON.stringify({\n count: hosts.length,\n hosts: hosts.map(h => ({\n hostname: h.hostname,\n port: h.port,\n protocol: h.protocol,\n source: h.source,\n })),\n note: 'Nur Hostnamen — keine Pfade, keine persönlichen Daten. Entscheide selbst welche davon Business-Tools sind.',\n }),\n }],\n };\n }),\n\n tool('scan_k8s_resources', 'Kubernetes-Cluster via kubectl scannen — 100% readonly (get, describe)', {\n namespace: z.string().optional().describe('Namespace filtern — leer = alle Namespaces'),\n }, async (args) => {\n const { execSync } = await import('node:child_process');\n const ns = args['namespace'] as string | undefined;\n const nsFlag = ns ? `-n ${ns}` : '--all-namespaces';\n const run = (cmd: string): string => {\n try {\n return execSync(cmd, { stdio: 'pipe', timeout: 15_000, shell: '/bin/sh' }).toString().trim();\n } catch (e) {\n return `(error: ${e instanceof Error ? e.message.split('\\n')[0] : String(e)})`;\n }\n };\n const sections: [string, string][] = [\n ['CONTEXT', 'kubectl config current-context 2>/dev/null || echo \"(kein Context gesetzt)\"'],\n ['NODES', 'kubectl get nodes -o wide'],\n ['NAMESPACES', 'kubectl get namespaces'],\n ['SERVICES', `kubectl get services ${nsFlag}`],\n ['DEPLOYMENTS', `kubectl get deployments ${nsFlag}`],\n ['STATEFULSETS', `kubectl get statefulsets ${nsFlag}`],\n ['INGRESSES', `kubectl get ingress ${nsFlag} 2>/dev/null || echo \"(keine)\"`],\n ['PODS_RUNNING', `kubectl get pods ${nsFlag} --field-selector=status.phase=Running 2>/dev/null | head -60`],\n ['CONFIGMAPS_SYSTEM', 'kubectl get configmaps -n kube-system 2>/dev/null | head -30'],\n ];\n const out = sections.map(([l, c]) => `=== ${l} ===\\n${run(c)}`).join('\\n\\n');\n return { content: [{ type: 'text', text: out }] };\n }),\n\n tool('scan_aws_resources', 'AWS-Infrastruktur via AWS CLI scannen — 100% readonly (describe, list)', {\n region: z.string().optional().describe('AWS Region — default: AWS_DEFAULT_REGION oder Profil'),\n profile: z.string().optional().describe('AWS CLI Profil'),\n }, async (args) => {\n const { execSync } = await import('node:child_process');\n const region = args['region'] as string | undefined;\n const profile = args['profile'] as string | undefined;\n const env: NodeJS.ProcessEnv = { ...process.env };\n if (region) env['AWS_DEFAULT_REGION'] = region;\n const pf = profile ? `--profile ${profile}` : '';\n const run = (cmd: string): string => {\n try {\n return execSync(cmd, { stdio: 'pipe', timeout: 20_000, shell: '/bin/sh', env }).toString().trim();\n } catch (e) {\n return `(error: ${e instanceof Error ? e.message.split('\\n')[0] : String(e)})`;\n }\n };\n const sections: [string, string][] = [\n ['IDENTITY', `aws sts get-caller-identity ${pf} --output json`],\n ['EC2', `aws ec2 describe-instances ${pf} --query 'Reservations[*].Instances[*].[InstanceId,InstanceType,State.Name,PublicIpAddress,PrivateIpAddress,Tags[?Key==\\`Name\\`].Value|[0]]' --output table`],\n ['RDS', `aws rds describe-db-instances ${pf} --query 'DBInstances[*].[DBInstanceIdentifier,Engine,DBInstanceStatus,Endpoint.Address,Endpoint.Port]' --output table`],\n ['ELB_V2', `aws elbv2 describe-load-balancers ${pf} --query 'LoadBalancers[*].[LoadBalancerName,DNSName,Type,State.Code]' --output table`],\n ['EKS', `aws eks list-clusters ${pf} --output json`],\n ['ELASTICACHE', `aws elasticache describe-cache-clusters ${pf} --query 'CacheClusters[*].[CacheClusterId,Engine,CacheClusterStatus]' --output table 2>/dev/null || echo \"(nicht verfügbar)\"`],\n ['S3', `aws s3 ls ${pf} 2>/dev/null || echo \"(nicht verfügbar)\"`],\n ['VPC', `aws ec2 describe-vpcs ${pf} --query 'Vpcs[*].[VpcId,CidrBlock,IsDefault,Tags[?Key==\\`Name\\`].Value|[0]]' --output table`],\n ];\n const out = sections.map(([l, c]) => `=== ${l} ===\\n${run(c)}`).join('\\n\\n');\n return { content: [{ type: 'text', text: out }] };\n }),\n\n tool('scan_gcp_resources', 'Google Cloud Platform via gcloud CLI scannen — 100% readonly (list, describe)', {\n project: z.string().optional().describe('GCP Project ID — default: aktuelles gcloud-Projekt'),\n }, async (args) => {\n const { execSync } = await import('node:child_process');\n const project = args['project'] as string | undefined;\n const pf = project ? `--project ${project}` : '';\n const run = (cmd: string): string => {\n try {\n return execSync(cmd, { stdio: 'pipe', timeout: 20_000, shell: '/bin/sh' }).toString().trim();\n } catch (e) {\n return `(error: ${e instanceof Error ? e.message.split('\\n')[0] : String(e)})`;\n }\n };\n const sections: [string, string][] = [\n ['IDENTITY', `gcloud config list account --format='value(core.account)' 2>/dev/null; gcloud config get-value project 2>/dev/null`],\n ['COMPUTE_INSTANCES', `gcloud compute instances list ${pf} 2>/dev/null || echo \"(error)\"`],\n ['SQL_INSTANCES', `gcloud sql instances list ${pf} 2>/dev/null || echo \"(error)\"`],\n ['GKE_CLUSTERS', `gcloud container clusters list ${pf} 2>/dev/null || echo \"(error)\"`],\n ['CLOUD_RUN', `gcloud run services list ${pf} --platform managed 2>/dev/null || echo \"(error)\"`],\n ['CLOUD_FUNCTIONS', `gcloud functions list ${pf} 2>/dev/null || echo \"(error)\"`],\n ['REDIS', `gcloud redis instances list ${pf} --regions=- 2>/dev/null || echo \"(error)\"`],\n ['PUBSUB', `gcloud pubsub topics list ${pf} 2>/dev/null || echo \"(error)\"`],\n ['SPANNER', `gcloud spanner instances list ${pf} 2>/dev/null || echo \"(error)\"`],\n ];\n const out = sections.map(([l, c]) => `=== ${l} ===\\n${run(c)}`).join('\\n\\n');\n return { content: [{ type: 'text', text: out }] };\n }),\n\n tool('scan_azure_resources', 'Azure-Infrastruktur via az CLI scannen — 100% readonly (list, show)', {\n subscription: z.string().optional().describe('Azure Subscription ID'),\n resourceGroup: z.string().optional().describe('Resource Group filtern'),\n }, async (args) => {\n const { execSync } = await import('node:child_process');\n const sub = args['subscription'] as string | undefined;\n const rg = args['resourceGroup'] as string | undefined;\n const sf = sub ? `--subscription ${sub}` : '';\n const rf = rg ? `--resource-group ${rg}` : '';\n const run = (cmd: string): string => {\n try {\n return execSync(cmd, { stdio: 'pipe', timeout: 20_000, shell: '/bin/sh' }).toString().trim();\n } catch (e) {\n return `(error: ${e instanceof Error ? e.message.split('\\n')[0] : String(e)})`;\n }\n };\n const sections: [string, string][] = [\n ['IDENTITY', `az account show --output json ${sf} 2>/dev/null || echo \"(nicht eingeloggt — az login)\"`],\n ['VMS', `az vm list ${sf} ${rf} --output table 2>/dev/null || echo \"(error)\"`],\n ['AKS', `az aks list ${sf} ${rf} --output table 2>/dev/null || echo \"(error)\"`],\n ['SQL_SERVERS', `az sql server list ${sf} ${rf} --output table 2>/dev/null || echo \"(error)\"`],\n ['POSTGRES', `az postgres server list ${sf} ${rf} --output table 2>/dev/null || echo \"(error)\"`],\n ['REDIS', `az redis list ${sf} ${rf} --output table 2>/dev/null || echo \"(error)\"`],\n ['WEBAPPS', `az webapp list ${sf} ${rf} --output table 2>/dev/null || echo \"(error)\"`],\n ['CONTAINER_APPS', `az containerapp list ${sf} ${rf} --output table 2>/dev/null || echo \"(error)\"`],\n ['FUNCTIONS', `az functionapp list ${sf} ${rf} --output table 2>/dev/null || echo \"(error)\"`],\n ];\n const out = sections.map(([l, c]) => `=== ${l} ===\\n${run(c)}`).join('\\n\\n');\n return { content: [{ type: 'text', text: out }] };\n }),\n\n tool('scan_installed_apps', 'Alle installierten Apps und Tools auf dem PC scannen — IDEs, Office, Dev-Tools, Business-Apps', {\n searchHint: z.string().optional().describe('Optionaler Suchbegriff um gezielt nach bestimmten Tools zu suchen (z.B. \"hubspot windsurf cursor\")'),\n }, async (args) => {\n const { execSync } = await import('node:child_process');\n const hint = args['searchHint'] as string | undefined;\n\n const run = (cmd: string): string => {\n try {\n return execSync(cmd, { stdio: 'pipe', timeout: 15_000, shell: '/bin/sh' }).toString().trim();\n } catch {\n return '';\n }\n };\n\n const platform = process.platform;\n const results: Record<string, string> = {};\n\n if (platform === 'darwin') {\n // macOS: scan /Applications\n results['APPLICATIONS'] = run('ls /Applications/ 2>/dev/null | head -200') || '(leer)';\n results['USER_APPLICATIONS'] = run('ls ~/Applications/ 2>/dev/null | head -100') || '(leer)';\n // Homebrew\n results['BREW_CASKS'] = run('brew list --cask 2>/dev/null | head -100') || '(brew nicht installiert)';\n results['BREW_FORMULAE'] = run('brew list --formula 2>/dev/null | head -150') || '(brew nicht installiert)';\n // Spotlight — find .app bundles\n results['SPOTLIGHT_APPS'] = run('mdfind \"kMDItemKind == \\'Application\\'\" 2>/dev/null | grep -v \"^/System\" | grep -v \"^/Library/Apple\" | head -100') || '(Spotlight nicht verfügbar)';\n } else if (platform === 'linux') {\n // Linux: dpkg, snap, flatpak, .desktop files\n results['DPKG'] = run('dpkg --list 2>/dev/null | awk \\'{print $2}\\' | head -200') || '(dpkg nicht verfügbar)';\n results['SNAP'] = run('snap list 2>/dev/null | head -50') || '(snap nicht verfügbar)';\n results['FLATPAK'] = run('flatpak list 2>/dev/null | head -50') || '(flatpak nicht verfügbar)';\n results['DESKTOP_FILES'] = run('ls /usr/share/applications/*.desktop ~/.local/share/applications/*.desktop 2>/dev/null | xargs -I{} basename {} .desktop 2>/dev/null | head -100') || '(keine .desktop files)';\n results['RPM'] = run('rpm -qa 2>/dev/null | head -200') || '(rpm nicht verfügbar)';\n } else if (platform === 'win32') {\n results['WINGET'] = run('winget list 2>/dev/null | head -100') || '(winget nicht verfügbar)';\n results['PROGRAMS_x64'] = run('reg query \"HKLM\\\\Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Uninstall\" /s /v DisplayName 2>/dev/null | findstr DisplayName | head -100') || '(nicht verfügbar)';\n }\n\n // Check known dev/business tools via `which`\n const knownTools = [\n // IDEs & Editors\n 'code', 'code-insiders', 'cursor', 'windsurf', 'zed', 'vim', 'nvim', 'emacs', 'nano', 'sublime_text', 'atom',\n 'idea', 'webstorm', 'pycharm', 'goland', 'datagrip', 'clion', 'rider', 'phpstorm', 'rubymine', 'appcode',\n // Dev Tools\n 'git', 'gh', 'docker', 'docker-compose', 'podman', 'kubectl', 'helm', 'terraform', 'ansible',\n 'node', 'npm', 'npx', 'yarn', 'pnpm', 'bun', 'deno',\n 'python', 'python3', 'pip', 'pip3', 'pipenv', 'poetry', 'conda',\n 'ruby', 'gem', 'bundler', 'rails',\n 'java', 'mvn', 'gradle', 'kotlin',\n 'go', 'cargo', 'rustc',\n 'php', 'composer',\n 'dotnet', 'dotnet-sdk',\n // Databases\n 'psql', 'mysql', 'mysqladmin', 'mongo', 'mongosh', 'redis-cli', 'sqlite3', 'clickhouse-client',\n // Cloud CLIs\n 'aws', 'gcloud', 'az', 'heroku', 'fly', 'vercel', 'netlify', 'wrangler',\n // Infra\n 'vagrant', 'packer', 'consul', 'vault', 'nomad',\n // Communication / SaaS\n 'slack', 'discord', 'zoom', 'teams', 'skype', 'telegram', 'signal',\n // Browsers\n 'google-chrome', 'chromium', 'firefox', 'safari', 'brave', 'opera', 'edge',\n // Monitoring / Analytics\n 'datadog-agent', 'newrelic-agent', 'prometheus', 'grafana-cli',\n // Other tools\n 'ngrok', 'stripe', 'supabase', 'neon',\n ];\n\n const found: string[] = [];\n const notFound: string[] = [];\n for (const t of knownTools) {\n const r = run(`which ${t} 2>/dev/null`);\n if (r) found.push(`${t}: ${r}`);\n else notFound.push(t);\n }\n results['WHICH_FOUND'] = found.join('\\n') || '(nichts gefunden)';\n results['WHICH_NOT_FOUND'] = notFound.join(', ');\n\n // Hint-based search: if user asks for specific tools, do targeted search\n if (hint) {\n const terms = hint.split(/[\\s,]+/).filter(Boolean);\n const hintResults: string[] = [];\n for (const term of terms) {\n const safe = term.replace(/[^a-zA-Z0-9._-]/g, '');\n if (!safe) continue;\n const r = run(`which ${safe} 2>/dev/null || find /Applications ~/Applications /usr/bin /usr/local/bin /opt/homebrew/bin ~/.local/bin 2>/dev/null -iname \"*${safe}*\" -maxdepth 3 2>/dev/null | head -5`);\n if (r) hintResults.push(`${term}: ${r}`);\n else hintResults.push(`${term}: (nicht gefunden)`);\n }\n results['HINT_SEARCH'] = hintResults.join('\\n');\n }\n\n const out = Object.entries(results)\n .map(([k, v]) => `=== ${k} ===\\n${v}`)\n .join('\\n\\n');\n\n return { content: [{ type: 'text', text: out }] };\n }),\n\n tool('save_sop', 'Standard Operating Procedure speichern', {\n workflowId: z.string(),\n title: z.string(),\n description: z.string(),\n steps: z.array(SOPStepSchema),\n involvedSystems: z.array(z.string()),\n estimatedDuration: z.string(),\n frequency: z.string(),\n confidence: z.number().min(0).max(1),\n }, async (args) => {\n db.insertSOP({\n workflowId: args['workflowId'] as string,\n title: args['title'] as string,\n description: args['description'] as string,\n steps: args['steps'] as ReturnType<typeof SOPStepSchema.parse>[],\n involvedSystems: args['involvedSystems'] as string[],\n estimatedDuration: args['estimatedDuration'] as string,\n frequency: args['frequency'] as string,\n confidence: args['confidence'] as number,\n });\n return { content: [{ type: 'text', text: `✓ SOP: ${args['title']}` }] };\n }),\n ];\n\n return createSdkMcpServer({\n name: 'cartography',\n version: '0.1.0',\n tools,\n });\n}\n","import { z } from 'zod';\n\n// ── Enums ────────────────────────────────\n\nexport const NODE_TYPES = [\n 'host', 'database_server', 'database', 'table',\n 'web_service', 'api_endpoint', 'cache_server',\n 'message_broker', 'queue', 'topic',\n 'container', 'pod', 'k8s_cluster',\n 'config_file', 'saas_tool', 'unknown',\n] as const;\nexport type NodeType = typeof NODE_TYPES[number];\n\nexport const EDGE_RELATIONSHIPS = [\n 'connects_to', 'reads_from', 'writes_to',\n 'calls', 'contains', 'depends_on',\n] as const;\nexport type EdgeRelationship = typeof EDGE_RELATIONSHIPS[number];\n\nexport const EVENT_TYPES = [\n 'process_start', 'process_end',\n 'connection_open', 'connection_close',\n 'window_focus', 'tool_switch',\n] as const;\nexport type EventType = typeof EVENT_TYPES[number];\n\n// ── Zod Schemas ──────────────────────────\n\nexport const NodeSchema = z.object({\n id: z.string().describe('Format: \"{type}:{host}:{port}\" oder \"{type}:{name}\"'),\n type: z.enum(NODE_TYPES),\n name: z.string(),\n discoveredVia: z.string(),\n confidence: z.number().min(0).max(1).default(0.5),\n metadata: z.record(z.unknown()).default({}),\n tags: z.array(z.string()).default([]),\n});\nexport type DiscoveryNode = z.infer<typeof NodeSchema>;\n\nexport const EdgeSchema = z.object({\n sourceId: z.string(),\n targetId: z.string(),\n relationship: z.enum(EDGE_RELATIONSHIPS),\n evidence: z.string(),\n confidence: z.number().min(0).max(1).default(0.5),\n});\nexport type DiscoveryEdge = z.infer<typeof EdgeSchema>;\n\nexport const EventSchema = z.object({\n eventType: z.enum(EVENT_TYPES),\n process: z.string(),\n pid: z.number(),\n target: z.string().optional(),\n targetType: z.enum(NODE_TYPES).optional(),\n protocol: z.string().optional(),\n port: z.number().optional(),\n});\nexport type ActivityEvent = z.infer<typeof EventSchema>;\n\nexport const SOPStepSchema = z.object({\n order: z.number(),\n instruction: z.string(),\n tool: z.string(),\n target: z.string().optional(),\n notes: z.string().optional(),\n});\nexport type SOPStep = z.infer<typeof SOPStepSchema>;\n\nexport const SOPSchema = z.object({\n title: z.string(),\n description: z.string(),\n steps: z.array(SOPStepSchema),\n involvedSystems: z.array(z.string()),\n estimatedDuration: z.string(),\n frequency: z.string(),\n confidence: z.number().min(0).max(1),\n});\nexport type SOP = z.infer<typeof SOPSchema>;\n\n// ── DB Row Types ─────────────────────────\n\nexport interface NodeRow extends DiscoveryNode {\n sessionId: string;\n discoveredAt: string;\n depth: number;\n pathId?: string;\n}\n\nexport interface EdgeRow extends DiscoveryEdge {\n id: string;\n sessionId: string;\n discoveredAt: string;\n pathId?: string;\n}\n\nexport interface EventRow {\n id: string;\n sessionId: string;\n taskId?: string;\n timestamp: string;\n eventType: EventType;\n process: string;\n pid: number;\n target?: string;\n targetType?: NodeType;\n port?: number;\n durationMs?: number;\n}\n\nexport interface TaskRow {\n id: string;\n sessionId: string;\n description?: string;\n startedAt: string;\n completedAt?: string;\n steps: string;\n involvedServices: string;\n status: 'active' | 'completed' | 'cancelled';\n isSOPCandidate: boolean;\n}\n\nexport interface WorkflowRow {\n id: string;\n sessionId: string;\n name?: string;\n pattern: string;\n taskIds: string;\n occurrences: number;\n firstSeen: string;\n lastSeen: string;\n avgDurationMs: number;\n involvedServices: string;\n}\n\nexport interface SessionRow {\n id: string;\n mode: 'discover' | 'shadow';\n startedAt: string;\n completedAt?: string;\n config: string;\n}\n\n// ── IPC Protokoll ────────────────────────\n\nexport type DaemonMessage =\n | { type: 'event'; data: EventRow }\n | { type: 'prompt'; id: string; prompt: PendingPrompt }\n | { type: 'status'; data: ShadowStatus }\n | { type: 'agent-output'; text: string }\n | { type: 'info'; message: string };\n\nexport type ClientMessage =\n | { type: 'prompt-response'; id: string; answer: string }\n | { type: 'command'; command: 'new-task' | 'end-task' | 'status' | 'stop' | 'pause' | 'resume' }\n | { type: 'task-description'; description: string };\n\nexport interface PendingPrompt {\n kind: 'node-approval' | 'task-boundary' | 'task-end';\n context: Record<string, unknown>;\n options: string[];\n defaultAnswer: string;\n timeoutMs: number;\n createdAt: string;\n}\n\nexport interface ShadowStatus {\n pid: number;\n uptime: number;\n nodeCount: number;\n eventCount: number;\n taskCount: number;\n sopCount: number;\n pendingPrompts: number;\n autoSave: boolean;\n mode: 'foreground' | 'daemon';\n agentActive: boolean;\n paused: boolean;\n cyclesRun: number;\n cyclesSkipped: number;\n}\n\n// ── Config ───────────────────────────────\n\nexport const MIN_POLL_INTERVAL_MS = 15_000; // 15s Minimum (Agent SDK Overhead)\n\nexport interface CartographyConfig {\n mode: 'discover' | 'shadow';\n maxDepth: number;\n maxTurns: number;\n entryPoints: string[];\n agentModel: string;\n shadowMode: 'foreground' | 'daemon';\n pollIntervalMs: number;\n inactivityTimeoutMs: number;\n promptTimeoutMs: number;\n trackWindowFocus: boolean;\n autoSaveNodes: boolean;\n enableNotifications: boolean;\n shadowModel: string;\n organization?: string;\n outputDir: string;\n dbPath: string;\n socketPath: string;\n pidFile: string;\n verbose: boolean;\n}\n\nexport function defaultConfig(overrides: Partial<CartographyConfig> = {}): CartographyConfig {\n const home = process.env.HOME ?? process.env.USERPROFILE ?? '/tmp';\n return {\n mode: 'discover',\n maxDepth: 8,\n maxTurns: 50,\n entryPoints: ['localhost'],\n agentModel: 'claude-sonnet-4-5-20250929',\n shadowMode: 'daemon',\n pollIntervalMs: 30_000,\n inactivityTimeoutMs: 300_000,\n promptTimeoutMs: 60_000,\n trackWindowFocus: false,\n autoSaveNodes: false,\n enableNotifications: true,\n shadowModel: 'claude-haiku-4-5-20251001',\n outputDir: './cartography-output',\n dbPath: `${home}/.cartography/cartography.db`,\n socketPath: `${home}/.cartography/daemon.sock`,\n pidFile: `${home}/.cartography/daemon.pid`,\n verbose: false,\n ...overrides,\n };\n}\n","import { homedir, tmpdir } from 'node:os';\nimport { existsSync, readFileSync, readdirSync, copyFileSync } from 'node:fs';\nimport { join } from 'node:path';\n\n// ── Types ─────────────────────────────────────────────────────────────────────\n\nexport interface BookmarkHost {\n hostname: string;\n port: number;\n protocol: 'http' | 'https';\n source: string;\n}\n\n// ── Helpers ───────────────────────────────────────────────────────────────────\n\nfunction extractHost(rawUrl: string, source: string): BookmarkHost | null {\n try {\n const u = new URL(rawUrl);\n if (u.protocol !== 'http:' && u.protocol !== 'https:') return null;\n const protocol = u.protocol === 'https:' ? 'https' as const : 'http' as const;\n // Strip: no paths, no params, no credentials — hostname only\n const port = u.port ? parseInt(u.port, 10) : (protocol === 'https' ? 443 : 80);\n const hostname = u.hostname.toLowerCase();\n if (!hostname || hostname === 'localhost' || hostname === '127.0.0.1') return null;\n return { hostname, port, protocol, source };\n } catch {\n return null;\n }\n}\n\n// Chrome/Edge/Brave JSON format\ninterface ChromeNode {\n type?: string;\n url?: string;\n children?: ChromeNode[];\n}\n\nfunction walkChrome(node: ChromeNode, source: string, out: BookmarkHost[]): void {\n if (node.type === 'url' && node.url) {\n const h = extractHost(node.url, source);\n if (h) out.push(h);\n }\n if (node.children) {\n for (const child of node.children) walkChrome(child, source, out);\n }\n}\n\nfunction readChromeLike(filePath: string, source: string): BookmarkHost[] {\n if (!existsSync(filePath)) return [];\n try {\n const raw = JSON.parse(readFileSync(filePath, 'utf8')) as {\n roots: Record<string, ChromeNode>;\n };\n const out: BookmarkHost[] = [];\n for (const root of Object.values(raw.roots)) {\n if (root) walkChrome(root, source, out);\n }\n return out;\n } catch {\n return [];\n }\n}\n\nasync function readFirefox(profileDir: string): Promise<BookmarkHost[]> {\n const src = join(profileDir, 'places.sqlite');\n if (!existsSync(src)) return [];\n const tmp = join(tmpdir(), `cartograph_ff_${Date.now()}.sqlite`);\n try {\n copyFileSync(src, tmp);\n const { default: Database } = await import('better-sqlite3');\n const db = new Database(tmp, { readonly: true, fileMustExist: true });\n const rows = db.prepare(`\n SELECT DISTINCT p.url\n FROM moz_places p\n JOIN moz_bookmarks b ON b.fk = p.id\n WHERE b.type = 1 AND p.url NOT LIKE 'place:%'\n LIMIT 3000\n `).all() as { url: string }[];\n db.close();\n return rows.map(r => extractHost(r.url, 'firefox')).filter((h): h is BookmarkHost => h !== null);\n } catch {\n return [];\n }\n}\n\n// ── Platform paths ────────────────────────────────────────────────────────────\n\nconst HOME = homedir();\nconst IS_MAC = process.platform === 'darwin';\n\nconst CHROME_PATHS = IS_MAC\n ? [`${HOME}/Library/Application Support/Google/Chrome/Default/Bookmarks`]\n : [`${HOME}/.config/google-chrome/Default/Bookmarks`];\n\nconst EDGE_PATHS = IS_MAC\n ? [`${HOME}/Library/Application Support/Microsoft Edge/Default/Bookmarks`]\n : [`${HOME}/.config/microsoft-edge/Default/Bookmarks`];\n\nconst BRAVE_PATHS = IS_MAC\n ? [`${HOME}/Library/Application Support/BraveSoftware/Brave-Browser/Default/Bookmarks`]\n : [`${HOME}/.config/BraveSoftware/Brave-Browser/Default/Bookmarks`];\n\nfunction firefoxProfileDirs(): string[] {\n const base = IS_MAC\n ? `${HOME}/Library/Application Support/Firefox/Profiles`\n : `${HOME}/.mozilla/firefox`;\n if (!existsSync(base)) return [];\n try {\n return readdirSync(base)\n .filter(d => d.includes('.default') || d.includes('-release'))\n .map(d => join(base, d));\n } catch {\n return [];\n }\n}\n\n// ── Public API ────────────────────────────────────────────────────────────────\n\nexport async function scanAllBookmarks(): Promise<BookmarkHost[]> {\n const all: BookmarkHost[] = [];\n\n for (const p of CHROME_PATHS) all.push(...readChromeLike(p, 'chrome'));\n for (const p of EDGE_PATHS) all.push(...readChromeLike(p, 'edge'));\n for (const p of BRAVE_PATHS) all.push(...readChromeLike(p, 'brave'));\n\n for (const dir of firefoxProfileDirs()) {\n all.push(...await readFirefox(dir));\n }\n\n // Deduplicate by hostname (port not included — same host on 80+443 = same service)\n const seen = new Set<string>();\n return all.filter(h => {\n const key = h.hostname;\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n });\n}\n","// PreToolUse Safety Hook — enforces read-only policy on all Bash calls\n\nimport type { HookCallback } from '@anthropic-ai/claude-code';\n\n// Word-boundary matched dangerous commands\nconst BLOCKED_CMDS =\n /\\b(rm|mv|cp|dd|mkfs|chmod|chown|chgrp|kill|killall|pkill|reboot|shutdown|poweroff|halt|systemctl\\s+(start|stop|restart|enable|disable)|service\\s+(start|stop|restart)|docker\\s+(rm|rmi|stop|kill|exec|run|build|push)|kubectl\\s+(delete|apply|edit|exec|run|create|patch)|apt|yum|dnf|pacman|pip\\s+install|npm\\s+(install|uninstall)|curl\\s+.*-X\\s*(POST|PUT|DELETE|PATCH)|wget\\s+-O|tee\\s)\\b/i;\n// Redirect operators (no word boundary needed)\nconst BLOCKED_REDIRECTS = />>|>[^>]/;\n\nexport type { HookCallback };\n\nexport const safetyHook: HookCallback = async (input) => {\n // Only intercept PreToolUse events (other hook events don't have tool_name)\n if (!('tool_name' in input)) return {};\n if ((input as { tool_name: string }).tool_name !== 'Bash') return {};\n\n const cmd = ((input as { tool_input: { command?: string } }).tool_input)?.command ?? '';\n\n if (BLOCKED_CMDS.test(cmd) || BLOCKED_REDIRECTS.test(cmd)) {\n return {\n hookSpecificOutput: {\n hookEventName: 'PreToolUse',\n permissionDecision: 'deny',\n permissionDecisionReason: `BLOCKED: \"${cmd}\" — read-only policy`,\n },\n };\n }\n\n return {\n hookSpecificOutput: {\n hookEventName: 'PreToolUse',\n permissionDecision: 'allow',\n },\n };\n};\n","import type { CartographyDB } from './db.js';\nimport { createCartographyTools } from './tools.js';\nimport { safetyHook } from './safety.js';\nimport type { CartographyConfig, TaskRow } from './types.js';\n\n// ── Discovery Event Types ────────────────────────────────────────────────────\n\nexport type DiscoveryEvent =\n | { kind: 'thinking'; text: string }\n | { kind: 'tool_call'; tool: string; input: Record<string, unknown> }\n | { kind: 'tool_result'; tool: string; output: string }\n | { kind: 'turn'; turn: number }\n | { kind: 'done' };\n\nexport type AskUserFn = (question: string, context?: string) => Promise<string>;\n\n// ── runDiscovery ─────────────────────────────────────────────────────────────\n\nexport async function runDiscovery(\n config: CartographyConfig,\n db: CartographyDB,\n sessionId: string,\n onEvent?: (event: DiscoveryEvent) => void,\n onAskUser?: AskUserFn,\n hint?: string,\n): Promise<void> {\n const { query } = await import('@anthropic-ai/claude-code');\n const tools = await createCartographyTools(db, sessionId, { onAskUser });\n\n const hintSection = hint\n ? `\\n⚡ USER-HINT (PRIORITÄT): Der User möchte gezielt nach folgenden Tools suchen: \"${hint}\"\\n → scan_installed_apps(searchHint: \"${hint}\") SOFORT ausführen und diese Tools als saas_tool oder config_file speichern!\\n`\n : '';\n\n const systemPrompt = `Du bist ein Infrastruktur-Discovery-Agent. Kartographiere die gesamte Systemlandschaft — lokale Services, SaaS-Tools UND alle installierten Apps/Tools des Users.\n${hintSection}\n━━ PFLICHT-REIHENFOLGE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\nSCHRITT 1 — Browser-Lesezeichen (IMMER ZUERST):\n scan_bookmarks() aufrufen → jede zurückgegebene Domain klassifizieren:\n • Business-Tools (GitHub, Notion, Jira, Linear, Vercel, AWS, Datadog, etc.) → save_node als saas_tool\n • Interne Hosts (IPs, custom.company.com:PORT) → save_node als web_service\n • Persönliches (Social Media, News, Streaming, Shopping) → IGNORIEREN, NICHT speichern\n\nSCHRITT 2 — Installierte Apps & Tools (SEHR WICHTIG):\n scan_installed_apps() aufrufen → ALLE gefundenen Apps/Tools klassifizieren:\n • IDEs (VS Code, Cursor, Windsurf, JetBrains, etc.) → save_node als saas_tool mit category=\"ide\"\n • Office & Produktivität (Word, Excel, Notion, Obsidian, etc.) → save_node als saas_tool mit category=\"productivity\"\n • Dev-Tools (Docker, kubectl, git, Node, Python, etc.) → save_node als saas_tool mit category=\"dev-tool\"\n • Business-Apps (Slack, Zoom, HubSpot, Salesforce, etc.) → save_node als saas_tool mit category=\"business\"\n • Browser (Chrome, Firefox, Safari, etc.) → save_node als saas_tool mit category=\"browser\"\n • Design-Tools (Figma, Sketch, Adobe, etc.) → save_node als saas_tool mit category=\"design\"\n ALLE relevanten Tools speichern — auch wenn offline/lokal!\n\nSCHRITT 3 — Lokale Infrastruktur:\n ss -tlnp && ps aux → alle lauschenden Ports/Prozesse identifizieren\n Jeden Service vertiefen: DB→Schemas, API→Endpoints, Queue→Topics\n\nSCHRITT 4 — Cloud & Kubernetes (falls CLI vorhanden):\n scan_k8s_resources() → Nodes, Services, Pods, Deployments, Ingresses\n scan_aws_resources() → EC2, RDS, ELB, EKS, ElastiCache, S3 (falls AWS CLI + Credentials)\n scan_gcp_resources() → Compute, SQL, GKE, Cloud Run, Functions (falls gcloud + Auth)\n scan_azure_resources() → VMs, AKS, SQL, Redis, WebApps (falls az CLI + Login)\n Fehler / \"nicht verfügbar\" → ignorieren, weiter mit nächstem Tool\n\nSCHRITT 5 — Config-Files:\n .env, docker-compose.yml, application.yml, kubernetes/*.yml\n Nur Host:Port extrahieren — KEINE Credentials\n\nSCHRITT 6 — Rückfragen bei Unklarheit:\n ask_user() nutzen wenn: Dienst unklar ist, Kontext fehlt, oder User Input sinnvoll wäre\n Beispiele: \"Welche Umgebung ist das (dev/staging/prod)?\", \"Ist <host> ein internes Tool?\"\n\nSCHRITT 7 — Fertig wenn alle Spuren erschöpft.\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\nPORT-MAPPING: 5432=postgres, 3306=mysql, 27017=mongodb, 6379=redis,\n9092=kafka, 5672=rabbitmq, 80/443/8080/3000=web_service,\n9090=prometheus, 8500=consul, 8200=vault, 2379=etcd\n\nREGELN:\n• Nur read-only (ss, ps, cat, head, curl -s, docker inspect, kubectl get)\n• Node IDs: \"type:host:port\" oder \"type:name\" — keine Pfade, keine Credentials\n• saas_tool IDs: \"saas_tool:github.com\", \"saas_tool:vscode\", \"saas_tool:cursor\"\n• Installed-App IDs: \"saas_tool:<appname>\" z.B. \"saas_tool:slack\", \"saas_tool:docker-desktop\"\n• Confidence: 0.9 direkt gesehen, 0.7 aus Config/Bookmarks/Apps, 0.5 Vermutung\n• metadata erlaubt: { description, category, port, version, path } — keine Passwörter\n• get_catalog vor save_node → Duplikate vermeiden\n• Edges speichern wenn Verbindungen klar erkennbar sind\n\nEntrypoints: ${config.entryPoints.join(', ')}`;\n\n const initialPrompt = hint\n ? `Starte Discovery mit USER-HINT: \"${hint}\".\nFühre SOFORT scan_installed_apps(searchHint: \"${hint}\") aus um nach diesen Tools zu suchen.\nDann scan_bookmarks, dann lokale Services.\nNutze ask_user wenn du Kontext vom User brauchst.`\n : `Starte Discovery jetzt.\nFühre SOFORT als erstes scan_bookmarks aus — noch bevor du ss oder ps verwendest.\nDanach scan_installed_apps() für alle installierten Apps und Tools.\nDann systematisch lokale Services, dann Config-Files.\nNutze ask_user wenn du Kontext vom User brauchst.`;\n\n let turnCount = 0;\n\n for await (const msg of query({\n prompt: initialPrompt,\n options: {\n model: config.agentModel,\n maxTurns: config.maxTurns,\n customSystemPrompt: systemPrompt,\n mcpServers: { cartography: tools },\n allowedTools: [\n 'Bash',\n 'mcp__cartograph__save_node',\n 'mcp__cartograph__save_edge',\n 'mcp__cartograph__get_catalog',\n 'mcp__cartograph__scan_bookmarks',\n 'mcp__cartograph__scan_installed_apps',\n 'mcp__cartograph__scan_k8s_resources',\n 'mcp__cartograph__scan_aws_resources',\n 'mcp__cartograph__scan_gcp_resources',\n 'mcp__cartograph__scan_azure_resources',\n 'mcp__cartograph__ask_user',\n ],\n hooks: {\n PreToolUse: [{ matcher: 'Bash', hooks: [safetyHook] }],\n },\n permissionMode: 'bypassPermissions',\n },\n })) {\n if (!onEvent) continue;\n\n if (msg.type === 'assistant') {\n turnCount++;\n onEvent({ kind: 'turn', turn: turnCount });\n\n for (const block of msg.message.content) {\n if (block.type === 'text') {\n onEvent({ kind: 'thinking', text: block.text });\n }\n if (block.type === 'tool_use') {\n onEvent({\n kind: 'tool_call',\n tool: block.name as string,\n input: block.input as Record<string, unknown>,\n });\n }\n }\n }\n\n if (msg.type === 'user') {\n const content = msg.message?.content;\n if (Array.isArray(content)) {\n for (const block of content) {\n if (typeof block === 'object' && block !== null && 'type' in block && (block as { type: string }).type === 'tool_result') {\n const tb = block as { tool_use_id?: string; content?: unknown };\n const text = typeof tb.content === 'string' ? tb.content : '';\n onEvent({ kind: 'tool_result', tool: tb.tool_use_id ?? '', output: text });\n }\n }\n }\n }\n\n if (msg.type === 'result') {\n onEvent({ kind: 'done' });\n return;\n }\n }\n}\n\n// ── runShadowCycle ───────────────────────────────────────────────────────────\n\nexport async function runShadowCycle(\n config: CartographyConfig,\n db: CartographyDB,\n sessionId: string,\n prevSnapshot: string,\n currSnapshot: string,\n onOutput?: (msg: unknown) => void,\n): Promise<void> {\n const { query } = await import('@anthropic-ai/claude-code');\n const tools = await createCartographyTools(db, sessionId);\n\n const prompt = `Analysiere den Diff zwischen diesen beiden System-Snapshots.\nFinde:\n- Neue/geschlossene TCP-Verbindungen → save_event\n- Neue/beendete Prozesse → save_event\n- Bisher unbekannte Services → get_catalog prüfen, dann save_node\n- Task-Grenzen (Inaktivität, Tool-Wechsel) → manage_task\ntarget = NUR Host:Port. Kurz und effizient.\n\n=== VORHER ===\n${prevSnapshot}\n\n=== JETZT ===\n${currSnapshot}`;\n\n for await (const msg of query({\n prompt,\n options: {\n model: config.shadowModel,\n maxTurns: 5,\n mcpServers: { cartography: tools },\n allowedTools: [\n 'mcp__cartograph__save_event',\n 'mcp__cartograph__save_node',\n 'mcp__cartograph__save_edge',\n 'mcp__cartograph__get_catalog',\n 'mcp__cartograph__manage_task',\n ],\n permissionMode: 'bypassPermissions',\n },\n })) {\n if (onOutput) onOutput(msg);\n }\n}\n\n// ── generateSOPs ─────────────────────────────────────────────────────────────\n\nexport async function generateSOPs(db: CartographyDB, sessionId: string): Promise<number> {\n const Anthropic = (await import('@anthropic-ai/sdk')).default;\n const client = new Anthropic();\n\n const tasks = db.getTasks(sessionId).filter(t => t.status === 'completed');\n if (tasks.length === 0) return 0;\n\n // Cluster tasks by involved services\n const clusters = clusterTasks(tasks);\n let generated = 0;\n\n for (const cluster of clusters) {\n const workflowId = crypto.randomUUID();\n const involved = JSON.parse(cluster[0]?.involvedServices ?? '[]') as string[];\n\n const taskDescriptions = cluster\n .map((t, i) => `Task ${i + 1}: ${t.description ?? 'Unnamed'}\\nSteps: ${t.steps}`)\n .join('\\n\\n');\n\n const response = await client.messages.create({\n model: 'claude-sonnet-4-5-20250929',\n max_tokens: 2048,\n messages: [{\n role: 'user',\n content: `Generiere eine SOP (Standard Operating Procedure) für diesen wiederkehrenden Workflow.\nAntworte NUR mit validen JSON im Format:\n{\n \"title\": \"...\",\n \"description\": \"...\",\n \"steps\": [{\"order\": 1, \"instruction\": \"...\", \"tool\": \"...\", \"target\": \"...\", \"notes\": \"...\"}],\n \"involvedSystems\": [\"...\"],\n \"estimatedDuration\": \"~N Minuten\",\n \"frequency\": \"Xmal täglich\",\n \"confidence\": 0.8\n}\n\nTasks:\n${taskDescriptions}\n\nBeteiligte Services: ${involved.join(', ')}`,\n }],\n });\n\n const text = response.content[0]?.type === 'text' ? response.content[0].text : '';\n\n try {\n const jsonMatch = text.match(/\\{[\\s\\S]*\\}/);\n if (!jsonMatch) continue;\n const parsed = JSON.parse(jsonMatch[0]) as {\n title: string;\n description: string;\n steps: Array<{ order: number; instruction: string; tool: string; target?: string; notes?: string }>;\n involvedSystems: string[];\n estimatedDuration: string;\n frequency: string;\n confidence: number;\n };\n\n db.insertSOP({ workflowId, ...parsed });\n generated++;\n } catch {\n // Skip malformed responses\n }\n }\n\n return generated;\n}\n\nfunction clusterTasks(tasks: TaskRow[]): TaskRow[][] {\n // Simple clustering: group by overlapping involved services\n const clusters: TaskRow[][] = [];\n const assigned = new Set<string>();\n\n for (const task of tasks) {\n if (assigned.has(task.id)) continue;\n\n const cluster = [task];\n assigned.add(task.id);\n\n const taskServices = new Set(JSON.parse(task.involvedServices ?? '[]') as string[]);\n\n for (const other of tasks) {\n if (assigned.has(other.id)) continue;\n const otherServices = new Set(JSON.parse(other.involvedServices ?? '[]') as string[]);\n // Check overlap\n const overlap = [...taskServices].filter(s => otherServices.has(s));\n if (overlap.length > 0) {\n cluster.push(other);\n assigned.add(other.id);\n }\n }\n\n clusters.push(cluster);\n }\n\n return clusters;\n}\n","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: '❓ Sonstige',\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 Force-Graph) ──────────────────────────────────────────────────\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 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=\"de\">\n<head>\n <meta charset=\"UTF-8\">\n <title>Cartography — Topology</title>\n <script src=\"https://d3js.org/d3.v7.min.js\"></script>\n <style>\n * { box-sizing: border-box; }\n body { margin: 0; background: #0d1117; color: #e6edf3; font-family: 'SF Mono', 'Fira Code', monospace; display: flex; }\n #graph { flex: 1; height: 100vh; }\n svg { width: 100%; height: 100%; }\n .link { stroke-opacity: 0.5; }\n .link-label { font-size: 9px; fill: #8b949e; }\n .node circle { stroke-width: 2px; cursor: pointer; transition: r 0.15s; }\n .node circle:hover { r: 14; }\n .node text { font-size: 11px; fill: #c9d1d9; pointer-events: none; }\n /* ── Sidebar ── */\n #sidebar {\n width: 300px; min-width: 300px; height: 100vh; overflow-y: auto;\n background: #161b22; border-left: 1px solid #30363d;\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 #21262d; vertical-align: top; }\n #sidebar .meta-table td:first-child { color: #8b949e; white-space: nowrap; width: 90px; }\n #sidebar .tag { display: inline-block; background: #21262d; border-radius: 3px; padding: 1px 5px; margin: 1px; }\n #sidebar .conf-bar { height: 6px; border-radius: 3px; background: #21262d; 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 #21262d; color: #8b949e; }\n #sidebar .edge-item span { color: #c9d1d9; }\n .hint { color: #484f58; font-size: 11px; margin-top: 8px; }\n #header { position: fixed; top: 10px; left: 10px; background: rgba(13,17,23,0.85);\n padding: 8px 12px; border-radius: 6px; font-size: 12px; border: 1px solid #30363d; }\n #header strong { color: #58a6ff; }\n </style>\n</head>\n<body>\n<div id=\"graph\">\n <div id=\"header\">\n <strong>Cartography</strong> \n <span style=\"color:#8b949e\">${nodes.length} Nodes · ${edges.length} Edges</span><br>\n <span style=\"color:#484f58;font-size:10px\">Scroll=zoom · Drag=pan · Click=details</span>\n </div>\n <svg></svg>\n</div>\n<div id=\"sidebar\">\n <h2>Infrastructure Map</h2>\n <p class=\"hint\">Klicke einen Node um Details anzuzeigen.</p>\n</div>\n<script>\nconst data = ${graphData};\n\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: '#da8bff', unknown: '#6c757d',\n};\n\nconst NODE_RADIUS = { saas_tool: 10, host: 11, database_server: 11, k8s_cluster: 13, default: 8 };\nconst radius = d => NODE_RADIUS[d.type] || NODE_RADIUS.default;\n\nconst sidebar = document.getElementById('sidebar');\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>Typ</td><td><span style=\"color:\\${c}\">\\${d.type}</span></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>Entdeckt via</td><td>\\${d.discoveredVia || '—'}</td></tr>\n <tr><td>Zeitpunkt</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>Verbindungen:</strong>'+edgeItems+'</div>' : ''}\n \\`;\n}\n\nconst svgEl = d3.select('svg');\nconst graphDiv = document.getElementById('graph');\nconst width = () => graphDiv.clientWidth;\nconst height = () => graphDiv.clientHeight;\nconst g = svgEl.append('g');\n\nsvgEl.call(d3.zoom().scaleExtent([0.1, 4]).on('zoom', e => g.attr('transform', e.transform)));\n\nconst sim = d3.forceSimulation(data.nodes)\n .force('link', d3.forceLink(data.links).id(d => d.id).distance(d => d.relationship === 'contains' ? 60 : 120))\n .force('charge', d3.forceManyBody().strength(-320))\n .force('center', d3.forceCenter(width() / 2, height() / 2))\n .force('collision', d3.forceCollide().radius(d => radius(d) + 20));\n\nconst link = g.append('g')\n .selectAll('line').data(data.links).join('line')\n .attr('class', 'link')\n .attr('stroke', d => d.confidence < 0.6 ? '#444' : '#555')\n .attr('stroke-dasharray', d => d.confidence < 0.6 ? '4 3' : null)\n .attr('stroke-width', d => d.confidence < 0.6 ? 1 : 1.5);\n\nlink.append('title').text(d => \\`\\${d.relationship} (conf:\\${d.confidence})\\n\\${d.evidence||''}\\`);\n\nconst node = g.append('g')\n .selectAll('g').data(data.nodes).join('g').attr('class', 'node')\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(); showNode(d); });\n\nnode.append('circle')\n .attr('r', radius)\n .attr('fill', d => TYPE_COLORS[d.type] || '#aaa')\n .attr('stroke', d => d3.color(TYPE_COLORS[d.type] || '#aaa').brighter(1).formatHex())\n .append('title').text(d => \\`\\${d.id}\\nconf:\\${d.confidence}\\`);\n\nnode.append('text').attr('dx', d => radius(d) + 4).attr('dy', '.35em').text(d => d.name);\n\nsim.on('tick', () => {\n link.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 node.attr('transform', d => \\`translate(\\${d.x},\\${d.y})\\`);\n});\n\nsvgEl.on('click', () => {\n sidebar.innerHTML = '<h2>Infrastructure Map</h2><p class=\"hint\">Klicke einen Node um Details anzuzeigen.</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 `**Beschreibung:** ${sop.description}`,\n `**Systeme:** ${sop.involvedSystems.join(', ')}`,\n `**Dauer:** ${sop.estimatedDuration}`,\n `**Häufigkeit:** ${sop.frequency}`,\n `**Confidence:** ${sop.confidence.toFixed(2)}`,\n '',\n '## Schritte',\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=\"de\">\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\">Beteiligte Systeme</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\">Keine SOPs vorhanden. Shadow-Daemon starten und Workflows beobachten.</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\">Generiert: \\${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","import { execSync } from 'node:child_process';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { MIN_POLL_INTERVAL_MS } from './types.js';\n\nfunction isOAuthLoggedIn(): boolean {\n // Claude CLI speichert OAuth-Tokens in ~/.claude/.credentials.json\n const home = process.env.HOME ?? process.env.USERPROFILE ?? '/tmp';\n const credFile = join(home, '.claude', '.credentials.json');\n if (!existsSync(credFile)) return false;\n try {\n const creds = JSON.parse(readFileSync(credFile, 'utf8')) as Record<string, unknown>;\n const oauth = creds['claudeAiOauth'] as Record<string, unknown> | undefined;\n return typeof oauth?.['accessToken'] === 'string' && oauth['accessToken'].length > 0;\n } catch {\n return false;\n }\n}\n\nexport function checkPrerequisites(): void {\n // Claude CLI vorhanden?\n try {\n execSync('claude --version', { stdio: 'pipe' });\n } catch {\n process.stderr.write(\n '\\n❌ Claude CLI nicht gefunden.\\n' +\n ' Datasynx Cartography braucht die Claude CLI als Runtime-Dependency.\\n\\n' +\n ' Installieren:\\n' +\n ' npm install -g @anthropic-ai/claude-code\\n' +\n ' # oder\\n' +\n ' curl -fsSL https://claude.ai/install.sh | bash\\n\\n' +\n ' Danach: claude login\\n\\n'\n );\n process.exitCode = 1;\n throw new Error('Claude CLI not found');\n }\n\n // Auth prüfen: API Key ODER OAuth-Login (claude.ai Subscription)\n const hasApiKey = Boolean(process.env.ANTHROPIC_API_KEY);\n const hasOAuth = isOAuthLoggedIn();\n\n if (!hasApiKey && !hasOAuth) {\n process.stderr.write(\n '⚠ Keine Authentifizierung gefunden. Bitte eine der folgenden Optionen:\\n\\n' +\n ' Option A — claude.ai Subscription (empfohlen):\\n' +\n ' claude login\\n\\n' +\n ' Option B — API Key:\\n' +\n ' export ANTHROPIC_API_KEY=sk-ant-...\\n\\n'\n );\n } else if (hasOAuth && !hasApiKey) {\n process.stderr.write('✓ Eingeloggt via claude login (Subscription)\\n');\n }\n}\n\nexport function checkPollInterval(intervalMs: number): number {\n if (intervalMs < MIN_POLL_INTERVAL_MS) {\n process.stderr.write(\n `⚠ Minimum Shadow-Intervall: ${MIN_POLL_INTERVAL_MS / 1000} Sekunden (Agent SDK Overhead)\\n`\n );\n return MIN_POLL_INTERVAL_MS;\n }\n return intervalMs;\n}\n"],"mappings":"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","names":["z","Database","z","execSync","mkdirSync","join","existsSync","readFileSync","join","join","existsSync","readFileSync"]}
|