@hugobatist/smartcode 0.1.0
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/LICENSE +21 -0
- package/README.md +292 -0
- package/dist/cli.js +4324 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +374 -0
- package/dist/index.js +1167 -0
- package/dist/index.js.map +1 -0
- package/dist/static/annotations-panel.js +133 -0
- package/dist/static/annotations-svg.js +108 -0
- package/dist/static/annotations.css +367 -0
- package/dist/static/annotations.js +367 -0
- package/dist/static/app-init.js +497 -0
- package/dist/static/breakpoints.css +69 -0
- package/dist/static/breakpoints.js +197 -0
- package/dist/static/clipboard.js +94 -0
- package/dist/static/collapse-ui.js +325 -0
- package/dist/static/command-history.js +89 -0
- package/dist/static/context-menu.js +334 -0
- package/dist/static/custom-renderer.js +201 -0
- package/dist/static/dagre-layout.js +291 -0
- package/dist/static/diagram-dom.js +241 -0
- package/dist/static/diagram-editor.js +368 -0
- package/dist/static/editor-panel.js +107 -0
- package/dist/static/editor-popovers.js +187 -0
- package/dist/static/event-bus.js +57 -0
- package/dist/static/export.js +181 -0
- package/dist/static/file-tree.js +470 -0
- package/dist/static/ghost-paths.js +397 -0
- package/dist/static/heatmap.css +116 -0
- package/dist/static/heatmap.js +308 -0
- package/dist/static/icons.js +66 -0
- package/dist/static/inline-edit.js +294 -0
- package/dist/static/interaction-state.js +155 -0
- package/dist/static/interaction-tracker.js +93 -0
- package/dist/static/live.html +239 -0
- package/dist/static/main-layout.css +220 -0
- package/dist/static/main.css +334 -0
- package/dist/static/mcp-sessions.js +202 -0
- package/dist/static/modal.css +109 -0
- package/dist/static/modal.js +171 -0
- package/dist/static/node-drag.js +293 -0
- package/dist/static/pan-zoom.js +199 -0
- package/dist/static/renderer.js +280 -0
- package/dist/static/search.css +103 -0
- package/dist/static/search.js +304 -0
- package/dist/static/selection.js +353 -0
- package/dist/static/session-player.css +137 -0
- package/dist/static/session-player.js +411 -0
- package/dist/static/sidebar.css +248 -0
- package/dist/static/svg-renderer.js +313 -0
- package/dist/static/svg-shapes.js +218 -0
- package/dist/static/tokens.css +76 -0
- package/dist/static/vendor/dagre-bundle.js +43 -0
- package/dist/static/vendor/dagre.min.js +3 -0
- package/dist/static/vendor/graphlib.min.js +2 -0
- package/dist/static/viewport-transform.js +107 -0
- package/dist/static/workspace-switcher.js +202 -0
- package/dist/static/ws-client.js +71 -0
- package/dist/static/ws-handler.js +125 -0
- package/package.json +74 -0
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/version.ts","../src/utils/logger.ts","../src/diagram/annotations.ts","../src/diagram/constants.ts","../src/diagram/parser.ts","../src/diagram/validator.ts","../src/diagram/graph-types.ts","../src/diagram/graph-edge-parser.ts","../src/diagram/graph-parser.ts","../src/utils/paths.ts","../src/project/discovery.ts","../src/diagram/service.ts","../src/server/static.ts","../src/diagram/collapser-parser.ts","../src/diagram/collapser-transform.ts","../src/diagram/collapser.ts","../src/diagram/graph-serializer.ts","../src/server/session-routes.ts","../src/server/file-tree.ts","../src/server/file-routes.ts","../src/server/breakpoint-routes.ts","../src/server/ghost-path-routes.ts","../src/server/annotation-routes.ts","../src/registry/mcp-session-registry.ts","../src/server/mcp-session-routes.ts","../src/server/heatmap-routes.ts","../src/registry/workspace-registry.ts","../src/server/routes.ts","../src/server/websocket.ts","../src/watcher/file-watcher.ts","../src/session/session-store.ts","../src/server/server.ts","../src/cli/init.ts","../src/cli/status.ts","../src/mcp/schemas.ts","../src/mcp/session-tools.ts","../src/mcp/tools.ts","../src/mcp/resources.ts","../src/mcp/instructions.ts","../src/mcp/server.ts","../src/cli.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\nimport { join, dirname } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nlet cachedVersion: string | undefined;\n\n/**\n * Read the package version from package.json.\n * Works from both source (src/utils/) and bundled (dist/) contexts\n * by searching upward for package.json.\n */\nexport function getVersion(): string {\n if (cachedVersion) return cachedVersion;\n\n const startDir = dirname(fileURLToPath(import.meta.url));\n\n // Search upward from current file location to find package.json\n let dir = startDir;\n for (let i = 0; i < 5; i++) {\n try {\n const pkgPath = join(dir, 'package.json');\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8')) as { version?: string };\n if (pkg.version) {\n cachedVersion = pkg.version;\n return cachedVersion;\n }\n } catch {\n // Not found at this level, go up\n }\n dir = dirname(dir);\n }\n\n cachedVersion = '0.0.0';\n return cachedVersion;\n}\n","import pc from 'picocolors';\n\nexport const log = {\n info: (...args: unknown[]) => console.error(pc.blue('[smartcode]'), ...args),\n warn: (...args: unknown[]) => console.error(pc.yellow('[smartcode]'), ...args),\n error: (...args: unknown[]) => console.error(pc.red('[smartcode]'), ...args),\n debug: (...args: unknown[]) => {\n if (process.env['DEBUG']) console.error(pc.dim('[smartcode]'), ...args);\n },\n};\n","import type { Flag, GhostPathAnnotation, NodeStatus, RiskAnnotation, RiskLevel } from './types.js';\nimport { log } from '../utils/logger.js';\n\nexport const ANNOTATION_START = '%% --- ANNOTATIONS (auto-managed by SmartCode) ---';\n/** Legacy start marker for backward compat with existing .mmd files */\nconst ANNOTATION_START_LEGACY = '%% --- ANNOTATIONS (auto-managed by SmartB Diagrams) ---';\nexport const ANNOTATION_END = '%% --- END ANNOTATIONS ---';\n\n/** Check if a line matches either the current or legacy annotation start marker */\nfunction isAnnotationStart(line: string): boolean {\n return line === ANNOTATION_START || line === ANNOTATION_START_LEGACY;\n}\nconst FLAG_REGEX = /^%%\\s*@flag\\s+(\\S+)\\s+\"([^\"]*)\"$/;\nconst STATUS_REGEX = /^%%\\s*@status\\s+(\\S+)\\s+(\\S+)$/;\nexport const BREAKPOINT_REGEX = /^%%\\s*@breakpoint\\s+(\\S+)$/;\nexport const RISK_REGEX = /^%%\\s*@risk\\s+(\\S+)\\s+(high|medium|low)\\s+\"([^\"]*)\"$/;\nexport const GHOST_REGEX = /^%%\\s*@ghost\\s+(\\S+)\\s+(\\S+)\\s+\"([^\"]*)\"$/;\n\nconst VALID_STATUSES: readonly string[] = ['ok', 'problem', 'in-progress', 'discarded'];\n\n/** Result of parsing all annotation types in a single pass */\nexport interface AllAnnotations {\n flags: Map<string, Flag>;\n statuses: Map<string, NodeStatus>;\n breakpoints: Set<string>;\n risks: Map<string, RiskAnnotation>;\n ghosts: GhostPathAnnotation[];\n}\n\n/**\n * Parse all annotation types (flags, statuses, breakpoints, risks) in a single pass.\n * Iterates through lines once, matching each annotation regex.\n * Unrecognized lines inside the annotation block are logged as debug warnings.\n */\nexport function parseAllAnnotations(content: string): AllAnnotations {\n const flags = new Map<string, Flag>();\n const statuses = new Map<string, NodeStatus>();\n const breakpoints = new Set<string>();\n const risks = new Map<string, RiskAnnotation>();\n const ghosts: GhostPathAnnotation[] = [];\n const lines = content.split('\\n');\n\n let inBlock = false;\n for (const line of lines) {\n const trimmed = line.trim();\n\n if (isAnnotationStart(trimmed)) {\n inBlock = true;\n continue;\n }\n\n if (trimmed === ANNOTATION_END) {\n inBlock = false;\n continue;\n }\n\n if (!inBlock || trimmed === '') continue;\n\n let match = FLAG_REGEX.exec(trimmed);\n if (match) {\n flags.set(match[1]!, { nodeId: match[1]!, message: match[2]! });\n continue;\n }\n\n match = STATUS_REGEX.exec(trimmed);\n if (match) {\n const statusValue = match[2]!;\n if (VALID_STATUSES.includes(statusValue)) {\n statuses.set(match[1]!, statusValue as NodeStatus);\n } else {\n log.debug(`Skipping invalid status value: ${statusValue}`);\n }\n continue;\n }\n\n match = BREAKPOINT_REGEX.exec(trimmed);\n if (match) {\n breakpoints.add(match[1]!);\n continue;\n }\n\n match = RISK_REGEX.exec(trimmed);\n if (match) {\n risks.set(match[1]!, { nodeId: match[1]!, level: match[2]! as RiskLevel, reason: match[3]! });\n continue;\n }\n\n match = GHOST_REGEX.exec(trimmed);\n if (match) {\n ghosts.push({ fromNodeId: match[1]!, toNodeId: match[2]!, label: match[3]! });\n continue;\n }\n\n log.debug(`Skipping unrecognized annotation line: ${trimmed}`);\n }\n\n return { flags, statuses, breakpoints, risks, ghosts };\n}\n\n/** Parse all `%% @flag` lines. Delegates to parseAllAnnotations. */\nexport function parseFlags(content: string): Map<string, Flag> {\n return parseAllAnnotations(content).flags;\n}\n\n/** Parse all `%% @status` lines. Delegates to parseAllAnnotations. */\nexport function parseStatuses(content: string): Map<string, NodeStatus> {\n return parseAllAnnotations(content).statuses;\n}\n\n/** Parse all `%% @breakpoint` lines. Delegates to parseAllAnnotations. */\nexport function parseBreakpoints(content: string): Set<string> {\n return parseAllAnnotations(content).breakpoints;\n}\n\n/** Parse all `%% @risk` lines. Delegates to parseAllAnnotations. */\nexport function parseRisks(content: string): Map<string, RiskAnnotation> {\n return parseAllAnnotations(content).risks;\n}\n\n/** Parse all `%% @ghost` lines. Delegates to parseAllAnnotations. */\nexport function parseGhosts(content: string): GhostPathAnnotation[] {\n return parseAllAnnotations(content).ghosts;\n}\n\n/**\n * Remove the entire annotation block (from ANNOTATION_START to ANNOTATION_END inclusive)\n * and any trailing blank lines. Returns pure Mermaid content.\n */\nexport function stripAnnotations(content: string): string {\n const lines = content.split('\\n');\n const result: string[] = [];\n\n let inBlock = false;\n for (const line of lines) {\n const trimmed = line.trim();\n\n if (isAnnotationStart(trimmed)) {\n inBlock = true;\n continue;\n }\n\n if (trimmed === ANNOTATION_END) {\n inBlock = false;\n continue;\n }\n\n if (!inBlock) {\n result.push(line);\n }\n }\n\n // Remove trailing blank lines\n while (result.length > 0 && result[result.length - 1]!.trim() === '') {\n result.pop();\n }\n\n // Ensure single trailing newline\n return result.join('\\n') + '\\n';\n}\n\n/**\n * Strip existing annotations, then append a new annotation block at the end.\n * If both flags and statuses maps are empty, returns content with no annotation block.\n * Escapes double quotes in flag messages by replacing \" with ''.\n */\nexport function injectAnnotations(\n content: string,\n flags: Map<string, Flag>,\n statuses?: Map<string, NodeStatus>,\n breakpoints?: Set<string>,\n risks?: Map<string, RiskAnnotation>,\n ghosts?: GhostPathAnnotation[],\n): string {\n const clean = stripAnnotations(content);\n\n const hasFlags = flags.size > 0;\n const hasStatuses = statuses !== undefined && statuses.size > 0;\n const hasBreakpoints = breakpoints !== undefined && breakpoints.size > 0;\n const hasRisks = risks !== undefined && risks.size > 0;\n const hasGhosts = ghosts !== undefined && ghosts.length > 0;\n\n if (!hasFlags && !hasStatuses && !hasBreakpoints && !hasRisks && !hasGhosts) {\n return clean;\n }\n\n const lines: string[] = [\n '',\n ANNOTATION_START,\n ];\n\n for (const [nodeId, flag] of flags) {\n const escapedMessage = flag.message.replace(/\"/g, \"''\");\n lines.push(`%% @flag ${nodeId} \"${escapedMessage}\"`);\n }\n\n if (hasStatuses) {\n for (const [nodeId, status] of statuses!) {\n lines.push(`%% @status ${nodeId} ${status}`);\n }\n }\n\n if (hasBreakpoints) {\n for (const nodeId of breakpoints!) {\n lines.push(`%% @breakpoint ${nodeId}`);\n }\n }\n\n if (hasRisks) {\n for (const [nodeId, risk] of risks!) {\n const escapedReason = risk.reason.replace(/\"/g, \"''\");\n lines.push(`%% @risk ${nodeId} ${risk.level} \"${escapedReason}\"`);\n }\n }\n\n if (hasGhosts) {\n for (const ghost of ghosts!) {\n const escapedLabel = ghost.label.replace(/\"/g, \"''\");\n lines.push(`%% @ghost ${ghost.fromNodeId} ${ghost.toNodeId} \"${escapedLabel}\"`);\n }\n }\n\n lines.push(ANNOTATION_END);\n lines.push('');\n\n return clean.trimEnd() + '\\n' + lines.join('\\n');\n}\n","/** Known Mermaid diagram type keywords */\nexport const KNOWN_DIAGRAM_TYPES = [\n 'flowchart',\n 'graph',\n 'sequenceDiagram',\n 'classDiagram',\n 'stateDiagram',\n 'erDiagram',\n 'gantt',\n 'pie',\n 'gitgraph',\n 'mindmap',\n 'timeline',\n] as const;\n\n/** Regex to match the start of a Mermaid subgraph definition */\nexport const SUBGRAPH_START = /^\\s*subgraph\\s+([^\\s\\[]+)(?:\\s*\\[\"([^\"]+)\"\\])?/;\n\n/** Regex to match the end of a Mermaid subgraph definition */\nexport const SUBGRAPH_END = /^\\s*end\\s*$/;\n","import type { Flag } from './types.js';\nimport { stripAnnotations, parseFlags } from './annotations.js';\nimport { KNOWN_DIAGRAM_TYPES } from './constants.js';\n\n/**\n * Extract the diagram type from the first non-empty, non-comment line.\n * Returns the matched type string or undefined if no match.\n */\nexport function parseDiagramType(content: string): string | undefined {\n const lines = content.split('\\n');\n\n for (const line of lines) {\n const trimmed = line.trim();\n\n // Skip empty lines and Mermaid comments\n if (trimmed === '' || trimmed.startsWith('%%')) continue;\n\n // Check if the line starts with a known diagram type keyword\n for (const diagramType of KNOWN_DIAGRAM_TYPES) {\n if (trimmed === diagramType || trimmed.startsWith(diagramType + ' ')) {\n return diagramType;\n }\n }\n\n // First non-empty, non-comment line didn't match any known type\n return undefined;\n }\n\n return undefined;\n}\n\n/**\n * Convenience function that strips annotations, parses flags, and detects diagram type.\n * Returns all three results together.\n */\nexport function parseDiagramContent(rawContent: string): {\n mermaidContent: string;\n flags: Map<string, Flag>;\n diagramType?: string;\n} {\n const mermaidContent = stripAnnotations(rawContent);\n const flags = parseFlags(rawContent);\n const diagramType = parseDiagramType(mermaidContent);\n\n return { mermaidContent, flags, diagramType };\n}\n","import type { ValidationResult } from './types.js';\nimport { parseDiagramType } from './parser.js';\nimport { KNOWN_DIAGRAM_TYPES } from './constants.js';\n\n/**\n * Validate Mermaid syntax using a regex-based heuristic approach.\n *\n * The @mermaid-js/parser package (v0.6) only supports a limited set of diagram types\n * (info, packet, pie, architecture, gitGraph, radar) and does NOT support flowchart,\n * which is the primary diagram type for SmartCode. We use a heuristic validator that\n * catches obvious syntax errors. Browser-side Mermaid.js catches the rest at render time.\n */\nexport function validateMermaidSyntax(content: string): ValidationResult {\n const errors: ValidationResult['errors'] = [];\n const trimmedContent = content.trim();\n\n if (trimmedContent === '') {\n return { valid: false, errors: [{ message: 'Empty diagram content' }] };\n }\n\n // Detect diagram type from first meaningful line\n const diagramType = parseDiagramType(content);\n\n if (!diagramType) {\n const firstLine = trimmedContent.split('\\n')[0]?.trim() ?? '';\n errors.push({\n message: `Unknown diagram type. First line: \"${firstLine}\". Expected one of: ${KNOWN_DIAGRAM_TYPES.join(', ')}`,\n line: 1,\n });\n return { valid: false, errors, diagramType: undefined };\n }\n\n // Check bracket matching\n const bracketErrors = checkBracketMatching(content);\n errors.push(...bracketErrors);\n\n // Check for dangling arrows (lines ending with --> with nothing after)\n const danglingErrors = checkDanglingArrows(content);\n errors.push(...danglingErrors);\n\n return {\n valid: errors.length === 0,\n errors,\n diagramType,\n };\n}\n\n/**\n * Check for unmatched brackets in the content.\n */\nfunction checkBracketMatching(content: string): ValidationResult['errors'] {\n const errors: ValidationResult['errors'] = [];\n const lines = content.split('\\n');\n\n const pairs: Array<[string, string]> = [['[', ']'], ['(', ')'], ['{', '}']];\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]!;\n const lineNum = i + 1;\n\n // Skip comment lines\n if (line.trim().startsWith('%%')) continue;\n\n for (const [open, close] of pairs) {\n let depth = 0;\n for (const char of line) {\n if (char === open) depth++;\n if (char === close) depth--;\n if (depth < 0) {\n errors.push({\n message: `Unexpected closing '${close}' without matching '${open}'`,\n line: lineNum,\n });\n break;\n }\n }\n if (depth > 0) {\n errors.push({\n message: `Unclosed '${open}' -- missing '${close}'`,\n line: lineNum,\n });\n }\n }\n }\n\n return errors;\n}\n\n/**\n * Check for dangling arrows (lines ending with an arrow operator and nothing after).\n */\nfunction checkDanglingArrows(content: string): ValidationResult['errors'] {\n const errors: ValidationResult['errors'] = [];\n const lines = content.split('\\n');\n\n const danglingArrowPattern = /-->\\s*$/;\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]!;\n const lineNum = i + 1;\n const trimmed = line.trim();\n\n // Skip empty lines and comments\n if (trimmed === '' || trimmed.startsWith('%%')) continue;\n\n if (danglingArrowPattern.test(trimmed)) {\n errors.push({\n message: `Dangling arrow -- line ends with '-->' but no target node`,\n line: lineNum,\n });\n }\n }\n\n return errors;\n}\n","import type { Flag, NodeStatus, ValidationResult } from './types.js';\n\nexport type NodeShape =\n | 'rect' | 'rounded' | 'stadium' | 'subroutine' | 'cylinder'\n | 'circle' | 'asymmetric' | 'diamond' | 'hexagon'\n | 'parallelogram' | 'parallelogram-alt' | 'trapezoid' | 'trapezoid-alt';\n\nexport type EdgeType = 'arrow' | 'open' | 'dotted' | 'thick' | 'invisible';\n\nexport type FlowDirection = 'TB' | 'LR' | 'BT' | 'RL';\n\nexport interface GraphNode {\n id: string;\n label: string;\n shape: NodeShape;\n status?: NodeStatus;\n flag?: Flag;\n subgraphId?: string;\n cssClass?: string;\n x?: number;\n y?: number;\n width?: number;\n height?: number;\n}\n\nexport interface GraphEdge {\n id: string;\n from: string;\n to: string;\n label?: string;\n type: EdgeType;\n bidirectional?: boolean;\n}\n\nexport interface GraphSubgraph {\n id: string;\n label: string;\n parentId: string | null;\n nodeIds: string[];\n childSubgraphIds: string[];\n}\n\nexport interface GraphModel {\n diagramType: 'flowchart' | 'graph';\n direction: FlowDirection;\n nodes: Map<string, GraphNode>;\n edges: GraphEdge[];\n subgraphs: Map<string, GraphSubgraph>;\n classDefs: Map<string, string>;\n nodeStyles: Map<string, string>;\n linkStyles: Map<number, string>;\n classAssignments: Map<string, string>;\n filePath: string;\n flags: Map<string, Flag>;\n statuses: Map<string, NodeStatus>;\n validation: ValidationResult;\n}\n\n/** Shape bracket patterns — ordered longest-first for correct parsing precedence */\nexport const SHAPE_PATTERNS: Array<{ open: string; close: string; shape: NodeShape }> = [\n { open: '([', close: '])', shape: 'stadium' },\n { open: '[[', close: ']]', shape: 'subroutine' },\n { open: '[(', close: ')]', shape: 'cylinder' },\n { open: '((', close: '))', shape: 'circle' },\n { open: '{{', close: '}}', shape: 'hexagon' },\n { open: '[/', close: '\\\\]', shape: 'trapezoid' },\n { open: '[\\\\', close: '/]', shape: 'trapezoid-alt' },\n { open: '[/', close: '/]', shape: 'parallelogram' },\n { open: '[\\\\', close: '\\\\]', shape: 'parallelogram-alt' },\n { open: '>', close: ']', shape: 'asymmetric' },\n { open: '{', close: '}', shape: 'diamond' },\n { open: '(', close: ')', shape: 'rounded' },\n { open: '[', close: ']', shape: 'rect' },\n];\n\n/** Edge type to serialization syntax mapping */\nexport const EDGE_SYNTAX: Record<EdgeType, string> = {\n arrow: '-->',\n open: '---',\n dotted: '-.->',\n thick: '==>',\n invisible: '~~~',\n};\n","/**\n * SmartCode - Graph Edge Parser Helpers\n * Extracts edge definitions and node ID references from Mermaid lines.\n * Used by graph-parser.ts as part of the multi-pass pipeline.\n */\n\nimport type { NodeShape, EdgeType } from './graph-types.js';\nimport { SHAPE_PATTERNS } from './graph-types.js';\n\n// ─── Types ──────────────────────────────────────────────────────────────────\n\nexport interface SimpleEdge {\n from: string;\n to: string;\n type: EdgeType;\n label?: string;\n bidirectional: boolean;\n}\n\n// ─── Edge parsing patterns ──────────────────────────────────────────────────\n\n/**\n * All edge operator patterns, ordered by specificity (longest first).\n */\nexport const EDGE_OPS: Array<{\n pattern: RegExp;\n type: EdgeType;\n bidirectional: boolean;\n}> = [\n // Bidirectional variants (must come before unidirectional)\n { pattern: /\\s*<==>\\s*/, type: 'thick', bidirectional: true },\n { pattern: /\\s*<-\\.->\\s*/, type: 'dotted', bidirectional: true },\n { pattern: /\\s*<-->\\s*/, type: 'arrow', bidirectional: true },\n // Labeled edges: pipe syntax -->|\"label\"| or -->|label|\n { pattern: /\\s*-->\\|\"([^\"]*)\"\\|\\s*/, type: 'arrow', bidirectional: false },\n { pattern: /\\s*-->\\|([^|]*)\\|\\s*/, type: 'arrow', bidirectional: false },\n // Labeled edges: inline syntax -- \"label\" -->\n { pattern: /\\s*--\\s*\"([^\"]*)\"\\s*-->\\s*/, type: 'arrow', bidirectional: false },\n // Unlabeled operators (order: longest first)\n { pattern: /\\s*~~~\\s*/, type: 'invisible', bidirectional: false },\n { pattern: /\\s*==>\\s*/, type: 'thick', bidirectional: false },\n { pattern: /\\s*-\\.->\\s*/, type: 'dotted', bidirectional: false },\n { pattern: /\\s*---\\s*/, type: 'open', bidirectional: false },\n { pattern: /\\s*-->\\s*/, type: 'arrow', bidirectional: false },\n];\n\n// ─── Inline class stripping ─────────────────────────────────────────────────\n\nexport function stripInlineClass(ref: string): { id: string; className?: string } {\n const classIdx = ref.indexOf(':::');\n if (classIdx === -1) return { id: ref };\n return {\n id: ref.substring(0, classIdx),\n className: ref.substring(classIdx + 3),\n };\n}\n\n// ─── Node shape parsing ─────────────────────────────────────────────────────\n\nexport function parseNodeShape(definition: string): {\n id: string;\n label: string;\n shape: NodeShape;\n className?: string;\n} | null {\n const trimmed = definition.trim();\n if (!trimmed) return null;\n\n const { id: withShape, className } = stripInlineClass(trimmed);\n\n for (const sp of SHAPE_PATTERNS) {\n const openIdx = withShape.indexOf(sp.open);\n if (openIdx === -1) continue;\n\n const nodeId = withShape.substring(0, openIdx).trim();\n if (!nodeId || !/^[\\w][\\w\\d_-]*$/.test(nodeId)) continue;\n\n const afterOpen = withShape.substring(openIdx + sp.open.length);\n if (!afterOpen.endsWith(sp.close)) continue;\n\n const labelRaw = afterOpen.substring(0, afterOpen.length - sp.close.length);\n\n let label = labelRaw;\n if (label.startsWith('\"') && label.endsWith('\"')) {\n label = label.substring(1, label.length - 1);\n }\n\n return { id: nodeId, label, shape: sp.shape, className };\n }\n\n return null;\n}\n\n// ─── Node segment extraction ────────────────────────────────────────────────\n\n/**\n * Split a line into segments around edge operators.\n * E.g., `A[\"Start\"] --> B[\"End\"]` yields `['A[\"Start\"]', 'B[\"End\"]']`\n */\nexport function extractNodeSegments(line: string): string[] {\n let work = line;\n\n for (const op of EDGE_OPS) {\n work = work.replace(op.pattern, ' \\x00 ');\n }\n\n return work.split('\\x00').map(s => s.trim()).filter(Boolean);\n}\n\n// ─── Edge parsing ───────────────────────────────────────────────────────────\n\n/**\n * Parse all edges from a line, handling chained edges like A-->B-->C.\n */\nexport function parseEdgesFromLine(line: string): SimpleEdge[] {\n const result: SimpleEdge[] = [];\n let remaining = line;\n let lastNode: string | null = null;\n\n while (remaining.trim()) {\n let earliest: {\n index: number;\n matchLen: number;\n type: EdgeType;\n bidirectional: boolean;\n label?: string;\n } | null = null;\n\n for (const op of EDGE_OPS) {\n const match = op.pattern.exec(remaining);\n if (match && (earliest === null || match.index < earliest.index)) {\n earliest = {\n index: match.index,\n matchLen: match[0].length,\n type: op.type,\n bidirectional: op.bidirectional,\n label: match[1],\n };\n }\n }\n\n if (!earliest) break;\n\n const beforeOp = remaining.substring(0, earliest.index).trim();\n remaining = remaining.substring(earliest.index + earliest.matchLen);\n\n if (lastNode === null) {\n lastNode = extractNodeId(beforeOp);\n if (!lastNode) break;\n }\n\n const afterTrimmed = remaining.trim();\n const nextNodeId = extractNodeId(afterTrimmed, 'left');\n if (!nextNodeId) break;\n\n result.push({\n from: lastNode,\n to: nextNodeId,\n type: earliest.type,\n label: earliest.label,\n bidirectional: earliest.bidirectional,\n });\n\n lastNode = nextNodeId;\n remaining = advancePastNode(remaining.trim(), nextNodeId);\n }\n\n return result;\n}\n\n// ─── Internal helpers ───────────────────────────────────────────────────────\n\n/**\n * Extract a node ID from text.\n */\nfunction extractNodeId(\n text: string,\n direction: 'right' | 'left' = 'right',\n): string | null {\n if (!text.trim()) return null;\n\n const { id } = stripInlineClass(text.trim());\n\n const shaped = parseNodeShape(text.trim());\n if (shaped) return shaped.id;\n\n if (direction === 'left') {\n const match = /^([\\w][\\w\\d_-]*)/.exec(id);\n return match ? match[1]! : null;\n }\n\n const match = /([\\w][\\w\\d_-]*)$/.exec(id);\n return match ? match[1]! : null;\n}\n\n/**\n * Advance past a node definition in text (including any shape brackets).\n */\nfunction advancePastNode(text: string, nodeId: string): string {\n const { id: cleanText } = stripInlineClass(text);\n\n for (const sp of SHAPE_PATTERNS) {\n const expectedStart = nodeId + sp.open;\n if (cleanText.startsWith(expectedStart)) {\n const closeIdx = cleanText.indexOf(sp.close, expectedStart.length);\n if (closeIdx !== -1) {\n const afterClose = closeIdx + sp.close.length;\n const afterWithClass = text.substring(afterClose);\n const classMatch = /^:::\\S+/.exec(afterWithClass);\n return classMatch\n ? afterWithClass.substring(classMatch[0].length)\n : afterWithClass;\n }\n }\n }\n\n const safeId = regexSafe(nodeId);\n const simplePattern = new RegExp(`^${safeId}(?::::\\\\S+)?`);\n const simpleMatch = simplePattern.exec(text);\n if (simpleMatch) {\n return text.substring(simpleMatch[0].length);\n }\n\n return text.substring(nodeId.length);\n}\n\n/** Escape special regex characters in a string */\nfunction regexSafe(s: string): string {\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n","/**\n * SmartCode - Mermaid to GraphModel Parser\n * Multi-pass parser that converts raw .mmd content into a structured GraphModel.\n */\n\nimport type { ValidationResult } from './types.js';\nimport type {\n GraphModel, GraphNode, GraphEdge, GraphSubgraph, FlowDirection,\n} from './graph-types.js';\nimport { parseFlags, parseStatuses, stripAnnotations } from './annotations.js';\nimport { validateMermaidSyntax } from './validator.js';\nimport { SUBGRAPH_START, SUBGRAPH_END } from './constants.js';\nimport {\n stripInlineClass, parseNodeShape, extractNodeSegments, parseEdgesFromLine,\n} from './graph-edge-parser.js';\n\n// ─── Main Parser ─────────────────────────────────────────────────────────────\n\n/**\n * Parse raw .mmd content into a structured GraphModel.\n * Uses a multi-pass pipeline: preprocessing, direction, styles,\n * subgraphs, nodes, edges, annotations merge, validation.\n */\nexport function parseMermaidToGraph(rawContent: string, filePath: string): GraphModel {\n // ── Pre-processing ──────────────────────────────────────────────────────\n const flags = parseFlags(rawContent);\n const statuses = parseStatuses(rawContent);\n const mermaidContent = stripAnnotations(rawContent);\n const lines = mermaidContent.split('\\n');\n\n // ── Pass 1: Parse direction line ────────────────────────────────────────\n let diagramType: 'flowchart' | 'graph' = 'flowchart';\n let direction: FlowDirection = 'TB';\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('%%')) continue;\n\n const dirMatch = /^(flowchart|graph)\\s+(TB|TD|BT|LR|RL)/.exec(trimmed);\n if (dirMatch) {\n diagramType = dirMatch[1] as 'flowchart' | 'graph';\n const rawDir = dirMatch[2]!;\n direction = rawDir === 'TD' ? 'TB' : rawDir as FlowDirection;\n }\n break; // Only check the first non-empty, non-comment line\n }\n\n // ── Pass 2: Extract style directives ────────────────────────────────────\n const classDefs = new Map<string, string>();\n const nodeStyles = new Map<string, string>();\n const linkStyles = new Map<number, string>();\n const classAssignments = new Map<string, string>();\n const directiveLineIndices = new Set<number>();\n\n parseStyleDirectives(\n lines, classDefs, nodeStyles, linkStyles, classAssignments, directiveLineIndices,\n );\n\n // ── Pass 3: Parse subgraph structure ────────────────────────────────────\n const subgraphs = new Map<string, GraphSubgraph>();\n const lineToSubgraph = new Map<number, string>();\n const subgraphLineIndices = new Set<number>();\n\n parseSubgraphStructure(lines, subgraphs, lineToSubgraph, subgraphLineIndices);\n\n // ── Pass 4: Parse node definitions ──────────────────────────────────────\n const nodes = new Map<string, GraphNode>();\n\n parseNodeDefinitions(\n lines, nodes, classAssignments, lineToSubgraph,\n directiveLineIndices, subgraphLineIndices,\n );\n\n // ── Pass 5: Parse edge definitions ──────────────────────────────────────\n const edges: GraphEdge[] = [];\n\n parseEdgeDefinitions(\n lines, edges, nodes, subgraphs, lineToSubgraph,\n directiveLineIndices, subgraphLineIndices,\n );\n\n // ── Pass 6: Merge annotations into nodes ────────────────────────────────\n for (const [nodeId, flag] of flags) {\n const node = nodes.get(nodeId);\n if (node) node.flag = flag;\n }\n\n for (const [nodeId, status] of statuses) {\n const node = nodes.get(nodeId);\n if (node) node.status = status;\n }\n\n // ── Pass 7: Validate ───────────────────────────────────────────────────\n const validation: ValidationResult = validateMermaidSyntax(mermaidContent);\n\n // ── Assemble and return ─────────────────────────────────────────────────\n return {\n diagramType,\n direction,\n nodes,\n edges,\n subgraphs,\n classDefs,\n nodeStyles,\n linkStyles,\n classAssignments,\n filePath,\n flags,\n statuses,\n validation,\n };\n}\n\n// ─── Pass 2: Style directives ───────────────────────────────────────────────\n\nfunction parseStyleDirectives(\n lines: string[],\n classDefs: Map<string, string>,\n nodeStyles: Map<string, string>,\n linkStyles: Map<number, string>,\n classAssignments: Map<string, string>,\n directiveLineIndices: Set<number>,\n): void {\n for (let i = 0; i < lines.length; i++) {\n const trimmed = lines[i]!.trim();\n\n const classDefMatch = /^classDef\\s+(\\S+)\\s+(.+);?\\s*$/.exec(trimmed);\n if (classDefMatch) {\n const name = classDefMatch[1]!;\n classDefs.set(name, classDefMatch[2]!.replace(/;\\s*$/, ''));\n directiveLineIndices.add(i);\n continue;\n }\n\n const styleMatch = /^style\\s+(\\S+)\\s+(.+);?\\s*$/.exec(trimmed);\n if (styleMatch) {\n nodeStyles.set(styleMatch[1]!, styleMatch[2]!.replace(/;\\s*$/, ''));\n directiveLineIndices.add(i);\n continue;\n }\n\n const linkStyleMatch = /^linkStyle\\s+(\\d+)\\s+(.+);?\\s*$/.exec(trimmed);\n if (linkStyleMatch) {\n linkStyles.set(\n parseInt(linkStyleMatch[1]!, 10),\n linkStyleMatch[2]!.replace(/;\\s*$/, ''),\n );\n directiveLineIndices.add(i);\n continue;\n }\n\n const classDirectiveMatch = /^class\\s+(.+?)\\s+(\\S+);?\\s*$/.exec(trimmed);\n if (classDirectiveMatch) {\n const className = classDirectiveMatch[2]!.replace(/;\\s*$/, '');\n const nodeIds = classDirectiveMatch[1]!.split(',').map(s => s.trim());\n for (const nid of nodeIds) {\n classAssignments.set(nid, className);\n }\n directiveLineIndices.add(i);\n continue;\n }\n }\n}\n\n// ─── Pass 3: Subgraph structure ─────────────────────────────────────────────\n\nfunction parseSubgraphStructure(\n lines: string[],\n subgraphs: Map<string, GraphSubgraph>,\n lineToSubgraph: Map<number, string>,\n subgraphLineIndices: Set<number>,\n): void {\n const subgraphStack: string[] = [];\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]!;\n const startMatch = SUBGRAPH_START.exec(line);\n\n if (startMatch) {\n const id = startMatch[1]!;\n const label = startMatch[2] || id;\n const parentId = subgraphStack.length > 0\n ? subgraphStack[subgraphStack.length - 1]!\n : null;\n\n const sg: GraphSubgraph = {\n id, label, parentId, nodeIds: [], childSubgraphIds: [],\n };\n\n subgraphs.set(id, sg);\n if (parentId) {\n const parent = subgraphs.get(parentId);\n if (parent) parent.childSubgraphIds.push(id);\n }\n\n subgraphStack.push(id);\n subgraphLineIndices.add(i);\n continue;\n }\n\n if (SUBGRAPH_END.test(line) && subgraphStack.length > 0) {\n subgraphStack.pop();\n subgraphLineIndices.add(i);\n continue;\n }\n\n if (subgraphStack.length > 0) {\n lineToSubgraph.set(i, subgraphStack[subgraphStack.length - 1]!);\n }\n }\n}\n\n// ─── Pass 4: Node definitions ───────────────────────────────────────────────\n\nconst DIRECTION_LINE = /^(flowchart|graph)\\s+(TB|TD|BT|LR|RL)/;\n\nfunction isSkippableLine(\n trimmed: string,\n lineIdx: number,\n directiveIndices: Set<number>,\n subgraphIndices: Set<number>,\n): boolean {\n if (directiveIndices.has(lineIdx)) return true;\n if (subgraphIndices.has(lineIdx)) return true;\n if (!trimmed || trimmed.startsWith('%%')) return true;\n if (DIRECTION_LINE.test(trimmed)) return true;\n return false;\n}\n\nfunction parseNodeDefinitions(\n lines: string[],\n nodes: Map<string, GraphNode>,\n classAssignments: Map<string, string>,\n lineToSubgraph: Map<number, string>,\n directiveLineIndices: Set<number>,\n subgraphLineIndices: Set<number>,\n): void {\n for (let i = 0; i < lines.length; i++) {\n const trimmed = lines[i]!.trim();\n if (isSkippableLine(trimmed, i, directiveLineIndices, subgraphLineIndices)) continue;\n\n const nodeSegments = extractNodeSegments(trimmed);\n\n for (const segment of nodeSegments) {\n const parsed = parseNodeShape(segment);\n if (parsed && !nodes.has(parsed.id)) {\n const subgraphId = lineToSubgraph.get(i);\n const cssClass = parsed.className || classAssignments.get(parsed.id);\n\n nodes.set(parsed.id, {\n id: parsed.id,\n label: parsed.label,\n shape: parsed.shape,\n subgraphId,\n cssClass,\n });\n\n if (parsed.className) {\n classAssignments.set(parsed.id, parsed.className);\n }\n } else if (!parsed) {\n // Handle bare ID:::className (no shape brackets)\n const { id: bareId, className } = stripInlineClass(segment.trim());\n if (className && /^[\\w][\\w\\d_-]*$/.test(bareId)) {\n classAssignments.set(bareId, className);\n if (!nodes.has(bareId)) {\n nodes.set(bareId, {\n id: bareId,\n label: bareId,\n shape: 'rect',\n subgraphId: lineToSubgraph.get(i),\n cssClass: className,\n });\n } else {\n nodes.get(bareId)!.cssClass = className;\n }\n }\n }\n }\n }\n}\n\n// ─── Pass 5: Edge definitions ───────────────────────────────────────────────\n\nfunction parseEdgeDefinitions(\n lines: string[],\n edges: GraphEdge[],\n nodes: Map<string, GraphNode>,\n subgraphs: Map<string, GraphSubgraph>,\n lineToSubgraph: Map<number, string>,\n directiveLineIndices: Set<number>,\n subgraphLineIndices: Set<number>,\n): void {\n const edgeIdCounts = new Map<string, number>();\n\n for (let i = 0; i < lines.length; i++) {\n const trimmed = lines[i]!.trim();\n if (isSkippableLine(trimmed, i, directiveLineIndices, subgraphLineIndices)) continue;\n\n const lineEdges = parseEdgesFromLine(trimmed);\n\n for (const edgeInfo of lineEdges) {\n const { id: fromId } = stripInlineClass(edgeInfo.from);\n const { id: toId } = stripInlineClass(edgeInfo.to);\n\n ensureNode(nodes, fromId, lineToSubgraph.get(i));\n ensureNode(nodes, toId, lineToSubgraph.get(i));\n\n // Track nodes inside subgraphs\n const sgId = lineToSubgraph.get(i);\n if (sgId) {\n const sg = subgraphs.get(sgId);\n if (sg) {\n if (!sg.nodeIds.includes(fromId) && !subgraphs.has(fromId)) {\n sg.nodeIds.push(fromId);\n }\n if (!sg.nodeIds.includes(toId) && !subgraphs.has(toId)) {\n sg.nodeIds.push(toId);\n }\n }\n }\n\n const baseId = `${fromId}->${toId}`;\n const count = edgeIdCounts.get(baseId) || 0;\n const edgeId = count === 0 ? baseId : `${baseId}#${count}`;\n edgeIdCounts.set(baseId, count + 1);\n\n edges.push({\n id: edgeId,\n from: fromId,\n to: toId,\n type: edgeInfo.type,\n label: edgeInfo.label,\n bidirectional: edgeInfo.bidirectional || undefined,\n });\n }\n }\n}\n\n// ─── Helper: ensure a node exists in the map ────────────────────────────────\n\nfunction ensureNode(\n nodes: Map<string, GraphNode>,\n id: string,\n subgraphId?: string,\n): void {\n if (nodes.has(id)) return;\n nodes.set(id, { id, label: id, shape: 'rect', subgraphId });\n}\n","import path from 'node:path';\nimport { existsSync } from 'node:fs';\nimport { fileURLToPath } from 'node:url';\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\n/**\n * Resolve path to static assets bundled with the package.\n * Works regardless of global/local install location.\n *\n * In production (built): __dirname points to dist/\n * -> static assets at dist/static/ (../static from dist/)\n * In development/test: __dirname points to src/utils/\n * -> static assets at <root>/static/ (../../static from src/utils/)\n */\nexport function getStaticDir(): string {\n // Production path: dist/ -> dist/static/\n const prodPath = path.join(__dirname, '..', 'static');\n if (existsSync(prodPath)) return prodPath;\n\n // Development path: src/utils/ -> <root>/static/\n const devPath = path.join(__dirname, '..', '..', 'static');\n if (existsSync(devPath)) return devPath;\n\n // Fallback to original behavior\n return prodPath;\n}\n\nexport function getStaticFile(filename: string): string {\n return path.join(getStaticDir(), filename);\n}\n\n/**\n * Resolve a relative file path against a project root.\n * Throws if the resolved path escapes the project root (path traversal protection).\n */\nexport function resolveProjectPath(projectRoot: string, filePath: string): string {\n const resolvedRoot = path.resolve(projectRoot);\n const resolved = path.resolve(resolvedRoot, filePath);\n if (!resolved.startsWith(resolvedRoot + path.sep) && resolved !== resolvedRoot) {\n throw new Error(`Path traversal detected: ${filePath}`);\n }\n return resolved;\n}\n","import { readdir } from 'node:fs/promises';\nimport { join } from 'node:path';\n\n/** Directories excluded from .mmd file discovery */\nconst EXCLUDED_DIRS = new Set([\n 'node_modules', '.git', 'test', 'dist', '.planning', '.smartcode',\n]);\n\n/**\n * Discover all .mmd files recursively under the given directory.\n * Returns relative paths (relative to the directory).\n * Excludes node_modules, .git, test, dist, .planning, and .smartcode directories.\n * Results are sorted alphabetically for deterministic output.\n *\n * Uses recursive readdir (Node 18.17+) with post-filtering to avoid\n * external CJS dependency bundling issues with tsup ESM output.\n */\nexport async function discoverMmdFiles(directory: string): Promise<string[]> {\n const entries = await readdir(directory, { recursive: true, withFileTypes: true });\n const files: string[] = [];\n\n for (const entry of entries) {\n if (!entry.isFile() || !entry.name.endsWith('.mmd')) continue;\n\n // Build relative path from parentPath (available since Node 18.17)\n const parentPath = (entry as { parentPath?: string }).parentPath ?? '';\n const relativePath = parentPath\n ? join(parentPath, entry.name).slice(directory.length + 1)\n : entry.name;\n\n // Check if any path segment is in the excluded set\n const segments = relativePath.split('/');\n const excluded = segments.some((seg) => EXCLUDED_DIRS.has(seg));\n if (!excluded) {\n files.push(relativePath);\n }\n }\n\n return files.sort();\n}\n","import { readFile, writeFile, mkdir } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport type { DiagramContent, Flag, GhostPathAnnotation, NodeStatus, RiskAnnotation, RiskLevel, ValidationResult } from './types.js';\nimport type { GraphModel } from './graph-types.js';\nimport { parseDiagramContent } from './parser.js';\nimport { injectAnnotations, parseAllAnnotations } from './annotations.js';\nimport { validateMermaidSyntax } from './validator.js';\nimport { parseMermaidToGraph } from './graph-parser.js';\nimport { resolveProjectPath } from '../utils/paths.js';\nimport { discoverMmdFiles } from '../project/discovery.js';\n\n/** All parsed annotation data from a .mmd file */\ninterface AnnotationData {\n raw: string;\n mermaidContent: string;\n flags: Map<string, Flag>;\n statuses: Map<string, NodeStatus>;\n breakpoints: Set<string>;\n risks: Map<string, RiskAnnotation>;\n ghosts: GhostPathAnnotation[];\n}\n\n/**\n * DiagramService -- single entry point for all .mmd file operations.\n * Each instance is bound to a project root for path security.\n */\nexport class DiagramService {\n /** Per-file write locks to serialize concurrent write operations */\n private writeLocks = new Map<string, Promise<void>>();\n\n /**\n * Serialize write operations on a given file path.\n * Each call waits for the previous write on the same file to finish before running.\n * Cleans up lock entry when no further writes are queued.\n */\n private async withWriteLock<T>(filePath: string, fn: () => Promise<T>): Promise<T> {\n const prev = this.writeLocks.get(filePath) ?? Promise.resolve();\n const current = prev.then(fn, fn); // run fn after previous completes (even if it failed)\n const settled = current.then(() => {}, () => {}); // swallow errors for the lock chain\n this.writeLocks.set(filePath, settled);\n const result = await current;\n // Clean up lock entry if no subsequent write has been queued\n if (this.writeLocks.get(filePath) === settled) {\n this.writeLocks.delete(filePath);\n }\n return result;\n }\n\n constructor(private readonly projectRoot: string) {}\n\n /**\n * Read a .mmd file and parse all annotations + mermaid content in one pass.\n */\n private async readAllAnnotations(filePath: string): Promise<AnnotationData> {\n const resolved = this.resolvePath(filePath);\n const raw = await readFile(resolved, 'utf-8');\n const { mermaidContent } = parseDiagramContent(raw);\n const { flags, statuses, breakpoints, risks, ghosts } = parseAllAnnotations(raw);\n return { raw, mermaidContent, flags, statuses, breakpoints, risks, ghosts };\n }\n\n /**\n * Read-modify-write cycle for annotation mutations.\n * Acquires the write lock, reads all annotations, calls modifyFn to mutate them,\n * then writes the result back.\n */\n private async modifyAnnotation(\n filePath: string,\n modifyFn: (data: AnnotationData) => void,\n ): Promise<void> {\n return this.withWriteLock(filePath, async () => {\n const data = await this.readAllAnnotations(filePath);\n modifyFn(data);\n await this._writeDiagramInternal(\n filePath, data.mermaidContent, data.flags, data.statuses, data.breakpoints, data.risks, data.ghosts,\n );\n });\n }\n\n /**\n * Read and parse a .mmd file.\n * Resolves path with traversal protection, parses content, and validates syntax.\n */\n async readDiagram(filePath: string): Promise<DiagramContent> {\n const resolved = this.resolvePath(filePath);\n const raw = await readFile(resolved, 'utf-8');\n const { mermaidContent, diagramType } = parseDiagramContent(raw);\n const { flags, statuses, breakpoints, risks, ghosts } = parseAllAnnotations(raw);\n const validation = validateMermaidSyntax(mermaidContent);\n\n // Ensure diagramType from parser is reflected in validation result\n if (diagramType && !validation.diagramType) {\n validation.diagramType = diagramType;\n }\n\n return { raw, mermaidContent, flags, statuses, breakpoints, risks, ghosts, validation, filePath };\n }\n\n /**\n * Read a .mmd file and parse it into a structured GraphModel.\n */\n async readGraph(filePath: string): Promise<GraphModel> {\n const resolved = this.resolvePath(filePath);\n const raw = await readFile(resolved, 'utf-8');\n return parseMermaidToGraph(raw, filePath);\n }\n\n /**\n * Write a .mmd file. If flags or statuses are provided, injects annotation block.\n * Creates parent directories if they don't exist.\n */\n async writeDiagram(\n filePath: string,\n content: string,\n flags?: Map<string, Flag>,\n statuses?: Map<string, NodeStatus>,\n breakpoints?: Set<string>,\n risks?: Map<string, RiskAnnotation>,\n ghosts?: GhostPathAnnotation[],\n ): Promise<void> {\n return this.withWriteLock(filePath, () =>\n this._writeDiagramInternal(filePath, content, flags, statuses, breakpoints, risks, ghosts),\n );\n }\n\n /**\n * Write diagram content while preserving existing developer-owned annotations (flags, breakpoints).\n * Reads existing annotations first, merges caller-provided statuses/risks/ghosts on top, preserves flags\n * and breakpoints unconditionally, then writes the merged result atomically under the write lock.\n *\n * Merge semantics:\n * - `content`: always replaces the Mermaid diagram body\n * - `statuses`: if provided, replaces all statuses; if undefined, preserves existing\n * - `risks`: if provided, replaces all risks; if undefined, preserves existing\n * - `ghosts`: if provided, replaces all ghosts; if undefined, preserves existing\n * - `flags`: always preserved from the file (developer-owned, never touched by MCP)\n * - `breakpoints`: always preserved from the file (developer-owned, never touched by MCP)\n */\n async writeDiagramPreserving(\n filePath: string,\n content: string,\n statuses?: Map<string, NodeStatus>,\n risks?: Map<string, RiskAnnotation>,\n ghosts?: GhostPathAnnotation[],\n ): Promise<void> {\n return this.withWriteLock(filePath, async () => {\n // Read existing annotations (if file exists)\n let existingFlags = new Map<string, Flag>();\n let existingBreakpoints = new Set<string>();\n let existingStatuses = new Map<string, NodeStatus>();\n let existingRisks = new Map<string, RiskAnnotation>();\n let existingGhosts: GhostPathAnnotation[] = [];\n try {\n const data = await this.readAllAnnotations(filePath);\n existingFlags = data.flags;\n existingBreakpoints = data.breakpoints;\n existingStatuses = data.statuses;\n existingRisks = data.risks;\n existingGhosts = data.ghosts;\n } catch {\n // File doesn't exist yet -- empty defaults are fine\n }\n\n await this._writeDiagramInternal(\n filePath,\n content,\n existingFlags, // always preserve\n statuses ?? existingStatuses, // replace if provided, else preserve\n existingBreakpoints, // always preserve\n risks ?? existingRisks, // replace if provided, else preserve\n ghosts ?? existingGhosts, // replace if provided, else preserve\n );\n });\n }\n\n /**\n * Write raw content to a .mmd file under the write lock.\n * Does NOT process annotations -- writes content as-is.\n * Used by /save endpoint which receives pre-formatted content from the editor.\n */\n async writeRaw(filePath: string, content: string): Promise<void> {\n return this.withWriteLock(filePath, async () => {\n const resolved = this.resolvePath(filePath);\n await mkdir(dirname(resolved), { recursive: true });\n await writeFile(resolved, content, 'utf-8');\n });\n }\n\n /**\n * Internal write without acquiring the lock.\n * Used by methods that already hold the write lock for the same file.\n */\n private async _writeDiagramInternal(\n filePath: string,\n content: string,\n flags?: Map<string, Flag>,\n statuses?: Map<string, NodeStatus>,\n breakpoints?: Set<string>,\n risks?: Map<string, RiskAnnotation>,\n ghosts?: GhostPathAnnotation[],\n ): Promise<void> {\n const resolved = this.resolvePath(filePath);\n let output = content;\n\n if (flags || statuses || breakpoints || risks || (ghosts && ghosts.length > 0)) {\n output = injectAnnotations(content, flags ?? new Map(), statuses, breakpoints, risks, ghosts);\n }\n\n await mkdir(dirname(resolved), { recursive: true });\n await writeFile(resolved, output, 'utf-8');\n }\n\n /** Get all flags from a .mmd file as an array. */\n async getFlags(filePath: string): Promise<Flag[]> {\n const diagram = await this.readDiagram(filePath);\n return Array.from(diagram.flags.values());\n }\n\n /** Set (add or update) a flag on a specific node. */\n async setFlag(filePath: string, nodeId: string, message: string): Promise<void> {\n return this.modifyAnnotation(filePath, (data) => {\n data.flags.set(nodeId, { nodeId, message });\n });\n }\n\n /** Remove a flag from a specific node. */\n async removeFlag(filePath: string, nodeId: string): Promise<void> {\n return this.modifyAnnotation(filePath, (data) => {\n data.flags.delete(nodeId);\n });\n }\n\n /** Get all statuses from a .mmd file. */\n async getStatuses(filePath: string): Promise<Map<string, NodeStatus>> {\n const diagram = await this.readDiagram(filePath);\n return diagram.statuses;\n }\n\n /** Set (add or update) a status on a specific node. */\n async setStatus(filePath: string, nodeId: string, status: NodeStatus): Promise<void> {\n return this.modifyAnnotation(filePath, (data) => {\n data.statuses.set(nodeId, status);\n });\n }\n\n /** Remove a status from a specific node. */\n async removeStatus(filePath: string, nodeId: string): Promise<void> {\n return this.modifyAnnotation(filePath, (data) => {\n data.statuses.delete(nodeId);\n });\n }\n\n /** Get all breakpoints from a .mmd file. */\n async getBreakpoints(filePath: string): Promise<Set<string>> {\n const resolved = this.resolvePath(filePath);\n const raw = await readFile(resolved, 'utf-8');\n return parseAllAnnotations(raw).breakpoints;\n }\n\n /** Set (add) a breakpoint on a specific node. */\n async setBreakpoint(filePath: string, nodeId: string): Promise<void> {\n return this.modifyAnnotation(filePath, (data) => {\n data.breakpoints.add(nodeId);\n });\n }\n\n /** Remove a breakpoint from a specific node. */\n async removeBreakpoint(filePath: string, nodeId: string): Promise<void> {\n return this.modifyAnnotation(filePath, (data) => {\n data.breakpoints.delete(nodeId);\n });\n }\n\n /** Get all risk annotations from a .mmd file. */\n async getRisks(filePath: string): Promise<Map<string, RiskAnnotation>> {\n const resolved = this.resolvePath(filePath);\n const raw = await readFile(resolved, 'utf-8');\n return parseAllAnnotations(raw).risks;\n }\n\n /** Set (add or update) a risk annotation on a specific node. */\n async setRisk(filePath: string, nodeId: string, level: RiskLevel, reason: string): Promise<void> {\n return this.modifyAnnotation(filePath, (data) => {\n data.risks.set(nodeId, { nodeId, level, reason });\n });\n }\n\n /** Remove a risk annotation from a specific node. */\n async removeRisk(filePath: string, nodeId: string): Promise<void> {\n return this.modifyAnnotation(filePath, (data) => {\n data.risks.delete(nodeId);\n });\n }\n\n /** Get all ghost path annotations from a .mmd file. */\n async getGhosts(filePath: string): Promise<GhostPathAnnotation[]> {\n const resolved = this.resolvePath(filePath);\n const raw = await readFile(resolved, 'utf-8');\n return parseAllAnnotations(raw).ghosts;\n }\n\n /** Add a ghost path annotation to a .mmd file. */\n async addGhost(filePath: string, fromNodeId: string, toNodeId: string, label: string): Promise<void> {\n return this.modifyAnnotation(filePath, (data) => {\n data.ghosts.push({ fromNodeId, toNodeId, label });\n });\n }\n\n /** Remove a specific ghost path annotation (by from+to+label exact match). */\n async removeGhost(filePath: string, fromNodeId: string, toNodeId: string): Promise<void> {\n return this.modifyAnnotation(filePath, (data) => {\n data.ghosts = data.ghosts.filter(\n (g) => !(g.fromNodeId === fromNodeId && g.toNodeId === toNodeId),\n );\n });\n }\n\n /** Clear all ghost path annotations from a .mmd file. */\n async clearGhosts(filePath: string): Promise<void> {\n return this.modifyAnnotation(filePath, (data) => {\n data.ghosts = [];\n });\n }\n\n /** Validate the Mermaid syntax of a .mmd file. */\n async validate(filePath: string): Promise<ValidationResult> {\n const diagram = await this.readDiagram(filePath);\n return diagram.validation;\n }\n\n /** List all .mmd files in the project root. */\n async listFiles(): Promise<string[]> {\n return discoverMmdFiles(this.projectRoot);\n }\n\n /**\n * Resolve a relative file path against the project root.\n * Single chokepoint for path security -- rejects path traversal.\n */\n private resolvePath(filePath: string): string {\n return resolveProjectPath(this.projectRoot, filePath);\n }\n}\n","import { readFile } from 'node:fs/promises';\nimport { extname } from 'node:path';\nimport type { ServerResponse } from 'node:http';\n\n/**\n * MIME type mappings for static file serving.\n * Only includes types used by the diagram viewer.\n */\nexport const MIME_TYPES: Record<string, string> = {\n '.html': 'text/html; charset=utf-8',\n '.js': 'application/javascript; charset=utf-8',\n '.css': 'text/css; charset=utf-8',\n '.json': 'application/json; charset=utf-8',\n '.svg': 'image/svg+xml',\n '.png': 'image/png',\n '.mmd': 'text/plain; charset=utf-8',\n};\n\n/**\n * Serve a static file from the given path.\n * Sets appropriate Content-Type based on file extension.\n *\n * @returns true if file was served, false if not found\n */\nexport async function serveStaticFile(\n res: ServerResponse,\n filePath: string,\n): Promise<boolean> {\n try {\n const content = await readFile(filePath);\n const ext = extname(filePath);\n const mime = MIME_TYPES[ext] ?? 'application/octet-stream';\n res.writeHead(200, { 'Content-Type': mime });\n res.end(content);\n return true;\n } catch {\n return false;\n }\n}\n","/**\n * SmartCode — Collapser Parser Module\n * Parses Mermaid subgraph structures and counts nodes.\n */\n\nimport { SUBGRAPH_START, SUBGRAPH_END } from './constants.js';\n\n// ─── Types ───────────────────────────────────────────────────────────────────\n\nexport interface SubgraphInfo {\n id: string;\n label: string;\n startLine: number;\n endLine: number;\n nodeIds: string[]; // nodes directly inside this subgraph\n childSubgraphs: string[]; // nested subgraph IDs\n parent: string | null; // parent subgraph ID or null for root-level\n}\n\nexport interface CollapseState {\n collapsed: Set<string>; // subgraph IDs currently collapsed\n focusPath: string[]; // path of subgraph IDs from root to focus\n focusedSubgraph: string | null; // the subgraph currently in focus\n}\n\n// ─── Regex Patterns ──────────────────────────────────────────────────────────\n\nconst NODE_DEF = /^\\s*(\\w[\\w\\d_-]*)(?:\\s*\\[|\\s*\\(|\\s*\\{|\\s*\\[\\[|\\s*>)/;\nconst EDGE_LINE = /^\\s*(\\w[\\w\\d_-]*)\\s*(?:-->|---|-\\.-|-.->|==>|-.->)/;\n\n// ─── Parsing ─────────────────────────────────────────────────────────────────\n\n/**\n * Parse Mermaid content to extract subgraph structure.\n */\nexport function parseSubgraphs(content: string): Map<string, SubgraphInfo> {\n const subgraphs = new Map<string, SubgraphInfo>();\n const lines = content.split('\\n');\n const stack: SubgraphInfo[] = [];\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]!;\n const startMatch = line.match(SUBGRAPH_START);\n\n if (startMatch) {\n const id = startMatch[1]!;\n const label = startMatch[2] || id;\n const parent = stack.length > 0 ? stack[stack.length - 1]!.id : null;\n\n const info: SubgraphInfo = {\n id,\n label,\n startLine: i,\n endLine: -1,\n nodeIds: [],\n childSubgraphs: [],\n parent,\n };\n\n stack.push(info);\n\n if (parent) {\n const parentInfo = subgraphs.get(parent) || stack.find(s => s.id === parent);\n if (parentInfo) parentInfo.childSubgraphs.push(id);\n }\n continue;\n }\n\n if (SUBGRAPH_END.test(line) && stack.length > 0) {\n const completed = stack.pop()!;\n completed.endLine = i;\n subgraphs.set(completed.id, completed);\n continue;\n }\n\n // Track nodes inside current subgraph\n if (stack.length > 0) {\n const current = stack[stack.length - 1]!;\n const nodeMatch = line.match(NODE_DEF);\n const edgeMatch = line.match(EDGE_LINE);\n\n if (nodeMatch && !current.nodeIds.includes(nodeMatch[1]!)) {\n current.nodeIds.push(nodeMatch[1]!);\n } else if (edgeMatch && !current.nodeIds.includes(edgeMatch[1]!)) {\n current.nodeIds.push(edgeMatch[1]!);\n }\n }\n }\n\n // Handle unclosed subgraphs\n while (stack.length > 0) {\n const incomplete = stack.pop()!;\n incomplete.endLine = lines.length - 1;\n subgraphs.set(incomplete.id, incomplete);\n }\n\n return subgraphs;\n}\n\n// ─── Node Counting ───────────────────────────────────────────────────────────\n\n/**\n * Count all node definitions in Mermaid content.\n */\nexport function countAllNodes(content: string): number {\n const seen = new Set<string>();\n const lines = content.split('\\n');\n\n for (const line of lines) {\n const nodeMatch = line.match(NODE_DEF);\n const edgeMatch = line.match(EDGE_LINE);\n if (nodeMatch) seen.add(nodeMatch[1]!);\n if (edgeMatch) seen.add(edgeMatch[1]!);\n }\n\n return seen.size;\n}\n\n/**\n * Count nodes recursively inside a subgraph (including children).\n */\nexport function countNodesInSubgraph(\n info: SubgraphInfo,\n subgraphs: Map<string, SubgraphInfo>\n): number {\n let count = info.nodeIds.length;\n\n for (const childId of info.childSubgraphs) {\n const child = subgraphs.get(childId);\n if (child) count += countNodesInSubgraph(child, subgraphs);\n }\n\n return count;\n}\n\n/**\n * Count visible nodes after collapse is applied.\n */\nexport function countVisibleNodes(\n content: string,\n subgraphs: Map<string, SubgraphInfo>,\n state: CollapseState\n): number {\n let total = countAllNodes(content);\n\n for (const subgraphId of state.collapsed) {\n const info = subgraphs.get(subgraphId);\n if (!info) continue;\n // Skip if parent is also collapsed (parent's count already includes this)\n if (info.parent && state.collapsed.has(info.parent)) continue;\n // Subtract nodes in collapsed subgraph\n total -= countNodesInSubgraph(info, subgraphs);\n // Add 1 for the summary node\n total += 1;\n }\n\n return Math.max(0, total);\n}\n\n/**\n * Get leaf subgraphs (those with no children).\n */\nexport function getLeafSubgraphs(subgraphs: Map<string, SubgraphInfo>): SubgraphInfo[] {\n return [...subgraphs.values()].filter(s => s.childSubgraphs.length === 0);\n}\n\n/**\n * Get all node IDs recursively inside a subgraph (including children).\n */\nexport function getAllNodesInSubgraph(\n info: SubgraphInfo,\n subgraphs: Map<string, SubgraphInfo>\n): string[] {\n const nodes = [...info.nodeIds];\n for (const childId of info.childSubgraphs) {\n const child = subgraphs.get(childId);\n if (child) nodes.push(...getAllNodesInSubgraph(child, subgraphs));\n }\n return nodes;\n}\n\n// ─── Focus Utilities ─────────────────────────────────────────────────────────\n\n/**\n * Find which subgraph contains a given node.\n */\nexport function findContainingSubgraph(\n nodeId: string,\n subgraphs: Map<string, SubgraphInfo>\n): string | null {\n let deepest: SubgraphInfo | null = null;\n\n for (const info of subgraphs.values()) {\n if (info.nodeIds.includes(nodeId)) {\n if (!deepest || (info.parent && info.parent === deepest.id)) {\n deepest = info;\n }\n }\n }\n\n return deepest?.id || null;\n}\n\n/**\n * Get path from root to a subgraph.\n */\nexport function getPathToRoot(\n subgraphId: string,\n subgraphs: Map<string, SubgraphInfo>\n): string[] {\n const path: string[] = [];\n let current = subgraphs.get(subgraphId);\n\n while (current) {\n path.unshift(current.id);\n current = current.parent ? subgraphs.get(current.parent) : undefined;\n }\n\n return path;\n}\n","/**\n * SmartCode — Collapser Transform Module\n * State management, auto-collapse, view generation, and focus mode.\n */\n\nimport type { SubgraphInfo, CollapseState } from './collapser-parser.js';\nimport {\n countVisibleNodes,\n countNodesInSubgraph,\n getLeafSubgraphs,\n getAllNodesInSubgraph,\n findContainingSubgraph,\n getPathToRoot,\n} from './collapser-parser.js';\n\n// ─── Config ──────────────────────────────────────────────────────────────────\n\nexport interface CollapseConfig {\n collapsedNodePrefix: string;\n maxVisibleNodes: number;\n autoCollapse: boolean;\n}\n\nexport interface CollapsedDiagram {\n content: string;\n visibleNodes: number;\n autoCollapsed: string[];\n manualCollapsed: string[];\n}\n\nexport const DEFAULT_CONFIG: CollapseConfig = {\n collapsedNodePrefix: '__collapsed__',\n maxVisibleNodes: 50,\n autoCollapse: true,\n};\n\n// ─── State Factory ───────────────────────────────────────────────────────────\n\nexport function createEmptyState(): CollapseState {\n return {\n collapsed: new Set(),\n focusPath: [],\n focusedSubgraph: null,\n };\n}\n\n// ─── State Management ────────────────────────────────────────────────────────\n\n/**\n * Toggle collapse state for a subgraph.\n */\nexport function toggleSubgraph(\n state: CollapseState,\n subgraphId: string,\n subgraphs: Map<string, SubgraphInfo>\n): CollapseState {\n const newCollapsed = new Set(state.collapsed);\n\n if (newCollapsed.has(subgraphId)) {\n // Expanding - also expand all parents\n newCollapsed.delete(subgraphId);\n let current = subgraphs.get(subgraphId);\n while (current?.parent) {\n newCollapsed.delete(current.parent);\n current = subgraphs.get(current.parent);\n }\n } else {\n // Collapsing\n newCollapsed.add(subgraphId);\n }\n\n return { ...state, collapsed: newCollapsed };\n}\n\n// ─── Auto-Collapse ───────────────────────────────────────────────────────────\n\n/**\n * Auto-collapse largest leaf subgraphs until under node limit.\n */\nexport function autoCollapseToLimit(\n content: string,\n subgraphs: Map<string, SubgraphInfo>,\n state: CollapseState,\n config: CollapseConfig\n): CollapseState {\n if (!config.autoCollapse) return state;\n\n const newCollapsed = new Set(state.collapsed);\n let visibleNodes = countVisibleNodes(content, subgraphs, { ...state, collapsed: newCollapsed });\n\n while (visibleNodes > config.maxVisibleNodes) {\n // Find uncollapsed leaf subgraphs\n const leaves = getLeafSubgraphs(subgraphs)\n .filter(s => !newCollapsed.has(s.id))\n .sort((a, b) => countNodesInSubgraph(b, subgraphs) - countNodesInSubgraph(a, subgraphs));\n\n if (leaves.length === 0) break;\n\n // Collapse largest leaf\n const largest = leaves[0]!;\n newCollapsed.add(largest.id);\n visibleNodes = countVisibleNodes(content, subgraphs, { ...state, collapsed: newCollapsed });\n }\n\n return { ...state, collapsed: newCollapsed };\n}\n\n// ─── Utilities ───────────────────────────────────────────────────────────────\n\nfunction escapeRegExp(s: string): string {\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\n// ─── Transformation ──────────────────────────────────────────────────────────\n\n/**\n * Generate Mermaid content with collapsed subgraphs replaced by summary nodes.\n * Precompiles regex patterns for edge redirects to avoid per-line compilation.\n */\nexport function generateCollapsedView(\n content: string,\n subgraphs: Map<string, SubgraphInfo>,\n state: CollapseState,\n config: CollapseConfig = DEFAULT_CONFIG\n): CollapsedDiagram {\n // Apply auto-collapse\n const autoState = autoCollapseToLimit(content, subgraphs, state, config);\n const autoCollapsed = [...autoState.collapsed].filter(id => !state.collapsed.has(id));\n const manualCollapsed = [...state.collapsed];\n\n // Apply transformation\n const lines = content.split('\\n');\n const result: string[] = [];\n const edgeRedirects = new Map<string, string>();\n const skipRanges: Array<{ start: number; end: number; id: string }> = [];\n\n // Build skip ranges and edge redirects\n for (const subgraphId of autoState.collapsed) {\n const info = subgraphs.get(subgraphId);\n if (!info) continue;\n\n // Skip if parent is also collapsed\n if (info.parent && autoState.collapsed.has(info.parent)) continue;\n\n skipRanges.push({ start: info.startLine, end: info.endLine, id: subgraphId });\n\n // Redirect edges from nodes inside to summary node\n const summaryId = `${config.collapsedNodePrefix}${subgraphId}`;\n for (const nodeId of getAllNodesInSubgraph(info, subgraphs)) {\n edgeRedirects.set(nodeId, summaryId);\n }\n }\n\n // Sort ranges by start line\n skipRanges.sort((a, b) => a.start - b.start);\n\n // Precompile regex patterns for edge redirects (performance fix)\n const compiledRedirects: Array<{ regex: RegExp; replacement: string }> = [];\n for (const [from, to] of edgeRedirects) {\n compiledRedirects.push({\n regex: new RegExp(`\\\\b${escapeRegExp(from)}\\\\b`, 'g'),\n replacement: to,\n });\n }\n\n // Build output\n let skipIndex = 0;\n for (let i = 0; i < lines.length; i++) {\n // Check if in skip range\n if (skipIndex < skipRanges.length && i >= skipRanges[skipIndex]!.start) {\n if (i === skipRanges[skipIndex]!.start) {\n // Insert summary node at start of collapsed subgraph\n const range = skipRanges[skipIndex]!;\n const summaryId = `${config.collapsedNodePrefix}${range.id}`;\n const info = subgraphs.get(range.id)!;\n const nodeCount = countNodesInSubgraph(info, subgraphs);\n result.push(` ${summaryId}[\"[+]${info.label} (${nodeCount} nodes)\"]`);\n }\n if (i <= skipRanges[skipIndex]!.end) {\n if (i === skipRanges[skipIndex]!.end) skipIndex++;\n continue;\n }\n }\n\n // Redirect edges using precompiled regex\n let line = lines[i]!;\n for (const { regex, replacement } of compiledRedirects) {\n regex.lastIndex = 0; // reset stateful global regex\n line = line.replace(regex, replacement);\n }\n\n result.push(line);\n }\n\n const collapsedContent = result.join('\\n');\n const visibleNodes = countVisibleNodes(content, subgraphs, autoState);\n\n return {\n content: collapsedContent,\n visibleNodes,\n autoCollapsed,\n manualCollapsed,\n };\n}\n\n// ─── Focus Mode ──────────────────────────────────────────────────────────────\n\n/**\n * Enter focus mode on a specific node.\n */\nexport function focusOnNode(\n nodeId: string,\n subgraphs: Map<string, SubgraphInfo>,\n currentState: CollapseState\n): CollapseState {\n const containingSubgraph = findContainingSubgraph(nodeId, subgraphs);\n if (!containingSubgraph) return currentState;\n\n const focusPath = getPathToRoot(containingSubgraph, subgraphs);\n const newCollapsed = new Set<string>();\n\n // Collapse all subgraphs not in focus path that are siblings at any level\n for (const info of subgraphs.values()) {\n if (!focusPath.includes(info.id)) {\n // Collapse if parent is in focusPath (sibling at any level)\n // or if parent is null/undefined (root-level sibling)\n if (info.parent == null || focusPath.includes(info.parent)) {\n newCollapsed.add(info.id);\n }\n }\n }\n\n return {\n collapsed: newCollapsed,\n focusPath,\n focusedSubgraph: containingSubgraph,\n };\n}\n\n/**\n * Navigate to a specific breadcrumb.\n */\nexport function navigateToBreadcrumb(\n breadcrumbId: string,\n _subgraphs: Map<string, SubgraphInfo>, // reserved for future breadcrumb validation\n currentState: CollapseState\n): CollapseState {\n if (breadcrumbId === 'root') {\n return exitFocus();\n }\n\n const index = currentState.focusPath.indexOf(breadcrumbId);\n if (index === -1) return currentState;\n\n const newFocusPath = currentState.focusPath.slice(0, index + 1);\n const focusedSubgraph = newFocusPath[newFocusPath.length - 1] || null;\n\n return {\n ...currentState,\n focusPath: newFocusPath,\n focusedSubgraph,\n };\n}\n\n/**\n * Exit focus mode.\n */\nexport function exitFocus(): CollapseState {\n return {\n collapsed: new Set(),\n focusPath: [],\n focusedSubgraph: null,\n };\n}\n\n/**\n * Get breadcrumb path for current state.\n */\nexport function getBreadcrumbs(\n state: CollapseState,\n subgraphs: Map<string, SubgraphInfo>\n): Array<{ id: string; label: string }> {\n const crumbs: Array<{ id: string; label: string }> = [{ id: 'root', label: 'Overview' }];\n\n for (const id of state.focusPath) {\n const info = subgraphs.get(id);\n if (info) crumbs.push({ id, label: info.label });\n }\n\n return crumbs;\n}\n","/**\n * SmartCode — Subgraph Collapse/Expand Module\n *\n * Re-exports all public API from the split modules.\n * Import from this file for backward compatibility.\n *\n * Internal modules:\n * - collapser-parser.ts — Mermaid parsing, node counting, subgraph queries\n * - collapser-transform.ts — State management, auto-collapse, view generation, focus mode\n */\n\n// ─── Parser (types + functions) ──────────────────────────────────────────────\n\nexport type { SubgraphInfo, CollapseState } from './collapser-parser.js';\n\nexport {\n parseSubgraphs,\n countAllNodes,\n countNodesInSubgraph,\n countVisibleNodes,\n getLeafSubgraphs,\n getAllNodesInSubgraph,\n findContainingSubgraph,\n getPathToRoot,\n} from './collapser-parser.js';\n\n// ─── Transform (types + functions + config) ──────────────────────────────────\n\nexport type { CollapseConfig, CollapsedDiagram } from './collapser-transform.js';\n\nexport {\n DEFAULT_CONFIG,\n createEmptyState,\n toggleSubgraph,\n autoCollapseToLimit,\n generateCollapsedView,\n focusOnNode,\n navigateToBreadcrumb,\n exitFocus,\n getBreadcrumbs,\n} from './collapser-transform.js';\n","/**\n * SmartCode - GraphModel to Mermaid Serializer\n * Converts a structured GraphModel back into valid Mermaid flowchart text.\n * Counterpart to graph-parser.ts — together they enable round-trip fidelity.\n */\n\nimport type { GraphModel, GraphSubgraph, NodeShape } from './graph-types.js';\nimport { SHAPE_PATTERNS, EDGE_SYNTAX } from './graph-types.js';\n\n// ─── Shape reverse lookup ───────────────────────────────────────────────────\n\n/** Map from shape name to bracket pair { open, close } */\nconst SHAPE_BRACKETS = new Map<NodeShape, { open: string; close: string }>();\n\nfor (const sp of SHAPE_PATTERNS) {\n // Only set the first match per shape (SHAPE_PATTERNS is ordered longest-first)\n if (!SHAPE_BRACKETS.has(sp.shape)) {\n SHAPE_BRACKETS.set(sp.shape, { open: sp.open, close: sp.close });\n }\n}\n\n// ─── Main serializer ────────────────────────────────────────────────────────\n\n/**\n * Serialize a GraphModel to valid Mermaid flowchart text.\n *\n * Output order (canonical):\n * 1. Direction line: `flowchart LR`\n * 2. classDef directives\n * 3. Subgraph blocks (recursive, with nodes inside)\n * 4. Root-level nodes (not inside any subgraph)\n * 5. Edges\n * 6. style directives\n * 7. linkStyle directives\n * 8. class assignments\n */\nexport function serializeGraphToMermaid(graph: GraphModel): string {\n const lines: string[] = [];\n\n // 1. Direction line\n lines.push(`${graph.diagramType} ${graph.direction}`);\n\n // 2. classDef directives\n for (const [name, styles] of graph.classDefs) {\n lines.push(` classDef ${name} ${styles}`);\n }\n\n // 3. Subgraph blocks (recursive) — track which nodes are emitted inside subgraphs\n const emittedNodes = new Set<string>();\n\n // Find root-level subgraphs (parentId === null)\n const rootSubgraphs: GraphSubgraph[] = [];\n for (const sg of graph.subgraphs.values()) {\n if (sg.parentId === null) {\n rootSubgraphs.push(sg);\n }\n }\n\n for (const sg of rootSubgraphs) {\n emitSubgraph(graph, sg, lines, emittedNodes, 1);\n }\n\n // 4. Root-level nodes (not emitted inside any subgraph)\n for (const [id, node] of graph.nodes) {\n if (emittedNodes.has(id)) continue;\n lines.push(` ${serializeNode(id, node.label, node.shape)}`);\n }\n\n // 5. Edges\n for (const edge of graph.edges) {\n const arrow = serializeEdgeOperator(edge.type, edge.bidirectional, edge.label);\n lines.push(` ${edge.from} ${arrow} ${edge.to}`);\n }\n\n // 6. style directives\n for (const [nodeId, styles] of graph.nodeStyles) {\n lines.push(` style ${nodeId} ${styles}`);\n }\n\n // 7. linkStyle directives\n const sortedLinkStyles = [...graph.linkStyles.entries()].sort((a, b) => a[0] - b[0]);\n for (const [idx, styles] of sortedLinkStyles) {\n lines.push(` linkStyle ${idx} ${styles}`);\n }\n\n // 8. class assignments — group by class name\n const classGroups = new Map<string, string[]>();\n for (const [nodeId, className] of graph.classAssignments) {\n if (!classGroups.has(className)) {\n classGroups.set(className, []);\n }\n classGroups.get(className)!.push(nodeId);\n }\n for (const [className, nodeIds] of classGroups) {\n lines.push(` class ${nodeIds.join(',')} ${className}`);\n }\n\n return lines.join('\\n') + '\\n';\n}\n\n// ─── Subgraph emitter (recursive) ───────────────────────────────────────────\n\nfunction emitSubgraph(\n graph: GraphModel,\n sg: GraphSubgraph,\n lines: string[],\n emittedNodes: Set<string>,\n depth: number,\n): void {\n const indent = ' '.repeat(depth);\n\n // Subgraph header\n if (sg.label !== sg.id) {\n lines.push(`${indent}subgraph ${sg.id}[\"${sg.label}\"]`);\n } else {\n lines.push(`${indent}subgraph ${sg.id}`);\n }\n\n // Child subgraphs first\n for (const childId of sg.childSubgraphIds) {\n const child = graph.subgraphs.get(childId);\n if (child) {\n emitSubgraph(graph, child, lines, emittedNodes, depth + 1);\n }\n }\n\n // Nodes inside this subgraph\n for (const nodeId of sg.nodeIds) {\n const node = graph.nodes.get(nodeId);\n if (node) {\n lines.push(`${indent} ${serializeNode(nodeId, node.label, node.shape)}`);\n emittedNodes.add(nodeId);\n }\n }\n\n // Also emit nodes that have subgraphId matching this subgraph but aren't in nodeIds\n for (const [id, node] of graph.nodes) {\n if (node.subgraphId === sg.id && !emittedNodes.has(id)) {\n lines.push(`${indent} ${serializeNode(id, node.label, node.shape)}`);\n emittedNodes.add(id);\n }\n }\n\n lines.push(`${indent}end`);\n}\n\n// ─── Node serializer ────────────────────────────────────────────────────────\n\n/**\n * Serialize a single node definition.\n * - If label === id AND shape === 'rect', emit bare id\n * - Otherwise emit id + shape brackets + quoted label\n */\nfunction serializeNode(id: string, label: string, shape: NodeShape): string {\n if (label === id && shape === 'rect') {\n return id;\n }\n\n const brackets = SHAPE_BRACKETS.get(shape);\n if (!brackets) {\n // Fallback to rect brackets\n return `${id}[\"${label}\"]`;\n }\n\n return `${id}${brackets.open}\"${label}\"${brackets.close}`;\n}\n\n// ─── Edge operator serializer ───────────────────────────────────────────────\n\nfunction serializeEdgeOperator(\n type: string,\n bidirectional?: boolean,\n label?: string,\n): string {\n const baseSyntax = EDGE_SYNTAX[type as keyof typeof EDGE_SYNTAX] ?? '-->';\n\n if (bidirectional) {\n // Prepend '<' to make bidirectional: --> becomes <-->, -.-> becomes <-.->\n return `<${baseSyntax}`;\n }\n\n if (label) {\n // Insert label in pipe syntax: -->|\"label\"|\n return `${baseSyntax}|\"${label}\"|`;\n }\n\n return baseSyntax;\n}\n\n// ─── JSON serializer (for WebSocket / REST) ─────────────────────────────────\n\n/**\n * Serialize a GraphModel to a plain JSON-safe object.\n * Converts all Map fields to plain objects for transmission over WebSocket or REST.\n */\nexport function serializeGraphModel(graph: GraphModel): Record<string, unknown> {\n return {\n diagramType: graph.diagramType,\n direction: graph.direction,\n nodes: Object.fromEntries(graph.nodes),\n edges: graph.edges,\n subgraphs: Object.fromEntries(graph.subgraphs),\n classDefs: Object.fromEntries(graph.classDefs),\n nodeStyles: Object.fromEntries(graph.nodeStyles),\n linkStyles: Object.fromEntries(graph.linkStyles),\n classAssignments: Object.fromEntries(graph.classAssignments),\n filePath: graph.filePath,\n flags: Object.fromEntries(graph.flags),\n statuses: Object.fromEntries(graph.statuses),\n };\n}\n","import type { IncomingMessage, ServerResponse } from 'node:http';\nimport type { SessionStore } from '../session/session-store.js';\nimport { sendJson, type Route } from './server.js';\n\n/**\n * Register session REST endpoints.\n * Adds 2 routes to the provided routes array:\n * GET /api/sessions/:file -- list sessions for a diagram file\n * GET /api/session/:id -- get full session events\n *\n * Note: Heatmap endpoints moved to heatmap-routes.ts (Phase 19).\n */\nexport function registerSessionRoutes(routes: Route[], sessionStore: SessionStore): void {\n // -------------------------------------------------------\n // GET /api/sessions/:file -- List sessions for a diagram file\n // -------------------------------------------------------\n routes.push({\n method: 'GET',\n pattern: new RegExp('^/api/sessions/(?<file>.+)$'),\n handler: async (_req: IncomingMessage, res: ServerResponse, params: Record<string, string>) => {\n try {\n const file = decodeURIComponent(params['file']!);\n const sessionIds = await sessionStore.listSessions(file);\n\n // Enrich each session ID with summary data (totalEvents, duration)\n const sessions = await Promise.all(\n sessionIds.map(async (sessionId) => {\n try {\n const events = await sessionStore.readSession(sessionId);\n const startEvent = events.find((e) => e.type === 'session:start');\n const endEvent = events.find((e) => e.type === 'session:end');\n const startTs = startEvent?.ts ?? 0;\n const endTs = endEvent?.ts ?? (events.length > 0 ? events[events.length - 1]!.ts : 0);\n return {\n sessionId,\n totalEvents: events.length,\n duration: endTs - startTs,\n startedAt: startTs,\n };\n } catch {\n return { sessionId, totalEvents: 0, duration: 0, startedAt: 0 };\n }\n }),\n );\n\n sendJson(res, { sessions });\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Unknown error';\n sendJson(res, { error: message }, 500);\n }\n },\n });\n\n // -------------------------------------------------------\n // GET /api/session/:id -- Get full session events\n // -------------------------------------------------------\n routes.push({\n method: 'GET',\n pattern: new RegExp('^/api/session/(?<id>[^/]+)$'),\n handler: async (_req: IncomingMessage, res: ServerResponse, params: Record<string, string>) => {\n try {\n const id = decodeURIComponent(params['id']!);\n if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(id)) {\n sendJson(res, { error: 'Invalid session ID' }, 400);\n return;\n }\n const events = await sessionStore.readSession(id);\n if (events.length === 0) {\n sendJson(res, { error: 'Session not found' }, 404);\n return;\n }\n sendJson(res, { events });\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Unknown error';\n sendJson(res, { error: message }, 500);\n }\n },\n });\n\n}\n","/**\n * A node in the file tree returned by /tree.json.\n */\nexport interface TreeNode {\n type: 'file' | 'folder';\n name: string;\n path?: string;\n children?: TreeNode[];\n}\n\n/**\n * Convert a flat list of relative file paths into a nested tree structure.\n * Used by /tree.json to match the format expected by live.html sidebar.\n */\nexport function buildFileTree(files: string[]): TreeNode[] {\n const root: TreeNode[] = [];\n\n for (const filePath of files) {\n const parts = filePath.split('/');\n let current = root;\n\n for (let i = 0; i < parts.length; i++) {\n const part = parts[i]!;\n const isFile = i === parts.length - 1;\n\n if (isFile) {\n current.push({ type: 'file', name: part, path: filePath });\n } else {\n let folder = current.find(\n (n) => n.type === 'folder' && n.name === part,\n );\n if (!folder) {\n folder = { type: 'folder', name: part, children: [] };\n current.push(folder);\n }\n current = folder.children!;\n }\n }\n }\n\n return root;\n}\n","import { mkdir, unlink, rename, rm } from 'node:fs/promises';\nimport path from 'node:path';\nimport type { IncomingMessage, ServerResponse } from 'node:http';\nimport type { DiagramService } from '../diagram/service.js';\nimport { resolveProjectPath } from '../utils/paths.js';\nimport { sendJson, readJsonBody, type Route } from './server.js';\nimport { buildFileTree } from './file-tree.js';\n\n/**\n * Register file CRUD routes: tree, save, delete, mkdir, move, rmdir.\n * Follows the same pattern as session-routes.ts.\n */\nexport function registerFileRoutes(\n routes: Route[],\n service: DiagramService,\n projectDir: string,\n): void {\n // -------------------------------------------------------\n // GET /tree.json -- File tree for sidebar\n // -------------------------------------------------------\n routes.push({\n method: 'GET',\n pattern: new RegExp('^/tree\\\\.json$'),\n handler: async (_req: IncomingMessage, res: ServerResponse) => {\n try {\n const files = await service.listFiles();\n const tree = buildFileTree(files);\n sendJson(res, tree);\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Unknown error';\n sendJson(res, { error: message }, 500);\n }\n },\n });\n\n // -------------------------------------------------------\n // POST /save -- Save diagram content\n // -------------------------------------------------------\n routes.push({\n method: 'POST',\n pattern: new RegExp('^/save$'),\n handler: async (req: IncomingMessage, res: ServerResponse) => {\n try {\n const body = await readJsonBody<{ filename: string; content: string }>(req);\n if (!body.filename || body.content === undefined) {\n sendJson(res, { error: 'Missing filename or content' }, 400);\n return;\n }\n await service.writeRaw(body.filename, body.content);\n sendJson(res, { ok: true });\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Unknown error';\n if (message === 'Payload too large') { sendJson(res, { error: message }, 413); return; }\n const code = (err as NodeJS.ErrnoException)?.code;\n sendJson(res, { error: message }, code === 'ENOENT' ? 404 : 500);\n }\n },\n });\n\n // -------------------------------------------------------\n // POST /delete -- Delete diagram file\n // -------------------------------------------------------\n routes.push({\n method: 'POST',\n pattern: new RegExp('^/delete$'),\n handler: async (req: IncomingMessage, res: ServerResponse) => {\n try {\n const body = await readJsonBody<{ filename: string }>(req);\n if (!body.filename) {\n sendJson(res, { error: 'Missing filename' }, 400);\n return;\n }\n const resolved = resolveProjectPath(projectDir, body.filename);\n await unlink(resolved);\n sendJson(res, { ok: true });\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Unknown error';\n if (message === 'Payload too large') { sendJson(res, { error: message }, 413); return; }\n const code = (err as NodeJS.ErrnoException)?.code;\n sendJson(res, { error: message }, code === 'ENOENT' ? 404 : 500);\n }\n },\n });\n\n // -------------------------------------------------------\n // POST /mkdir -- Create directory\n // -------------------------------------------------------\n routes.push({\n method: 'POST',\n pattern: new RegExp('^/mkdir$'),\n handler: async (req: IncomingMessage, res: ServerResponse) => {\n try {\n const body = await readJsonBody<{ folder: string }>(req);\n if (!body.folder) {\n sendJson(res, { error: 'Missing folder' }, 400);\n return;\n }\n const resolved = resolveProjectPath(projectDir, body.folder);\n await mkdir(resolved, { recursive: true });\n sendJson(res, { ok: true });\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Unknown error';\n if (message === 'Payload too large') { sendJson(res, { error: message }, 413); return; }\n sendJson(res, { error: message }, 500);\n }\n },\n });\n\n // -------------------------------------------------------\n // POST /move -- Rename/move file\n // -------------------------------------------------------\n routes.push({\n method: 'POST',\n pattern: new RegExp('^/move$'),\n handler: async (req: IncomingMessage, res: ServerResponse) => {\n try {\n const body = await readJsonBody<{ from: string; to: string }>(req);\n if (!body.from || !body.to) {\n sendJson(res, { error: 'Missing from or to' }, 400);\n return;\n }\n const resolvedFrom = resolveProjectPath(projectDir, body.from);\n const resolvedTo = resolveProjectPath(projectDir, body.to);\n await mkdir(path.dirname(resolvedTo), { recursive: true });\n await rename(resolvedFrom, resolvedTo);\n sendJson(res, { ok: true });\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Unknown error';\n if (message === 'Payload too large') { sendJson(res, { error: message }, 413); return; }\n const code = (err as NodeJS.ErrnoException)?.code;\n sendJson(res, { error: message }, code === 'ENOENT' ? 404 : 500);\n }\n },\n });\n\n // -------------------------------------------------------\n // POST /rmdir -- Delete directory recursively\n // -------------------------------------------------------\n routes.push({\n method: 'POST',\n pattern: new RegExp('^/rmdir$'),\n handler: async (req: IncomingMessage, res: ServerResponse) => {\n try {\n const body = await readJsonBody<{ folder: string }>(req);\n if (!body.folder) {\n sendJson(res, { error: 'Missing folder' }, 400);\n return;\n }\n const resolved = resolveProjectPath(projectDir, body.folder);\n await rm(resolved, { recursive: true });\n sendJson(res, { ok: true });\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Unknown error';\n if (message === 'Payload too large') { sendJson(res, { error: message }, 413); return; }\n const code = (err as NodeJS.ErrnoException)?.code;\n sendJson(res, { error: message }, code === 'ENOENT' ? 404 : 500);\n }\n },\n });\n}\n","import type { IncomingMessage, ServerResponse } from 'node:http';\nimport type { DiagramService } from '../diagram/service.js';\nimport type { WebSocketManager } from './websocket.js';\nimport { sendJson, readJsonBody, type Route } from './server.js';\n\n/**\n * Register breakpoint REST endpoints.\n * Follows the same pattern as session-routes.ts.\n */\nexport function registerBreakpointRoutes(\n routes: Route[],\n service: DiagramService,\n wsManager?: WebSocketManager,\n breakpointContinueSignals?: Map<string, boolean>,\n): void {\n // -------------------------------------------------------\n // POST /api/breakpoints/:file/continue -- Signal continue past breakpoint\n // (must be registered BEFORE the general breakpoints route)\n // -------------------------------------------------------\n routes.push({\n method: 'POST',\n pattern: new RegExp('^/api/breakpoints/(?<file>.+)/continue$'),\n handler: async (req: IncomingMessage, res: ServerResponse, params: Record<string, string>) => {\n try {\n const file = decodeURIComponent(params['file']!);\n const body = await readJsonBody<{ nodeId: string }>(req);\n if (!body.nodeId) {\n sendJson(res, { error: 'Missing nodeId' }, 400);\n return;\n }\n if (breakpointContinueSignals) {\n // Prevent unbounded growth: evict oldest if map exceeds 500 entries\n if (breakpointContinueSignals.size >= 500) {\n const firstKey = breakpointContinueSignals.keys().next().value;\n if (firstKey !== undefined) breakpointContinueSignals.delete(firstKey);\n }\n breakpointContinueSignals.set(`${file}:${body.nodeId}`, true);\n }\n if (wsManager) {\n wsManager.broadcastAll({ type: 'breakpoint:continue', file, nodeId: body.nodeId });\n }\n sendJson(res, { ok: true });\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Unknown error';\n if (message === 'Payload too large') { sendJson(res, { error: message }, 413); return; }\n sendJson(res, { error: message }, 500);\n }\n },\n });\n\n // -------------------------------------------------------\n // GET /api/breakpoints/:file -- Get all breakpoints for a file\n // -------------------------------------------------------\n routes.push({\n method: 'GET',\n pattern: new RegExp('^/api/breakpoints/(?<file>.+)$'),\n handler: async (_req: IncomingMessage, res: ServerResponse, params: Record<string, string>) => {\n try {\n const file = decodeURIComponent(params['file']!);\n const breakpoints = await service.getBreakpoints(file);\n sendJson(res, { breakpoints: Array.from(breakpoints) });\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Unknown error';\n const code = (err as NodeJS.ErrnoException)?.code;\n sendJson(res, { error: message }, code === 'ENOENT' ? 404 : 500);\n }\n },\n });\n\n // -------------------------------------------------------\n // POST /api/breakpoints/:file -- Set or remove a breakpoint\n // -------------------------------------------------------\n routes.push({\n method: 'POST',\n pattern: new RegExp('^/api/breakpoints/(?<file>.+)$'),\n handler: async (req: IncomingMessage, res: ServerResponse, params: Record<string, string>) => {\n try {\n const file = decodeURIComponent(params['file']!);\n const body = await readJsonBody<{ nodeId: string; action: 'set' | 'remove' }>(req);\n if (!body.nodeId || !body.action) {\n sendJson(res, { error: 'Missing nodeId or action' }, 400);\n return;\n }\n if (body.action === 'set') {\n await service.setBreakpoint(file, body.nodeId);\n if (wsManager) {\n wsManager.broadcastAll({ type: 'breakpoint:hit', file, nodeId: body.nodeId });\n }\n } else {\n await service.removeBreakpoint(file, body.nodeId);\n }\n sendJson(res, { ok: true });\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Unknown error';\n if (message === 'Payload too large') { sendJson(res, { error: message }, 413); return; }\n const code = (err as NodeJS.ErrnoException)?.code;\n sendJson(res, { error: message }, code === 'ENOENT' ? 404 : 500);\n }\n },\n });\n}\n","import type { IncomingMessage, ServerResponse } from 'node:http';\nimport type { DiagramService } from '../diagram/service.js';\nimport type { WebSocketManager } from './websocket.js';\nimport { sendJson, readJsonBody, type Route } from './server.js';\n\n/**\n * Register ghost path REST endpoints.\n * Ghost paths are now persisted as @ghost annotations in .mmd files via DiagramService.\n */\nexport function registerGhostPathRoutes(\n routes: Route[],\n service: DiagramService,\n wsManager?: WebSocketManager,\n): void {\n // -------------------------------------------------------\n // GET /api/ghost-paths/:file -- Get ghost paths for a file\n // -------------------------------------------------------\n routes.push({\n method: 'GET',\n pattern: new RegExp('^/api/ghost-paths/(?<file>.+)$'),\n handler: async (_req: IncomingMessage, res: ServerResponse, params: Record<string, string>) => {\n try {\n const file = decodeURIComponent(params['file']!);\n const ghosts = await service.getGhosts(file);\n sendJson(res, { ghostPaths: ghosts });\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Unknown error';\n const code = (err as NodeJS.ErrnoException)?.code;\n sendJson(res, { error: message }, code === 'ENOENT' ? 404 : 500);\n }\n },\n });\n\n // -------------------------------------------------------\n // POST /api/ghost-paths/:file -- Add a ghost path\n // -------------------------------------------------------\n routes.push({\n method: 'POST',\n pattern: new RegExp('^/api/ghost-paths/(?<file>.+)$'),\n handler: async (req: IncomingMessage, res: ServerResponse, params: Record<string, string>) => {\n try {\n const file = decodeURIComponent(params['file']!);\n const body = await readJsonBody<{ fromNodeId: string; toNodeId: string; label?: string }>(req);\n if (!body.fromNodeId || !body.toNodeId) {\n sendJson(res, { error: 'Missing fromNodeId or toNodeId' }, 400);\n return;\n }\n await service.addGhost(file, body.fromNodeId, body.toNodeId, body.label ?? '');\n const ghostPaths = await service.getGhosts(file);\n if (wsManager) {\n wsManager.broadcastAll({ type: 'ghost:update', file, ghostPaths });\n }\n sendJson(res, { ok: true });\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Unknown error';\n if (message === 'Payload too large') { sendJson(res, { error: message }, 413); return; }\n sendJson(res, { error: message }, 500);\n }\n },\n });\n\n // -------------------------------------------------------\n // DELETE /api/ghost-paths/:file -- Clear all ghost paths for a file\n // -------------------------------------------------------\n routes.push({\n method: 'DELETE',\n pattern: new RegExp('^/api/ghost-paths/(?<file>.+)$'),\n handler: async (_req: IncomingMessage, res: ServerResponse, params: Record<string, string>) => {\n try {\n const file = decodeURIComponent(params['file']!);\n await service.clearGhosts(file);\n if (wsManager) {\n wsManager.broadcastAll({ type: 'ghost:update', file, ghostPaths: [] });\n }\n sendJson(res, { ok: true });\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Unknown error';\n sendJson(res, { error: message }, 500);\n }\n },\n });\n}\n","import type { IncomingMessage, ServerResponse } from 'node:http';\nimport type { DiagramService } from '../diagram/service.js';\nimport type { RiskLevel } from '../diagram/types.js';\nimport { sendJson, readJsonBody, type Route } from './server.js';\n\nconst VALID_RISK_LEVELS = new Set<string>(['high', 'medium', 'low']);\n\n/**\n * Register annotation REST endpoints (risk levels).\n * Follows the same pattern as breakpoint-routes.ts.\n */\nexport function registerAnnotationRoutes(\n routes: Route[],\n service: DiagramService,\n): void {\n // -------------------------------------------------------\n // GET /api/annotations/:file/risks -- Get all risk annotations\n // -------------------------------------------------------\n routes.push({\n method: 'GET',\n pattern: new RegExp('^/api/annotations/(?<file>.+)/risks$'),\n handler: async (_req: IncomingMessage, res: ServerResponse, params: Record<string, string>) => {\n try {\n const file = decodeURIComponent(params['file']!);\n const risks = await service.getRisks(file);\n const entries: Array<{ nodeId: string; level: string; reason: string }> = [];\n for (const [, risk] of risks) {\n entries.push({ nodeId: risk.nodeId, level: risk.level, reason: risk.reason });\n }\n sendJson(res, { risks: entries });\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Unknown error';\n const code = (err as NodeJS.ErrnoException)?.code;\n sendJson(res, { error: message }, code === 'ENOENT' ? 404 : 500);\n }\n },\n });\n\n // -------------------------------------------------------\n // POST /api/annotations/:file/risk -- Set a risk annotation\n // -------------------------------------------------------\n routes.push({\n method: 'POST',\n pattern: new RegExp('^/api/annotations/(?<file>.+)/risk$'),\n handler: async (req: IncomingMessage, res: ServerResponse, params: Record<string, string>) => {\n try {\n const file = decodeURIComponent(params['file']!);\n const body = await readJsonBody<{ nodeId: string; level: string; reason: string }>(req);\n if (!body.nodeId || !body.level || !body.reason) {\n sendJson(res, { error: 'Missing nodeId, level, or reason' }, 400);\n return;\n }\n if (!VALID_RISK_LEVELS.has(body.level)) {\n sendJson(res, { error: `Invalid level: must be high, medium, or low` }, 400);\n return;\n }\n await service.setRisk(file, body.nodeId, body.level as RiskLevel, body.reason);\n sendJson(res, { ok: true });\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Unknown error';\n if (message === 'Payload too large') { sendJson(res, { error: message }, 413); return; }\n const code = (err as NodeJS.ErrnoException)?.code;\n sendJson(res, { error: message }, code === 'ENOENT' ? 404 : 500);\n }\n },\n });\n\n // -------------------------------------------------------\n // DELETE /api/annotations/:file/risk -- Remove a risk annotation\n // -------------------------------------------------------\n routes.push({\n method: 'DELETE',\n pattern: new RegExp('^/api/annotations/(?<file>.+)/risk$'),\n handler: async (req: IncomingMessage, res: ServerResponse, params: Record<string, string>) => {\n try {\n const file = decodeURIComponent(params['file']!);\n const body = await readJsonBody<{ nodeId: string }>(req);\n if (!body.nodeId) {\n sendJson(res, { error: 'Missing nodeId' }, 400);\n return;\n }\n await service.removeRisk(file, body.nodeId);\n sendJson(res, { ok: true });\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Unknown error';\n if (message === 'Payload too large') { sendJson(res, { error: message }, 413); return; }\n const code = (err as NodeJS.ErrnoException)?.code;\n sendJson(res, { error: message }, code === 'ENOENT' ? 404 : 500);\n }\n },\n });\n}\n","/**\n * MCP Session Registry -- tracks active MCP/AI sessions via filesystem manifests.\n *\n * Supports MULTIPLE sessions per MCP process (one per conversation).\n * Each session writes a JSON manifest to .smartcode/mcp-sessions/<sessionId>.json.\n * Any HTTP server can read these files to discover which AI sessions are active\n * and which diagrams each session has touched.\n *\n * Uses atomic write (write to temp + rename) and PID liveness checks,\n * following the same pattern as workspace-registry.ts.\n */\nimport { readFile, writeFile, readdir, mkdir, rename, unlink } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { tmpdir } from 'node:os';\nimport { randomBytes, randomUUID } from 'node:crypto';\nimport { log } from '../utils/logger.js';\n\n/** A single diagram tracked within an MCP session */\nexport interface DiagramEntry {\n filePath: string;\n firstSeen: number;\n lastUpdated: number;\n}\n\n/** Manifest written to disk for each MCP session */\nexport interface McpSessionManifest {\n sessionId: string;\n pid: number;\n startedAt: number;\n label: string;\n diagrams: DiagramEntry[];\n}\n\n/** Internal session data held in memory */\ninterface SessionData {\n sessionId: string;\n label: string;\n startedAt: number;\n diagrams: Map<string, DiagramEntry>;\n}\n\n/**\n * Registry for MCP sessions within a single process.\n * Supports N sessions with one \"active\" session at a time.\n * Backward-compatible: trackDiagram() auto-creates a default session if none exists.\n */\nexport class McpSessionRegistry {\n private readonly manifestDir: string;\n private readonly projectRoot: string;\n private readonly sessions = new Map<string, SessionData>();\n private activeSessionId: string | null = null;\n\n constructor(projectRoot: string) {\n this.projectRoot = projectRoot;\n this.manifestDir = join(projectRoot, '.smartcode', 'mcp-sessions');\n }\n\n /** Register the registry by ensuring the manifest directory exists */\n async register(): Promise<void> {\n await mkdir(this.manifestDir, { recursive: true });\n // Backward-compat: create a default session so existing code works\n if (this.sessions.size === 0) {\n await this.createSession();\n }\n log.debug(`MCP session registry registered (pid ${process.pid})`);\n }\n\n /**\n * Create a new session and make it the active one.\n * Returns the new session ID.\n */\n async createSession(label?: string): Promise<string> {\n await mkdir(this.manifestDir, { recursive: true });\n const sessionId = randomUUID();\n const shortId = sessionId.substring(0, 8);\n const session: SessionData = {\n sessionId,\n label: label || `Session ${shortId}`,\n startedAt: Date.now(),\n diagrams: new Map(),\n };\n this.sessions.set(sessionId, session);\n this.activeSessionId = sessionId;\n await this.writeManifest(session);\n log.debug(`MCP session created: ${sessionId} (label: ${session.label})`);\n return sessionId;\n }\n\n /** Switch the active session to an existing session ID */\n setActiveSession(sessionId: string): void {\n if (!this.sessions.has(sessionId)) {\n throw new Error(`Session not found: ${sessionId}`);\n }\n this.activeSessionId = sessionId;\n }\n\n /** Get the current active session ID (or null) */\n getActiveSessionId(): string | null {\n return this.activeSessionId;\n }\n\n /** Rename a session's label and persist to disk */\n async renameSession(sessionId: string, label: string): Promise<void> {\n const session = this.sessions.get(sessionId);\n if (session) {\n session.label = label;\n await this.writeManifest(session);\n }\n // Also handle sessions from other processes (on-disk only)\n await McpSessionRegistry.renameOnDisk(this.projectRoot, sessionId, label);\n }\n\n /**\n * Track a diagram file in the active session.\n * Backward-compat: auto-creates a default session if none exists.\n */\n async trackDiagram(filePath: string): Promise<void> {\n if (!this.activeSessionId || !this.sessions.has(this.activeSessionId)) {\n await this.createSession();\n }\n const session = this.sessions.get(this.activeSessionId!)!;\n const now = Date.now();\n const existing = session.diagrams.get(filePath);\n if (existing) {\n existing.lastUpdated = now;\n } else {\n session.diagrams.set(filePath, { filePath, firstSeen: now, lastUpdated: now });\n // Auto-derive label if it's still the default \"Session XXXXXXXX\"\n if (session.label.startsWith('Session ')) {\n const base = filePath.includes('/') ? filePath.split('/').pop()! : filePath;\n session.label = base.replace('.mmd', '');\n }\n }\n await this.writeManifest(session);\n }\n\n /** Deregister all sessions owned by this process */\n async deregister(): Promise<void> {\n for (const session of this.sessions.values()) {\n try {\n await unlink(this.manifestPath(session.sessionId));\n } catch {\n // File might already be deleted\n }\n }\n this.sessions.clear();\n this.activeSessionId = null;\n log.debug(`MCP session registry deregistered (pid ${process.pid})`);\n }\n\n /** List all sessions owned by this process instance */\n listSessions(): McpSessionManifest[] {\n return Array.from(this.sessions.values()).map((s) => this.buildManifest(s));\n }\n\n // ── Backward-compat getters ──\n\n /** Get the session ID (returns active session for backward compat) */\n get sessionId(): string {\n return this.activeSessionId ?? '';\n }\n\n // ── Static methods (read from disk, cross-process) ──\n\n /** List all active MCP sessions for a project (filters out dead PIDs, cleans stale) */\n static async listActive(projectRoot: string): Promise<McpSessionManifest[]> {\n const dir = join(projectRoot, '.smartcode', 'mcp-sessions');\n let entries: string[];\n try {\n entries = await readdir(dir);\n } catch {\n return [];\n }\n\n const manifests: McpSessionManifest[] = [];\n const stale: string[] = [];\n\n for (const entry of entries) {\n if (!entry.endsWith('.json')) continue;\n try {\n const raw = await readFile(join(dir, entry), 'utf-8');\n const manifest = JSON.parse(raw) as McpSessionManifest;\n if (isProcessAlive(manifest.pid)) {\n manifests.push(manifest);\n } else {\n stale.push(entry);\n }\n } catch {\n stale.push(entry);\n }\n }\n\n // Clean up stale manifests (best-effort, no await)\n for (const s of stale) {\n unlink(join(dir, s)).catch(() => {});\n }\n\n return manifests;\n }\n\n /** Get a specific session manifest by ID */\n static async getSession(projectRoot: string, sessionId: string): Promise<McpSessionManifest | null> {\n const filePath = join(projectRoot, '.smartcode', 'mcp-sessions', `${sessionId}.json`);\n try {\n const raw = await readFile(filePath, 'utf-8');\n const manifest = JSON.parse(raw) as McpSessionManifest;\n return isProcessAlive(manifest.pid) ? manifest : null;\n } catch {\n return null;\n }\n }\n\n /** Rename a session on disk (works for any process's sessions) */\n static async renameOnDisk(projectRoot: string, sessionId: string, label: string): Promise<boolean> {\n const filePath = join(projectRoot, '.smartcode', 'mcp-sessions', `${sessionId}.json`);\n try {\n const raw = await readFile(filePath, 'utf-8');\n const manifest = JSON.parse(raw) as McpSessionManifest;\n manifest.label = label;\n const data = JSON.stringify(manifest, null, 2);\n const tempPath = join(tmpdir(), `smartcode-mcp-${randomBytes(4).toString('hex')}.json`);\n await writeFile(tempPath, data, 'utf-8');\n try {\n await rename(tempPath, filePath);\n } catch {\n await writeFile(filePath, data, 'utf-8');\n await unlink(tempPath).catch(() => {});\n }\n return true;\n } catch {\n return false;\n }\n }\n\n // ── Private helpers ──\n\n private manifestPath(sessionId: string): string {\n return join(this.manifestDir, `${sessionId}.json`);\n }\n\n private buildManifest(session: SessionData): McpSessionManifest {\n return {\n sessionId: session.sessionId,\n pid: process.pid,\n startedAt: session.startedAt,\n label: session.label,\n diagrams: Array.from(session.diagrams.values()),\n };\n }\n\n /** Atomically write manifest (temp file + rename) */\n private async writeManifest(session: SessionData): Promise<void> {\n const data = JSON.stringify(this.buildManifest(session), null, 2);\n const tempPath = join(tmpdir(), `smartcode-mcp-${randomBytes(4).toString('hex')}.json`);\n await writeFile(tempPath, data, 'utf-8');\n try {\n await rename(tempPath, this.manifestPath(session.sessionId));\n } catch {\n // rename across filesystems can fail; fall back to write-in-place\n await writeFile(this.manifestPath(session.sessionId), data, 'utf-8');\n await unlink(tempPath).catch(() => {});\n }\n }\n}\n\n/** Check if a process with the given PID is still alive */\nfunction isProcessAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n}\n","import type { IncomingMessage, ServerResponse } from 'node:http';\nimport { McpSessionRegistry } from '../registry/mcp-session-registry.js';\nimport { sendJson, readJsonBody, type Route } from './server.js';\nimport type { WebSocketManager } from './websocket.js';\n\n/**\n * Register REST endpoints for MCP session discovery.\n * GET /api/mcp-sessions -- list all active AI sessions\n * GET /api/mcp-sessions/:id -- get details of a specific session\n * PATCH /api/mcp-sessions/:id -- rename a session label\n */\nexport function registerMcpSessionRoutes(\n routes: Route[],\n projectDir: string,\n wsManager?: WebSocketManager,\n): void {\n // -------------------------------------------------------\n // GET /api/mcp-sessions -- List all active MCP sessions\n // -------------------------------------------------------\n routes.push({\n method: 'GET',\n pattern: new RegExp('^/api/mcp-sessions$'),\n handler: async (_req: IncomingMessage, res: ServerResponse) => {\n try {\n const sessions = await McpSessionRegistry.listActive(projectDir);\n sendJson(res, { sessions });\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Unknown error';\n sendJson(res, { error: message }, 500);\n }\n },\n });\n\n // -------------------------------------------------------\n // GET /api/mcp-sessions/:id -- Get a specific MCP session\n // -------------------------------------------------------\n routes.push({\n method: 'GET',\n pattern: new RegExp('^/api/mcp-sessions/(?<id>[^/]+)$'),\n handler: async (_req: IncomingMessage, res: ServerResponse, params: Record<string, string>) => {\n try {\n const id = decodeURIComponent(params['id']!);\n const session = await McpSessionRegistry.getSession(projectDir, id);\n if (!session) {\n sendJson(res, { error: 'Session not found' }, 404);\n return;\n }\n sendJson(res, session);\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Unknown error';\n sendJson(res, { error: message }, 500);\n }\n },\n });\n\n // -------------------------------------------------------\n // PATCH /api/mcp-sessions/:id -- Rename a session label\n // -------------------------------------------------------\n routes.push({\n method: 'PATCH',\n pattern: new RegExp('^/api/mcp-sessions/(?<id>[^/]+)$'),\n handler: async (req: IncomingMessage, res: ServerResponse, params: Record<string, string>) => {\n try {\n const id = decodeURIComponent(params['id']!);\n const body = await readJsonBody<{ label?: string }>(req);\n const label = body?.label;\n\n if (!label || typeof label !== 'string' || !label.trim()) {\n sendJson(res, { error: 'label is required' }, 400);\n return;\n }\n\n const ok = await McpSessionRegistry.renameOnDisk(projectDir, id, label.trim());\n if (!ok) {\n sendJson(res, { error: 'Session not found' }, 404);\n return;\n }\n\n if (wsManager) {\n wsManager.broadcastAll({ type: 'mcp-session:updated' });\n }\n\n sendJson(res, { ok: true, sessionId: id, label: label.trim() });\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Unknown error';\n sendJson(res, { error: message }, 500);\n }\n },\n });\n}\n","import type { IncomingMessage, ServerResponse } from 'node:http';\nimport type { SessionStore } from '../session/session-store.js';\nimport type { WebSocketManager } from './websocket.js';\nimport { sendJson, readJsonBody, type Route } from './server.js';\n\n/**\n * In-memory store for browser click frequency data.\n * Stores nodeId -> click count per file.\n * Ephemeral: cleared on server restart (session JSONL provides persistent data).\n */\nexport class HeatmapStore {\n private data = new Map<string, Map<string, number>>();\n\n /** Merge incoming counts into the store for a given file */\n increment(file: string, counts: Record<string, number>): void {\n let fileMap = this.data.get(file);\n if (!fileMap) {\n fileMap = new Map();\n this.data.set(file, fileMap);\n }\n for (const [nodeId, count] of Object.entries(counts)) {\n if (typeof count !== 'number' || count < 0) continue;\n fileMap.set(nodeId, (fileMap.get(nodeId) ?? 0) + count);\n }\n }\n\n /** Get click counts for a file as a plain object */\n getCounts(file: string): Record<string, number> {\n const fileMap = this.data.get(file);\n if (!fileMap) return {};\n const result: Record<string, number> = {};\n for (const [nodeId, count] of fileMap) {\n result[nodeId] = count;\n }\n return result;\n }\n\n /** Clear counts for a specific file (used in testing) */\n clear(file: string): void {\n this.data.delete(file);\n }\n\n /** Clear all data (used in testing) */\n clearAll(): void {\n this.data.clear();\n }\n}\n\n/**\n * Merge two count objects. Returns a new object with summed counts.\n */\nfunction mergeCounts(\n a: Record<string, number>,\n b: Record<string, number>,\n): Record<string, number> {\n const result = { ...a };\n for (const [key, value] of Object.entries(b)) {\n result[key] = (result[key] ?? 0) + value;\n }\n return result;\n}\n\n/**\n * Register heatmap REST endpoints.\n * Adds 2 routes:\n * GET /api/heatmap/:file -- get merged heatmap data (clicks + sessions)\n * POST /api/heatmap/:file/increment -- increment click counts from browser\n */\nexport function registerHeatmapRoutes(\n routes: Route[],\n heatmapStore: HeatmapStore,\n sessionStore: SessionStore | undefined,\n wsManager: WebSocketManager | undefined,\n): void {\n // -------------------------------------------------------\n // GET /api/heatmap/:file -- Get merged heatmap data\n // -------------------------------------------------------\n routes.push({\n method: 'GET',\n pattern: new RegExp('^/api/heatmap/(?<file>.+)$'),\n handler: async (_req: IncomingMessage, res: ServerResponse, params: Record<string, string>) => {\n try {\n const file = decodeURIComponent(params['file']!);\n\n // Get click counts from in-memory store\n const clickCounts = heatmapStore.getCounts(file);\n\n // Get session counts from persistent store\n let sessionCounts: Record<string, number> = {};\n if (sessionStore) {\n try {\n sessionCounts = await sessionStore.getHeatmapData(file);\n } catch {\n // Session store errors shouldn't block click data\n }\n }\n\n // Merge both sources\n const merged = mergeCounts(clickCounts, sessionCounts);\n sendJson(res, merged);\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Unknown error';\n sendJson(res, { error: message }, 500);\n }\n },\n });\n\n // -------------------------------------------------------\n // POST /api/heatmap/:file/increment -- Increment click counts\n // -------------------------------------------------------\n routes.push({\n method: 'POST',\n pattern: new RegExp('^/api/heatmap/(?<file>.+)/increment$'),\n handler: async (req: IncomingMessage, res: ServerResponse, params: Record<string, string>) => {\n try {\n const file = decodeURIComponent(params['file']!);\n const body = await readJsonBody<{ counts?: Record<string, number> }>(req);\n\n if (!body.counts || typeof body.counts !== 'object') {\n sendJson(res, { error: 'Missing or invalid \"counts\" field' }, 400);\n return;\n }\n\n // Validate that all values are positive numbers\n for (const [key, value] of Object.entries(body.counts)) {\n if (typeof key !== 'string' || typeof value !== 'number' || value < 0) {\n sendJson(res, { error: 'Invalid count entry' }, 400);\n return;\n }\n }\n\n heatmapStore.increment(file, body.counts);\n\n // Broadcast updated heatmap to browsers\n if (wsManager) {\n const allCounts = heatmapStore.getCounts(file);\n // Merge with session data for complete picture\n let sessionCounts: Record<string, number> = {};\n if (sessionStore) {\n try {\n sessionCounts = await sessionStore.getHeatmapData(file);\n } catch {\n // Non-fatal\n }\n }\n const merged = mergeCounts(allCounts, sessionCounts);\n wsManager.broadcastAll({\n type: 'heatmap:update',\n file,\n data: merged,\n });\n }\n\n sendJson(res, { ok: true });\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Unknown error';\n if (message === 'Invalid JSON' || message === 'Payload too large') {\n sendJson(res, { error: message }, 400);\n return;\n }\n sendJson(res, { error: message }, 500);\n }\n },\n });\n}\n","/**\n * Workspace Registry -- shared JSON file at ~/.smartcode/workspaces.json\n * that tracks all running SmartCode server instances.\n *\n * Each instance registers on startup and deregisters on shutdown.\n * The browser reads this registry to build the workspace switcher dropdown.\n *\n * Uses atomic write (write to temp file + rename) to avoid race conditions\n * between simultaneous MCP/serve processes.\n */\nimport { readFile, writeFile, mkdir, rename, unlink } from 'node:fs/promises';\nimport { join, basename } from 'node:path';\nimport { homedir, tmpdir } from 'node:os';\nimport { randomBytes } from 'node:crypto';\nimport { log } from '../utils/logger.js';\n\n/** A single workspace entry in the registry */\nexport interface WorkspaceEntry {\n name: string;\n dir: string;\n port: number;\n pid: number;\n}\n\nconst SMARTCODE_DIR = join(homedir(), '.smartcode');\nconst REGISTRY_PATH = join(SMARTCODE_DIR, 'workspaces.json');\n\n/** Read the registry file, returning an empty array on any error */\nasync function readRegistry(): Promise<WorkspaceEntry[]> {\n try {\n const raw = await readFile(REGISTRY_PATH, 'utf-8');\n const data = JSON.parse(raw);\n return Array.isArray(data) ? data : [];\n } catch {\n return [];\n }\n}\n\n/** Atomically write the registry (write to temp + rename) */\nasync function writeRegistry(entries: WorkspaceEntry[]): Promise<void> {\n await mkdir(SMARTCODE_DIR, { recursive: true });\n const tempPath = join(tmpdir(), `smartcode-registry-${randomBytes(4).toString('hex')}.json`);\n await writeFile(tempPath, JSON.stringify(entries, null, 2), 'utf-8');\n try {\n await rename(tempPath, REGISTRY_PATH);\n } catch {\n // rename across filesystems can fail; fall back to write-in-place\n await writeFile(REGISTRY_PATH, JSON.stringify(entries, null, 2), 'utf-8');\n await unlink(tempPath).catch(() => {});\n }\n}\n\n/** Check if a process with the given PID is still alive */\nfunction isProcessAlive(pid: number): boolean {\n try {\n process.kill(pid, 0); // signal 0 = just check existence\n return true;\n } catch {\n return false;\n }\n}\n\n/** Filter out entries whose processes have died (crash cleanup) */\nfunction filterAlive(entries: WorkspaceEntry[]): WorkspaceEntry[] {\n return entries.filter((e) => isProcessAlive(e.pid));\n}\n\n/**\n * Register this server instance in the workspace registry.\n * Derives workspace name from the last segment of the directory path.\n */\nexport async function register(dir: string, port: number): Promise<void> {\n const name = basename(dir) || dir;\n const pid = process.pid;\n const entries = filterAlive(await readRegistry());\n\n // Remove any stale entry for the same port or same dir\n const cleaned = entries.filter((e) => e.port !== port && e.dir !== dir);\n cleaned.push({ name, dir, port, pid });\n\n await writeRegistry(cleaned);\n log.debug(`Workspace registered: ${name} (port ${port}, pid ${pid})`);\n}\n\n/**\n * Remove this server instance from the workspace registry.\n */\nexport async function deregister(port: number): Promise<void> {\n const entries = await readRegistry();\n const filtered = entries.filter((e) => e.port !== port);\n await writeRegistry(filtered);\n log.debug(`Workspace deregistered (port ${port})`);\n}\n\n/**\n * List all live workspace entries (filters out dead PIDs).\n */\nexport async function list(): Promise<WorkspaceEntry[]> {\n const entries = await readRegistry();\n const alive = filterAlive(entries);\n\n // If we filtered out dead entries, rewrite the file to clean up\n if (alive.length !== entries.length) {\n await writeRegistry(alive).catch(() => {});\n }\n\n return alive;\n}\n","import { readFile } from 'node:fs/promises';\nimport type { IncomingMessage, ServerResponse } from 'node:http';\nimport type { DiagramService } from '../diagram/service.js';\nimport type { WebSocketManager } from './websocket.js';\nimport { resolveProjectPath } from '../utils/paths.js';\nimport { sendJson, type Route } from './server.js';\nimport {\n parseSubgraphs,\n generateCollapsedView,\n focusOnNode,\n navigateToBreadcrumb,\n getBreadcrumbs,\n createEmptyState,\n DEFAULT_CONFIG,\n type CollapseConfig,\n type CollapseState,\n} from '../diagram/collapser.js';\nimport { serializeGraphModel } from '../diagram/graph-serializer.js';\nimport type { SessionStore } from '../session/session-store.js';\nimport { registerSessionRoutes } from './session-routes.js';\nimport { registerFileRoutes } from './file-routes.js';\nimport { registerBreakpointRoutes } from './breakpoint-routes.js';\nimport { registerGhostPathRoutes } from './ghost-path-routes.js';\nimport { registerAnnotationRoutes } from './annotation-routes.js';\nimport { registerMcpSessionRoutes } from './mcp-session-routes.js';\nimport { registerHeatmapRoutes, type HeatmapStore } from './heatmap-routes.js';\nimport { list as listWorkspaces } from '../registry/workspace-registry.js';\n\n/**\n * Register all route handlers for the diagram viewer server.\n * Returns an array of routes matching method + URL pattern to handler functions.\n */\nexport function registerRoutes(\n service: DiagramService,\n projectDir: string,\n wsManager?: WebSocketManager,\n breakpointContinueSignals?: Map<string, boolean>,\n sessionStore?: SessionStore,\n heatmapStore?: HeatmapStore,\n): Route[] {\n const routes: Route[] = [];\n\n // ── File CRUD routes (tree, save, delete, mkdir, move, rmdir) ──\n registerFileRoutes(routes, service, projectDir);\n\n // -------------------------------------------------------\n // GET /api/status -- Server diagnostics\n // -------------------------------------------------------\n routes.push({\n method: 'GET',\n pattern: new RegExp('^/api/status$'),\n handler: async (_req: IncomingMessage, res: ServerResponse) => {\n try {\n const files = await service.listFiles();\n\n const activeFlags: Array<{ file: string; nodeId: string; message: string }> = [];\n for (const file of files) {\n try {\n const flags = await service.getFlags(file);\n for (const flag of flags) {\n activeFlags.push({ file, nodeId: flag.nodeId, message: flag.message });\n }\n } catch {\n // Skip files that can't be read\n }\n }\n\n sendJson(res, {\n status: 'running',\n uptime: process.uptime(),\n port: null,\n projectDir,\n files: files.length,\n connectedClients: wsManager?.getClientCount() ?? 0,\n activeFlags,\n });\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Unknown error';\n sendJson(res, { error: message }, 500);\n }\n },\n });\n\n // -------------------------------------------------------\n // GET /api/diagrams -- REST: List all diagrams\n // -------------------------------------------------------\n routes.push({\n method: 'GET',\n pattern: new RegExp('^/api/diagrams$'),\n handler: async (_req: IncomingMessage, res: ServerResponse) => {\n try {\n const files = await service.listFiles();\n sendJson(res, { files });\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Unknown error';\n sendJson(res, { error: message }, 500);\n }\n },\n });\n\n // -------------------------------------------------------\n // GET /api/diagrams/:file -- REST: Get diagram content\n // -------------------------------------------------------\n routes.push({\n method: 'GET',\n pattern: new RegExp('^/api/diagrams/(?<file>.+)$'),\n handler: async (req: IncomingMessage, res: ServerResponse, params: Record<string, string>) => {\n try {\n const file = decodeURIComponent(params['file']!);\n const diagram = await service.readDiagram(file);\n\n const url = new URL(req.url ?? '/', `http://${req.headers.host}`);\n const collapsedParam = url.searchParams.get('collapsed');\n const configParam = url.searchParams.get('collapseConfig');\n const focusParam = url.searchParams.get('focus');\n const breadcrumbParam = url.searchParams.get('breadcrumb');\n\n let collapseConfig: CollapseConfig = { ...DEFAULT_CONFIG };\n if (configParam) {\n try {\n const userConfig = JSON.parse(configParam) as Partial<CollapseConfig>;\n collapseConfig = { ...DEFAULT_CONFIG, ...userConfig };\n } catch { /* use defaults */ }\n }\n\n const subgraphs = parseSubgraphs(diagram.mermaidContent);\n let userCollapsed: string[] = [];\n if (collapsedParam) {\n try {\n const parsed = JSON.parse(collapsedParam);\n if (Array.isArray(parsed)) userCollapsed = parsed as string[];\n } catch { /* ignore malformed collapsed param */ }\n }\n let state: CollapseState = {\n ...createEmptyState(),\n collapsed: new Set(userCollapsed),\n };\n\n if (focusParam) {\n state = focusOnNode(focusParam, subgraphs, state);\n } else if (breadcrumbParam) {\n state = navigateToBreadcrumb(breadcrumbParam, subgraphs, state);\n }\n\n const result = generateCollapsedView(\n diagram.mermaidContent,\n subgraphs,\n state,\n collapseConfig,\n );\n\n const breadcrumbs = getBreadcrumbs(state, subgraphs);\n\n sendJson(res, {\n filePath: diagram.filePath,\n mermaidContent: result.content,\n rawContent: diagram.mermaidContent,\n flags: Object.fromEntries(diagram.flags),\n validation: {\n valid: diagram.validation.valid,\n errors: diagram.validation.errors,\n diagramType: diagram.validation.diagramType,\n },\n collapse: {\n visibleNodes: result.visibleNodes,\n autoCollapsed: result.autoCollapsed,\n manualCollapsed: result.manualCollapsed,\n config: collapseConfig,\n breadcrumbs,\n focusedSubgraph: state.focusedSubgraph,\n },\n });\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Unknown error';\n const code = (err as NodeJS.ErrnoException)?.code;\n sendJson(res, { error: message }, code === 'ENOENT' ? 404 : 500);\n }\n },\n });\n\n // -------------------------------------------------------\n // GET /api/graph/:file -- REST: Get graph model\n // -------------------------------------------------------\n routes.push({\n method: 'GET',\n pattern: new RegExp('^/api/graph/(?<file>.+)$'),\n handler: async (_req: IncomingMessage, res: ServerResponse, params: Record<string, string>) => {\n try {\n const file = decodeURIComponent(params['file']!);\n const graph = await service.readGraph(file);\n const json = serializeGraphModel(graph);\n sendJson(res, json);\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Unknown error';\n const code = (err as NodeJS.ErrnoException)?.code;\n sendJson(res, { error: message }, code === 'ENOENT' ? 404 : 500);\n }\n },\n });\n\n // ── Breakpoint routes ──\n registerBreakpointRoutes(routes, service, wsManager, breakpointContinueSignals);\n\n // ── Ghost path routes ──\n registerGhostPathRoutes(routes, service, wsManager);\n\n // ── Annotation routes (risk levels) ──\n registerAnnotationRoutes(routes, service);\n\n // ── Session routes ──\n if (sessionStore) {\n registerSessionRoutes(routes, sessionStore);\n }\n\n // ── Heatmap routes (click tracking + session data merge) ──\n if (heatmapStore) {\n registerHeatmapRoutes(routes, heatmapStore, sessionStore, wsManager);\n }\n\n // ── MCP Session discovery routes ──\n registerMcpSessionRoutes(routes, projectDir, wsManager);\n\n // -------------------------------------------------------\n // GET /api/workspaces -- List all registered workspace instances\n // -------------------------------------------------------\n routes.push({\n method: 'GET',\n pattern: new RegExp('^/api/workspaces$'),\n handler: async (_req: IncomingMessage, res: ServerResponse) => {\n try {\n const workspaces = await listWorkspaces();\n sendJson(res, workspaces);\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Unknown error';\n sendJson(res, { error: message }, 500);\n }\n },\n });\n\n // -------------------------------------------------------\n // GET /*.mmd -- Serve raw .mmd file content from project dir\n // (must be registered AFTER /api routes to avoid conflicts)\n // -------------------------------------------------------\n routes.push({\n method: 'GET',\n pattern: new RegExp('^/(?<mmdPath>.+\\\\.mmd)$'),\n handler: async (_req: IncomingMessage, res: ServerResponse, params: Record<string, string>) => {\n try {\n const filePath = params['mmdPath']!;\n const resolved = resolveProjectPath(projectDir, filePath);\n const content = await readFile(resolved, 'utf-8');\n res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });\n res.end(content);\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Unknown error';\n const code = (err as NodeJS.ErrnoException)?.code;\n sendJson(res, { error: message }, code === 'ENOENT' ? 404 : 500);\n }\n },\n });\n\n return routes;\n}\n","import { WebSocketServer, WebSocket as WsWebSocket } from 'ws';\nimport type { Server, IncomingMessage } from 'node:http';\nimport type { Duplex } from 'node:stream';\nimport { log } from '../utils/logger.js';\n\n/** Server-to-client WebSocket message types */\nexport type WsMessage =\n | { type: 'file:changed'; file: string; content: string }\n | { type: 'file:added'; file: string }\n | { type: 'file:removed'; file: string }\n | { type: 'tree:updated'; files: string[] }\n | { type: 'connected'; project: string }\n | { type: 'graph:update'; file: string; graph: Record<string, unknown> }\n // Phase 15: Breakpoints + Ghost Paths\n | { type: 'breakpoint:hit'; file: string; nodeId: string }\n | { type: 'breakpoint:continue'; file: string; nodeId: string }\n | { type: 'ghost:update'; file: string; ghostPaths: Array<{ fromNodeId: string; toNodeId: string; label?: string }> }\n // Phase 16: Heatmap + Session Recording\n | { type: 'session:event'; sessionId: string; event: Record<string, unknown> }\n | { type: 'heatmap:update'; file: string; data: Record<string, number> }\n // MCP Session tracking\n | { type: 'mcp-session:updated' };\n\n/**\n * Manages WebSocket servers using noServer mode for multi-project namespacing.\n * Each project directory gets its own WebSocketServer instance.\n * Clients are routed to the correct namespace via URL path:\n * /ws -> default project\n * /ws/name -> named project\n */\nexport class WebSocketManager {\n private namespaces: Map<string, WebSocketServer> = new Map();\n\n constructor(httpServer: Server) {\n httpServer.on('upgrade', (request: IncomingMessage, socket: Duplex, head: Buffer) => {\n const { pathname } = new URL(request.url!, `http://${request.headers.host}`);\n\n // Accept both /ws (default project) and /ws/project-name\n let projectName = 'default';\n if (pathname.startsWith('/ws/')) {\n projectName = decodeURIComponent(pathname.slice(4)) || 'default';\n } else if (pathname !== '/ws') {\n socket.destroy();\n return;\n }\n\n const wss = this.getOrCreateNamespace(projectName);\n wss.handleUpgrade(request, socket, head, (ws) => {\n wss.emit('connection', ws, request);\n });\n });\n }\n\n /** Get or create a WebSocketServer for the given project namespace */\n private getOrCreateNamespace(name: string): WebSocketServer {\n let wss = this.namespaces.get(name);\n if (wss) return wss;\n\n wss = new WebSocketServer({ noServer: true });\n wss.on('connection', (ws) => {\n ws.on('error', (err) => log.error(`WebSocket error [${name}]:`, err.message));\n ws.send(JSON.stringify({ type: 'connected', project: name } satisfies WsMessage));\n });\n this.namespaces.set(name, wss);\n return wss;\n }\n\n /** Ensure a namespace exists for the given project name */\n addProject(name: string): void {\n this.getOrCreateNamespace(name);\n }\n\n /** Broadcast a JSON message to all clients in a specific project namespace */\n broadcast(projectName: string, message: WsMessage): void {\n const wss = this.namespaces.get(projectName);\n if (!wss) return;\n const data = JSON.stringify(message);\n wss.clients.forEach((client) => {\n if (client.readyState === WsWebSocket.OPEN) {\n client.send(data);\n }\n });\n }\n\n /** Broadcast a JSON message to all clients across all namespaces */\n broadcastAll(message: WsMessage): void {\n const data = JSON.stringify(message);\n for (const wss of this.namespaces.values()) {\n wss.clients.forEach((client) => {\n if (client.readyState === WsWebSocket.OPEN) {\n client.send(data);\n }\n });\n }\n }\n\n /** Count connected clients with OPEN readyState */\n getClientCount(namespace?: string): number {\n if (namespace) {\n const wss = this.namespaces.get(namespace);\n if (!wss) return 0;\n let count = 0;\n wss.clients.forEach((client) => {\n if (client.readyState === WsWebSocket.OPEN) count++;\n });\n return count;\n }\n\n let total = 0;\n for (const wss of this.namespaces.values()) {\n wss.clients.forEach((client) => {\n if (client.readyState === WsWebSocket.OPEN) total++;\n });\n }\n return total;\n }\n\n /** Close all WebSocketServer instances */\n close(): void {\n for (const wss of this.namespaces.values()) {\n wss.close();\n }\n this.namespaces.clear();\n }\n}\n","import { watch, existsSync, type FSWatcher } from 'node:fs';\nimport path from 'node:path';\nimport { discoverMmdFiles } from '../project/discovery.js';\nimport { log } from '../utils/logger.js';\n\n/**\n * Watches a project directory for .mmd file changes using Node.js native fs.watch.\n * Uses recursive mode (supported on macOS and Windows with Node >= 22).\n * Fires callbacks with normalized forward-slash relative paths.\n *\n * Pre-populates knownFiles from discoverMmdFiles so the first event for existing\n * files is classified as \"change\" rather than \"add\".\n *\n * Replaces chokidar which has known issues with directory watching on macOS (Darwin 25+).\n */\nexport class FileWatcher {\n private watcher: FSWatcher;\n /** Debounce map to avoid duplicate events for the same file */\n private debounceTimers = new Map<string, ReturnType<typeof setTimeout>>();\n private static readonly DEBOUNCE_MS = 80;\n /** Tracks known files so we can distinguish adds from changes */\n private knownFiles = new Set<string>();\n /** Resolves when initial file discovery is complete */\n private ready: Promise<void>;\n\n constructor(\n private projectDir: string,\n private onFileChanged: (relativePath: string) => void,\n private onFileAdded: (relativePath: string) => void,\n private onFileRemoved: (relativePath: string) => void,\n ) {\n // Pre-populate knownFiles so the first event for existing files is \"change\" not \"add\"\n this.ready = discoverMmdFiles(projectDir).then(files => {\n for (const f of files) this.knownFiles.add(f);\n log.debug(`FileWatcher pre-populated ${files.length} known files`);\n }).catch(() => {\n log.warn('FileWatcher: failed to discover existing files, first events may misclassify');\n });\n\n this.watcher = watch(\n projectDir,\n { recursive: true },\n (_eventType, filename) => {\n if (!filename) return;\n\n // Normalize to forward slashes\n const relative = filename.split(path.sep).join('/');\n\n // Only watch .mmd files\n if (!relative.endsWith('.mmd')) return;\n\n // Skip node_modules and .git\n if (relative.includes('node_modules/') || relative.includes('.git/')) return;\n\n // Debounce: fs.watch can fire multiple events for a single write\n const existing = this.debounceTimers.get(relative);\n if (existing) clearTimeout(existing);\n\n this.debounceTimers.set(relative, setTimeout(() => {\n this.debounceTimers.delete(relative);\n // Gate on ready promise to ensure knownFiles is populated before classification\n this.ready.then(() => this.handleEvent(relative));\n }, FileWatcher.DEBOUNCE_MS));\n },\n );\n\n log.debug(`FileWatcher started for ${projectDir} (native fs.watch recursive)`);\n }\n\n /** Check if file exists and route to appropriate callback */\n private handleEvent(relative: string): void {\n const absolute = path.join(this.projectDir, relative);\n const exists = existsSync(absolute);\n\n if (exists) {\n if (this.knownFiles.has(relative)) {\n log.debug(`File changed: ${relative}`);\n this.onFileChanged(relative);\n } else {\n log.debug(`File added: ${relative}`);\n this.knownFiles.add(relative);\n this.onFileAdded(relative);\n }\n } else {\n log.debug(`File removed: ${relative}`);\n this.knownFiles.delete(relative);\n this.onFileRemoved(relative);\n }\n }\n\n /** Wait for initial file discovery to complete. Useful for tests. */\n whenReady(): Promise<void> {\n return this.ready;\n }\n\n /** Close the file watcher and release OS file handles */\n async close(): Promise<void> {\n this.watcher.close();\n for (const timer of this.debounceTimers.values()) {\n clearTimeout(timer);\n }\n this.debounceTimers.clear();\n log.debug('FileWatcher closed');\n }\n}\n","import { appendFile, readFile, readdir, mkdir, open as fsOpen } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { randomUUID } from 'node:crypto';\nimport type { SessionEvent, SessionMeta, SessionSummary } from './session-types.js';\n\n/**\n * SessionStore -- persists session events as JSONL files in .smartcode/sessions/.\n * Each session is a single .jsonl file with one JSON object per line.\n * Uses per-session write locks to prevent concurrent JSONL corruption.\n */\nexport class SessionStore {\n private readonly sessionsDir: string;\n private readonly activeSessions = new Map<string, SessionMeta>();\n private readonly writeLocks = new Map<string, Promise<void>>();\n\n constructor(projectRoot: string) {\n this.sessionsDir = join(projectRoot, '.smartcode', 'sessions');\n }\n\n /** Valid session ID pattern (UUID format) */\n private static readonly SESSION_ID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;\n\n /** Validate a session ID to prevent path traversal */\n private validateSessionId(sessionId: string): void {\n if (!SessionStore.SESSION_ID_RE.test(sessionId)) {\n throw new Error(`Invalid session ID: ${sessionId}`);\n }\n }\n\n /** Ensure the sessions directory exists */\n private async ensureDir(): Promise<void> {\n await mkdir(this.sessionsDir, { recursive: true });\n }\n\n /** Serialize write operations on a given session to prevent JSONL corruption */\n private async withWriteLock<T>(sessionId: string, fn: () => Promise<T>): Promise<T> {\n const prev = this.writeLocks.get(sessionId) ?? Promise.resolve();\n const current = prev.then(fn, fn);\n const settled = current.then(() => {}, () => {});\n this.writeLocks.set(sessionId, settled);\n const result = await current;\n // Clean up write lock entry if it's still ours (no subsequent write queued)\n if (this.writeLocks.get(sessionId) === settled) {\n this.writeLocks.delete(sessionId);\n }\n return result;\n }\n\n /** Get the file path for a session's JSONL file */\n private filePath(sessionId: string): string {\n this.validateSessionId(sessionId);\n return join(this.sessionsDir, `${sessionId}.jsonl`);\n }\n\n /**\n * Start a new session for a diagram file.\n * Creates the sessions directory if needed, generates a UUID, and writes the start event.\n * Returns the session ID.\n */\n async startSession(diagramFile: string): Promise<string> {\n await this.ensureDir();\n\n const id = randomUUID();\n const startedAt = Date.now();\n const meta: SessionMeta = { id, diagramFile, startedAt };\n this.activeSessions.set(id, meta);\n\n const startEvent: SessionEvent = {\n ts: startedAt,\n type: 'session:start',\n payload: { diagramFile },\n };\n\n await appendFile(this.filePath(id), JSON.stringify(startEvent) + '\\n', 'utf-8');\n return id;\n }\n\n /**\n * Record a step (event) in an active session.\n * Uses a write lock to prevent concurrent JSONL corruption.\n */\n async recordStep(sessionId: string, event: SessionEvent): Promise<void> {\n return this.withWriteLock(sessionId, async () => {\n await appendFile(this.filePath(sessionId), JSON.stringify(event) + '\\n', 'utf-8');\n });\n }\n\n /**\n * End an active session.\n * Appends a session:end event, computes summary statistics, and removes from active sessions.\n */\n async endSession(sessionId: string): Promise<SessionSummary> {\n const meta = this.activeSessions.get(sessionId);\n if (!meta) {\n throw new Error(`Session ${sessionId} is not active`);\n }\n const diagramFile = meta.diagramFile;\n\n const endEvent: SessionEvent = {\n ts: Date.now(),\n type: 'session:end',\n payload: {},\n };\n\n await this.withWriteLock(sessionId, async () => {\n await appendFile(this.filePath(sessionId), JSON.stringify(endEvent) + '\\n', 'utf-8');\n });\n\n const events = await this.readSession(sessionId);\n this.activeSessions.delete(sessionId);\n this.writeLocks.delete(sessionId);\n\n return this.computeSummary(events, sessionId, diagramFile);\n }\n\n /**\n * Read all events from a session's JSONL file.\n * Each line is parsed as a JSON object. Empty lines are filtered.\n */\n async readSession(sessionId: string): Promise<SessionEvent[]> {\n try {\n const content = await readFile(this.filePath(sessionId), 'utf-8');\n return content\n .split('\\n')\n .filter((line) => line.trim() !== '')\n .map((line) => JSON.parse(line) as SessionEvent);\n } catch (err) {\n if ((err as NodeJS.ErrnoException)?.code === 'ENOENT') {\n return [];\n }\n throw err;\n }\n }\n\n /**\n * List session IDs for a specific diagram file.\n * Reads the first line of each .jsonl file to check the diagramFile in the session:start payload.\n */\n async listSessions(diagramFile: string): Promise<string[]> {\n await this.ensureDir();\n\n let entries: string[];\n try {\n entries = await readdir(this.sessionsDir);\n } catch {\n return [];\n }\n\n const matching: string[] = [];\n\n for (const entry of entries) {\n if (!entry.endsWith('.jsonl')) continue;\n\n const sessionId = entry.replace('.jsonl', '');\n try {\n // Read only the first line instead of the entire file\n const firstLine = await this.readFirstLine(join(this.sessionsDir, entry));\n if (!firstLine) continue;\n const event = JSON.parse(firstLine) as SessionEvent;\n if (event.type === 'session:start' && event.payload.diagramFile === diagramFile) {\n matching.push(sessionId);\n }\n } catch {\n // Skip files that can't be read or parsed\n }\n }\n\n return matching;\n }\n\n /**\n * Get heatmap data for a diagram file: counts of node:visited events by nodeId.\n * Aggregates across all sessions for the given file.\n */\n async getHeatmapData(diagramFile: string): Promise<Record<string, number>> {\n const sessionIds = await this.listSessions(diagramFile);\n const counts: Record<string, number> = {};\n\n for (const sessionId of sessionIds) {\n const events = await this.readSession(sessionId);\n for (const event of events) {\n if (event.type === 'node:visited' && typeof event.payload.nodeId === 'string') {\n const nodeId = event.payload.nodeId;\n counts[nodeId] = (counts[nodeId] ?? 0) + 1;\n }\n }\n }\n\n return counts;\n }\n\n /** Read only the first line of a file without loading the entire file into memory */\n private async readFirstLine(filePath: string): Promise<string | null> {\n const fh = await fsOpen(filePath, 'r');\n try {\n const buf = Buffer.alloc(4096); // First line of a session JSONL is ~100 bytes\n const { bytesRead } = await fh.read(buf, 0, buf.length, 0);\n if (bytesRead === 0) return null;\n const text = buf.toString('utf-8', 0, bytesRead);\n const newlineIdx = text.indexOf('\\n');\n return newlineIdx === -1 ? text : text.substring(0, newlineIdx);\n } finally {\n await fh.close();\n }\n }\n\n /** Get metadata for an active session, or undefined if not active */\n getActiveSession(sessionId: string): SessionMeta | undefined {\n return this.activeSessions.get(sessionId);\n }\n\n /** Compute summary statistics from a list of session events */\n private computeSummary(\n events: SessionEvent[],\n sessionId: string,\n diagramFile: string,\n ): SessionSummary {\n const startEvent = events.find((e) => e.type === 'session:start');\n const endEvent = events.find((e) => e.type === 'session:end');\n\n const startTs = startEvent?.ts ?? 0;\n const endTs = endEvent?.ts ?? Date.now();\n const duration = endTs - startTs;\n\n let nodesVisited = 0;\n const uniqueNodes = new Set<string>();\n let edgesTraversed = 0;\n\n for (const event of events) {\n if (event.type === 'node:visited') {\n nodesVisited++;\n if (typeof event.payload.nodeId === 'string') {\n uniqueNodes.add(event.payload.nodeId);\n }\n } else if (event.type === 'edge:traversed') {\n edgesTraversed++;\n }\n }\n\n return {\n sessionId,\n diagramFile,\n duration,\n totalEvents: events.length,\n nodesVisited,\n uniqueNodesVisited: uniqueNodes.size,\n edgesTraversed,\n };\n }\n}\n","import { createServer, type IncomingMessage, type ServerResponse } from 'node:http';\nimport { readFile } from 'node:fs/promises';\nimport path from 'node:path';\nimport { detect } from 'detect-port';\nimport open from 'open';\nimport { DiagramService } from '../diagram/service.js';\nimport { getStaticDir } from '../utils/paths.js';\nimport { log } from '../utils/logger.js';\nimport { serveStaticFile } from './static.js';\nimport { registerRoutes } from './routes.js';\nimport { WebSocketManager } from './websocket.js';\nimport { FileWatcher } from '../watcher/file-watcher.js';\nimport { serializeGraphModel } from '../diagram/graph-serializer.js';\nimport { SessionStore } from '../session/session-store.js';\nimport { HeatmapStore } from './heatmap-routes.js';\nimport { register as registerWorkspace, deregister as deregisterWorkspace } from '../registry/workspace-registry.js';\n\n/** Options for starting the HTTP server */\nexport interface ServerOptions {\n port: number;\n dir: string;\n openBrowser: boolean;\n}\n\n/** A route handler function */\nexport type Handler = (\n req: IncomingMessage,\n res: ServerResponse,\n params: Record<string, string>,\n) => void | Promise<void>;\n\n/** A registered route with method, pattern, and handler */\nexport interface Route {\n method: string;\n pattern: RegExp;\n handler: Handler;\n}\n\n/** Allowed localhost origins for CORS */\nconst LOCALHOST_PATTERNS = [\n /^https?:\\/\\/localhost(:\\d+)?$/,\n /^https?:\\/\\/127\\.0\\.0\\.1(:\\d+)?$/,\n /^https?:\\/\\/\\[::1\\](:\\d+)?$/,\n];\n\n/**\n * Set CORS headers on a response.\n * Only allows localhost origins (127.0.0.1, localhost, [::1]).\n */\nfunction setCorsHeaders(req: IncomingMessage, res: ServerResponse): void {\n const origin = req.headers.origin;\n if (origin && LOCALHOST_PATTERNS.some((p) => p.test(origin))) {\n res.setHeader('Access-Control-Allow-Origin', origin);\n res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH, DELETE, OPTIONS');\n res.setHeader('Access-Control-Allow-Headers', 'Content-Type');\n }\n}\n\n/**\n * Send a JSON response with CORS headers.\n */\nexport function sendJson(res: ServerResponse, data: unknown, status = 200): void {\n const body = JSON.stringify(data);\n res.writeHead(status, {\n 'Content-Type': 'application/json; charset=utf-8',\n 'Content-Length': Buffer.byteLength(body),\n });\n res.end(body);\n}\n\n/** Maximum allowed request body size (1 MB) */\nconst MAX_BODY_SIZE = 1 * 1024 * 1024;\n\n/**\n * Read and parse a JSON body from an incoming request.\n * Enforces a size limit to prevent memory exhaustion (DoS).\n * Throws an error with message 'Payload too large' if the limit is exceeded.\n */\nexport async function readJsonBody<T>(req: IncomingMessage): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n const chunks: Buffer[] = [];\n let size = 0;\n let aborted = false;\n req.on('data', (chunk: Buffer) => {\n size += chunk.length;\n if (size > MAX_BODY_SIZE) {\n aborted = true;\n req.destroy();\n reject(new Error('Payload too large'));\n return;\n }\n chunks.push(chunk);\n });\n req.on('end', () => {\n if (aborted) return;\n try {\n resolve(JSON.parse(Buffer.concat(chunks).toString('utf-8')) as T);\n } catch {\n reject(new Error('Invalid JSON'));\n }\n });\n req.on('error', (err) => {\n if (!aborted) reject(err);\n });\n });\n}\n\n/**\n * Create the HTTP request handler for the diagram server.\n * This is the core handler logic shared between startServer and createHttpServer.\n */\nfunction createHandler(\n routes: Route[],\n staticDir: string,\n) {\n return async (req: IncomingMessage, res: ServerResponse): Promise<void> => {\n try {\n const url = new URL(req.url ?? '/', `http://${req.headers.host}`);\n\n // CORS headers on all responses (localhost-only)\n setCorsHeaders(req, res);\n\n // Handle OPTIONS preflight\n if (req.method === 'OPTIONS') {\n res.writeHead(204);\n res.end();\n return;\n }\n\n // Try matching a registered route\n for (const route of routes) {\n if (req.method === route.method) {\n const match = route.pattern.exec(url.pathname);\n if (match) {\n const params = match.groups ?? {};\n await route.handler(req, res, params);\n return;\n }\n }\n }\n\n // Serve index: / or /index.html -> live.html\n if (url.pathname === '/' || url.pathname === '/index.html') {\n const served = await serveStaticFile(res, path.join(staticDir, 'live.html'));\n if (served) return;\n }\n\n // Try serving static file from static dir (with path traversal protection)\n const safePath = path.normalize(url.pathname).replace(/^(\\.\\.[/\\\\])+/, '');\n const staticFilePath = path.join(staticDir, safePath);\n if (staticFilePath === staticDir || staticFilePath.startsWith(staticDir + path.sep)) {\n const served = await serveStaticFile(res, staticFilePath);\n if (served) return;\n }\n\n // 404\n sendJson(res, { error: 'Not Found' }, 404);\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Internal Server Error';\n log.error('Request error:', message);\n sendJson(res, { error: message }, 500);\n }\n };\n}\n\n/** The composite server instance returned by createHttpServer */\nexport interface ServerInstance {\n httpServer: ReturnType<typeof createServer>;\n wsManager: WebSocketManager;\n fileWatcher: FileWatcher;\n breakpointContinueSignals: Map<string, boolean>;\n sessionStore: SessionStore;\n heatmapStore: HeatmapStore;\n /** Add a new project directory with its own FileWatcher and WebSocket namespace */\n addProject: (name: string, dir: string) => void;\n /** Close all FileWatcher instances (default + named projects) */\n closeAllWatchers: () => Promise<void>;\n}\n\n/**\n * Create an http.Server instance for the given project directory.\n * Used for integration testing (port 0) and as the core of startServer.\n * Returns a ServerInstance with httpServer, wsManager, fileWatcher, and addProject().\n *\n * The default project connects on /ws. Named projects connect on /ws/project-name.\n */\nexport function createHttpServer(projectDir: string, existingService?: DiagramService): ServerInstance {\n const resolvedDir = path.resolve(projectDir);\n const service = existingService ?? new DiagramService(resolvedDir);\n const staticDir = getStaticDir();\n\n const httpServer = createServer();\n const wsManager = new WebSocketManager(httpServer);\n const breakpointContinueSignals = new Map<string, boolean>();\n const sessionStore = new SessionStore(resolvedDir);\n const heatmapStore = new HeatmapStore();\n\n const routes = registerRoutes(service, resolvedDir, wsManager, breakpointContinueSignals, sessionStore, heatmapStore);\n const handler = createHandler(routes, staticDir);\n\n httpServer.on('request', (req, res) => {\n handler(req, res).catch((err) => {\n log.error('Unhandled error:', err);\n if (!res.headersSent) {\n sendJson(res, { error: 'Internal Server Error' }, 500);\n }\n });\n });\n\n // Track all watchers for cleanup\n const watchers = new Map<string, FileWatcher>();\n\n /** Create a FileWatcher for a project directory with standard broadcast callbacks */\n function createProjectWatcher(\n projectName: string, projectDir: string, projectService: DiagramService,\n ): FileWatcher {\n return new FileWatcher(\n projectDir,\n async (file) => {\n const content = await readFile(\n path.join(projectDir, file), 'utf-8',\n ).catch(() => null);\n if (content !== null) {\n wsManager.broadcast(projectName, { type: 'file:changed', file, content });\n }\n try {\n const graph = await projectService.readGraph(file);\n const graphJson = serializeGraphModel(graph);\n wsManager.broadcast(projectName, { type: 'graph:update', file, graph: graphJson });\n } catch {\n // Parse failure -- file:changed already sent, browser falls back to Mermaid\n }\n },\n (file) => {\n wsManager.broadcast(projectName, { type: 'file:added', file });\n projectService.listFiles().then((files) => {\n wsManager.broadcast(projectName, { type: 'tree:updated', files });\n }).catch((err) => { log.error(`Failed to list files for ${projectName} after add:`, err); });\n },\n (file) => {\n wsManager.broadcast(projectName, { type: 'file:removed', file });\n projectService.listFiles().then((files) => {\n wsManager.broadcast(projectName, { type: 'tree:updated', files });\n }).catch((err) => { log.error(`Failed to list files for ${projectName} after remove:`, err); });\n },\n );\n }\n\n const fileWatcher = createProjectWatcher('default', resolvedDir, service);\n watchers.set('default', fileWatcher);\n\n /** Add a new project directory with its own FileWatcher and WebSocket namespace */\n function addProject(name: string, dir: string): void {\n const resolvedProjectDir = path.resolve(dir);\n const projectService = new DiagramService(resolvedProjectDir);\n wsManager.addProject(name);\n watchers.set(name, createProjectWatcher(name, resolvedProjectDir, projectService));\n }\n\n /** Close all FileWatcher instances (default + named projects) */\n async function closeAllWatchers(): Promise<void> {\n for (const w of watchers.values()) {\n await w.close();\n }\n watchers.clear();\n }\n\n return { httpServer, wsManager, fileWatcher, breakpointContinueSignals, sessionStore, heatmapStore, addProject, closeAllWatchers };\n}\n\n/**\n * Start the HTTP server for the diagram viewer.\n *\n * - Creates a DiagramService bound to the project directory\n * - Detects an available port (falls back if preferred port is in use)\n * - Serves static assets from getStaticDir() and diagram files from project dir\n * - Registers all routes (live.html endpoints + REST API)\n * - Opens the browser automatically (unless disabled)\n * - Handles graceful shutdown on SIGINT\n */\nexport async function startServer(options: ServerOptions): Promise<void> {\n const projectDir = path.resolve(options.dir);\n\n const actualPort = await detect(options.port);\n if (actualPort !== options.port) {\n log.warn(`Port ${options.port} is in use, using port ${actualPort}`);\n }\n\n const service = new DiagramService(projectDir);\n const { httpServer, wsManager, closeAllWatchers } = createHttpServer(projectDir, service);\n\n // Check for .mmd files and warn if none found\n const mmdFiles = await service.listFiles();\n if (mmdFiles.length === 0) {\n log.warn('No .mmd files found in ' + projectDir);\n log.warn(\"Run 'smartcode init' to create a sample diagram, or create a .mmd file manually.\");\n }\n\n httpServer.listen(actualPort, () => {\n const url = `http://localhost:${actualPort}`;\n log.info(`Server running at ${url}`);\n log.info(`Serving diagrams from ${projectDir}`);\n if (options.openBrowser) {\n open(url).catch(() => {\n log.warn('Could not open browser automatically');\n });\n }\n });\n\n // Register in workspace registry\n await registerWorkspace(projectDir, actualPort).catch((err) => {\n log.warn('Failed to register workspace:', err instanceof Error ? err.message : err);\n });\n\n // Graceful shutdown\n process.once('SIGINT', async () => {\n log.info('Shutting down...');\n const shutdownTimeout = setTimeout(() => {\n log.warn('Shutdown timed out after 5s, forcing exit');\n process.exit(1);\n }, 5000);\n try {\n await deregisterWorkspace(actualPort).catch(() => {});\n await closeAllWatchers().catch(() => {});\n wsManager.close();\n await new Promise<void>((resolve) => httpServer.close(() => resolve()));\n } finally {\n clearTimeout(shutdownTimeout);\n process.exit(0);\n }\n });\n}\n","import { writeFile, access } from 'node:fs/promises';\nimport path from 'node:path';\nimport pc from 'picocolors';\nimport { log } from '../utils/logger.js';\n\n/** Default project config for .smartcode.json */\nconst DEFAULT_CONFIG = {\n version: 1,\n diagramDir: '.',\n port: 3333,\n};\n\n/** MCP config so Claude Code / Cursor auto-start SmartCode */\nconst MCP_CONFIG = {\n mcpServers: {\n 'smartcode': {\n command: 'smartcode',\n args: ['mcp', '--serve'],\n },\n },\n};\n\n/** Sample reasoning.mmd content for new projects */\nconst SAMPLE_DIAGRAM = `flowchart LR\n Start[\"Problem Statement\"] --> Analyze[\"Analyze Requirements\"]\n Analyze --> Plan[\"Create Plan\"]\n Plan --> Implement[\"Implement Solution\"]\n Implement --> Verify[\"Verify Results\"]\n Verify --> Done[\"Complete\"]\n`;\n\n/**\n * Initialize a SmartCode project in the given directory.\n * Creates .smartcode.json config and a sample reasoning.mmd file.\n *\n * @param dir - Directory to initialize (default: current directory)\n * @param force - Overwrite existing .smartcode.json if present\n */\nexport async function initProject(dir: string, force?: boolean): Promise<void> {\n const resolvedDir = path.resolve(dir);\n const configPath = path.join(resolvedDir, '.smartcode.json');\n const diagramPath = path.join(resolvedDir, 'reasoning.mmd');\n\n // Check if already initialized\n const exists = await access(configPath).then(() => true).catch(() => false);\n if (exists && !force) {\n throw new Error(\n 'Already initialized: .smartcode.json exists. Use --force to reinitialize.',\n );\n }\n\n // Write .smartcode.json\n await writeFile(configPath, JSON.stringify(DEFAULT_CONFIG, null, 2) + '\\n', 'utf-8');\n\n // Write .mcp.json (MCP config for AI tools)\n const mcpPath = path.join(resolvedDir, '.mcp.json');\n const mcpExists = await access(mcpPath).then(() => true).catch(() => false);\n if (!mcpExists || force) {\n await writeFile(mcpPath, JSON.stringify(MCP_CONFIG, null, 2) + '\\n', 'utf-8');\n }\n\n // Write reasoning.mmd (only if missing or force)\n const diagramExists = await access(diagramPath).then(() => true).catch(() => false);\n if (!diagramExists || force) {\n await writeFile(diagramPath, SAMPLE_DIAGRAM, 'utf-8');\n }\n\n log.info(pc.green('Initialized SmartCode'));\n log.info(pc.dim(` ${configPath}`));\n log.info(pc.dim(` ${mcpPath}`));\n log.info(pc.dim(` ${diagramPath}`));\n log.info('');\n log.info(`Open this project in ${pc.cyan('Claude Code')} or ${pc.cyan('Cursor')} — SmartCode starts automatically.`);\n log.info(`Or run ${pc.cyan('smartcode serve')} to start the viewer manually.`);\n}\n","import { request } from 'node:http';\nimport pc from 'picocolors';\nimport { log } from '../utils/logger.js';\n\n/** Format seconds into human-readable duration (e.g., \"1h 2m 3s\") */\nexport function formatUptime(seconds: number): string {\n const hrs = Math.floor(seconds / 3600);\n const mins = Math.floor((seconds % 3600) / 60);\n const secs = Math.floor(seconds % 60);\n\n const parts: string[] = [];\n if (hrs > 0) parts.push(`${hrs}h`);\n if (mins > 0) parts.push(`${mins}m`);\n if (secs > 0 || parts.length === 0) parts.push(`${secs}s`);\n\n return parts.join(' ');\n}\n\n/** Status response shape from /api/status */\ninterface StatusResponse {\n status: string;\n uptime: number;\n port: number | null;\n projectDir: string;\n files: number;\n connectedClients: number;\n activeFlags: Array<{ file: string; nodeId: string; message: string }>;\n}\n\n/**\n * Query the running SmartCode server and display its status.\n *\n * @param port - Port to query (default: 3333)\n */\nexport async function showStatus(port: number): Promise<void> {\n try {\n const data = await fetchStatus(port);\n\n log.info(pc.green('Server is running'));\n log.info(` Port: ${port}`);\n log.info(` Uptime: ${formatUptime(data.uptime)}`);\n log.info(` Project: ${data.projectDir}`);\n log.info(` Files: ${data.files}`);\n log.info(` Clients: ${data.connectedClients}`);\n log.info(` Flags: ${data.activeFlags.length}`);\n\n if (data.activeFlags.length > 0) {\n log.info('');\n log.info(pc.yellow('Active Flags:'));\n for (const flag of data.activeFlags) {\n log.info(` ${pc.dim(flag.file)} ${flag.nodeId}: ${flag.message}`);\n }\n }\n } catch {\n log.info(pc.red('Server is not running'));\n log.info(` Tried port: ${port}`);\n log.info(` Run ${pc.cyan('smartcode serve')} to start the server`);\n }\n}\n\n/** Fetch /api/status from the local server */\nfunction fetchStatus(port: number): Promise<StatusResponse> {\n return new Promise((resolve, reject) => {\n const req = request(\n {\n hostname: 'localhost',\n port,\n path: '/api/status',\n method: 'GET',\n timeout: 3000,\n },\n (res) => {\n const chunks: Buffer[] = [];\n res.on('data', (chunk: Buffer) => chunks.push(chunk));\n res.on('end', () => {\n try {\n const body = Buffer.concat(chunks).toString('utf-8');\n resolve(JSON.parse(body) as StatusResponse);\n } catch (err) {\n reject(err);\n }\n });\n },\n );\n\n req.on('error', reject);\n req.on('timeout', () => {\n req.destroy();\n reject(new Error('Request timed out'));\n });\n req.end();\n });\n}\n","import { z } from 'zod';\n\n/**\n * Raw Zod shapes for MCP tool inputs.\n * These are NOT wrapped in z.object() -- the MCP SDK wraps them internally\n * when passed to registerTool()'s inputSchema option.\n */\n\nexport const UpdateDiagramInput = {\n filePath: z\n .string()\n .describe(\n 'Relative path to the .mmd file (e.g., \"reasoning.mmd\")',\n ),\n content: z\n .string()\n .describe('Full Mermaid diagram content'),\n nodeStatuses: z\n .record(\n z.string(),\n z.enum(['ok', 'problem', 'in-progress', 'discarded']),\n )\n .optional()\n .describe(\n 'Node status colors. Map of nodeId to status. Example: {\"ANALYZE\": \"ok\", \"PLAN\": \"in-progress\", \"DEPLOY\": \"problem\"}',\n ),\n riskLevels: z\n .record(\n z.string(),\n z.object({\n level: z.enum(['high', 'medium', 'low']),\n reason: z.string(),\n }),\n )\n .optional()\n .describe(\n 'Risk assessments per node. Example: {\"DEPLOY\": {\"level\": \"high\", \"reason\": \"touches production DB\"}}',\n ),\n ghostPaths: z\n .array(\n z.object({\n from: z.string(),\n to: z.string(),\n label: z.string().optional(),\n }),\n )\n .optional()\n .describe(\n 'Rejected alternatives. Example: [{\"from\": \"A\", \"to\": \"C\", \"label\": \"Skipped: too risky\"}]',\n ),\n};\n\nexport const ReadFlagsInput = {\n filePath: z\n .string()\n .describe(\n 'Relative path to the .mmd file to read flags from',\n ),\n};\n\nexport const GetDiagramContextInput = {\n filePath: z\n .string()\n .describe(\n 'Relative path to the .mmd file to get context for',\n ),\n};\n\nexport const UpdateNodeStatusInput = {\n filePath: z\n .string()\n .describe('Relative path to the .mmd file'),\n nodeId: z\n .string()\n .describe('ID of the node to update status for'),\n status: z\n .enum(['ok', 'problem', 'in-progress', 'discarded'])\n .describe('Status to set on the node'),\n};\n\nexport const GetCorrectionContextInput = {\n filePath: z\n .string()\n .describe('Relative path to the .mmd file'),\n nodeId: z\n .string()\n .describe('ID of the flagged node to get correction context for'),\n};\n\nexport const CheckBreakpointsInput = {\n filePath: z\n .string()\n .describe('Relative path to the .mmd file'),\n currentNodeId: z\n .string()\n .describe('Node ID the AI is currently processing'),\n};\n\nexport const RecordGhostPathInput = {\n filePath: z\n .string()\n .describe('Relative path to the .mmd file'),\n fromNodeId: z\n .string()\n .describe('Source node of the discarded path'),\n toNodeId: z\n .string()\n .describe('Target node of the discarded path'),\n label: z\n .string()\n .optional()\n .describe('Optional reason for discarding this path'),\n};\n\n// Tool 12: create_mcp_session\nexport const CreateMcpSessionInput = {\n label: z\n .string()\n .optional()\n .describe(\n 'Human-readable label for this session (e.g., \"Debug auth bug\"). Auto-generated if not provided.',\n ),\n};\n\n// Phase 16: Session recording + risk annotation schemas\n\nexport const StartSessionInput = {\n filePath: z\n .string()\n .describe('Relative path to the .mmd file to record a session for'),\n};\n\nexport const RecordStepInput = {\n sessionId: z\n .string()\n .describe('ID of the active session to record a step in'),\n nodeId: z\n .string()\n .describe('ID of the node being visited'),\n action: z\n .string()\n .describe('Description of the action taken (e.g., \"analyzed\", \"modified\", \"flagged\")'),\n metadata: z\n .record(z.string(), z.unknown())\n .optional()\n .describe('Optional metadata about this step'),\n};\n\nexport const EndSessionInput = {\n sessionId: z\n .string()\n .describe('ID of the active session to end'),\n};\n\nexport const SetRiskLevelInput = {\n filePath: z\n .string()\n .describe('Relative path to the .mmd file'),\n nodeId: z\n .string()\n .describe('ID of the node to set risk level on'),\n level: z\n .enum(['high', 'medium', 'low'])\n .describe('Risk level: high, medium, or low'),\n reason: z\n .string()\n .describe('Reason for the risk assessment'),\n};\n","import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { DiagramService } from '../diagram/service.js';\nimport type { SessionStore } from '../session/session-store.js';\nimport type { WebSocketManager } from '../server/websocket.js';\nimport type { McpSessionRegistry } from '../registry/mcp-session-registry.js';\nimport type { SessionEvent } from '../session/session-types.js';\nimport {\n StartSessionInput,\n RecordStepInput,\n EndSessionInput,\n SetRiskLevelInput,\n} from './schemas.js';\n\n/**\n * Register session recording and risk annotation MCP tools.\n *\n * Tools:\n * - start_session (Tool 8): Start a new JSONL session for a diagram file\n * - record_step (Tool 9): Record a node visit event in an active session\n * - end_session (Tool 10): Close a session and return summary statistics\n * - set_risk_level (Tool 11): Set @risk annotation on a node\n */\nexport function registerSessionTools(\n server: McpServer,\n service: DiagramService,\n options?: {\n sessionStore?: SessionStore;\n wsManager?: WebSocketManager;\n mcpSessionRegistry?: McpSessionRegistry;\n },\n): void {\n // Tool 8: start_session (Phase 16)\n server.registerTool(\n 'start_session',\n {\n description:\n 'Start a new recording session for a diagram file. Returns a session ID used by record_step and end_session. Sessions are persisted as JSONL files.',\n inputSchema: StartSessionInput,\n },\n async ({ filePath }) => {\n try {\n const sessionStore = options?.sessionStore;\n\n if (!sessionStore) {\n return {\n content: [\n {\n type: 'text' as const,\n text: 'Session recording unavailable: no session store (requires --serve mode)',\n },\n ],\n isError: true,\n };\n }\n\n const sessionId = await sessionStore.startSession(filePath);\n\n if (options?.mcpSessionRegistry) {\n options.mcpSessionRegistry.trackDiagram(filePath).catch(() => {});\n if (options?.wsManager) {\n options.wsManager.broadcastAll({ type: 'mcp-session:updated' });\n }\n }\n\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify({ sessionId, message: 'Session started' }),\n },\n ],\n };\n } catch (error) {\n const message =\n error instanceof Error ? error.message : 'Unknown error';\n return {\n content: [{ type: 'text' as const, text: message }],\n isError: true,\n };\n }\n },\n );\n\n // Tool 9: record_step (Phase 16)\n server.registerTool(\n 'record_step',\n {\n description:\n 'Record a step in an active session. Each step represents a node visit with an action description. The event is persisted to the session JSONL file and optionally broadcast via WebSocket.',\n inputSchema: RecordStepInput,\n },\n async ({ sessionId, nodeId, action, metadata }) => {\n try {\n const sessionStore = options?.sessionStore;\n\n if (!sessionStore) {\n return {\n content: [\n {\n type: 'text' as const,\n text: 'Session recording unavailable: no session store (requires --serve mode)',\n },\n ],\n isError: true,\n };\n }\n\n const event: SessionEvent = {\n ts: Date.now(),\n type: 'node:visited',\n payload: { nodeId, action, ...metadata },\n };\n\n await sessionStore.recordStep(sessionId, event);\n\n if (options?.wsManager) {\n options.wsManager.broadcastAll({\n type: 'session:event',\n sessionId,\n event: { ts: event.ts, type: event.type, payload: event.payload } as Record<string, unknown>,\n });\n\n // Broadcast incremental heatmap update for real-time visualization (HEAT-02)\n const activeMeta = sessionStore.getActiveSession(sessionId);\n if (activeMeta?.diagramFile) {\n options.wsManager.broadcastAll({\n type: 'heatmap:update',\n file: activeMeta.diagramFile,\n data: { [nodeId]: 1 },\n });\n }\n }\n\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify({ recorded: true }),\n },\n ],\n };\n } catch (error) {\n const message =\n error instanceof Error ? error.message : 'Unknown error';\n return {\n content: [{ type: 'text' as const, text: message }],\n isError: true,\n };\n }\n },\n );\n\n // Tool 10: end_session (Phase 16)\n server.registerTool(\n 'end_session',\n {\n description:\n 'End an active recording session. Returns a summary with statistics (duration, nodes visited, edges traversed). If a WebSocket manager is available, broadcasts updated heatmap data.',\n inputSchema: EndSessionInput,\n },\n async ({ sessionId }) => {\n try {\n const sessionStore = options?.sessionStore;\n\n if (!sessionStore) {\n return {\n content: [\n {\n type: 'text' as const,\n text: 'Session recording unavailable: no session store (requires --serve mode)',\n },\n ],\n isError: true,\n };\n }\n\n const summary = await sessionStore.endSession(sessionId);\n\n if (options?.wsManager && summary.diagramFile) {\n const heatmapData = await sessionStore.getHeatmapData(summary.diagramFile);\n options.wsManager.broadcastAll({\n type: 'heatmap:update',\n file: summary.diagramFile,\n data: heatmapData,\n });\n }\n\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify(summary, null, 2),\n },\n ],\n };\n } catch (error) {\n const message =\n error instanceof Error ? error.message : 'Unknown error';\n return {\n content: [{ type: 'text' as const, text: message }],\n isError: true,\n };\n }\n },\n );\n\n // Tool 11: set_risk_level (Phase 16)\n server.registerTool(\n 'set_risk_level',\n {\n description:\n 'Set a risk level annotation on a diagram node. Risk levels (high, medium, low) are persisted as @risk annotations in the .mmd file and rendered in the browser viewer.',\n inputSchema: SetRiskLevelInput,\n },\n async ({ filePath, nodeId, level, reason }) => {\n try {\n await service.setRisk(filePath, nodeId, level, reason);\n\n if (options?.mcpSessionRegistry) {\n options.mcpSessionRegistry.trackDiagram(filePath).catch(() => {});\n if (options?.wsManager) {\n options.wsManager.broadcastAll({ type: 'mcp-session:updated' });\n }\n }\n\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify({ set: true, nodeId, level }),\n },\n ],\n };\n } catch (error) {\n const message =\n error instanceof Error ? error.message : 'Unknown error';\n return {\n content: [{ type: 'text' as const, text: message }],\n isError: true,\n };\n }\n },\n );\n}\n","import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { DiagramService } from '../diagram/service.js';\nimport type { WebSocketManager } from '../server/websocket.js';\nimport type { SessionStore } from '../session/session-store.js';\nimport type { McpSessionRegistry } from '../registry/mcp-session-registry.js';\nimport {\n UpdateDiagramInput,\n ReadFlagsInput,\n GetDiagramContextInput,\n UpdateNodeStatusInput,\n GetCorrectionContextInput,\n CheckBreakpointsInput,\n RecordGhostPathInput,\n CreateMcpSessionInput,\n} from './schemas.js';\nimport { registerSessionTools } from './session-tools.js';\n\n/**\n * Register all 11 MCP tools on the server, backed by DiagramService.\n *\n * Tools 1-7 (Phase 5/15):\n * - update_diagram: Create or update a .mmd file\n * - read_flags: Read all active developer flags from a diagram\n * - get_diagram_context: Get full diagram state (content, flags, statuses, validation)\n * - update_node_status: Set node status (ok, problem, in-progress, discarded)\n * - get_correction_context: Get structured correction context for a flagged node\n * - check_breakpoints: Check if a node has a breakpoint, returns 'pause' or 'continue'\n * - record_ghost_path: Record a discarded reasoning branch as a ghost path\n *\n * Tool 12:\n * - create_mcp_session: Start a new MCP session to group diagrams per conversation\n *\n * Tools 8-11 (Phase 16, registered via session-tools.ts):\n * - start_session: Start a new JSONL recording session\n * - record_step: Record a node visit event in a session\n * - end_session: Close a session and return summary\n * - set_risk_level: Set @risk annotation on a node\n */\nexport function registerTools(\n server: McpServer,\n service: DiagramService,\n options?: {\n wsManager?: WebSocketManager;\n breakpointContinueSignals?: Map<string, boolean>;\n sessionStore?: SessionStore;\n mcpSessionRegistry?: McpSessionRegistry;\n },\n): void {\n // Tool 1: update_diagram (MCP-02) — all-in-one: diagram + statuses + risks + ghost paths\n server.registerTool(\n 'update_diagram',\n {\n description:\n 'Create or update a Mermaid diagram (.mmd file) with optional annotations — all in ONE call. ' +\n 'Pass nodeStatuses to color nodes (ok=green, problem=red, in-progress=yellow, discarded=gray). ' +\n 'Pass riskLevels to flag risky nodes with reasons. ' +\n 'Pass ghostPaths to show rejected alternatives as dashed edges. ' +\n 'Changes appear in the browser viewer within 100ms via WebSocket.',\n inputSchema: UpdateDiagramInput,\n },\n async ({ filePath, content, nodeStatuses, riskLevels, ghostPaths }) => {\n try {\n // Build annotation maps from the flat input\n const statusMap = nodeStatuses\n ? new Map(Object.entries(nodeStatuses)) as Map<string, import('../diagram/types.js').NodeStatus>\n : undefined;\n\n const riskMap = riskLevels\n ? new Map(\n Object.entries(riskLevels).map(([nodeId, r]) => [\n nodeId,\n { nodeId, level: r.level as import('../diagram/types.js').RiskLevel, reason: r.reason },\n ]),\n )\n : undefined;\n\n // Build ghost path annotations from input\n const ghostAnnotations = ghostPaths && ghostPaths.length > 0\n ? ghostPaths.map((gp) => ({\n fromNodeId: gp.from,\n toNodeId: gp.to,\n label: gp.label ?? '',\n }))\n : undefined;\n\n // Write diagram preserving existing flags/breakpoints (developer-owned annotations)\n await service.writeDiagramPreserving(filePath, content, statusMap, riskMap, ghostAnnotations);\n\n // Track diagram in MCP session registry and notify browsers\n if (options?.mcpSessionRegistry) {\n options.mcpSessionRegistry.trackDiagram(filePath).catch(() => {});\n if (options?.wsManager) {\n options.wsManager.broadcastAll({ type: 'mcp-session:updated' });\n }\n }\n\n // Broadcast ghost path update to browsers\n if (ghostAnnotations && ghostAnnotations.length > 0 && options?.wsManager) {\n const allGhosts = await service.getGhosts(filePath);\n options.wsManager.broadcastAll({\n type: 'ghost:update',\n file: filePath,\n ghostPaths: allGhosts,\n });\n }\n\n // Build summary response\n const parts = [`Diagram updated: ${filePath}`];\n if (statusMap && statusMap.size > 0) parts.push(`${statusMap.size} node statuses set`);\n if (riskMap && riskMap.size > 0) parts.push(`${riskMap.size} risk levels set`);\n if (ghostPaths && ghostPaths.length > 0) parts.push(`${ghostPaths.length} ghost paths recorded`);\n\n return {\n content: [{ type: 'text' as const, text: parts.join('. ') + '.' }],\n };\n } catch (error) {\n const message =\n error instanceof Error ? error.message : 'Unknown error';\n return {\n content: [{ type: 'text' as const, text: message }],\n isError: true,\n };\n }\n },\n );\n\n // Tool 2: read_flags (MCP-03)\n server.registerTool(\n 'read_flags',\n {\n description:\n 'Read all active developer flags from a .mmd diagram file. Flags are annotations added by developers to signal issues or requests to the AI.',\n inputSchema: ReadFlagsInput,\n },\n async ({ filePath }) => {\n try {\n const flags = await service.getFlags(filePath);\n const result = flags.map((f) => ({\n nodeId: f.nodeId,\n message: f.message,\n }));\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify(result, null, 2),\n },\n ],\n };\n } catch (error) {\n const message =\n error instanceof Error ? error.message : 'Unknown error';\n return {\n content: [{ type: 'text' as const, text: message }],\n isError: true,\n };\n }\n },\n );\n\n // Tool 3: get_diagram_context (MCP-04)\n server.registerTool(\n 'get_diagram_context',\n {\n description:\n 'Get the current state of a diagram including Mermaid content, flags, node statuses, and validation info. Use this to understand the diagram before making changes.',\n inputSchema: GetDiagramContextInput,\n },\n async ({ filePath }) => {\n try {\n const diagram = await service.readDiagram(filePath);\n\n const context = {\n filePath: diagram.filePath,\n mermaidContent: diagram.mermaidContent,\n flags: Array.from(diagram.flags.values()).map((f) => ({\n nodeId: f.nodeId,\n message: f.message,\n })),\n statuses: Object.fromEntries(diagram.statuses),\n breakpoints: Array.from(diagram.breakpoints),\n risks: Array.from(diagram.risks.values()).map((r) => ({\n nodeId: r.nodeId,\n level: r.level,\n reason: r.reason,\n })),\n ghostPaths: diagram.ghosts.map((gp) => ({\n fromNodeId: gp.fromNodeId,\n toNodeId: gp.toNodeId,\n label: gp.label,\n })),\n validation: {\n valid: diagram.validation.valid,\n errors: diagram.validation.errors,\n diagramType: diagram.validation.diagramType,\n },\n };\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify(context, null, 2),\n },\n ],\n };\n } catch (error) {\n const message =\n error instanceof Error ? error.message : 'Unknown error';\n return {\n content: [{ type: 'text' as const, text: message }],\n isError: true,\n };\n }\n },\n );\n\n // Tool 4: update_node_status (MCP-05)\n server.registerTool(\n 'update_node_status',\n {\n description:\n 'Set the status of a specific node in a diagram. Status values: \"ok\" (green), \"problem\" (red), \"in-progress\" (yellow), \"discarded\" (gray). Status renders as color in the browser viewer.',\n inputSchema: UpdateNodeStatusInput,\n },\n async ({ filePath, nodeId, status }) => {\n try {\n await service.setStatus(filePath, nodeId, status);\n if (options?.mcpSessionRegistry) {\n options.mcpSessionRegistry.trackDiagram(filePath).catch(() => {});\n if (options?.wsManager) {\n options.wsManager.broadcastAll({ type: 'mcp-session:updated' });\n }\n }\n return {\n content: [\n {\n type: 'text' as const,\n text: `Node \"${nodeId}\" status set to \"${status}\" in ${filePath}`,\n },\n ],\n };\n } catch (error) {\n const message =\n error instanceof Error ? error.message : 'Unknown error';\n return {\n content: [{ type: 'text' as const, text: message }],\n isError: true,\n };\n }\n },\n );\n\n // Tool 5: get_correction_context (AI-02, AI-03)\n server.registerTool(\n 'get_correction_context',\n {\n description:\n 'Get structured correction context for a flagged diagram node. Returns the flag message, node context (statuses, other flags), the full diagram content, and a natural language instruction for making corrections. Use this when a developer has flagged a node for correction.',\n inputSchema: GetCorrectionContextInput,\n },\n async ({ filePath, nodeId }) => {\n try {\n const diagram = await service.readDiagram(filePath);\n const flag = diagram.flags.get(nodeId);\n\n if (!flag) {\n return {\n content: [\n {\n type: 'text' as const,\n text: `No flag found on node \"${nodeId}\" in ${filePath}`,\n },\n ],\n isError: true,\n };\n }\n\n const context = {\n correction: {\n nodeId: flag.nodeId,\n flagMessage: flag.message,\n },\n diagramState: {\n filePath,\n mermaidContent: diagram.mermaidContent,\n allFlags: Array.from(diagram.flags.values()).map((f) => ({\n nodeId: f.nodeId,\n message: f.message,\n })),\n statuses: Object.fromEntries(diagram.statuses),\n },\n instruction: `The developer flagged node \"${nodeId}\" with the message: \"${flag.message}\". Review the diagram and update it to address this feedback. Use the update_diagram tool to write the corrected Mermaid content.`,\n };\n\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify(context, null, 2),\n },\n ],\n };\n } catch (error) {\n const message =\n error instanceof Error ? error.message : 'Unknown error';\n return {\n content: [{ type: 'text' as const, text: message }],\n isError: true,\n };\n }\n },\n );\n\n // Tool 6: check_breakpoints (Phase 15)\n server.registerTool(\n 'check_breakpoints',\n {\n description:\n 'Check if the current node has a breakpoint set. Returns \"pause\" if a breakpoint exists and no continue signal is pending, \"continue\" otherwise. The AI should respect the pause signal by waiting and re-checking.',\n inputSchema: CheckBreakpointsInput,\n },\n async ({ filePath, currentNodeId }) => {\n try {\n const breakpoints = await service.getBreakpoints(filePath);\n\n if (breakpoints.has(currentNodeId)) {\n const signalKey = `${filePath}:${currentNodeId}`;\n const continueSignals = options?.breakpointContinueSignals;\n\n if (continueSignals && continueSignals.has(signalKey)) {\n // One-time consumption of continue signal\n continueSignals.delete(signalKey);\n if (options?.wsManager) {\n options.wsManager.broadcastAll({\n type: 'breakpoint:continue',\n file: filePath,\n nodeId: currentNodeId,\n });\n }\n return {\n content: [{ type: 'text' as const, text: 'continue' }],\n };\n }\n\n // Breakpoint exists, no continue signal\n if (options?.wsManager) {\n options.wsManager.broadcastAll({\n type: 'breakpoint:hit',\n file: filePath,\n nodeId: currentNodeId,\n });\n }\n return {\n content: [{ type: 'text' as const, text: 'pause' }],\n };\n }\n\n // No breakpoint on this node\n return {\n content: [{ type: 'text' as const, text: 'continue' }],\n };\n } catch (error) {\n const message =\n error instanceof Error ? error.message : 'Unknown error';\n return {\n content: [{ type: 'text' as const, text: message }],\n isError: true,\n };\n }\n },\n );\n\n // Tool 7: record_ghost_path (Phase 15)\n server.registerTool(\n 'record_ghost_path',\n {\n description:\n 'Record a discarded reasoning branch as a ghost path. Ghost paths are displayed as dashed translucent edges in the browser viewer.',\n inputSchema: RecordGhostPathInput,\n },\n async ({ filePath, fromNodeId, toNodeId, label }) => {\n try {\n if (options?.mcpSessionRegistry) {\n options.mcpSessionRegistry.trackDiagram(filePath).catch(() => {});\n if (options?.wsManager) {\n options.wsManager.broadcastAll({ type: 'mcp-session:updated' });\n }\n }\n\n // Persist ghost path as @ghost annotation in the .mmd file\n await service.addGhost(filePath, fromNodeId, toNodeId, label ?? '');\n\n // Broadcast updated ghost paths to browsers\n if (options?.wsManager) {\n const allGhosts = await service.getGhosts(filePath);\n options.wsManager.broadcastAll({\n type: 'ghost:update',\n file: filePath,\n ghostPaths: allGhosts,\n });\n }\n\n return {\n content: [\n {\n type: 'text' as const,\n text: `Ghost path recorded: ${fromNodeId} -> ${toNodeId}`,\n },\n ],\n };\n } catch (error) {\n const message =\n error instanceof Error ? error.message : 'Unknown error';\n return {\n content: [{ type: 'text' as const, text: message }],\n isError: true,\n };\n }\n },\n );\n\n // Tool 12: create_mcp_session -- Start a new session per conversation\n server.registerTool(\n 'create_mcp_session',\n {\n description:\n 'Start a new MCP session to group diagrams for this conversation. ' +\n 'Call at the start of each conversation to keep diagrams organized.',\n inputSchema: CreateMcpSessionInput,\n },\n async ({ label }) => {\n try {\n if (!options?.mcpSessionRegistry) {\n return {\n content: [{ type: 'text' as const, text: 'MCP sessions require --serve mode' }],\n isError: true,\n };\n }\n const sessionId = await options.mcpSessionRegistry.createSession(label);\n if (options?.wsManager) {\n options.wsManager.broadcastAll({ type: 'mcp-session:updated' });\n }\n return {\n content: [{ type: 'text' as const, text: `Session created: ${sessionId} (label: ${label || 'auto'})` }],\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n return {\n content: [{ type: 'text' as const, text: message }],\n isError: true,\n };\n }\n },\n );\n\n // Tools 8-11: Session recording + risk annotation (Phase 16)\n registerSessionTools(server, service, {\n sessionStore: options?.sessionStore,\n wsManager: options?.wsManager,\n mcpSessionRegistry: options?.mcpSessionRegistry,\n });\n}\n","import {\n McpServer,\n ResourceTemplate,\n} from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { DiagramService } from '../diagram/service.js';\n\n/**\n * Register all 2 MCP resources on the server, backed by DiagramService.\n *\n * Resources:\n * - diagram-list: List of all .mmd files in the project (fixed URI)\n * - diagram-content: Content of a specific .mmd file (URI template)\n */\nexport function registerResources(\n server: McpServer,\n service: DiagramService,\n): void {\n // Resource 1: diagram-list (MCP-06)\n // Fixed resource that lists all available .mmd files\n server.registerResource(\n 'diagram-list',\n 'smartcode://diagrams',\n {\n title: 'Available Diagrams',\n description: 'List of all .mmd diagram files in the project',\n mimeType: 'application/json',\n },\n async (uri) => {\n const files = await service.listFiles();\n return {\n contents: [\n {\n uri: uri.href,\n mimeType: 'application/json',\n text: JSON.stringify({ files }),\n },\n ],\n };\n },\n );\n\n // Resource 2: diagram-content (MCP-07)\n // Template resource for reading individual diagram content\n const diagramTemplate = new ResourceTemplate(\n 'smartcode://diagrams/{filePath}',\n {\n list: async () => {\n const files = await service.listFiles();\n return {\n resources: files.map((f) => ({\n uri: `smartcode://diagrams/${encodeURIComponent(f)}`,\n name: f,\n })),\n };\n },\n },\n );\n\n server.registerResource(\n 'diagram-content',\n diagramTemplate,\n {\n title: 'Diagram Content',\n description: 'Content of a specific .mmd diagram file',\n mimeType: 'text/plain',\n },\n async (_uri, variables) => {\n try {\n const filePath = decodeURIComponent(\n String(variables.filePath),\n );\n const diagram = await service.readDiagram(filePath);\n return {\n contents: [\n {\n uri: _uri.href,\n mimeType: 'text/plain',\n text: diagram.mermaidContent,\n },\n ],\n };\n } catch {\n // Resources don't have isError -- return empty contents on error\n return { contents: [] };\n }\n },\n );\n}\n","/**\n * MCP server instructions sent to AI clients on connection.\n * Teaches the AI HOW to use SmartCode effectively —\n * optimized for minimal tool calls and maximum proactive usage.\n */\nexport const MCP_INSTRUCTIONS = `\n# SmartCode — Show Your Reasoning Visually\n\nYou have SmartCode. Use it to show the developer your reasoning in real-time\nas a visual flowchart in their browser. ONE tool call = complete diagram with colors,\nrisks, and rejected alternatives.\n\n## Session Management\n\nAt the START of each conversation, call \\`create_mcp_session\\` with a descriptive label:\n\\`\\`\\`json\n{ \"label\": \"Debug auth bug\" }\n\\`\\`\\`\nThis groups all diagrams from this conversation into one session visible in the browser.\nIf you forget, diagrams still work but will go into a default session.\n\n## When to Use (PROACTIVELY, without being asked)\n\n- Planning any implementation with 3+ steps\n- Debugging: show your hypothesis tree\n- Refactoring: show before/after or decision points\n- Architecture analysis: show components and data flow\n- Any task where visualizing your plan prevents wasted effort\n\nDo NOT use for: one-line fixes, simple answers, obvious tasks.\n\n## How to Use: ONE Call Does Everything\n\n\\`update_diagram\\` accepts everything at once — diagram + annotations:\n\n\\`\\`\\`json\n{\n \"filePath\": \"reasoning.mmd\",\n \"content\": \"flowchart TD\\\\n ANALYZE[\\\\\"Analyze Code\\\\\"] --> PLAN[\\\\\"Create Plan\\\\\"]\\\\n PLAN --> IMPL[\\\\\"Implement\\\\\"]\\\\n IMPL --> TEST[\\\\\"Run Tests\\\\\"]\",\n \"nodeStatuses\": {\n \"ANALYZE\": \"ok\",\n \"PLAN\": \"in-progress\",\n \"IMPL\": \"problem\"\n },\n \"riskLevels\": {\n \"IMPL\": { \"level\": \"high\", \"reason\": \"Touches auth module, could break login flow\" }\n },\n \"ghostPaths\": [\n { \"from\": \"ANALYZE\", \"to\": \"IMPL\", \"label\": \"Skip planning: rejected, too complex\" }\n ]\n}\n\\`\\`\\`\n\n### Status Colors (nodeStatuses)\n- **\"ok\"** (green) = verified, working, done\n- **\"in-progress\"** (yellow) = currently working on this\n- **\"problem\"** (red) = found issue, needs attention\n- **\"discarded\"** (gray) = ruled out, not pursuing\n\n### Risk Levels (riskLevels)\n- **\"high\"** = likely bugs, edge cases, or failures — ALWAYS explain why\n- **\"medium\"** = moderate complexity, worth watching\n- **\"low\"** = straightforward\n\n### Ghost Paths (ghostPaths)\nAlternatives you considered but rejected. Include WHY you rejected them.\n\n## Diagram Design Rules\n\n- **Max 15 nodes** — be concise, not comprehensive\n- **Short labels** — \"Validate Input\" not \"Validate all user input fields and return errors\"\n- **Meaningful IDs** — use \\`VALIDATE\\` not \\`A\\` or \\`node1\\`\n- **Use subgraphs** to group phases\n- **TD** for sequential flows, **LR** for comparison/parallel\n\n## CRITICAL: Never Block Work for Diagrams\n\n**NEVER stop your workflow just to update a diagram.** Diagram calls must NOT interrupt your task flow.\n\nRules:\n1. **Always batch diagram calls with other tool calls** — if you're about to run a command, edit a file, or read something, include the \\`update_diagram\\` call in the SAME parallel tool call batch. Never make a dedicated turn just for a diagram.\n2. **If you have nothing else to do in this turn**, then a standalone diagram call is OK (e.g., initial plan before starting work, or final summary).\n3. **Prefer fewer, bigger updates** over many small ones. Update the diagram 2-3 times max per task: plan, mid-progress, done.\n\nGood pattern:\n\\`\\`\\`\nTurn 1: [update_diagram (plan)] + [read_file] — parallel\nTurn 2: [edit_file] + [update_diagram (progress)] — parallel\nTurn 3: [run_tests] + [update_diagram (final)] — parallel\n\\`\\`\\`\n\nBad pattern (NEVER do this):\n\\`\\`\\`\nTurn 1: [read_file]\nTurn 2: [update_diagram] ← BLOCKING! Wasted turn\nTurn 3: [edit_file]\nTurn 4: [update_diagram] ← BLOCKING again!\n\\`\\`\\`\n\n## Workflow During a Task\n\n1. **Before coding**: Create diagram showing your plan — batch it with your first read/search call\n2. **As you work**: Update statuses — batch it with your next edit/command call\n3. **When done**: Final update with all nodes green (ok) or red (problem) — batch with summary\n\nEach update is ONE \\`update_diagram\\` call — fast and fluid.\n\n## Incremental Updates\n\nFor small changes to an existing diagram, you can also use:\n- \\`update_node_status\\` — change one node's color\n- \\`set_risk_level\\` — add/change one risk assessment\n- \\`record_ghost_path\\` — add one rejected alternative\n\nBut prefer \\`update_diagram\\` for initial creation and major updates.\n\n## Developer Feedback (Flags)\n\nUse \\`read_flags\\` to check if the developer flagged any nodes for correction.\nIf flags exist, use \\`get_correction_context\\` to understand what they want.\n\n## Sessions (Optional, for long tasks)\n\nFor tasks spanning many steps, use sessions to generate heatmaps:\n- \\`start_session\\` → \\`record_step\\` per node → \\`end_session\\`\n\n## Breakpoints\n\nIf \\`check_breakpoints\\` returns \"pause\", STOP and wait for the developer.\n`.trim();\n","import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport type { DiagramService } from '../diagram/service.js';\nimport type { WebSocketManager } from '../server/websocket.js';\nimport type { SessionStore } from '../session/session-store.js';\nimport { registerTools } from './tools.js';\nimport { registerResources } from './resources.js';\nimport { MCP_INSTRUCTIONS } from './instructions.js';\nimport { log } from '../utils/logger.js';\nimport { register as registerWorkspace, deregister as deregisterWorkspace } from '../registry/workspace-registry.js';\nimport { McpSessionRegistry } from '../registry/mcp-session-registry.js';\nimport { getVersion } from '../utils/version.js';\n\n/** Options for starting the MCP server */\nexport interface McpServerOptions {\n dir: string;\n serve?: boolean;\n port?: number;\n}\n\n/** Optional dependencies for breakpoint/session features */\nexport interface McpToolDependencies {\n wsManager?: WebSocketManager;\n breakpointContinueSignals?: Map<string, boolean>;\n sessionStore?: SessionStore;\n mcpSessionRegistry?: McpSessionRegistry;\n}\n\n/**\n * Create an MCP server instance configured with the shared DiagramService.\n * Registers all tools and resources on the server.\n * When deps are provided, breakpoint and ghost path tools get full functionality.\n */\nexport function createMcpServer(\n service: DiagramService,\n deps?: McpToolDependencies,\n): McpServer {\n const server = new McpServer(\n { name: 'smartcode', version: getVersion() },\n { instructions: MCP_INSTRUCTIONS },\n );\n\n registerTools(server, service, deps);\n registerResources(server, service);\n\n log.debug('MCP server created');\n\n return server;\n}\n\n/**\n * Start the MCP server on stdio transport.\n * Accepts an options object with dir, optional serve flag, and optional port.\n *\n * When serve=false (default): Starts MCP on stdio only (lightweight for AI tools).\n * When serve=true: Also starts HTTP+WS server sharing the same DiagramService,\n * so MCP tool calls that modify .mmd files trigger WebSocket broadcasts to browsers.\n *\n * CRITICAL: All logging goes to stderr (via log.*). Never write to stdout\n * -- it would corrupt the MCP JSON-RPC protocol stream.\n */\nexport async function startMcpServer(options: McpServerOptions): Promise<void> {\n const { resolve } = await import('node:path');\n const { DiagramService } = await import('../diagram/service.js');\n\n const resolvedDir = resolve(options.dir);\n const service = new DiagramService(resolvedDir);\n const transport = new StdioServerTransport();\n\n // Track HTTP server instance for cleanup (only when --serve)\n let httpCleanup: (() => Promise<void>) | undefined;\n let deps: McpToolDependencies | undefined;\n\n if (options.serve) {\n const { createHttpServer } = await import('../server/server.js');\n const { detect } = await import('detect-port');\n\n const preferredPort = options.port ?? 3333;\n const actualPort = await detect(preferredPort);\n if (actualPort !== preferredPort) {\n log.warn(`Port ${preferredPort} is in use, using port ${actualPort}`);\n }\n\n // Share the SAME DiagramService between MCP and HTTP servers\n const { httpServer, wsManager, breakpointContinueSignals, sessionStore, closeAllWatchers } =\n createHttpServer(resolvedDir, service);\n\n deps = { wsManager, breakpointContinueSignals, sessionStore };\n\n await new Promise<void>((resolvePromise) => {\n httpServer.listen(actualPort, () => {\n log.info(`HTTP+WS server running at http://localhost:${actualPort}`);\n resolvePromise();\n });\n });\n\n // Register in workspace registry so other browsers can discover this instance\n await registerWorkspace(resolvedDir, actualPort).catch((err) => {\n log.warn('Failed to register workspace:', err instanceof Error ? err.message : err);\n });\n\n // Register MCP session for AI session tracking\n const mcpRegistry = new McpSessionRegistry(resolvedDir);\n await mcpRegistry.register().catch((err) => {\n log.warn('Failed to register MCP session:', err instanceof Error ? err.message : err);\n });\n deps.mcpSessionRegistry = mcpRegistry;\n\n httpCleanup = async () => {\n log.info('Shutting down HTTP+WS server...');\n await deregisterWorkspace(actualPort).catch(() => {});\n if (deps?.mcpSessionRegistry) {\n await deps.mcpSessionRegistry.deregister().catch(() => {});\n }\n await closeAllWatchers();\n wsManager.close();\n await new Promise<void>((resolveClose) => {\n httpServer.close(() => resolveClose());\n });\n };\n }\n\n const server = createMcpServer(service, deps);\n\n await server.connect(transport);\n log.info(`MCP server running on stdio (project: ${resolvedDir})`);\n\n // Graceful shutdown handler\n const shutdown = async () => {\n log.info('Shutting down MCP server...');\n if (httpCleanup) {\n await httpCleanup();\n }\n process.exit(0);\n };\n\n // Parent process disconnected from stdio\n process.stdin.on('end', shutdown);\n\n // Signal handlers\n process.on('SIGINT', shutdown);\n process.on('SIGTERM', shutdown);\n}\n","#!/usr/bin/env node\nimport { Command } from 'commander';\nimport { getVersion } from './utils/version.js';\n\nconst program = new Command();\n\nprogram\n .name('smartcode')\n .description('AI observability diagrams -- see what your AI is thinking')\n .version(getVersion());\n\nprogram\n .command('serve')\n .description('Start the diagram viewer server')\n .option('-p, --port <number>', 'port number', '3333')\n .option('-d, --dir <path>', 'project directory', '.')\n .option('--no-open', 'do not open browser automatically')\n .action(async (options: { port: string; dir: string; open: boolean }) => {\n const { startServer } = await import('./server/server.js');\n await startServer({\n port: parseInt(options.port, 10),\n dir: options.dir,\n openBrowser: options.open,\n });\n });\n\nprogram\n .command('init')\n .description('Initialize a SmartCode project')\n .option('-d, --dir <path>', 'project directory', '.')\n .option('-f, --force', 'overwrite existing config')\n .action(async (options: { dir: string; force?: boolean }) => {\n const { initProject } = await import('./cli/init.js');\n await initProject(options.dir, options.force);\n });\n\nprogram\n .command('status')\n .description('Show status of the running SmartCode server')\n .option('-p, --port <number>', 'server port to check', '3333')\n .action(async (options: { port: string }) => {\n const { showStatus } = await import('./cli/status.js');\n await showStatus(parseInt(options.port, 10));\n });\n\nprogram\n .command('mcp')\n .description('Start the MCP server for AI tool integration (stdio transport)')\n .option('-d, --dir <path>', 'project directory', '.')\n .option('-s, --serve', 'also start HTTP+WS server for browser viewing')\n .option('-p, --port <number>', 'HTTP server port (requires --serve)', '3333')\n .action(async (options: { dir: string; serve?: boolean; port: string }) => {\n const { startMcpServer } = await import('./mcp/server.js');\n await startMcpServer({\n dir: options.dir,\n serve: options.serve,\n port: parseInt(options.port, 10),\n });\n });\n\nprogram.parse();\n"],"mappings":"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","names":["open","match","fileURLToPath","join","dirname","readFile","path","mkdir","path","readFile","writeFile","readdir","mkdir","rename","unlink","join","readFile","writeFile","mkdir","rename","unlink","join","tmpdir","randomBytes","isProcessAlive","readFile","request","existsSync","path","readFile","readdir","mkdir","join","randomUUID","readFile","path","projectDir","writeFile","path","pc","DEFAULT_CONFIG","pc","server_exports","McpServer","DiagramService","createHttpServer","detect","init_server","startServer","initProject","showStatus","startMcpServer"]}
|