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

@@ -56,9 +56,14 @@ // src/cli/index.ts

program.command("mcp").description("Start the Atlas MCP server over stdio").option("-p, --path <path>", "project root", ".").option("-o, --output <path>", "Atlas output directory relative to the project", ".atlas").action(async ({ path, output }) => {
const { startMcpServer } = await import("../server-UI74K4P7.js");
const { startMcpServer } = await import("../server-4KJYDYJS.js");
await startMcpServer(resolve(path), output);
});
program.parseAsync(process.argv).catch((error) => {
console.error(`Atlas error: ${error instanceof Error ? error.message : String(error)}`);
const isDebug = process.argv.includes("--debug");
if (error instanceof Error) {
console.error(`Atlas error: ${isDebug ? error.stack : error.message}`);
} else {
console.error(`Atlas error: ${String(error)}`);
}
process.exitCode = 1;
});
//# sourceMappingURL=index.js.map

@@ -1,1 +0,1 @@

{"version":3,"sources":["../../src/cli/index.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { access } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\nimport { Command } from \"commander\";\nimport { ATLAS_VERSION } from \"../version.js\";\n\nconst program = new Command();\nprogram.name(\"atlas\").description(\"Local architecture intelligence for NestJS projects\").version(ATLAS_VERSION);\n\nprogram.command(\"scan\")\n .description(\"Scan a local NestJS project and generate its architecture graph\")\n .option(\"-p, --path <path>\", \"project root\", \".\")\n .option(\"-o, --output <path>\", \"output directory relative to the project\", \".atlas\")\n .option(\"--format <format>\", \"output format\", \"json\")\n .option(\"--no-cache\", \"ignore the previous Atlas analysis and scan everything again\")\n .option(\"--debug\", \"show diagnostic details\", false)\n .action(async (options) => {\n if (options.format !== \"json\") throw new Error(`Unsupported format: ${options.format}. Use json.`);\n const { scanProject } = await import(\"../index.js\");\n console.log(\"Atlas scan started\");\n const result = await scanProject({\n projectPath: options.path,\n outputPath: options.output,\n incremental: options.cache,\n debug: options.debug,\n onProgress: ({ message }) => console.log(message),\n });\n console.log(`Graph created: ${result.graph.stats.totalNodes} nodes, ${result.graph.stats.totalEdges} edges`);\n console.log(`Risks detected: ${result.risks.length}`);\n console.log(`Viewer created: ${resolve(result.outputPath, \"viewer\", \"index.html\")}`);\n console.log(\"Done\");\n });\n\nprogram.command(\"open\")\n .description(\"Open the generated static viewer\")\n .option(\"-p, --path <path>\", \"project root\", \".\")\n .option(\"-o, --output <path>\", \"Atlas output directory relative to the project\", \".atlas\")\n .action(async ({ path, output }) => {\n const { openBrowser } = await import(\"../server/open-browser.js\");\n const file = resolve(path, output, \"viewer\", \"index.html\");\n await access(file);\n await openBrowser(file);\n console.log(`Opened ${file}`);\n });\n\nprogram.command(\"serve\")\n .description(\"Serve the generated viewer on localhost\")\n .option(\"-p, --path <path>\", \"project root\", \".\")\n .option(\"-o, --output <path>\", \"Atlas output directory relative to the project\", \".atlas\")\n .option(\"--port <port>\", \"local port\", \"4317\")\n .option(\"--open\", \"open the viewer in a browser\", false)\n .action(async ({ path, output, port, open }) => {\n const numericPort = Number.parseInt(port, 10);\n if (!Number.isInteger(numericPort) || numericPort < 1 || numericPort > 65535) throw new Error(`Invalid port: ${port}`);\n const { serveViewer } = await import(\"../server/viewer-server.js\");\n await serveViewer(resolve(path, output, \"viewer\"), numericPort);\n if (open) {\n const { openBrowser } = await import(\"../server/open-browser.js\");\n await openBrowser(`http://localhost:${numericPort}`);\n }\n });\n\nprogram.command(\"report\")\n .description(\"Regenerate report.md from graph.json and risks.json\")\n .option(\"-p, --path <path>\", \"project root\", \".\")\n .option(\"-o, --output <path>\", \"Atlas output directory relative to the project\", \".atlas\")\n .action(async ({ path, output }) => {\n const { regenerateReport } = await import(\"../index.js\");\n console.log(`Report created: ${await regenerateReport(resolve(path), output)}`);\n });\n\nprogram.command(\"merge-runtime\")\n .description(\"Merge locally observed runtime links into the generated architecture graph\")\n .option(\"-p, --path <path>\", \"project root\", \".\")\n .option(\"-o, --output <path>\", \"Atlas output directory relative to the project\", \".atlas\")\n .option(\"-i, --input <path>\", \"runtime JSONL file relative to the project\")\n .action(async ({ path, output, input }) => {\n const { mergeRuntimeTrace } = await import(\"../index.js\");\n const result = await mergeRuntimeTrace(path, output, input);\n console.log(`Runtime evidence merged: ${result.metadata.runtimeEvents ?? 0} observations`);\n console.log(`Graph updated: ${result.graph.stats.totalNodes} nodes, ${result.graph.stats.totalEdges} edges`);\n });\n\nprogram.command(\"mcp\")\n .description(\"Start the Atlas MCP server over stdio\")\n .option(\"-p, --path <path>\", \"project root\", \".\")\n .option(\"-o, --output <path>\", \"Atlas output directory relative to the project\", \".atlas\")\n .action(async ({ path, output }) => {\n const { startMcpServer } = await import(\"../mcp/server.js\");\n await startMcpServer(resolve(path), output);\n });\n\nprogram.parseAsync(process.argv).catch((error: unknown) => {\n console.error(`Atlas error: ${error instanceof Error ? error.message : String(error)}`);\n process.exitCode = 1;\n});\n"],"mappings":"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","names":[]}
{"version":3,"sources":["../../src/cli/index.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { access } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\nimport { Command } from \"commander\";\nimport { ATLAS_VERSION } from \"../version.js\";\n\nconst program = new Command();\nprogram.name(\"atlas\").description(\"Local architecture intelligence for NestJS projects\").version(ATLAS_VERSION);\n\nprogram.command(\"scan\")\n .description(\"Scan a local NestJS project and generate its architecture graph\")\n .option(\"-p, --path <path>\", \"project root\", \".\")\n .option(\"-o, --output <path>\", \"output directory relative to the project\", \".atlas\")\n .option(\"--format <format>\", \"output format\", \"json\")\n .option(\"--no-cache\", \"ignore the previous Atlas analysis and scan everything again\")\n .option(\"--debug\", \"show diagnostic details\", false)\n .action(async (options) => {\n if (options.format !== \"json\") throw new Error(`Unsupported format: ${options.format}. Use json.`);\n const { scanProject } = await import(\"../index.js\");\n console.log(\"Atlas scan started\");\n const result = await scanProject({\n projectPath: options.path,\n outputPath: options.output,\n incremental: options.cache,\n debug: options.debug,\n onProgress: ({ message }) => console.log(message),\n });\n console.log(`Graph created: ${result.graph.stats.totalNodes} nodes, ${result.graph.stats.totalEdges} edges`);\n console.log(`Risks detected: ${result.risks.length}`);\n console.log(`Viewer created: ${resolve(result.outputPath, \"viewer\", \"index.html\")}`);\n console.log(\"Done\");\n });\n\nprogram.command(\"open\")\n .description(\"Open the generated static viewer\")\n .option(\"-p, --path <path>\", \"project root\", \".\")\n .option(\"-o, --output <path>\", \"Atlas output directory relative to the project\", \".atlas\")\n .action(async ({ path, output }) => {\n const { openBrowser } = await import(\"../server/open-browser.js\");\n const file = resolve(path, output, \"viewer\", \"index.html\");\n await access(file);\n await openBrowser(file);\n console.log(`Opened ${file}`);\n });\n\nprogram.command(\"serve\")\n .description(\"Serve the generated viewer on localhost\")\n .option(\"-p, --path <path>\", \"project root\", \".\")\n .option(\"-o, --output <path>\", \"Atlas output directory relative to the project\", \".atlas\")\n .option(\"--port <port>\", \"local port\", \"4317\")\n .option(\"--open\", \"open the viewer in a browser\", false)\n .action(async ({ path, output, port, open }) => {\n const numericPort = Number.parseInt(port, 10);\n if (!Number.isInteger(numericPort) || numericPort < 1 || numericPort > 65535) throw new Error(`Invalid port: ${port}`);\n const { serveViewer } = await import(\"../server/viewer-server.js\");\n await serveViewer(resolve(path, output, \"viewer\"), numericPort);\n if (open) {\n const { openBrowser } = await import(\"../server/open-browser.js\");\n await openBrowser(`http://localhost:${numericPort}`);\n }\n });\n\nprogram.command(\"report\")\n .description(\"Regenerate report.md from graph.json and risks.json\")\n .option(\"-p, --path <path>\", \"project root\", \".\")\n .option(\"-o, --output <path>\", \"Atlas output directory relative to the project\", \".atlas\")\n .action(async ({ path, output }) => {\n const { regenerateReport } = await import(\"../index.js\");\n console.log(`Report created: ${await regenerateReport(resolve(path), output)}`);\n });\n\nprogram.command(\"merge-runtime\")\n .description(\"Merge locally observed runtime links into the generated architecture graph\")\n .option(\"-p, --path <path>\", \"project root\", \".\")\n .option(\"-o, --output <path>\", \"Atlas output directory relative to the project\", \".atlas\")\n .option(\"-i, --input <path>\", \"runtime JSONL file relative to the project\")\n .action(async ({ path, output, input }) => {\n const { mergeRuntimeTrace } = await import(\"../index.js\");\n const result = await mergeRuntimeTrace(path, output, input);\n console.log(`Runtime evidence merged: ${result.metadata.runtimeEvents ?? 0} observations`);\n console.log(`Graph updated: ${result.graph.stats.totalNodes} nodes, ${result.graph.stats.totalEdges} edges`);\n });\n\nprogram.command(\"mcp\")\n .description(\"Start the Atlas MCP server over stdio\")\n .option(\"-p, --path <path>\", \"project root\", \".\")\n .option(\"-o, --output <path>\", \"Atlas output directory relative to the project\", \".atlas\")\n .action(async ({ path, output }) => {\n const { startMcpServer } = await import(\"../mcp/server.js\");\n await startMcpServer(resolve(path), output);\n });\n\nprogram.parseAsync(process.argv).catch((error: unknown) => {\n const isDebug = process.argv.includes(\"--debug\");\n if (error instanceof Error) {\n console.error(`Atlas error: ${isDebug ? error.stack : error.message}`);\n } else {\n console.error(`Atlas error: ${String(error)}`);\n }\n process.exitCode = 1;\n});\n"],"mappings":"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","names":[]}
{
"name": "@dthreads/atlas",
"version": "0.4.1",
"version": "0.4.2",
"description": "Architecture intelligence for NestJS codebases.",

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

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

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

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