🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@dthreads/atlas

Package Overview
Dependencies
Maintainers
1
Versions
6
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@dthreads/atlas - npm Package Compare versions

Comparing version
0.2.0
to
0.3.0
+395
dist/chunk-4WKRCGRX.js
import {
ATLAS_VERSION
} from "./chunk-DWXUUWMF.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);
}
byType(type) {
return this.nodesByType.get(type) ?? [];
}
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 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-4WKRCGRX.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 private byType(type: GraphNode[\"type\"]): GraphNode[] {\n return this.nodesByType.get(type) ?? [];\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 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.3.0";
export {
ATLAS_VERSION
};
//# sourceMappingURL=chunk-DWXUUWMF.js.map
{"version":3,"sources":["../src/version.ts"],"sourcesContent":["export const ATLAS_VERSION = \"0.3.0\";\n"],"mappings":";AAAO,IAAM,gBAAgB;","names":[]}
import {
GraphQuery
} from "./chunk-4WKRCGRX.js";
import "./chunk-DWXUUWMF.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_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-WM7LIGZ5.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_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":[]}
+13
-3
#!/usr/bin/env node
import {
ATLAS_VERSION
} from "../chunk-DWXUUWMF.js";

@@ -8,4 +11,4 @@ // src/cli/index.ts

var program = new Command();
program.name("atlas").description("Local architecture intelligence for NestJS projects").version("0.1.0");
program.command("scan").description("Scan a local NestJS project and generate its architecture graph").option("-p, --path <path>", "project root", ".").option("-o, --output <path>", "output directory relative to the project", ".atlas").option("--format <format>", "output format", "json").option("--debug", "show diagnostic details", false).action(async (options) => {
program.name("atlas").description("Local architecture intelligence for NestJS projects").version(ATLAS_VERSION);
program.command("scan").description("Scan a local NestJS project and generate its architecture graph").option("-p, --path <path>", "project root", ".").option("-o, --output <path>", "output directory relative to the project", ".atlas").option("--format <format>", "output format", "json").option("--no-cache", "ignore the previous Atlas analysis and scan everything again").option("--debug", "show diagnostic details", false).action(async (options) => {
if (options.format !== "json") throw new Error(`Unsupported format: ${options.format}. Use json.`);

@@ -17,2 +20,3 @@ const { scanProject } = await import("../index.js");

outputPath: options.output,
incremental: options.cache,
debug: options.debug,

@@ -47,4 +51,10 @@ onProgress: ({ message }) => console.log(message)

});
program.command("merge-runtime").description("Merge locally observed runtime links into the generated architecture graph").option("-p, --path <path>", "project root", ".").option("-o, --output <path>", "Atlas output directory relative to the project", ".atlas").option("-i, --input <path>", "runtime JSONL file relative to the project").action(async ({ path, output, input }) => {
const { mergeRuntimeTrace } = await import("../index.js");
const result = await mergeRuntimeTrace(path, output, input);
console.log(`Runtime evidence merged: ${result.metadata.runtimeEvents ?? 0} observations`);
console.log(`Graph updated: ${result.graph.stats.totalNodes} nodes, ${result.graph.stats.totalEdges} edges`);
});
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-MDSHY22G.js");
const { startMcpServer } = await import("../server-WM7LIGZ5.js");
await startMcpServer(resolve(path), output);

@@ -51,0 +61,0 @@ });

+1
-1

@@ -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\";\n\nconst program = new Command();\nprogram.name(\"atlas\").description(\"Local architecture intelligence for NestJS projects\").version(\"0.1.0\");\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(\"--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 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(\"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 console.error(`Atlas error: ${error instanceof Error ? error.message : String(error)}`);\n process.exitCode = 1;\n});\n"],"mappings":"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","names":[]}

@@ -7,3 +7,3 @@ import { Server } from 'node:http';

type GraphEdgeType = (typeof graphEdgeTypes)[number];
type GraphSourceType = "static_analysis" | "ast" | "config" | "package_json" | "heuristic" | "manual";
type GraphSourceType = "static_analysis" | "ast" | "config" | "package_json" | "heuristic" | "runtime" | "manual";
interface SourceLocation {

@@ -77,2 +77,11 @@ file: string;

filesIgnored: number;
filesHashed?: number;
filesReused?: number;
cacheHit?: boolean;
inputFingerprint?: string;
analysisCacheVersion?: number;
viewerFingerprint?: string;
runtimeEvents?: number;
runtimeMergedAt?: string;
runtimeFingerprint?: string;
detectedStacks: DetectedStack[];

@@ -109,2 +118,3 @@ }

outputPath?: string;
incremental?: boolean;
debug?: boolean;

@@ -119,2 +129,19 @@ onProgress?: (progress: ScanProgress) => void;

}
interface RuntimeTraceNode {
id: string;
type: GraphNodeType;
label?: string;
file?: string;
}
interface RuntimeTraceEvent {
from: string;
to: string;
type: GraphEdgeType;
timestamp?: string;
count?: number;
durationMs?: number;
fromNode?: RuntimeTraceNode;
toNode?: RuntimeTraceNode;
metadata?: Record<string, unknown>;
}

@@ -137,2 +164,6 @@ declare function enrichGraphDescriptions(graph: ArchitectureGraph): ArchitectureGraph;

private readonly nodeMap;
private readonly edgeMap;
private readonly incomingMap;
private readonly outgoingMap;
private readonly nodesByType;
constructor(graph: ArchitectureGraph);

@@ -186,12 +217,68 @@ findNode(query: string): GraphNode[];

ignored: number;
hashed: number;
reused: number;
}
interface FileScanOptions {
ignoredPaths?: string[];
cachePath?: string;
useCache?: boolean;
concurrency?: number;
}
declare function scanFiles(projectRoot: string, options?: FileScanOptions): Promise<FileScanResult>;
declare function readRuntimeEvents(path: string): Promise<RuntimeTraceEvent[]>;
declare function mergeRuntimeEvidence(graph: ArchitectureGraph, events: RuntimeTraceEvent[]): ArchitectureGraph;
interface RuntimeTracerOptions {
outputPath?: string;
flushIntervalMs?: number;
}
declare class RuntimeTracer {
private readonly outputPath;
private readonly flushIntervalMs;
private readonly pending;
private flushTimer;
constructor(options?: RuntimeTracerOptions);
record(event: RuntimeTraceEvent): void;
edge(from: string, to: string, type: GraphEdgeType, metadata?: Record<string, unknown>): void;
flush(): Promise<void>;
private scheduleFlush;
}
interface NestExecutionContextLike {
getClass(): {
name?: string;
};
getHandler(): {
name?: string;
};
getType?(): string;
switchToHttp?(): {
getRequest(): {
method?: string;
baseUrl?: string;
route?: {
path?: string;
};
url?: string;
};
};
switchToRpc?(): {
getContext(): {
getPattern?(): unknown;
pattern?: unknown;
};
};
}
interface NestCallHandlerLike {
handle(): unknown;
}
declare function createNestRuntimeInterceptor(tracer: RuntimeTracer): {
intercept(context: NestExecutionContextLike, next: NestCallHandlerLike): unknown;
};
declare function scanProject(options: ScanOptions): Promise<ScanResult>;
declare function loadGraph(projectPath: string, outputPath?: string): Promise<ArchitectureGraph>;
declare function regenerateReport(projectPath: string, outputPath?: string): Promise<string>;
declare function mergeRuntimeTrace(projectPath: string, outputPath?: string, inputPath?: string): Promise<ScanResult>;
export { type ArchitectureGraph, type ArchitectureRisk, type DetectedStack, type FileScanOptions, type FileScanResult, GraphBuilder, type GraphEdge, type GraphEdgeType, type GraphNode, type GraphNodeType, GraphQuery, type GraphSearchResult, type GraphSourceType, type GraphStats, type GraphSubgraph, type RiskSeverity, type ScanMetadata, type ScanOptions, type ScanProgress, type ScanProgressStage, type ScanResult, type ScannedFile, type SourceLocation, detectRisks, enrichGraphDescriptions, generateReport, getBrowserLaunch, graphEdgeTypes, graphNodeTypes, loadGraph, openBrowser, regenerateReport, scanFiles, scanProject, serveViewer };
export { type ArchitectureGraph, type ArchitectureRisk, type DetectedStack, type FileScanOptions, type FileScanResult, GraphBuilder, type GraphEdge, type GraphEdgeType, type GraphNode, type GraphNodeType, GraphQuery, type GraphSearchResult, type GraphSourceType, type GraphStats, type GraphSubgraph, type RiskSeverity, type RuntimeTraceEvent, type RuntimeTraceNode, RuntimeTracer, type RuntimeTracerOptions, type ScanMetadata, type ScanOptions, type ScanProgress, type ScanProgressStage, type ScanResult, type ScannedFile, type SourceLocation, createNestRuntimeInterceptor, detectRisks, enrichGraphDescriptions, generateReport, getBrowserLaunch, graphEdgeTypes, graphNodeTypes, loadGraph, mergeRuntimeEvidence, mergeRuntimeTrace, openBrowser, readRuntimeEvents, regenerateReport, scanFiles, scanProject, serveViewer };
{
"name": "@dthreads/atlas",
"version": "0.2.0",
"version": "0.3.0",
"description": "Architecture intelligence for NestJS codebases.",

@@ -5,0 +5,0 @@ "keywords": [

@@ -90,3 +90,3 @@ # Atlas

```bash
atlas scan [--path <project>] [--output <directory>] [--debug]
atlas scan [--path <project>] [--output <directory>] [--no-cache] [--debug]
```

@@ -99,2 +99,11 @@

Atlas keeps a local file manifest and reuses the generated architecture graph when
the supported source and configuration files have not changed. A warm scan avoids
parsing the project again. Use `--no-cache` after changing analyzer configuration or
whenever you explicitly want a complete scan:
```bash
atlas scan --path ../my-nest-app --no-cache
```
The scanner respects rules from the project's root `.gitignore`. It also skips

@@ -105,2 +114,15 @@ dependencies, generated output, caches, temporary directories, Git worktrees,

### `atlas merge-runtime`
Merges locally observed runtime links with the static graph and regenerates the
viewer. Existing static links are marked as runtime-confirmed; newly observed links
remain clearly identified as runtime evidence.
```bash
atlas merge-runtime [--path <project>] [--output <directory>] [--input <runtime.jsonl>]
```
The default input is `<project>/.atlas/runtime.jsonl`. Payloads, request bodies,
headers, message contents, and environment values are not recorded.
### `atlas open`

@@ -144,4 +166,8 @@

- modules, controllers, services, providers, and dependency injection;
- DI token bindings through `@Inject`, `useClass`, `useExisting`, and `useFactory`, including factory dependencies;
- `forwardRef`, `forRoot`, `forRootAsync`, `register`, and `registerAsync` module wiring;
- routes, controller methods, service methods, and method calls;
- Kafka publishers and consumers declared with `ClientKafka`, `@MessagePattern`, and `@EventPattern`;
- Kafka publishers and consumers declared with `ClientKafka`, KafkaJS, `@MessagePattern`, and `@EventPattern`;
- NestJS CQRS command, query, and event bus calls linked to their handlers;
- in-process events declared with `EventEmitter2` and `@OnEvent`;
- RabbitMQ handlers declared with `@RabbitSubscribe` and `@RabbitRPC`;

@@ -164,6 +190,48 @@ - Bull and BullMQ queues, producers, processors, and jobs;

Static analysis has limits. Dynamic modules, runtime-generated providers, reflection,
and indirect calls may not always be resolved. Every inferred graph item includes its
source and confidence so consumers can distinguish evidence from inference.
Static analysis has limits. Runtime-generated providers, reflection, and indirect
calls may not always be resolved from source alone. Every inferred graph item
includes its source and confidence. Optional runtime evidence can confirm important
paths without replacing or hiding the static evidence.
## Optional runtime evidence
Static analysis should remain the default. For local development or integration
tests, Atlas also exports a small NestJS interceptor that records route/RPC handler
transitions. It only records graph identifiers, timestamps, and counters.
```ts
import {
createNestRuntimeInterceptor,
RuntimeTracer,
} from "@dthreads/atlas";
const tracer = new RuntimeTracer({
outputPath: ".atlas/runtime.jsonl",
});
app.useGlobalInterceptors(createNestRuntimeInterceptor(tracer));
```
Call `await tracer.flush()` from the application's normal shutdown hook. Internal
transitions that cannot be observed by a NestJS interceptor can be recorded
explicitly:
```ts
tracer.edge(
"method:CheckoutService.checkout",
"message_topic:orders.created",
"publishes_to",
);
```
Run the application or its integration tests, then merge the observations:
```bash
atlas merge-runtime
atlas serve
```
Runtime tracing is opt-in and local. Do not commit `runtime.jsonl` when architecture
names are confidential.
## Generated files

@@ -173,2 +241,4 @@

.atlas/
cache/
files.json Local incremental-scan manifest
graph.json Typed nodes and relationships

@@ -178,2 +248,3 @@ metadata.json Scan time, file counts, stack evidence

report.md Human-readable architecture summary
runtime.jsonl Optional local runtime observations
viewer/

@@ -194,2 +265,7 @@ index.html Offline architecture application

Large scenes use adaptive detail: off-screen elements are not rendered, distant
cards switch to a lightweight form, edge labels appear when useful, and animation
is bounded. Catalogs load in pages and remain fully searchable, so a large project
does not need thousands of DOM elements just to open one focused flow.
The interactive viewer UX reference is stored in

@@ -277,6 +353,7 @@ [`docs/design/atlas-viewer-prototype.html`](docs/design/atlas-viewer-prototype.html).

The tests scan a representative NestJS fixture, validate route-to-database,
publisher-to-consumer, migration, schedule, and delivery flows, exercise all 18 MCP
publisher-to-consumer, DI-token, CQRS, runtime, migration, schedule, and delivery flows, exercise all 18 MCP
tools, verify architecture and deployment risks, and confirm that real secret values
never enter generated artifacts. The performance test generates 1,000
TypeScript files, 100 controllers, 300 services, and 1,000 routes.
never enter generated artifacts. The performance suite generates 1,000 TypeScript
files, 100 controllers, 300 services, and 1,000 routes; it also checks warm-scan
reuse, indexed graph queries, viewport culling, and bounded animation.

@@ -283,0 +360,0 @@ The detailed MVP requirements and their automated evidence are listed in

// 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: "0.1.0", 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]));
}
graph;
nodeMap;
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.graph.edges.filter((edge) => edge.to === id);
}
getOutgoing(id) {
return this.graph.edges.filter((edge) => edge.from === 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.graph.edges.filter((edge) => edgeTypes.has(edge.type) && (edge.from === tableId || edge.to === tableId));
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: this.graph.edges.filter((edge) => edgeIds.has(edge.id))
};
}
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: this.graph.edges.filter((edge) => edgeIds.has(edge.id))
};
}
findDependencies(nodeId, depth = 2) {
return this.walk(nodeId, "outgoing", depth);
}
findDependents(nodeId, depth = 2) {
return this.walk(nodeId, "incoming", depth);
}
byType(type) {
return this.graph.nodes.filter((node) => node.type === type);
}
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: this.graph.edges.filter((edge) => edgeIds.has(edge.id))
};
}
};
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,
GraphQuery
};
//# sourceMappingURL=chunk-M2XP6F7I.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 | \"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 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 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","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\";\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: \"0.1.0\", 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\n constructor(readonly graph: ArchitectureGraph) {\n this.nodeMap = new Map(graph.nodes.map((node) => [node.id, node]));\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.graph.edges.filter((edge) => edge.to === id);\n }\n\n getOutgoing(id: string): GraphEdge[] {\n return this.graph.edges.filter((edge) => edge.from === 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.graph.edges.filter((edge) => edgeTypes.has(edge.type) && (edge.from === tableId || edge.to === tableId));\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: this.graph.edges.filter((edge) => edgeIds.has(edge.id)),\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: this.graph.edges.filter((edge) => edgeIds.has(edge.id)),\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 private byType(type: GraphNode[\"type\"]): GraphNode[] {\n return this.graph.nodes.filter((node) => node.type === type);\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: this.graph.edges.filter((edge) => edgeIds.has(edge.id)),\n };\n }\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-M2XP6F7I.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_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-MDSHY22G.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_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

Sorry, the diff of this file is too big to display