@dthreads/atlas
Advanced tools
| // src/version.ts | ||
| var ATLAS_VERSION = "0.4.2"; | ||
| export { | ||
| ATLAS_VERSION | ||
| }; | ||
| //# sourceMappingURL=chunk-F76HWREH.js.map |
| {"version":3,"sources":["../src/version.ts"],"sourcesContent":["export const ATLAS_VERSION = \"0.4.2\";\n"],"mappings":";AAAO,IAAM,gBAAgB;","names":[]} |
| import { | ||
| ATLAS_VERSION | ||
| } from "./chunk-F76HWREH.js"; | ||
| // src/core/types.ts | ||
| var graphNodeTypes = [ | ||
| "project", | ||
| "folder", | ||
| "file", | ||
| "package", | ||
| "module", | ||
| "controller", | ||
| "service", | ||
| "provider", | ||
| "repository", | ||
| "use_case", | ||
| "port", | ||
| "adapter", | ||
| "entity", | ||
| "dto", | ||
| "method", | ||
| "function", | ||
| "route", | ||
| "guard", | ||
| "pipe", | ||
| "interceptor", | ||
| "middleware", | ||
| "decorator", | ||
| "database", | ||
| "table", | ||
| "column", | ||
| "model", | ||
| "environment_variable", | ||
| "external_api", | ||
| "message_broker", | ||
| "message_topic", | ||
| "queue", | ||
| "processor", | ||
| "schema", | ||
| "index", | ||
| "constraint", | ||
| "migration", | ||
| "materialized_view", | ||
| "scheduled_job", | ||
| "workflow", | ||
| "pipeline_job", | ||
| "build_stage", | ||
| "container_image", | ||
| "container", | ||
| "deployment", | ||
| "infrastructure_service", | ||
| "ingress", | ||
| "config_map", | ||
| "secret", | ||
| "environment", | ||
| "config", | ||
| "test", | ||
| "library", | ||
| "risk" | ||
| ]; | ||
| var graphEdgeTypes = [ | ||
| "contains", | ||
| "imports", | ||
| "exports", | ||
| "declares", | ||
| "provides", | ||
| "injects", | ||
| "implements", | ||
| "calls", | ||
| "uses", | ||
| "reads", | ||
| "writes", | ||
| "handles", | ||
| "depends_on", | ||
| "decorates", | ||
| "validates", | ||
| "returns", | ||
| "references", | ||
| "connects_to", | ||
| "tests", | ||
| "has_method", | ||
| "has_column", | ||
| "publishes_to", | ||
| "delivers_to", | ||
| "enqueues", | ||
| "processes", | ||
| "creates", | ||
| "alters", | ||
| "drops", | ||
| "indexes", | ||
| "schedules", | ||
| "triggers", | ||
| "builds", | ||
| "publishes", | ||
| "deploys", | ||
| "exposes", | ||
| "configures", | ||
| "runs_in", | ||
| "targets" | ||
| ]; | ||
| // src/core/graph.ts | ||
| var validNodeTypes = new Set(graphNodeTypes); | ||
| var validEdgeTypes = new Set(graphEdgeTypes); | ||
| var GraphBuilder = class { | ||
| nodes = /* @__PURE__ */ new Map(); | ||
| edges = /* @__PURE__ */ new Map(); | ||
| addNode(node) { | ||
| const current = this.nodes.get(node.id); | ||
| if (!current) { | ||
| this.nodes.set(node.id, node); | ||
| return node; | ||
| } | ||
| const merged = { | ||
| ...current, | ||
| ...node, | ||
| metadata: { ...current.metadata, ...node.metadata } | ||
| }; | ||
| this.nodes.set(node.id, merged); | ||
| return merged; | ||
| } | ||
| addEdge(edge) { | ||
| if (!this.nodes.has(edge.from) || !this.nodes.has(edge.to)) return null; | ||
| const key = `${edge.from}|${edge.type}|${edge.to}|${edge.label ?? ""}`; | ||
| const id = edge.id ?? `edge:${encodeURIComponent(key)}`; | ||
| const result = { ...edge, id }; | ||
| this.edges.set(key, result); | ||
| return result; | ||
| } | ||
| hasNode(id) { | ||
| return this.nodes.has(id); | ||
| } | ||
| validate() { | ||
| const errors = []; | ||
| for (const node of this.nodes.values()) { | ||
| if (!validNodeTypes.has(String(node.type))) errors.push(`${node.id}: invalid node type ${String(node.type)}`); | ||
| } | ||
| for (const edge of this.edges.values()) { | ||
| if (!validEdgeTypes.has(String(edge.type))) errors.push(`${edge.id}: invalid edge type ${String(edge.type)}`); | ||
| if (!this.nodes.has(edge.from)) errors.push(`${edge.id}: missing source ${edge.from}`); | ||
| if (!this.nodes.has(edge.to)) errors.push(`${edge.id}: missing target ${edge.to}`); | ||
| } | ||
| return errors; | ||
| } | ||
| toGraph(project) { | ||
| const nodes = [...this.nodes.values()].sort((a, b) => a.id.localeCompare(b.id)); | ||
| const edges = [...this.edges.values()].sort((a, b) => a.id.localeCompare(b.id)); | ||
| return { version: ATLAS_VERSION, project, nodes, edges, stats: buildStats(nodes, edges) }; | ||
| } | ||
| }; | ||
| function increment(target, key) { | ||
| target[key] = (target[key] ?? 0) + 1; | ||
| } | ||
| function buildStats(nodes, edges) { | ||
| const byNodeType = /* @__PURE__ */ Object.create(null); | ||
| const byEdgeType = /* @__PURE__ */ Object.create(null); | ||
| for (const node of nodes) increment(byNodeType, node.type); | ||
| for (const edge of edges) increment(byEdgeType, edge.type); | ||
| return { totalNodes: nodes.length, totalEdges: edges.length, byNodeType, byEdgeType }; | ||
| } | ||
| var GraphQuery = class { | ||
| constructor(graph) { | ||
| this.graph = graph; | ||
| this.nodeMap = new Map(graph.nodes.map((node) => [node.id, node])); | ||
| for (const node of graph.nodes) { | ||
| const typed = this.nodesByType.get(node.type) ?? []; | ||
| typed.push(node); | ||
| this.nodesByType.set(node.type, typed); | ||
| } | ||
| for (const edge of graph.edges) { | ||
| this.edgeMap.set(edge.id, edge); | ||
| const incoming = this.incomingMap.get(edge.to) ?? []; | ||
| incoming.push(edge); | ||
| this.incomingMap.set(edge.to, incoming); | ||
| const outgoing = this.outgoingMap.get(edge.from) ?? []; | ||
| outgoing.push(edge); | ||
| this.outgoingMap.set(edge.from, outgoing); | ||
| } | ||
| } | ||
| graph; | ||
| nodeMap; | ||
| edgeMap = /* @__PURE__ */ new Map(); | ||
| incomingMap = /* @__PURE__ */ new Map(); | ||
| outgoingMap = /* @__PURE__ */ new Map(); | ||
| nodesByType = /* @__PURE__ */ new Map(); | ||
| findNode(query) { | ||
| const needle = query.trim().toLowerCase(); | ||
| if (!needle) return []; | ||
| return this.graph.nodes.filter((node) => searchableNode(node).includes(needle)).sort((a, b) => scoreNode(b, needle) - scoreNode(a, needle)).slice(0, 100); | ||
| } | ||
| search(query) { | ||
| const needle = query.trim().toLowerCase(); | ||
| if (!needle) return []; | ||
| return this.findNode(query).map((node) => ({ | ||
| node, | ||
| score: scoreNode(node, needle), | ||
| matches: matchingFields(node, needle) | ||
| })); | ||
| } | ||
| getNode(id) { | ||
| return this.nodeMap.get(id) ?? null; | ||
| } | ||
| getIncoming(id) { | ||
| return this.incomingMap.get(id) ?? []; | ||
| } | ||
| getOutgoing(id) { | ||
| return this.outgoingMap.get(id) ?? []; | ||
| } | ||
| findRoutes() { | ||
| return this.byType("route"); | ||
| } | ||
| findServices() { | ||
| return this.byType("service"); | ||
| } | ||
| findControllers() { | ||
| return this.byType("controller"); | ||
| } | ||
| findTables() { | ||
| return this.byType("table"); | ||
| } | ||
| findSchemas() { | ||
| return this.byType("schema"); | ||
| } | ||
| findIndexes() { | ||
| return this.byType("index"); | ||
| } | ||
| findConstraints() { | ||
| return this.byType("constraint"); | ||
| } | ||
| findMigrations() { | ||
| return this.byType("migration"); | ||
| } | ||
| findScheduledJobs() { | ||
| return this.byType("scheduled_job"); | ||
| } | ||
| findWorkflows() { | ||
| return this.byType("workflow"); | ||
| } | ||
| findDeployments() { | ||
| return this.byType("deployment"); | ||
| } | ||
| findEnvironments() { | ||
| return this.byType("environment"); | ||
| } | ||
| findExternalApis() { | ||
| return this.byType("external_api"); | ||
| } | ||
| findMessageTopics() { | ||
| return this.byType("message_topic"); | ||
| } | ||
| findQueues() { | ||
| return this.byType("queue"); | ||
| } | ||
| findProcessors() { | ||
| return this.byType("processor"); | ||
| } | ||
| findTableProfile(tableId) { | ||
| const table = this.nodeMap.get(tableId); | ||
| if (!table || table.type !== "table") return { nodes: [], edges: [] }; | ||
| const edgeTypes = /* @__PURE__ */ new Set(["has_column", "indexes", "contains", "references", "reads", "writes", "creates", "alters", "drops"]); | ||
| const edges = [...this.getIncoming(tableId), ...this.getOutgoing(tableId)].filter((edge) => edgeTypes.has(edge.type)); | ||
| const ids = /* @__PURE__ */ new Set([tableId, ...edges.flatMap((edge) => [edge.from, edge.to])]); | ||
| return { nodes: [...ids].map((id) => this.nodeMap.get(id)).filter(Boolean), edges }; | ||
| } | ||
| getNeighbors(nodeId, depth = 1) { | ||
| if (!this.nodeMap.has(nodeId)) return { nodes: [], edges: [] }; | ||
| const nodeIds = /* @__PURE__ */ new Set([nodeId]); | ||
| const edgeIds = /* @__PURE__ */ new Set(); | ||
| let frontier = [nodeId]; | ||
| for (let level = 0; level < Math.max(0, depth) && frontier.length; level += 1) { | ||
| const next = []; | ||
| for (const id of frontier) { | ||
| for (const edge of [...this.getIncoming(id), ...this.getOutgoing(id)]) { | ||
| edgeIds.add(edge.id); | ||
| const neighbor = edge.from === id ? edge.to : edge.from; | ||
| if (!nodeIds.has(neighbor)) { | ||
| nodeIds.add(neighbor); | ||
| next.push(neighbor); | ||
| } | ||
| } | ||
| } | ||
| frontier = next; | ||
| } | ||
| return { | ||
| nodes: [...nodeIds].map((id) => this.nodeMap.get(id)).filter(Boolean), | ||
| edges: [...edgeIds].map((id) => this.edgeMap.get(id)).filter(Boolean) | ||
| }; | ||
| } | ||
| findFlowFromRoute(routeId) { | ||
| return this.walk(routeId, "outgoing", 12, /* @__PURE__ */ new Set([ | ||
| "handles", | ||
| "calls", | ||
| "reads", | ||
| "writes", | ||
| "uses", | ||
| "connects_to", | ||
| "validates", | ||
| "returns", | ||
| "publishes_to", | ||
| "delivers_to", | ||
| "enqueues", | ||
| "processes" | ||
| ])); | ||
| } | ||
| findAsyncFlow(rootId) { | ||
| const root = this.nodeMap.get(rootId); | ||
| if (!root || !["message_topic", "queue"].includes(root.type)) return { nodes: [], edges: [] }; | ||
| const flow = this.walk(rootId, "outgoing", 12, /* @__PURE__ */ new Set([ | ||
| "delivers_to", | ||
| "calls", | ||
| "reads", | ||
| "writes", | ||
| "uses", | ||
| "connects_to", | ||
| "publishes_to", | ||
| "enqueues", | ||
| "processes" | ||
| ])); | ||
| const nodeIds = new Set(flow.nodes.map((node) => node.id)); | ||
| const edgeIds = new Set(flow.edges.map((edge) => edge.id)); | ||
| for (const edge of this.getIncoming(rootId).filter((item) => ["publishes_to", "enqueues"].includes(item.type))) { | ||
| nodeIds.add(edge.from); | ||
| edgeIds.add(edge.id); | ||
| } | ||
| return { | ||
| nodes: [...nodeIds].map((id) => this.nodeMap.get(id)).filter(Boolean), | ||
| edges: [...edgeIds].map((id) => this.edgeMap.get(id)).filter(Boolean) | ||
| }; | ||
| } | ||
| findDependencies(nodeId, depth = 2) { | ||
| return this.walk(nodeId, "outgoing", depth); | ||
| } | ||
| findDependents(nodeId, depth = 2) { | ||
| return this.walk(nodeId, "incoming", depth); | ||
| } | ||
| findPath(fromId, toId, direction = "outgoing", maxDepth = 20) { | ||
| if (!this.nodeMap.has(fromId) || !this.nodeMap.has(toId)) return { nodes: [], edges: [] }; | ||
| if (fromId === toId) return { nodes: [this.nodeMap.get(fromId)], edges: [] }; | ||
| const queue = [{ id: fromId, depth: 0 }]; | ||
| const visited = /* @__PURE__ */ new Set([fromId]); | ||
| const previous = /* @__PURE__ */ new Map(); | ||
| let cursor = 0; | ||
| while (cursor < queue.length) { | ||
| const current = queue[cursor++]; | ||
| if (current.depth >= Math.max(1, maxDepth)) continue; | ||
| const candidates = [ | ||
| ...this.getOutgoing(current.id).map((edge) => ({ edge, next: edge.to })), | ||
| ...direction === "both" ? this.getIncoming(current.id).map((edge) => ({ edge, next: edge.from })) : [] | ||
| ].sort((a, b) => pathEdgePriority(a.edge) - pathEdgePriority(b.edge) || a.edge.id.localeCompare(b.edge.id)); | ||
| for (const candidate of candidates) { | ||
| if (visited.has(candidate.next)) continue; | ||
| visited.add(candidate.next); | ||
| previous.set(candidate.next, { nodeId: current.id, edge: candidate.edge }); | ||
| if (candidate.next === toId) return this.reconstructPath(fromId, toId, previous); | ||
| queue.push({ id: candidate.next, depth: current.depth + 1 }); | ||
| } | ||
| } | ||
| return { nodes: [], edges: [] }; | ||
| } | ||
| byType(type) { | ||
| return this.nodesByType.get(type) ?? []; | ||
| } | ||
| reconstructPath(fromId, toId, previous) { | ||
| const nodeIds = [toId]; | ||
| const edges = []; | ||
| let current = toId; | ||
| while (current !== fromId) { | ||
| const step = previous.get(current); | ||
| if (!step) return { nodes: [], edges: [] }; | ||
| nodeIds.push(step.nodeId); | ||
| edges.push(step.edge); | ||
| current = step.nodeId; | ||
| } | ||
| nodeIds.reverse(); | ||
| edges.reverse(); | ||
| return { nodes: nodeIds.map((id) => this.nodeMap.get(id)), edges }; | ||
| } | ||
| walk(startId, direction, depth, allowedTypes) { | ||
| if (!this.nodeMap.has(startId)) return { nodes: [], edges: [] }; | ||
| const nodeIds = /* @__PURE__ */ new Set([startId]); | ||
| const edgeIds = /* @__PURE__ */ new Set(); | ||
| let frontier = [startId]; | ||
| for (let level = 0; level < Math.max(0, depth) && frontier.length; level += 1) { | ||
| const next = []; | ||
| for (const id of frontier) { | ||
| const edges = direction === "outgoing" ? this.getOutgoing(id) : this.getIncoming(id); | ||
| for (const edge of edges) { | ||
| if (allowedTypes && !allowedTypes.has(edge.type)) continue; | ||
| edgeIds.add(edge.id); | ||
| const neighbor = direction === "outgoing" ? edge.to : edge.from; | ||
| if (!nodeIds.has(neighbor)) { | ||
| nodeIds.add(neighbor); | ||
| next.push(neighbor); | ||
| } | ||
| } | ||
| } | ||
| frontier = next; | ||
| } | ||
| return { | ||
| nodes: [...nodeIds].map((id) => this.nodeMap.get(id)).filter(Boolean), | ||
| edges: [...edgeIds].map((id) => this.edgeMap.get(id)).filter(Boolean) | ||
| }; | ||
| } | ||
| }; | ||
| function pathEdgePriority(edge) { | ||
| if (["handles", "calls", "reads", "writes", "publishes_to", "delivers_to", "enqueues", "processes", "targets", "exposes", "deploys"].includes(edge.type)) return 0; | ||
| if (["injects", "implements", "uses", "connects_to", "configures", "builds", "publishes", "triggers", "schedules"].includes(edge.type)) return 1; | ||
| if (["depends_on", "references", "imports", "exports", "provides"].includes(edge.type)) return 2; | ||
| return 3; | ||
| } | ||
| function searchableNode(node) { | ||
| return [node.id, node.type, node.label, node.name, node.file, JSON.stringify(node.metadata ?? {})].filter(Boolean).join(" ").toLowerCase(); | ||
| } | ||
| function scoreNode(node, needle) { | ||
| const label = node.label.toLowerCase(); | ||
| if (label === needle) return 100; | ||
| if (label.startsWith(needle)) return 80; | ||
| if (node.id.toLowerCase().includes(needle)) return 60; | ||
| return 20; | ||
| } | ||
| function matchingFields(node, needle) { | ||
| const fields = { | ||
| id: node.id, | ||
| label: node.label, | ||
| name: node.name ?? "", | ||
| type: node.type, | ||
| file: node.file ?? "", | ||
| metadata: JSON.stringify(node.metadata ?? {}) | ||
| }; | ||
| return Object.entries(fields).filter(([, value]) => value.toLowerCase().includes(needle)).map(([key]) => key); | ||
| } | ||
| export { | ||
| graphNodeTypes, | ||
| graphEdgeTypes, | ||
| GraphBuilder, | ||
| buildStats, | ||
| GraphQuery | ||
| }; | ||
| //# sourceMappingURL=chunk-W7ACPOFP.js.map |
| {"version":3,"sources":["../src/core/types.ts","../src/core/graph.ts"],"sourcesContent":["export const graphNodeTypes = [\n \"project\", \"folder\", \"file\", \"package\", \"module\", \"controller\", \"service\",\n \"provider\", \"repository\", \"use_case\", \"port\", \"adapter\", \"entity\", \"dto\", \"method\", \"function\", \"route\",\n \"guard\", \"pipe\", \"interceptor\", \"middleware\", \"decorator\", \"database\",\n \"table\", \"column\", \"model\", \"environment_variable\", \"external_api\",\n \"message_broker\", \"message_topic\", \"queue\", \"processor\",\n \"schema\", \"index\", \"constraint\", \"migration\", \"materialized_view\",\n \"scheduled_job\", \"workflow\", \"pipeline_job\", \"build_stage\", \"container_image\",\n \"container\", \"deployment\", \"infrastructure_service\", \"ingress\", \"config_map\",\n \"secret\", \"environment\", \"config\", \"test\", \"library\", \"risk\",\n] as const;\n\nexport const graphEdgeTypes = [\n \"contains\", \"imports\", \"exports\", \"declares\", \"provides\", \"injects\", \"implements\", \"calls\",\n \"uses\", \"reads\", \"writes\", \"handles\", \"depends_on\", \"decorates\", \"validates\",\n \"returns\", \"references\", \"connects_to\", \"tests\", \"has_method\", \"has_column\",\n \"publishes_to\", \"delivers_to\", \"enqueues\", \"processes\",\n \"creates\", \"alters\", \"drops\", \"indexes\", \"schedules\", \"triggers\", \"builds\",\n \"publishes\", \"deploys\", \"exposes\", \"configures\", \"runs_in\", \"targets\",\n] as const;\n\nexport type GraphNodeType = (typeof graphNodeTypes)[number];\nexport type GraphEdgeType = (typeof graphEdgeTypes)[number];\nexport type GraphSourceType =\n | \"static_analysis\"\n | \"ast\"\n | \"config\"\n | \"package_json\"\n | \"heuristic\"\n | \"runtime\"\n | \"manual\";\n\nexport interface SourceLocation {\n file: string;\n startLine?: number;\n endLine?: number;\n}\n\nexport interface GraphNode {\n id: string;\n type: GraphNodeType;\n label: string;\n name?: string;\n file?: string;\n language?: string;\n framework?: string;\n sourceLocation?: SourceLocation;\n confidence?: number;\n source?: GraphSourceType;\n metadata?: Record<string, unknown>;\n}\n\nexport interface GraphEdge {\n id: string;\n from: string;\n to: string;\n type: GraphEdgeType;\n label?: string;\n confidence?: number;\n source?: GraphSourceType;\n metadata?: Record<string, unknown>;\n}\n\nexport interface DetectedStack {\n name: string;\n confidence: number;\n evidence: string[];\n}\n\nexport interface GraphStats {\n totalNodes: number;\n totalEdges: number;\n byNodeType: Partial<Record<GraphNodeType, number>>;\n byEdgeType: Partial<Record<GraphEdgeType, number>>;\n}\n\nexport interface ArchitectureGraph {\n version: string;\n project: {\n name: string;\n root: string;\n detectedStacks: string[];\n createdAt: string;\n };\n nodes: GraphNode[];\n edges: GraphEdge[];\n stats: GraphStats;\n}\n\nexport interface ScannedFile {\n absolutePath: string;\n path: string;\n extension: string;\n size: number;\n hash?: string;\n lastModified: string;\n}\n\nexport interface ScanMetadata {\n version: string;\n projectName: string;\n projectRoot: string;\n scanStartedAt: string;\n scanFinishedAt: string;\n durationMs: number;\n filesScanned: number;\n filesIgnored: number;\n filesHashed?: number;\n filesReused?: number;\n cacheHit?: boolean;\n inputFingerprint?: string;\n analysisCacheVersion?: number;\n viewerFingerprint?: string;\n runtimeEvents?: number;\n runtimeMergedAt?: string;\n runtimeFingerprint?: string;\n detectedStacks: DetectedStack[];\n}\n\nexport type RiskSeverity = \"low\" | \"medium\" | \"high\" | \"critical\";\n\nexport interface ArchitectureRisk {\n id: string;\n type: string;\n severity: RiskSeverity;\n title: string;\n description: string;\n recommendation: string;\n nodeId?: string;\n file?: string;\n metadata?: Record<string, unknown>;\n}\n\nexport interface GraphSubgraph {\n nodes: GraphNode[];\n edges: GraphEdge[];\n}\n\nexport interface GraphSearchResult {\n node: GraphNode;\n score: number;\n matches: string[];\n}\n\nexport type ScanProgressStage =\n | \"scan_files\"\n | \"detect_stack\"\n | \"parse_architecture\"\n | \"build_graph\"\n | \"detect_risks\"\n | \"write_outputs\";\n\nexport interface ScanProgress {\n stage: ScanProgressStage;\n message: string;\n}\n\nexport interface ScanOptions {\n projectPath: string;\n outputPath?: string;\n incremental?: boolean;\n debug?: boolean;\n onProgress?: (progress: ScanProgress) => void;\n}\n\nexport interface ScanResult {\n graph: ArchitectureGraph;\n metadata: ScanMetadata;\n risks: ArchitectureRisk[];\n outputPath: string;\n}\n\nexport interface RuntimeTraceNode {\n id: string;\n type: GraphNodeType;\n label?: string;\n file?: string;\n}\n\nexport interface RuntimeTraceEvent {\n from: string;\n to: string;\n type: GraphEdgeType;\n timestamp?: string;\n count?: number;\n durationMs?: number;\n fromNode?: RuntimeTraceNode;\n toNode?: RuntimeTraceNode;\n metadata?: Record<string, unknown>;\n}\n","import type {\n ArchitectureGraph,\n GraphEdge,\n GraphEdgeType,\n GraphNode,\n GraphSearchResult,\n GraphStats,\n GraphSubgraph,\n} from \"./types.js\";\nimport { graphEdgeTypes, graphNodeTypes } from \"./types.js\";\nimport { ATLAS_VERSION } from \"../version.js\";\n\nconst validNodeTypes = new Set<string>(graphNodeTypes);\nconst validEdgeTypes = new Set<string>(graphEdgeTypes);\n\nexport class GraphBuilder {\n readonly nodes = new Map<string, GraphNode>();\n readonly edges = new Map<string, GraphEdge>();\n\n addNode(node: GraphNode): GraphNode {\n const current = this.nodes.get(node.id);\n if (!current) {\n this.nodes.set(node.id, node);\n return node;\n }\n const merged = {\n ...current,\n ...node,\n metadata: { ...current.metadata, ...node.metadata },\n };\n this.nodes.set(node.id, merged);\n return merged;\n }\n\n addEdge(edge: Omit<GraphEdge, \"id\"> & { id?: string }): GraphEdge | null {\n if (!this.nodes.has(edge.from) || !this.nodes.has(edge.to)) return null;\n const key = `${edge.from}|${edge.type}|${edge.to}|${edge.label ?? \"\"}`;\n const id = edge.id ?? `edge:${encodeURIComponent(key)}`;\n const result: GraphEdge = { ...edge, id };\n this.edges.set(key, result);\n return result;\n }\n\n hasNode(id: string): boolean {\n return this.nodes.has(id);\n }\n\n validate(): string[] {\n const errors: string[] = [];\n for (const node of this.nodes.values()) {\n if (!validNodeTypes.has(String(node.type))) errors.push(`${node.id}: invalid node type ${String(node.type)}`);\n }\n for (const edge of this.edges.values()) {\n if (!validEdgeTypes.has(String(edge.type))) errors.push(`${edge.id}: invalid edge type ${String(edge.type)}`);\n if (!this.nodes.has(edge.from)) errors.push(`${edge.id}: missing source ${edge.from}`);\n if (!this.nodes.has(edge.to)) errors.push(`${edge.id}: missing target ${edge.to}`);\n }\n return errors;\n }\n\n toGraph(project: ArchitectureGraph[\"project\"]): ArchitectureGraph {\n const nodes = [...this.nodes.values()].sort((a, b) => a.id.localeCompare(b.id));\n const edges = [...this.edges.values()].sort((a, b) => a.id.localeCompare(b.id));\n return { version: ATLAS_VERSION, project, nodes, edges, stats: buildStats(nodes, edges) };\n }\n}\n\nfunction increment<T extends string>(target: Partial<Record<T, number>>, key: T) {\n target[key] = (target[key] ?? 0) + 1;\n}\n\nexport function buildStats(nodes: GraphNode[], edges: GraphEdge[]): GraphStats {\n const byNodeType: GraphStats[\"byNodeType\"] = Object.create(null) as GraphStats[\"byNodeType\"];\n const byEdgeType: GraphStats[\"byEdgeType\"] = Object.create(null) as GraphStats[\"byEdgeType\"];\n for (const node of nodes) increment(byNodeType, node.type);\n for (const edge of edges) increment(byEdgeType, edge.type);\n return { totalNodes: nodes.length, totalEdges: edges.length, byNodeType, byEdgeType };\n}\n\nexport class GraphQuery {\n private readonly nodeMap: Map<string, GraphNode>;\n private readonly edgeMap = new Map<string, GraphEdge>();\n private readonly incomingMap = new Map<string, GraphEdge[]>();\n private readonly outgoingMap = new Map<string, GraphEdge[]>();\n private readonly nodesByType = new Map<GraphNode[\"type\"], GraphNode[]>();\n\n constructor(readonly graph: ArchitectureGraph) {\n this.nodeMap = new Map(graph.nodes.map((node) => [node.id, node]));\n for (const node of graph.nodes) {\n const typed = this.nodesByType.get(node.type) ?? [];\n typed.push(node);\n this.nodesByType.set(node.type, typed);\n }\n for (const edge of graph.edges) {\n this.edgeMap.set(edge.id, edge);\n const incoming = this.incomingMap.get(edge.to) ?? [];\n incoming.push(edge);\n this.incomingMap.set(edge.to, incoming);\n const outgoing = this.outgoingMap.get(edge.from) ?? [];\n outgoing.push(edge);\n this.outgoingMap.set(edge.from, outgoing);\n }\n }\n\n findNode(query: string): GraphNode[] {\n const needle = query.trim().toLowerCase();\n if (!needle) return [];\n return this.graph.nodes\n .filter((node) => searchableNode(node).includes(needle))\n .sort((a, b) => scoreNode(b, needle) - scoreNode(a, needle))\n .slice(0, 100);\n }\n\n search(query: string): GraphSearchResult[] {\n const needle = query.trim().toLowerCase();\n if (!needle) return [];\n return this.findNode(query).map((node) => ({\n node,\n score: scoreNode(node, needle),\n matches: matchingFields(node, needle),\n }));\n }\n\n getNode(id: string): GraphNode | null {\n return this.nodeMap.get(id) ?? null;\n }\n\n getIncoming(id: string): GraphEdge[] {\n return this.incomingMap.get(id) ?? [];\n }\n\n getOutgoing(id: string): GraphEdge[] {\n return this.outgoingMap.get(id) ?? [];\n }\n\n findRoutes(): GraphNode[] { return this.byType(\"route\"); }\n findServices(): GraphNode[] { return this.byType(\"service\"); }\n findControllers(): GraphNode[] { return this.byType(\"controller\"); }\n findTables(): GraphNode[] { return this.byType(\"table\"); }\n findSchemas(): GraphNode[] { return this.byType(\"schema\"); }\n findIndexes(): GraphNode[] { return this.byType(\"index\"); }\n findConstraints(): GraphNode[] { return this.byType(\"constraint\"); }\n findMigrations(): GraphNode[] { return this.byType(\"migration\"); }\n findScheduledJobs(): GraphNode[] { return this.byType(\"scheduled_job\"); }\n findWorkflows(): GraphNode[] { return this.byType(\"workflow\"); }\n findDeployments(): GraphNode[] { return this.byType(\"deployment\"); }\n findEnvironments(): GraphNode[] { return this.byType(\"environment\"); }\n findExternalApis(): GraphNode[] { return this.byType(\"external_api\"); }\n findMessageTopics(): GraphNode[] { return this.byType(\"message_topic\"); }\n findQueues(): GraphNode[] { return this.byType(\"queue\"); }\n findProcessors(): GraphNode[] { return this.byType(\"processor\"); }\n\n findTableProfile(tableId: string): GraphSubgraph {\n const table = this.nodeMap.get(tableId);\n if (!table || table.type !== \"table\") return { nodes: [], edges: [] };\n const edgeTypes = new Set<GraphEdgeType>([\"has_column\", \"indexes\", \"contains\", \"references\", \"reads\", \"writes\", \"creates\", \"alters\", \"drops\"]);\n const edges = [...this.getIncoming(tableId), ...this.getOutgoing(tableId)]\n .filter((edge) => edgeTypes.has(edge.type));\n const ids = new Set([tableId, ...edges.flatMap((edge) => [edge.from, edge.to])]);\n return { nodes: [...ids].map((id) => this.nodeMap.get(id)).filter(Boolean) as GraphNode[], edges };\n }\n\n getNeighbors(nodeId: string, depth = 1): GraphSubgraph {\n if (!this.nodeMap.has(nodeId)) return { nodes: [], edges: [] };\n const nodeIds = new Set([nodeId]);\n const edgeIds = new Set<string>();\n let frontier = [nodeId];\n for (let level = 0; level < Math.max(0, depth) && frontier.length; level += 1) {\n const next: string[] = [];\n for (const id of frontier) {\n for (const edge of [...this.getIncoming(id), ...this.getOutgoing(id)]) {\n edgeIds.add(edge.id);\n const neighbor = edge.from === id ? edge.to : edge.from;\n if (!nodeIds.has(neighbor)) { nodeIds.add(neighbor); next.push(neighbor); }\n }\n }\n frontier = next;\n }\n return {\n nodes: [...nodeIds].map((id) => this.nodeMap.get(id)).filter(Boolean) as GraphNode[],\n edges: [...edgeIds].map((id) => this.edgeMap.get(id)).filter(Boolean) as GraphEdge[],\n };\n }\n\n findFlowFromRoute(routeId: string): GraphSubgraph {\n return this.walk(routeId, \"outgoing\", 12, new Set([\n \"handles\", \"calls\", \"reads\", \"writes\", \"uses\", \"connects_to\", \"validates\", \"returns\",\n \"publishes_to\", \"delivers_to\", \"enqueues\", \"processes\",\n ]));\n }\n\n findAsyncFlow(rootId: string): GraphSubgraph {\n const root = this.nodeMap.get(rootId);\n if (!root || ![\"message_topic\", \"queue\"].includes(root.type)) return { nodes: [], edges: [] };\n const flow = this.walk(rootId, \"outgoing\", 12, new Set([\n \"delivers_to\", \"calls\", \"reads\", \"writes\", \"uses\", \"connects_to\", \"publishes_to\", \"enqueues\", \"processes\",\n ]));\n const nodeIds = new Set(flow.nodes.map((node) => node.id));\n const edgeIds = new Set(flow.edges.map((edge) => edge.id));\n for (const edge of this.getIncoming(rootId).filter((item) => [\"publishes_to\", \"enqueues\"].includes(item.type))) {\n nodeIds.add(edge.from);\n edgeIds.add(edge.id);\n }\n return {\n nodes: [...nodeIds].map((id) => this.nodeMap.get(id)).filter(Boolean) as GraphNode[],\n edges: [...edgeIds].map((id) => this.edgeMap.get(id)).filter(Boolean) as GraphEdge[],\n };\n }\n\n findDependencies(nodeId: string, depth = 2): GraphSubgraph {\n return this.walk(nodeId, \"outgoing\", depth);\n }\n\n findDependents(nodeId: string, depth = 2): GraphSubgraph {\n return this.walk(nodeId, \"incoming\", depth);\n }\n\n findPath(\n fromId: string,\n toId: string,\n direction: \"outgoing\" | \"both\" = \"outgoing\",\n maxDepth = 20,\n ): GraphSubgraph {\n if (!this.nodeMap.has(fromId) || !this.nodeMap.has(toId)) return { nodes: [], edges: [] };\n if (fromId === toId) return { nodes: [this.nodeMap.get(fromId)!], edges: [] };\n const queue: Array<{ id: string; depth: number }> = [{ id: fromId, depth: 0 }];\n const visited = new Set([fromId]);\n const previous = new Map<string, { nodeId: string; edge: GraphEdge }>();\n let cursor = 0;\n while (cursor < queue.length) {\n const current = queue[cursor++];\n if (current.depth >= Math.max(1, maxDepth)) continue;\n const candidates = [\n ...this.getOutgoing(current.id).map((edge) => ({ edge, next: edge.to })),\n ...(direction === \"both\" ? this.getIncoming(current.id).map((edge) => ({ edge, next: edge.from })) : []),\n ].sort((a, b) => pathEdgePriority(a.edge) - pathEdgePriority(b.edge) || a.edge.id.localeCompare(b.edge.id));\n for (const candidate of candidates) {\n if (visited.has(candidate.next)) continue;\n visited.add(candidate.next);\n previous.set(candidate.next, { nodeId: current.id, edge: candidate.edge });\n if (candidate.next === toId) return this.reconstructPath(fromId, toId, previous);\n queue.push({ id: candidate.next, depth: current.depth + 1 });\n }\n }\n return { nodes: [], edges: [] };\n }\n\n private byType(type: GraphNode[\"type\"]): GraphNode[] {\n return this.nodesByType.get(type) ?? [];\n }\n\n private reconstructPath(fromId: string, toId: string, previous: Map<string, { nodeId: string; edge: GraphEdge }>): GraphSubgraph {\n const nodeIds = [toId];\n const edges: GraphEdge[] = [];\n let current = toId;\n while (current !== fromId) {\n const step = previous.get(current);\n if (!step) return { nodes: [], edges: [] };\n nodeIds.push(step.nodeId);\n edges.push(step.edge);\n current = step.nodeId;\n }\n nodeIds.reverse();\n edges.reverse();\n return { nodes: nodeIds.map((id) => this.nodeMap.get(id)!), edges };\n }\n\n private walk(\n startId: string,\n direction: \"incoming\" | \"outgoing\",\n depth: number,\n allowedTypes?: Set<GraphEdgeType>,\n ): GraphSubgraph {\n if (!this.nodeMap.has(startId)) return { nodes: [], edges: [] };\n const nodeIds = new Set([startId]);\n const edgeIds = new Set<string>();\n let frontier = [startId];\n for (let level = 0; level < Math.max(0, depth) && frontier.length; level += 1) {\n const next: string[] = [];\n for (const id of frontier) {\n const edges = direction === \"outgoing\" ? this.getOutgoing(id) : this.getIncoming(id);\n for (const edge of edges) {\n if (allowedTypes && !allowedTypes.has(edge.type)) continue;\n edgeIds.add(edge.id);\n const neighbor = direction === \"outgoing\" ? edge.to : edge.from;\n if (!nodeIds.has(neighbor)) {\n nodeIds.add(neighbor);\n next.push(neighbor);\n }\n }\n }\n frontier = next;\n }\n return {\n nodes: [...nodeIds].map((id) => this.nodeMap.get(id)).filter(Boolean) as GraphNode[],\n edges: [...edgeIds].map((id) => this.edgeMap.get(id)).filter(Boolean) as GraphEdge[],\n };\n }\n}\n\nfunction pathEdgePriority(edge: GraphEdge): number {\n if ([\"handles\", \"calls\", \"reads\", \"writes\", \"publishes_to\", \"delivers_to\", \"enqueues\", \"processes\", \"targets\", \"exposes\", \"deploys\"].includes(edge.type)) return 0;\n if ([\"injects\", \"implements\", \"uses\", \"connects_to\", \"configures\", \"builds\", \"publishes\", \"triggers\", \"schedules\"].includes(edge.type)) return 1;\n if ([\"depends_on\", \"references\", \"imports\", \"exports\", \"provides\"].includes(edge.type)) return 2;\n return 3;\n}\n\nfunction searchableNode(node: GraphNode): string {\n return [node.id, node.type, node.label, node.name, node.file, JSON.stringify(node.metadata ?? {})]\n .filter(Boolean)\n .join(\" \")\n .toLowerCase();\n}\n\nfunction scoreNode(node: GraphNode, needle: string): number {\n const label = node.label.toLowerCase();\n if (label === needle) return 100;\n if (label.startsWith(needle)) return 80;\n if (node.id.toLowerCase().includes(needle)) return 60;\n return 20;\n}\n\nfunction matchingFields(node: GraphNode, needle: string): string[] {\n const fields = {\n id: node.id,\n label: node.label,\n name: node.name ?? \"\",\n type: node.type,\n file: node.file ?? \"\",\n metadata: JSON.stringify(node.metadata ?? {}),\n };\n return Object.entries(fields).filter(([, value]) => value.toLowerCase().includes(needle)).map(([key]) => key);\n}\n"],"mappings":"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","names":[]} |
| import { | ||
| GraphQuery | ||
| } from "./chunk-W7ACPOFP.js"; | ||
| import "./chunk-F76HWREH.js"; | ||
| // src/mcp/server.ts | ||
| import { readFile } from "fs/promises"; | ||
| import { resolve } from "path"; | ||
| import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; | ||
| import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; | ||
| import * as z from "zod/v4"; | ||
| async function startMcpServer(projectPath, outputPath = ".atlas") { | ||
| const graphPath = resolve(projectPath, outputPath, "graph.json"); | ||
| const graph = JSON.parse(await readFile(graphPath, "utf8")); | ||
| const query = new GraphQuery(graph); | ||
| const server = new McpServer({ name: "atlas", version: graph.version }); | ||
| const result = (data) => ({ | ||
| content: [{ type: "text", text: JSON.stringify(data, null, 2) }], | ||
| structuredContent: data | ||
| }); | ||
| server.registerTool("atlas_find_node", { | ||
| description: "Find architecture nodes by name, label, type, file, route, or metadata.", | ||
| inputSchema: { query: z.string().min(1) } | ||
| }, async ({ query: value }) => result({ results: query.findNode(value) })); | ||
| server.registerTool("atlas_get_node", { | ||
| description: "Get one node and its incoming, outgoing, and method relationships.", | ||
| inputSchema: { id: z.string().min(1) } | ||
| }, async ({ id }) => { | ||
| const node = query.getNode(id); | ||
| const outgoing = query.getOutgoing(id); | ||
| const methods = outgoing.filter((edge) => edge.type === "has_method").map((edge) => query.getNode(edge.to)).filter(Boolean); | ||
| return result({ node, incoming: query.getIncoming(id), outgoing, methods }); | ||
| }); | ||
| server.registerTool("atlas_get_dependencies", { | ||
| description: "Traverse outgoing architecture dependencies from a node.", | ||
| inputSchema: { id: z.string().min(1), depth: z.number().int().min(1).max(10).default(2) } | ||
| }, async ({ id, depth }) => result({ graph: query.findDependencies(id, depth) })); | ||
| server.registerTool("atlas_get_dependents", { | ||
| description: "Traverse incoming architecture dependents of a node.", | ||
| inputSchema: { id: z.string().min(1), depth: z.number().int().min(1).max(10).default(2) } | ||
| }, async ({ id, depth }) => result({ graph: query.findDependents(id, depth) })); | ||
| server.registerTool("atlas_find_path", { | ||
| description: "Find the shortest explainable architecture path between two exact node IDs.", | ||
| inputSchema: { | ||
| from: z.string().min(1), | ||
| to: z.string().min(1), | ||
| direction: z.enum(["outgoing", "both"]).default("outgoing"), | ||
| maxDepth: z.number().int().min(1).max(50).default(20) | ||
| } | ||
| }, async ({ from, to, direction, maxDepth }) => result({ | ||
| from: query.getNode(from), | ||
| to: query.getNode(to), | ||
| path: query.findPath(from, to, direction, maxDepth) | ||
| })); | ||
| server.registerTool("atlas_find_routes", { description: "List all detected HTTP routes." }, async () => result({ routes: query.findRoutes() })); | ||
| server.registerTool("atlas_find_flow", { | ||
| description: "Find a route and return its route-to-controller-to-service-to-data flow.", | ||
| inputSchema: { query: z.string().min(1) } | ||
| }, async ({ query: value }) => { | ||
| const route = query.findNode(value).find((node) => node.type === "route"); | ||
| return result({ route: route ?? null, flow: route ? query.findFlowFromRoute(route.id) : { nodes: [], edges: [] } }); | ||
| }); | ||
| server.registerTool("atlas_find_tables", { description: "List detected database tables." }, async () => result({ tables: query.findTables() })); | ||
| server.registerTool("atlas_find_data_model", { description: "List schemas, tables, indexes, constraints, migrations, and ClickHouse structures." }, async () => result({ | ||
| schemas: query.findSchemas(), | ||
| tables: query.findTables(), | ||
| indexes: query.findIndexes(), | ||
| constraints: query.findConstraints(), | ||
| migrations: query.findMigrations() | ||
| })); | ||
| server.registerTool("atlas_get_table_profile", { | ||
| description: "Return a table with its columns, indexes, constraints, relations, migrations, readers, and writers.", | ||
| inputSchema: { query: z.string().min(1) } | ||
| }, async ({ query: value }) => { | ||
| const table = query.findNode(value).find((node) => node.type === "table"); | ||
| return result({ table: table ?? null, profile: table ? query.findTableProfile(table.id) : { nodes: [], edges: [] } }); | ||
| }); | ||
| server.registerTool("atlas_find_migrations", { description: "List migrations and the structures they create, alter, or drop." }, async () => result({ migrations: query.findMigrations() })); | ||
| server.registerTool("atlas_find_external_apis", { description: "List detected external API hosts." }, async () => result({ externalApis: query.findExternalApis() })); | ||
| server.registerTool("atlas_find_async_flows", { | ||
| description: "List detected Kafka or RabbitMQ topics, Bull/BullMQ queues, and background processors." | ||
| }, async () => result({ topics: query.findMessageTopics(), queues: query.findQueues(), processors: query.findProcessors() })); | ||
| server.registerTool("atlas_find_async_flow", { | ||
| description: "Find a message topic or queue and return publishers, consumers, processors, and downstream calls.", | ||
| inputSchema: { query: z.string().min(1) } | ||
| }, async ({ query: value }) => { | ||
| const root = query.findNode(value).find((node) => ["message_topic", "queue"].includes(node.type)); | ||
| return result({ root: root ?? null, flow: root ? query.findAsyncFlow(root.id) : { nodes: [], edges: [] } }); | ||
| }); | ||
| server.registerTool("atlas_find_schedules", { description: "List cron, interval, timeout, repeatable queue, and Kubernetes scheduled jobs." }, async () => result({ schedules: query.findScheduledJobs() })); | ||
| server.registerTool("atlas_find_delivery", { description: "List CI/CD workflows and runtime deployments." }, async () => result({ workflows: query.findWorkflows(), deployments: query.findDeployments() })); | ||
| server.registerTool("atlas_find_environments", { description: "List detected development, staging, production, and custom runtime environments." }, async () => result({ environments: query.findEnvironments() })); | ||
| server.registerTool("atlas_search", { | ||
| description: "Search the complete architecture graph.", | ||
| inputSchema: { query: z.string().min(1) } | ||
| }, async ({ query: value }) => result({ results: query.search(value) })); | ||
| server.registerTool("atlas_project_summary", { description: "Return project identity and graph statistics." }, async () => result({ project: graph.project, stats: graph.stats })); | ||
| await server.connect(new StdioServerTransport()); | ||
| console.error(`Atlas MCP server ready: ${graphPath}`); | ||
| } | ||
| export { | ||
| startMcpServer | ||
| }; | ||
| //# sourceMappingURL=server-4KJYDYJS.js.map |
| {"version":3,"sources":["../src/mcp/server.ts"],"sourcesContent":["import { readFile } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport * as z from \"zod/v4\";\nimport { GraphQuery } from \"../core/graph.js\";\nimport type { ArchitectureGraph } from \"../core/types.js\";\n\nexport async function startMcpServer(projectPath: string, outputPath = \".atlas\"): Promise<void> {\n const graphPath = resolve(projectPath, outputPath, \"graph.json\");\n const graph = JSON.parse(await readFile(graphPath, \"utf8\")) as ArchitectureGraph;\n const query = new GraphQuery(graph);\n const server = new McpServer({ name: \"atlas\", version: graph.version });\n const result = (data: Record<string, unknown>) => ({\n content: [{ type: \"text\" as const, text: JSON.stringify(data, null, 2) }],\n structuredContent: data,\n });\n\n server.registerTool(\"atlas_find_node\", {\n description: \"Find architecture nodes by name, label, type, file, route, or metadata.\",\n inputSchema: { query: z.string().min(1) },\n }, async ({ query: value }) => result({ results: query.findNode(value) }));\n\n server.registerTool(\"atlas_get_node\", {\n description: \"Get one node and its incoming, outgoing, and method relationships.\",\n inputSchema: { id: z.string().min(1) },\n }, async ({ id }) => {\n const node = query.getNode(id);\n const outgoing = query.getOutgoing(id);\n const methods = outgoing.filter((edge) => edge.type === \"has_method\").map((edge) => query.getNode(edge.to)).filter(Boolean);\n return result({ node, incoming: query.getIncoming(id), outgoing, methods });\n });\n\n server.registerTool(\"atlas_get_dependencies\", {\n description: \"Traverse outgoing architecture dependencies from a node.\",\n inputSchema: { id: z.string().min(1), depth: z.number().int().min(1).max(10).default(2) },\n }, async ({ id, depth }) => result({ graph: query.findDependencies(id, depth) }));\n\n server.registerTool(\"atlas_get_dependents\", {\n description: \"Traverse incoming architecture dependents of a node.\",\n inputSchema: { id: z.string().min(1), depth: z.number().int().min(1).max(10).default(2) },\n }, async ({ id, depth }) => result({ graph: query.findDependents(id, depth) }));\n\n server.registerTool(\"atlas_find_path\", {\n description: \"Find the shortest explainable architecture path between two exact node IDs.\",\n inputSchema: {\n from: z.string().min(1),\n to: z.string().min(1),\n direction: z.enum([\"outgoing\", \"both\"]).default(\"outgoing\"),\n maxDepth: z.number().int().min(1).max(50).default(20),\n },\n }, async ({ from, to, direction, maxDepth }) => result({\n from: query.getNode(from),\n to: query.getNode(to),\n path: query.findPath(from, to, direction, maxDepth),\n }));\n\n server.registerTool(\"atlas_find_routes\", { description: \"List all detected HTTP routes.\" }, async () => result({ routes: query.findRoutes() }));\n\n server.registerTool(\"atlas_find_flow\", {\n description: \"Find a route and return its route-to-controller-to-service-to-data flow.\",\n inputSchema: { query: z.string().min(1) },\n }, async ({ query: value }) => {\n const route = query.findNode(value).find((node) => node.type === \"route\");\n return result({ route: route ?? null, flow: route ? query.findFlowFromRoute(route.id) : { nodes: [], edges: [] } });\n });\n\n server.registerTool(\"atlas_find_tables\", { description: \"List detected database tables.\" }, async () => result({ tables: query.findTables() }));\n server.registerTool(\"atlas_find_data_model\", { description: \"List schemas, tables, indexes, constraints, migrations, and ClickHouse structures.\" }, async () => result({\n schemas: query.findSchemas(), tables: query.findTables(), indexes: query.findIndexes(), constraints: query.findConstraints(), migrations: query.findMigrations(),\n }));\n server.registerTool(\"atlas_get_table_profile\", {\n description: \"Return a table with its columns, indexes, constraints, relations, migrations, readers, and writers.\",\n inputSchema: { query: z.string().min(1) },\n }, async ({ query: value }) => {\n const table = query.findNode(value).find((node) => node.type === \"table\");\n return result({ table: table ?? null, profile: table ? query.findTableProfile(table.id) : { nodes: [], edges: [] } });\n });\n server.registerTool(\"atlas_find_migrations\", { description: \"List migrations and the structures they create, alter, or drop.\" }, async () => result({ migrations: query.findMigrations() }));\n server.registerTool(\"atlas_find_external_apis\", { description: \"List detected external API hosts.\" }, async () => result({ externalApis: query.findExternalApis() }));\n\n server.registerTool(\"atlas_find_async_flows\", {\n description: \"List detected Kafka or RabbitMQ topics, Bull/BullMQ queues, and background processors.\",\n }, async () => result({ topics: query.findMessageTopics(), queues: query.findQueues(), processors: query.findProcessors() }));\n\n server.registerTool(\"atlas_find_async_flow\", {\n description: \"Find a message topic or queue and return publishers, consumers, processors, and downstream calls.\",\n inputSchema: { query: z.string().min(1) },\n }, async ({ query: value }) => {\n const root = query.findNode(value).find((node) => [\"message_topic\", \"queue\"].includes(node.type));\n return result({ root: root ?? null, flow: root ? query.findAsyncFlow(root.id) : { nodes: [], edges: [] } });\n });\n\n server.registerTool(\"atlas_find_schedules\", { description: \"List cron, interval, timeout, repeatable queue, and Kubernetes scheduled jobs.\" }, async () => result({ schedules: query.findScheduledJobs() }));\n server.registerTool(\"atlas_find_delivery\", { description: \"List CI/CD workflows and runtime deployments.\" }, async () => result({ workflows: query.findWorkflows(), deployments: query.findDeployments() }));\n server.registerTool(\"atlas_find_environments\", { description: \"List detected development, staging, production, and custom runtime environments.\" }, async () => result({ environments: query.findEnvironments() }));\n\n server.registerTool(\"atlas_search\", {\n description: \"Search the complete architecture graph.\",\n inputSchema: { query: z.string().min(1) },\n }, async ({ query: value }) => result({ results: query.search(value) }));\n\n server.registerTool(\"atlas_project_summary\", { description: \"Return project identity and graph statistics.\" }, async () => result({ project: graph.project, stats: graph.stats }));\n\n await server.connect(new StdioServerTransport());\n console.error(`Atlas MCP server ready: ${graphPath}`);\n}\n"],"mappings":"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","names":[]} |
| #!/usr/bin/env node | ||
| import { | ||
| ATLAS_VERSION | ||
| } from "../chunk-7TO27FDE.js"; | ||
| } from "../chunk-F76HWREH.js"; | ||
@@ -56,9 +56,14 @@ // src/cli/index.ts | ||
| program.command("mcp").description("Start the Atlas MCP server over stdio").option("-p, --path <path>", "project root", ".").option("-o, --output <path>", "Atlas output directory relative to the project", ".atlas").action(async ({ path, output }) => { | ||
| const { startMcpServer } = await import("../server-UI74K4P7.js"); | ||
| const { startMcpServer } = await import("../server-4KJYDYJS.js"); | ||
| await startMcpServer(resolve(path), output); | ||
| }); | ||
| program.parseAsync(process.argv).catch((error) => { | ||
| console.error(`Atlas error: ${error instanceof Error ? error.message : String(error)}`); | ||
| const isDebug = process.argv.includes("--debug"); | ||
| if (error instanceof Error) { | ||
| console.error(`Atlas error: ${isDebug ? error.stack : error.message}`); | ||
| } else { | ||
| console.error(`Atlas error: ${String(error)}`); | ||
| } | ||
| process.exitCode = 1; | ||
| }); | ||
| //# sourceMappingURL=index.js.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"sources":["../../src/cli/index.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { access } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\nimport { Command } from \"commander\";\nimport { ATLAS_VERSION } from \"../version.js\";\n\nconst program = new Command();\nprogram.name(\"atlas\").description(\"Local architecture intelligence for NestJS projects\").version(ATLAS_VERSION);\n\nprogram.command(\"scan\")\n .description(\"Scan a local NestJS project and generate its architecture graph\")\n .option(\"-p, --path <path>\", \"project root\", \".\")\n .option(\"-o, --output <path>\", \"output directory relative to the project\", \".atlas\")\n .option(\"--format <format>\", \"output format\", \"json\")\n .option(\"--no-cache\", \"ignore the previous Atlas analysis and scan everything again\")\n .option(\"--debug\", \"show diagnostic details\", false)\n .action(async (options) => {\n if (options.format !== \"json\") throw new Error(`Unsupported format: ${options.format}. Use json.`);\n const { scanProject } = await import(\"../index.js\");\n console.log(\"Atlas scan started\");\n const result = await scanProject({\n projectPath: options.path,\n outputPath: options.output,\n incremental: options.cache,\n debug: options.debug,\n onProgress: ({ message }) => console.log(message),\n });\n console.log(`Graph created: ${result.graph.stats.totalNodes} nodes, ${result.graph.stats.totalEdges} edges`);\n console.log(`Risks detected: ${result.risks.length}`);\n console.log(`Viewer created: ${resolve(result.outputPath, \"viewer\", \"index.html\")}`);\n console.log(\"Done\");\n });\n\nprogram.command(\"open\")\n .description(\"Open the generated static viewer\")\n .option(\"-p, --path <path>\", \"project root\", \".\")\n .option(\"-o, --output <path>\", \"Atlas output directory relative to the project\", \".atlas\")\n .action(async ({ path, output }) => {\n const { openBrowser } = await import(\"../server/open-browser.js\");\n const file = resolve(path, output, \"viewer\", \"index.html\");\n await access(file);\n await openBrowser(file);\n console.log(`Opened ${file}`);\n });\n\nprogram.command(\"serve\")\n .description(\"Serve the generated viewer on localhost\")\n .option(\"-p, --path <path>\", \"project root\", \".\")\n .option(\"-o, --output <path>\", \"Atlas output directory relative to the project\", \".atlas\")\n .option(\"--port <port>\", \"local port\", \"4317\")\n .option(\"--open\", \"open the viewer in a browser\", false)\n .action(async ({ path, output, port, open }) => {\n const numericPort = Number.parseInt(port, 10);\n if (!Number.isInteger(numericPort) || numericPort < 1 || numericPort > 65535) throw new Error(`Invalid port: ${port}`);\n const { serveViewer } = await import(\"../server/viewer-server.js\");\n await serveViewer(resolve(path, output, \"viewer\"), numericPort);\n if (open) {\n const { openBrowser } = await import(\"../server/open-browser.js\");\n await openBrowser(`http://localhost:${numericPort}`);\n }\n });\n\nprogram.command(\"report\")\n .description(\"Regenerate report.md from graph.json and risks.json\")\n .option(\"-p, --path <path>\", \"project root\", \".\")\n .option(\"-o, --output <path>\", \"Atlas output directory relative to the project\", \".atlas\")\n .action(async ({ path, output }) => {\n const { regenerateReport } = await import(\"../index.js\");\n console.log(`Report created: ${await regenerateReport(resolve(path), output)}`);\n });\n\nprogram.command(\"merge-runtime\")\n .description(\"Merge locally observed runtime links into the generated architecture graph\")\n .option(\"-p, --path <path>\", \"project root\", \".\")\n .option(\"-o, --output <path>\", \"Atlas output directory relative to the project\", \".atlas\")\n .option(\"-i, --input <path>\", \"runtime JSONL file relative to the project\")\n .action(async ({ path, output, input }) => {\n const { mergeRuntimeTrace } = await import(\"../index.js\");\n const result = await mergeRuntimeTrace(path, output, input);\n console.log(`Runtime evidence merged: ${result.metadata.runtimeEvents ?? 0} observations`);\n console.log(`Graph updated: ${result.graph.stats.totalNodes} nodes, ${result.graph.stats.totalEdges} edges`);\n });\n\nprogram.command(\"mcp\")\n .description(\"Start the Atlas MCP server over stdio\")\n .option(\"-p, --path <path>\", \"project root\", \".\")\n .option(\"-o, --output <path>\", \"Atlas output directory relative to the project\", \".atlas\")\n .action(async ({ path, output }) => {\n const { startMcpServer } = await import(\"../mcp/server.js\");\n await startMcpServer(resolve(path), output);\n });\n\nprogram.parseAsync(process.argv).catch((error: unknown) => {\n console.error(`Atlas error: ${error instanceof Error ? error.message : String(error)}`);\n process.exitCode = 1;\n});\n"],"mappings":"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","names":[]} | ||
| {"version":3,"sources":["../../src/cli/index.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { access } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\nimport { Command } from \"commander\";\nimport { ATLAS_VERSION } from \"../version.js\";\n\nconst program = new Command();\nprogram.name(\"atlas\").description(\"Local architecture intelligence for NestJS projects\").version(ATLAS_VERSION);\n\nprogram.command(\"scan\")\n .description(\"Scan a local NestJS project and generate its architecture graph\")\n .option(\"-p, --path <path>\", \"project root\", \".\")\n .option(\"-o, --output <path>\", \"output directory relative to the project\", \".atlas\")\n .option(\"--format <format>\", \"output format\", \"json\")\n .option(\"--no-cache\", \"ignore the previous Atlas analysis and scan everything again\")\n .option(\"--debug\", \"show diagnostic details\", false)\n .action(async (options) => {\n if (options.format !== \"json\") throw new Error(`Unsupported format: ${options.format}. Use json.`);\n const { scanProject } = await import(\"../index.js\");\n console.log(\"Atlas scan started\");\n const result = await scanProject({\n projectPath: options.path,\n outputPath: options.output,\n incremental: options.cache,\n debug: options.debug,\n onProgress: ({ message }) => console.log(message),\n });\n console.log(`Graph created: ${result.graph.stats.totalNodes} nodes, ${result.graph.stats.totalEdges} edges`);\n console.log(`Risks detected: ${result.risks.length}`);\n console.log(`Viewer created: ${resolve(result.outputPath, \"viewer\", \"index.html\")}`);\n console.log(\"Done\");\n });\n\nprogram.command(\"open\")\n .description(\"Open the generated static viewer\")\n .option(\"-p, --path <path>\", \"project root\", \".\")\n .option(\"-o, --output <path>\", \"Atlas output directory relative to the project\", \".atlas\")\n .action(async ({ path, output }) => {\n const { openBrowser } = await import(\"../server/open-browser.js\");\n const file = resolve(path, output, \"viewer\", \"index.html\");\n await access(file);\n await openBrowser(file);\n console.log(`Opened ${file}`);\n });\n\nprogram.command(\"serve\")\n .description(\"Serve the generated viewer on localhost\")\n .option(\"-p, --path <path>\", \"project root\", \".\")\n .option(\"-o, --output <path>\", \"Atlas output directory relative to the project\", \".atlas\")\n .option(\"--port <port>\", \"local port\", \"4317\")\n .option(\"--open\", \"open the viewer in a browser\", false)\n .action(async ({ path, output, port, open }) => {\n const numericPort = Number.parseInt(port, 10);\n if (!Number.isInteger(numericPort) || numericPort < 1 || numericPort > 65535) throw new Error(`Invalid port: ${port}`);\n const { serveViewer } = await import(\"../server/viewer-server.js\");\n await serveViewer(resolve(path, output, \"viewer\"), numericPort);\n if (open) {\n const { openBrowser } = await import(\"../server/open-browser.js\");\n await openBrowser(`http://localhost:${numericPort}`);\n }\n });\n\nprogram.command(\"report\")\n .description(\"Regenerate report.md from graph.json and risks.json\")\n .option(\"-p, --path <path>\", \"project root\", \".\")\n .option(\"-o, --output <path>\", \"Atlas output directory relative to the project\", \".atlas\")\n .action(async ({ path, output }) => {\n const { regenerateReport } = await import(\"../index.js\");\n console.log(`Report created: ${await regenerateReport(resolve(path), output)}`);\n });\n\nprogram.command(\"merge-runtime\")\n .description(\"Merge locally observed runtime links into the generated architecture graph\")\n .option(\"-p, --path <path>\", \"project root\", \".\")\n .option(\"-o, --output <path>\", \"Atlas output directory relative to the project\", \".atlas\")\n .option(\"-i, --input <path>\", \"runtime JSONL file relative to the project\")\n .action(async ({ path, output, input }) => {\n const { mergeRuntimeTrace } = await import(\"../index.js\");\n const result = await mergeRuntimeTrace(path, output, input);\n console.log(`Runtime evidence merged: ${result.metadata.runtimeEvents ?? 0} observations`);\n console.log(`Graph updated: ${result.graph.stats.totalNodes} nodes, ${result.graph.stats.totalEdges} edges`);\n });\n\nprogram.command(\"mcp\")\n .description(\"Start the Atlas MCP server over stdio\")\n .option(\"-p, --path <path>\", \"project root\", \".\")\n .option(\"-o, --output <path>\", \"Atlas output directory relative to the project\", \".atlas\")\n .action(async ({ path, output }) => {\n const { startMcpServer } = await import(\"../mcp/server.js\");\n await startMcpServer(resolve(path), output);\n });\n\nprogram.parseAsync(process.argv).catch((error: unknown) => {\n const isDebug = process.argv.includes(\"--debug\");\n if (error instanceof Error) {\n console.error(`Atlas error: ${isDebug ? error.stack : error.message}`);\n } else {\n console.error(`Atlas error: ${String(error)}`);\n }\n process.exitCode = 1;\n});\n"],"mappings":"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","names":[]} |
+1
-1
| { | ||
| "name": "@dthreads/atlas", | ||
| "version": "0.4.1", | ||
| "version": "0.4.2", | ||
| "description": "Architecture intelligence for NestJS codebases.", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
| import { | ||
| ATLAS_VERSION | ||
| } from "./chunk-7TO27FDE.js"; | ||
| // src/core/types.ts | ||
| var graphNodeTypes = [ | ||
| "project", | ||
| "folder", | ||
| "file", | ||
| "package", | ||
| "module", | ||
| "controller", | ||
| "service", | ||
| "provider", | ||
| "repository", | ||
| "use_case", | ||
| "port", | ||
| "adapter", | ||
| "entity", | ||
| "dto", | ||
| "method", | ||
| "function", | ||
| "route", | ||
| "guard", | ||
| "pipe", | ||
| "interceptor", | ||
| "middleware", | ||
| "decorator", | ||
| "database", | ||
| "table", | ||
| "column", | ||
| "model", | ||
| "environment_variable", | ||
| "external_api", | ||
| "message_broker", | ||
| "message_topic", | ||
| "queue", | ||
| "processor", | ||
| "schema", | ||
| "index", | ||
| "constraint", | ||
| "migration", | ||
| "materialized_view", | ||
| "scheduled_job", | ||
| "workflow", | ||
| "pipeline_job", | ||
| "build_stage", | ||
| "container_image", | ||
| "container", | ||
| "deployment", | ||
| "infrastructure_service", | ||
| "ingress", | ||
| "config_map", | ||
| "secret", | ||
| "environment", | ||
| "config", | ||
| "test", | ||
| "library", | ||
| "risk" | ||
| ]; | ||
| var graphEdgeTypes = [ | ||
| "contains", | ||
| "imports", | ||
| "exports", | ||
| "declares", | ||
| "provides", | ||
| "injects", | ||
| "implements", | ||
| "calls", | ||
| "uses", | ||
| "reads", | ||
| "writes", | ||
| "handles", | ||
| "depends_on", | ||
| "decorates", | ||
| "validates", | ||
| "returns", | ||
| "references", | ||
| "connects_to", | ||
| "tests", | ||
| "has_method", | ||
| "has_column", | ||
| "publishes_to", | ||
| "delivers_to", | ||
| "enqueues", | ||
| "processes", | ||
| "creates", | ||
| "alters", | ||
| "drops", | ||
| "indexes", | ||
| "schedules", | ||
| "triggers", | ||
| "builds", | ||
| "publishes", | ||
| "deploys", | ||
| "exposes", | ||
| "configures", | ||
| "runs_in", | ||
| "targets" | ||
| ]; | ||
| // src/core/graph.ts | ||
| var validNodeTypes = new Set(graphNodeTypes); | ||
| var validEdgeTypes = new Set(graphEdgeTypes); | ||
| var GraphBuilder = class { | ||
| nodes = /* @__PURE__ */ new Map(); | ||
| edges = /* @__PURE__ */ new Map(); | ||
| addNode(node) { | ||
| const current = this.nodes.get(node.id); | ||
| if (!current) { | ||
| this.nodes.set(node.id, node); | ||
| return node; | ||
| } | ||
| const merged = { | ||
| ...current, | ||
| ...node, | ||
| metadata: { ...current.metadata, ...node.metadata } | ||
| }; | ||
| this.nodes.set(node.id, merged); | ||
| return merged; | ||
| } | ||
| addEdge(edge) { | ||
| if (!this.nodes.has(edge.from) || !this.nodes.has(edge.to)) return null; | ||
| const key = `${edge.from}|${edge.type}|${edge.to}|${edge.label ?? ""}`; | ||
| const id = edge.id ?? `edge:${encodeURIComponent(key)}`; | ||
| const result = { ...edge, id }; | ||
| this.edges.set(key, result); | ||
| return result; | ||
| } | ||
| hasNode(id) { | ||
| return this.nodes.has(id); | ||
| } | ||
| validate() { | ||
| const errors = []; | ||
| for (const node of this.nodes.values()) { | ||
| if (!validNodeTypes.has(String(node.type))) errors.push(`${node.id}: invalid node type ${String(node.type)}`); | ||
| } | ||
| for (const edge of this.edges.values()) { | ||
| if (!validEdgeTypes.has(String(edge.type))) errors.push(`${edge.id}: invalid edge type ${String(edge.type)}`); | ||
| if (!this.nodes.has(edge.from)) errors.push(`${edge.id}: missing source ${edge.from}`); | ||
| if (!this.nodes.has(edge.to)) errors.push(`${edge.id}: missing target ${edge.to}`); | ||
| } | ||
| return errors; | ||
| } | ||
| toGraph(project) { | ||
| const nodes = [...this.nodes.values()].sort((a, b) => a.id.localeCompare(b.id)); | ||
| const edges = [...this.edges.values()].sort((a, b) => a.id.localeCompare(b.id)); | ||
| return { version: ATLAS_VERSION, project, nodes, edges, stats: buildStats(nodes, edges) }; | ||
| } | ||
| }; | ||
| function increment(target, key) { | ||
| target[key] = (target[key] ?? 0) + 1; | ||
| } | ||
| function buildStats(nodes, edges) { | ||
| const byNodeType = /* @__PURE__ */ Object.create(null); | ||
| const byEdgeType = /* @__PURE__ */ Object.create(null); | ||
| for (const node of nodes) increment(byNodeType, node.type); | ||
| for (const edge of edges) increment(byEdgeType, edge.type); | ||
| return { totalNodes: nodes.length, totalEdges: edges.length, byNodeType, byEdgeType }; | ||
| } | ||
| var GraphQuery = class { | ||
| constructor(graph) { | ||
| this.graph = graph; | ||
| this.nodeMap = new Map(graph.nodes.map((node) => [node.id, node])); | ||
| for (const node of graph.nodes) { | ||
| const typed = this.nodesByType.get(node.type) ?? []; | ||
| typed.push(node); | ||
| this.nodesByType.set(node.type, typed); | ||
| } | ||
| for (const edge of graph.edges) { | ||
| this.edgeMap.set(edge.id, edge); | ||
| const incoming = this.incomingMap.get(edge.to) ?? []; | ||
| incoming.push(edge); | ||
| this.incomingMap.set(edge.to, incoming); | ||
| const outgoing = this.outgoingMap.get(edge.from) ?? []; | ||
| outgoing.push(edge); | ||
| this.outgoingMap.set(edge.from, outgoing); | ||
| } | ||
| } | ||
| graph; | ||
| nodeMap; | ||
| edgeMap = /* @__PURE__ */ new Map(); | ||
| incomingMap = /* @__PURE__ */ new Map(); | ||
| outgoingMap = /* @__PURE__ */ new Map(); | ||
| nodesByType = /* @__PURE__ */ new Map(); | ||
| findNode(query) { | ||
| const needle = query.trim().toLowerCase(); | ||
| if (!needle) return []; | ||
| return this.graph.nodes.filter((node) => searchableNode(node).includes(needle)).sort((a, b) => scoreNode(b, needle) - scoreNode(a, needle)).slice(0, 100); | ||
| } | ||
| search(query) { | ||
| const needle = query.trim().toLowerCase(); | ||
| if (!needle) return []; | ||
| return this.findNode(query).map((node) => ({ | ||
| node, | ||
| score: scoreNode(node, needle), | ||
| matches: matchingFields(node, needle) | ||
| })); | ||
| } | ||
| getNode(id) { | ||
| return this.nodeMap.get(id) ?? null; | ||
| } | ||
| getIncoming(id) { | ||
| return this.incomingMap.get(id) ?? []; | ||
| } | ||
| getOutgoing(id) { | ||
| return this.outgoingMap.get(id) ?? []; | ||
| } | ||
| findRoutes() { | ||
| return this.byType("route"); | ||
| } | ||
| findServices() { | ||
| return this.byType("service"); | ||
| } | ||
| findControllers() { | ||
| return this.byType("controller"); | ||
| } | ||
| findTables() { | ||
| return this.byType("table"); | ||
| } | ||
| findSchemas() { | ||
| return this.byType("schema"); | ||
| } | ||
| findIndexes() { | ||
| return this.byType("index"); | ||
| } | ||
| findConstraints() { | ||
| return this.byType("constraint"); | ||
| } | ||
| findMigrations() { | ||
| return this.byType("migration"); | ||
| } | ||
| findScheduledJobs() { | ||
| return this.byType("scheduled_job"); | ||
| } | ||
| findWorkflows() { | ||
| return this.byType("workflow"); | ||
| } | ||
| findDeployments() { | ||
| return this.byType("deployment"); | ||
| } | ||
| findEnvironments() { | ||
| return this.byType("environment"); | ||
| } | ||
| findExternalApis() { | ||
| return this.byType("external_api"); | ||
| } | ||
| findMessageTopics() { | ||
| return this.byType("message_topic"); | ||
| } | ||
| findQueues() { | ||
| return this.byType("queue"); | ||
| } | ||
| findProcessors() { | ||
| return this.byType("processor"); | ||
| } | ||
| findTableProfile(tableId) { | ||
| const table = this.nodeMap.get(tableId); | ||
| if (!table || table.type !== "table") return { nodes: [], edges: [] }; | ||
| const edgeTypes = /* @__PURE__ */ new Set(["has_column", "indexes", "contains", "references", "reads", "writes", "creates", "alters", "drops"]); | ||
| const edges = [...this.getIncoming(tableId), ...this.getOutgoing(tableId)].filter((edge) => edgeTypes.has(edge.type)); | ||
| const ids = /* @__PURE__ */ new Set([tableId, ...edges.flatMap((edge) => [edge.from, edge.to])]); | ||
| return { nodes: [...ids].map((id) => this.nodeMap.get(id)).filter(Boolean), edges }; | ||
| } | ||
| getNeighbors(nodeId, depth = 1) { | ||
| if (!this.nodeMap.has(nodeId)) return { nodes: [], edges: [] }; | ||
| const nodeIds = /* @__PURE__ */ new Set([nodeId]); | ||
| const edgeIds = /* @__PURE__ */ new Set(); | ||
| let frontier = [nodeId]; | ||
| for (let level = 0; level < Math.max(0, depth) && frontier.length; level += 1) { | ||
| const next = []; | ||
| for (const id of frontier) { | ||
| for (const edge of [...this.getIncoming(id), ...this.getOutgoing(id)]) { | ||
| edgeIds.add(edge.id); | ||
| const neighbor = edge.from === id ? edge.to : edge.from; | ||
| if (!nodeIds.has(neighbor)) { | ||
| nodeIds.add(neighbor); | ||
| next.push(neighbor); | ||
| } | ||
| } | ||
| } | ||
| frontier = next; | ||
| } | ||
| return { | ||
| nodes: [...nodeIds].map((id) => this.nodeMap.get(id)).filter(Boolean), | ||
| edges: [...edgeIds].map((id) => this.edgeMap.get(id)).filter(Boolean) | ||
| }; | ||
| } | ||
| findFlowFromRoute(routeId) { | ||
| return this.walk(routeId, "outgoing", 12, /* @__PURE__ */ new Set([ | ||
| "handles", | ||
| "calls", | ||
| "reads", | ||
| "writes", | ||
| "uses", | ||
| "connects_to", | ||
| "validates", | ||
| "returns", | ||
| "publishes_to", | ||
| "delivers_to", | ||
| "enqueues", | ||
| "processes" | ||
| ])); | ||
| } | ||
| findAsyncFlow(rootId) { | ||
| const root = this.nodeMap.get(rootId); | ||
| if (!root || !["message_topic", "queue"].includes(root.type)) return { nodes: [], edges: [] }; | ||
| const flow = this.walk(rootId, "outgoing", 12, /* @__PURE__ */ new Set([ | ||
| "delivers_to", | ||
| "calls", | ||
| "reads", | ||
| "writes", | ||
| "uses", | ||
| "connects_to", | ||
| "publishes_to", | ||
| "enqueues", | ||
| "processes" | ||
| ])); | ||
| const nodeIds = new Set(flow.nodes.map((node) => node.id)); | ||
| const edgeIds = new Set(flow.edges.map((edge) => edge.id)); | ||
| for (const edge of this.getIncoming(rootId).filter((item) => ["publishes_to", "enqueues"].includes(item.type))) { | ||
| nodeIds.add(edge.from); | ||
| edgeIds.add(edge.id); | ||
| } | ||
| return { | ||
| nodes: [...nodeIds].map((id) => this.nodeMap.get(id)).filter(Boolean), | ||
| edges: [...edgeIds].map((id) => this.edgeMap.get(id)).filter(Boolean) | ||
| }; | ||
| } | ||
| findDependencies(nodeId, depth = 2) { | ||
| return this.walk(nodeId, "outgoing", depth); | ||
| } | ||
| findDependents(nodeId, depth = 2) { | ||
| return this.walk(nodeId, "incoming", depth); | ||
| } | ||
| findPath(fromId, toId, direction = "outgoing", maxDepth = 20) { | ||
| if (!this.nodeMap.has(fromId) || !this.nodeMap.has(toId)) return { nodes: [], edges: [] }; | ||
| if (fromId === toId) return { nodes: [this.nodeMap.get(fromId)], edges: [] }; | ||
| const queue = [{ id: fromId, depth: 0 }]; | ||
| const visited = /* @__PURE__ */ new Set([fromId]); | ||
| const previous = /* @__PURE__ */ new Map(); | ||
| let cursor = 0; | ||
| while (cursor < queue.length) { | ||
| const current = queue[cursor++]; | ||
| if (current.depth >= Math.max(1, maxDepth)) continue; | ||
| const candidates = [ | ||
| ...this.getOutgoing(current.id).map((edge) => ({ edge, next: edge.to })), | ||
| ...direction === "both" ? this.getIncoming(current.id).map((edge) => ({ edge, next: edge.from })) : [] | ||
| ].sort((a, b) => pathEdgePriority(a.edge) - pathEdgePriority(b.edge) || a.edge.id.localeCompare(b.edge.id)); | ||
| for (const candidate of candidates) { | ||
| if (visited.has(candidate.next)) continue; | ||
| visited.add(candidate.next); | ||
| previous.set(candidate.next, { nodeId: current.id, edge: candidate.edge }); | ||
| if (candidate.next === toId) return this.reconstructPath(fromId, toId, previous); | ||
| queue.push({ id: candidate.next, depth: current.depth + 1 }); | ||
| } | ||
| } | ||
| return { nodes: [], edges: [] }; | ||
| } | ||
| byType(type) { | ||
| return this.nodesByType.get(type) ?? []; | ||
| } | ||
| reconstructPath(fromId, toId, previous) { | ||
| const nodeIds = [toId]; | ||
| const edges = []; | ||
| let current = toId; | ||
| while (current !== fromId) { | ||
| const step = previous.get(current); | ||
| if (!step) return { nodes: [], edges: [] }; | ||
| nodeIds.push(step.nodeId); | ||
| edges.push(step.edge); | ||
| current = step.nodeId; | ||
| } | ||
| nodeIds.reverse(); | ||
| edges.reverse(); | ||
| return { nodes: nodeIds.map((id) => this.nodeMap.get(id)), edges }; | ||
| } | ||
| walk(startId, direction, depth, allowedTypes) { | ||
| if (!this.nodeMap.has(startId)) return { nodes: [], edges: [] }; | ||
| const nodeIds = /* @__PURE__ */ new Set([startId]); | ||
| const edgeIds = /* @__PURE__ */ new Set(); | ||
| let frontier = [startId]; | ||
| for (let level = 0; level < Math.max(0, depth) && frontier.length; level += 1) { | ||
| const next = []; | ||
| for (const id of frontier) { | ||
| const edges = direction === "outgoing" ? this.getOutgoing(id) : this.getIncoming(id); | ||
| for (const edge of edges) { | ||
| if (allowedTypes && !allowedTypes.has(edge.type)) continue; | ||
| edgeIds.add(edge.id); | ||
| const neighbor = direction === "outgoing" ? edge.to : edge.from; | ||
| if (!nodeIds.has(neighbor)) { | ||
| nodeIds.add(neighbor); | ||
| next.push(neighbor); | ||
| } | ||
| } | ||
| } | ||
| frontier = next; | ||
| } | ||
| return { | ||
| nodes: [...nodeIds].map((id) => this.nodeMap.get(id)).filter(Boolean), | ||
| edges: [...edgeIds].map((id) => this.edgeMap.get(id)).filter(Boolean) | ||
| }; | ||
| } | ||
| }; | ||
| function pathEdgePriority(edge) { | ||
| if (["handles", "calls", "reads", "writes", "publishes_to", "delivers_to", "enqueues", "processes", "targets", "exposes", "deploys"].includes(edge.type)) return 0; | ||
| if (["injects", "implements", "uses", "connects_to", "configures", "builds", "publishes", "triggers", "schedules"].includes(edge.type)) return 1; | ||
| if (["depends_on", "references", "imports", "exports", "provides"].includes(edge.type)) return 2; | ||
| return 3; | ||
| } | ||
| function searchableNode(node) { | ||
| return [node.id, node.type, node.label, node.name, node.file, JSON.stringify(node.metadata ?? {})].filter(Boolean).join(" ").toLowerCase(); | ||
| } | ||
| function scoreNode(node, needle) { | ||
| const label = node.label.toLowerCase(); | ||
| if (label === needle) return 100; | ||
| if (label.startsWith(needle)) return 80; | ||
| if (node.id.toLowerCase().includes(needle)) return 60; | ||
| return 20; | ||
| } | ||
| function matchingFields(node, needle) { | ||
| const fields = { | ||
| id: node.id, | ||
| label: node.label, | ||
| name: node.name ?? "", | ||
| type: node.type, | ||
| file: node.file ?? "", | ||
| metadata: JSON.stringify(node.metadata ?? {}) | ||
| }; | ||
| return Object.entries(fields).filter(([, value]) => value.toLowerCase().includes(needle)).map(([key]) => key); | ||
| } | ||
| export { | ||
| graphNodeTypes, | ||
| graphEdgeTypes, | ||
| GraphBuilder, | ||
| buildStats, | ||
| GraphQuery | ||
| }; | ||
| //# sourceMappingURL=chunk-33U6HYHN.js.map |
| {"version":3,"sources":["../src/core/types.ts","../src/core/graph.ts"],"sourcesContent":["export const graphNodeTypes = [\n \"project\", \"folder\", \"file\", \"package\", \"module\", \"controller\", \"service\",\n \"provider\", \"repository\", \"use_case\", \"port\", \"adapter\", \"entity\", \"dto\", \"method\", \"function\", \"route\",\n \"guard\", \"pipe\", \"interceptor\", \"middleware\", \"decorator\", \"database\",\n \"table\", \"column\", \"model\", \"environment_variable\", \"external_api\",\n \"message_broker\", \"message_topic\", \"queue\", \"processor\",\n \"schema\", \"index\", \"constraint\", \"migration\", \"materialized_view\",\n \"scheduled_job\", \"workflow\", \"pipeline_job\", \"build_stage\", \"container_image\",\n \"container\", \"deployment\", \"infrastructure_service\", \"ingress\", \"config_map\",\n \"secret\", \"environment\", \"config\", \"test\", \"library\", \"risk\",\n] as const;\n\nexport const graphEdgeTypes = [\n \"contains\", \"imports\", \"exports\", \"declares\", \"provides\", \"injects\", \"implements\", \"calls\",\n \"uses\", \"reads\", \"writes\", \"handles\", \"depends_on\", \"decorates\", \"validates\",\n \"returns\", \"references\", \"connects_to\", \"tests\", \"has_method\", \"has_column\",\n \"publishes_to\", \"delivers_to\", \"enqueues\", \"processes\",\n \"creates\", \"alters\", \"drops\", \"indexes\", \"schedules\", \"triggers\", \"builds\",\n \"publishes\", \"deploys\", \"exposes\", \"configures\", \"runs_in\", \"targets\",\n] as const;\n\nexport type GraphNodeType = (typeof graphNodeTypes)[number];\nexport type GraphEdgeType = (typeof graphEdgeTypes)[number];\nexport type GraphSourceType =\n | \"static_analysis\"\n | \"ast\"\n | \"config\"\n | \"package_json\"\n | \"heuristic\"\n | \"runtime\"\n | \"manual\";\n\nexport interface SourceLocation {\n file: string;\n startLine?: number;\n endLine?: number;\n}\n\nexport interface GraphNode {\n id: string;\n type: GraphNodeType;\n label: string;\n name?: string;\n file?: string;\n language?: string;\n framework?: string;\n sourceLocation?: SourceLocation;\n confidence?: number;\n source?: GraphSourceType;\n metadata?: Record<string, unknown>;\n}\n\nexport interface GraphEdge {\n id: string;\n from: string;\n to: string;\n type: GraphEdgeType;\n label?: string;\n confidence?: number;\n source?: GraphSourceType;\n metadata?: Record<string, unknown>;\n}\n\nexport interface DetectedStack {\n name: string;\n confidence: number;\n evidence: string[];\n}\n\nexport interface GraphStats {\n totalNodes: number;\n totalEdges: number;\n byNodeType: Partial<Record<GraphNodeType, number>>;\n byEdgeType: Partial<Record<GraphEdgeType, number>>;\n}\n\nexport interface ArchitectureGraph {\n version: string;\n project: {\n name: string;\n root: string;\n detectedStacks: string[];\n createdAt: string;\n };\n nodes: GraphNode[];\n edges: GraphEdge[];\n stats: GraphStats;\n}\n\nexport interface ScannedFile {\n absolutePath: string;\n path: string;\n extension: string;\n size: number;\n hash?: string;\n lastModified: string;\n}\n\nexport interface ScanMetadata {\n version: string;\n projectName: string;\n projectRoot: string;\n scanStartedAt: string;\n scanFinishedAt: string;\n durationMs: number;\n filesScanned: number;\n filesIgnored: number;\n filesHashed?: number;\n filesReused?: number;\n cacheHit?: boolean;\n inputFingerprint?: string;\n analysisCacheVersion?: number;\n viewerFingerprint?: string;\n runtimeEvents?: number;\n runtimeMergedAt?: string;\n runtimeFingerprint?: string;\n detectedStacks: DetectedStack[];\n}\n\nexport type RiskSeverity = \"low\" | \"medium\" | \"high\" | \"critical\";\n\nexport interface ArchitectureRisk {\n id: string;\n type: string;\n severity: RiskSeverity;\n title: string;\n description: string;\n recommendation: string;\n nodeId?: string;\n file?: string;\n metadata?: Record<string, unknown>;\n}\n\nexport interface GraphSubgraph {\n nodes: GraphNode[];\n edges: GraphEdge[];\n}\n\nexport interface GraphSearchResult {\n node: GraphNode;\n score: number;\n matches: string[];\n}\n\nexport type ScanProgressStage =\n | \"scan_files\"\n | \"detect_stack\"\n | \"parse_architecture\"\n | \"build_graph\"\n | \"detect_risks\"\n | \"write_outputs\";\n\nexport interface ScanProgress {\n stage: ScanProgressStage;\n message: string;\n}\n\nexport interface ScanOptions {\n projectPath: string;\n outputPath?: string;\n incremental?: boolean;\n debug?: boolean;\n onProgress?: (progress: ScanProgress) => void;\n}\n\nexport interface ScanResult {\n graph: ArchitectureGraph;\n metadata: ScanMetadata;\n risks: ArchitectureRisk[];\n outputPath: string;\n}\n\nexport interface RuntimeTraceNode {\n id: string;\n type: GraphNodeType;\n label?: string;\n file?: string;\n}\n\nexport interface RuntimeTraceEvent {\n from: string;\n to: string;\n type: GraphEdgeType;\n timestamp?: string;\n count?: number;\n durationMs?: number;\n fromNode?: RuntimeTraceNode;\n toNode?: RuntimeTraceNode;\n metadata?: Record<string, unknown>;\n}\n","import type {\n ArchitectureGraph,\n GraphEdge,\n GraphEdgeType,\n GraphNode,\n GraphSearchResult,\n GraphStats,\n GraphSubgraph,\n} from \"./types.js\";\nimport { graphEdgeTypes, graphNodeTypes } from \"./types.js\";\nimport { ATLAS_VERSION } from \"../version.js\";\n\nconst validNodeTypes = new Set<string>(graphNodeTypes);\nconst validEdgeTypes = new Set<string>(graphEdgeTypes);\n\nexport class GraphBuilder {\n readonly nodes = new Map<string, GraphNode>();\n readonly edges = new Map<string, GraphEdge>();\n\n addNode(node: GraphNode): GraphNode {\n const current = this.nodes.get(node.id);\n if (!current) {\n this.nodes.set(node.id, node);\n return node;\n }\n const merged = {\n ...current,\n ...node,\n metadata: { ...current.metadata, ...node.metadata },\n };\n this.nodes.set(node.id, merged);\n return merged;\n }\n\n addEdge(edge: Omit<GraphEdge, \"id\"> & { id?: string }): GraphEdge | null {\n if (!this.nodes.has(edge.from) || !this.nodes.has(edge.to)) return null;\n const key = `${edge.from}|${edge.type}|${edge.to}|${edge.label ?? \"\"}`;\n const id = edge.id ?? `edge:${encodeURIComponent(key)}`;\n const result: GraphEdge = { ...edge, id };\n this.edges.set(key, result);\n return result;\n }\n\n hasNode(id: string): boolean {\n return this.nodes.has(id);\n }\n\n validate(): string[] {\n const errors: string[] = [];\n for (const node of this.nodes.values()) {\n if (!validNodeTypes.has(String(node.type))) errors.push(`${node.id}: invalid node type ${String(node.type)}`);\n }\n for (const edge of this.edges.values()) {\n if (!validEdgeTypes.has(String(edge.type))) errors.push(`${edge.id}: invalid edge type ${String(edge.type)}`);\n if (!this.nodes.has(edge.from)) errors.push(`${edge.id}: missing source ${edge.from}`);\n if (!this.nodes.has(edge.to)) errors.push(`${edge.id}: missing target ${edge.to}`);\n }\n return errors;\n }\n\n toGraph(project: ArchitectureGraph[\"project\"]): ArchitectureGraph {\n const nodes = [...this.nodes.values()].sort((a, b) => a.id.localeCompare(b.id));\n const edges = [...this.edges.values()].sort((a, b) => a.id.localeCompare(b.id));\n return { version: ATLAS_VERSION, project, nodes, edges, stats: buildStats(nodes, edges) };\n }\n}\n\nfunction increment<T extends string>(target: Partial<Record<T, number>>, key: T) {\n target[key] = (target[key] ?? 0) + 1;\n}\n\nexport function buildStats(nodes: GraphNode[], edges: GraphEdge[]): GraphStats {\n const byNodeType: GraphStats[\"byNodeType\"] = Object.create(null) as GraphStats[\"byNodeType\"];\n const byEdgeType: GraphStats[\"byEdgeType\"] = Object.create(null) as GraphStats[\"byEdgeType\"];\n for (const node of nodes) increment(byNodeType, node.type);\n for (const edge of edges) increment(byEdgeType, edge.type);\n return { totalNodes: nodes.length, totalEdges: edges.length, byNodeType, byEdgeType };\n}\n\nexport class GraphQuery {\n private readonly nodeMap: Map<string, GraphNode>;\n private readonly edgeMap = new Map<string, GraphEdge>();\n private readonly incomingMap = new Map<string, GraphEdge[]>();\n private readonly outgoingMap = new Map<string, GraphEdge[]>();\n private readonly nodesByType = new Map<GraphNode[\"type\"], GraphNode[]>();\n\n constructor(readonly graph: ArchitectureGraph) {\n this.nodeMap = new Map(graph.nodes.map((node) => [node.id, node]));\n for (const node of graph.nodes) {\n const typed = this.nodesByType.get(node.type) ?? [];\n typed.push(node);\n this.nodesByType.set(node.type, typed);\n }\n for (const edge of graph.edges) {\n this.edgeMap.set(edge.id, edge);\n const incoming = this.incomingMap.get(edge.to) ?? [];\n incoming.push(edge);\n this.incomingMap.set(edge.to, incoming);\n const outgoing = this.outgoingMap.get(edge.from) ?? [];\n outgoing.push(edge);\n this.outgoingMap.set(edge.from, outgoing);\n }\n }\n\n findNode(query: string): GraphNode[] {\n const needle = query.trim().toLowerCase();\n if (!needle) return [];\n return this.graph.nodes\n .filter((node) => searchableNode(node).includes(needle))\n .sort((a, b) => scoreNode(b, needle) - scoreNode(a, needle))\n .slice(0, 100);\n }\n\n search(query: string): GraphSearchResult[] {\n const needle = query.trim().toLowerCase();\n if (!needle) return [];\n return this.findNode(query).map((node) => ({\n node,\n score: scoreNode(node, needle),\n matches: matchingFields(node, needle),\n }));\n }\n\n getNode(id: string): GraphNode | null {\n return this.nodeMap.get(id) ?? null;\n }\n\n getIncoming(id: string): GraphEdge[] {\n return this.incomingMap.get(id) ?? [];\n }\n\n getOutgoing(id: string): GraphEdge[] {\n return this.outgoingMap.get(id) ?? [];\n }\n\n findRoutes(): GraphNode[] { return this.byType(\"route\"); }\n findServices(): GraphNode[] { return this.byType(\"service\"); }\n findControllers(): GraphNode[] { return this.byType(\"controller\"); }\n findTables(): GraphNode[] { return this.byType(\"table\"); }\n findSchemas(): GraphNode[] { return this.byType(\"schema\"); }\n findIndexes(): GraphNode[] { return this.byType(\"index\"); }\n findConstraints(): GraphNode[] { return this.byType(\"constraint\"); }\n findMigrations(): GraphNode[] { return this.byType(\"migration\"); }\n findScheduledJobs(): GraphNode[] { return this.byType(\"scheduled_job\"); }\n findWorkflows(): GraphNode[] { return this.byType(\"workflow\"); }\n findDeployments(): GraphNode[] { return this.byType(\"deployment\"); }\n findEnvironments(): GraphNode[] { return this.byType(\"environment\"); }\n findExternalApis(): GraphNode[] { return this.byType(\"external_api\"); }\n findMessageTopics(): GraphNode[] { return this.byType(\"message_topic\"); }\n findQueues(): GraphNode[] { return this.byType(\"queue\"); }\n findProcessors(): GraphNode[] { return this.byType(\"processor\"); }\n\n findTableProfile(tableId: string): GraphSubgraph {\n const table = this.nodeMap.get(tableId);\n if (!table || table.type !== \"table\") return { nodes: [], edges: [] };\n const edgeTypes = new Set<GraphEdgeType>([\"has_column\", \"indexes\", \"contains\", \"references\", \"reads\", \"writes\", \"creates\", \"alters\", \"drops\"]);\n const edges = [...this.getIncoming(tableId), ...this.getOutgoing(tableId)]\n .filter((edge) => edgeTypes.has(edge.type));\n const ids = new Set([tableId, ...edges.flatMap((edge) => [edge.from, edge.to])]);\n return { nodes: [...ids].map((id) => this.nodeMap.get(id)).filter(Boolean) as GraphNode[], edges };\n }\n\n getNeighbors(nodeId: string, depth = 1): GraphSubgraph {\n if (!this.nodeMap.has(nodeId)) return { nodes: [], edges: [] };\n const nodeIds = new Set([nodeId]);\n const edgeIds = new Set<string>();\n let frontier = [nodeId];\n for (let level = 0; level < Math.max(0, depth) && frontier.length; level += 1) {\n const next: string[] = [];\n for (const id of frontier) {\n for (const edge of [...this.getIncoming(id), ...this.getOutgoing(id)]) {\n edgeIds.add(edge.id);\n const neighbor = edge.from === id ? edge.to : edge.from;\n if (!nodeIds.has(neighbor)) { nodeIds.add(neighbor); next.push(neighbor); }\n }\n }\n frontier = next;\n }\n return {\n nodes: [...nodeIds].map((id) => this.nodeMap.get(id)).filter(Boolean) as GraphNode[],\n edges: [...edgeIds].map((id) => this.edgeMap.get(id)).filter(Boolean) as GraphEdge[],\n };\n }\n\n findFlowFromRoute(routeId: string): GraphSubgraph {\n return this.walk(routeId, \"outgoing\", 12, new Set([\n \"handles\", \"calls\", \"reads\", \"writes\", \"uses\", \"connects_to\", \"validates\", \"returns\",\n \"publishes_to\", \"delivers_to\", \"enqueues\", \"processes\",\n ]));\n }\n\n findAsyncFlow(rootId: string): GraphSubgraph {\n const root = this.nodeMap.get(rootId);\n if (!root || ![\"message_topic\", \"queue\"].includes(root.type)) return { nodes: [], edges: [] };\n const flow = this.walk(rootId, \"outgoing\", 12, new Set([\n \"delivers_to\", \"calls\", \"reads\", \"writes\", \"uses\", \"connects_to\", \"publishes_to\", \"enqueues\", \"processes\",\n ]));\n const nodeIds = new Set(flow.nodes.map((node) => node.id));\n const edgeIds = new Set(flow.edges.map((edge) => edge.id));\n for (const edge of this.getIncoming(rootId).filter((item) => [\"publishes_to\", \"enqueues\"].includes(item.type))) {\n nodeIds.add(edge.from);\n edgeIds.add(edge.id);\n }\n return {\n nodes: [...nodeIds].map((id) => this.nodeMap.get(id)).filter(Boolean) as GraphNode[],\n edges: [...edgeIds].map((id) => this.edgeMap.get(id)).filter(Boolean) as GraphEdge[],\n };\n }\n\n findDependencies(nodeId: string, depth = 2): GraphSubgraph {\n return this.walk(nodeId, \"outgoing\", depth);\n }\n\n findDependents(nodeId: string, depth = 2): GraphSubgraph {\n return this.walk(nodeId, \"incoming\", depth);\n }\n\n findPath(\n fromId: string,\n toId: string,\n direction: \"outgoing\" | \"both\" = \"outgoing\",\n maxDepth = 20,\n ): GraphSubgraph {\n if (!this.nodeMap.has(fromId) || !this.nodeMap.has(toId)) return { nodes: [], edges: [] };\n if (fromId === toId) return { nodes: [this.nodeMap.get(fromId)!], edges: [] };\n const queue: Array<{ id: string; depth: number }> = [{ id: fromId, depth: 0 }];\n const visited = new Set([fromId]);\n const previous = new Map<string, { nodeId: string; edge: GraphEdge }>();\n let cursor = 0;\n while (cursor < queue.length) {\n const current = queue[cursor++];\n if (current.depth >= Math.max(1, maxDepth)) continue;\n const candidates = [\n ...this.getOutgoing(current.id).map((edge) => ({ edge, next: edge.to })),\n ...(direction === \"both\" ? this.getIncoming(current.id).map((edge) => ({ edge, next: edge.from })) : []),\n ].sort((a, b) => pathEdgePriority(a.edge) - pathEdgePriority(b.edge) || a.edge.id.localeCompare(b.edge.id));\n for (const candidate of candidates) {\n if (visited.has(candidate.next)) continue;\n visited.add(candidate.next);\n previous.set(candidate.next, { nodeId: current.id, edge: candidate.edge });\n if (candidate.next === toId) return this.reconstructPath(fromId, toId, previous);\n queue.push({ id: candidate.next, depth: current.depth + 1 });\n }\n }\n return { nodes: [], edges: [] };\n }\n\n private byType(type: GraphNode[\"type\"]): GraphNode[] {\n return this.nodesByType.get(type) ?? [];\n }\n\n private reconstructPath(fromId: string, toId: string, previous: Map<string, { nodeId: string; edge: GraphEdge }>): GraphSubgraph {\n const nodeIds = [toId];\n const edges: GraphEdge[] = [];\n let current = toId;\n while (current !== fromId) {\n const step = previous.get(current);\n if (!step) return { nodes: [], edges: [] };\n nodeIds.push(step.nodeId);\n edges.push(step.edge);\n current = step.nodeId;\n }\n nodeIds.reverse();\n edges.reverse();\n return { nodes: nodeIds.map((id) => this.nodeMap.get(id)!), edges };\n }\n\n private walk(\n startId: string,\n direction: \"incoming\" | \"outgoing\",\n depth: number,\n allowedTypes?: Set<GraphEdgeType>,\n ): GraphSubgraph {\n if (!this.nodeMap.has(startId)) return { nodes: [], edges: [] };\n const nodeIds = new Set([startId]);\n const edgeIds = new Set<string>();\n let frontier = [startId];\n for (let level = 0; level < Math.max(0, depth) && frontier.length; level += 1) {\n const next: string[] = [];\n for (const id of frontier) {\n const edges = direction === \"outgoing\" ? this.getOutgoing(id) : this.getIncoming(id);\n for (const edge of edges) {\n if (allowedTypes && !allowedTypes.has(edge.type)) continue;\n edgeIds.add(edge.id);\n const neighbor = direction === \"outgoing\" ? edge.to : edge.from;\n if (!nodeIds.has(neighbor)) {\n nodeIds.add(neighbor);\n next.push(neighbor);\n }\n }\n }\n frontier = next;\n }\n return {\n nodes: [...nodeIds].map((id) => this.nodeMap.get(id)).filter(Boolean) as GraphNode[],\n edges: [...edgeIds].map((id) => this.edgeMap.get(id)).filter(Boolean) as GraphEdge[],\n };\n }\n}\n\nfunction pathEdgePriority(edge: GraphEdge): number {\n if ([\"handles\", \"calls\", \"reads\", \"writes\", \"publishes_to\", \"delivers_to\", \"enqueues\", \"processes\", \"targets\", \"exposes\", \"deploys\"].includes(edge.type)) return 0;\n if ([\"injects\", \"implements\", \"uses\", \"connects_to\", \"configures\", \"builds\", \"publishes\", \"triggers\", \"schedules\"].includes(edge.type)) return 1;\n if ([\"depends_on\", \"references\", \"imports\", \"exports\", \"provides\"].includes(edge.type)) return 2;\n return 3;\n}\n\nfunction searchableNode(node: GraphNode): string {\n return [node.id, node.type, node.label, node.name, node.file, JSON.stringify(node.metadata ?? {})]\n .filter(Boolean)\n .join(\" \")\n .toLowerCase();\n}\n\nfunction scoreNode(node: GraphNode, needle: string): number {\n const label = node.label.toLowerCase();\n if (label === needle) return 100;\n if (label.startsWith(needle)) return 80;\n if (node.id.toLowerCase().includes(needle)) return 60;\n return 20;\n}\n\nfunction matchingFields(node: GraphNode, needle: string): string[] {\n const fields = {\n id: node.id,\n label: node.label,\n name: node.name ?? \"\",\n type: node.type,\n file: node.file ?? \"\",\n metadata: JSON.stringify(node.metadata ?? {}),\n };\n return Object.entries(fields).filter(([, value]) => value.toLowerCase().includes(needle)).map(([key]) => key);\n}\n"],"mappings":"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","names":[]} |
| // src/version.ts | ||
| var ATLAS_VERSION = "0.4.1"; | ||
| export { | ||
| ATLAS_VERSION | ||
| }; | ||
| //# sourceMappingURL=chunk-7TO27FDE.js.map |
| {"version":3,"sources":["../src/version.ts"],"sourcesContent":["export const ATLAS_VERSION = \"0.4.1\";\n"],"mappings":";AAAO,IAAM,gBAAgB;","names":[]} |
| import { | ||
| GraphQuery | ||
| } from "./chunk-33U6HYHN.js"; | ||
| import "./chunk-7TO27FDE.js"; | ||
| // src/mcp/server.ts | ||
| import { readFile } from "fs/promises"; | ||
| import { resolve } from "path"; | ||
| import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; | ||
| import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; | ||
| import * as z from "zod/v4"; | ||
| async function startMcpServer(projectPath, outputPath = ".atlas") { | ||
| const graphPath = resolve(projectPath, outputPath, "graph.json"); | ||
| const graph = JSON.parse(await readFile(graphPath, "utf8")); | ||
| const query = new GraphQuery(graph); | ||
| const server = new McpServer({ name: "atlas", version: graph.version }); | ||
| const result = (data) => ({ | ||
| content: [{ type: "text", text: JSON.stringify(data, null, 2) }], | ||
| structuredContent: data | ||
| }); | ||
| server.registerTool("atlas_find_node", { | ||
| description: "Find architecture nodes by name, label, type, file, route, or metadata.", | ||
| inputSchema: { query: z.string().min(1) } | ||
| }, async ({ query: value }) => result({ results: query.findNode(value) })); | ||
| server.registerTool("atlas_get_node", { | ||
| description: "Get one node and its incoming, outgoing, and method relationships.", | ||
| inputSchema: { id: z.string().min(1) } | ||
| }, async ({ id }) => { | ||
| const node = query.getNode(id); | ||
| const outgoing = query.getOutgoing(id); | ||
| const methods = outgoing.filter((edge) => edge.type === "has_method").map((edge) => query.getNode(edge.to)).filter(Boolean); | ||
| return result({ node, incoming: query.getIncoming(id), outgoing, methods }); | ||
| }); | ||
| server.registerTool("atlas_get_dependencies", { | ||
| description: "Traverse outgoing architecture dependencies from a node.", | ||
| inputSchema: { id: z.string().min(1), depth: z.number().int().min(1).max(10).default(2) } | ||
| }, async ({ id, depth }) => result({ graph: query.findDependencies(id, depth) })); | ||
| server.registerTool("atlas_get_dependents", { | ||
| description: "Traverse incoming architecture dependents of a node.", | ||
| inputSchema: { id: z.string().min(1), depth: z.number().int().min(1).max(10).default(2) } | ||
| }, async ({ id, depth }) => result({ graph: query.findDependents(id, depth) })); | ||
| server.registerTool("atlas_find_path", { | ||
| description: "Find the shortest explainable architecture path between two exact node IDs.", | ||
| inputSchema: { | ||
| from: z.string().min(1), | ||
| to: z.string().min(1), | ||
| direction: z.enum(["outgoing", "both"]).default("outgoing"), | ||
| maxDepth: z.number().int().min(1).max(50).default(20) | ||
| } | ||
| }, async ({ from, to, direction, maxDepth }) => result({ | ||
| from: query.getNode(from), | ||
| to: query.getNode(to), | ||
| path: query.findPath(from, to, direction, maxDepth) | ||
| })); | ||
| server.registerTool("atlas_find_routes", { description: "List all detected HTTP routes." }, async () => result({ routes: query.findRoutes() })); | ||
| server.registerTool("atlas_find_flow", { | ||
| description: "Find a route and return its route-to-controller-to-service-to-data flow.", | ||
| inputSchema: { query: z.string().min(1) } | ||
| }, async ({ query: value }) => { | ||
| const route = query.findNode(value).find((node) => node.type === "route"); | ||
| return result({ route: route ?? null, flow: route ? query.findFlowFromRoute(route.id) : { nodes: [], edges: [] } }); | ||
| }); | ||
| server.registerTool("atlas_find_tables", { description: "List detected database tables." }, async () => result({ tables: query.findTables() })); | ||
| server.registerTool("atlas_find_data_model", { description: "List schemas, tables, indexes, constraints, migrations, and ClickHouse structures." }, async () => result({ | ||
| schemas: query.findSchemas(), | ||
| tables: query.findTables(), | ||
| indexes: query.findIndexes(), | ||
| constraints: query.findConstraints(), | ||
| migrations: query.findMigrations() | ||
| })); | ||
| server.registerTool("atlas_get_table_profile", { | ||
| description: "Return a table with its columns, indexes, constraints, relations, migrations, readers, and writers.", | ||
| inputSchema: { query: z.string().min(1) } | ||
| }, async ({ query: value }) => { | ||
| const table = query.findNode(value).find((node) => node.type === "table"); | ||
| return result({ table: table ?? null, profile: table ? query.findTableProfile(table.id) : { nodes: [], edges: [] } }); | ||
| }); | ||
| server.registerTool("atlas_find_migrations", { description: "List migrations and the structures they create, alter, or drop." }, async () => result({ migrations: query.findMigrations() })); | ||
| server.registerTool("atlas_find_external_apis", { description: "List detected external API hosts." }, async () => result({ externalApis: query.findExternalApis() })); | ||
| server.registerTool("atlas_find_async_flows", { | ||
| description: "List detected Kafka or RabbitMQ topics, Bull/BullMQ queues, and background processors." | ||
| }, async () => result({ topics: query.findMessageTopics(), queues: query.findQueues(), processors: query.findProcessors() })); | ||
| server.registerTool("atlas_find_async_flow", { | ||
| description: "Find a message topic or queue and return publishers, consumers, processors, and downstream calls.", | ||
| inputSchema: { query: z.string().min(1) } | ||
| }, async ({ query: value }) => { | ||
| const root = query.findNode(value).find((node) => ["message_topic", "queue"].includes(node.type)); | ||
| return result({ root: root ?? null, flow: root ? query.findAsyncFlow(root.id) : { nodes: [], edges: [] } }); | ||
| }); | ||
| server.registerTool("atlas_find_schedules", { description: "List cron, interval, timeout, repeatable queue, and Kubernetes scheduled jobs." }, async () => result({ schedules: query.findScheduledJobs() })); | ||
| server.registerTool("atlas_find_delivery", { description: "List CI/CD workflows and runtime deployments." }, async () => result({ workflows: query.findWorkflows(), deployments: query.findDeployments() })); | ||
| server.registerTool("atlas_find_environments", { description: "List detected development, staging, production, and custom runtime environments." }, async () => result({ environments: query.findEnvironments() })); | ||
| server.registerTool("atlas_search", { | ||
| description: "Search the complete architecture graph.", | ||
| inputSchema: { query: z.string().min(1) } | ||
| }, async ({ query: value }) => result({ results: query.search(value) })); | ||
| server.registerTool("atlas_project_summary", { description: "Return project identity and graph statistics." }, async () => result({ project: graph.project, stats: graph.stats })); | ||
| await server.connect(new StdioServerTransport()); | ||
| console.error(`Atlas MCP server ready: ${graphPath}`); | ||
| } | ||
| export { | ||
| startMcpServer | ||
| }; | ||
| //# sourceMappingURL=server-UI74K4P7.js.map |
| {"version":3,"sources":["../src/mcp/server.ts"],"sourcesContent":["import { readFile } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport * as z from \"zod/v4\";\nimport { GraphQuery } from \"../core/graph.js\";\nimport type { ArchitectureGraph } from \"../core/types.js\";\n\nexport async function startMcpServer(projectPath: string, outputPath = \".atlas\"): Promise<void> {\n const graphPath = resolve(projectPath, outputPath, \"graph.json\");\n const graph = JSON.parse(await readFile(graphPath, \"utf8\")) as ArchitectureGraph;\n const query = new GraphQuery(graph);\n const server = new McpServer({ name: \"atlas\", version: graph.version });\n const result = (data: Record<string, unknown>) => ({\n content: [{ type: \"text\" as const, text: JSON.stringify(data, null, 2) }],\n structuredContent: data,\n });\n\n server.registerTool(\"atlas_find_node\", {\n description: \"Find architecture nodes by name, label, type, file, route, or metadata.\",\n inputSchema: { query: z.string().min(1) },\n }, async ({ query: value }) => result({ results: query.findNode(value) }));\n\n server.registerTool(\"atlas_get_node\", {\n description: \"Get one node and its incoming, outgoing, and method relationships.\",\n inputSchema: { id: z.string().min(1) },\n }, async ({ id }) => {\n const node = query.getNode(id);\n const outgoing = query.getOutgoing(id);\n const methods = outgoing.filter((edge) => edge.type === \"has_method\").map((edge) => query.getNode(edge.to)).filter(Boolean);\n return result({ node, incoming: query.getIncoming(id), outgoing, methods });\n });\n\n server.registerTool(\"atlas_get_dependencies\", {\n description: \"Traverse outgoing architecture dependencies from a node.\",\n inputSchema: { id: z.string().min(1), depth: z.number().int().min(1).max(10).default(2) },\n }, async ({ id, depth }) => result({ graph: query.findDependencies(id, depth) }));\n\n server.registerTool(\"atlas_get_dependents\", {\n description: \"Traverse incoming architecture dependents of a node.\",\n inputSchema: { id: z.string().min(1), depth: z.number().int().min(1).max(10).default(2) },\n }, async ({ id, depth }) => result({ graph: query.findDependents(id, depth) }));\n\n server.registerTool(\"atlas_find_path\", {\n description: \"Find the shortest explainable architecture path between two exact node IDs.\",\n inputSchema: {\n from: z.string().min(1),\n to: z.string().min(1),\n direction: z.enum([\"outgoing\", \"both\"]).default(\"outgoing\"),\n maxDepth: z.number().int().min(1).max(50).default(20),\n },\n }, async ({ from, to, direction, maxDepth }) => result({\n from: query.getNode(from),\n to: query.getNode(to),\n path: query.findPath(from, to, direction, maxDepth),\n }));\n\n server.registerTool(\"atlas_find_routes\", { description: \"List all detected HTTP routes.\" }, async () => result({ routes: query.findRoutes() }));\n\n server.registerTool(\"atlas_find_flow\", {\n description: \"Find a route and return its route-to-controller-to-service-to-data flow.\",\n inputSchema: { query: z.string().min(1) },\n }, async ({ query: value }) => {\n const route = query.findNode(value).find((node) => node.type === \"route\");\n return result({ route: route ?? null, flow: route ? query.findFlowFromRoute(route.id) : { nodes: [], edges: [] } });\n });\n\n server.registerTool(\"atlas_find_tables\", { description: \"List detected database tables.\" }, async () => result({ tables: query.findTables() }));\n server.registerTool(\"atlas_find_data_model\", { description: \"List schemas, tables, indexes, constraints, migrations, and ClickHouse structures.\" }, async () => result({\n schemas: query.findSchemas(), tables: query.findTables(), indexes: query.findIndexes(), constraints: query.findConstraints(), migrations: query.findMigrations(),\n }));\n server.registerTool(\"atlas_get_table_profile\", {\n description: \"Return a table with its columns, indexes, constraints, relations, migrations, readers, and writers.\",\n inputSchema: { query: z.string().min(1) },\n }, async ({ query: value }) => {\n const table = query.findNode(value).find((node) => node.type === \"table\");\n return result({ table: table ?? null, profile: table ? query.findTableProfile(table.id) : { nodes: [], edges: [] } });\n });\n server.registerTool(\"atlas_find_migrations\", { description: \"List migrations and the structures they create, alter, or drop.\" }, async () => result({ migrations: query.findMigrations() }));\n server.registerTool(\"atlas_find_external_apis\", { description: \"List detected external API hosts.\" }, async () => result({ externalApis: query.findExternalApis() }));\n\n server.registerTool(\"atlas_find_async_flows\", {\n description: \"List detected Kafka or RabbitMQ topics, Bull/BullMQ queues, and background processors.\",\n }, async () => result({ topics: query.findMessageTopics(), queues: query.findQueues(), processors: query.findProcessors() }));\n\n server.registerTool(\"atlas_find_async_flow\", {\n description: \"Find a message topic or queue and return publishers, consumers, processors, and downstream calls.\",\n inputSchema: { query: z.string().min(1) },\n }, async ({ query: value }) => {\n const root = query.findNode(value).find((node) => [\"message_topic\", \"queue\"].includes(node.type));\n return result({ root: root ?? null, flow: root ? query.findAsyncFlow(root.id) : { nodes: [], edges: [] } });\n });\n\n server.registerTool(\"atlas_find_schedules\", { description: \"List cron, interval, timeout, repeatable queue, and Kubernetes scheduled jobs.\" }, async () => result({ schedules: query.findScheduledJobs() }));\n server.registerTool(\"atlas_find_delivery\", { description: \"List CI/CD workflows and runtime deployments.\" }, async () => result({ workflows: query.findWorkflows(), deployments: query.findDeployments() }));\n server.registerTool(\"atlas_find_environments\", { description: \"List detected development, staging, production, and custom runtime environments.\" }, async () => result({ environments: query.findEnvironments() }));\n\n server.registerTool(\"atlas_search\", {\n description: \"Search the complete architecture graph.\",\n inputSchema: { query: z.string().min(1) },\n }, async ({ query: value }) => result({ results: query.search(value) }));\n\n server.registerTool(\"atlas_project_summary\", { description: \"Return project identity and graph statistics.\" }, async () => result({ project: graph.project, stats: graph.stats }));\n\n await server.connect(new StdioServerTransport());\n console.error(`Atlas MCP server ready: ${graphPath}`);\n}\n"],"mappings":"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","names":[]} |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
1432560
0.06%8055
0.2%