@dreamtree-org/graphify 1.1.2 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -2
- package/dist/{chunk-PXVI2L45.js → chunk-NS5HB65S.js} +116 -42
- package/dist/chunk-NS5HB65S.js.map +1 -0
- package/dist/{chunk-YT7B6DOD.js → chunk-ZK3TA6FW.js} +33 -7
- package/dist/chunk-ZK3TA6FW.js.map +1 -0
- package/dist/cli/index.cjs +212 -55
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +67 -10
- package/dist/cli/index.js.map +1 -1
- package/dist/index.cjs +147 -47
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +16 -1
- package/dist/index.d.ts +16 -1
- package/dist/index.js +2 -2
- package/dist/mcp/server.cjs +26 -5
- package/dist/mcp/server.cjs.map +1 -1
- package/dist/mcp/server.js +1 -1
- package/package.json +1 -1
- package/src/skill/SKILL.md +9 -4
- package/dist/chunk-PXVI2L45.js.map +0 -1
- package/dist/chunk-YT7B6DOD.js.map +0 -1
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../node_modules/tsup/assets/cjs_shims.js","../src/detect.ts","../src/extract.ts","../src/extractors/csharp.ts","../src/extractors/common.ts","../src/extractors/wasmLoader.ts","../src/extractors/go.ts","../src/extractors/java.ts","../src/extractors/python.ts","../src/extractors/ruby.ts","../src/extractors/rust.ts","../src/extractors/typescript.ts","../src/build.ts","../src/schema.ts","../src/resolve.ts","../src/cluster.ts","../src/analyze.ts","../src/report.ts","../src/export.ts","../src/security.ts","../src/pipeline.ts","../src/extractionCache.ts","../src/graphStore.ts","../src/query.ts","../src/impact.ts","../src/merge.ts","../src/extractors/mysql.ts","../src/memory.ts","../src/context.ts","../src/testmap.ts","../src/diff.ts","../src/check.ts"],"sourcesContent":["export { collectFiles } from './detect.js';\nexport { extract, EXTRACTOR_REGISTRY } from './extract.js';\nexport { buildGraph } from './build.js';\nexport { resolveCrossFileReferences } from './resolve.js';\nexport type { ResolveStats } from './resolve.js';\nexport { cluster } from './cluster.js';\nexport type { ClusterAlgorithm, ClusterOptions } from './cluster.js';\nexport { analyze } from './analyze.js';\nexport { renderReport } from './report.js';\nexport { exportGraph } from './export.js';\nexport { runPipeline } from './pipeline.js';\nexport type { PipelineOptions, PipelineResult } from './pipeline.js';\nexport { loadGraph } from './graphStore.js';\nexport { queryGraph, shortestPath, explainNode, scoreNodes, resolveNode } from './query.js';\nexport { affectedBy } from './impact.js';\nexport type { AffectedNode, ImpactOptions, ImpactResult } from './impact.js';\nexport { mergeGraphs } from './merge.js';\nexport type { MergeEntry } from './merge.js';\nexport { extractMysql } from './extractors/mysql.js';\nexport type { DsnQueryFn } from './extractors/mysql.js';\nexport { saveResult, loadResults, renderLessons } from './memory.js';\nexport type { SavedResult, ResultOutcome, ResultType, ReflectOptions } from './memory.js';\nexport { buildContextPack, renderContextPack, rankForTask } from './context.js';\nexport type { ContextPack, ContextSnippet, ContextOptions } from './context.js';\nexport { testsForNode, testsForChangedFiles, isTestFile } from './testmap.js';\nexport type { TestSelection } from './testmap.js';\nexport { reviewRevisions, diffGraphs, graphForDirectory, renderReview } from './diff.js';\nexport type { GraphDiff, ChangedSymbol, RewiredSymbol } from './diff.js';\nexport { checkRules, validateRules, globToRegExp } from './check.js';\nexport type { DependencyRule, RulesConfig, Violation } from './check.js';\nexport { ExtractionCache } from './extractionCache.js';\nexport type {\n NodeMatch,\n QueryOptions,\n QueryResult,\n PathResult,\n ExplainResult,\n TraversalEdge,\n VisitedNode,\n} from './query.js';\nexport {\n validateExtraction,\n ExtractionValidationError,\n ExtractionResultSchema,\n} from './schema.js';\nexport type { ExtractionValidationIssue } from './schema.js';\nexport * from './types.js';\n","// Shim globals in cjs bundle\n// There's a weird bug that esbuild will always inject importMetaUrl\n// if we export it as `const importMetaUrl = ... __filename ...`\n// But using a function will not cause this issue\n\nconst getImportMetaUrl = () => \n typeof document === \"undefined\" \n ? new URL(`file:${__filename}`).href \n : (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') \n ? document.currentScript.src \n : new URL(\"main.js\", document.baseURI).href;\n\nexport const importMetaUrl = /* @__PURE__ */ getImportMetaUrl()\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { FileCategory, FileManifest } from './types.js';\n\n/** Directories that are never worth walking into. */\nconst SKIP_DIRS = new Set([\n 'node_modules',\n '.git',\n 'dist',\n 'build',\n 'out',\n 'graphify-out',\n '.next',\n '.venv',\n 'venv',\n '__pycache__',\n '.cache',\n 'coverage',\n '.turbo',\n]);\n\nconst CODE_EXTENSIONS = new Set([\n '.ts',\n '.tsx',\n '.js',\n '.jsx',\n '.mjs',\n '.cjs',\n '.mts',\n '.cts',\n '.py',\n '.go',\n '.rs',\n '.java',\n '.cs',\n '.rb',\n '.c',\n '.h',\n '.cpp',\n '.hpp',\n '.cc',\n '.php',\n '.kt',\n '.swift',\n '.scala',\n '.lua',\n '.sh',\n '.sql',\n]);\n\nconst DOCUMENT_EXTENSIONS = new Set(['.md', '.mdx', '.txt', '.rst', '.adoc', '.org', '.json', '.yaml', '.yml', '.toml']);\n\nconst PAPER_EXTENSIONS = new Set(['.pdf', '.tex', '.bib']);\n\nconst IMAGE_EXTENSIONS = new Set(['.png', '.jpg', '.jpeg', '.gif', '.svg', '.webp', '.bmp', '.ico']);\n\nconst VIDEO_EXTENSIONS = new Set(['.mp4', '.mov', '.avi', '.mkv', '.webm']);\n\n/**\n * Filenames or name fragments that must never be read into the graph or an\n * LLM prompt — credentials, secrets, key material. Skipped into\n * `skippedSensitive` rather than silently ignored, so a run's manifest is\n * auditable.\n */\nconst SENSITIVE_NAME_PATTERNS: RegExp[] = [\n /^\\.env(\\..*)?$/i,\n /^\\.npmrc$/i,\n /^\\.pypirc$/i,\n /credentials/i,\n /secret/i,\n /^id_rsa$/i,\n /^id_ed25519$/i,\n /\\.pem$/i,\n /\\.key$/i,\n /\\.pfx$/i,\n /\\.p12$/i,\n /^\\.aws\\//i,\n /service[-_]?account.*\\.json$/i,\n];\n\nfunction isSensitiveName(name: string): boolean {\n return SENSITIVE_NAME_PATTERNS.some((pattern) => pattern.test(name));\n}\n\nfunction categorize(ext: string): FileCategory | null {\n const lower = ext.toLowerCase();\n if (CODE_EXTENSIONS.has(lower)) return 'code';\n if (DOCUMENT_EXTENSIONS.has(lower)) return 'document';\n if (PAPER_EXTENSIONS.has(lower)) return 'paper';\n if (IMAGE_EXTENSIONS.has(lower)) return 'image';\n if (VIDEO_EXTENSIONS.has(lower)) return 'video';\n return null;\n}\n\nfunction countWords(content: string): number {\n const trimmed = content.trim();\n if (trimmed.length === 0) return 0;\n return trimmed.split(/\\s+/).length;\n}\n\n/** Decode a file's bytes as UTF-8 with a replacement strategy — never throw on invalid bytes. */\nfunction readTextSafely(filePath: string): string {\n const buf = fs.readFileSync(filePath);\n return buf.toString('utf-8');\n}\n\n/**\n * Walk `root` and categorize files into code/document/paper/image/video\n * buckets. Does not follow symlinks (security.ts §5 — symlink traversal).\n * Sensitive-looking files (.env, credentials, key material) are recorded in\n * `skippedSensitive` and excluded from every other bucket/count.\n */\nexport function collectFiles(root: string): FileManifest {\n const scanRoot = path.resolve(root);\n const stat = fs.statSync(scanRoot);\n if (!stat.isDirectory()) {\n throw new Error(`collectFiles: not a directory: ${scanRoot}`);\n }\n\n const files: Record<FileCategory, string[]> = {\n code: [],\n document: [],\n paper: [],\n image: [],\n video: [],\n };\n const skippedSensitive: string[] = [];\n let totalWords = 0;\n\n const stack: string[] = [scanRoot];\n const textCategories: Set<FileCategory> = new Set(['code', 'document', 'paper']);\n\n while (stack.length > 0) {\n const dir = stack.pop() as string;\n let entries: fs.Dirent[];\n try {\n entries = fs.readdirSync(dir, { withFileTypes: true });\n } catch {\n continue; // unreadable directory (permissions) — skip, don't crash the run\n }\n\n // Sort for deterministic traversal order.\n entries.sort((a, b) => a.name.localeCompare(b.name));\n\n for (const entry of entries) {\n if (entry.isSymbolicLink()) continue; // never follow symlinks\n\n const fullPath = path.join(dir, entry.name);\n const relPath = path.relative(scanRoot, fullPath);\n\n if (entry.isDirectory()) {\n if (SKIP_DIRS.has(entry.name) || entry.name.startsWith('.')) continue;\n stack.push(fullPath);\n continue;\n }\n\n if (!entry.isFile()) continue; // sockets, devices, fifos, etc.\n\n if (isSensitiveName(entry.name)) {\n skippedSensitive.push(relPath);\n continue;\n }\n\n const ext = path.extname(entry.name);\n const category = categorize(ext);\n if (category === null) continue; // unrecognized extension — not tracked\n\n files[category].push(relPath);\n\n if (textCategories.has(category)) {\n try {\n const content = readTextSafely(fullPath);\n totalWords += countWords(content);\n } catch {\n // Unreadable/binary-under-a-text-extension — degrade gracefully.\n }\n }\n }\n }\n\n for (const category of Object.keys(files) as FileCategory[]) {\n files[category].sort();\n }\n skippedSensitive.sort();\n\n const totalFiles = Object.values(files).reduce((sum, list) => sum + list.length, 0);\n\n return {\n scanRoot,\n files,\n totalFiles,\n totalWords,\n skippedSensitive,\n };\n}\n","import * as path from 'node:path';\nimport { extractCSharp } from './extractors/csharp.js';\nimport { extractGo } from './extractors/go.js';\nimport { extractJava } from './extractors/java.js';\nimport { extractPython } from './extractors/python.js';\nimport { extractRuby } from './extractors/ruby.js';\nimport { extractRust } from './extractors/rust.js';\nimport { extractTypeScript } from './extractors/typescript.js';\nimport type { ExtractionResult } from './types.js';\n\n/** `displayPath`, when given, is used for node ids/sourceFile instead of the read path — see extract(). */\nexport type Extractor = (path: string, displayPath?: string) => Promise<ExtractionResult>;\n\n/** File extension -> extractor module. Register new languages here. */\nexport const EXTRACTOR_REGISTRY: Record<string, Extractor> = {\n '.ts': extractTypeScript,\n '.tsx': extractTypeScript,\n '.js': extractTypeScript,\n '.jsx': extractTypeScript,\n '.mjs': extractTypeScript,\n '.cjs': extractTypeScript,\n '.mts': extractTypeScript,\n '.cts': extractTypeScript,\n '.py': extractPython,\n '.go': extractGo,\n '.rs': extractRust,\n '.java': extractJava,\n '.cs': extractCSharp,\n '.rb': extractRuby,\n};\n\n/**\n * Dispatch a single file to its language extractor. Returns an empty\n * extraction (not a thrown error) for unregistered extensions so detect's\n * file list and extract's coverage can diverge without crashing a run.\n *\n * `displayPath` decouples where the file is read from (relative to the\n * process cwd) from the path used in node ids and sourceFile attributes —\n * the pipeline passes the project-root-relative path so ids stay stable\n * and portable no matter which directory the pipeline was launched from\n * (this is what makes cross-project merging's namespacing meaningful).\n */\nexport async function extract(filePath: string, displayPath?: string): Promise<ExtractionResult> {\n const ext = path.extname(filePath);\n const extractor = EXTRACTOR_REGISTRY[ext];\n if (!extractor) {\n return { nodes: [], edges: [] };\n }\n return extractor(filePath, displayPath);\n}\n","import * as fs from 'node:fs/promises';\nimport type { Node as TSNode } from 'web-tree-sitter';\nimport type { ExtractionResult } from '../types.js';\nimport {\n ExtractionBuilder,\n descendantsOfType,\n entityId,\n externalId,\n lineOf,\n namedChildren,\n resolveModuleRef,\n toPosix,\n} from './common.js';\nimport { createParser } from './wasmLoader.js';\n\n/**\n * Structural extraction for .cs via web-tree-sitter (WASM, no native\n * compilation, no eval/exec of source content).\n *\n * Like Java, C# has no free top-level functions — methods live inside a\n * class or interface — but unlike Java, top-level types are usually\n * nested one level deeper inside a `namespace Foo { ... }` block, so pass\n * 1 flattens namespace bodies (recursively, for nested namespaces) before\n * walking classes/interfaces/methods, exactly as if their members were\n * declared at the top level.\n *\n * C#'s base-type list (`class Calculator : Base, IGreeter`) doesn't\n * distinguish a base class from an implemented interface syntactically —\n * that's only knowable from the *referenced* declaration. The one\n * compiler-enforced rule this grammar does guarantee is ordering: a base\n * class, if present, must be listed first. So the first entry becomes an\n * `inherits` edge and every subsequent entry becomes `implements` — a\n * deliberate best-effort heuristic, not a guarantee.\n *\n * Every `invocation_expression` is resolved (pass 2): a same-file\n * method/`this.Method()` call resolved against the enclosing class is\n * EXTRACTED; a call qualified by a `using Alias = Namespace.Type;`\n * binding (or an unqualified call resolved only through one) is\n * INFERRED — the \"cross-file second pass\" placeholder described in the\n * master prompt §3. It intentionally does not open and parse the\n * referenced type to confirm the target. An unresolvable callee produces\n * no edge at all.\n */\nexport async function extractCSharp(filePath: string, displayPath?: string): Promise<ExtractionResult> {\n const parser = await createParser('c_sharp');\n\n const raw = await fs.readFile(filePath);\n const content = raw.toString('utf-8'); // replacement-decoded — never throws on invalid bytes\n\n const tree = parser.parse(content);\n if (!tree) {\n throw new Error(`extractCSharp: parser produced no tree for ${filePath}`);\n }\n const root = tree.rootNode;\n\n const sourceFile = toPosix(displayPath ?? filePath);\n const builder = new ExtractionBuilder();\n const fileId = sourceFile;\n builder.addNode({ id: fileId, label: sourceFile, sourceFile, sourceLocation: 'L1' });\n\n /** Declared name (class/interface) -> our graph id. */\n const nameIndex = new Map<string, string>();\n /** tree-sitter node id -> our graph id, for every method entity we track. */\n const functionNodeMap = new Map<number, string>();\n /** tree-sitter class/interface declaration node id -> method name -> our graph id. */\n const classMethods = new Map<number, Map<string, string>>();\n /** tree-sitter method_declaration node id -> its enclosing type's node id. */\n const enclosingClassOf = new Map<number, number>();\n /** local binding name (`using Alias = ...`) -> the module it came from. */\n const importIndex = new Map<string, ReturnType<typeof resolveModuleRef>>();\n\n function addModuleNode(ref: ReturnType<typeof resolveModuleRef>): void {\n if (builder.hasNode(ref.id)) return;\n builder.addNode({\n id: ref.id,\n label: ref.label,\n sourceFile: ref.external ? '<external>' : ref.id,\n sourceLocation: 'L1',\n });\n }\n\n function resolveHeritageTarget(name: string): string {\n const resolved = nameIndex.get(name);\n if (resolved) return resolved;\n const extId = externalId(name);\n if (!builder.hasNode(extId)) {\n builder.addNode({ id: extId, label: name, sourceFile: '<external>', sourceLocation: 'L0' });\n }\n return extId;\n }\n\n function handleUsingDirective(node: TSNode): void {\n const children = namedChildren(node);\n const first = children[0];\n if (!first) return;\n\n let aliasName: string | undefined;\n let targetNode: TSNode | undefined;\n if (first.type === 'name_equals') {\n aliasName = namedChildren(first)[0]?.text;\n targetNode = children[1];\n } else {\n targetNode = first;\n }\n if (!targetNode) return;\n\n const ref = resolveModuleRef(sourceFile, targetNode.text);\n addModuleNode(ref);\n if (aliasName) importIndex.set(aliasName, ref);\n builder.addEdge({ source: fileId, target: ref.id, relation: 'imports', confidence: 'EXTRACTED' });\n }\n\n function handleMethodDeclaration(typeNode: TSNode, typeId: string, typeName: string, member: TSNode): void {\n const methodName = member.childForFieldName('name')?.text ?? '(anonymous)';\n const methodId = entityId(sourceFile, `${typeName}.${methodName}`);\n builder.addNode({\n id: methodId,\n label: `method ${typeName}.${methodName}`,\n sourceFile,\n sourceLocation: lineOf(member),\n });\n builder.addEdge({ source: typeId, target: methodId, relation: 'method', confidence: 'EXTRACTED' });\n\n let methods = classMethods.get(typeNode.id);\n if (!methods) {\n methods = new Map();\n classMethods.set(typeNode.id, methods);\n }\n methods.set(methodName, methodId);\n functionNodeMap.set(member.id, methodId);\n enclosingClassOf.set(member.id, typeNode.id);\n }\n\n function handleBaseList(typeId: string, node: TSNode): void {\n const baseList = node.childForFieldName('bases');\n if (!baseList) return;\n const entries = namedChildren(baseList);\n entries.forEach((entry, index) => {\n builder.addEdge({\n source: typeId,\n target: resolveHeritageTarget(entry.text),\n relation: index === 0 ? 'inherits' : 'implements',\n confidence: 'EXTRACTED',\n });\n });\n }\n\n function handleClassDeclaration(node: TSNode): void {\n const name = node.childForFieldName('name')?.text ?? '(anonymous)';\n const classId = entityId(sourceFile, name);\n builder.addNode({ id: classId, label: `class ${name}`, sourceFile, sourceLocation: lineOf(node) });\n builder.addEdge({ source: fileId, target: classId, relation: 'contains', confidence: 'EXTRACTED' });\n nameIndex.set(name, classId);\n functionNodeMap.set(node.id, classId);\n classMethods.set(node.id, new Map());\n\n handleBaseList(classId, node);\n\n const body = node.childForFieldName('body');\n if (body) {\n for (const member of namedChildren(body)) {\n if (member.type !== 'method_declaration') continue; // constructors intentionally not tracked\n handleMethodDeclaration(node, classId, name, member);\n }\n }\n }\n\n function handleInterfaceDeclaration(node: TSNode): void {\n const name = node.childForFieldName('name')?.text ?? '(anonymous)';\n const id = entityId(sourceFile, name);\n builder.addNode({ id, label: `interface ${name}`, sourceFile, sourceLocation: lineOf(node) });\n builder.addEdge({ source: fileId, target: id, relation: 'contains', confidence: 'EXTRACTED' });\n nameIndex.set(name, id);\n handleBaseList(id, node); // interface-extends-interface(s) — same shape as a class base list\n }\n\n // Pass 1: top-level declarations (usings, classes, interfaces),\n // flattening `namespace Foo { ... }` wrappers (recursively).\n function walkTopLevel(node: TSNode): void {\n for (const child of namedChildren(node)) {\n switch (child.type) {\n case 'using_directive':\n handleUsingDirective(child);\n break;\n case 'class_declaration':\n handleClassDeclaration(child);\n break;\n case 'interface_declaration':\n handleInterfaceDeclaration(child);\n break;\n case 'namespace_declaration': {\n const nsBody = child.childForFieldName('body');\n if (nsBody) walkTopLevel(nsBody);\n break;\n }\n case 'file_scoped_namespace_declaration':\n // `namespace Foo;` (C# 10+) — declarations are direct named\n // children of this node itself (no separate `body` field).\n walkTopLevel(child);\n break;\n default:\n break;\n }\n }\n }\n walkTopLevel(root);\n\n function closestTrackedCaller(node: TSNode): string {\n let current: TSNode | null = node.parent;\n while (current) {\n const tracked = functionNodeMap.get(current.id);\n if (tracked) return tracked;\n current = current.parent;\n }\n return fileId;\n }\n\n function closestEnclosingClassMethods(node: TSNode): Map<string, string> | undefined {\n let current: TSNode | null = node.parent;\n while (current) {\n if (current.type === 'method_declaration') {\n const typeNodeId = enclosingClassOf.get(current.id);\n if (typeNodeId !== undefined) return classMethods.get(typeNodeId);\n }\n current = current.parent;\n }\n return undefined;\n }\n\n // Pass 2: calls (see the function doc comment above for the\n // EXTRACTED/INFERRED policy).\n for (const call of descendantsOfType(root, ['invocation_expression'])) {\n const fn = call.childForFieldName('function');\n if (!fn) continue;\n\n let targetId: string | null = null;\n let confidence: 'EXTRACTED' | 'INFERRED' = 'EXTRACTED';\n\n if (fn.type === 'identifier') {\n const name = fn.text;\n const methodId = closestEnclosingClassMethods(call)?.get(name);\n if (methodId) {\n targetId = methodId;\n } else {\n const viaImport = importIndex.get(name);\n if (viaImport) {\n targetId = viaImport.id;\n confidence = 'INFERRED';\n }\n }\n } else if (fn.type === 'member_access_expression') {\n const expression = fn.childForFieldName('expression');\n const name = fn.childForFieldName('name')?.text;\n if (expression && name) {\n if (expression.type === 'this_expression') {\n const methodId = closestEnclosingClassMethods(call)?.get(name);\n if (methodId) targetId = methodId;\n } else if (expression.type === 'identifier') {\n const viaImport = importIndex.get(expression.text);\n if (viaImport) {\n targetId = viaImport.id;\n confidence = 'INFERRED';\n }\n }\n }\n }\n\n if (!targetId) continue; // unresolved callee (builtin, external value, ...) — no noisy guess\n const callerId = closestTrackedCaller(call);\n builder.addEdge({ source: callerId, target: targetId, relation: 'calls', confidence });\n }\n\n return builder.build();\n}\n","import * as path from 'node:path';\nimport type { Node as TSNode } from 'web-tree-sitter';\nimport type { ExtractionResult, GraphEdge, GraphNode } from '../types.js';\n\n/**\n * web-tree-sitter types `namedChildren`/`descendantsOfType` as\n * `(Node | null)[]` (a node slot can be null for a missing/erroneous\n * child). These two helpers give every extractor a non-null array to\n * iterate without repeating the same `.filter()` everywhere.\n */\nexport function namedChildren(node: TSNode): TSNode[] {\n return node.namedChildren.filter((c): c is TSNode => c !== null);\n}\n\nexport function descendantsOfType(node: TSNode, types: string | string[]): TSNode[] {\n return node.descendantsOfType(types).filter((c): c is TSNode => c !== null);\n}\n\n/** Normalize a path to forward slashes so ids/labels are stable across platforms. */\nexport function toPosix(p: string): string {\n return p.split(path.sep).join('/');\n}\n\n/** `tree-sitter` node shape narrowed to what id/location helpers need. */\nexport interface PositionedNode {\n startPosition: { row: number };\n}\n\n/** 1-based \"L<line>\" source location string, matching the schema example (`\"L42\"`). */\nexport function lineOf(node: PositionedNode): string {\n return `L${node.startPosition.row + 1}`;\n}\n\n/** Build a stable, file-scoped node id: unique across the whole graph once merged. */\nexport function entityId(sourceFile: string, qualifiedName: string): string {\n return `${toPosix(sourceFile)}::${qualifiedName}`;\n}\n\n/** Id for a reference we could not resolve to any declaration we saw (best-effort target). */\nexport function externalId(name: string): string {\n return `external:${name}`;\n}\n\nexport interface ModuleRef {\n id: string;\n label: string;\n /** true when the specifier is a bare package (not resolvable to an in-repo file). */\n external: boolean;\n}\n\n/**\n * Resolve an import/require specifier to a best-effort module id relative\n * to the importing file. This is intentionally lightweight (string/path\n * math only, no filesystem probing, no extension resolution) — it exists\n * so same-repo relative imports get a deterministic, file-shaped id that a\n * later cross-file pass (or a second extraction of the target file) can\n * line up against, not to fully replicate a module resolver.\n */\nexport function resolveModuleRef(sourceFile: string, specifier: string): ModuleRef {\n if (specifier.startsWith('.') || specifier.startsWith('/')) {\n const dir = path.posix.dirname(toPosix(sourceFile));\n const joined = specifier.startsWith('/') ? specifier : path.posix.join(dir, specifier);\n const normalized = path.posix.normalize(joined);\n return { id: normalized, label: specifier, external: false };\n }\n return { id: `module:${specifier}`, label: specifier, external: true };\n}\n\n/**\n * Accumulates nodes/edges for one file's ExtractionResult with node-id\n * dedup (a file can otherwise easily emit the same module/external\n * placeholder node twice — once per import, once per call resolution).\n */\nexport class ExtractionBuilder {\n private readonly nodeIds = new Set<string>();\n readonly nodes: GraphNode[] = [];\n readonly edges: GraphEdge[] = [];\n\n addNode(node: GraphNode): void {\n if (this.nodeIds.has(node.id)) return;\n this.nodeIds.add(node.id);\n this.nodes.push(node);\n }\n\n hasNode(id: string): boolean {\n return this.nodeIds.has(id);\n }\n\n addEdge(edge: GraphEdge): void {\n this.edges.push(edge);\n }\n\n build(): ExtractionResult {\n return { nodes: this.nodes, edges: this.edges };\n }\n}\n","import { createRequire } from 'node:module';\nimport { Language, Parser } from 'web-tree-sitter';\n\n/**\n * Shared web-tree-sitter bootstrapping for every language extractor.\n *\n * Pinned to web-tree-sitter@^0.25.x deliberately (not the newer 0.26.x\n * major that ships with the rest of the dependency set): 0.26 requires\n * every language grammar to carry a \"dylink.0\" WASM custom section (the\n * newer wasm dynamic-linking convention), but `tree-sitter-wasms`'s\n * prebuilt grammars still use the legacy \"dylink\" section — loading any\n * grammar under 0.26 throws `need dylink section` before a single file can\n * be parsed. 0.25.x accepts the legacy section and loads every grammar\n * `tree-sitter-wasms` ships. Revisit this pin once `tree-sitter-wasms`\n * republishes grammars built against a dylink.0-era tree-sitter-cli.\n */\n\nconst require = createRequire(import.meta.url);\n\nlet initPromise: Promise<void> | null = null;\n\nfunction ensureInitialized(): Promise<void> {\n if (!initPromise) {\n initPromise = Parser.init();\n }\n return initPromise;\n}\n\nconst languageCache = new Map<string, Promise<Language>>();\n\n/** Load (and cache) a tree-sitter-wasms grammar by its `tree-sitter-<name>.wasm` basename. */\nexport async function loadLanguage(grammarName: string): Promise<Language> {\n await ensureInitialized();\n let cached = languageCache.get(grammarName);\n if (!cached) {\n const wasmPath = require.resolve(`tree-sitter-wasms/out/tree-sitter-${grammarName}.wasm`);\n cached = Language.load(wasmPath);\n languageCache.set(grammarName, cached);\n }\n return cached;\n}\n\n/** Create a fresh Parser bound to the given grammar. Parsers are cheap and not thread-shared. */\nexport async function createParser(grammarName: string): Promise<Parser> {\n const language = await loadLanguage(grammarName);\n const parser = new Parser();\n parser.setLanguage(language);\n return parser;\n}\n","import * as fs from 'node:fs/promises';\nimport type { Node as TSNode } from 'web-tree-sitter';\nimport type { ExtractionResult } from '../types.js';\nimport {\n ExtractionBuilder,\n descendantsOfType,\n entityId,\n externalId,\n lineOf,\n namedChildren,\n resolveModuleRef,\n toPosix,\n} from './common.js';\nimport { createParser } from './wasmLoader.js';\n\n/** Strip the surrounding quotes tree-sitter keeps on an interpreted/raw string literal's text. */\nfunction stripQuotes(text: string): string {\n if (text.length >= 2) {\n const first = text[0];\n const last = text[text.length - 1];\n if ((first === '\"' || first === '`') && first === last) {\n return text.slice(1, -1);\n }\n }\n return text;\n}\n\n/** Default package qualifier Go infers from an import path when no explicit alias is given. */\nfunction defaultPackageQualifier(importPath: string): string {\n const segments = importPath.split('/');\n return segments[segments.length - 1] ?? importPath;\n}\n\n/**\n * Structural extraction for .go via web-tree-sitter (WASM, no native\n * compilation, no eval/exec of source content).\n *\n * Pattern mirrors typescript.ts, adapted to Go's shape: top-level named\n * types (struct/interface/defined types), functions, methods (declared\n * separately from their receiver type via `func (recv T) Name(...)`), and\n * imports (pass 1) -> every `call_expression` resolved against what pass 1\n * saw (pass 2). A same-file callee, or a call through the receiver\n * variable of the enclosing method onto a method of the same struct, is\n * EXTRACTED; a call through an imported package qualifier (e.g.\n * `m.Add(x, x)` where `m` is an import alias) is INFERRED — the\n * \"cross-file second pass\" placeholder described in the master prompt §3.\n * An unresolvable callee produces no edge at all.\n *\n * Go has no `extends`/`implements` clauses; struct embedding\n * (`type Calculator struct { Base }`) is the one heritage-like construct\n * Go's grammar exposes directly, so it becomes an `embeds` edge.\n */\nexport async function extractGo(filePath: string, displayPath?: string): Promise<ExtractionResult> {\n const parser = await createParser('go');\n\n const raw = await fs.readFile(filePath);\n const content = raw.toString('utf-8'); // replacement-decoded — never throws on invalid bytes\n\n const tree = parser.parse(content);\n if (!tree) {\n throw new Error(`extractGo: parser produced no tree for ${filePath}`);\n }\n const root = tree.rootNode;\n\n const sourceFile = toPosix(displayPath ?? filePath);\n const builder = new ExtractionBuilder();\n const fileId = sourceFile;\n builder.addNode({ id: fileId, label: sourceFile, sourceFile, sourceLocation: 'L1' });\n\n /** Declared name (function or named type) -> our graph id. */\n const nameIndex = new Map<string, string>();\n /** tree-sitter node id -> our graph id, for every function/method entity we track. */\n const functionNodeMap = new Map<number, string>();\n /** graph id of a named type -> method name -> our graph id. */\n const typeMethods = new Map<string, Map<string, string>>();\n /** tree-sitter method_declaration node id -> { receiver variable name, owning type's graph id }. */\n const receiverInfo = new Map<number, { varName: string; typeId: string }>();\n /** local package qualifier (import alias or inferred name) -> the module it came from. */\n const importIndex = new Map<string, ReturnType<typeof resolveModuleRef>>();\n\n function addModuleNode(ref: ReturnType<typeof resolveModuleRef>): void {\n if (builder.hasNode(ref.id)) return;\n builder.addNode({\n id: ref.id,\n label: ref.label,\n sourceFile: ref.external ? '<external>' : ref.id,\n sourceLocation: 'L1',\n });\n }\n\n function resolveTypeTarget(name: string): string {\n const resolved = nameIndex.get(name);\n if (resolved) return resolved;\n const extId = externalId(name);\n if (!builder.hasNode(extId)) {\n builder.addNode({ id: extId, label: name, sourceFile: '<external>', sourceLocation: 'L0' });\n }\n return extId;\n }\n\n function handleImportSpec(spec: TSNode): void {\n const pathNode = spec.childForFieldName('path');\n if (!pathNode) return;\n const specifier = stripQuotes(pathNode.text);\n const ref = resolveModuleRef(sourceFile, specifier);\n addModuleNode(ref);\n builder.addEdge({ source: fileId, target: ref.id, relation: 'imports', confidence: 'EXTRACTED' });\n\n const aliasNode = spec.childForFieldName('name');\n const alias = aliasNode?.text;\n if (alias && alias !== '_' && alias !== '.') {\n importIndex.set(alias, ref);\n } else if (!alias) {\n importIndex.set(defaultPackageQualifier(specifier), ref);\n }\n }\n\n function handleImportDeclaration(node: TSNode): void {\n for (const child of namedChildren(node)) {\n if (child.type === 'import_spec') {\n handleImportSpec(child);\n } else if (child.type === 'import_spec_list') {\n for (const spec of namedChildren(child)) {\n if (spec.type === 'import_spec') handleImportSpec(spec);\n }\n }\n }\n }\n\n function handleFunctionDeclaration(node: TSNode): void {\n const name = node.childForFieldName('name')?.text ?? '(anonymous)';\n const id = entityId(sourceFile, name);\n builder.addNode({ id, label: `function ${name}`, sourceFile, sourceLocation: lineOf(node) });\n builder.addEdge({ source: fileId, target: id, relation: 'contains', confidence: 'EXTRACTED' });\n nameIndex.set(name, id);\n functionNodeMap.set(node.id, id);\n }\n\n function handleTypeDeclaration(node: TSNode): void {\n for (const spec of namedChildren(node)) {\n if (spec.type !== 'type_spec') continue; // skip `type X = Y` aliases\n const name = spec.childForFieldName('name')?.text;\n if (!name) continue;\n const underlying = spec.childForFieldName('type');\n const kind = underlying?.type === 'struct_type' ? 'struct' : underlying?.type === 'interface_type' ? 'interface' : 'type';\n const id = entityId(sourceFile, name);\n builder.addNode({ id, label: `${kind} ${name}`, sourceFile, sourceLocation: lineOf(spec) });\n builder.addEdge({ source: fileId, target: id, relation: 'contains', confidence: 'EXTRACTED' });\n nameIndex.set(name, id);\n typeMethods.set(id, new Map());\n\n if (underlying?.type === 'struct_type') {\n const fieldList = namedChildren(underlying).find((c) => c.type === 'field_declaration_list');\n if (fieldList) {\n for (const field of namedChildren(fieldList)) {\n if (field.type !== 'field_declaration') continue;\n if (field.childForFieldName('name')) continue; // named field, not embedding\n const embeddedType = namedChildren(field)[0];\n if (!embeddedType) continue;\n const base = embeddedType.type === 'pointer_type' ? namedChildren(embeddedType)[0] : embeddedType;\n if (!base) continue;\n builder.addEdge({\n source: id,\n target: resolveTypeTarget(base.text),\n relation: 'embeds',\n confidence: 'EXTRACTED',\n });\n }\n }\n }\n }\n }\n\n /** Receiver's declared type name, unwrapping a pointer receiver (`*T`). */\n function receiverTypeName(receiver: TSNode): string | null {\n const paramDecl = namedChildren(receiver)[0];\n if (!paramDecl) return null;\n let typeNode = paramDecl.childForFieldName('type');\n if (typeNode?.type === 'pointer_type') {\n typeNode = namedChildren(typeNode)[0] ?? null;\n }\n return typeNode?.type === 'type_identifier' ? typeNode.text : null;\n }\n\n function receiverVarName(receiver: TSNode): string | null {\n const paramDecl = namedChildren(receiver)[0];\n return paramDecl?.childForFieldName('name')?.text ?? null;\n }\n\n function handleMethodDeclaration(node: TSNode): void {\n const receiver = node.childForFieldName('receiver');\n const methodName = node.childForFieldName('name')?.text ?? '(anonymous)';\n if (!receiver) return;\n const typeName = receiverTypeName(receiver);\n if (!typeName) return;\n const typeId = resolveTypeTarget(typeName);\n\n const methodId = entityId(sourceFile, `${typeName}.${methodName}`);\n builder.addNode({ id: methodId, label: `method ${typeName}.${methodName}`, sourceFile, sourceLocation: lineOf(node) });\n builder.addEdge({ source: typeId, target: methodId, relation: 'method', confidence: 'EXTRACTED' });\n\n let methods = typeMethods.get(typeId);\n if (!methods) {\n methods = new Map();\n typeMethods.set(typeId, methods);\n }\n methods.set(methodName, methodId);\n\n functionNodeMap.set(node.id, methodId);\n const varName = receiverVarName(receiver);\n if (varName) receiverInfo.set(node.id, { varName, typeId });\n }\n\n // Pass 1: top-level declarations (imports, named types, functions, methods).\n for (const child of namedChildren(root)) {\n switch (child.type) {\n case 'import_declaration':\n handleImportDeclaration(child);\n break;\n case 'type_declaration':\n handleTypeDeclaration(child);\n break;\n case 'function_declaration':\n handleFunctionDeclaration(child);\n break;\n case 'method_declaration':\n handleMethodDeclaration(child);\n break;\n default:\n break;\n }\n }\n\n function closestTrackedCaller(node: TSNode): string {\n let current: TSNode | null = node.parent;\n while (current) {\n const tracked = functionNodeMap.get(current.id);\n if (tracked) return tracked;\n current = current.parent;\n }\n return fileId;\n }\n\n function closestEnclosingReceiver(node: TSNode): { varName: string; typeId: string } | undefined {\n let current: TSNode | null = node.parent;\n while (current) {\n if (current.type === 'method_declaration') {\n return receiverInfo.get(current.id);\n }\n current = current.parent;\n }\n return undefined;\n }\n\n // Pass 2: calls (see the function doc comment above for the\n // EXTRACTED/INFERRED policy).\n for (const call of descendantsOfType(root, ['call_expression'])) {\n const fn = call.childForFieldName('function');\n if (!fn) continue;\n\n let targetId: string | null = null;\n let confidence: 'EXTRACTED' | 'INFERRED' = 'EXTRACTED';\n\n if (fn.type === 'identifier') {\n const sameFile = nameIndex.get(fn.text);\n if (sameFile) targetId = sameFile;\n } else if (fn.type === 'selector_expression') {\n const operand = fn.childForFieldName('operand');\n const property = fn.childForFieldName('field')?.text;\n if (operand && property && operand.type === 'identifier') {\n const receiver = closestEnclosingReceiver(call);\n if (receiver && receiver.varName === operand.text) {\n const methodId = typeMethods.get(receiver.typeId)?.get(property);\n if (methodId) targetId = methodId;\n } else {\n const viaImport = importIndex.get(operand.text);\n if (viaImport) {\n targetId = viaImport.id;\n confidence = 'INFERRED';\n }\n }\n }\n }\n\n if (!targetId) continue; // unresolved callee (builtin, external value, ...) — no noisy guess\n const callerId = closestTrackedCaller(call);\n builder.addEdge({ source: callerId, target: targetId, relation: 'calls', confidence });\n }\n\n return builder.build();\n}\n","import * as fs from 'node:fs/promises';\nimport type { Node as TSNode } from 'web-tree-sitter';\nimport type { ExtractionResult } from '../types.js';\nimport {\n ExtractionBuilder,\n descendantsOfType,\n entityId,\n externalId,\n lineOf,\n namedChildren,\n resolveModuleRef,\n toPosix,\n} from './common.js';\nimport { createParser } from './wasmLoader.js';\n\n/**\n * Structural extraction for .java via web-tree-sitter (WASM, no native\n * compilation, no eval/exec of source content).\n *\n * Java has no free top-level functions — every method lives inside a\n * class or interface — so pass 1 walks top-level class/interface\n * declarations and, for classes, their methods (an interface's methods\n * are abstract signatures with no body, so only the interface itself\n * becomes a node, mirroring typescript.ts's interface handling).\n * Constructors (`constructor_declaration`, distinct from\n * `method_declaration` in this grammar) are intentionally not tracked as\n * separate entities — same \"structural, not exhaustive\" scope as the\n * other extractors in this file.\n *\n * Every `method_invocation` is then resolved (pass 2): a same-file\n * method/`this.method()` call resolved against the enclosing class is\n * EXTRACTED; a call qualified by an imported class name (or bound via a\n * static import) is INFERRED — the \"cross-file second pass\" placeholder\n * described in the master prompt §3. It intentionally does not open and\n * parse the imported class to confirm the target. An unresolvable callee\n * produces no edge at all.\n *\n * Fully-qualified import paths (`com.example.math.MathUtils`) have no\n * clean mapping to a same-repo relative file without real classpath/\n * package-root information, so every import resolves to an external\n * module placeholder via resolveModuleRef — consistent with how the Go\n * extractor treats its (also always-absolute) import paths.\n */\nexport async function extractJava(filePath: string, displayPath?: string): Promise<ExtractionResult> {\n const parser = await createParser('java');\n\n const raw = await fs.readFile(filePath);\n const content = raw.toString('utf-8'); // replacement-decoded — never throws on invalid bytes\n\n const tree = parser.parse(content);\n if (!tree) {\n throw new Error(`extractJava: parser produced no tree for ${filePath}`);\n }\n const root = tree.rootNode;\n\n const sourceFile = toPosix(displayPath ?? filePath);\n const builder = new ExtractionBuilder();\n const fileId = sourceFile;\n builder.addNode({ id: fileId, label: sourceFile, sourceFile, sourceLocation: 'L1' });\n\n /** Declared name (class/interface) -> our graph id. */\n const nameIndex = new Map<string, string>();\n /** tree-sitter node id -> our graph id, for every method entity we track. */\n const functionNodeMap = new Map<number, string>();\n /** tree-sitter class_declaration node id -> method name -> our graph id. */\n const classMethods = new Map<number, Map<string, string>>();\n /** tree-sitter method_declaration node id -> its enclosing class's node id. */\n const enclosingClassOf = new Map<number, number>();\n /** local binding name (imported class or statically-imported member) -> the module it came from. */\n const importIndex = new Map<string, ReturnType<typeof resolveModuleRef>>();\n\n function addModuleNode(ref: ReturnType<typeof resolveModuleRef>): void {\n if (builder.hasNode(ref.id)) return;\n builder.addNode({\n id: ref.id,\n label: ref.label,\n sourceFile: ref.external ? '<external>' : ref.id,\n sourceLocation: 'L1',\n });\n }\n\n function resolveHeritageTarget(name: string): string {\n const resolved = nameIndex.get(name);\n if (resolved) return resolved;\n const extId = externalId(name);\n if (!builder.hasNode(extId)) {\n builder.addNode({ id: extId, label: name, sourceFile: '<external>', sourceLocation: 'L0' });\n }\n return extId;\n }\n\n function handleImportDeclaration(node: TSNode): void {\n // Java's grammar keeps `static`/`*` as bare tokens (no field name), so\n // we detect them structurally rather than via childForFieldName.\n const hasWildcard = namedChildren(node).some((c) => c.type === 'asterisk');\n const scoped = namedChildren(node).find((c) => c.type === 'scoped_identifier' || c.type === 'identifier');\n if (!scoped) return;\n const fullPath = scoped.text;\n const ref = resolveModuleRef(sourceFile, fullPath);\n addModuleNode(ref);\n\n if (hasWildcard) {\n // `import com.example.util.*;` — whole package, no single local binding to record.\n builder.addEdge({ source: fileId, target: ref.id, relation: 'imports', confidence: 'EXTRACTED' });\n return;\n }\n\n // Plain class import (`import a.b.Foo;`) and static-member import\n // (`import static a.b.Foo.bar;`) both bind their last dotted segment\n // as the local name callers use unqualified.\n const segments = fullPath.split('.');\n const localName = segments[segments.length - 1];\n if (localName) importIndex.set(localName, ref);\n builder.addEdge({ source: fileId, target: ref.id, relation: 'imports_from', confidence: 'EXTRACTED' });\n }\n\n function handleMethodDeclaration(classNode: TSNode, classId: string, className: string, member: TSNode): void {\n const methodName = member.childForFieldName('name')?.text ?? '(anonymous)';\n const methodId = entityId(sourceFile, `${className}.${methodName}`);\n builder.addNode({\n id: methodId,\n label: `method ${className}.${methodName}`,\n sourceFile,\n sourceLocation: lineOf(member),\n });\n builder.addEdge({ source: classId, target: methodId, relation: 'method', confidence: 'EXTRACTED' });\n\n let methods = classMethods.get(classNode.id);\n if (!methods) {\n methods = new Map();\n classMethods.set(classNode.id, methods);\n }\n methods.set(methodName, methodId);\n functionNodeMap.set(member.id, methodId);\n enclosingClassOf.set(member.id, classNode.id);\n }\n\n function handleClassDeclaration(node: TSNode): void {\n const name = node.childForFieldName('name')?.text ?? '(anonymous)';\n const classId = entityId(sourceFile, name);\n builder.addNode({ id: classId, label: `class ${name}`, sourceFile, sourceLocation: lineOf(node) });\n builder.addEdge({ source: fileId, target: classId, relation: 'contains', confidence: 'EXTRACTED' });\n nameIndex.set(name, classId);\n functionNodeMap.set(node.id, classId);\n classMethods.set(node.id, new Map());\n\n const superclass = node.childForFieldName('superclass');\n if (superclass) {\n const base = namedChildren(superclass)[0];\n if (base) {\n builder.addEdge({\n source: classId,\n target: resolveHeritageTarget(base.text),\n relation: 'inherits',\n confidence: 'EXTRACTED',\n });\n }\n }\n\n const interfaces = node.childForFieldName('interfaces');\n if (interfaces) {\n const typeList = namedChildren(interfaces).find((c) => c.type === 'type_list');\n for (const iface of typeList ? namedChildren(typeList) : []) {\n builder.addEdge({\n source: classId,\n target: resolveHeritageTarget(iface.text),\n relation: 'implements',\n confidence: 'EXTRACTED',\n });\n }\n }\n\n const body = node.childForFieldName('body');\n if (body) {\n for (const member of namedChildren(body)) {\n if (member.type !== 'method_declaration') continue; // constructors intentionally not tracked\n handleMethodDeclaration(node, classId, name, member);\n }\n }\n }\n\n function handleInterfaceDeclaration(node: TSNode): void {\n const name = node.childForFieldName('name')?.text ?? '(anonymous)';\n const id = entityId(sourceFile, name);\n builder.addNode({ id, label: `interface ${name}`, sourceFile, sourceLocation: lineOf(node) });\n builder.addEdge({ source: fileId, target: id, relation: 'contains', confidence: 'EXTRACTED' });\n nameIndex.set(name, id);\n\n const extendsInterfaces = namedChildren(node).find((c) => c.type === 'extends_interfaces');\n if (extendsInterfaces) {\n const typeList = namedChildren(extendsInterfaces).find((c) => c.type === 'type_list');\n for (const parent of typeList ? namedChildren(typeList) : []) {\n builder.addEdge({\n source: id,\n target: resolveHeritageTarget(parent.text),\n relation: 'inherits',\n confidence: 'EXTRACTED',\n });\n }\n }\n }\n\n // Pass 1: top-level declarations (imports, classes, interfaces).\n for (const child of namedChildren(root)) {\n switch (child.type) {\n case 'import_declaration':\n handleImportDeclaration(child);\n break;\n case 'class_declaration':\n handleClassDeclaration(child);\n break;\n case 'interface_declaration':\n handleInterfaceDeclaration(child);\n break;\n default:\n break;\n }\n }\n\n function closestTrackedCaller(node: TSNode): string {\n let current: TSNode | null = node.parent;\n while (current) {\n const tracked = functionNodeMap.get(current.id);\n if (tracked) return tracked;\n current = current.parent;\n }\n return fileId;\n }\n\n function closestEnclosingClassMethods(node: TSNode): Map<string, string> | undefined {\n let current: TSNode | null = node.parent;\n while (current) {\n if (current.type === 'method_declaration') {\n const classNodeId = enclosingClassOf.get(current.id);\n if (classNodeId !== undefined) return classMethods.get(classNodeId);\n }\n current = current.parent;\n }\n return undefined;\n }\n\n // Pass 2: calls (see the function doc comment above for the\n // EXTRACTED/INFERRED policy).\n for (const call of descendantsOfType(root, ['method_invocation'])) {\n const name = call.childForFieldName('name')?.text;\n if (!name) continue;\n const object = call.childForFieldName('object');\n\n let targetId: string | null = null;\n let confidence: 'EXTRACTED' | 'INFERRED' = 'EXTRACTED';\n\n if (!object) {\n // Unqualified call: same-file method (via the tracked caller's own\n // class) or a statically-imported member.\n const methodId = closestEnclosingClassMethods(call)?.get(name);\n if (methodId) {\n targetId = methodId;\n } else {\n const viaImport = importIndex.get(name);\n if (viaImport) {\n targetId = viaImport.id;\n confidence = 'INFERRED';\n }\n }\n } else if (object.type === 'this') {\n const methodId = closestEnclosingClassMethods(call)?.get(name);\n if (methodId) targetId = methodId;\n } else if (object.type === 'identifier') {\n const viaImport = importIndex.get(object.text);\n if (viaImport) {\n targetId = viaImport.id;\n confidence = 'INFERRED';\n }\n }\n\n if (!targetId) continue; // unresolved callee (builtin, external value, ...) — no noisy guess\n const callerId = closestTrackedCaller(call);\n builder.addEdge({ source: callerId, target: targetId, relation: 'calls', confidence });\n }\n\n return builder.build();\n}\n","import * as fs from 'node:fs/promises';\nimport type { Node as TSNode } from 'web-tree-sitter';\nimport type { ExtractionResult } from '../types.js';\nimport {\n ExtractionBuilder,\n descendantsOfType,\n entityId,\n externalId,\n lineOf,\n namedChildren,\n resolveModuleRef,\n toPosix,\n} from './common.js';\nimport { createParser } from './wasmLoader.js';\n\n/**\n * Structural extraction for .py via web-tree-sitter (WASM, no native\n * compilation, no eval/exec of source content).\n *\n * Pattern mirrors typescript.ts: parse -> walk the module body for\n * top-level functions/classes/imports (pass 1) -> walk every `call` node\n * and resolve its callee against what pass 1 saw (pass 2). A same-file\n * callee (or a `self.method()` call resolved against the enclosing class)\n * is EXTRACTED; a callee that only resolves through an imported local\n * binding (a directly-imported name, or a member access on an imported\n * module alias) is emitted as INFERRED — the \"cross-file second pass\"\n * placeholder described in the master prompt §3. It intentionally does not\n * open and parse the imported module to confirm the target. An\n * unresolvable callee (a builtin, a call on some arbitrary local value,\n * etc.) produces no edge at all rather than a noisy guess.\n *\n * Python has no separate interface/heritage-clause concept: every base\n * class listed in `class Foo(Base, Other):` becomes an `inherits` edge.\n */\nexport async function extractPython(filePath: string, displayPath?: string): Promise<ExtractionResult> {\n const parser = await createParser('python');\n\n const raw = await fs.readFile(filePath);\n const content = raw.toString('utf-8'); // replacement-decoded — never throws on invalid bytes\n\n const tree = parser.parse(content);\n if (!tree) {\n throw new Error(`extractPython: parser produced no tree for ${filePath}`);\n }\n const root = tree.rootNode;\n\n const sourceFile = toPosix(displayPath ?? filePath);\n const builder = new ExtractionBuilder();\n const fileId = sourceFile;\n builder.addNode({ id: fileId, label: sourceFile, sourceFile, sourceLocation: 'L1' });\n\n /** Declared name (function/class) -> our graph id. */\n const nameIndex = new Map<string, string>();\n /** tree-sitter node id -> our graph id, for every function-like entity we track. */\n const functionNodeMap = new Map<number, string>();\n /** tree-sitter class_definition node id -> method name -> our graph id. */\n const classMethods = new Map<number, Map<string, string>>();\n /** tree-sitter function_definition (method) node id -> its enclosing class's node id. */\n const enclosingClassOf = new Map<number, number>();\n /** local binding name (import) -> the module it came from. */\n const importIndex = new Map<string, ReturnType<typeof resolveModuleRef>>();\n\n function addModuleNode(ref: ReturnType<typeof resolveModuleRef>): void {\n if (builder.hasNode(ref.id)) return;\n builder.addNode({\n id: ref.id,\n label: ref.label,\n sourceFile: ref.external ? '<external>' : ref.id,\n sourceLocation: 'L1',\n });\n }\n\n function resolveHeritageTarget(name: string): string {\n const resolved = nameIndex.get(name);\n if (resolved) return resolved;\n const extId = externalId(name);\n if (!builder.hasNode(extId)) {\n builder.addNode({ id: extId, label: name, sourceFile: '<external>', sourceLocation: 'L0' });\n }\n return extId;\n }\n\n /** Unwrap a `@decorator` / `decorated_definition` wrapper to the function/class it decorates. */\n function unwrapDecorated(node: TSNode): TSNode | null {\n if (node.type !== 'decorated_definition') return node;\n return (\n namedChildren(node).find((c) => c.type === 'function_definition' || c.type === 'class_definition') ?? null\n );\n }\n\n /**\n * Convert a `relative_import` node (e.g. \".\", \".foo\", \"..foo.bar\") into a\n * relative-path-shaped specifier resolveModuleRef understands (e.g. \".\",\n * \"./foo\", \"../foo/bar\") — one leading dot means \"this package\" (`.`),\n * each additional dot means one more directory up.\n */\n function relativeSpecifier(relImport: TSNode): string {\n let dots = 0;\n for (const ch of relImport.text) {\n if (ch !== '.') break;\n dots++;\n }\n const dotted = namedChildren(relImport).find((c) => c.type === 'dotted_name');\n const up = dots - 1;\n let base = up === 0 ? '.' : Array.from({ length: up }, () => '..').join('/');\n if (dotted) {\n base = `${base}/${dotted.text.split('.').join('/')}`;\n }\n return base;\n }\n\n function moduleSpecifierOf(node: TSNode): string {\n if (node.type === 'relative_import') return relativeSpecifier(node);\n return node.text; // dotted_name, e.g. \"pkg.sub\"\n }\n\n function handleFunctionDefinition(node: TSNode): void {\n const name = node.childForFieldName('name')?.text ?? '(anonymous)';\n const id = entityId(sourceFile, name);\n builder.addNode({ id, label: `function ${name}`, sourceFile, sourceLocation: lineOf(node) });\n builder.addEdge({ source: fileId, target: id, relation: 'contains', confidence: 'EXTRACTED' });\n nameIndex.set(name, id);\n functionNodeMap.set(node.id, id);\n }\n\n function handleClassDefinition(node: TSNode): void {\n const name = node.childForFieldName('name')?.text ?? '(anonymous)';\n const classId = entityId(sourceFile, name);\n builder.addNode({ id: classId, label: `class ${name}`, sourceFile, sourceLocation: lineOf(node) });\n builder.addEdge({ source: fileId, target: classId, relation: 'contains', confidence: 'EXTRACTED' });\n nameIndex.set(name, classId);\n functionNodeMap.set(node.id, classId);\n\n const superclasses = node.childForFieldName('superclasses');\n if (superclasses) {\n for (const base of namedChildren(superclasses)) {\n if (base.type !== 'identifier' && base.type !== 'attribute') continue; // skip e.g. metaclass=Meta\n builder.addEdge({\n source: classId,\n target: resolveHeritageTarget(base.text),\n relation: 'inherits',\n confidence: 'EXTRACTED',\n });\n }\n }\n\n const methods = new Map<string, string>();\n classMethods.set(node.id, methods);\n\n const body = node.childForFieldName('body');\n if (body) {\n for (const rawMember of namedChildren(body)) {\n const member = unwrapDecorated(rawMember);\n if (!member || member.type !== 'function_definition') continue;\n const methodName = member.childForFieldName('name')?.text ?? '(anonymous)';\n const methodId = entityId(sourceFile, `${name}.${methodName}`);\n builder.addNode({\n id: methodId,\n label: `method ${name}.${methodName}`,\n sourceFile,\n sourceLocation: lineOf(member),\n });\n builder.addEdge({ source: classId, target: methodId, relation: 'method', confidence: 'EXTRACTED' });\n methods.set(methodName, methodId);\n functionNodeMap.set(member.id, methodId);\n enclosingClassOf.set(member.id, node.id);\n }\n }\n }\n\n function handleImportStatement(node: TSNode): void {\n // `import a, b.c as d` — every item is a top-level named child, either\n // `dotted_name` (bare module) or `aliased_import` (module `as` alias).\n for (const item of namedChildren(node)) {\n if (item.type === 'dotted_name') {\n const ref = resolveModuleRef(sourceFile, item.text);\n addModuleNode(ref);\n const bindingName = namedChildren(item)[0]?.text ?? item.text; // `import pkg.sub` binds `pkg`\n importIndex.set(bindingName, ref);\n builder.addEdge({ source: fileId, target: ref.id, relation: 'imports', confidence: 'EXTRACTED' });\n } else if (item.type === 'aliased_import') {\n const dotted = item.childForFieldName('name');\n const alias = item.childForFieldName('alias')?.text;\n if (!dotted || !alias) continue;\n const ref = resolveModuleRef(sourceFile, dotted.text);\n addModuleNode(ref);\n importIndex.set(alias, ref);\n builder.addEdge({ source: fileId, target: ref.id, relation: 'imports', confidence: 'EXTRACTED' });\n }\n }\n }\n\n function handleImportFromStatement(node: TSNode): void {\n const moduleNode = node.childForFieldName('module_name');\n if (!moduleNode) return;\n const ref = resolveModuleRef(sourceFile, moduleSpecifierOf(moduleNode));\n addModuleNode(ref);\n\n let sawItem = false;\n for (const child of namedChildren(node)) {\n if (child.id === moduleNode.id) continue;\n if (child.type === 'dotted_name') {\n sawItem = true;\n importIndex.set(child.text, ref);\n } else if (child.type === 'aliased_import') {\n sawItem = true;\n const alias = child.childForFieldName('alias')?.text;\n const name = child.childForFieldName('name')?.text;\n if (alias) importIndex.set(alias, ref);\n else if (name) importIndex.set(name, ref);\n } else if (child.type === 'wildcard_import') {\n sawItem = true;\n }\n }\n if (sawItem) {\n builder.addEdge({ source: fileId, target: ref.id, relation: 'imports_from', confidence: 'EXTRACTED' });\n }\n }\n\n // Pass 1: top-level declarations (functions, classes, imports),\n // unwrapping `@decorator` wrappers where present.\n for (const rawChild of namedChildren(root)) {\n if (rawChild.type === 'import_statement') {\n handleImportStatement(rawChild);\n continue;\n }\n if (rawChild.type === 'import_from_statement') {\n handleImportFromStatement(rawChild);\n continue;\n }\n\n const effective = unwrapDecorated(rawChild);\n if (!effective) continue;\n\n switch (effective.type) {\n case 'function_definition':\n handleFunctionDefinition(effective);\n break;\n case 'class_definition':\n handleClassDefinition(effective);\n break;\n default:\n break;\n }\n }\n\n function closestTrackedCaller(node: TSNode): string {\n let current: TSNode | null = node.parent;\n while (current) {\n const tracked = functionNodeMap.get(current.id);\n if (tracked) return tracked;\n current = current.parent;\n }\n return fileId;\n }\n\n function closestEnclosingClassMethods(node: TSNode): Map<string, string> | undefined {\n let current: TSNode | null = node.parent;\n while (current) {\n if (current.type === 'function_definition') {\n const classNodeId = enclosingClassOf.get(current.id);\n if (classNodeId !== undefined) return classMethods.get(classNodeId);\n }\n current = current.parent;\n }\n return undefined;\n }\n\n // Pass 2: calls (see the function doc comment above for the\n // EXTRACTED/INFERRED policy).\n for (const call of descendantsOfType(root, ['call'])) {\n const fn = call.childForFieldName('function');\n if (!fn) continue;\n\n let targetId: string | null = null;\n let confidence: 'EXTRACTED' | 'INFERRED' = 'EXTRACTED';\n\n if (fn.type === 'identifier') {\n const name = fn.text;\n const sameFile = nameIndex.get(name);\n if (sameFile) {\n targetId = sameFile;\n } else {\n const viaImport = importIndex.get(name);\n if (viaImport) {\n targetId = viaImport.id;\n confidence = 'INFERRED';\n }\n }\n } else if (fn.type === 'attribute') {\n const object = fn.childForFieldName('object');\n const property = fn.childForFieldName('attribute')?.text;\n if (object && property) {\n if (object.type === 'identifier' && object.text === 'self') {\n const methodId = closestEnclosingClassMethods(call)?.get(property);\n if (methodId) targetId = methodId;\n } else if (object.type === 'identifier') {\n const viaImport = importIndex.get(object.text);\n if (viaImport) {\n targetId = viaImport.id;\n confidence = 'INFERRED';\n }\n }\n }\n }\n\n if (!targetId) continue; // unresolved callee (builtin, external value, ...) — no noisy guess\n const callerId = closestTrackedCaller(call);\n builder.addEdge({ source: callerId, target: targetId, relation: 'calls', confidence });\n }\n\n return builder.build();\n}\n","import * as fs from 'node:fs/promises';\nimport type { Node as TSNode } from 'web-tree-sitter';\nimport type { ExtractionResult } from '../types.js';\nimport {\n ExtractionBuilder,\n descendantsOfType,\n entityId,\n externalId,\n lineOf,\n namedChildren,\n resolveModuleRef,\n toPosix,\n} from './common.js';\nimport { createParser } from './wasmLoader.js';\n\n/**\n * Best-effort conversion of a required path's last segment into the\n * CamelCase constant name Ruby convention says it defines (`require_relative\n * './math'` -> `Math`, `require 'active_support/core_ext'` -> `CoreExt`).\n * Ruby's `require`/`require_relative` bind no local alias at all (unlike\n * every other language here), so this is the one available heuristic for\n * giving later `Constant.method(...)` calls something to resolve against —\n * it is a naming-convention guess, not a confirmed binding.\n */\nfunction conventionalConstantName(specifier: string): string {\n const lastSegment = specifier.split('/').filter(Boolean).pop() ?? specifier;\n return lastSegment\n .split('_')\n .filter(Boolean)\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join('');\n}\n\n/** Text of a `string` node's `string_content` child (already unquoted), or '' for an empty literal. */\nfunction stringLiteralContent(node: TSNode): string | null {\n if (node.type !== 'string') return null;\n const content = namedChildren(node).find((c) => c.type === 'string_content');\n return content ? content.text : '';\n}\n\n/**\n * Structural extraction for .rb via web-tree-sitter (WASM, no native\n * compilation, no eval/exec of source content).\n *\n * Pattern mirrors typescript.ts, adapted to Ruby's shape: top-level\n * classes/modules and free `method`s (pass 1) -> every `call` node walked\n * once to special-case `require`/`require_relative` into import edges (Ruby\n * has no dedicated import AST node — these are plain method calls, per the\n * master prompt), then a second walk resolves the rest as method calls\n * (pass 2). A same-file callee — including an implicit- or explicit-`self`\n * call resolved against the enclosing class/module — is EXTRACTED; a call\n * through a `Constant.method(...)` receiver that only resolves via the\n * conventional-constant-name heuristic above is INFERRED. An unresolvable\n * callee produces no edge at all.\n *\n * Known, deliberate scope limit: a bare, paren-less, argument-less\n * identifier (`helper_top` with no parens or `()`) is genuinely ambiguous\n * with a local-variable reference at the grammar level — tree-sitter-ruby\n * itself represents it as a plain `identifier`, not a `call` — so this\n * extractor (like a human reading the AST alone) cannot tell them apart\n * and does not attempt to. Only calls that surface as an actual `call`\n * node (parens, and/or arguments, and/or an explicit receiver) are\n * resolved.\n *\n * `include`/`extend`/`prepend` (Ruby's mixin mechanism) become `mixes_in`\n * edges; `class Foo < Bar` becomes `inherits`. Ruby has no `implements`\n * equivalent.\n */\nexport async function extractRuby(filePath: string, displayPath?: string): Promise<ExtractionResult> {\n const parser = await createParser('ruby');\n\n const raw = await fs.readFile(filePath);\n const content = raw.toString('utf-8'); // replacement-decoded — never throws on invalid bytes\n\n const tree = parser.parse(content);\n if (!tree) {\n throw new Error(`extractRuby: parser produced no tree for ${filePath}`);\n }\n const root = tree.rootNode;\n\n const sourceFile = toPosix(displayPath ?? filePath);\n const builder = new ExtractionBuilder();\n const fileId = sourceFile;\n builder.addNode({ id: fileId, label: sourceFile, sourceFile, sourceLocation: 'L1' });\n\n /** Declared name (top-level function/class/module) -> our graph id. */\n const nameIndex = new Map<string, string>();\n /** tree-sitter node id -> our graph id, for every function/method entity we track. */\n const functionNodeMap = new Map<number, string>();\n /** graph id of a class/module -> method name -> our graph id. */\n const typeMethods = new Map<string, Map<string, string>>();\n /** tree-sitter method node id -> its enclosing class/module's graph id. */\n const enclosingTypeOf = new Map<number, string>();\n /** conventional constant name (derived from a require path) -> the module it came from. */\n const importIndex = new Map<string, ReturnType<typeof resolveModuleRef>>();\n\n function addModuleNode(ref: ReturnType<typeof resolveModuleRef>): void {\n if (builder.hasNode(ref.id)) return;\n builder.addNode({\n id: ref.id,\n label: ref.label,\n sourceFile: ref.external ? '<external>' : ref.id,\n sourceLocation: 'L1',\n });\n }\n\n function resolveHeritageTarget(name: string): string {\n const resolved = nameIndex.get(name);\n if (resolved) return resolved;\n const extId = externalId(name);\n if (!builder.hasNode(extId)) {\n builder.addNode({ id: extId, label: name, sourceFile: '<external>', sourceLocation: 'L0' });\n }\n return extId;\n }\n\n function handleTopLevelMethod(node: TSNode): void {\n const name = node.childForFieldName('name')?.text ?? '(anonymous)';\n const id = entityId(sourceFile, name);\n builder.addNode({ id, label: `function ${name}`, sourceFile, sourceLocation: lineOf(node) });\n builder.addEdge({ source: fileId, target: id, relation: 'contains', confidence: 'EXTRACTED' });\n nameIndex.set(name, id);\n functionNodeMap.set(node.id, id);\n }\n\n function handleClassOrModule(node: TSNode, kind: 'class' | 'module'): void {\n const name = node.childForFieldName('name')?.text ?? '(anonymous)';\n const id = entityId(sourceFile, name);\n builder.addNode({ id, label: `${kind} ${name}`, sourceFile, sourceLocation: lineOf(node) });\n builder.addEdge({ source: fileId, target: id, relation: 'contains', confidence: 'EXTRACTED' });\n nameIndex.set(name, id);\n typeMethods.set(id, new Map());\n\n if (kind === 'class') {\n const superclass = node.childForFieldName('superclass');\n const base = superclass ? namedChildren(superclass)[0] : undefined;\n if (base) {\n builder.addEdge({\n source: id,\n target: resolveHeritageTarget(base.text),\n relation: 'inherits',\n confidence: 'EXTRACTED',\n });\n }\n }\n\n const body = node.childForFieldName('body');\n if (!body) return;\n const methods = typeMethods.get(id);\n for (const member of namedChildren(body)) {\n if (member.type === 'method') {\n const methodName = member.childForFieldName('name')?.text ?? '(anonymous)';\n const methodId = entityId(sourceFile, `${name}.${methodName}`);\n builder.addNode({\n id: methodId,\n label: `method ${name}.${methodName}`,\n sourceFile,\n sourceLocation: lineOf(member),\n });\n builder.addEdge({ source: id, target: methodId, relation: 'method', confidence: 'EXTRACTED' });\n methods?.set(methodName, methodId);\n functionNodeMap.set(member.id, methodId);\n enclosingTypeOf.set(member.id, id);\n } else if (member.type === 'call') {\n const methodField = member.childForFieldName('method')?.text;\n if (methodField !== 'include' && methodField !== 'extend' && methodField !== 'prepend') continue;\n const args = member.childForFieldName('arguments');\n for (const arg of args ? namedChildren(args) : []) {\n if (arg.type !== 'constant' && arg.type !== 'scoped_constant') continue;\n builder.addEdge({\n source: id,\n target: resolveHeritageTarget(arg.text),\n relation: 'mixes_in',\n confidence: 'EXTRACTED',\n });\n }\n }\n }\n }\n\n // Pass 1: top-level declarations (free methods, classes, modules).\n for (const child of namedChildren(root)) {\n switch (child.type) {\n case 'method':\n handleTopLevelMethod(child);\n break;\n case 'class':\n handleClassOrModule(child, 'class');\n break;\n case 'module':\n handleClassOrModule(child, 'module');\n break;\n default:\n break;\n }\n }\n\n function closestTrackedCaller(node: TSNode): string {\n let current: TSNode | null = node.parent;\n while (current) {\n const tracked = functionNodeMap.get(current.id);\n if (tracked) return tracked;\n current = current.parent;\n }\n return fileId;\n }\n\n function closestEnclosingTypeMethods(node: TSNode): Map<string, string> | undefined {\n let current: TSNode | null = node.parent;\n while (current) {\n if (current.type === 'method') {\n const typeId = enclosingTypeOf.get(current.id);\n if (typeId !== undefined) return typeMethods.get(typeId);\n }\n current = current.parent;\n }\n return undefined;\n }\n\n const allCalls = descendantsOfType(root, ['call']);\n\n // Pass 2a: `require`/`require_relative` — plain method calls in Ruby's\n // grammar, special-cased into import edges instead of `calls` edges.\n const requireCallIds = new Set<number>();\n for (const call of allCalls) {\n const methodName = call.childForFieldName('method')?.text;\n if (methodName !== 'require' && methodName !== 'require_relative') continue;\n const args = call.childForFieldName('arguments');\n const soleArg = args ? namedChildren(args) : [];\n if (soleArg.length !== 1) continue;\n const literal = stringLiteralContent(soleArg[0] as TSNode);\n if (literal === null) continue;\n\n requireCallIds.add(call.id);\n const ref = resolveModuleRef(sourceFile, literal);\n addModuleNode(ref);\n builder.addEdge({ source: fileId, target: ref.id, relation: 'imports', confidence: 'EXTRACTED' });\n importIndex.set(conventionalConstantName(literal), ref);\n }\n\n // Pass 2b: every other call (see the function doc comment above for the\n // EXTRACTED/INFERRED policy).\n for (const call of allCalls) {\n if (requireCallIds.has(call.id)) continue;\n const methodName = call.childForFieldName('method')?.text;\n if (!methodName) continue;\n const receiver = call.childForFieldName('receiver');\n\n let targetId: string | null = null;\n let confidence: 'EXTRACTED' | 'INFERRED' = 'EXTRACTED';\n\n if (!receiver) {\n const viaEnclosingType = closestEnclosingTypeMethods(call)?.get(methodName);\n if (viaEnclosingType) {\n targetId = viaEnclosingType;\n } else {\n const sameFile = nameIndex.get(methodName);\n if (sameFile) targetId = sameFile;\n }\n } else if (receiver.type === 'self') {\n const methodId = closestEnclosingTypeMethods(call)?.get(methodName);\n if (methodId) targetId = methodId;\n } else if (receiver.type === 'constant' || receiver.type === 'scoped_constant') {\n const sameFileTypeId = nameIndex.get(receiver.text);\n const methodId = sameFileTypeId ? typeMethods.get(sameFileTypeId)?.get(methodName) : undefined;\n if (methodId) {\n targetId = methodId;\n } else {\n const viaImport = importIndex.get(receiver.text);\n if (viaImport) {\n targetId = viaImport.id;\n confidence = 'INFERRED';\n }\n }\n }\n\n if (!targetId) continue; // unresolved callee (builtin, local var, ...) — no noisy guess\n const callerId = closestTrackedCaller(call);\n builder.addEdge({ source: callerId, target: targetId, relation: 'calls', confidence });\n }\n\n return builder.build();\n}\n","import * as fs from 'node:fs/promises';\nimport type { Node as TSNode } from 'web-tree-sitter';\nimport type { ExtractionResult } from '../types.js';\nimport {\n ExtractionBuilder,\n descendantsOfType,\n entityId,\n externalId,\n lineOf,\n namedChildren,\n resolveModuleRef,\n toPosix,\n} from './common.js';\nimport { createParser } from './wasmLoader.js';\n\n/**\n * Convert a Rust `use` path's `::`-joined segments into the relative-path\n * shape resolveModuleRef() understands: `crate`/`self` map to \"this\n * directory\" (`.`), each leading `super` walks up one directory, and\n * anything else (an external crate, `std`, ...) is left `::`-joined so\n * resolveModuleRef treats it as an external module specifier.\n */\nfunction convertUsePath(segments: string[]): string {\n const first = segments[0];\n if (first === 'crate' || first === 'self') {\n const rest = segments.slice(1);\n return rest.length ? `./${rest.join('/')}` : '.';\n }\n if (first === 'super') {\n let i = 0;\n while (segments[i] === 'super') i++;\n const ups = Array.from({ length: i }, () => '..').join('/');\n const rest = segments.slice(i);\n return rest.length ? `${ups}/${rest.join('/')}` : ups;\n }\n return segments.join('::');\n}\n\n/**\n * Structural extraction for .rs via web-tree-sitter (WASM, no native\n * compilation, no eval/exec of source content).\n *\n * Pattern mirrors typescript.ts, adapted to Rust's shape: top-level\n * structs/traits and free functions come from pass 1, but methods are\n * declared separately in `impl` blocks (inherent `impl Type { ... }` or\n * trait `impl Trait for Type { ... }`), so those are walked as their own\n * step and attached to whichever struct/trait `name` they target. Every\n * call_expression is then resolved (pass 2): a same-file callee, or a\n * `self.method()` call resolved against the enclosing impl block's type,\n * is EXTRACTED; a callee that only resolves through a `use`-imported local\n * binding (an imported item, or a module alias via `use ... as`) is\n * INFERRED — the \"cross-file second pass\" placeholder described in the\n * master prompt §3. It intentionally does not open and parse the\n * imported module to confirm the target. An unresolvable callee produces\n * no edge at all.\n *\n * `impl Trait for Type` is Rust's one heritage-like construct exposed\n * directly in the grammar, so it becomes an `implements` edge from `Type`\n * to `Trait`.\n */\nexport async function extractRust(filePath: string, displayPath?: string): Promise<ExtractionResult> {\n const parser = await createParser('rust');\n\n const raw = await fs.readFile(filePath);\n const content = raw.toString('utf-8'); // replacement-decoded — never throws on invalid bytes\n\n const tree = parser.parse(content);\n if (!tree) {\n throw new Error(`extractRust: parser produced no tree for ${filePath}`);\n }\n const root = tree.rootNode;\n\n const sourceFile = toPosix(displayPath ?? filePath);\n const builder = new ExtractionBuilder();\n const fileId = sourceFile;\n builder.addNode({ id: fileId, label: sourceFile, sourceFile, sourceLocation: 'L1' });\n\n /** Declared name (function/struct/trait) -> our graph id. */\n const nameIndex = new Map<string, string>();\n /** tree-sitter node id -> our graph id, for every function/method entity we track. */\n const functionNodeMap = new Map<number, string>();\n /** graph id of a struct/trait -> method name -> our graph id. */\n const typeMethods = new Map<string, Map<string, string>>();\n /** tree-sitter function_item (method) node id -> the owning impl block's type graph id. */\n const enclosingTypeOf = new Map<number, string>();\n /** local binding name (`use` item/alias) -> the module it came from. */\n const importIndex = new Map<string, ReturnType<typeof resolveModuleRef>>();\n\n function addModuleNode(ref: ReturnType<typeof resolveModuleRef>): void {\n if (builder.hasNode(ref.id)) return;\n builder.addNode({\n id: ref.id,\n label: ref.label,\n sourceFile: ref.external ? '<external>' : ref.id,\n sourceLocation: 'L1',\n });\n }\n\n function resolveTypeTarget(name: string): string {\n const resolved = nameIndex.get(name);\n if (resolved) return resolved;\n const extId = externalId(name);\n if (!builder.hasNode(extId)) {\n builder.addNode({ id: extId, label: name, sourceFile: '<external>', sourceLocation: 'L0' });\n }\n return extId;\n }\n\n function processUseArgument(node: TSNode): void {\n switch (node.type) {\n case 'identifier': {\n // `use foo;` — whole-module import, single segment.\n const ref = resolveModuleRef(sourceFile, convertUsePath([node.text]));\n addModuleNode(ref);\n importIndex.set(node.text, ref);\n builder.addEdge({ source: fileId, target: ref.id, relation: 'imports', confidence: 'EXTRACTED' });\n break;\n }\n case 'scoped_identifier': {\n // `use std::fmt;` — single named item `fmt` from module `std`.\n const pathNode = node.childForFieldName('path');\n const nameNode = node.childForFieldName('name');\n if (!pathNode || !nameNode) break;\n const ref = resolveModuleRef(sourceFile, convertUsePath(pathNode.text.split('::')));\n addModuleNode(ref);\n importIndex.set(nameNode.text, ref);\n builder.addEdge({ source: fileId, target: ref.id, relation: 'imports_from', confidence: 'EXTRACTED' });\n break;\n }\n case 'use_as_clause': {\n // `use crate::math as m;` — whole module aliased to `m`.\n const pathNode = node.childForFieldName('path');\n const aliasNode = node.childForFieldName('alias');\n if (!pathNode || !aliasNode) break;\n const ref = resolveModuleRef(sourceFile, convertUsePath(pathNode.text.split('::')));\n addModuleNode(ref);\n importIndex.set(aliasNode.text, ref);\n builder.addEdge({ source: fileId, target: ref.id, relation: 'imports', confidence: 'EXTRACTED' });\n break;\n }\n case 'scoped_use_list': {\n // `use crate::math::{add, multiply};` — named items from a module.\n const pathNode = node.childForFieldName('path');\n const listNode = node.childForFieldName('list');\n if (!listNode) break;\n const prefixSegments = pathNode ? pathNode.text.split('::') : [];\n const ref = resolveModuleRef(sourceFile, convertUsePath(prefixSegments));\n addModuleNode(ref);\n let sawItem = false;\n for (const item of namedChildren(listNode)) {\n sawItem = true;\n if (item.type === 'identifier') {\n importIndex.set(item.text, ref);\n } else if (item.type === 'use_as_clause') {\n const alias = item.childForFieldName('alias')?.text;\n if (alias) importIndex.set(alias, ref);\n }\n // nested scoped_identifier / use_wildcard / `self` items: edge is\n // still emitted below, just no simple local binding to record.\n }\n if (sawItem) {\n builder.addEdge({ source: fileId, target: ref.id, relation: 'imports_from', confidence: 'EXTRACTED' });\n }\n break;\n }\n default:\n break; // `use foo::*;` (use_wildcard) or other rare forms — no clean binding to model\n }\n }\n\n function handleStructItem(node: TSNode): void {\n const name = node.childForFieldName('name')?.text ?? '(anonymous)';\n const id = entityId(sourceFile, name);\n builder.addNode({ id, label: `struct ${name}`, sourceFile, sourceLocation: lineOf(node) });\n builder.addEdge({ source: fileId, target: id, relation: 'contains', confidence: 'EXTRACTED' });\n nameIndex.set(name, id);\n typeMethods.set(id, new Map());\n }\n\n function handleTraitItem(node: TSNode): void {\n const name = node.childForFieldName('name')?.text ?? '(anonymous)';\n const id = entityId(sourceFile, name);\n builder.addNode({ id, label: `trait ${name}`, sourceFile, sourceLocation: lineOf(node) });\n builder.addEdge({ source: fileId, target: id, relation: 'contains', confidence: 'EXTRACTED' });\n nameIndex.set(name, id);\n }\n\n function handleFunctionItem(node: TSNode): void {\n const name = node.childForFieldName('name')?.text ?? '(anonymous)';\n const id = entityId(sourceFile, name);\n builder.addNode({ id, label: `function ${name}`, sourceFile, sourceLocation: lineOf(node) });\n builder.addEdge({ source: fileId, target: id, relation: 'contains', confidence: 'EXTRACTED' });\n nameIndex.set(name, id);\n functionNodeMap.set(node.id, id);\n }\n\n function handleImplItem(node: TSNode): void {\n const typeName = node.childForFieldName('type')?.text;\n if (!typeName) return;\n const typeId = resolveTypeTarget(typeName);\n\n const traitName = node.childForFieldName('trait')?.text;\n if (traitName) {\n builder.addEdge({\n source: typeId,\n target: resolveTypeTarget(traitName),\n relation: 'implements',\n confidence: 'EXTRACTED',\n });\n }\n\n let methods = typeMethods.get(typeId);\n if (!methods) {\n methods = new Map();\n typeMethods.set(typeId, methods);\n }\n\n const body = node.childForFieldName('body');\n if (!body) return;\n for (const member of namedChildren(body)) {\n if (member.type !== 'function_item') continue;\n const methodName = member.childForFieldName('name')?.text ?? '(anonymous)';\n const methodId = entityId(sourceFile, `${typeName}.${methodName}`);\n builder.addNode({\n id: methodId,\n label: `method ${typeName}.${methodName}`,\n sourceFile,\n sourceLocation: lineOf(member),\n });\n builder.addEdge({ source: typeId, target: methodId, relation: 'method', confidence: 'EXTRACTED' });\n methods.set(methodName, methodId);\n functionNodeMap.set(member.id, methodId);\n enclosingTypeOf.set(member.id, typeId);\n }\n }\n\n // Pass 1: top-level declarations (imports, structs, traits, free\n // functions). Impl blocks are handled in their own pass below so every\n // struct/trait name is already registered before methods attach to it.\n const implNodes: TSNode[] = [];\n for (const child of namedChildren(root)) {\n switch (child.type) {\n case 'use_declaration': {\n const arg = child.childForFieldName('argument');\n if (arg) processUseArgument(arg);\n break;\n }\n case 'struct_item':\n handleStructItem(child);\n break;\n case 'trait_item':\n handleTraitItem(child);\n break;\n case 'function_item':\n handleFunctionItem(child);\n break;\n case 'impl_item':\n implNodes.push(child);\n break;\n default:\n break;\n }\n }\n for (const impl of implNodes) handleImplItem(impl);\n\n function closestTrackedCaller(node: TSNode): string {\n let current: TSNode | null = node.parent;\n while (current) {\n const tracked = functionNodeMap.get(current.id);\n if (tracked) return tracked;\n current = current.parent;\n }\n return fileId;\n }\n\n function closestEnclosingTypeMethods(node: TSNode): Map<string, string> | undefined {\n let current: TSNode | null = node.parent;\n while (current) {\n if (current.type === 'function_item') {\n const typeId = enclosingTypeOf.get(current.id);\n if (typeId !== undefined) return typeMethods.get(typeId);\n }\n current = current.parent;\n }\n return undefined;\n }\n\n // Pass 2: calls (see the function doc comment above for the\n // EXTRACTED/INFERRED policy).\n for (const call of descendantsOfType(root, ['call_expression'])) {\n const fn = call.childForFieldName('function');\n if (!fn) continue;\n\n let targetId: string | null = null;\n let confidence: 'EXTRACTED' | 'INFERRED' = 'EXTRACTED';\n\n if (fn.type === 'identifier') {\n const name = fn.text;\n const sameFile = nameIndex.get(name);\n if (sameFile) {\n targetId = sameFile;\n } else {\n const viaImport = importIndex.get(name);\n if (viaImport) {\n targetId = viaImport.id;\n confidence = 'INFERRED';\n }\n }\n } else if (fn.type === 'field_expression') {\n const value = fn.childForFieldName('value');\n const field = fn.childForFieldName('field')?.text;\n if (value && field) {\n if (value.type === 'self') {\n const methodId = closestEnclosingTypeMethods(call)?.get(field);\n if (methodId) targetId = methodId;\n }\n }\n } else if (fn.type === 'scoped_identifier') {\n // `m::add(1, 2)` — call through a `use ... as m` module alias.\n const path = fn.childForFieldName('path')?.text;\n const name = fn.childForFieldName('name')?.text;\n if (path && name) {\n const viaImport = importIndex.get(path);\n if (viaImport) {\n targetId = viaImport.id;\n confidence = 'INFERRED';\n }\n }\n }\n\n if (!targetId) continue; // unresolved callee (builtin, external value, ...) — no noisy guess\n const callerId = closestTrackedCaller(call);\n builder.addEdge({ source: callerId, target: targetId, relation: 'calls', confidence });\n }\n\n return builder.build();\n}\n","import * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport type { Node as TSNode } from 'web-tree-sitter';\nimport type { ExtractionResult } from '../types.js';\nimport {\n ExtractionBuilder,\n descendantsOfType,\n entityId,\n externalId,\n lineOf,\n namedChildren,\n resolveModuleRef,\n toPosix,\n} from './common.js';\nimport { createParser } from './wasmLoader.js';\n\nfunction grammarForExtension(ext: string): 'typescript' | 'tsx' | 'javascript' {\n const lower = ext.toLowerCase();\n if (lower === '.tsx') return 'tsx';\n if (lower === '.jsx') return 'javascript';\n if (lower === '.ts' || lower === '.mts' || lower === '.cts') return 'typescript';\n return 'javascript'; // .js / .mjs / .cjs\n}\n\n/** Strip the surrounding quotes tree-sitter keeps on a `string` node's text. */\nfunction stripQuotes(text: string): string {\n if (text.length >= 2) {\n const first = text[0];\n const last = text[text.length - 1];\n if ((first === '\"' || first === \"'\" || first === '`') && first === last) {\n return text.slice(1, -1);\n }\n }\n return text;\n}\n\n/** The sole string-literal argument of a call, if that's exactly what it has (used for `require('x')` / `import('x')`). */\nfunction firstStringArgument(call: TSNode): string | null {\n const args = call.childForFieldName('arguments');\n if (!args) return null;\n const first = namedChildren(args)[0];\n if (!first || first.type !== 'string') return null;\n return stripQuotes(first.text);\n}\n\n/**\n * Structural extraction for .ts/.tsx/.js/.jsx via web-tree-sitter (WASM,\n * no native compilation, no eval/exec of source content).\n *\n * Pattern: parse -> walk the AST for top-level functions/classes/\n * interfaces/const-bound functions/imports/re-exports (pass 1) -> walk all\n * `call_expression`s and resolve each callee against what pass 1 saw\n * (pass 2). A same-file callee is EXTRACTED; a callee that resolves only\n * through an imported local binding (e.g. calling a function you imported,\n * or a member on a namespace import) is emitted as INFERRED — this is the\n * \"cross-file second pass\" placeholder described in the master prompt §3.\n * It intentionally does not open and parse the imported file to confirm\n * the target; a real multi-file resolver is future work (see\n * ARCHITECTURE.md). An unresolvable callee (a builtin, a call on some\n * arbitrary local value, etc.) produces no edge at all rather than a noisy\n * guess.\n */\nexport async function extractTypeScript(filePath: string, displayPath?: string): Promise<ExtractionResult> {\n const ext = path.extname(filePath);\n const grammar = grammarForExtension(ext);\n const parser = await createParser(grammar);\n\n const raw = await fs.readFile(filePath);\n const content = raw.toString('utf-8'); // replacement-decoded — never throws on invalid bytes\n\n const tree = parser.parse(content);\n if (!tree) {\n throw new Error(`extractTypeScript: parser produced no tree for ${filePath}`);\n }\n const root = tree.rootNode;\n\n const sourceFile = toPosix(displayPath ?? filePath);\n const builder = new ExtractionBuilder();\n const fileId = sourceFile;\n builder.addNode({ id: fileId, label: sourceFile, sourceFile, sourceLocation: 'L1' });\n\n /** Declared name (function/class/interface/top-level const) -> our graph id. */\n const nameIndex = new Map<string, string>();\n /** tree-sitter node id -> our graph id, for every function-like entity we track. */\n const functionNodeMap = new Map<number, string>();\n /** tree-sitter class_declaration node id -> method name -> our graph id. */\n const classMethods = new Map<number, Map<string, string>>();\n /** tree-sitter method_definition node id -> its enclosing class's node id. */\n const enclosingClassOf = new Map<number, number>();\n\n interface ImportBinding {\n ref: ReturnType<typeof resolveModuleRef>;\n /** The name as declared in the *source* module — undefined for namespace/default/require-whole\n * bindings, where the local name tells us nothing about what the target file actually calls it. */\n importedName?: string;\n kind: 'named' | 'namespace' | 'default';\n }\n /** local binding name (import, or CommonJS require()) -> where it came from. */\n const importIndex = new Map<string, ImportBinding>();\n\n function addModuleNode(ref: ReturnType<typeof resolveModuleRef>): void {\n if (builder.hasNode(ref.id)) return;\n builder.addNode({\n id: ref.id,\n label: ref.label,\n sourceFile: ref.external ? '<external>' : ref.id,\n sourceLocation: 'L1',\n });\n }\n\n /**\n * Resolve an import/require binding to the most specific target id we can\n * reasonably guess without opening the target file: a named import of a\n * same-repo module points at that module's *own* entityId for the name it\n * was declared under there (not the local alias here) — the same\n * deterministic id scheme means this will actually line up with the real\n * node once that file is extracted too. A namespace/require-whole binding\n * used via member access (`ns.foo()`) does the same with the accessed\n * property name. Anything else (default import, external package, bare\n * namespace call) falls back to the module node itself.\n */\n function importTargetId(binding: ImportBinding, property?: string): string {\n if (!binding.ref.external) {\n if (binding.kind === 'named' && binding.importedName) {\n return entityId(binding.ref.id, binding.importedName);\n }\n if (binding.kind === 'namespace' && property) {\n return entityId(binding.ref.id, property);\n }\n }\n return binding.ref.id;\n }\n\n function resolveHeritageTarget(name: string): string {\n const resolved = nameIndex.get(name);\n if (resolved) return resolved;\n const extId = externalId(name);\n if (!builder.hasNode(extId)) {\n builder.addNode({ id: extId, label: name, sourceFile: '<external>', sourceLocation: 'L0' });\n }\n return extId;\n }\n\n function handleFunctionDeclaration(node: TSNode): void {\n const name = node.childForFieldName('name')?.text ?? '(anonymous)';\n const id = entityId(sourceFile, name);\n builder.addNode({ id, label: `function ${name}`, sourceFile, sourceLocation: lineOf(node) });\n builder.addEdge({ source: fileId, target: id, relation: 'contains', confidence: 'EXTRACTED' });\n nameIndex.set(name, id);\n functionNodeMap.set(node.id, id);\n }\n\n /** `const foo = require('bar')` / `const { a, b: c } = require('bar')` — register bindings only; pass 2 emits the actual `imports` edge when it walks this same call_expression. */\n function registerRequireBinding(nameNode: TSNode, ref: ReturnType<typeof resolveModuleRef>): void {\n if (nameNode.type === 'identifier') {\n importIndex.set(nameNode.text, { ref, kind: 'namespace' });\n return;\n }\n if (nameNode.type === 'object_pattern') {\n for (const prop of namedChildren(nameNode)) {\n if (prop.type === 'shorthand_property_identifier_pattern') {\n importIndex.set(prop.text, { ref, importedName: prop.text, kind: 'named' });\n } else if (prop.type === 'pair_pattern') {\n const key = prop.childForFieldName('key')?.text;\n const value = prop.childForFieldName('value')?.text;\n if (key && value) importIndex.set(value, { ref, importedName: key, kind: 'named' });\n }\n }\n }\n }\n\n function handleTopLevelVariableFunctions(node: TSNode): void {\n for (const declarator of namedChildren(node)) {\n if (declarator.type !== 'variable_declarator') continue;\n const value = declarator.childForFieldName('value');\n if (!value) continue;\n\n if (value.type === 'arrow_function' || value.type === 'function_expression') {\n const name = declarator.childForFieldName('name')?.text;\n if (!name) continue;\n const id = entityId(sourceFile, name);\n builder.addNode({ id, label: `function ${name}`, sourceFile, sourceLocation: lineOf(declarator) });\n builder.addEdge({ source: fileId, target: id, relation: 'contains', confidence: 'EXTRACTED' });\n nameIndex.set(name, id);\n functionNodeMap.set(value.id, id);\n continue;\n }\n\n if (value.type === 'call_expression') {\n const callee = value.childForFieldName('function');\n const specifier = callee?.type === 'identifier' && callee.text === 'require' ? firstStringArgument(value) : null;\n if (specifier) {\n const nameNode = declarator.childForFieldName('name');\n if (nameNode) {\n const ref = resolveModuleRef(sourceFile, specifier);\n addModuleNode(ref);\n registerRequireBinding(nameNode, ref);\n }\n }\n }\n }\n }\n\n function handleInterfaceDeclaration(node: TSNode): void {\n const name = node.childForFieldName('name')?.text ?? '(anonymous)';\n const id = entityId(sourceFile, name);\n builder.addNode({ id, label: `interface ${name}`, sourceFile, sourceLocation: lineOf(node) });\n builder.addEdge({ source: fileId, target: id, relation: 'contains', confidence: 'EXTRACTED' });\n nameIndex.set(name, id);\n }\n\n function handleClassDeclaration(node: TSNode): void {\n const name = node.childForFieldName('name')?.text ?? '(anonymous)';\n const classId = entityId(sourceFile, name);\n builder.addNode({ id: classId, label: `class ${name}`, sourceFile, sourceLocation: lineOf(node) });\n builder.addEdge({ source: fileId, target: classId, relation: 'contains', confidence: 'EXTRACTED' });\n nameIndex.set(name, classId);\n functionNodeMap.set(node.id, classId);\n\n const heritage = namedChildren(node).find((c) => c.type === 'class_heritage');\n if (heritage) {\n for (const clause of namedChildren(heritage)) {\n if (clause.type === 'extends_clause') {\n const base = clause.childForFieldName('value')?.text;\n if (base) {\n builder.addEdge({\n source: classId,\n target: resolveHeritageTarget(base),\n relation: 'inherits',\n confidence: 'EXTRACTED',\n });\n }\n } else if (clause.type === 'implements_clause') {\n for (const iface of namedChildren(clause)) {\n builder.addEdge({\n source: classId,\n target: resolveHeritageTarget(iface.text),\n relation: 'implements',\n confidence: 'EXTRACTED',\n });\n }\n }\n }\n }\n\n const methods = new Map<string, string>();\n classMethods.set(node.id, methods);\n\n const body = node.childForFieldName('body');\n if (body) {\n for (const member of namedChildren(body)) {\n if (member.type !== 'method_definition') continue;\n const methodName = member.childForFieldName('name')?.text ?? '(anonymous)';\n const methodId = entityId(sourceFile, `${name}.${methodName}`);\n builder.addNode({\n id: methodId,\n label: `method ${name}.${methodName}`,\n sourceFile,\n sourceLocation: lineOf(member),\n });\n builder.addEdge({ source: classId, target: methodId, relation: 'method', confidence: 'EXTRACTED' });\n methods.set(methodName, methodId);\n functionNodeMap.set(member.id, methodId);\n enclosingClassOf.set(member.id, node.id);\n }\n }\n }\n\n function handleImport(node: TSNode): void {\n const sourceNode = node.childForFieldName('source');\n if (!sourceNode) return;\n const ref = resolveModuleRef(sourceFile, stripQuotes(sourceNode.text));\n addModuleNode(ref);\n\n const clause = namedChildren(node).find((c) => c.type === 'import_clause');\n if (!clause) return; // side-effect-only import, e.g. `import './setup.js'`\n\n let sawNamed = false;\n let sawWhole = false;\n\n for (const child of namedChildren(clause)) {\n if (child.type === 'named_imports') {\n sawNamed = true;\n for (const specifierNode of namedChildren(child)) {\n const importedName = specifierNode.childForFieldName('name')?.text;\n const localName = specifierNode.childForFieldName('alias')?.text ?? importedName;\n if (localName) importIndex.set(localName, { ref, importedName, kind: 'named' });\n }\n } else if (child.type === 'namespace_import') {\n sawWhole = true;\n const localName = namedChildren(child)[0]?.text;\n if (localName) importIndex.set(localName, { ref, kind: 'namespace' });\n } else if (child.type === 'identifier') {\n sawWhole = true;\n importIndex.set(child.text, { ref, kind: 'default' });\n }\n }\n\n if (sawNamed) {\n builder.addEdge({ source: fileId, target: ref.id, relation: 'imports_from', confidence: 'EXTRACTED' });\n }\n if (sawWhole) {\n builder.addEdge({ source: fileId, target: ref.id, relation: 'imports', confidence: 'EXTRACTED' });\n }\n }\n\n function handleReExport(node: TSNode): void {\n const sourceNode = node.childForFieldName('source');\n if (!sourceNode) return;\n const ref = resolveModuleRef(sourceFile, stripQuotes(sourceNode.text));\n addModuleNode(ref);\n builder.addEdge({ source: fileId, target: ref.id, relation: 're_exports', confidence: 'EXTRACTED' });\n }\n\n function unwrapExport(node: TSNode): TSNode | null {\n if (node.type !== 'export_statement') return node;\n return node.childForFieldName('declaration');\n }\n\n // Pass 1: top-level declarations (functions, classes, interfaces,\n // const-bound functions, imports, re-exports).\n for (const child of namedChildren(root)) {\n if (child.type === 'import_statement') {\n handleImport(child);\n continue;\n }\n if (child.type === 'export_statement' && child.childForFieldName('source')) {\n handleReExport(child);\n continue;\n }\n\n const effective = unwrapExport(child);\n if (!effective) continue;\n\n switch (effective.type) {\n case 'function_declaration':\n case 'generator_function_declaration':\n handleFunctionDeclaration(effective);\n break;\n case 'class_declaration':\n handleClassDeclaration(effective);\n break;\n case 'interface_declaration':\n handleInterfaceDeclaration(effective);\n break;\n case 'lexical_declaration':\n case 'variable_declaration':\n handleTopLevelVariableFunctions(effective);\n break;\n default:\n break;\n }\n }\n\n function closestTrackedCaller(node: TSNode): string {\n let current: TSNode | null = node.parent;\n while (current) {\n const tracked = functionNodeMap.get(current.id);\n if (tracked) return tracked;\n current = current.parent;\n }\n return fileId;\n }\n\n function closestEnclosingClassMethods(node: TSNode): Map<string, string> | undefined {\n let current: TSNode | null = node.parent;\n while (current) {\n if (current.type === 'method_definition') {\n const classNodeId = enclosingClassOf.get(current.id);\n if (classNodeId !== undefined) return classMethods.get(classNodeId);\n }\n current = current.parent;\n }\n return undefined;\n }\n\n // Pass 2: calls (see the function doc comment above for the\n // EXTRACTED/INFERRED policy).\n for (const call of descendantsOfType(root, ['call_expression'])) {\n const fn = call.childForFieldName('function');\n if (!fn) continue;\n\n // CommonJS `require('x')` and dynamic `import('x')` are import\n // expressions wearing a call's clothing — treat them as `imports`\n // edges (module-level, EXTRACTED) rather than `calls`, wherever in the\n // tree they occur (module scope, or lazily inside a function).\n if ((fn.type === 'identifier' && fn.text === 'require') || fn.type === 'import') {\n const specifier = firstStringArgument(call);\n if (specifier) {\n const ref = resolveModuleRef(sourceFile, specifier);\n addModuleNode(ref);\n builder.addEdge({\n source: closestTrackedCaller(call),\n target: ref.id,\n relation: 'imports',\n confidence: 'EXTRACTED',\n });\n continue;\n }\n }\n\n let targetId: string | null = null;\n let confidence: 'EXTRACTED' | 'INFERRED' = 'EXTRACTED';\n\n if (fn.type === 'identifier') {\n const name = fn.text;\n const sameFile = nameIndex.get(name);\n if (sameFile) {\n targetId = sameFile;\n } else {\n const binding = importIndex.get(name);\n if (binding) {\n targetId = importTargetId(binding);\n confidence = 'INFERRED';\n }\n }\n } else if (fn.type === 'member_expression') {\n const object = fn.childForFieldName('object');\n const property = fn.childForFieldName('property')?.text;\n if (object && property) {\n if (object.type === 'this') {\n const methodId = closestEnclosingClassMethods(call)?.get(property);\n if (methodId) targetId = methodId;\n } else if (object.type === 'identifier') {\n const binding = importIndex.get(object.text);\n if (binding) {\n targetId = importTargetId(binding, property);\n confidence = 'INFERRED';\n }\n }\n }\n }\n\n if (!targetId) continue; // unresolved callee (builtin, external value, ...) — no noisy guess\n const callerId = closestTrackedCaller(call);\n builder.addEdge({ source: callerId, target: targetId, relation: 'calls', confidence });\n }\n\n return builder.build();\n}\n","import Graph from 'graphology';\nimport { validateExtraction } from './schema.js';\nimport type { Confidence, ExtractionResult } from './types.js';\n\nconst CONFIDENCE_RANK: Record<Confidence, number> = { EXTRACTED: 3, INFERRED: 2, AMBIGUOUS: 1 };\n\nfunction strongerConfidence(a: Confidence, b: Confidence): Confidence {\n return CONFIDENCE_RANK[a] >= CONFIDENCE_RANK[b] ? a : b;\n}\n\nfunction ensureNode(graph: Graph, id: string): void {\n if (graph.hasNode(id)) return;\n // An edge endpoint that never appeared in any extraction's `nodes` array —\n // shouldn't happen with a well-behaved extractor, but auto-vivify a\n // minimal placeholder rather than let addEdge throw and abort the merge.\n graph.addNode(id, { label: id, sourceFile: '<unknown>', sourceLocation: 'L0' });\n}\n\n/**\n * Merge per-file extraction results into one graphology graph.\n *\n * Every extraction is validated against the ExtractionResult schema before\n * anything is added to the graph — a single malformed extraction throws\n * (via validateExtraction()/ExtractionValidationError) before any node from\n * *any* extraction is merged, so a bad extractor can never silently\n * corrupt a graph that also contains good data.\n *\n * Nodes and edges are sorted before being added so the resulting graph (and\n * the graph.json ultimately exported from it) is deterministic regardless\n * of the order files were extracted in. Duplicate edges — same\n * source/target/relation, e.g. two different call sites resolving to the\n * same callee — are merged into a single edge, keeping the strongest\n * confidence seen (EXTRACTED > INFERRED > AMBIGUOUS) rather than being\n * counted as parallel edges (the schema has no call-count/weight field, so\n * \"A calls B\" is either true or it isn't). Multiple distinct relations\n * between the same pair (e.g. a file both `imports` and `imports_from` the\n * same module) are kept as separate edges.\n */\nexport function buildGraph(extractions: ExtractionResult[]): Graph {\n const graph = new Graph({ type: 'directed', multi: true, allowSelfLoops: true });\n\n const validated = extractions.map((extraction, index) =>\n validateExtraction(extraction, `extraction #${index}`),\n );\n\n const allNodes = validated.flatMap((extraction) => extraction.nodes);\n const allEdges = validated.flatMap((extraction) => extraction.edges);\n\n const sortedNodes = [...allNodes].sort((a, b) => a.id.localeCompare(b.id));\n for (const node of sortedNodes) {\n if (graph.hasNode(node.id)) continue;\n graph.addNode(node.id, {\n label: node.label,\n sourceFile: node.sourceFile,\n sourceLocation: node.sourceLocation,\n });\n }\n\n const sortedEdges = [...allEdges].sort(\n (a, b) =>\n a.source.localeCompare(b.source) ||\n a.target.localeCompare(b.target) ||\n a.relation.localeCompare(b.relation),\n );\n\n for (const edge of sortedEdges) {\n ensureNode(graph, edge.source);\n ensureNode(graph, edge.target);\n\n const key = `${edge.source}|${edge.relation}|${edge.target}`;\n if (graph.hasEdge(key)) {\n const existing = graph.getEdgeAttribute(key, 'confidence') as Confidence;\n graph.setEdgeAttribute(key, 'confidence', strongerConfidence(existing, edge.confidence));\n continue;\n }\n graph.addEdgeWithKey(key, edge.source, edge.target, {\n relation: edge.relation,\n confidence: edge.confidence,\n });\n }\n\n return graph;\n}\n","import { z } from 'zod';\nimport type { ExtractionResult } from './types.js';\n\n/**\n * Runtime schema for ExtractionResult (see types.ts + master prompt §2).\n * Every extractor's output is validated against this before buildGraph()\n * merges it — a malformed extractor must fail loudly, never silently\n * corrupt the graph.\n */\nexport const ConfidenceSchema = z.enum(['EXTRACTED', 'INFERRED', 'AMBIGUOUS']);\n\nexport const RelationSchema = z.enum([\n 'calls',\n 'imports',\n 'imports_from',\n 'inherits',\n 'implements',\n 'mixes_in',\n 'embeds',\n 'references',\n 'contains',\n 'method',\n 're_exports',\n]);\n\nexport const GraphNodeSchema = z.object({\n id: z.string().min(1, 'node id must be non-empty'),\n label: z.string(),\n sourceFile: z.string(),\n sourceLocation: z.string(),\n});\n\nexport const GraphEdgeSchema = z.object({\n source: z.string().min(1, 'edge source must be non-empty'),\n target: z.string().min(1, 'edge target must be non-empty'),\n relation: RelationSchema,\n confidence: ConfidenceSchema,\n});\n\nexport const ExtractionResultSchema = z.object({\n nodes: z.array(GraphNodeSchema),\n edges: z.array(GraphEdgeSchema),\n});\n\nexport interface ExtractionValidationIssue {\n path: Array<string | number>;\n message: string;\n}\n\n/** Thrown by validateExtraction() on schema mismatch. Carries the raw zod issues. */\nexport class ExtractionValidationError extends Error {\n readonly issues: ExtractionValidationIssue[];\n\n constructor(message: string, issues: ExtractionValidationIssue[]) {\n super(message);\n this.name = 'ExtractionValidationError';\n this.issues = issues;\n }\n}\n\n/**\n * Validate an unknown value (typically an extractor's return value) against\n * the ExtractionResult schema. Throws ExtractionValidationError with a clear,\n * human-readable message on mismatch instead of letting malformed data reach\n * buildGraph().\n */\nexport function validateExtraction(value: unknown, context?: string): ExtractionResult {\n const result = ExtractionResultSchema.safeParse(value);\n if (!result.success) {\n const label = context ? ` (${context})` : '';\n const issues: ExtractionValidationIssue[] = result.error.issues.map((issue) => ({\n path: issue.path as Array<string | number>,\n message: issue.message,\n }));\n const details = issues\n .map((issue) => `${issue.path.join('.') || '<root>'}: ${issue.message}`)\n .join('; ');\n throw new ExtractionValidationError(`Invalid ExtractionResult${label}: ${details}`, issues);\n }\n return result.data;\n}\n","import * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport type { ExtractionResult } from './types.js';\n\n/**\n * Cross-file reference resolution — the pass the per-file extractors can't\n * do alone. An extractor guesses an import target's id from the specifier\n * text (`import { scoreNodes } from './query.js'` → `src/query.js::scoreNodes`)\n * without opening the target file, so in a TypeScript repo the guess carries\n * the wrong extension (`.js` vs the real `src/query.ts`), and extensionless\n * or directory imports (`'./utils'` → `src/utils`) miss entirely. Once every\n * file is extracted we know the full set of real node ids, so guessed ids\n * that don't exist can be re-pointed at the single real node they were\n * clearly aiming for — turning phantom auto-vivified endpoints into edges\n * that reach the actual definition (this is what makes `graphify affected`\n * see cross-file callers).\n *\n * Deliberately conservative: a guess is only re-pointed when exactly ONE\n * real candidate matches; anything ambiguous or unknown is left alone\n * (buildGraph auto-vivifies it as before). Edge confidence is untouched —\n * the call target is still inferred, it just lands on a real node now.\n */\n\nconst CODE_EXTENSIONS = [\n '.ts', '.tsx', '.mts', '.cts',\n '.js', '.jsx', '.mjs', '.cjs',\n '.py', '.go', '.rs', '.java', '.cs', '.rb',\n];\n\n/** Ids that name things outside the extracted file set — never remap candidates. */\nfunction isOpaque(id: string): boolean {\n return id.startsWith('module:') || id.startsWith('external:') || id.startsWith('db:');\n}\n\nexport interface ResolveOptions {\n /**\n * The scanned package's own name(s) (from package.json). Tests very\n * commonly import the package's PUBLIC entry (`import { persist } from\n * 'zustand/middleware'`) rather than a relative path — without this,\n * those land on an opaque `module:` node and the test never connects to\n * the source it exercises (so `graphify tests` under-selects).\n */\n selfNames?: string[];\n}\n\n/** Where a self-import's subpath usually lives in the source tree. */\nconst SELF_IMPORT_STEMS = (subpath: string): string[] =>\n subpath === ''\n ? ['index', 'src/index', 'lib/index', 'source/index', 'src/main']\n : [\n subpath,\n `src/${subpath}`,\n `lib/${subpath}`,\n `source/${subpath}`,\n `${subpath}/index`,\n `src/${subpath}/index`,\n `lib/${subpath}/index`,\n ];\n\n/** Candidate real files for `module:<selfName>[/subpath]`. */\nfunction selfImportCandidates(spec: string, selfNames: string[]): string[] | null {\n const selfName = selfNames.find((n) => spec === n || spec.startsWith(`${n}/`));\n if (selfName === undefined) return null;\n const subpath = spec === selfName ? '' : spec.slice(selfName.length + 1);\n return SELF_IMPORT_STEMS(subpath).flatMap((stem) => CODE_EXTENSIONS.map((ext) => `${stem}${ext}`));\n}\n\n/** The scanned root's own package name(s), for ResolveOptions.selfNames. Missing/invalid package.json -> []. */\nexport async function readSelfNames(root: string): Promise<string[]> {\n try {\n const pkg = JSON.parse(await fs.readFile(path.join(root, 'package.json'), 'utf-8')) as { name?: unknown };\n return typeof pkg.name === 'string' && pkg.name.length > 0 ? [pkg.name] : [];\n } catch {\n return [];\n }\n}\n\nfunction stripKnownExtension(p: string): string | null {\n for (const ext of CODE_EXTENSIONS) {\n if (p.endsWith(ext)) return p.slice(0, -ext.length);\n }\n return null;\n}\n\n/** All the real file paths a guessed path could have meant: other extensions on the same stem, or the directory's index file. */\nfunction candidatePaths(guessed: string): string[] {\n const stem = stripKnownExtension(guessed) ?? guessed;\n const candidates: string[] = [];\n for (const ext of CODE_EXTENSIONS) candidates.push(`${stem}${ext}`);\n for (const ext of CODE_EXTENSIONS) candidates.push(`${guessed}/index${ext}`);\n if (stem !== guessed) {\n for (const ext of CODE_EXTENSIONS) candidates.push(`${stem}/index${ext}`);\n }\n return candidates.filter((c) => c !== guessed);\n}\n\n/** The unique real id `guessed` could resolve to, or null when unknown/ambiguous. */\nfunction uniqueMatch(guessed: string, candidates: string[], realIds: ReadonlySet<string>): string | null {\n const matches = new Set<string>();\n for (const candidate of candidates) {\n if (realIds.has(candidate)) matches.add(candidate);\n }\n if (matches.size !== 1) return null;\n return [...matches][0] as string;\n}\n\nexport interface ResolveStats {\n /** Edge endpoints re-pointed from a guessed id to a real node id. */\n resolvedEndpoints: number;\n /** Placeholder module nodes dropped because the real file node replaced them. */\n droppedPlaceholders: number;\n}\n\n/**\n * Mutates `extractions` in place: re-points guessed edge endpoints at real\n * node ids and drops the placeholder module nodes those guesses created.\n */\nexport function resolveCrossFileReferences(\n extractions: ExtractionResult[],\n options: ResolveOptions = {},\n): ResolveStats {\n const selfNames = options.selfNames ?? [];\n const realIds = new Set<string>();\n const realFiles = new Set<string>();\n for (const extraction of extractions) {\n for (const node of extraction.nodes) realIds.add(node.id);\n // Every extractor seeds its own file node FIRST (id === sourceFile) —\n // the only reliable signal for pure re-export barrels, which have no\n // entities or contains edges but are exactly what self-imports like\n // 'zustand/middleware' point at.\n const first = extraction.nodes[0];\n if (first && first.id === first.sourceFile && !isOpaque(first.id)) {\n realFiles.add(first.id);\n }\n for (const node of extraction.nodes) {\n const sep = node.id.indexOf('::');\n if (sep > 0) realFiles.add(node.id.slice(0, sep));\n }\n for (const edge of extraction.edges) {\n if (edge.relation === 'contains') realFiles.add(edge.source);\n }\n }\n\n const remap = new Map<string, string>();\n\n const resolveId = (id: string): string | null => {\n // Self-imports (the package importing itself by its published name)\n // are module: ids we CAN ground — check before the opaque bailout.\n if (id.startsWith('module:') && selfNames.length > 0) {\n const cachedSelf = remap.get(id);\n if (cachedSelf !== undefined) return cachedSelf;\n const candidates = selfImportCandidates(id.slice('module:'.length), selfNames);\n if (candidates !== null) {\n const resolved = uniqueMatch(id, candidates, realFiles);\n if (resolved !== null) {\n remap.set(id, resolved);\n return resolved;\n }\n }\n return null;\n }\n if (isOpaque(id)) return null;\n const cached = remap.get(id);\n if (cached !== undefined) return cached;\n\n const sep = id.indexOf('::');\n let resolved: string | null;\n if (sep > 0) {\n // Guessed entity: only ever a phantom (extractors never create nodes\n // for these), so an existing id needs no fixing.\n if (realIds.has(id)) return null;\n const guessedPath = id.slice(0, sep);\n const name = id.slice(sep);\n const candidates = candidatePaths(guessedPath).map((p) => `${p}${name}`);\n resolved = uniqueMatch(id, candidates, realIds);\n } else {\n // Guessed module/file: the extractor DID add a placeholder node for\n // it, so it is in realIds — what matters is whether it's a really\n // extracted file. Check against realFiles, and remap only onto real\n // files so a file reference never lands on some non-file node.\n if (realFiles.has(id)) return null;\n resolved = uniqueMatch(id, candidatePaths(id), realFiles);\n }\n if (resolved !== null) remap.set(id, resolved);\n return resolved;\n };\n\n let resolvedEndpoints = 0;\n for (const extraction of extractions) {\n for (const edge of extraction.edges) {\n const source = resolveId(edge.source);\n if (source !== null) {\n edge.source = source;\n resolvedEndpoints++;\n }\n const target = resolveId(edge.target);\n if (target !== null) {\n edge.target = target;\n resolvedEndpoints++;\n }\n }\n }\n\n // Placeholder module nodes (added by extractors for guessed same-repo\n // imports) whose id was remapped now duplicate the real file node — drop\n // them so they don't linger as isolated near-duplicates.\n let droppedPlaceholders = 0;\n for (const extraction of extractions) {\n const before = extraction.nodes.length;\n extraction.nodes = extraction.nodes.filter((node) => !remap.has(node.id));\n droppedPlaceholders += before - extraction.nodes.length;\n }\n\n return { resolvedEndpoints, droppedPlaceholders };\n}\n","import { createHash } from 'node:crypto';\nimport Graph from 'graphology';\n// A pure-JS, graphology-native Leiden implementation — extracted from the\n// upstream graphology monorepo's own (never separately published)\n// src/communities-leiden, repackaged with an optional `maxIterations` cap.\n// No native compilation (no .node bindings) — same \"no native\n// compilation\" constraint as the rest of this package. See v2 notes below.\nimport leiden from '@aflsolutions/graphology-communities-leiden';\nimport louvain from 'graphology-communities-louvain';\n\n/** Fixed seed so repeated runs on the same graph explore ties identically. */\nconst FIXED_SEED = 0x5eed_1234;\n\n/** mulberry32 — small, dependency-free, deterministic PRNG. */\nfunction mulberry32(seed: number): () => number {\n let a = seed >>> 0;\n return function next(): number {\n a = (a + 0x6d2b79f5) | 0;\n let t = Math.imul(a ^ (a >>> 15), 1 | a);\n t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n };\n}\n\ninterface EdgeEntry {\n key: string;\n source: string;\n target: string;\n attributes: Record<string, unknown>;\n}\n\n/**\n * Build a copy of `graph` with nodes and edges (re-)inserted in sorted\n * order, so the clustering algorithm's own internal iteration — and\n * therefore its tie-breaking — is fed a canonical order regardless of how\n * the input graph happened to be constructed (master prompt §4: \"sort\n * nodes/edges before feeding the algorithm\").\n */\nfunction sortedWorkingCopy(graph: Graph): Graph {\n const copy = new Graph({ type: graph.type, multi: graph.multi, allowSelfLoops: graph.allowSelfLoops });\n\n const nodeIds = graph.nodes().sort((a, b) => a.localeCompare(b));\n for (const id of nodeIds) {\n copy.addNode(id, { ...graph.getNodeAttributes(id) });\n }\n\n const edgeEntries: EdgeEntry[] = [];\n graph.forEachEdge((edge, attributes, source, target) => {\n edgeEntries.push({ key: edge, source, target, attributes });\n });\n edgeEntries.sort(\n (a, b) =>\n a.source.localeCompare(b.source) ||\n a.target.localeCompare(b.target) ||\n String(a.attributes.relation).localeCompare(String(b.attributes.relation)),\n );\n for (const entry of edgeEntries) {\n copy.addEdgeWithKey(entry.key, entry.source, entry.target, { ...entry.attributes });\n }\n\n return copy;\n}\n\nexport type ClusterAlgorithm = 'louvain' | 'leiden';\n\nexport interface ClusterOptions {\n /**\n * `louvain` (default, v1 behavior, unchanged) or `leiden` (v2: better\n * community quality / guaranteed well-connectedness, via\n * `@aflsolutions/graphology-communities-leiden` — see master prompt's\n * v2 upgrade ideas, \"Real Leiden clustering\"). Both run deterministically\n * against a sorted working copy with the same fixed-seed PRNG.\n */\n algorithm?: ClusterAlgorithm;\n /**\n * Leiden-only: hard cap on outer iterations, for very large graphs where\n * full convergence is expensive and the last iterations buy little\n * additional modularity. Ignored for `algorithm: 'louvain'`.\n */\n maxIterations?: number;\n}\n\n/**\n * @aflsolutions/graphology-communities-leiden (like upstream graphology's\n * own Leiden) only implements the undirected case — it throws on a graph\n * whose edges are all directed. Community detection is inherently an\n * undirected-connectivity notion anyway (classic Louvain/Leiden\n * modularity is defined over undirected graphs), so we run Leiden against\n * an undirected copy and copy the resulting `community` assignment back\n * onto `working` by node id.\n */\nfunction toUndirectedCopy(graph: Graph): Graph {\n const copy = new Graph({ type: 'undirected', multi: true, allowSelfLoops: graph.allowSelfLoops });\n graph.forEachNode((nodeId, attributes) => copy.addNode(nodeId, { ...attributes }));\n graph.forEachEdge((edgeKey, attributes, source, target) => {\n copy.addEdgeWithKey(edgeKey, source, target, { ...attributes });\n });\n return copy;\n}\n\nfunction runAlgorithm(working: Graph, options: ClusterOptions): void {\n const rng = mulberry32(FIXED_SEED);\n if (options.algorithm === 'leiden') {\n const undirected = toUndirectedCopy(working);\n leiden.assign(undirected, { rng, maxIterations: options.maxIterations ?? 0 });\n undirected.forEachNode((nodeId, attributes) => {\n working.setNodeAttribute(nodeId, 'community', attributes.community);\n });\n return;\n }\n louvain.assign(working, { rng });\n}\n\n/**\n * Community detection — Louvain by default (v1, unchanged), or Leiden\n * (v2, `{ algorithm: 'leiden' }`) for better-quality, guaranteed\n * well-connected communities on the same graph. Deterministic: runs\n * against a sorted working copy with a fixed RNG seed, then copies the\n * resulting `community` assignment back onto the original graph by node id\n * (so `cluster()` still mutates and returns the graph instance it was\n * given). Labels each community after its highest-degree (\"hub\") member;\n * no LLM required for a usable baseline. Also stamps a `communityHash`\n * (sha256 of the community's sorted member ids) so `--cluster-only` can\n * tell which communities actually changed vs. merely being relabeled with\n * a different arbitrary index next run.\n */\nexport function cluster(graph: Graph, options: ClusterOptions = {}): Graph {\n if (graph.order === 0) return graph;\n\n const working = sortedWorkingCopy(graph);\n runAlgorithm(working, options);\n\n // Highest-degree member per community, computed on the sorted copy so\n // ties break on node id deterministically.\n const hubs = new Map<number, { id: string; degree: number }>();\n working.forEachNode((nodeId) => {\n const community = working.getNodeAttribute(nodeId, 'community') as number;\n const degree = working.degree(nodeId);\n const current = hubs.get(community);\n if (!current || degree > current.degree) {\n hubs.set(community, { id: nodeId, degree });\n }\n });\n\n const membersByCommunity = new Map<number, string[]>();\n working.forEachNode((nodeId) => {\n const community = working.getNodeAttribute(nodeId, 'community') as number;\n const list = membersByCommunity.get(community);\n if (list) list.push(nodeId);\n else membersByCommunity.set(community, [nodeId]);\n });\n\n const labelByCommunity = new Map<number, string>();\n const hashByCommunity = new Map<number, string>();\n for (const [community, members] of membersByCommunity) {\n members.sort((a, b) => a.localeCompare(b));\n hashByCommunity.set(community, createHash('sha256').update(members.join('\\n')).digest('hex'));\n\n const hub = hubs.get(community);\n const hubLabel = hub ? (working.getNodeAttribute(hub.id, 'label') as string) : undefined;\n labelByCommunity.set(community, hubLabel && hubLabel.length > 0 ? hubLabel : `community-${community}`);\n }\n\n working.forEachNode((nodeId) => {\n const community = working.getNodeAttribute(nodeId, 'community') as number;\n graph.mergeNodeAttributes(nodeId, {\n community,\n communityLabel: labelByCommunity.get(community),\n communityHash: hashByCommunity.get(community),\n });\n });\n\n return graph;\n}\n","import type Graph from 'graphology';\nimport type { Analysis, Confidence } from './types.js';\n\n/** A node needs at least this many total connections to ever be a \"god node\", regardless of graph size. */\nconst ABSOLUTE_DEGREE_FLOOR = 10;\n/** ...and needs to be at least this many times the graph's mean degree. */\nconst MEAN_DEGREE_MULTIPLIER = 3;\n/** Cap how many items of a given kind get spelled out in a single message. */\nconst MAX_LISTED = 10;\n\nfunction truncatedList(items: string[]): string {\n const shown = items.slice(0, MAX_LISTED).join(', ');\n return items.length > MAX_LISTED ? `${shown}, ...` : shown;\n}\n\n/** Connected components treating the (directed) graph as undirected — reachability via any edge direction. */\nfunction connectedComponents(graph: Graph): string[][] {\n const visited = new Set<string>();\n const components: string[][] = [];\n const sortedNodes = [...graph.nodes()].sort((a, b) => a.localeCompare(b));\n\n for (const start of sortedNodes) {\n if (visited.has(start)) continue;\n const component: string[] = [];\n const queue: string[] = [start];\n visited.add(start);\n\n while (queue.length > 0) {\n const current = queue.shift() as string;\n component.push(current);\n const neighbors = [...graph.neighbors(current)].sort((a, b) => a.localeCompare(b));\n for (const neighbor of neighbors) {\n if (!visited.has(neighbor)) {\n visited.add(neighbor);\n queue.push(neighbor);\n }\n }\n }\n\n component.sort((a, b) => a.localeCompare(b));\n components.push(component);\n }\n\n components.sort((a, b) => b.length - a.length || (a[0] ?? '').localeCompare(b[0] ?? ''));\n return components;\n}\n\nfunction labelOf(graph: Graph, id: string): string {\n return (graph.getNodeAttribute(id, 'label') as string | undefined) ?? id;\n}\n\n/**\n * Surface god-nodes (excessive fan-in/out), structural surprises (self\n * references, AMBIGUOUS edges), and open questions (isolated nodes,\n * disconnected components) for a human to review in GRAPH_REPORT.md.\n */\nexport function analyze(graph: Graph): Analysis {\n const godNodes: string[] = [];\n const surprises: string[] = [];\n const openQuestions: string[] = [];\n\n if (graph.order === 0) {\n openQuestions.push(\n 'The graph is empty — no nodes were extracted. Check detect()/extract() coverage for this codebase.',\n );\n return { godNodes, surprises, openQuestions };\n }\n\n const degreeEntries = [...graph.nodes()]\n .map((id) => ({ id, degree: graph.degree(id) }))\n .sort((a, b) => a.id.localeCompare(b.id));\n const meanDegree = degreeEntries.reduce((sum, e) => sum + e.degree, 0) / degreeEntries.length;\n const threshold = Math.max(ABSOLUTE_DEGREE_FLOOR, meanDegree * MEAN_DEGREE_MULTIPLIER);\n\n for (const { id, degree } of degreeEntries) {\n if (degree > 0 && degree >= threshold) {\n godNodes.push(id);\n surprises.push(\n `${labelOf(graph, id)} has ${degree} connections (fan-in + fan-out) — well above the graph ` +\n `average of ${meanDegree.toFixed(1)}. Likely a god node / hotspot worth reviewing for ` +\n 'excessive coupling.',\n );\n }\n }\n\n graph.forEachEdge((_edge, attributes, source, target) => {\n if (source === target) {\n surprises.push(`${labelOf(graph, source)} has a self-referential \"${String(attributes.relation)}\" edge.`);\n }\n });\n\n const ambiguousEdges: string[] = [];\n graph.forEachEdge((_edge, attributes, source, target) => {\n if ((attributes.confidence as Confidence) === 'AMBIGUOUS') {\n ambiguousEdges.push(\n `${labelOf(graph, source)} --${String(attributes.relation)}--> ${labelOf(graph, target)}`,\n );\n }\n });\n if (ambiguousEdges.length > 0) {\n ambiguousEdges.sort((a, b) => a.localeCompare(b));\n openQuestions.push(\n `${ambiguousEdges.length} edge(s) are marked AMBIGUOUS and need human review: ` +\n truncatedList(ambiguousEdges),\n );\n }\n\n const isolated = degreeEntries.filter((e) => e.degree === 0).map((e) => e.id);\n if (isolated.length > 0) {\n openQuestions.push(\n `${isolated.length} node(s) have no incoming or outgoing edges (${truncatedList(isolated)}) — ` +\n 'dead code, an entry point, or a gap in extraction?',\n );\n }\n\n const components = connectedComponents(graph);\n if (components.length > 1) {\n const largest = components[0] as string[];\n openQuestions.push(\n `The graph has ${components.length} disconnected components — the largest has ${largest.length} ` +\n 'node(s). Confirm this reflects real module boundaries rather than missed cross-file edges.',\n );\n }\n\n return { godNodes, surprises, openQuestions };\n}\n","import type Graph from 'graphology';\nimport type { Analysis } from './types.js';\n\nfunction labelOf(graph: Graph, id: string): string {\n return (graph.getNodeAttribute(id, 'label') as string | undefined) ?? id;\n}\n\nfunction bulletList(items: string[]): string {\n if (items.length === 0) return '_None found._';\n return items.map((item) => `- ${item}`).join('\\n');\n}\n\ninterface CommunitySummary {\n label: string;\n members: string[];\n}\n\nfunction summarizeCommunities(graph: Graph): CommunitySummary[] {\n const byCommunity = new Map<number, CommunitySummary>();\n graph.forEachNode((nodeId, attributes) => {\n const community = attributes.community as number | undefined;\n if (community === undefined) return;\n const label = (attributes.communityLabel as string | undefined) ?? `community-${community}`;\n const existing = byCommunity.get(community);\n if (existing) {\n existing.members.push(nodeId);\n } else {\n byCommunity.set(community, { label, members: [nodeId] });\n }\n });\n\n const summaries = [...byCommunity.values()];\n for (const summary of summaries) {\n summary.members.sort((a, b) => a.localeCompare(b));\n }\n summaries.sort((a, b) => b.members.length - a.members.length || a.label.localeCompare(b.label));\n return summaries;\n}\n\n/**\n * Render the plain-language GRAPH_REPORT.md content: a short summary,\n * community breakdown, god nodes, structural surprises, and open\n * questions — everything a human (or an agent) needs to sanity-check a\n * freshly built graph before trusting it.\n */\nexport function renderReport(graph: Graph, analysis: Analysis, now: Date = new Date()): string {\n const generatedAt = now.toISOString();\n const communities = summarizeCommunities(graph);\n\n const lines: string[] = [];\n lines.push('# Graph Report');\n lines.push('');\n lines.push(`Generated: ${generatedAt}`);\n lines.push('');\n lines.push('## Summary');\n lines.push('');\n lines.push(`- **Nodes:** ${graph.order}`);\n lines.push(`- **Edges:** ${graph.size}`);\n lines.push(`- **Communities:** ${communities.length}`);\n lines.push(`- **God nodes:** ${analysis.godNodes.length}`);\n lines.push('');\n\n lines.push('## Communities');\n lines.push('');\n if (communities.length === 0) {\n lines.push('_No communities detected (graph may be empty, or cluster() has not run yet)._');\n } else {\n for (const community of communities) {\n lines.push(`### ${community.label} (${community.members.length} member(s))`);\n lines.push('');\n const shown = community.members.slice(0, 25).map((id) => labelOf(graph, id));\n lines.push(bulletList(shown));\n if (community.members.length > 25) {\n lines.push(`- ...and ${community.members.length - 25} more`);\n }\n lines.push('');\n }\n }\n\n lines.push('## God Nodes');\n lines.push('');\n lines.push(\n 'Nodes with unusually high fan-in + fan-out relative to the rest of this graph — often a sign of a ' +\n 'shared utility, a bottleneck, or a module that has taken on too many responsibilities.',\n );\n lines.push('');\n lines.push(bulletList(analysis.godNodes.map((id) => labelOf(graph, id))));\n lines.push('');\n\n lines.push('## Structural Surprises');\n lines.push('');\n lines.push(bulletList(analysis.surprises));\n lines.push('');\n\n lines.push('## Open Questions');\n lines.push('');\n lines.push(bulletList(analysis.openQuestions));\n lines.push('');\n\n return lines.join('\\n');\n}\n","import { createRequire } from 'node:module';\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport type Graph from 'graphology';\nimport { escapeHtml, sanitizeLabel, validateGraphPath } from './security.js';\nimport type { ExportOptions } from './types.js';\n\nconst require = createRequire(import.meta.url);\n\n/** Locate the bundled, self-contained vis-network assets (no CDN, works fully offline). */\nfunction resolveVisNetworkAssets(): { jsPath: string; cssPath: string } {\n const packageJsonPath = require.resolve('vis-network/package.json');\n const root = path.dirname(packageJsonPath);\n return {\n jsPath: path.join(root, 'standalone', 'umd', 'vis-network.min.js'),\n cssPath: path.join(root, 'styles', 'vis-network.min.css'),\n };\n}\n\n/** A small, deterministic categorical palette, cycled by community index. */\nconst COMMUNITY_PALETTE = [\n '#4e79a7',\n '#f28e2b',\n '#e15759',\n '#76b7b2',\n '#59a14f',\n '#edc948',\n '#b07aa1',\n '#ff9da7',\n '#9c755f',\n '#bab0ac',\n];\n\nfunction colorForCommunity(community: number | undefined): string {\n if (community === undefined) return '#8ab4f8';\n const index = ((community % COMMUNITY_PALETTE.length) + COMMUNITY_PALETTE.length) % COMMUNITY_PALETTE.length;\n return COMMUNITY_PALETTE[index] as string;\n}\n\n/**\n * Embedding untrusted-derived strings (node labels ultimately come from\n * source file content) inside an inline <script> tag has one extra XSS\n * vector JSON.stringify() alone doesn't cover: a literal `</script>`\n * substring in the JSON text would close our script tag early and let the\n * rest be parsed as raw HTML. Escape the forward slash so that can't happen.\n */\nfunction safeInlineJson(value: unknown): string {\n return JSON.stringify(value, null, 2).replace(/<\\/(script)/gi, '<\\\\/$1');\n}\n\nfunction buildVisNodesAndEdges(graph: Graph): { nodes: unknown[]; edges: unknown[] } {\n const nodes = graph.nodes().map((id) => {\n const attributes = graph.getNodeAttributes(id);\n const rawLabel = (attributes.label as string | undefined) ?? id;\n const label = escapeHtml(sanitizeLabel(rawLabel));\n const sourceFile = escapeHtml(sanitizeLabel((attributes.sourceFile as string | undefined) ?? ''));\n const sourceLocation = escapeHtml(sanitizeLabel((attributes.sourceLocation as string | undefined) ?? ''));\n const communityLabel = escapeHtml(sanitizeLabel((attributes.communityLabel as string | undefined) ?? ''));\n return {\n id,\n label,\n title: `${label}\\n${sourceFile}${sourceLocation ? `:${sourceLocation}` : ''}${\n communityLabel ? `\\ncommunity: ${communityLabel}` : ''\n }`,\n color: colorForCommunity(attributes.community as number | undefined),\n };\n });\n\n const edges: unknown[] = [];\n graph.forEachEdge((edgeKey, attributes, source, target) => {\n const relation = escapeHtml(sanitizeLabel(String(attributes.relation ?? '')));\n const confidence = escapeHtml(sanitizeLabel(String(attributes.confidence ?? '')));\n edges.push({\n id: edgeKey,\n from: source,\n to: target,\n label: relation,\n title: `${relation} (${confidence})`,\n dashes: confidence === 'INFERRED' || confidence === 'AMBIGUOUS',\n arrows: 'to',\n });\n });\n\n return { nodes, edges };\n}\n\nasync function renderHtml(graph: Graph): Promise<string> {\n const { jsPath, cssPath } = resolveVisNetworkAssets();\n const [visJs, visCss] = await Promise.all([\n fs.readFile(jsPath, 'utf-8'),\n fs.readFile(cssPath, 'utf-8'),\n ]);\n\n const { nodes, edges } = buildVisNodesAndEdges(graph);\n const dataJson = safeInlineJson({ nodes, edges });\n\n return `<!doctype html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<title>graphify — graph.html</title>\n<style>\n html, body { margin: 0; padding: 0; height: 100%; font-family: system-ui, sans-serif; }\n #graph { width: 100%; height: 100vh; }\n ${visCss}\n</style>\n</head>\n<body>\n<div id=\"graph\"></div>\n<script>\n${visJs}\n</script>\n<script>\n(function () {\n var data = ${dataJson};\n var nodes = new vis.DataSet(data.nodes);\n var edges = new vis.DataSet(data.edges);\n var container = document.getElementById('graph');\n var network = new vis.Network(container, { nodes: nodes, edges: edges }, {\n nodes: { shape: 'dot', size: 12, font: { size: 14 } },\n edges: { smooth: { type: 'continuous' }, font: { size: 10, align: 'middle' } },\n physics: { stabilization: true },\n interaction: { hover: true, tooltipDelay: 150 },\n });\n window.__graphifyNetwork = network;\n})();\n</script>\n</body>\n</html>\n`;\n}\n\n/**\n * Write graph.json (graphology's node-link serialization, GraphRAG-ready)\n * and, per options, graph.html (vis-network, bundled inline — no CDN, works\n * fully offline) and GRAPH_REPORT.md. Every label/title embedded in\n * graph.html is passed through security.sanitizeLabel() + escapeHtml()\n * first (XSS control, see SECURITY.md).\n *\n * Obsidian vault / .graphml / Neo4j cypher export are NOT implemented in\n * v1 — if requested, exportGraph logs a clear warning and skips them\n * rather than silently doing nothing or faking output.\n */\nexport async function exportGraph(graph: Graph, options: ExportOptions, report?: string): Promise<void> {\n const outDir = path.resolve(options.outDir);\n await fs.mkdir(outDir, { recursive: true });\n\n const jsonPath = validateGraphPath('graph.json', outDir);\n await fs.writeFile(jsonPath, JSON.stringify(graph.toJSON(), null, 2), 'utf-8');\n\n if (options.html !== false) {\n const htmlPath = validateGraphPath('graph.html', outDir);\n await fs.writeFile(htmlPath, await renderHtml(graph), 'utf-8');\n }\n\n if (report !== undefined) {\n const reportPath = validateGraphPath('GRAPH_REPORT.md', outDir);\n await fs.writeFile(reportPath, report, 'utf-8');\n }\n\n const notImplemented: string[] = [];\n if (options.svg) notImplemented.push('--svg');\n if (options.graphml) notImplemented.push('--graphml');\n if (options.neo4j) notImplemented.push('--neo4j');\n if (options.obsidian) notImplemented.push('--obsidian');\n for (const flag of notImplemented) {\n console.warn(`graphify: ${flag} export is not implemented yet in v1 — skipping.`);\n }\n}\n","/**\n * Security helpers — URL validation, SSRF-guarded fetch, path guards, label\n * sanitization, prompt-injection defenses. Every control listed in\n * SECURITY.md must have a corresponding function here and a unit test in\n * tests/security.test.ts. See the master prompt §5 for the full checklist.\n */\n\nimport { createHash } from 'node:crypto';\nimport * as dns from 'node:dns';\nimport * as http from 'node:http';\nimport * as https from 'node:https';\nimport * as fs from 'node:fs';\nimport * as net from 'node:net';\nimport * as nodePath from 'node:path';\n\nconst ALLOWED_SCHEMES = new Set(['http:', 'https:']);\nconst MAX_FETCH_BYTES = 50 * 1024 * 1024;\nconst MAX_TEXT_BYTES = 10 * 1024 * 1024;\nconst MAX_LABEL_LEN = 256;\nconst MAX_REDIRECTS = 5;\nconst REQUEST_TIMEOUT_MS = 15_000;\n\n/** Hostnames that must never be reachable, regardless of what they resolve to. */\nconst BLOCKED_HOSTNAMES = new Set([\n 'metadata.google.internal',\n 'metadata.internal',\n 'metadata',\n 'metadata.azure.com',\n 'instance-data',\n 'instance-data.ec2.internal',\n]);\n\n// ---------------------------------------------------------------------------\n// IP range checks (SSRF guard core). Implemented without extra dependencies.\n// ---------------------------------------------------------------------------\n\nfunction ipv4ToInt(ip: string): number | null {\n const parts = ip.split('.');\n if (parts.length !== 4) return null;\n let result = 0;\n for (const part of parts) {\n if (!/^\\d{1,3}$/.test(part)) return null;\n const n = Number(part);\n if (n > 255) return null;\n result = (result << 8) | n;\n }\n return result >>> 0;\n}\n\nfunction ipv4InCidr(ipInt: number, cidr: string): boolean {\n const [base, prefixStr] = cidr.split('/');\n const prefix = Number(prefixStr);\n const baseInt = ipv4ToInt(base ?? '');\n if (baseInt === null) return false;\n const mask = prefix === 0 ? 0 : (~0 << (32 - prefix)) >>> 0;\n return (ipInt & mask) >>> 0 === (baseInt & mask) >>> 0;\n}\n\n/** IPv4 ranges that must never be connected to from a server-side fetch. */\nconst BLOCKED_IPV4_CIDRS = [\n '0.0.0.0/8', // \"this\" network\n '10.0.0.0/8', // private\n '100.64.0.0/10', // carrier-grade NAT (CGN)\n '127.0.0.0/8', // loopback\n '169.254.0.0/16', // link-local (covers 169.254.169.254 cloud metadata)\n '172.16.0.0/12', // private\n '192.0.0.0/24', // IETF protocol assignments\n '192.0.2.0/24', // TEST-NET-1\n '192.168.0.0/16', // private\n '198.18.0.0/15', // benchmarking\n '198.51.100.0/24', // TEST-NET-2\n '203.0.113.0/24', // TEST-NET-3\n '224.0.0.0/4', // multicast\n '240.0.0.0/4', // reserved\n '255.255.255.255/32', // broadcast\n];\n\nexport function isForbiddenIpv4(ip: string): boolean {\n const ipInt = ipv4ToInt(ip);\n if (ipInt === null) return true; // malformed -> treat as forbidden, fail closed\n return BLOCKED_IPV4_CIDRS.some((cidr) => ipv4InCidr(ipInt, cidr));\n}\n\n/** Expand a (possibly `::`-compressed) IPv6 address into 8 16-bit groups. */\nfunction expandIpv6(ip: string): number[] | null {\n const withoutZone = ip.split('%')[0] ?? '';\n const parts = withoutZone.split('::');\n if (parts.length > 2) return null;\n\n const head = parts[0] ? parts[0].split(':').filter((s) => s.length > 0) : [];\n const tail = parts.length === 2 && parts[1] ? parts[1].split(':').filter((s) => s.length > 0) : [];\n\n let missing = 0;\n if (parts.length === 2) {\n missing = 8 - head.length - tail.length;\n if (missing < 0) return null;\n } else if (head.length + tail.length !== 8) {\n return null;\n }\n\n const groupsHex = [...head, ...Array(missing).fill('0'), ...tail];\n if (groupsHex.length !== 8) return null;\n\n const groups: number[] = [];\n for (const g of groupsHex) {\n if (!/^[0-9a-fA-F]{1,4}$/.test(g)) return null;\n groups.push(parseInt(g, 16));\n }\n return groups;\n}\n\nexport function isForbiddenIpv6(ip: string): boolean {\n const lower = ip.toLowerCase();\n if (lower === '::1' || lower === '::') return true;\n\n const mapped = /^::ffff:(\\d+\\.\\d+\\.\\d+\\.\\d+)$/.exec(lower);\n if (mapped) return isForbiddenIpv4(mapped[1] as string);\n\n const groups = expandIpv6(lower);\n if (groups === null) return true; // unparsable -> fail closed\n const first = groups[0] as number;\n if ((first & 0xffc0) === 0xfe80) return true; // fe80::/10 link-local\n if ((first & 0xfe00) === 0xfc00) return true; // fc00::/7 unique local\n if ((first & 0xff00) === 0xff00) return true; // ff00::/8 multicast\n if (groups.every((g) => g === 0)) return true; // unspecified/all-zero\n return false;\n}\n\nexport function isForbiddenIp(ip: string): boolean {\n return net.isIPv6(ip) ? isForbiddenIpv6(ip) : isForbiddenIpv4(ip);\n}\n\n// ---------------------------------------------------------------------------\n// URL validation\n// ---------------------------------------------------------------------------\n\n/**\n * Validate a URL is http/https and, when the hostname is itself a literal\n * IP or a known cloud-metadata hostname, reject it synchronously. DNS-bound\n * hostnames are re-validated at connect time by safeFetch() (see below) —\n * this function alone cannot rule out DNS rebinding for a hostname that\n * currently resolves to a public IP.\n */\nexport function validateUrl(url: string): string {\n let parsed: URL;\n try {\n parsed = new URL(url);\n } catch {\n throw new Error(`Invalid URL: ${url}`);\n }\n\n if (!ALLOWED_SCHEMES.has(parsed.protocol)) {\n throw new Error(\n `URL scheme not allowed: \"${parsed.protocol}\" (allowed: ${[...ALLOWED_SCHEMES].join(', ')})`,\n );\n }\n\n const hostname = parsed.hostname.toLowerCase();\n if (BLOCKED_HOSTNAMES.has(hostname)) {\n throw new Error(`URL targets a blocked host: ${hostname}`);\n }\n\n // WHATWG URL keeps the brackets on an IPv6 literal host (e.g. \"[::1]\") —\n // strip them before checking net.isIP()/isForbiddenIp().\n const bareHost =\n hostname.startsWith('[') && hostname.endsWith(']') ? hostname.slice(1, -1) : hostname;\n if (net.isIP(bareHost) && isForbiddenIp(bareHost)) {\n throw new Error(`URL targets a forbidden IP address: ${bareHost}`);\n }\n\n return parsed.toString();\n}\n\n// ---------------------------------------------------------------------------\n// safeFetch — SSRF-guarded, size-capped, redirect-revalidating fetch\n// ---------------------------------------------------------------------------\n\nexport type LookupFn = (hostname: string) => Promise<{ address: string; family: number }>;\n\n/**\n * Resolve a hostname (or pass through a literal IP) and validate the\n * result. `lookup` defaults to the real `dns.promises.lookup` — tests\n * substitute a fake to exercise the rebind guard deterministically without\n * making a real DNS query.\n */\nexport async function resolveAndValidate(\n hostname: string,\n lookup: LookupFn = dns.promises.lookup,\n): Promise<{ address: string; family: number }> {\n if (net.isIP(hostname)) {\n if (isForbiddenIp(hostname)) {\n throw new Error(`Refusing to connect to forbidden IP: ${hostname}`);\n }\n return { address: hostname, family: net.isIPv6(hostname) ? 6 : 4 };\n }\n const result = await lookup(hostname);\n if (isForbiddenIp(result.address)) {\n throw new Error(`Refusing to connect to forbidden IP: ${hostname} -> ${result.address}`);\n }\n return result;\n}\n\nexport interface RawResponse {\n statusCode: number;\n headers: http.IncomingHttpHeaders;\n body: Buffer;\n}\n\n/** Minimal shape of the `http`/`https` modules that requestOnce() needs — narrow on purpose so tests can substitute a fake transport instead of mocking network I/O. */\nexport type RequestTransport = Pick<typeof http, 'request'>;\n\n/**\n * Issue a single HTTP(S) request, connecting to `resolvedAddress` directly\n * (via a `lookup` override) rather than re-resolving DNS at connect time —\n * this is what prevents a DNS-rebind attacker from swapping the target\n * between validation and connection (TOCTOU). Streams the body and aborts\n * once it exceeds the byte cap for its declared content type.\n */\nexport function requestOnce(\n target: URL,\n resolvedAddress: string,\n resolvedFamily: number,\n transport: RequestTransport = target.protocol === 'https:' ? https : http,\n): Promise<RawResponse> {\n return new Promise((resolve, reject) => {\n const req = transport.request(\n {\n protocol: target.protocol,\n hostname: target.hostname,\n host: target.hostname,\n port: target.port || (target.protocol === 'https:' ? 443 : 80),\n path: `${target.pathname}${target.search}`,\n method: 'GET',\n timeout: REQUEST_TIMEOUT_MS,\n headers: { 'user-agent': 'graphify/0.1', accept: '*/*' },\n // Force the connection to the address we already validated — do not\n // let Node re-resolve `target.hostname` at connect time.\n lookup: (\n _hostname: string,\n options: unknown,\n callback: (err: NodeJS.ErrnoException | null, address: string, family: number) => void,\n ) => {\n callback(null, resolvedAddress, resolvedFamily);\n },\n } as http.RequestOptions,\n (res) => {\n const statusCode = res.statusCode ?? 0;\n const contentType = String(res.headers['content-type'] ?? '');\n const isTextual = /^text\\/|json|xml|html|charset=/i.test(contentType);\n const cap = isTextual ? MAX_TEXT_BYTES : MAX_FETCH_BYTES;\n\n const chunks: Buffer[] = [];\n let total = 0;\n let aborted = false;\n\n res.on('data', (chunk: Buffer) => {\n total += chunk.length;\n if (total > cap) {\n aborted = true;\n res.destroy();\n req.destroy();\n reject(new Error(`Response exceeded ${cap} byte cap (content-type: ${contentType})`));\n return;\n }\n chunks.push(chunk);\n });\n res.on('end', () => {\n if (aborted) return;\n resolve({ statusCode, headers: res.headers, body: Buffer.concat(chunks) });\n });\n res.on('error', (err) => {\n if (!aborted) reject(err);\n });\n },\n );\n\n req.on('timeout', () => {\n req.destroy(new Error(`Request timed out after ${REQUEST_TIMEOUT_MS}ms`));\n });\n req.on('error', reject);\n req.end();\n });\n}\n\nexport interface SafeFetchDeps {\n /** Override DNS resolution + IP validation (default: resolveAndValidate). */\n resolve?: (hostname: string) => Promise<{ address: string; family: number }>;\n /** Override the actual request (default: requestOnce against real http/https). */\n request?: (target: URL, address: string, family: number) => Promise<RawResponse>;\n}\n\n/**\n * Fetch a URL with the SSRF guards from validateUrl() plus streaming size\n * caps (MAX_FETCH_BYTES / MAX_TEXT_BYTES) and a hard error on non-2xx\n * status. Every redirect hop is independently validated and re-resolved —\n * a redirect to a private/loopback/metadata address is rejected exactly\n * like a direct request would be.\n *\n * `deps` exists so tests can substitute the DNS/network collaborators with\n * deterministic fakes (see tests/security.test.ts) instead of mocking\n * Node's core modules or hitting real sockets — production callers should\n * never need to pass it.\n */\nexport async function safeFetch(url: string, deps: SafeFetchDeps = {}): Promise<Buffer> {\n const resolve = deps.resolve ?? resolveAndValidate;\n const doRequest = deps.request ?? requestOnce;\n\n let current = validateUrl(url);\n for (let hop = 0; hop <= MAX_REDIRECTS; hop++) {\n const target = new URL(current);\n const { address, family } = await resolve(target.hostname);\n const response = await doRequest(target, address, family);\n\n if (response.statusCode >= 300 && response.statusCode < 400) {\n const location = response.headers.location;\n if (!location) {\n throw new Error(`Redirect response (${response.statusCode}) missing Location header`);\n }\n const next = new URL(location, target).toString();\n current = validateUrl(next);\n continue;\n }\n\n if (response.statusCode < 200 || response.statusCode >= 300) {\n throw new Error(`Non-2xx response: ${response.statusCode}`);\n }\n\n return response.body;\n }\n throw new Error(`Too many redirects (> ${MAX_REDIRECTS}) while fetching ${url}`);\n}\n\n// ---------------------------------------------------------------------------\n// Database DSN validation (MySQL schema extraction)\n// ---------------------------------------------------------------------------\n\nexport interface ValidatedDsn {\n /**\n * Credential-free rendering (`mysql://host:port/db`). This is the ONLY\n * form that may ever appear in graph nodes, reports, logs, or errors —\n * the password exists solely inside `connection`.\n */\n safeDisplay: string;\n connection: {\n host: string;\n port: number;\n user: string;\n password: string;\n database: string;\n };\n}\n\nconst DEFAULT_MYSQL_PORT = 3306;\n\n/**\n * Parse and validate a `mysql://user:pass@host:port/database` DSN.\n *\n * Deliberately does NOT apply the SSRF IP blocklist that safeFetch()\n * enforces: connecting to a localhost/private-network database is the\n * primary legitimate use of an explicitly user-supplied DSN, unlike a URL\n * scraped out of corpus content. The security property that matters here\n * is credential containment — see ValidatedDsn.safeDisplay.\n */\nexport function validateDsn(dsn: string): ValidatedDsn {\n let parsed: URL;\n try {\n parsed = new URL(dsn);\n } catch {\n throw new Error('Invalid DSN — expected mysql://user:pass@host:port/database');\n }\n\n if (parsed.protocol !== 'mysql:') {\n throw new Error(`DSN scheme not supported: \"${parsed.protocol}\" (only mysql: is supported)`);\n }\n\n const database = decodeURIComponent(parsed.pathname.replace(/^\\//, ''));\n if (!database || database.includes('/')) {\n throw new Error('DSN must name exactly one database, e.g. mysql://localhost:3306/mydb');\n }\n if (!parsed.hostname) {\n throw new Error('DSN must include a host, e.g. mysql://localhost:3306/mydb');\n }\n\n const port = parsed.port ? Number(parsed.port) : DEFAULT_MYSQL_PORT;\n return {\n safeDisplay: `mysql://${parsed.hostname}:${port}/${database}`,\n connection: {\n host: parsed.hostname,\n port,\n user: decodeURIComponent(parsed.username) || 'root',\n password: decodeURIComponent(parsed.password),\n database,\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Path traversal guard\n// ---------------------------------------------------------------------------\n\n/**\n * Resolve `path` and require it stays inside `base` (defaults to\n * `<cwd>/graphify-out`). `base` must already exist. Throws on traversal\n * attempts (`../`, absolute escapes, symlink-resolved escapes).\n */\nexport function validateGraphPath(path: string, base?: string): string {\n const baseDir = base ?? nodePath.join(process.cwd(), 'graphify-out');\n\n let resolvedBase: string;\n try {\n resolvedBase = fs.realpathSync(baseDir);\n } catch {\n throw new Error(`Base directory does not exist: ${baseDir}`);\n }\n\n const candidate = nodePath.isAbsolute(path) ? path : nodePath.join(resolvedBase, path);\n const resolvedCandidate = nodePath.resolve(candidate);\n\n // Resolve symlinks for whichever is the deepest existing ancestor, so a\n // symlink inside an otherwise-valid path can't escape the base dir either.\n let realCandidate = resolvedCandidate;\n try {\n realCandidate = fs.realpathSync(resolvedCandidate);\n } catch {\n // Path (or part of it) may not exist yet (e.g. a file we're about to\n // write) — fall back to the lexically-resolved path for the check.\n }\n\n const relative = nodePath.relative(resolvedBase, realCandidate);\n const escapes = relative === '..' || relative.startsWith(`..${nodePath.sep}`) || nodePath.isAbsolute(relative);\n if (escapes) {\n throw new Error(`Path escapes graphify-out/: ${path}`);\n }\n\n return realCandidate;\n}\n\n// ---------------------------------------------------------------------------\n// Label sanitization (unchanged reference implementation) + HTML escaping\n// ---------------------------------------------------------------------------\n\n/** Strip control characters, cap length. Apply to every node/edge label. */\nexport function sanitizeLabel(text: string | null | undefined): string {\n if (text == null) return '';\n // eslint-disable-next-line no-control-regex -- intentional: stripping raw control chars\n const stripped = String(text).replace(/[\\x00-\\x1f\\x7f]/g, '');\n return stripped.slice(0, MAX_LABEL_LEN);\n}\n\n/**\n * HTML-escape a string. Callers must run sanitizeLabel() first for\n * length/control-char stripping, then escapeHtml() immediately before\n * embedding into graph.html (XSS control, see SECURITY.md).\n */\nexport function escapeHtml(text: string): string {\n return text\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\n}\n\n// ---------------------------------------------------------------------------\n// Prompt-injection defenses for LLM-bound file content\n// ---------------------------------------------------------------------------\n\n/**\n * Known jailbreak / chat-template sentinels that must never reach a prompt\n * unescaped, whether they occur in source files or are forged to spoof our\n * own <untrusted_source> delimiter.\n */\nconst SENTINEL_PATTERNS: RegExp[] = [\n /<\\|im_start\\|>/gi,\n /<\\|im_end\\|>/gi,\n /<\\|system\\|>/gi,\n /\\[INST\\]/gi,\n /\\[\\/INST\\]/gi,\n /<<SYS>>/gi,\n /<<\\/SYS>>/gi,\n /<\\/untrusted_source>/gi,\n /<untrusted_source/gi,\n];\n\n/**\n * Render brackets as fullwidth lookalikes (< > [ ]) so the defanged\n * echo is human-visible but no longer byte-identical to the original\n * sentinel — a naive downstream scan for the literal delimiter/sentinel\n * text will not re-match our own \"we found one\" marker.\n */\nfunction toFullwidthBrackets(text: string): string {\n return text\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\\[/g, '[')\n .replace(/\\]/g, ']');\n}\n\n/**\n * Replace known jailbreak/chat-template sentinels with a visibly defanged\n * form — never silently stripped (silent stripping can itself be an\n * injection vector if it changes meaning unexpectedly).\n */\nfunction defangSentinels(content: string): string {\n let result = content;\n for (const pattern of SENTINEL_PATTERNS) {\n result = result.replace(pattern, (match) => `[DEFANGED:${toFullwidthBrackets(match)}]`);\n }\n return result;\n}\n\n/**\n * Wrap file content for LLM prompts in a hash-stamped untrusted-source\n * delimiter and neutralize known jailbreak/chat-template sentinels. This\n * raises the bar against prompt injection; it does not eliminate it —\n * document that plainly wherever this is referenced.\n */\nexport function wrapUntrustedSource(path: string, content: string): string {\n const sha256 = createHash('sha256').update(content, 'utf8').digest('hex');\n const safePath = escapeHtml(sanitizeLabel(path));\n const defanged = defangSentinels(content);\n return `<untrusted_source path=\"${safePath}\" sha256=\"${sha256}\">\\n${defanged}\\n</untrusted_source>`;\n}\n","import * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport type Graph from 'graphology';\nimport { analyze } from './analyze.js';\nimport { buildGraph } from './build.js';\nimport { ExtractionCache } from './extractionCache.js';\nimport { cluster, type ClusterAlgorithm } from './cluster.js';\nimport { collectFiles } from './detect.js';\nimport { extract } from './extract.js';\nimport { exportGraph } from './export.js';\nimport { renderReport } from './report.js';\nimport { readSelfNames, resolveCrossFileReferences } from './resolve.js';\nimport type { Analysis, ExtractionResult, FileManifest } from './types.js';\n\nexport interface PipelineOptions {\n /** Where to write graph.json/graph.html/GRAPH_REPORT.md. Defaults to `<root>/graphify-out`. */\n outDir?: string;\n html?: boolean;\n svg?: boolean;\n graphml?: boolean;\n neo4j?: boolean;\n obsidian?: boolean;\n /** `louvain` (default, v1) or `leiden` (v2 — better community quality, see cluster.ts). */\n algorithm?: ClusterAlgorithm;\n /** Leiden-only: cap on outer iterations for very large graphs. */\n maxIterations?: number;\n /**\n * Pre-computed extractions from non-filesystem sources (e.g. a MySQL\n * schema via extractMysql()) merged into the same graph as the code.\n */\n extraExtractions?: ExtractionResult[];\n /**\n * Incremental mode: reuse cached per-file extractions (keyed by content\n * hash) and re-parse only changed files. The cache is warmed on every\n * run either way — `update` only controls whether it's read.\n */\n update?: boolean;\n /** Called with a short progress message after each stage (e.g. for CLI stderr output). */\n onProgress?: (message: string) => void;\n}\n\nexport interface PipelineResult {\n manifest: FileManifest;\n graph: Graph;\n analysis: Analysis;\n report: string;\n}\n\n/**\n * The full `detect -> extract -> build -> cluster -> analyze -> report ->\n * export` pipeline as a single library call — the CLI's default command is\n * a thin wrapper over this. Every extension registered in\n * EXTRACTOR_REGISTRY (see extract.ts) is run; files with no registered\n * extractor are skipped (not an error — see extract()'s doc comment).\n */\nexport async function runPipeline(root: string, options: PipelineOptions = {}): Promise<PipelineResult> {\n const progress = options.onProgress ?? (() => {});\n const resolvedRoot = path.resolve(root);\n\n progress(`Scanning ${resolvedRoot} ...`);\n const manifest = collectFiles(resolvedRoot);\n progress(\n `Found ${manifest.totalFiles} file(s) (${manifest.files.code.length} code, ` +\n `${manifest.skippedSensitive.length} skipped as sensitive).`,\n );\n\n const outDir = options.outDir ?? path.join(resolvedRoot, 'graphify-out');\n const cache = new ExtractionCache(outDir);\n\n progress('Extracting...');\n const extractions: ExtractionResult[] = [];\n let cacheHits = 0;\n for (const relFile of manifest.files.code.sort((a, b) => a.localeCompare(b))) {\n // Read path: relative to CWD so fs reads inside the extractor resolve\n // correctly. Display path (second arg): relative to the scan root, so\n // node ids/sourceFile are stable and portable no matter where the\n // pipeline was launched from — required for cross-project merging.\n const filePath = path.relative(process.cwd(), path.join(resolvedRoot, relFile)) || relFile;\n try {\n const key = cache.key(relFile, await fs.readFile(path.join(resolvedRoot, relFile)));\n let extraction = options.update ? await cache.get(key) : null;\n if (extraction) {\n cacheHits++;\n } else {\n extraction = await extract(filePath, relFile);\n // Cache BEFORE the resolution pass mutates edges — entries must stay pristine.\n await cache.put(key, extraction);\n }\n extractions.push(extraction);\n } catch (error) {\n progress(` extraction failed for ${relFile}: ${(error as Error).message}`);\n throw error;\n }\n }\n if (options.update) {\n progress(` cache: ${cacheHits} hit(s), ${extractions.length - cacheHits} re-extracted.`);\n }\n\n if (options.extraExtractions && options.extraExtractions.length > 0) {\n extractions.push(...options.extraExtractions);\n }\n\n progress('Resolving cross-file references...');\n const resolveStats = resolveCrossFileReferences(extractions, {\n selfNames: await readSelfNames(resolvedRoot),\n });\n if (resolveStats.resolvedEndpoints > 0) {\n progress(\n ` re-pointed ${resolveStats.resolvedEndpoints} guessed reference(s) at real nodes ` +\n `(${resolveStats.droppedPlaceholders} placeholder node(s) dropped).`,\n );\n }\n\n progress('Building graph...');\n const graph = buildGraph(extractions);\n\n progress(`Clustering (${options.algorithm ?? 'louvain'})...`);\n cluster(graph, { algorithm: options.algorithm, maxIterations: options.maxIterations });\n\n progress('Analyzing...');\n const analysis = analyze(graph);\n\n progress('Rendering report...');\n const report = renderReport(graph, analysis);\n\n progress(`Exporting to ${outDir} ...`);\n await exportGraph(\n graph,\n {\n outDir,\n html: options.html,\n svg: options.svg,\n graphml: options.graphml,\n neo4j: options.neo4j,\n obsidian: options.obsidian,\n },\n report,\n );\n\n progress('Done.');\n return { manifest, graph, analysis, report };\n}\n","import { createHash } from 'node:crypto';\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport type { ExtractionResult } from './types.js';\n\n/**\n * Per-file extraction cache — what makes `--update` (and every rebuild\n * behind a git hook or --watch) incremental. Entries are keyed by a hash of\n * the file's CONTENT plus its root-relative path: content because that's\n * what extraction depends on, path because node ids embed it. A stale entry\n * for content that changed simply never matches again; the whole directory\n * can always be deleted safely.\n */\n\nexport class ExtractionCache {\n private readonly dir: string;\n\n constructor(outDir: string) {\n this.dir = path.join(outDir, 'cache');\n }\n\n key(relFile: string, content: Buffer | string): string {\n return createHash('sha256').update(relFile).update('\u0000').update(content).digest('hex');\n }\n\n async get(key: string): Promise<ExtractionResult | null> {\n try {\n const raw = await fs.readFile(path.join(this.dir, `${key}.json`), 'utf-8');\n const parsed = JSON.parse(raw) as ExtractionResult;\n if (!Array.isArray(parsed.nodes) || !Array.isArray(parsed.edges)) return null;\n return parsed;\n } catch {\n return null;\n }\n }\n\n async put(key: string, extraction: ExtractionResult): Promise<void> {\n await fs.mkdir(this.dir, { recursive: true });\n await fs.writeFile(path.join(this.dir, `${key}.json`), JSON.stringify(extraction), 'utf-8');\n }\n}\n","import * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport Graph from 'graphology';\nimport { validateGraphPath } from './security.js';\n\n/**\n * Load a previously-exported graph.json back into a graphology Graph.\n * Always goes through security.validateGraphPath() (path-traversal guard —\n * see SECURITY.md) so a caller-supplied `outDir`/CLI arg can never make\n * this read outside the graphify-out/ directory it resolves to.\n */\nexport async function loadGraph(outDir: string = path.join(process.cwd(), 'graphify-out')): Promise<Graph> {\n const jsonPath = validateGraphPath('graph.json', outDir);\n const raw = await fs.readFile(jsonPath, 'utf-8');\n const data: unknown = JSON.parse(raw);\n return Graph.from(data as Parameters<typeof Graph.from>[0]);\n}\n","import type Graph from 'graphology';\n\n/**\n * Library-level graph queries shared by the CLI (`graphify query/path/\n * explain`) and the MCP server tools of the same name. None of this is an\n * LLM call — it's lexical node matching + graph traversal, so it works\n * fully offline and deterministically.\n */\n\nconst STOPWORDS = new Set([\n 'a', 'an', 'the', 'is', 'are', 'was', 'were', 'do', 'does', 'did', 'how',\n 'what', 'where', 'when', 'why', 'who', 'which', 'to', 'of', 'in', 'on',\n 'for', 'and', 'or', 'this', 'that', 'it', 'does', 'that\\'s',\n]);\n\n/** Insert spaces at camelCase boundaries so identifier words become separate tokens. */\nfunction splitCamelCase(text: string): string {\n return text\n .replace(/([a-z0-9])([A-Z])/g, '$1 $2')\n .replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2');\n}\n\nfunction tokenize(text: string): string[] {\n return splitCamelCase(text)\n .toLowerCase()\n .split(/[^a-z0-9]+/)\n .filter((token) => token.length > 1 && !STOPWORDS.has(token));\n}\n\n/**\n * Split an identifier-ish string (node label/id) into its word subtokens:\n * camelCase, snake_case, kebab-case, dots, and path separators all become\n * boundaries, so `src/a/fileStorage.js::saveAttachment` yields\n * `src, file, storage, js, save, attachment`.\n */\nfunction subtokenize(text: string): string[] {\n return splitCamelCase(text)\n .toLowerCase()\n .split(/[^a-z0-9]+/)\n .filter((token) => token.length > 1);\n}\n\n/** Don't run the fuzzy tier on tokens this short — too many false positives. */\nconst FUZZY_MIN_TOKEN_LEN = 3;\n/** Minimum similarity for a fuzzy match to count at all. */\nconst FUZZY_THRESHOLD = 0.7;\nconst SUBTOKEN_MATCH_SCORE = 1;\nconst SUBSTRING_MATCH_SCORE = 0.6;\nconst FUZZY_MATCH_WEIGHT = 0.5;\n\n/**\n * Optimal-string-alignment Damerau-Levenshtein distance. Chosen over\n * bigram-set similarity because the common code-search typo is a\n * transposition (\"sorceNodes\"), which OSA counts as one edit but bigram\n * overlap punishes brutally.\n */\nfunction osaDistance(a: string, b: string): number {\n let prev2: number[] = [];\n let prev: number[] = Array.from({ length: b.length + 1 }, (_, j) => j);\n let curr: number[] = new Array<number>(b.length + 1).fill(0);\n\n for (let i = 1; i <= a.length; i++) {\n curr[0] = i;\n for (let j = 1; j <= b.length; j++) {\n const substitution = a[i - 1] === b[j - 1] ? 0 : 1;\n let best = Math.min(\n (prev[j] as number) + 1,\n (curr[j - 1] as number) + 1,\n (prev[j - 1] as number) + substitution,\n );\n if (i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1]) {\n best = Math.min(best, (prev2[j - 2] as number) + 1);\n }\n curr[j] = best;\n }\n [prev2, prev, curr] = [prev, curr, new Array<number>(b.length + 1).fill(0)];\n }\n return prev[b.length] as number;\n}\n\n/** Normalized similarity in [0, 1]; short-circuits pairs whose length gap alone puts them under FUZZY_THRESHOLD. */\nfunction fuzzySimilarity(a: string, b: string): number {\n if (a === b) return 1;\n const maxLen = Math.max(a.length, b.length);\n if (maxLen === 0) return 1;\n if (Math.abs(a.length - b.length) / maxLen > 1 - FUZZY_THRESHOLD) return 0;\n return 1 - osaDistance(a, b) / maxLen;\n}\n\nexport interface NodeMatch {\n id: string;\n label: string;\n score: number;\n}\n\n/**\n * Score every node against the query's tokens. Identifier-aware and\n * typo-tolerant, in three tiers per token (best tier wins):\n *\n * 1. exact subtoken match (camelCase/snake_case-split word of the label\n * or id) — \"storage\" matches `fileStorage.js`;\n * 2. plain substring of the label/id (the original v1 behavior);\n * 3. fuzzy (Damerau-Levenshtein) match against a subtoken — \"sorce\"\n * still finds `scoreNodes`.\n *\n * Still fully lexical and deterministic — no LLM, no randomness.\n */\nexport function scoreNodes(graph: Graph, query: string): NodeMatch[] {\n const tokens = tokenize(query);\n const matches: NodeMatch[] = [];\n\n graph.forEachNode((id, attributes) => {\n const label = (attributes.label as string | undefined) ?? id;\n const haystack = `${label} ${id}`.toLowerCase();\n const subtokens = new Set(subtokenize(`${label} ${id}`));\n let score = 0;\n for (const token of tokens) {\n if (subtokens.has(token)) {\n score += SUBTOKEN_MATCH_SCORE;\n continue;\n }\n if (haystack.includes(token)) {\n score += SUBSTRING_MATCH_SCORE;\n continue;\n }\n if (token.length >= FUZZY_MIN_TOKEN_LEN) {\n let best = 0;\n for (const subtoken of subtokens) {\n const similarity = fuzzySimilarity(token, subtoken);\n if (similarity > best) best = similarity;\n }\n if (best >= FUZZY_THRESHOLD) score += best * FUZZY_MATCH_WEIGHT;\n }\n }\n if (score > 0) matches.push({ id, label, score });\n });\n\n matches.sort((a, b) => b.score - a.score || a.id.localeCompare(b.id));\n return matches;\n}\n\n/**\n * Best-effort single-node resolution: the highest-scoring lexical match,\n * or null if nothing in the graph matches at all. Deliberately does *not*\n * fall back to \"the most connected node\" — path/explain name a specific\n * node by intent, and silently substituting an unrelated one would be\n * more misleading than clearly saying \"no match\".\n */\nexport function resolveNode(graph: Graph, query: string): NodeMatch | null {\n const matches = scoreNodes(graph, query);\n return matches[0] ?? null;\n}\n\nexport interface VisitedNode {\n id: string;\n label: string;\n sourceFile: string;\n sourceLocation: string;\n depth: number;\n}\n\nexport interface TraversalEdge {\n source: string;\n target: string;\n relation: string;\n confidence: string;\n}\n\nexport interface QueryResult {\n seeds: NodeMatch[];\n visited: VisitedNode[];\n edges: TraversalEdge[];\n}\n\nexport interface QueryOptions {\n dfs?: boolean;\n /** Hard cap on how many nodes to include. Defaults to a generous ceiling derived from `tokenBudget`. */\n budget?: number;\n /** Approximate cap, in tokens (~4 chars each), on the serialized size of the result. Default 2000. */\n tokenBudget?: number;\n maxDepth?: number;\n maxSeeds?: number;\n}\n\nconst DEFAULT_MAX_DEPTH = 2;\nconst DEFAULT_MAX_SEEDS = 5;\nconst DEFAULT_BUDGET = 40;\nconst DEFAULT_TOKEN_BUDGET = 2000;\n/** When only tokenBudget is given, allow up to this many nodes per budgeted token-decile as a safety ceiling. */\nconst NODES_PER_TOKEN = 1 / 10;\n\n/**\n * Estimated token contribution of one node to the rendered result: its own\n * line (label, file, location) plus a rough allowance for the edge lines\n * that mention its id. Chars/4 is the usual serviceable approximation.\n */\nfunction nodeTokenCost(graph: Graph, id: string): number {\n const attrs = graph.getNodeAttributes(id);\n const label = (attrs.label as string | undefined) ?? id;\n const sourceFile = (attrs.sourceFile as string | undefined) ?? '';\n return Math.ceil((id.length * 2 + label.length + sourceFile.length + 24) / 4);\n}\n\n/**\n * BFS (default, broad context) or DFS (--dfs, trace a specific path)\n * traversal from the nodes whose label best matches `question`'s\n * keywords. This is lexical retrieval, not natural-language\n * understanding — it surfaces the neighborhood of the graph an agent (or\n * a human) should look at to answer the question, it does not itself\n * compose an answer.\n */\nexport function queryGraph(graph: Graph, question: string, options: QueryOptions = {}): QueryResult {\n const maxDepth = options.maxDepth ?? DEFAULT_MAX_DEPTH;\n const maxSeeds = options.maxSeeds ?? DEFAULT_MAX_SEEDS;\n const tokenBudget = options.tokenBudget ?? DEFAULT_TOKEN_BUDGET;\n const budget = options.budget ?? Math.max(DEFAULT_BUDGET, Math.ceil(tokenBudget * NODES_PER_TOKEN));\n\n const allMatches = scoreNodes(graph, question);\n const seeds = allMatches.length > 0 ? allMatches.slice(0, maxSeeds) : [];\n\n const visited = new Map<string, number>(); // id -> depth\n const frontier: Array<{ id: string; depth: number }> = seeds.map((s) => ({ id: s.id, depth: 0 }));\n let spentTokens = 0;\n for (const seed of seeds) {\n visited.set(seed.id, 0);\n spentTokens += nodeTokenCost(graph, seed.id);\n }\n\n while (frontier.length > 0 && visited.size < budget && spentTokens < tokenBudget) {\n const current = options.dfs ? (frontier.pop() as { id: string; depth: number }) : (frontier.shift() as { id: string; depth: number });\n if (current.depth >= maxDepth) continue;\n\n const neighbors = [...graph.neighbors(current.id)].sort((a, b) => a.localeCompare(b));\n for (const neighbor of neighbors) {\n if (visited.has(neighbor) || visited.size >= budget || spentTokens >= tokenBudget) continue;\n visited.set(neighbor, current.depth + 1);\n spentTokens += nodeTokenCost(graph, neighbor);\n frontier.push({ id: neighbor, depth: current.depth + 1 });\n }\n }\n\n const visitedNodes: VisitedNode[] = [...visited.entries()]\n .map(([id, depth]) => {\n const attrs = graph.getNodeAttributes(id);\n return {\n id,\n label: (attrs.label as string | undefined) ?? id,\n sourceFile: (attrs.sourceFile as string | undefined) ?? '',\n sourceLocation: (attrs.sourceLocation as string | undefined) ?? '',\n depth,\n };\n })\n .sort((a, b) => a.depth - b.depth || a.id.localeCompare(b.id));\n\n const edges: TraversalEdge[] = [];\n graph.forEachEdge((_edge, attrs, source, target) => {\n if (visited.has(source) && visited.has(target)) {\n edges.push({\n source,\n target,\n relation: String(attrs.relation),\n confidence: String(attrs.confidence),\n });\n }\n });\n edges.sort(\n (a, b) => a.source.localeCompare(b.source) || a.target.localeCompare(b.target) || a.relation.localeCompare(b.relation),\n );\n\n return enforceTokenBudget({ seeds, visited: visitedNodes, edges }, tokenBudget);\n}\n\n/**\n * The traversal-time cost estimate can't see how densely connected the\n * visited neighborhood is — a hub-heavy subgraph induces far more edge\n * lines than nodes. Enforce the budget on the *actual* result: drop the\n * deepest/last nodes (and the edges that touched them) until the\n * serialized size fits. Seeds are never dropped.\n */\nfunction enforceTokenBudget(result: QueryResult, tokenBudget: number): QueryResult {\n const cost = (value: unknown): number => Math.ceil(JSON.stringify(value).length / 4);\n\n const visited = [...result.visited];\n let edges = [...result.edges];\n let total = cost(result.seeds) + visited.reduce((s, n) => s + cost(n), 0) + edges.reduce((s, e) => s + cost(e), 0);\n\n const seedIds = new Set(result.seeds.map((s) => s.id));\n // visited is sorted by (depth, id) — pop from the end so the deepest,\n // least-central context goes first and the result stays deterministic.\n while (total > tokenBudget && visited.length > 0) {\n const last = visited[visited.length - 1] as VisitedNode;\n if (seedIds.has(last.id)) break;\n visited.pop();\n total -= cost(last);\n const remaining: TraversalEdge[] = [];\n for (const edge of edges) {\n if (edge.source === last.id || edge.target === last.id) {\n total -= cost(edge);\n } else {\n remaining.push(edge);\n }\n }\n edges = remaining;\n }\n\n return { seeds: result.seeds, visited, edges };\n}\n\nexport interface PathResult {\n from: NodeMatch;\n to: NodeMatch;\n found: boolean;\n path: string[];\n edges: TraversalEdge[];\n}\n\n/** Shortest path between the nodes that best match `fromQuery` and `toQuery` (undirected BFS — connectivity, not call direction). */\nexport function shortestPath(graph: Graph, fromQuery: string, toQuery: string): PathResult | null {\n const from = resolveNode(graph, fromQuery);\n const to = resolveNode(graph, toQuery);\n if (!from || !to) return null;\n\n if (from.id === to.id) {\n return { from, to, found: true, path: [from.id], edges: [] };\n }\n\n const predecessor = new Map<string, string>();\n const visited = new Set<string>([from.id]);\n const queue: string[] = [from.id];\n\n while (queue.length > 0) {\n const current = queue.shift() as string;\n if (current === to.id) break;\n const neighbors = [...graph.neighbors(current)].sort((a, b) => a.localeCompare(b));\n for (const neighbor of neighbors) {\n if (visited.has(neighbor)) continue;\n visited.add(neighbor);\n predecessor.set(neighbor, current);\n queue.push(neighbor);\n }\n }\n\n if (!visited.has(to.id)) {\n return { from, to, found: false, path: [], edges: [] };\n }\n\n const path: string[] = [to.id];\n let cursor = to.id;\n while (cursor !== from.id) {\n const prev = predecessor.get(cursor);\n if (!prev) break;\n path.unshift(prev);\n cursor = prev;\n }\n\n const edges: TraversalEdge[] = [];\n for (let i = 0; i < path.length - 1; i++) {\n const a = path[i] as string;\n const b = path[i + 1] as string;\n const key = graph.edges(a, b)[0] ?? graph.edges(b, a)[0];\n if (key) {\n const attrs = graph.getEdgeAttributes(key);\n edges.push({ source: a, target: b, relation: String(attrs.relation), confidence: String(attrs.confidence) });\n }\n }\n\n return { from, to, found: true, path, edges };\n}\n\nexport interface ExplainResult {\n id: string;\n label: string;\n sourceFile: string;\n sourceLocation: string;\n communityLabel?: string;\n outgoing: TraversalEdge[];\n incoming: TraversalEdge[];\n}\n\n/** Plain-language-ready explanation of the node that best matches `query`. */\nexport function explainNode(graph: Graph, query: string): ExplainResult | null {\n const match = resolveNode(graph, query);\n if (!match) return null;\n\n const attrs = graph.getNodeAttributes(match.id);\n const outgoing: TraversalEdge[] = [];\n const incoming: TraversalEdge[] = [];\n\n graph.forEachOutEdge(match.id, (_edge, edgeAttrs, source, target) => {\n outgoing.push({ source, target, relation: String(edgeAttrs.relation), confidence: String(edgeAttrs.confidence) });\n });\n graph.forEachInEdge(match.id, (_edge, edgeAttrs, source, target) => {\n incoming.push({ source, target, relation: String(edgeAttrs.relation), confidence: String(edgeAttrs.confidence) });\n });\n\n outgoing.sort((a, b) => a.target.localeCompare(b.target) || a.relation.localeCompare(b.relation));\n incoming.sort((a, b) => a.source.localeCompare(b.source) || a.relation.localeCompare(b.relation));\n\n return {\n id: match.id,\n label: match.label,\n sourceFile: (attrs.sourceFile as string | undefined) ?? '',\n sourceLocation: (attrs.sourceLocation as string | undefined) ?? '',\n communityLabel: attrs.communityLabel as string | undefined,\n outgoing,\n incoming,\n };\n}\n","import type Graph from 'graphology';\nimport { resolveNode, type NodeMatch } from './query.js';\nimport type { Confidence, Relation } from './types.js';\n\n/**\n * Reverse impact analysis — \"what breaks if I change X\". Walks *incoming*\n * dependency edges (who calls / imports / inherits from the target)\n * transitively, so depth 1 is the direct blast radius and deeper levels are\n * ripple effects. Like everything in query.ts this is lexical + structural,\n * fully offline and deterministic.\n */\n\n/**\n * Relations where `source --rel--> target` means \"source depends on target\",\n * i.e. changing the target can break the source. `contains`/`method` are\n * included because changing an entity plausibly affects its container file\n * or class signature consumers see.\n */\nconst DEPENDENCY_RELATIONS: ReadonlySet<Relation> = new Set([\n 'calls',\n 'imports',\n 'imports_from',\n 'inherits',\n 'implements',\n 'mixes_in',\n 'embeds',\n 'references',\n 're_exports',\n 'method',\n 'contains',\n] satisfies Relation[]);\n\nexport interface AffectedNode {\n id: string;\n label: string;\n sourceFile: string;\n sourceLocation: string;\n /** 1 = depends on the target directly, 2 = one step removed, ... */\n depth: number;\n /** The dependency edge that pulled this node in (this node -> something already affected). */\n via: {\n relation: Relation;\n confidence: Confidence;\n /** The already-affected node this one depends on. */\n dependsOn: string;\n };\n}\n\nexport interface ImpactResult {\n target: NodeMatch;\n affected: AffectedNode[];\n /** How many affected nodes there are per confidence tier of the edge that pulled each one in. */\n byConfidence: Record<Confidence, number>;\n maxDepth: number;\n truncated: boolean;\n}\n\nexport interface ImpactOptions {\n /** How many reverse hops to follow (default 3). */\n maxDepth?: number;\n /** Hard cap on affected nodes reported (default 200). */\n limit?: number;\n}\n\nconst DEFAULT_IMPACT_DEPTH = 3;\nconst DEFAULT_IMPACT_LIMIT = 200;\n\nconst CONFIDENCE_RANK: Record<Confidence, number> = { EXTRACTED: 3, INFERRED: 2, AMBIGUOUS: 1 };\n\n/**\n * Resolve `nodeQuery` to its best-matching node, then reverse-BFS over\n * incoming dependency edges. Returns null when nothing in the graph matches\n * the query at all (same contract as explainNode()).\n */\nexport function affectedBy(graph: Graph, nodeQuery: string, options: ImpactOptions = {}): ImpactResult | null {\n const target = resolveNode(graph, nodeQuery);\n if (!target) return null;\n\n const maxDepth = options.maxDepth ?? DEFAULT_IMPACT_DEPTH;\n const limit = options.limit ?? DEFAULT_IMPACT_LIMIT;\n\n const affected: AffectedNode[] = [];\n const visited = new Set<string>([target.id]);\n let frontier: string[] = [target.id];\n let truncated = false;\n\n for (let depth = 1; depth <= maxDepth && frontier.length > 0 && !truncated; depth++) {\n // Collect every dependent of the current frontier before descending, so\n // each node's reported depth is its *shortest* reverse distance.\n const nextFrontier = new Map<string, AffectedNode>();\n\n for (const current of [...frontier].sort((a, b) => a.localeCompare(b))) {\n graph.forEachInEdge(current, (_edge, edgeAttrs, source) => {\n if (visited.has(source)) return;\n const relation = edgeAttrs.relation as Relation;\n if (!DEPENDENCY_RELATIONS.has(relation)) return;\n\n const confidence = edgeAttrs.confidence as Confidence;\n const existing = nextFrontier.get(source);\n // Same node reachable via several edges this round: keep the\n // strongest-confidence one, mirroring buildGraph()'s merge rule.\n if (existing && CONFIDENCE_RANK[existing.via.confidence] >= CONFIDENCE_RANK[confidence]) return;\n\n const attrs = graph.getNodeAttributes(source);\n nextFrontier.set(source, {\n id: source,\n label: (attrs.label as string | undefined) ?? source,\n sourceFile: (attrs.sourceFile as string | undefined) ?? '',\n sourceLocation: (attrs.sourceLocation as string | undefined) ?? '',\n depth,\n via: { relation, confidence, dependsOn: current },\n });\n });\n }\n\n const roundNodes = [...nextFrontier.values()].sort((a, b) => a.id.localeCompare(b.id));\n for (const node of roundNodes) {\n if (affected.length >= limit) {\n truncated = true;\n break;\n }\n visited.add(node.id);\n affected.push(node);\n }\n frontier = roundNodes.filter((n) => visited.has(n.id)).map((n) => n.id);\n }\n\n const byConfidence: Record<Confidence, number> = { EXTRACTED: 0, INFERRED: 0, AMBIGUOUS: 0 };\n for (const node of affected) byConfidence[node.via.confidence] += 1;\n\n return { target, affected, byConfidence, maxDepth, truncated };\n}\n","import Graph from 'graphology';\nimport type { Confidence } from './types.js';\n\n/**\n * Cross-project graph merging — combine several already-built graphs (one\n * per repo/project) into a single queryable global graph.\n *\n * Node ids inside one project are relative-path-based (`src/a.ts::foo`), so\n * two projects' ids would collide. Every node id and sourceFile is therefore\n * prefixed with `<project>/` — EXCEPT `module:*` (bare package imports) and\n * `external:*` (unresolved reference targets) nodes, which deliberately stay\n * unprefixed and shared: two repos importing the same package meet at the\n * same node, so cross-repo bridges emerge in the merged graph instead of\n * each repo floating as a disconnected island.\n */\n\nexport interface MergeEntry {\n /** Project name used as the id/sourceFile namespace prefix. */\n name: string;\n graph: Graph;\n}\n\nconst CONFIDENCE_RANK: Record<Confidence, number> = { EXTRACTED: 3, INFERRED: 2, AMBIGUOUS: 1 };\n\nfunction strongerConfidence(a: Confidence, b: Confidence): Confidence {\n return CONFIDENCE_RANK[a] >= CONFIDENCE_RANK[b] ? a : b;\n}\n\nfunction isShared(id: string): boolean {\n // `external:` = unresolved reference targets, `module:` = bare package\n // imports (see extractors/common.ts) — both name things outside any one\n // project, so they stay unprefixed and shared across the merge.\n return id.startsWith('external:') || id.startsWith('module:');\n}\n\nfunction namespaced(project: string, id: string): string {\n return isShared(id) ? id : `${project}/${id}`;\n}\n\n/**\n * Merge the entries into one directed graph, applying the same\n * deterministic-ordering and duplicate-edge rules as buildGraph(): entries\n * are processed in name order, duplicate edges (possible via shared\n * external nodes) keep the strongest confidence, and every node carries a\n * `project` attribute (shared external nodes get `project: '(shared)'`\n * once more than one project touches them).\n */\nexport function mergeGraphs(entries: MergeEntry[]): Graph {\n const names = entries.map((e) => e.name);\n const duplicate = names.find((name, i) => names.indexOf(name) !== i);\n if (duplicate !== undefined) {\n throw new Error(`Duplicate project name in merge: \"${duplicate}\" — every entry needs a unique name.`);\n }\n\n const merged = new Graph({ type: 'directed', multi: true, allowSelfLoops: true });\n const sorted = [...entries].sort((a, b) => a.name.localeCompare(b.name));\n\n for (const { name, graph } of sorted) {\n const nodeIds = [...graph.nodes()].sort((a, b) => a.localeCompare(b));\n for (const id of nodeIds) {\n const attrs = graph.getNodeAttributes(id);\n const newId = namespaced(name, id);\n\n if (merged.hasNode(newId)) {\n // Only shared external nodes can collide across projects.\n merged.setNodeAttribute(newId, 'project', '(shared)');\n continue;\n }\n\n const sourceFile = (attrs.sourceFile as string | undefined) ?? '';\n merged.addNode(newId, {\n label: (attrs.label as string | undefined) ?? id,\n sourceFile: isShared(id) || sourceFile === '' ? sourceFile : `${name}/${sourceFile}`,\n sourceLocation: (attrs.sourceLocation as string | undefined) ?? '',\n project: name,\n });\n }\n\n const edgeKeys = [...graph.edges()].sort((a, b) => a.localeCompare(b));\n for (const edgeKey of edgeKeys) {\n const attrs = graph.getEdgeAttributes(edgeKey);\n const source = namespaced(name, graph.source(edgeKey));\n const target = namespaced(name, graph.target(edgeKey));\n const relation = String(attrs.relation);\n const confidence = attrs.confidence as Confidence;\n\n const key = `${source}|${relation}|${target}`;\n if (merged.hasEdge(key)) {\n const existing = merged.getEdgeAttribute(key, 'confidence') as Confidence;\n merged.setEdgeAttribute(key, 'confidence', strongerConfidence(existing, confidence));\n continue;\n }\n merged.addEdgeWithKey(key, source, target, { relation, confidence });\n }\n }\n\n return merged;\n}\n","import { validateDsn } from '../security.js';\nimport type { ExtractionResult, GraphEdge, GraphNode } from '../types.js';\n\n/**\n * MySQL schema extraction — introspect information_schema over a\n * user-supplied DSN and map the schema onto the same ExtractionResult shape\n * every code extractor produces, so tables/columns/foreign keys land in the\n * same graph as the code that talks to them.\n *\n * Only ever surfaces the credential-free DSN rendering (see\n * security.validateDsn()) in node attributes; the password never leaves the\n * connection config.\n */\n\n/** One `SELECT` against the live connection. Injectable so tests run on canned rows, mirroring security.ts's LookupFn pattern. */\nexport type DsnQueryFn = (sql: string, params: ReadonlyArray<string>) => Promise<Array<Record<string, unknown>>>;\n\ninterface TableRow {\n name: string;\n isView: boolean;\n}\n\nconst schemaId = (schema: string): string => `db:${schema}`;\nconst tableId = (schema: string, table: string): string => `db:${schema}::${table}`;\nconst columnId = (schema: string, table: string, column: string): string => `db:${schema}::${table}.${column}`;\n\nasync function defaultQueryFn(dsn: string): Promise<{ query: DsnQueryFn; close: () => Promise<void> }> {\n const { connection } = validateDsn(dsn);\n // Dynamic import so merely bundling/importing this module never loads the\n // mysql2 driver — it's only pulled in when a DSN is actually used.\n const mysql = await import('mysql2/promise');\n const conn = await mysql.createConnection({\n host: connection.host,\n port: connection.port,\n user: connection.user,\n password: connection.password,\n database: connection.database,\n });\n return {\n query: async (sql, params) => {\n const [rows] = await conn.execute(sql, [...params]);\n return rows as Array<Record<string, unknown>>;\n },\n close: () => conn.end(),\n };\n}\n\n/**\n * Extract the schema graph for the database named in `dsn`.\n *\n * Nodes: the schema, every table/view, every column.\n * Edges: schema `contains` table, table `contains` column, FK column\n * `references` the referenced table (EXTRACTED), view `references` its base\n * tables (EXTRACTED via VIEW_TABLE_USAGE on MySQL >= 8.0.13, INFERRED via a\n * VIEW_DEFINITION text match on older servers).\n */\nexport async function extractMysql(dsn: string, queryFn?: DsnQueryFn): Promise<ExtractionResult> {\n const { safeDisplay, connection } = validateDsn(dsn);\n const schema = connection.database;\n\n let query = queryFn;\n let close: (() => Promise<void>) | undefined;\n if (!query) {\n const live = await defaultQueryFn(dsn);\n query = live.query;\n close = live.close;\n }\n\n try {\n const nodes: GraphNode[] = [];\n const edges: GraphEdge[] = [];\n\n nodes.push({ id: schemaId(schema), label: schema, sourceFile: safeDisplay, sourceLocation: schema });\n\n const tableRows = await query(\n 'SELECT TABLE_NAME, TABLE_TYPE FROM information_schema.TABLES WHERE TABLE_SCHEMA = ? ORDER BY TABLE_NAME',\n [schema],\n );\n const tables: TableRow[] = tableRows.map((row) => ({\n name: String(row.TABLE_NAME),\n isView: String(row.TABLE_TYPE).toUpperCase() === 'VIEW',\n }));\n const tableNames = new Set(tables.map((t) => t.name));\n\n for (const table of tables) {\n nodes.push({\n id: tableId(schema, table.name),\n label: `${table.isView ? 'view' : 'table'} ${table.name}`,\n sourceFile: safeDisplay,\n sourceLocation: table.name,\n });\n edges.push({\n source: schemaId(schema),\n target: tableId(schema, table.name),\n relation: 'contains',\n confidence: 'EXTRACTED',\n });\n }\n\n const columnRows = await query(\n 'SELECT TABLE_NAME, COLUMN_NAME, COLUMN_TYPE FROM information_schema.COLUMNS ' +\n 'WHERE TABLE_SCHEMA = ? ORDER BY TABLE_NAME, ORDINAL_POSITION',\n [schema],\n );\n for (const row of columnRows) {\n const table = String(row.TABLE_NAME);\n const column = String(row.COLUMN_NAME);\n if (!tableNames.has(table)) continue;\n nodes.push({\n id: columnId(schema, table, column),\n label: `${table}.${column}: ${String(row.COLUMN_TYPE)}`,\n sourceFile: safeDisplay,\n sourceLocation: `${table}.${column}`,\n });\n edges.push({\n source: tableId(schema, table),\n target: columnId(schema, table, column),\n relation: 'contains',\n confidence: 'EXTRACTED',\n });\n }\n\n const fkRows = await query(\n 'SELECT TABLE_NAME, COLUMN_NAME, REFERENCED_TABLE_NAME FROM information_schema.KEY_COLUMN_USAGE ' +\n 'WHERE TABLE_SCHEMA = ? AND REFERENCED_TABLE_NAME IS NOT NULL ORDER BY TABLE_NAME, COLUMN_NAME',\n [schema],\n );\n for (const row of fkRows) {\n const table = String(row.TABLE_NAME);\n const column = String(row.COLUMN_NAME);\n const referenced = String(row.REFERENCED_TABLE_NAME);\n if (!tableNames.has(table) || !tableNames.has(referenced)) continue;\n edges.push({\n source: columnId(schema, table, column),\n target: tableId(schema, referenced),\n relation: 'references',\n confidence: 'EXTRACTED',\n });\n }\n\n const viewNames = tables.filter((t) => t.isView).map((t) => t.name);\n if (viewNames.length > 0) {\n await addViewEdges(query, schema, viewNames, tableNames, edges);\n }\n\n return { nodes, edges };\n } finally {\n await close?.();\n }\n}\n\n/** View -> base-table edges: VIEW_TABLE_USAGE when the server has it (MySQL >= 8.0.13), else an INFERRED VIEW_DEFINITION text match. */\nasync function addViewEdges(\n query: DsnQueryFn,\n schema: string,\n viewNames: string[],\n tableNames: ReadonlySet<string>,\n edges: GraphEdge[],\n): Promise<void> {\n try {\n const usageRows = await query(\n 'SELECT VIEW_NAME, TABLE_NAME FROM information_schema.VIEW_TABLE_USAGE ' +\n 'WHERE VIEW_SCHEMA = ? AND TABLE_SCHEMA = ? ORDER BY VIEW_NAME, TABLE_NAME',\n [schema, schema],\n );\n for (const row of usageRows) {\n const view = String(row.VIEW_NAME);\n const table = String(row.TABLE_NAME);\n if (!tableNames.has(view) || !tableNames.has(table) || view === table) continue;\n edges.push({\n source: tableId(schema, view),\n target: tableId(schema, table),\n relation: 'references',\n confidence: 'EXTRACTED',\n });\n }\n return;\n } catch {\n // Server predates VIEW_TABLE_USAGE — fall back to matching table names\n // inside the view definition text, honestly downgraded to INFERRED.\n }\n\n const definitionRows = await query(\n 'SELECT TABLE_NAME, VIEW_DEFINITION FROM information_schema.VIEWS WHERE TABLE_SCHEMA = ? ORDER BY TABLE_NAME',\n [schema],\n );\n for (const row of definitionRows) {\n const view = String(row.TABLE_NAME);\n if (!viewNames.includes(view)) continue;\n const definition = String(row.VIEW_DEFINITION ?? '').toLowerCase();\n for (const table of [...tableNames].sort((a, b) => a.localeCompare(b))) {\n if (table === view) continue;\n if (new RegExp(`\\\\b${table.toLowerCase()}\\\\b`).test(definition)) {\n edges.push({\n source: tableId(schema, view),\n target: tableId(schema, table),\n relation: 'references',\n confidence: 'INFERRED',\n });\n }\n }\n }\n}\n","import { createHash } from 'node:crypto';\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\n\n/**\n * The graph feedback loop — `graphify save-result` logs which graph nodes\n * actually helped answer a question (or led nowhere), and `graphify\n * reflect` aggregates those logs into a recency-weighted LESSONS.md an\n * agent can read at session start. This is what turns the graph from a\n * static map into one that learns which landmarks matter.\n */\n\nexport type ResultOutcome = 'useful' | 'dead_end' | 'corrected';\nexport type ResultType = 'query' | 'path' | 'explain' | 'affected';\n\nexport interface SavedResult {\n question: string;\n answer: string;\n type: ResultType;\n outcome: ResultOutcome;\n /** Node ids/labels cited in the answer. */\n nodes: string[];\n /** What the right answer was — pairs with outcome 'corrected'. */\n correction?: string;\n savedAt: string; // ISO timestamp\n}\n\nconst OUTCOMES: ReadonlySet<string> = new Set(['useful', 'dead_end', 'corrected']);\nconst TYPES: ReadonlySet<string> = new Set(['query', 'path', 'explain', 'affected']);\n\nexport function validateResult(value: Omit<SavedResult, 'savedAt'>): void {\n if (!value.question) throw new Error('save-result requires --question');\n if (!value.answer) throw new Error('save-result requires --answer');\n if (!OUTCOMES.has(value.outcome)) {\n throw new Error(`--outcome must be one of: useful, dead_end, corrected (got \"${value.outcome}\")`);\n }\n if (!TYPES.has(value.type)) {\n throw new Error(`--type must be one of: query, path, explain, affected (got \"${value.type}\")`);\n }\n if (value.outcome === 'corrected' && !value.correction) {\n throw new Error('--outcome corrected requires --correction with what the right answer was');\n }\n}\n\n/** Append one result to `<memoryDir>/result-<stamp>-<hash>.json`. Returns the file path. */\nexport async function saveResult(\n entry: Omit<SavedResult, 'savedAt'>,\n memoryDir: string,\n now: Date = new Date(),\n): Promise<string> {\n validateResult(entry);\n await fs.mkdir(memoryDir, { recursive: true });\n\n const saved: SavedResult = { ...entry, savedAt: now.toISOString() };\n const hash = createHash('sha256').update(JSON.stringify(saved)).digest('hex').slice(0, 8);\n const stamp = saved.savedAt.replace(/[:.]/g, '-');\n const filePath = path.join(memoryDir, `result-${stamp}-${hash}.json`);\n await fs.writeFile(filePath, JSON.stringify(saved, null, 2), 'utf-8');\n return filePath;\n}\n\nexport interface ReflectOptions {\n /** A result's weight halves every this many days (default 30). */\n halfLifeDays?: number;\n /** Injectable clock for deterministic tests. */\n now?: Date;\n /** Only list nodes cited usefully at least this many distinct times (default 2). */\n minCorroboration?: number;\n}\n\ninterface NodeSignal {\n useful: number;\n deadEnd: number;\n usefulCount: number;\n deadEndCount: number;\n}\n\n/** Read every result JSON under `memoryDir` (missing dir = no results). */\nexport async function loadResults(memoryDir: string): Promise<SavedResult[]> {\n let files: string[];\n try {\n files = (await fs.readdir(memoryDir)).filter((f) => f.startsWith('result-') && f.endsWith('.json'));\n } catch {\n return [];\n }\n\n const results: SavedResult[] = [];\n for (const file of files.sort((a, b) => a.localeCompare(b))) {\n try {\n const parsed = JSON.parse(await fs.readFile(path.join(memoryDir, file), 'utf-8')) as SavedResult;\n if (parsed.question && parsed.savedAt) results.push(parsed);\n } catch {\n // one corrupt file must not sink the reflection\n }\n }\n return results;\n}\n\n/** Aggregate saved results into a LESSONS.md string. Deterministic given results + options.now. */\nexport function renderLessons(results: SavedResult[], options: ReflectOptions = {}): string {\n const halfLife = options.halfLifeDays ?? 30;\n const now = options.now ?? new Date();\n const minCorroboration = options.minCorroboration ?? 2;\n\n const weightOf = (savedAt: string): number => {\n const ageDays = Math.max(0, (now.getTime() - new Date(savedAt).getTime()) / 86_400_000);\n return Math.pow(0.5, ageDays / halfLife);\n };\n\n const signals = new Map<string, NodeSignal>();\n const corrections: Array<{ question: string; correction: string; savedAt: string }> = [];\n\n for (const result of results) {\n const weight = weightOf(result.savedAt);\n for (const node of result.nodes ?? []) {\n const signal = signals.get(node) ?? { useful: 0, deadEnd: 0, usefulCount: 0, deadEndCount: 0 };\n if (result.outcome === 'useful') {\n signal.useful += weight;\n signal.usefulCount++;\n } else if (result.outcome === 'dead_end') {\n signal.deadEnd += weight;\n signal.deadEndCount++;\n }\n signals.set(node, signal);\n }\n if (result.outcome === 'corrected' && result.correction) {\n corrections.push({ question: result.question, correction: result.correction, savedAt: result.savedAt });\n }\n }\n\n const byScore = (kind: 'useful' | 'deadEnd') =>\n [...signals.entries()]\n .filter(([, s]) => (kind === 'useful' ? s.usefulCount >= minCorroboration : s.deadEndCount > 0))\n .sort((a, b) => b[1][kind] - a[1][kind] || a[0].localeCompare(b[0]))\n .slice(0, 10);\n\n const lines: string[] = [\n '# Graph lessons',\n '',\n `_Aggregated from ${results.length} saved result(s); signal half-life ${halfLife} day(s)._`,\n '',\n '## Nodes that keep answering',\n '',\n ];\n\n const useful = byScore('useful');\n if (useful.length === 0) {\n lines.push(`(none yet with >= ${minCorroboration} corroborating results — keep saving results)`);\n } else {\n for (const [node, s] of useful) {\n lines.push(`- **${node}** — score ${s.useful.toFixed(2)} across ${s.usefulCount} useful result(s)`);\n }\n }\n\n lines.push('', '## Dead ends', '');\n const deadEnds = byScore('deadEnd');\n if (deadEnds.length === 0) {\n lines.push('(none recorded)');\n } else {\n for (const [node, s] of deadEnds) {\n lines.push(`- **${node}** — score ${s.deadEnd.toFixed(2)} across ${s.deadEndCount} dead-end result(s)`);\n }\n }\n\n lines.push('', '## Corrections', '');\n if (corrections.length === 0) {\n lines.push('(none recorded)');\n } else {\n corrections.sort((a, b) => b.savedAt.localeCompare(a.savedAt));\n for (const c of corrections.slice(0, 20)) {\n lines.push(`- (${c.savedAt.slice(0, 10)}) Q: ${c.question}`);\n lines.push(` Right answer: ${c.correction}`);\n }\n }\n\n lines.push('');\n return lines.join('\\n');\n}\n","import type Graph from 'graphology';\nimport { scoreNodes } from './query.js';\n\n/**\n * `graphify context` — the working-set pack. Instead of returning node\n * names for the agent to chase (query -> then read whole files anyway),\n * this fuses the two steps: the graph knows every entity's file and line,\n * so rank the nodes relevant to the task, read just the relevant line\n * ranges, and pack the actual code into a token budget. One call returns\n * the code an agent needs to start a task.\n */\n\nexport interface ContextSnippet {\n nodeId: string;\n label: string;\n file: string;\n startLine: number;\n endLine: number;\n code: string;\n /** Why this snippet is in the pack (lexical match / neighbor-of relation). */\n reason: string;\n score: number;\n}\n\nexport interface ContextPack {\n task: string;\n snippets: ContextSnippet[];\n /** Approximate tokens used out of the budget. */\n tokens: number;\n tokenBudget: number;\n /** Ranked nodes that didn't fit the budget — the agent can pull them explicitly. */\n overflow: Array<{ nodeId: string; file: string }>;\n}\n\nexport interface ContextOptions {\n /** Approximate token cap for the pack (default 4000). */\n tokenBudget?: number;\n maxSeeds?: number;\n /** Cap on snippet length in lines (default 60). */\n maxSnippetLines?: number;\n}\n\nexport type FileReader = (path: string) => Promise<string>;\n\nconst DEFAULT_CONTEXT_BUDGET = 4000;\nconst DEFAULT_MAX_SEEDS = 8;\nconst DEFAULT_MAX_SNIPPET_LINES = 60;\n/** A neighbor inherits this fraction of the score of the node that pulled it in. */\nconst NEIGHBOR_DECAY = 0.4;\n\nconst tokensOf = (text: string): number => Math.ceil(text.length / 4);\n\nfunction lineNumberOf(sourceLocation: string): number | null {\n const match = /^L(\\d+)$/.exec(sourceLocation);\n return match ? Number(match[1]) : null;\n}\n\nfunction isReadableFile(sourceFile: string): boolean {\n return sourceFile !== '' && !sourceFile.startsWith('<') && !sourceFile.includes('://');\n}\n\ninterface RankedNode {\n id: string;\n score: number;\n reason: string;\n}\n\n/**\n * Rank nodes for the task: lexical seeds first (their match score), then\n * their graph neighbors at a decayed score, labeled with the relation that\n * connects them. Deterministic (score desc, id asc).\n */\nexport function rankForTask(graph: Graph, task: string, maxSeeds = DEFAULT_MAX_SEEDS): RankedNode[] {\n const seeds = scoreNodes(graph, task).slice(0, maxSeeds);\n const ranked = new Map<string, RankedNode>();\n for (const seed of seeds) {\n ranked.set(seed.id, { id: seed.id, score: seed.score, reason: 'matches the task' });\n }\n\n for (const seed of seeds) {\n graph.forEachEdge(seed.id, (_edge, attrs, source, target) => {\n const neighbor = source === seed.id ? target : source;\n if (ranked.has(neighbor)) return;\n const relation = String(attrs.relation);\n const direction = source === seed.id ? `${relation} ->` : `<- ${relation}`;\n ranked.set(neighbor, {\n id: neighbor,\n score: seed.score * NEIGHBOR_DECAY,\n reason: `${direction} ${seed.label}`,\n });\n });\n }\n\n return [...ranked.values()].sort((a, b) => b.score - a.score || a.id.localeCompare(b.id));\n}\n\n/**\n * Extract the snippet for a node: from its declaration line to just before\n * the next known entity in the same file (capped), so snippets align with\n * real code block boundaries without needing a parser here.\n */\nfunction snippetRange(\n startLine: number,\n fileLineCount: number,\n entityStartsInFile: number[],\n maxLines: number,\n): { start: number; end: number } {\n const nextStart = entityStartsInFile.find((l) => l > startLine);\n const hardEnd = nextStart !== undefined ? nextStart - 1 : fileLineCount;\n return { start: startLine, end: Math.min(hardEnd, startLine + maxLines - 1) };\n}\n\nexport async function buildContextPack(\n graph: Graph,\n task: string,\n readFile: FileReader,\n options: ContextOptions = {},\n): Promise<ContextPack> {\n const tokenBudget = options.tokenBudget ?? DEFAULT_CONTEXT_BUDGET;\n const maxSnippetLines = options.maxSnippetLines ?? DEFAULT_MAX_SNIPPET_LINES;\n const ranked = rankForTask(graph, task, options.maxSeeds);\n\n // Every known entity start line per file — used to end snippets at the\n // next declaration instead of an arbitrary window.\n const entityStarts = new Map<string, number[]>();\n graph.forEachNode((_id, attrs) => {\n const file = attrs.sourceFile as string | undefined;\n const line = lineNumberOf((attrs.sourceLocation as string | undefined) ?? '');\n if (file && line !== null) {\n const starts = entityStarts.get(file) ?? [];\n starts.push(line);\n entityStarts.set(file, starts);\n }\n });\n for (const starts of entityStarts.values()) starts.sort((a, b) => a - b);\n\n const fileCache = new Map<string, string[] | null>();\n const readLines = async (file: string): Promise<string[] | null> => {\n const cached = fileCache.get(file);\n if (cached !== undefined) return cached;\n let lines: string[] | null;\n try {\n lines = (await readFile(file)).split('\\n');\n } catch {\n lines = null;\n }\n fileCache.set(file, lines);\n return lines;\n };\n\n const snippets: ContextSnippet[] = [];\n const overflow: Array<{ nodeId: string; file: string }> = [];\n const coveredRanges = new Map<string, Array<{ start: number; end: number }>>();\n let tokens = 0;\n\n for (const node of ranked) {\n const attrs = graph.getNodeAttributes(node.id);\n const file = (attrs.sourceFile as string | undefined) ?? '';\n const startLine = lineNumberOf((attrs.sourceLocation as string | undefined) ?? '');\n if (!isReadableFile(file) || startLine === null) continue;\n\n const lines = await readLines(file);\n if (lines === null) continue;\n\n const { start, end } = snippetRange(startLine, lines.length, entityStarts.get(file) ?? [], maxSnippetLines);\n\n // Skip if an already-packed snippet from the same file covers this range.\n const covered = (coveredRanges.get(file) ?? []).some((r) => start >= r.start && end <= r.end);\n if (covered) continue;\n\n const code = lines.slice(start - 1, end).join('\\n');\n const cost = tokensOf(code) + 15; // header overhead\n if (tokens + cost > tokenBudget) {\n overflow.push({ nodeId: node.id, file: `${file}:L${startLine}` });\n continue;\n }\n\n tokens += cost;\n snippets.push({\n nodeId: node.id,\n label: (attrs.label as string | undefined) ?? node.id,\n file,\n startLine: start,\n endLine: end,\n code,\n reason: node.reason,\n score: node.score,\n });\n const ranges = coveredRanges.get(file) ?? [];\n ranges.push({ start, end });\n coveredRanges.set(file, ranges);\n }\n\n return { task, snippets, tokens, tokenBudget, overflow };\n}\n\n/** Render a pack as agent-ready markdown. */\nexport function renderContextPack(pack: ContextPack): string {\n const lines: string[] = [\n `# Context pack: ${pack.task}`,\n '',\n `_~${pack.tokens} of ${pack.tokenBudget} token budget, ${pack.snippets.length} snippet(s)._`,\n '',\n ];\n\n if (pack.snippets.length === 0) {\n lines.push('No matching code found — try different keywords.');\n return lines.join('\\n');\n }\n\n for (const snippet of pack.snippets) {\n lines.push(`## ${snippet.label} — \\`${snippet.file}:L${snippet.startLine}-L${snippet.endLine}\\``);\n lines.push(`_${snippet.reason}_`);\n lines.push('```');\n lines.push(snippet.code);\n lines.push('```');\n lines.push('');\n }\n\n if (pack.overflow.length > 0) {\n lines.push(`## Didn't fit the budget (${pack.overflow.length})`);\n for (const item of pack.overflow.slice(0, 15)) {\n lines.push(`- ${item.nodeId} (${item.file})`);\n }\n lines.push('');\n }\n\n return lines.join('\\n');\n}\n","import type Graph from 'graphology';\nimport { affectedBy } from './impact.js';\nimport { resolveNode } from './query.js';\n\n/**\n * `graphify tests` — structural test selection. Coverage tools need\n * instrumentation and a full test run to know what covers what; the graph\n * already knows, statically: a test file imports/calls the code it\n * exercises, so the test files inside a change's reverse blast radius are\n * exactly the ones worth running. Cross-language, no instrumentation.\n */\n\n/** Test-file naming conventions across the supported languages. */\nconst TEST_FILE_PATTERNS: RegExp[] = [\n /(^|\\/)tests?\\//, // tests/ or test/ directory\n /(^|\\/)__tests__\\//,\n /(^|\\/)spec\\//,\n /\\.test\\.[cm]?[jt]sx?$/,\n /\\.spec\\.[cm]?[jt]sx?$/,\n /(^|\\/)test_[^/]+\\.py$/,\n /_test\\.py$/,\n /_test\\.go$/,\n /Tests?\\.(java|cs)$/,\n /_spec\\.rb$/,\n /_test\\.rb$/,\n];\n\nexport function isTestFile(path: string): boolean {\n return TEST_FILE_PATTERNS.some((p) => p.test(path));\n}\n\nexport interface TestSelection {\n /** What the selection was computed for (resolved node id, or the changed files). */\n target: string;\n /** Unique test files, most directly affected first. */\n testFiles: Array<{ file: string; depth: number; via: string }>;\n /** How many non-test nodes were in the blast radius (context for confidence). */\n affectedNodeCount: number;\n}\n\nconst TEST_REACH_DEPTH = 4;\nconst TEST_REACH_LIMIT = 2000;\n\nfunction selectionFromImpact(\n graph: Graph,\n targetIds: string[],\n targetLabel: string,\n): TestSelection {\n const best = new Map<string, { depth: number; via: string }>();\n let affectedNodeCount = 0;\n\n for (const id of targetIds) {\n const impact = affectedBy(graph, id, { maxDepth: TEST_REACH_DEPTH, limit: TEST_REACH_LIMIT });\n if (!impact) continue;\n affectedNodeCount += impact.affected.length;\n for (const node of impact.affected) {\n if (!isTestFile(node.sourceFile)) continue;\n const existing = best.get(node.sourceFile);\n if (!existing || node.depth < existing.depth) {\n best.set(node.sourceFile, { depth: node.depth, via: node.via.dependsOn });\n }\n }\n // The target might itself be inside a test file's blast radius via the\n // file node too — affectedBy already walks contains edges, so imports\n // from test files reach here.\n }\n\n const testFiles = [...best.entries()]\n .map(([file, info]) => ({ file, depth: info.depth, via: info.via }))\n .sort((a, b) => a.depth - b.depth || a.file.localeCompare(b.file));\n\n return { target: targetLabel, testFiles, affectedNodeCount };\n}\n\n/** Test files reachable (reverse) from the node best matching `nodeQuery`. Null if nothing matches. */\nexport function testsForNode(graph: Graph, nodeQuery: string): TestSelection | null {\n const match = resolveNode(graph, nodeQuery);\n if (!match) return null;\n return selectionFromImpact(graph, [match.id], match.id);\n}\n\n/**\n * Test files reachable from any of the given changed files (as reported by\n * `git diff --name-only`). Changed test files select themselves. Unknown\n * files (not in the graph) are skipped.\n */\nexport function testsForChangedFiles(graph: Graph, changedFiles: string[]): TestSelection {\n const fileIds: string[] = [];\n const selfSelected = new Map<string, { depth: number; via: string }>();\n\n for (const file of changedFiles) {\n if (isTestFile(file)) {\n selfSelected.set(file, { depth: 0, via: '(changed directly)' });\n continue;\n }\n if (graph.hasNode(file)) fileIds.push(file);\n }\n\n const selection = selectionFromImpact(graph, fileIds, changedFiles.join(', '));\n for (const [file, info] of selfSelected) {\n if (!selection.testFiles.some((t) => t.file === file)) {\n selection.testFiles.push({ file, depth: info.depth, via: info.via });\n }\n }\n selection.testFiles.sort((a, b) => a.depth - b.depth || a.file.localeCompare(b.file));\n return selection;\n}\n","import { execFile } from 'node:child_process';\nimport * as fs from 'node:fs/promises';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport { promisify } from 'node:util';\nimport type Graph from 'graphology';\nimport { buildGraph } from './build.js';\nimport { collectFiles } from './detect.js';\nimport { extract } from './extract.js';\nimport { affectedBy } from './impact.js';\nimport { readSelfNames, resolveCrossFileReferences } from './resolve.js';\nimport { testsForNode } from './testmap.js';\nimport type { ExtractionResult } from './types.js';\n\nconst execFileAsync = promisify(execFile);\n\n/**\n * `graphify review` — semantic graph diff between two git revisions.\n * Full structural extraction is sub-second, so instead of parsing text\n * diffs we build the graph at both revs and diff the graphs: which symbols\n * appeared, disappeared, or got rewired — each with its blast radius and\n * the test files worth running. One command answers both \"what changed\n * since I was last here\" and \"review this PR structurally\".\n */\n\nexport interface ChangedSymbol {\n id: string;\n label: string;\n sourceFile: string;\n /** Everything that depends on this symbol (computed in the graph where it exists). */\n blastRadius: number;\n /** Test files reachable from it. */\n tests: string[];\n}\n\nexport interface RewiredSymbol extends ChangedSymbol {\n gainedEdges: string[];\n lostEdges: string[];\n}\n\nexport interface GraphDiff {\n base: string;\n head: string;\n added: ChangedSymbol[];\n removed: ChangedSymbol[];\n rewired: RewiredSymbol[];\n}\n\n/** Extract a graph from a directory without exporting anything. */\nexport async function graphForDirectory(root: string): Promise<Graph> {\n const manifest = collectFiles(root);\n const extractions: ExtractionResult[] = [];\n for (const relFile of manifest.files.code.sort((a, b) => a.localeCompare(b))) {\n extractions.push(await extract(path.join(root, relFile), relFile));\n }\n resolveCrossFileReferences(extractions, { selfNames: await readSelfNames(root) });\n return buildGraph(extractions);\n}\n\n/** `git archive <rev> | tar -x` into a fresh temp dir — tracked files only, no worktree pollution. */\nasync function checkoutRev(repoRoot: string, rev: string): Promise<string> {\n const dest = await fs.mkdtemp(path.join(os.tmpdir(), `graphify-review-${rev.replace(/[^a-zA-Z0-9]/g, '_')}-`));\n const { stdout } = await execFileAsync(\n 'git',\n ['-C', repoRoot, 'archive', '--format=tar', rev],\n { encoding: 'buffer', maxBuffer: 512 * 1024 * 1024 },\n );\n await new Promise<void>((resolve, reject) => {\n const tar = execFile('tar', ['-x', '-C', dest], (error) => (error ? reject(error) : resolve()));\n tar.stdin?.end(stdout);\n });\n return dest;\n}\n\n/** Signature of a node's edge set, for rewire detection. */\nfunction edgeSignature(graph: Graph, id: string): Set<string> {\n const signature = new Set<string>();\n graph.forEachOutEdge(id, (_e, attrs, _s, target) => signature.add(`-> ${String(attrs.relation)} ${target}`));\n graph.forEachInEdge(id, (_e, attrs, source) => signature.add(`<- ${String(attrs.relation)} ${source}`));\n return signature;\n}\n\nfunction describeSymbol(graph: Graph, id: string): ChangedSymbol {\n const attrs = graph.getNodeAttributes(id);\n const impact = affectedBy(graph, id, { maxDepth: 3 });\n const tests = testsForNode(graph, id);\n return {\n id,\n label: (attrs.label as string | undefined) ?? id,\n sourceFile: (attrs.sourceFile as string | undefined) ?? '',\n blastRadius: impact?.affected.length ?? 0,\n tests: tests?.testFiles.map((t) => t.file) ?? [],\n };\n}\n\n/** Entity nodes only — file add/removes are visible from the entities inside them, and file nodes double-count. */\nfunction entityIds(graph: Graph): Set<string> {\n const ids = new Set<string>();\n graph.forEachNode((id) => {\n if (id.includes('::')) ids.add(id);\n });\n return ids;\n}\n\nexport function diffGraphs(baseGraph: Graph, headGraph: Graph, base: string, head: string): GraphDiff {\n const baseIds = entityIds(baseGraph);\n const headIds = entityIds(headGraph);\n\n const added: ChangedSymbol[] = [];\n const removed: ChangedSymbol[] = [];\n const rewired: RewiredSymbol[] = [];\n\n for (const id of [...headIds].sort((a, b) => a.localeCompare(b))) {\n if (!baseIds.has(id)) {\n added.push(describeSymbol(headGraph, id));\n continue;\n }\n const before = edgeSignature(baseGraph, id);\n const after = edgeSignature(headGraph, id);\n const gained = [...after].filter((e) => !before.has(e)).sort((a, b) => a.localeCompare(b));\n const lost = [...before].filter((e) => !after.has(e)).sort((a, b) => a.localeCompare(b));\n if (gained.length > 0 || lost.length > 0) {\n rewired.push({ ...describeSymbol(headGraph, id), gainedEdges: gained, lostEdges: lost });\n }\n }\n\n for (const id of [...baseIds].sort((a, b) => a.localeCompare(b))) {\n if (!headIds.has(id)) removed.push(describeSymbol(baseGraph, id));\n }\n\n return { base, head, added, removed, rewired };\n}\n\n/** Diff two revisions of the repo at `repoRoot`. `head` defaults to the working head via a second archive of HEAD. */\nexport async function reviewRevisions(repoRoot: string, base: string, head = 'HEAD'): Promise<GraphDiff> {\n const [baseDir, headDir] = await Promise.all([checkoutRev(repoRoot, base), checkoutRev(repoRoot, head)]);\n try {\n const [baseGraph, headGraph] = [await graphForDirectory(baseDir), await graphForDirectory(headDir)];\n return diffGraphs(baseGraph, headGraph, base, head);\n } finally {\n await Promise.all([\n fs.rm(baseDir, { recursive: true, force: true }),\n fs.rm(headDir, { recursive: true, force: true }),\n ]);\n }\n}\n\nexport function renderReview(diff: GraphDiff): string {\n const lines: string[] = [\n `# Structural review: ${diff.base}..${diff.head}`,\n '',\n `${diff.added.length} symbol(s) added, ${diff.removed.length} removed, ${diff.rewired.length} rewired.`,\n '',\n ];\n\n const section = (title: string, symbols: ChangedSymbol[]): void => {\n lines.push(`## ${title} (${symbols.length})`, '');\n if (symbols.length === 0) {\n lines.push('(none)', '');\n return;\n }\n for (const s of symbols) {\n const tests = s.tests.length > 0 ? ` | tests: ${s.tests.join(', ')}` : ' | tests: none found';\n lines.push(`- **${s.label}** (${s.sourceFile}) — blast radius ${s.blastRadius}${tests}`);\n const r = s as RewiredSymbol;\n if (r.gainedEdges) {\n for (const e of r.gainedEdges.slice(0, 5)) lines.push(` - gained: ${e}`);\n for (const e of r.lostEdges.slice(0, 5)) lines.push(` - lost: ${e}`);\n }\n }\n lines.push('');\n };\n\n section('Removed — check every caller', diff.removed);\n section('Rewired — dependencies changed', diff.rewired);\n section('Added', diff.added);\n\n const allTests = new Set<string>();\n for (const s of [...diff.removed, ...diff.rewired, ...diff.added]) {\n for (const t of s.tests) allTests.add(t);\n }\n lines.push(`## Suggested test run (${allTests.size} file(s))`, '');\n for (const t of [...allTests].sort((a, b) => a.localeCompare(b))) lines.push(`- ${t}`);\n lines.push('');\n\n return lines.join('\\n');\n}\n","import type Graph from 'graphology';\n\n/**\n * `graphify check` — architecture guardrails. Declarative dependency rules\n * checked against the graph's edges, with CI-friendly results: an agent (or\n * a pipeline) can verify an edit didn't violate the architecture before it\n * lands. Cross-language, because the graph already is.\n */\n\nexport interface DependencyRule {\n /** Short rule name shown in violations. */\n name: string;\n /** Glob over the depending file (edge source's sourceFile). */\n from: string;\n /** Globs the dependency target's file must NOT match. */\n disallow: string[];\n /** Optional human explanation echoed with violations. */\n reason?: string;\n}\n\nexport interface RulesConfig {\n rules: DependencyRule[];\n}\n\nexport interface Violation {\n rule: string;\n reason?: string;\n fromFile: string;\n fromNode: string;\n toFile: string;\n toNode: string;\n relation: string;\n}\n\n/** Relations that constitute a dependency for rule purposes. */\nconst DEPENDENCY_RELATIONS = new Set([\n 'calls', 'imports', 'imports_from', 'inherits', 'implements', 'mixes_in', 'embeds', 're_exports',\n]);\n\n/**\n * Minimal glob: `**` crosses directories, `*` stays within one segment.\n * Anchored on both ends. Enough for path rules without a dependency.\n */\nexport function globToRegExp(glob: string): RegExp {\n const escaped = glob.replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&');\n const pattern = escaped.replace(/\\*\\*|\\*|\\?/g, (token) =>\n token === '**' ? '.*' : token === '*' ? '[^/]*' : '[^/]',\n );\n return new RegExp(`^${pattern}$`);\n}\n\nexport function validateRules(value: unknown): RulesConfig {\n const config = value as RulesConfig;\n if (!config || !Array.isArray(config.rules)) {\n throw new Error('Rules file must be JSON of shape { \"rules\": [{ \"name\", \"from\", \"disallow\": [...] }] }');\n }\n for (const rule of config.rules) {\n if (!rule.name || typeof rule.from !== 'string' || !Array.isArray(rule.disallow)) {\n throw new Error(`Malformed rule \"${rule.name ?? '(unnamed)'}\" — need name, from, and disallow[].`);\n }\n }\n return config;\n}\n\n/** Check every dependency edge in the graph against the rules. Deterministic ordering. */\nexport function checkRules(graph: Graph, config: RulesConfig): Violation[] {\n const compiled = config.rules.map((rule) => ({\n rule,\n from: globToRegExp(rule.from),\n disallow: rule.disallow.map(globToRegExp),\n }));\n\n const violations: Violation[] = [];\n graph.forEachEdge((_edge, attrs, source, target) => {\n const relation = String(attrs.relation);\n if (!DEPENDENCY_RELATIONS.has(relation)) return;\n\n const fromFile = (graph.getNodeAttribute(source, 'sourceFile') as string | undefined) ?? '';\n const toFile = (graph.getNodeAttribute(target, 'sourceFile') as string | undefined) ?? '';\n if (!fromFile || !toFile || fromFile === toFile) return;\n\n for (const { rule, from, disallow } of compiled) {\n if (!from.test(fromFile)) continue;\n if (disallow.some((d) => d.test(toFile))) {\n violations.push({\n rule: rule.name,\n reason: rule.reason,\n fromFile,\n fromNode: source,\n toFile,\n toNode: target,\n relation,\n });\n }\n }\n });\n\n violations.sort(\n (a, b) =>\n a.rule.localeCompare(b.rule) ||\n a.fromFile.localeCompare(b.fromFile) ||\n a.toFile.localeCompare(b.toFile) ||\n a.fromNode.localeCompare(b.fromNode),\n );\n return violations;\n}\n"],"mappings":"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","names":["path","fs","path","require","fs","fs","fs","fs","fs","path","fs","path","stripQuotes","Graph","fs","path","CODE_EXTENSIONS","sep","resolved","import_graphology","Graph","leiden","louvain","labelOf","import_node_module","fs","path","import_node_crypto","fs","path","relative","require","fs","path","import_node_crypto","fs","path","fs","path","import_graphology","Graph","path","CONFIDENCE_RANK","import_graphology","CONFIDENCE_RANK","strongerConfidence","Graph","import_node_crypto","fs","path","DEFAULT_MAX_SEEDS","readFile","path","fs","path","resolve","DEPENDENCY_RELATIONS"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../node_modules/tsup/assets/cjs_shims.js","../src/detect.ts","../src/extract.ts","../src/extractors/csharp.ts","../src/extractors/common.ts","../src/extractors/wasmLoader.ts","../src/extractors/go.ts","../src/extractors/java.ts","../src/extractors/python.ts","../src/extractors/ruby.ts","../src/extractors/rust.ts","../src/extractors/typescript.ts","../src/build.ts","../src/schema.ts","../src/resolve.ts","../src/cluster.ts","../src/analyze.ts","../src/report.ts","../src/export.ts","../src/security.ts","../src/pipeline.ts","../src/extractionCache.ts","../src/graphStore.ts","../src/query.ts","../src/impact.ts","../src/merge.ts","../src/extractors/mysql.ts","../src/memory.ts","../src/context.ts","../src/testmap.ts","../src/diff.ts","../src/check.ts"],"sourcesContent":["export { collectFiles } from './detect.js';\nexport { extract, EXTRACTOR_REGISTRY } from './extract.js';\nexport { buildGraph } from './build.js';\nexport { resolveCrossFileReferences } from './resolve.js';\nexport type { ResolveStats } from './resolve.js';\nexport { cluster } from './cluster.js';\nexport type { ClusterAlgorithm, ClusterOptions } from './cluster.js';\nexport { analyze } from './analyze.js';\nexport { renderReport } from './report.js';\nexport { exportGraph } from './export.js';\nexport { runPipeline } from './pipeline.js';\nexport type { PipelineOptions, PipelineResult } from './pipeline.js';\nexport { loadGraph } from './graphStore.js';\nexport { queryGraph, shortestPath, explainNode, scoreNodes, resolveNode } from './query.js';\nexport { affectedBy } from './impact.js';\nexport type { AffectedNode, ImpactOptions, ImpactResult } from './impact.js';\nexport { mergeGraphs } from './merge.js';\nexport type { MergeEntry } from './merge.js';\nexport { extractMysql } from './extractors/mysql.js';\nexport type { DsnQueryFn } from './extractors/mysql.js';\nexport { saveResult, loadResults, renderLessons } from './memory.js';\nexport type { SavedResult, ResultOutcome, ResultType, ReflectOptions } from './memory.js';\nexport { buildContextPack, renderContextPack, rankForTask } from './context.js';\nexport type { ContextPack, ContextSnippet, ContextOptions } from './context.js';\nexport { testsForNode, testsForChangedFiles, isTestFile } from './testmap.js';\nexport type { TestSelection } from './testmap.js';\nexport { reviewRevisions, diffGraphs, graphForDirectory, renderReview } from './diff.js';\nexport type { GraphDiff, ChangedSymbol, RewiredSymbol } from './diff.js';\nexport { checkRules, validateRules, globToRegExp } from './check.js';\nexport type { DependencyRule, RulesConfig, Violation } from './check.js';\nexport { ExtractionCache } from './extractionCache.js';\nexport type {\n NodeMatch,\n QueryOptions,\n QueryResult,\n PathResult,\n ExplainResult,\n TraversalEdge,\n VisitedNode,\n} from './query.js';\nexport {\n validateExtraction,\n ExtractionValidationError,\n ExtractionResultSchema,\n} from './schema.js';\nexport type { ExtractionValidationIssue } from './schema.js';\nexport * from './types.js';\n","// Shim globals in cjs bundle\n// There's a weird bug that esbuild will always inject importMetaUrl\n// if we export it as `const importMetaUrl = ... __filename ...`\n// But using a function will not cause this issue\n\nconst getImportMetaUrl = () => \n typeof document === \"undefined\" \n ? new URL(`file:${__filename}`).href \n : (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') \n ? document.currentScript.src \n : new URL(\"main.js\", document.baseURI).href;\n\nexport const importMetaUrl = /* @__PURE__ */ getImportMetaUrl()\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { FileCategory, FileManifest } from './types.js';\n\n/** Directories that are never worth walking into. */\nconst SKIP_DIRS = new Set([\n 'node_modules',\n '.git',\n 'dist',\n 'build',\n 'out',\n 'graphify-out',\n '.next',\n '.venv',\n 'venv',\n '__pycache__',\n '.cache',\n 'coverage',\n '.turbo',\n]);\n\nconst CODE_EXTENSIONS = new Set([\n '.ts',\n '.tsx',\n '.js',\n '.jsx',\n '.mjs',\n '.cjs',\n '.mts',\n '.cts',\n '.py',\n '.go',\n '.rs',\n '.java',\n '.cs',\n '.rb',\n '.c',\n '.h',\n '.cpp',\n '.hpp',\n '.cc',\n '.php',\n '.kt',\n '.swift',\n '.scala',\n '.lua',\n '.sh',\n '.sql',\n]);\n\nconst DOCUMENT_EXTENSIONS = new Set(['.md', '.mdx', '.txt', '.rst', '.adoc', '.org', '.json', '.yaml', '.yml', '.toml']);\n\nconst PAPER_EXTENSIONS = new Set(['.pdf', '.tex', '.bib']);\n\nconst IMAGE_EXTENSIONS = new Set(['.png', '.jpg', '.jpeg', '.gif', '.svg', '.webp', '.bmp', '.ico']);\n\nconst VIDEO_EXTENSIONS = new Set(['.mp4', '.mov', '.avi', '.mkv', '.webm']);\n\n/**\n * Filenames or name fragments that must never be read into the graph or an\n * LLM prompt — credentials, secrets, key material. Skipped into\n * `skippedSensitive` rather than silently ignored, so a run's manifest is\n * auditable.\n */\nconst SENSITIVE_NAME_PATTERNS: RegExp[] = [\n /^\\.env(\\..*)?$/i,\n /^\\.npmrc$/i,\n /^\\.pypirc$/i,\n /credentials/i,\n /secret/i,\n /^id_rsa$/i,\n /^id_ed25519$/i,\n /\\.pem$/i,\n /\\.key$/i,\n /\\.pfx$/i,\n /\\.p12$/i,\n /^\\.aws\\//i,\n /service[-_]?account.*\\.json$/i,\n];\n\nfunction isSensitiveName(name: string): boolean {\n return SENSITIVE_NAME_PATTERNS.some((pattern) => pattern.test(name));\n}\n\nfunction categorize(ext: string): FileCategory | null {\n const lower = ext.toLowerCase();\n if (CODE_EXTENSIONS.has(lower)) return 'code';\n if (DOCUMENT_EXTENSIONS.has(lower)) return 'document';\n if (PAPER_EXTENSIONS.has(lower)) return 'paper';\n if (IMAGE_EXTENSIONS.has(lower)) return 'image';\n if (VIDEO_EXTENSIONS.has(lower)) return 'video';\n return null;\n}\n\nfunction countWords(content: string): number {\n const trimmed = content.trim();\n if (trimmed.length === 0) return 0;\n return trimmed.split(/\\s+/).length;\n}\n\n/** Decode a file's bytes as UTF-8 with a replacement strategy — never throw on invalid bytes. */\nfunction readTextSafely(filePath: string): string {\n const buf = fs.readFileSync(filePath);\n return buf.toString('utf-8');\n}\n\n/**\n * Walk `root` and categorize files into code/document/paper/image/video\n * buckets. Does not follow symlinks (security.ts §5 — symlink traversal).\n * Sensitive-looking files (.env, credentials, key material) are recorded in\n * `skippedSensitive` and excluded from every other bucket/count.\n */\nexport function collectFiles(root: string): FileManifest {\n const scanRoot = path.resolve(root);\n const stat = fs.statSync(scanRoot);\n if (!stat.isDirectory()) {\n throw new Error(`collectFiles: not a directory: ${scanRoot}`);\n }\n\n const files: Record<FileCategory, string[]> = {\n code: [],\n document: [],\n paper: [],\n image: [],\n video: [],\n };\n const skippedSensitive: string[] = [];\n let totalWords = 0;\n\n const stack: string[] = [scanRoot];\n const textCategories: Set<FileCategory> = new Set(['code', 'document', 'paper']);\n\n while (stack.length > 0) {\n const dir = stack.pop() as string;\n let entries: fs.Dirent[];\n try {\n entries = fs.readdirSync(dir, { withFileTypes: true });\n } catch {\n continue; // unreadable directory (permissions) — skip, don't crash the run\n }\n\n // Sort for deterministic traversal order.\n entries.sort((a, b) => a.name.localeCompare(b.name));\n\n for (const entry of entries) {\n if (entry.isSymbolicLink()) continue; // never follow symlinks\n\n const fullPath = path.join(dir, entry.name);\n const relPath = path.relative(scanRoot, fullPath);\n\n if (entry.isDirectory()) {\n if (SKIP_DIRS.has(entry.name) || entry.name.startsWith('.')) continue;\n stack.push(fullPath);\n continue;\n }\n\n if (!entry.isFile()) continue; // sockets, devices, fifos, etc.\n\n if (isSensitiveName(entry.name)) {\n skippedSensitive.push(relPath);\n continue;\n }\n\n const ext = path.extname(entry.name);\n const category = categorize(ext);\n if (category === null) continue; // unrecognized extension — not tracked\n\n files[category].push(relPath);\n\n if (textCategories.has(category)) {\n try {\n const content = readTextSafely(fullPath);\n totalWords += countWords(content);\n } catch {\n // Unreadable/binary-under-a-text-extension — degrade gracefully.\n }\n }\n }\n }\n\n for (const category of Object.keys(files) as FileCategory[]) {\n files[category].sort();\n }\n skippedSensitive.sort();\n\n const totalFiles = Object.values(files).reduce((sum, list) => sum + list.length, 0);\n\n return {\n scanRoot,\n files,\n totalFiles,\n totalWords,\n skippedSensitive,\n };\n}\n","import * as path from 'node:path';\nimport { extractCSharp } from './extractors/csharp.js';\nimport { extractGo } from './extractors/go.js';\nimport { extractJava } from './extractors/java.js';\nimport { extractPython } from './extractors/python.js';\nimport { extractRuby } from './extractors/ruby.js';\nimport { extractRust } from './extractors/rust.js';\nimport { extractTypeScript } from './extractors/typescript.js';\nimport type { ExtractionResult } from './types.js';\n\n/** `displayPath`, when given, is used for node ids/sourceFile instead of the read path — see extract(). */\nexport type Extractor = (path: string, displayPath?: string) => Promise<ExtractionResult>;\n\n/** File extension -> extractor module. Register new languages here. */\nexport const EXTRACTOR_REGISTRY: Record<string, Extractor> = {\n '.ts': extractTypeScript,\n '.tsx': extractTypeScript,\n '.js': extractTypeScript,\n '.jsx': extractTypeScript,\n '.mjs': extractTypeScript,\n '.cjs': extractTypeScript,\n '.mts': extractTypeScript,\n '.cts': extractTypeScript,\n '.py': extractPython,\n '.go': extractGo,\n '.rs': extractRust,\n '.java': extractJava,\n '.cs': extractCSharp,\n '.rb': extractRuby,\n};\n\n/**\n * Dispatch a single file to its language extractor. Returns an empty\n * extraction (not a thrown error) for unregistered extensions so detect's\n * file list and extract's coverage can diverge without crashing a run.\n *\n * `displayPath` decouples where the file is read from (relative to the\n * process cwd) from the path used in node ids and sourceFile attributes —\n * the pipeline passes the project-root-relative path so ids stay stable\n * and portable no matter which directory the pipeline was launched from\n * (this is what makes cross-project merging's namespacing meaningful).\n */\nexport async function extract(filePath: string, displayPath?: string): Promise<ExtractionResult> {\n const ext = path.extname(filePath);\n const extractor = EXTRACTOR_REGISTRY[ext];\n if (!extractor) {\n return { nodes: [], edges: [] };\n }\n return extractor(filePath, displayPath);\n}\n","import * as fs from 'node:fs/promises';\nimport type { Node as TSNode } from 'web-tree-sitter';\nimport type { ExtractionResult } from '../types.js';\nimport {\n ExtractionBuilder,\n descendantsOfType,\n entityId,\n externalId,\n lineOf,\n namedChildren,\n resolveModuleRef,\n toPosix,\n} from './common.js';\nimport { createParser } from './wasmLoader.js';\n\n/**\n * Structural extraction for .cs via web-tree-sitter (WASM, no native\n * compilation, no eval/exec of source content).\n *\n * Like Java, C# has no free top-level functions — methods live inside a\n * class or interface — but unlike Java, top-level types are usually\n * nested one level deeper inside a `namespace Foo { ... }` block, so pass\n * 1 flattens namespace bodies (recursively, for nested namespaces) before\n * walking classes/interfaces/methods, exactly as if their members were\n * declared at the top level.\n *\n * C#'s base-type list (`class Calculator : Base, IGreeter`) doesn't\n * distinguish a base class from an implemented interface syntactically —\n * that's only knowable from the *referenced* declaration. The one\n * compiler-enforced rule this grammar does guarantee is ordering: a base\n * class, if present, must be listed first. So the first entry becomes an\n * `inherits` edge and every subsequent entry becomes `implements` — a\n * deliberate best-effort heuristic, not a guarantee.\n *\n * Every `invocation_expression` is resolved (pass 2): a same-file\n * method/`this.Method()` call resolved against the enclosing class is\n * EXTRACTED; a call qualified by a `using Alias = Namespace.Type;`\n * binding (or an unqualified call resolved only through one) is\n * INFERRED — the \"cross-file second pass\" placeholder described in the\n * master prompt §3. It intentionally does not open and parse the\n * referenced type to confirm the target. An unresolvable callee produces\n * no edge at all.\n */\nexport async function extractCSharp(filePath: string, displayPath?: string): Promise<ExtractionResult> {\n const parser = await createParser('c_sharp');\n\n const raw = await fs.readFile(filePath);\n const content = raw.toString('utf-8'); // replacement-decoded — never throws on invalid bytes\n\n const tree = parser.parse(content);\n if (!tree) {\n throw new Error(`extractCSharp: parser produced no tree for ${filePath}`);\n }\n const root = tree.rootNode;\n\n const sourceFile = toPosix(displayPath ?? filePath);\n const builder = new ExtractionBuilder();\n const fileId = sourceFile;\n builder.addNode({ id: fileId, label: sourceFile, sourceFile, sourceLocation: 'L1' });\n\n /** Declared name (class/interface) -> our graph id. */\n const nameIndex = new Map<string, string>();\n /** tree-sitter node id -> our graph id, for every method entity we track. */\n const functionNodeMap = new Map<number, string>();\n /** tree-sitter class/interface declaration node id -> method name -> our graph id. */\n const classMethods = new Map<number, Map<string, string>>();\n /** tree-sitter method_declaration node id -> its enclosing type's node id. */\n const enclosingClassOf = new Map<number, number>();\n /** local binding name (`using Alias = ...`) -> the module it came from. */\n const importIndex = new Map<string, ReturnType<typeof resolveModuleRef>>();\n\n function addModuleNode(ref: ReturnType<typeof resolveModuleRef>): void {\n if (builder.hasNode(ref.id)) return;\n builder.addNode({\n id: ref.id,\n label: ref.label,\n sourceFile: ref.external ? '<external>' : ref.id,\n sourceLocation: 'L1',\n });\n }\n\n function resolveHeritageTarget(name: string): string {\n const resolved = nameIndex.get(name);\n if (resolved) return resolved;\n const extId = externalId(name);\n if (!builder.hasNode(extId)) {\n builder.addNode({ id: extId, label: name, sourceFile: '<external>', sourceLocation: 'L0' });\n }\n return extId;\n }\n\n function handleUsingDirective(node: TSNode): void {\n const children = namedChildren(node);\n const first = children[0];\n if (!first) return;\n\n let aliasName: string | undefined;\n let targetNode: TSNode | undefined;\n if (first.type === 'name_equals') {\n aliasName = namedChildren(first)[0]?.text;\n targetNode = children[1];\n } else {\n targetNode = first;\n }\n if (!targetNode) return;\n\n const ref = resolveModuleRef(sourceFile, targetNode.text);\n addModuleNode(ref);\n if (aliasName) importIndex.set(aliasName, ref);\n builder.addEdge({ source: fileId, target: ref.id, relation: 'imports', confidence: 'EXTRACTED' });\n }\n\n function handleMethodDeclaration(typeNode: TSNode, typeId: string, typeName: string, member: TSNode): void {\n const methodName = member.childForFieldName('name')?.text ?? '(anonymous)';\n const methodId = entityId(sourceFile, `${typeName}.${methodName}`);\n builder.addNode({\n id: methodId,\n label: `method ${typeName}.${methodName}`,\n sourceFile,\n sourceLocation: lineOf(member),\n });\n builder.addEdge({ source: typeId, target: methodId, relation: 'method', confidence: 'EXTRACTED' });\n\n let methods = classMethods.get(typeNode.id);\n if (!methods) {\n methods = new Map();\n classMethods.set(typeNode.id, methods);\n }\n methods.set(methodName, methodId);\n functionNodeMap.set(member.id, methodId);\n enclosingClassOf.set(member.id, typeNode.id);\n }\n\n function handleBaseList(typeId: string, node: TSNode): void {\n const baseList = node.childForFieldName('bases');\n if (!baseList) return;\n const entries = namedChildren(baseList);\n entries.forEach((entry, index) => {\n builder.addEdge({\n source: typeId,\n target: resolveHeritageTarget(entry.text),\n relation: index === 0 ? 'inherits' : 'implements',\n confidence: 'EXTRACTED',\n });\n });\n }\n\n function handleClassDeclaration(node: TSNode): void {\n const name = node.childForFieldName('name')?.text ?? '(anonymous)';\n const classId = entityId(sourceFile, name);\n builder.addNode({ id: classId, label: `class ${name}`, sourceFile, sourceLocation: lineOf(node) });\n builder.addEdge({ source: fileId, target: classId, relation: 'contains', confidence: 'EXTRACTED' });\n nameIndex.set(name, classId);\n functionNodeMap.set(node.id, classId);\n classMethods.set(node.id, new Map());\n\n handleBaseList(classId, node);\n\n const body = node.childForFieldName('body');\n if (body) {\n for (const member of namedChildren(body)) {\n if (member.type !== 'method_declaration') continue; // constructors intentionally not tracked\n handleMethodDeclaration(node, classId, name, member);\n }\n }\n }\n\n function handleInterfaceDeclaration(node: TSNode): void {\n const name = node.childForFieldName('name')?.text ?? '(anonymous)';\n const id = entityId(sourceFile, name);\n builder.addNode({ id, label: `interface ${name}`, sourceFile, sourceLocation: lineOf(node) });\n builder.addEdge({ source: fileId, target: id, relation: 'contains', confidence: 'EXTRACTED' });\n nameIndex.set(name, id);\n handleBaseList(id, node); // interface-extends-interface(s) — same shape as a class base list\n }\n\n // Pass 1: top-level declarations (usings, classes, interfaces),\n // flattening `namespace Foo { ... }` wrappers (recursively).\n function walkTopLevel(node: TSNode): void {\n for (const child of namedChildren(node)) {\n switch (child.type) {\n case 'using_directive':\n handleUsingDirective(child);\n break;\n case 'class_declaration':\n handleClassDeclaration(child);\n break;\n case 'interface_declaration':\n handleInterfaceDeclaration(child);\n break;\n case 'namespace_declaration': {\n const nsBody = child.childForFieldName('body');\n if (nsBody) walkTopLevel(nsBody);\n break;\n }\n case 'file_scoped_namespace_declaration':\n // `namespace Foo;` (C# 10+) — declarations are direct named\n // children of this node itself (no separate `body` field).\n walkTopLevel(child);\n break;\n default:\n break;\n }\n }\n }\n walkTopLevel(root);\n\n function closestTrackedCaller(node: TSNode): string {\n let current: TSNode | null = node.parent;\n while (current) {\n const tracked = functionNodeMap.get(current.id);\n if (tracked) return tracked;\n current = current.parent;\n }\n return fileId;\n }\n\n function closestEnclosingClassMethods(node: TSNode): Map<string, string> | undefined {\n let current: TSNode | null = node.parent;\n while (current) {\n if (current.type === 'method_declaration') {\n const typeNodeId = enclosingClassOf.get(current.id);\n if (typeNodeId !== undefined) return classMethods.get(typeNodeId);\n }\n current = current.parent;\n }\n return undefined;\n }\n\n // Pass 2: calls (see the function doc comment above for the\n // EXTRACTED/INFERRED policy).\n for (const call of descendantsOfType(root, ['invocation_expression'])) {\n const fn = call.childForFieldName('function');\n if (!fn) continue;\n\n let targetId: string | null = null;\n let confidence: 'EXTRACTED' | 'INFERRED' = 'EXTRACTED';\n\n if (fn.type === 'identifier') {\n const name = fn.text;\n const methodId = closestEnclosingClassMethods(call)?.get(name);\n if (methodId) {\n targetId = methodId;\n } else {\n const viaImport = importIndex.get(name);\n if (viaImport) {\n targetId = viaImport.id;\n confidence = 'INFERRED';\n }\n }\n } else if (fn.type === 'member_access_expression') {\n const expression = fn.childForFieldName('expression');\n const name = fn.childForFieldName('name')?.text;\n if (expression && name) {\n if (expression.type === 'this_expression') {\n const methodId = closestEnclosingClassMethods(call)?.get(name);\n if (methodId) targetId = methodId;\n } else if (expression.type === 'identifier') {\n const viaImport = importIndex.get(expression.text);\n if (viaImport) {\n targetId = viaImport.id;\n confidence = 'INFERRED';\n }\n }\n }\n }\n\n if (!targetId) continue; // unresolved callee (builtin, external value, ...) — no noisy guess\n const callerId = closestTrackedCaller(call);\n builder.addEdge({ source: callerId, target: targetId, relation: 'calls', confidence });\n }\n\n return builder.build();\n}\n","import * as path from 'node:path';\nimport type { Node as TSNode } from 'web-tree-sitter';\nimport type { ExtractionResult, GraphEdge, GraphNode } from '../types.js';\n\n/**\n * web-tree-sitter types `namedChildren`/`descendantsOfType` as\n * `(Node | null)[]` (a node slot can be null for a missing/erroneous\n * child). These two helpers give every extractor a non-null array to\n * iterate without repeating the same `.filter()` everywhere.\n */\nexport function namedChildren(node: TSNode): TSNode[] {\n return node.namedChildren.filter((c): c is TSNode => c !== null);\n}\n\nexport function descendantsOfType(node: TSNode, types: string | string[]): TSNode[] {\n return node.descendantsOfType(types).filter((c): c is TSNode => c !== null);\n}\n\n/** Normalize a path to forward slashes so ids/labels are stable across platforms. */\nexport function toPosix(p: string): string {\n return p.split(path.sep).join('/');\n}\n\n/** `tree-sitter` node shape narrowed to what id/location helpers need. */\nexport interface PositionedNode {\n startPosition: { row: number };\n}\n\n/** 1-based \"L<line>\" source location string, matching the schema example (`\"L42\"`). */\nexport function lineOf(node: PositionedNode): string {\n return `L${node.startPosition.row + 1}`;\n}\n\n/** Build a stable, file-scoped node id: unique across the whole graph once merged. */\nexport function entityId(sourceFile: string, qualifiedName: string): string {\n return `${toPosix(sourceFile)}::${qualifiedName}`;\n}\n\n/** Id for a reference we could not resolve to any declaration we saw (best-effort target). */\nexport function externalId(name: string): string {\n return `external:${name}`;\n}\n\nexport interface ModuleRef {\n id: string;\n label: string;\n /** true when the specifier is a bare package (not resolvable to an in-repo file). */\n external: boolean;\n}\n\n/**\n * Resolve an import/require specifier to a best-effort module id relative\n * to the importing file. This is intentionally lightweight (string/path\n * math only, no filesystem probing, no extension resolution) — it exists\n * so same-repo relative imports get a deterministic, file-shaped id that a\n * later cross-file pass (or a second extraction of the target file) can\n * line up against, not to fully replicate a module resolver.\n */\nexport function resolveModuleRef(sourceFile: string, specifier: string): ModuleRef {\n if (specifier.startsWith('.') || specifier.startsWith('/')) {\n const dir = path.posix.dirname(toPosix(sourceFile));\n const joined = specifier.startsWith('/') ? specifier : path.posix.join(dir, specifier);\n const normalized = path.posix.normalize(joined);\n return { id: normalized, label: specifier, external: false };\n }\n return { id: `module:${specifier}`, label: specifier, external: true };\n}\n\n/**\n * Accumulates nodes/edges for one file's ExtractionResult with node-id\n * dedup (a file can otherwise easily emit the same module/external\n * placeholder node twice — once per import, once per call resolution).\n */\nexport class ExtractionBuilder {\n private readonly nodeIds = new Set<string>();\n readonly nodes: GraphNode[] = [];\n readonly edges: GraphEdge[] = [];\n\n addNode(node: GraphNode): void {\n if (this.nodeIds.has(node.id)) return;\n this.nodeIds.add(node.id);\n this.nodes.push(node);\n }\n\n hasNode(id: string): boolean {\n return this.nodeIds.has(id);\n }\n\n addEdge(edge: GraphEdge): void {\n this.edges.push(edge);\n }\n\n build(): ExtractionResult {\n return { nodes: this.nodes, edges: this.edges };\n }\n}\n","import { createRequire } from 'node:module';\nimport { Language, Parser } from 'web-tree-sitter';\n\n/**\n * Shared web-tree-sitter bootstrapping for every language extractor.\n *\n * Pinned to web-tree-sitter@^0.25.x deliberately (not the newer 0.26.x\n * major that ships with the rest of the dependency set): 0.26 requires\n * every language grammar to carry a \"dylink.0\" WASM custom section (the\n * newer wasm dynamic-linking convention), but `tree-sitter-wasms`'s\n * prebuilt grammars still use the legacy \"dylink\" section — loading any\n * grammar under 0.26 throws `need dylink section` before a single file can\n * be parsed. 0.25.x accepts the legacy section and loads every grammar\n * `tree-sitter-wasms` ships. Revisit this pin once `tree-sitter-wasms`\n * republishes grammars built against a dylink.0-era tree-sitter-cli.\n */\n\nconst require = createRequire(import.meta.url);\n\nlet initPromise: Promise<void> | null = null;\n\nfunction ensureInitialized(): Promise<void> {\n if (!initPromise) {\n initPromise = Parser.init();\n }\n return initPromise;\n}\n\nconst languageCache = new Map<string, Promise<Language>>();\n\n/** Load (and cache) a tree-sitter-wasms grammar by its `tree-sitter-<name>.wasm` basename. */\nexport async function loadLanguage(grammarName: string): Promise<Language> {\n await ensureInitialized();\n let cached = languageCache.get(grammarName);\n if (!cached) {\n const wasmPath = require.resolve(`tree-sitter-wasms/out/tree-sitter-${grammarName}.wasm`);\n cached = Language.load(wasmPath);\n languageCache.set(grammarName, cached);\n }\n return cached;\n}\n\n/** Create a fresh Parser bound to the given grammar. Parsers are cheap and not thread-shared. */\nexport async function createParser(grammarName: string): Promise<Parser> {\n const language = await loadLanguage(grammarName);\n const parser = new Parser();\n parser.setLanguage(language);\n return parser;\n}\n","import * as fs from 'node:fs/promises';\nimport type { Node as TSNode } from 'web-tree-sitter';\nimport type { ExtractionResult } from '../types.js';\nimport {\n ExtractionBuilder,\n descendantsOfType,\n entityId,\n externalId,\n lineOf,\n namedChildren,\n resolveModuleRef,\n toPosix,\n} from './common.js';\nimport { createParser } from './wasmLoader.js';\n\n/** Strip the surrounding quotes tree-sitter keeps on an interpreted/raw string literal's text. */\nfunction stripQuotes(text: string): string {\n if (text.length >= 2) {\n const first = text[0];\n const last = text[text.length - 1];\n if ((first === '\"' || first === '`') && first === last) {\n return text.slice(1, -1);\n }\n }\n return text;\n}\n\n/** Default package qualifier Go infers from an import path when no explicit alias is given. */\nfunction defaultPackageQualifier(importPath: string): string {\n const segments = importPath.split('/');\n return segments[segments.length - 1] ?? importPath;\n}\n\n/**\n * Structural extraction for .go via web-tree-sitter (WASM, no native\n * compilation, no eval/exec of source content).\n *\n * Pattern mirrors typescript.ts, adapted to Go's shape: top-level named\n * types (struct/interface/defined types), functions, methods (declared\n * separately from their receiver type via `func (recv T) Name(...)`), and\n * imports (pass 1) -> every `call_expression` resolved against what pass 1\n * saw (pass 2). A same-file callee, or a call through the receiver\n * variable of the enclosing method onto a method of the same struct, is\n * EXTRACTED; a call through an imported package qualifier (e.g.\n * `m.Add(x, x)` where `m` is an import alias) is INFERRED — the\n * \"cross-file second pass\" placeholder described in the master prompt §3.\n * An unresolvable callee produces no edge at all.\n *\n * Go has no `extends`/`implements` clauses; struct embedding\n * (`type Calculator struct { Base }`) is the one heritage-like construct\n * Go's grammar exposes directly, so it becomes an `embeds` edge.\n */\nexport async function extractGo(filePath: string, displayPath?: string): Promise<ExtractionResult> {\n const parser = await createParser('go');\n\n const raw = await fs.readFile(filePath);\n const content = raw.toString('utf-8'); // replacement-decoded — never throws on invalid bytes\n\n const tree = parser.parse(content);\n if (!tree) {\n throw new Error(`extractGo: parser produced no tree for ${filePath}`);\n }\n const root = tree.rootNode;\n\n const sourceFile = toPosix(displayPath ?? filePath);\n const builder = new ExtractionBuilder();\n const fileId = sourceFile;\n builder.addNode({ id: fileId, label: sourceFile, sourceFile, sourceLocation: 'L1' });\n\n /** Declared name (function or named type) -> our graph id. */\n const nameIndex = new Map<string, string>();\n /** tree-sitter node id -> our graph id, for every function/method entity we track. */\n const functionNodeMap = new Map<number, string>();\n /** graph id of a named type -> method name -> our graph id. */\n const typeMethods = new Map<string, Map<string, string>>();\n /** tree-sitter method_declaration node id -> { receiver variable name, owning type's graph id }. */\n const receiverInfo = new Map<number, { varName: string; typeId: string }>();\n /** local package qualifier (import alias or inferred name) -> the module it came from. */\n const importIndex = new Map<string, ReturnType<typeof resolveModuleRef>>();\n\n function addModuleNode(ref: ReturnType<typeof resolveModuleRef>): void {\n if (builder.hasNode(ref.id)) return;\n builder.addNode({\n id: ref.id,\n label: ref.label,\n sourceFile: ref.external ? '<external>' : ref.id,\n sourceLocation: 'L1',\n });\n }\n\n function resolveTypeTarget(name: string): string {\n const resolved = nameIndex.get(name);\n if (resolved) return resolved;\n const extId = externalId(name);\n if (!builder.hasNode(extId)) {\n builder.addNode({ id: extId, label: name, sourceFile: '<external>', sourceLocation: 'L0' });\n }\n return extId;\n }\n\n function handleImportSpec(spec: TSNode): void {\n const pathNode = spec.childForFieldName('path');\n if (!pathNode) return;\n const specifier = stripQuotes(pathNode.text);\n const ref = resolveModuleRef(sourceFile, specifier);\n addModuleNode(ref);\n builder.addEdge({ source: fileId, target: ref.id, relation: 'imports', confidence: 'EXTRACTED' });\n\n const aliasNode = spec.childForFieldName('name');\n const alias = aliasNode?.text;\n if (alias && alias !== '_' && alias !== '.') {\n importIndex.set(alias, ref);\n } else if (!alias) {\n importIndex.set(defaultPackageQualifier(specifier), ref);\n }\n }\n\n function handleImportDeclaration(node: TSNode): void {\n for (const child of namedChildren(node)) {\n if (child.type === 'import_spec') {\n handleImportSpec(child);\n } else if (child.type === 'import_spec_list') {\n for (const spec of namedChildren(child)) {\n if (spec.type === 'import_spec') handleImportSpec(spec);\n }\n }\n }\n }\n\n function handleFunctionDeclaration(node: TSNode): void {\n const name = node.childForFieldName('name')?.text ?? '(anonymous)';\n const id = entityId(sourceFile, name);\n builder.addNode({ id, label: `function ${name}`, sourceFile, sourceLocation: lineOf(node) });\n builder.addEdge({ source: fileId, target: id, relation: 'contains', confidence: 'EXTRACTED' });\n nameIndex.set(name, id);\n functionNodeMap.set(node.id, id);\n }\n\n function handleTypeDeclaration(node: TSNode): void {\n for (const spec of namedChildren(node)) {\n if (spec.type !== 'type_spec') continue; // skip `type X = Y` aliases\n const name = spec.childForFieldName('name')?.text;\n if (!name) continue;\n const underlying = spec.childForFieldName('type');\n const kind = underlying?.type === 'struct_type' ? 'struct' : underlying?.type === 'interface_type' ? 'interface' : 'type';\n const id = entityId(sourceFile, name);\n builder.addNode({ id, label: `${kind} ${name}`, sourceFile, sourceLocation: lineOf(spec) });\n builder.addEdge({ source: fileId, target: id, relation: 'contains', confidence: 'EXTRACTED' });\n nameIndex.set(name, id);\n typeMethods.set(id, new Map());\n\n if (underlying?.type === 'struct_type') {\n const fieldList = namedChildren(underlying).find((c) => c.type === 'field_declaration_list');\n if (fieldList) {\n for (const field of namedChildren(fieldList)) {\n if (field.type !== 'field_declaration') continue;\n if (field.childForFieldName('name')) continue; // named field, not embedding\n const embeddedType = namedChildren(field)[0];\n if (!embeddedType) continue;\n const base = embeddedType.type === 'pointer_type' ? namedChildren(embeddedType)[0] : embeddedType;\n if (!base) continue;\n builder.addEdge({\n source: id,\n target: resolveTypeTarget(base.text),\n relation: 'embeds',\n confidence: 'EXTRACTED',\n });\n }\n }\n }\n }\n }\n\n /** Receiver's declared type name, unwrapping a pointer receiver (`*T`). */\n function receiverTypeName(receiver: TSNode): string | null {\n const paramDecl = namedChildren(receiver)[0];\n if (!paramDecl) return null;\n let typeNode = paramDecl.childForFieldName('type');\n if (typeNode?.type === 'pointer_type') {\n typeNode = namedChildren(typeNode)[0] ?? null;\n }\n return typeNode?.type === 'type_identifier' ? typeNode.text : null;\n }\n\n function receiverVarName(receiver: TSNode): string | null {\n const paramDecl = namedChildren(receiver)[0];\n return paramDecl?.childForFieldName('name')?.text ?? null;\n }\n\n function handleMethodDeclaration(node: TSNode): void {\n const receiver = node.childForFieldName('receiver');\n const methodName = node.childForFieldName('name')?.text ?? '(anonymous)';\n if (!receiver) return;\n const typeName = receiverTypeName(receiver);\n if (!typeName) return;\n const typeId = resolveTypeTarget(typeName);\n\n const methodId = entityId(sourceFile, `${typeName}.${methodName}`);\n builder.addNode({ id: methodId, label: `method ${typeName}.${methodName}`, sourceFile, sourceLocation: lineOf(node) });\n builder.addEdge({ source: typeId, target: methodId, relation: 'method', confidence: 'EXTRACTED' });\n\n let methods = typeMethods.get(typeId);\n if (!methods) {\n methods = new Map();\n typeMethods.set(typeId, methods);\n }\n methods.set(methodName, methodId);\n\n functionNodeMap.set(node.id, methodId);\n const varName = receiverVarName(receiver);\n if (varName) receiverInfo.set(node.id, { varName, typeId });\n }\n\n // Pass 1: top-level declarations (imports, named types, functions, methods).\n for (const child of namedChildren(root)) {\n switch (child.type) {\n case 'import_declaration':\n handleImportDeclaration(child);\n break;\n case 'type_declaration':\n handleTypeDeclaration(child);\n break;\n case 'function_declaration':\n handleFunctionDeclaration(child);\n break;\n case 'method_declaration':\n handleMethodDeclaration(child);\n break;\n default:\n break;\n }\n }\n\n function closestTrackedCaller(node: TSNode): string {\n let current: TSNode | null = node.parent;\n while (current) {\n const tracked = functionNodeMap.get(current.id);\n if (tracked) return tracked;\n current = current.parent;\n }\n return fileId;\n }\n\n function closestEnclosingReceiver(node: TSNode): { varName: string; typeId: string } | undefined {\n let current: TSNode | null = node.parent;\n while (current) {\n if (current.type === 'method_declaration') {\n return receiverInfo.get(current.id);\n }\n current = current.parent;\n }\n return undefined;\n }\n\n // Pass 2: calls (see the function doc comment above for the\n // EXTRACTED/INFERRED policy).\n for (const call of descendantsOfType(root, ['call_expression'])) {\n const fn = call.childForFieldName('function');\n if (!fn) continue;\n\n let targetId: string | null = null;\n let confidence: 'EXTRACTED' | 'INFERRED' = 'EXTRACTED';\n\n if (fn.type === 'identifier') {\n const sameFile = nameIndex.get(fn.text);\n if (sameFile) targetId = sameFile;\n } else if (fn.type === 'selector_expression') {\n const operand = fn.childForFieldName('operand');\n const property = fn.childForFieldName('field')?.text;\n if (operand && property && operand.type === 'identifier') {\n const receiver = closestEnclosingReceiver(call);\n if (receiver && receiver.varName === operand.text) {\n const methodId = typeMethods.get(receiver.typeId)?.get(property);\n if (methodId) targetId = methodId;\n } else {\n const viaImport = importIndex.get(operand.text);\n if (viaImport) {\n targetId = viaImport.id;\n confidence = 'INFERRED';\n }\n }\n }\n }\n\n if (!targetId) continue; // unresolved callee (builtin, external value, ...) — no noisy guess\n const callerId = closestTrackedCaller(call);\n builder.addEdge({ source: callerId, target: targetId, relation: 'calls', confidence });\n }\n\n return builder.build();\n}\n","import * as fs from 'node:fs/promises';\nimport type { Node as TSNode } from 'web-tree-sitter';\nimport type { ExtractionResult } from '../types.js';\nimport {\n ExtractionBuilder,\n descendantsOfType,\n entityId,\n externalId,\n lineOf,\n namedChildren,\n resolveModuleRef,\n toPosix,\n} from './common.js';\nimport { createParser } from './wasmLoader.js';\n\n/**\n * Structural extraction for .java via web-tree-sitter (WASM, no native\n * compilation, no eval/exec of source content).\n *\n * Java has no free top-level functions — every method lives inside a\n * class or interface — so pass 1 walks top-level class/interface\n * declarations and, for classes, their methods (an interface's methods\n * are abstract signatures with no body, so only the interface itself\n * becomes a node, mirroring typescript.ts's interface handling).\n * Constructors (`constructor_declaration`, distinct from\n * `method_declaration` in this grammar) are intentionally not tracked as\n * separate entities — same \"structural, not exhaustive\" scope as the\n * other extractors in this file.\n *\n * Every `method_invocation` is then resolved (pass 2): a same-file\n * method/`this.method()` call resolved against the enclosing class is\n * EXTRACTED; a call qualified by an imported class name (or bound via a\n * static import) is INFERRED — the \"cross-file second pass\" placeholder\n * described in the master prompt §3. It intentionally does not open and\n * parse the imported class to confirm the target. An unresolvable callee\n * produces no edge at all.\n *\n * Fully-qualified import paths (`com.example.math.MathUtils`) have no\n * clean mapping to a same-repo relative file without real classpath/\n * package-root information, so every import resolves to an external\n * module placeholder via resolveModuleRef — consistent with how the Go\n * extractor treats its (also always-absolute) import paths.\n */\nexport async function extractJava(filePath: string, displayPath?: string): Promise<ExtractionResult> {\n const parser = await createParser('java');\n\n const raw = await fs.readFile(filePath);\n const content = raw.toString('utf-8'); // replacement-decoded — never throws on invalid bytes\n\n const tree = parser.parse(content);\n if (!tree) {\n throw new Error(`extractJava: parser produced no tree for ${filePath}`);\n }\n const root = tree.rootNode;\n\n const sourceFile = toPosix(displayPath ?? filePath);\n const builder = new ExtractionBuilder();\n const fileId = sourceFile;\n builder.addNode({ id: fileId, label: sourceFile, sourceFile, sourceLocation: 'L1' });\n\n /** Declared name (class/interface) -> our graph id. */\n const nameIndex = new Map<string, string>();\n /** tree-sitter node id -> our graph id, for every method entity we track. */\n const functionNodeMap = new Map<number, string>();\n /** tree-sitter class_declaration node id -> method name -> our graph id. */\n const classMethods = new Map<number, Map<string, string>>();\n /** tree-sitter method_declaration node id -> its enclosing class's node id. */\n const enclosingClassOf = new Map<number, number>();\n /** local binding name (imported class or statically-imported member) -> the module it came from. */\n const importIndex = new Map<string, ReturnType<typeof resolveModuleRef>>();\n\n function addModuleNode(ref: ReturnType<typeof resolveModuleRef>): void {\n if (builder.hasNode(ref.id)) return;\n builder.addNode({\n id: ref.id,\n label: ref.label,\n sourceFile: ref.external ? '<external>' : ref.id,\n sourceLocation: 'L1',\n });\n }\n\n function resolveHeritageTarget(name: string): string {\n const resolved = nameIndex.get(name);\n if (resolved) return resolved;\n const extId = externalId(name);\n if (!builder.hasNode(extId)) {\n builder.addNode({ id: extId, label: name, sourceFile: '<external>', sourceLocation: 'L0' });\n }\n return extId;\n }\n\n function handleImportDeclaration(node: TSNode): void {\n // Java's grammar keeps `static`/`*` as bare tokens (no field name), so\n // we detect them structurally rather than via childForFieldName.\n const hasWildcard = namedChildren(node).some((c) => c.type === 'asterisk');\n const scoped = namedChildren(node).find((c) => c.type === 'scoped_identifier' || c.type === 'identifier');\n if (!scoped) return;\n const fullPath = scoped.text;\n const ref = resolveModuleRef(sourceFile, fullPath);\n addModuleNode(ref);\n\n if (hasWildcard) {\n // `import com.example.util.*;` — whole package, no single local binding to record.\n builder.addEdge({ source: fileId, target: ref.id, relation: 'imports', confidence: 'EXTRACTED' });\n return;\n }\n\n // Plain class import (`import a.b.Foo;`) and static-member import\n // (`import static a.b.Foo.bar;`) both bind their last dotted segment\n // as the local name callers use unqualified.\n const segments = fullPath.split('.');\n const localName = segments[segments.length - 1];\n if (localName) importIndex.set(localName, ref);\n builder.addEdge({ source: fileId, target: ref.id, relation: 'imports_from', confidence: 'EXTRACTED' });\n }\n\n function handleMethodDeclaration(classNode: TSNode, classId: string, className: string, member: TSNode): void {\n const methodName = member.childForFieldName('name')?.text ?? '(anonymous)';\n const methodId = entityId(sourceFile, `${className}.${methodName}`);\n builder.addNode({\n id: methodId,\n label: `method ${className}.${methodName}`,\n sourceFile,\n sourceLocation: lineOf(member),\n });\n builder.addEdge({ source: classId, target: methodId, relation: 'method', confidence: 'EXTRACTED' });\n\n let methods = classMethods.get(classNode.id);\n if (!methods) {\n methods = new Map();\n classMethods.set(classNode.id, methods);\n }\n methods.set(methodName, methodId);\n functionNodeMap.set(member.id, methodId);\n enclosingClassOf.set(member.id, classNode.id);\n }\n\n function handleClassDeclaration(node: TSNode): void {\n const name = node.childForFieldName('name')?.text ?? '(anonymous)';\n const classId = entityId(sourceFile, name);\n builder.addNode({ id: classId, label: `class ${name}`, sourceFile, sourceLocation: lineOf(node) });\n builder.addEdge({ source: fileId, target: classId, relation: 'contains', confidence: 'EXTRACTED' });\n nameIndex.set(name, classId);\n functionNodeMap.set(node.id, classId);\n classMethods.set(node.id, new Map());\n\n const superclass = node.childForFieldName('superclass');\n if (superclass) {\n const base = namedChildren(superclass)[0];\n if (base) {\n builder.addEdge({\n source: classId,\n target: resolveHeritageTarget(base.text),\n relation: 'inherits',\n confidence: 'EXTRACTED',\n });\n }\n }\n\n const interfaces = node.childForFieldName('interfaces');\n if (interfaces) {\n const typeList = namedChildren(interfaces).find((c) => c.type === 'type_list');\n for (const iface of typeList ? namedChildren(typeList) : []) {\n builder.addEdge({\n source: classId,\n target: resolveHeritageTarget(iface.text),\n relation: 'implements',\n confidence: 'EXTRACTED',\n });\n }\n }\n\n const body = node.childForFieldName('body');\n if (body) {\n for (const member of namedChildren(body)) {\n if (member.type !== 'method_declaration') continue; // constructors intentionally not tracked\n handleMethodDeclaration(node, classId, name, member);\n }\n }\n }\n\n function handleInterfaceDeclaration(node: TSNode): void {\n const name = node.childForFieldName('name')?.text ?? '(anonymous)';\n const id = entityId(sourceFile, name);\n builder.addNode({ id, label: `interface ${name}`, sourceFile, sourceLocation: lineOf(node) });\n builder.addEdge({ source: fileId, target: id, relation: 'contains', confidence: 'EXTRACTED' });\n nameIndex.set(name, id);\n\n const extendsInterfaces = namedChildren(node).find((c) => c.type === 'extends_interfaces');\n if (extendsInterfaces) {\n const typeList = namedChildren(extendsInterfaces).find((c) => c.type === 'type_list');\n for (const parent of typeList ? namedChildren(typeList) : []) {\n builder.addEdge({\n source: id,\n target: resolveHeritageTarget(parent.text),\n relation: 'inherits',\n confidence: 'EXTRACTED',\n });\n }\n }\n }\n\n // Pass 1: top-level declarations (imports, classes, interfaces).\n for (const child of namedChildren(root)) {\n switch (child.type) {\n case 'import_declaration':\n handleImportDeclaration(child);\n break;\n case 'class_declaration':\n handleClassDeclaration(child);\n break;\n case 'interface_declaration':\n handleInterfaceDeclaration(child);\n break;\n default:\n break;\n }\n }\n\n function closestTrackedCaller(node: TSNode): string {\n let current: TSNode | null = node.parent;\n while (current) {\n const tracked = functionNodeMap.get(current.id);\n if (tracked) return tracked;\n current = current.parent;\n }\n return fileId;\n }\n\n function closestEnclosingClassMethods(node: TSNode): Map<string, string> | undefined {\n let current: TSNode | null = node.parent;\n while (current) {\n if (current.type === 'method_declaration') {\n const classNodeId = enclosingClassOf.get(current.id);\n if (classNodeId !== undefined) return classMethods.get(classNodeId);\n }\n current = current.parent;\n }\n return undefined;\n }\n\n // Pass 2: calls (see the function doc comment above for the\n // EXTRACTED/INFERRED policy).\n for (const call of descendantsOfType(root, ['method_invocation'])) {\n const name = call.childForFieldName('name')?.text;\n if (!name) continue;\n const object = call.childForFieldName('object');\n\n let targetId: string | null = null;\n let confidence: 'EXTRACTED' | 'INFERRED' = 'EXTRACTED';\n\n if (!object) {\n // Unqualified call: same-file method (via the tracked caller's own\n // class) or a statically-imported member.\n const methodId = closestEnclosingClassMethods(call)?.get(name);\n if (methodId) {\n targetId = methodId;\n } else {\n const viaImport = importIndex.get(name);\n if (viaImport) {\n targetId = viaImport.id;\n confidence = 'INFERRED';\n }\n }\n } else if (object.type === 'this') {\n const methodId = closestEnclosingClassMethods(call)?.get(name);\n if (methodId) targetId = methodId;\n } else if (object.type === 'identifier') {\n const viaImport = importIndex.get(object.text);\n if (viaImport) {\n targetId = viaImport.id;\n confidence = 'INFERRED';\n }\n }\n\n if (!targetId) continue; // unresolved callee (builtin, external value, ...) — no noisy guess\n const callerId = closestTrackedCaller(call);\n builder.addEdge({ source: callerId, target: targetId, relation: 'calls', confidence });\n }\n\n return builder.build();\n}\n","import * as fs from 'node:fs/promises';\nimport type { Node as TSNode } from 'web-tree-sitter';\nimport type { ExtractionResult } from '../types.js';\nimport {\n ExtractionBuilder,\n descendantsOfType,\n entityId,\n externalId,\n lineOf,\n namedChildren,\n resolveModuleRef,\n toPosix,\n} from './common.js';\nimport { createParser } from './wasmLoader.js';\n\n/**\n * Structural extraction for .py via web-tree-sitter (WASM, no native\n * compilation, no eval/exec of source content).\n *\n * Pattern mirrors typescript.ts: parse -> walk the module body for\n * top-level functions/classes/imports (pass 1) -> walk every `call` node\n * and resolve its callee against what pass 1 saw (pass 2). A same-file\n * callee (or a `self.method()` call resolved against the enclosing class)\n * is EXTRACTED; a callee that only resolves through an imported local\n * binding (a directly-imported name, or a member access on an imported\n * module alias) is emitted as INFERRED — the \"cross-file second pass\"\n * placeholder described in the master prompt §3. It intentionally does not\n * open and parse the imported module to confirm the target. An\n * unresolvable callee (a builtin, a call on some arbitrary local value,\n * etc.) produces no edge at all rather than a noisy guess.\n *\n * Python has no separate interface/heritage-clause concept: every base\n * class listed in `class Foo(Base, Other):` becomes an `inherits` edge.\n */\nexport async function extractPython(filePath: string, displayPath?: string): Promise<ExtractionResult> {\n const parser = await createParser('python');\n\n const raw = await fs.readFile(filePath);\n const content = raw.toString('utf-8'); // replacement-decoded — never throws on invalid bytes\n\n const tree = parser.parse(content);\n if (!tree) {\n throw new Error(`extractPython: parser produced no tree for ${filePath}`);\n }\n const root = tree.rootNode;\n\n const sourceFile = toPosix(displayPath ?? filePath);\n const builder = new ExtractionBuilder();\n const fileId = sourceFile;\n builder.addNode({ id: fileId, label: sourceFile, sourceFile, sourceLocation: 'L1' });\n\n /** Declared name (function/class) -> our graph id. */\n const nameIndex = new Map<string, string>();\n /** tree-sitter node id -> our graph id, for every function-like entity we track. */\n const functionNodeMap = new Map<number, string>();\n /** tree-sitter class_definition node id -> method name -> our graph id. */\n const classMethods = new Map<number, Map<string, string>>();\n /** tree-sitter function_definition (method) node id -> its enclosing class's node id. */\n const enclosingClassOf = new Map<number, number>();\n /** local binding name (import) -> the module it came from. */\n const importIndex = new Map<string, ReturnType<typeof resolveModuleRef>>();\n\n function addModuleNode(ref: ReturnType<typeof resolveModuleRef>): void {\n if (builder.hasNode(ref.id)) return;\n builder.addNode({\n id: ref.id,\n label: ref.label,\n sourceFile: ref.external ? '<external>' : ref.id,\n sourceLocation: 'L1',\n });\n }\n\n function resolveHeritageTarget(name: string): string {\n const resolved = nameIndex.get(name);\n if (resolved) return resolved;\n const extId = externalId(name);\n if (!builder.hasNode(extId)) {\n builder.addNode({ id: extId, label: name, sourceFile: '<external>', sourceLocation: 'L0' });\n }\n return extId;\n }\n\n /** Unwrap a `@decorator` / `decorated_definition` wrapper to the function/class it decorates. */\n function unwrapDecorated(node: TSNode): TSNode | null {\n if (node.type !== 'decorated_definition') return node;\n return (\n namedChildren(node).find((c) => c.type === 'function_definition' || c.type === 'class_definition') ?? null\n );\n }\n\n /**\n * Convert a `relative_import` node (e.g. \".\", \".foo\", \"..foo.bar\") into a\n * relative-path-shaped specifier resolveModuleRef understands (e.g. \".\",\n * \"./foo\", \"../foo/bar\") — one leading dot means \"this package\" (`.`),\n * each additional dot means one more directory up.\n */\n function relativeSpecifier(relImport: TSNode): string {\n let dots = 0;\n for (const ch of relImport.text) {\n if (ch !== '.') break;\n dots++;\n }\n const dotted = namedChildren(relImport).find((c) => c.type === 'dotted_name');\n const up = dots - 1;\n let base = up === 0 ? '.' : Array.from({ length: up }, () => '..').join('/');\n if (dotted) {\n base = `${base}/${dotted.text.split('.').join('/')}`;\n }\n return base;\n }\n\n function moduleSpecifierOf(node: TSNode): string {\n if (node.type === 'relative_import') return relativeSpecifier(node);\n return node.text; // dotted_name, e.g. \"pkg.sub\"\n }\n\n function handleFunctionDefinition(node: TSNode): void {\n const name = node.childForFieldName('name')?.text ?? '(anonymous)';\n const id = entityId(sourceFile, name);\n builder.addNode({ id, label: `function ${name}`, sourceFile, sourceLocation: lineOf(node) });\n builder.addEdge({ source: fileId, target: id, relation: 'contains', confidence: 'EXTRACTED' });\n nameIndex.set(name, id);\n functionNodeMap.set(node.id, id);\n }\n\n function handleClassDefinition(node: TSNode): void {\n const name = node.childForFieldName('name')?.text ?? '(anonymous)';\n const classId = entityId(sourceFile, name);\n builder.addNode({ id: classId, label: `class ${name}`, sourceFile, sourceLocation: lineOf(node) });\n builder.addEdge({ source: fileId, target: classId, relation: 'contains', confidence: 'EXTRACTED' });\n nameIndex.set(name, classId);\n functionNodeMap.set(node.id, classId);\n\n const superclasses = node.childForFieldName('superclasses');\n if (superclasses) {\n for (const base of namedChildren(superclasses)) {\n if (base.type !== 'identifier' && base.type !== 'attribute') continue; // skip e.g. metaclass=Meta\n builder.addEdge({\n source: classId,\n target: resolveHeritageTarget(base.text),\n relation: 'inherits',\n confidence: 'EXTRACTED',\n });\n }\n }\n\n const methods = new Map<string, string>();\n classMethods.set(node.id, methods);\n\n const body = node.childForFieldName('body');\n if (body) {\n for (const rawMember of namedChildren(body)) {\n const member = unwrapDecorated(rawMember);\n if (!member || member.type !== 'function_definition') continue;\n const methodName = member.childForFieldName('name')?.text ?? '(anonymous)';\n const methodId = entityId(sourceFile, `${name}.${methodName}`);\n builder.addNode({\n id: methodId,\n label: `method ${name}.${methodName}`,\n sourceFile,\n sourceLocation: lineOf(member),\n });\n builder.addEdge({ source: classId, target: methodId, relation: 'method', confidence: 'EXTRACTED' });\n methods.set(methodName, methodId);\n functionNodeMap.set(member.id, methodId);\n enclosingClassOf.set(member.id, node.id);\n }\n }\n }\n\n function handleImportStatement(node: TSNode): void {\n // `import a, b.c as d` — every item is a top-level named child, either\n // `dotted_name` (bare module) or `aliased_import` (module `as` alias).\n for (const item of namedChildren(node)) {\n if (item.type === 'dotted_name') {\n const ref = resolveModuleRef(sourceFile, item.text);\n addModuleNode(ref);\n const bindingName = namedChildren(item)[0]?.text ?? item.text; // `import pkg.sub` binds `pkg`\n importIndex.set(bindingName, ref);\n builder.addEdge({ source: fileId, target: ref.id, relation: 'imports', confidence: 'EXTRACTED' });\n } else if (item.type === 'aliased_import') {\n const dotted = item.childForFieldName('name');\n const alias = item.childForFieldName('alias')?.text;\n if (!dotted || !alias) continue;\n const ref = resolveModuleRef(sourceFile, dotted.text);\n addModuleNode(ref);\n importIndex.set(alias, ref);\n builder.addEdge({ source: fileId, target: ref.id, relation: 'imports', confidence: 'EXTRACTED' });\n }\n }\n }\n\n function handleImportFromStatement(node: TSNode): void {\n const moduleNode = node.childForFieldName('module_name');\n if (!moduleNode) return;\n const ref = resolveModuleRef(sourceFile, moduleSpecifierOf(moduleNode));\n addModuleNode(ref);\n\n let sawItem = false;\n for (const child of namedChildren(node)) {\n if (child.id === moduleNode.id) continue;\n if (child.type === 'dotted_name') {\n sawItem = true;\n importIndex.set(child.text, ref);\n } else if (child.type === 'aliased_import') {\n sawItem = true;\n const alias = child.childForFieldName('alias')?.text;\n const name = child.childForFieldName('name')?.text;\n if (alias) importIndex.set(alias, ref);\n else if (name) importIndex.set(name, ref);\n } else if (child.type === 'wildcard_import') {\n sawItem = true;\n }\n }\n if (sawItem) {\n builder.addEdge({ source: fileId, target: ref.id, relation: 'imports_from', confidence: 'EXTRACTED' });\n }\n }\n\n // Pass 1: top-level declarations (functions, classes, imports),\n // unwrapping `@decorator` wrappers where present.\n for (const rawChild of namedChildren(root)) {\n if (rawChild.type === 'import_statement') {\n handleImportStatement(rawChild);\n continue;\n }\n if (rawChild.type === 'import_from_statement') {\n handleImportFromStatement(rawChild);\n continue;\n }\n\n const effective = unwrapDecorated(rawChild);\n if (!effective) continue;\n\n switch (effective.type) {\n case 'function_definition':\n handleFunctionDefinition(effective);\n break;\n case 'class_definition':\n handleClassDefinition(effective);\n break;\n default:\n break;\n }\n }\n\n function closestTrackedCaller(node: TSNode): string {\n let current: TSNode | null = node.parent;\n while (current) {\n const tracked = functionNodeMap.get(current.id);\n if (tracked) return tracked;\n current = current.parent;\n }\n return fileId;\n }\n\n function closestEnclosingClassMethods(node: TSNode): Map<string, string> | undefined {\n let current: TSNode | null = node.parent;\n while (current) {\n if (current.type === 'function_definition') {\n const classNodeId = enclosingClassOf.get(current.id);\n if (classNodeId !== undefined) return classMethods.get(classNodeId);\n }\n current = current.parent;\n }\n return undefined;\n }\n\n // Pass 2: calls (see the function doc comment above for the\n // EXTRACTED/INFERRED policy).\n for (const call of descendantsOfType(root, ['call'])) {\n const fn = call.childForFieldName('function');\n if (!fn) continue;\n\n let targetId: string | null = null;\n let confidence: 'EXTRACTED' | 'INFERRED' = 'EXTRACTED';\n\n if (fn.type === 'identifier') {\n const name = fn.text;\n const sameFile = nameIndex.get(name);\n if (sameFile) {\n targetId = sameFile;\n } else {\n const viaImport = importIndex.get(name);\n if (viaImport) {\n targetId = viaImport.id;\n confidence = 'INFERRED';\n }\n }\n } else if (fn.type === 'attribute') {\n const object = fn.childForFieldName('object');\n const property = fn.childForFieldName('attribute')?.text;\n if (object && property) {\n if (object.type === 'identifier' && object.text === 'self') {\n const methodId = closestEnclosingClassMethods(call)?.get(property);\n if (methodId) targetId = methodId;\n } else if (object.type === 'identifier') {\n const viaImport = importIndex.get(object.text);\n if (viaImport) {\n targetId = viaImport.id;\n confidence = 'INFERRED';\n }\n }\n }\n }\n\n if (!targetId) continue; // unresolved callee (builtin, external value, ...) — no noisy guess\n const callerId = closestTrackedCaller(call);\n builder.addEdge({ source: callerId, target: targetId, relation: 'calls', confidence });\n }\n\n return builder.build();\n}\n","import * as fs from 'node:fs/promises';\nimport type { Node as TSNode } from 'web-tree-sitter';\nimport type { ExtractionResult } from '../types.js';\nimport {\n ExtractionBuilder,\n descendantsOfType,\n entityId,\n externalId,\n lineOf,\n namedChildren,\n resolveModuleRef,\n toPosix,\n} from './common.js';\nimport { createParser } from './wasmLoader.js';\n\n/**\n * Best-effort conversion of a required path's last segment into the\n * CamelCase constant name Ruby convention says it defines (`require_relative\n * './math'` -> `Math`, `require 'active_support/core_ext'` -> `CoreExt`).\n * Ruby's `require`/`require_relative` bind no local alias at all (unlike\n * every other language here), so this is the one available heuristic for\n * giving later `Constant.method(...)` calls something to resolve against —\n * it is a naming-convention guess, not a confirmed binding.\n */\nfunction conventionalConstantName(specifier: string): string {\n const lastSegment = specifier.split('/').filter(Boolean).pop() ?? specifier;\n return lastSegment\n .split('_')\n .filter(Boolean)\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join('');\n}\n\n/** Text of a `string` node's `string_content` child (already unquoted), or '' for an empty literal. */\nfunction stringLiteralContent(node: TSNode): string | null {\n if (node.type !== 'string') return null;\n const content = namedChildren(node).find((c) => c.type === 'string_content');\n return content ? content.text : '';\n}\n\n/**\n * Structural extraction for .rb via web-tree-sitter (WASM, no native\n * compilation, no eval/exec of source content).\n *\n * Pattern mirrors typescript.ts, adapted to Ruby's shape: top-level\n * classes/modules and free `method`s (pass 1) -> every `call` node walked\n * once to special-case `require`/`require_relative` into import edges (Ruby\n * has no dedicated import AST node — these are plain method calls, per the\n * master prompt), then a second walk resolves the rest as method calls\n * (pass 2). A same-file callee — including an implicit- or explicit-`self`\n * call resolved against the enclosing class/module — is EXTRACTED; a call\n * through a `Constant.method(...)` receiver that only resolves via the\n * conventional-constant-name heuristic above is INFERRED. An unresolvable\n * callee produces no edge at all.\n *\n * Known, deliberate scope limit: a bare, paren-less, argument-less\n * identifier (`helper_top` with no parens or `()`) is genuinely ambiguous\n * with a local-variable reference at the grammar level — tree-sitter-ruby\n * itself represents it as a plain `identifier`, not a `call` — so this\n * extractor (like a human reading the AST alone) cannot tell them apart\n * and does not attempt to. Only calls that surface as an actual `call`\n * node (parens, and/or arguments, and/or an explicit receiver) are\n * resolved.\n *\n * `include`/`extend`/`prepend` (Ruby's mixin mechanism) become `mixes_in`\n * edges; `class Foo < Bar` becomes `inherits`. Ruby has no `implements`\n * equivalent.\n */\nexport async function extractRuby(filePath: string, displayPath?: string): Promise<ExtractionResult> {\n const parser = await createParser('ruby');\n\n const raw = await fs.readFile(filePath);\n const content = raw.toString('utf-8'); // replacement-decoded — never throws on invalid bytes\n\n const tree = parser.parse(content);\n if (!tree) {\n throw new Error(`extractRuby: parser produced no tree for ${filePath}`);\n }\n const root = tree.rootNode;\n\n const sourceFile = toPosix(displayPath ?? filePath);\n const builder = new ExtractionBuilder();\n const fileId = sourceFile;\n builder.addNode({ id: fileId, label: sourceFile, sourceFile, sourceLocation: 'L1' });\n\n /** Declared name (top-level function/class/module) -> our graph id. */\n const nameIndex = new Map<string, string>();\n /** tree-sitter node id -> our graph id, for every function/method entity we track. */\n const functionNodeMap = new Map<number, string>();\n /** graph id of a class/module -> method name -> our graph id. */\n const typeMethods = new Map<string, Map<string, string>>();\n /** tree-sitter method node id -> its enclosing class/module's graph id. */\n const enclosingTypeOf = new Map<number, string>();\n /** conventional constant name (derived from a require path) -> the module it came from. */\n const importIndex = new Map<string, ReturnType<typeof resolveModuleRef>>();\n\n function addModuleNode(ref: ReturnType<typeof resolveModuleRef>): void {\n if (builder.hasNode(ref.id)) return;\n builder.addNode({\n id: ref.id,\n label: ref.label,\n sourceFile: ref.external ? '<external>' : ref.id,\n sourceLocation: 'L1',\n });\n }\n\n function resolveHeritageTarget(name: string): string {\n const resolved = nameIndex.get(name);\n if (resolved) return resolved;\n const extId = externalId(name);\n if (!builder.hasNode(extId)) {\n builder.addNode({ id: extId, label: name, sourceFile: '<external>', sourceLocation: 'L0' });\n }\n return extId;\n }\n\n function handleTopLevelMethod(node: TSNode): void {\n const name = node.childForFieldName('name')?.text ?? '(anonymous)';\n const id = entityId(sourceFile, name);\n builder.addNode({ id, label: `function ${name}`, sourceFile, sourceLocation: lineOf(node) });\n builder.addEdge({ source: fileId, target: id, relation: 'contains', confidence: 'EXTRACTED' });\n nameIndex.set(name, id);\n functionNodeMap.set(node.id, id);\n }\n\n function handleClassOrModule(node: TSNode, kind: 'class' | 'module'): void {\n const name = node.childForFieldName('name')?.text ?? '(anonymous)';\n const id = entityId(sourceFile, name);\n builder.addNode({ id, label: `${kind} ${name}`, sourceFile, sourceLocation: lineOf(node) });\n builder.addEdge({ source: fileId, target: id, relation: 'contains', confidence: 'EXTRACTED' });\n nameIndex.set(name, id);\n typeMethods.set(id, new Map());\n\n if (kind === 'class') {\n const superclass = node.childForFieldName('superclass');\n const base = superclass ? namedChildren(superclass)[0] : undefined;\n if (base) {\n builder.addEdge({\n source: id,\n target: resolveHeritageTarget(base.text),\n relation: 'inherits',\n confidence: 'EXTRACTED',\n });\n }\n }\n\n const body = node.childForFieldName('body');\n if (!body) return;\n const methods = typeMethods.get(id);\n for (const member of namedChildren(body)) {\n if (member.type === 'method') {\n const methodName = member.childForFieldName('name')?.text ?? '(anonymous)';\n const methodId = entityId(sourceFile, `${name}.${methodName}`);\n builder.addNode({\n id: methodId,\n label: `method ${name}.${methodName}`,\n sourceFile,\n sourceLocation: lineOf(member),\n });\n builder.addEdge({ source: id, target: methodId, relation: 'method', confidence: 'EXTRACTED' });\n methods?.set(methodName, methodId);\n functionNodeMap.set(member.id, methodId);\n enclosingTypeOf.set(member.id, id);\n } else if (member.type === 'call') {\n const methodField = member.childForFieldName('method')?.text;\n if (methodField !== 'include' && methodField !== 'extend' && methodField !== 'prepend') continue;\n const args = member.childForFieldName('arguments');\n for (const arg of args ? namedChildren(args) : []) {\n if (arg.type !== 'constant' && arg.type !== 'scoped_constant') continue;\n builder.addEdge({\n source: id,\n target: resolveHeritageTarget(arg.text),\n relation: 'mixes_in',\n confidence: 'EXTRACTED',\n });\n }\n }\n }\n }\n\n // Pass 1: top-level declarations (free methods, classes, modules).\n for (const child of namedChildren(root)) {\n switch (child.type) {\n case 'method':\n handleTopLevelMethod(child);\n break;\n case 'class':\n handleClassOrModule(child, 'class');\n break;\n case 'module':\n handleClassOrModule(child, 'module');\n break;\n default:\n break;\n }\n }\n\n function closestTrackedCaller(node: TSNode): string {\n let current: TSNode | null = node.parent;\n while (current) {\n const tracked = functionNodeMap.get(current.id);\n if (tracked) return tracked;\n current = current.parent;\n }\n return fileId;\n }\n\n function closestEnclosingTypeMethods(node: TSNode): Map<string, string> | undefined {\n let current: TSNode | null = node.parent;\n while (current) {\n if (current.type === 'method') {\n const typeId = enclosingTypeOf.get(current.id);\n if (typeId !== undefined) return typeMethods.get(typeId);\n }\n current = current.parent;\n }\n return undefined;\n }\n\n const allCalls = descendantsOfType(root, ['call']);\n\n // Pass 2a: `require`/`require_relative` — plain method calls in Ruby's\n // grammar, special-cased into import edges instead of `calls` edges.\n const requireCallIds = new Set<number>();\n for (const call of allCalls) {\n const methodName = call.childForFieldName('method')?.text;\n if (methodName !== 'require' && methodName !== 'require_relative') continue;\n const args = call.childForFieldName('arguments');\n const soleArg = args ? namedChildren(args) : [];\n if (soleArg.length !== 1) continue;\n const literal = stringLiteralContent(soleArg[0] as TSNode);\n if (literal === null) continue;\n\n requireCallIds.add(call.id);\n const ref = resolveModuleRef(sourceFile, literal);\n addModuleNode(ref);\n builder.addEdge({ source: fileId, target: ref.id, relation: 'imports', confidence: 'EXTRACTED' });\n importIndex.set(conventionalConstantName(literal), ref);\n }\n\n // Pass 2b: every other call (see the function doc comment above for the\n // EXTRACTED/INFERRED policy).\n for (const call of allCalls) {\n if (requireCallIds.has(call.id)) continue;\n const methodName = call.childForFieldName('method')?.text;\n if (!methodName) continue;\n const receiver = call.childForFieldName('receiver');\n\n let targetId: string | null = null;\n let confidence: 'EXTRACTED' | 'INFERRED' = 'EXTRACTED';\n\n if (!receiver) {\n const viaEnclosingType = closestEnclosingTypeMethods(call)?.get(methodName);\n if (viaEnclosingType) {\n targetId = viaEnclosingType;\n } else {\n const sameFile = nameIndex.get(methodName);\n if (sameFile) targetId = sameFile;\n }\n } else if (receiver.type === 'self') {\n const methodId = closestEnclosingTypeMethods(call)?.get(methodName);\n if (methodId) targetId = methodId;\n } else if (receiver.type === 'constant' || receiver.type === 'scoped_constant') {\n const sameFileTypeId = nameIndex.get(receiver.text);\n const methodId = sameFileTypeId ? typeMethods.get(sameFileTypeId)?.get(methodName) : undefined;\n if (methodId) {\n targetId = methodId;\n } else {\n const viaImport = importIndex.get(receiver.text);\n if (viaImport) {\n targetId = viaImport.id;\n confidence = 'INFERRED';\n }\n }\n }\n\n if (!targetId) continue; // unresolved callee (builtin, local var, ...) — no noisy guess\n const callerId = closestTrackedCaller(call);\n builder.addEdge({ source: callerId, target: targetId, relation: 'calls', confidence });\n }\n\n return builder.build();\n}\n","import * as fs from 'node:fs/promises';\nimport type { Node as TSNode } from 'web-tree-sitter';\nimport type { ExtractionResult } from '../types.js';\nimport {\n ExtractionBuilder,\n descendantsOfType,\n entityId,\n externalId,\n lineOf,\n namedChildren,\n resolveModuleRef,\n toPosix,\n} from './common.js';\nimport { createParser } from './wasmLoader.js';\n\n/**\n * Convert a Rust `use` path's `::`-joined segments into the relative-path\n * shape resolveModuleRef() understands: `crate`/`self` map to \"this\n * directory\" (`.`), each leading `super` walks up one directory, and\n * anything else (an external crate, `std`, ...) is left `::`-joined so\n * resolveModuleRef treats it as an external module specifier.\n */\nfunction convertUsePath(segments: string[]): string {\n const first = segments[0];\n if (first === 'crate' || first === 'self') {\n const rest = segments.slice(1);\n return rest.length ? `./${rest.join('/')}` : '.';\n }\n if (first === 'super') {\n let i = 0;\n while (segments[i] === 'super') i++;\n const ups = Array.from({ length: i }, () => '..').join('/');\n const rest = segments.slice(i);\n return rest.length ? `${ups}/${rest.join('/')}` : ups;\n }\n return segments.join('::');\n}\n\n/**\n * Structural extraction for .rs via web-tree-sitter (WASM, no native\n * compilation, no eval/exec of source content).\n *\n * Pattern mirrors typescript.ts, adapted to Rust's shape: top-level\n * structs/traits and free functions come from pass 1, but methods are\n * declared separately in `impl` blocks (inherent `impl Type { ... }` or\n * trait `impl Trait for Type { ... }`), so those are walked as their own\n * step and attached to whichever struct/trait `name` they target. Every\n * call_expression is then resolved (pass 2): a same-file callee, or a\n * `self.method()` call resolved against the enclosing impl block's type,\n * is EXTRACTED; a callee that only resolves through a `use`-imported local\n * binding (an imported item, or a module alias via `use ... as`) is\n * INFERRED — the \"cross-file second pass\" placeholder described in the\n * master prompt §3. It intentionally does not open and parse the\n * imported module to confirm the target. An unresolvable callee produces\n * no edge at all.\n *\n * `impl Trait for Type` is Rust's one heritage-like construct exposed\n * directly in the grammar, so it becomes an `implements` edge from `Type`\n * to `Trait`.\n */\nexport async function extractRust(filePath: string, displayPath?: string): Promise<ExtractionResult> {\n const parser = await createParser('rust');\n\n const raw = await fs.readFile(filePath);\n const content = raw.toString('utf-8'); // replacement-decoded — never throws on invalid bytes\n\n const tree = parser.parse(content);\n if (!tree) {\n throw new Error(`extractRust: parser produced no tree for ${filePath}`);\n }\n const root = tree.rootNode;\n\n const sourceFile = toPosix(displayPath ?? filePath);\n const builder = new ExtractionBuilder();\n const fileId = sourceFile;\n builder.addNode({ id: fileId, label: sourceFile, sourceFile, sourceLocation: 'L1' });\n\n /** Declared name (function/struct/trait) -> our graph id. */\n const nameIndex = new Map<string, string>();\n /** tree-sitter node id -> our graph id, for every function/method entity we track. */\n const functionNodeMap = new Map<number, string>();\n /** graph id of a struct/trait -> method name -> our graph id. */\n const typeMethods = new Map<string, Map<string, string>>();\n /** tree-sitter function_item (method) node id -> the owning impl block's type graph id. */\n const enclosingTypeOf = new Map<number, string>();\n /** local binding name (`use` item/alias) -> the module it came from. */\n const importIndex = new Map<string, ReturnType<typeof resolveModuleRef>>();\n\n function addModuleNode(ref: ReturnType<typeof resolveModuleRef>): void {\n if (builder.hasNode(ref.id)) return;\n builder.addNode({\n id: ref.id,\n label: ref.label,\n sourceFile: ref.external ? '<external>' : ref.id,\n sourceLocation: 'L1',\n });\n }\n\n function resolveTypeTarget(name: string): string {\n const resolved = nameIndex.get(name);\n if (resolved) return resolved;\n const extId = externalId(name);\n if (!builder.hasNode(extId)) {\n builder.addNode({ id: extId, label: name, sourceFile: '<external>', sourceLocation: 'L0' });\n }\n return extId;\n }\n\n function processUseArgument(node: TSNode): void {\n switch (node.type) {\n case 'identifier': {\n // `use foo;` — whole-module import, single segment.\n const ref = resolveModuleRef(sourceFile, convertUsePath([node.text]));\n addModuleNode(ref);\n importIndex.set(node.text, ref);\n builder.addEdge({ source: fileId, target: ref.id, relation: 'imports', confidence: 'EXTRACTED' });\n break;\n }\n case 'scoped_identifier': {\n // `use std::fmt;` — single named item `fmt` from module `std`.\n const pathNode = node.childForFieldName('path');\n const nameNode = node.childForFieldName('name');\n if (!pathNode || !nameNode) break;\n const ref = resolveModuleRef(sourceFile, convertUsePath(pathNode.text.split('::')));\n addModuleNode(ref);\n importIndex.set(nameNode.text, ref);\n builder.addEdge({ source: fileId, target: ref.id, relation: 'imports_from', confidence: 'EXTRACTED' });\n break;\n }\n case 'use_as_clause': {\n // `use crate::math as m;` — whole module aliased to `m`.\n const pathNode = node.childForFieldName('path');\n const aliasNode = node.childForFieldName('alias');\n if (!pathNode || !aliasNode) break;\n const ref = resolveModuleRef(sourceFile, convertUsePath(pathNode.text.split('::')));\n addModuleNode(ref);\n importIndex.set(aliasNode.text, ref);\n builder.addEdge({ source: fileId, target: ref.id, relation: 'imports', confidence: 'EXTRACTED' });\n break;\n }\n case 'scoped_use_list': {\n // `use crate::math::{add, multiply};` — named items from a module.\n const pathNode = node.childForFieldName('path');\n const listNode = node.childForFieldName('list');\n if (!listNode) break;\n const prefixSegments = pathNode ? pathNode.text.split('::') : [];\n const ref = resolveModuleRef(sourceFile, convertUsePath(prefixSegments));\n addModuleNode(ref);\n let sawItem = false;\n for (const item of namedChildren(listNode)) {\n sawItem = true;\n if (item.type === 'identifier') {\n importIndex.set(item.text, ref);\n } else if (item.type === 'use_as_clause') {\n const alias = item.childForFieldName('alias')?.text;\n if (alias) importIndex.set(alias, ref);\n }\n // nested scoped_identifier / use_wildcard / `self` items: edge is\n // still emitted below, just no simple local binding to record.\n }\n if (sawItem) {\n builder.addEdge({ source: fileId, target: ref.id, relation: 'imports_from', confidence: 'EXTRACTED' });\n }\n break;\n }\n default:\n break; // `use foo::*;` (use_wildcard) or other rare forms — no clean binding to model\n }\n }\n\n function handleStructItem(node: TSNode): void {\n const name = node.childForFieldName('name')?.text ?? '(anonymous)';\n const id = entityId(sourceFile, name);\n builder.addNode({ id, label: `struct ${name}`, sourceFile, sourceLocation: lineOf(node) });\n builder.addEdge({ source: fileId, target: id, relation: 'contains', confidence: 'EXTRACTED' });\n nameIndex.set(name, id);\n typeMethods.set(id, new Map());\n }\n\n function handleTraitItem(node: TSNode): void {\n const name = node.childForFieldName('name')?.text ?? '(anonymous)';\n const id = entityId(sourceFile, name);\n builder.addNode({ id, label: `trait ${name}`, sourceFile, sourceLocation: lineOf(node) });\n builder.addEdge({ source: fileId, target: id, relation: 'contains', confidence: 'EXTRACTED' });\n nameIndex.set(name, id);\n }\n\n function handleFunctionItem(node: TSNode): void {\n const name = node.childForFieldName('name')?.text ?? '(anonymous)';\n const id = entityId(sourceFile, name);\n builder.addNode({ id, label: `function ${name}`, sourceFile, sourceLocation: lineOf(node) });\n builder.addEdge({ source: fileId, target: id, relation: 'contains', confidence: 'EXTRACTED' });\n nameIndex.set(name, id);\n functionNodeMap.set(node.id, id);\n }\n\n function handleImplItem(node: TSNode): void {\n const typeName = node.childForFieldName('type')?.text;\n if (!typeName) return;\n const typeId = resolveTypeTarget(typeName);\n\n const traitName = node.childForFieldName('trait')?.text;\n if (traitName) {\n builder.addEdge({\n source: typeId,\n target: resolveTypeTarget(traitName),\n relation: 'implements',\n confidence: 'EXTRACTED',\n });\n }\n\n let methods = typeMethods.get(typeId);\n if (!methods) {\n methods = new Map();\n typeMethods.set(typeId, methods);\n }\n\n const body = node.childForFieldName('body');\n if (!body) return;\n for (const member of namedChildren(body)) {\n if (member.type !== 'function_item') continue;\n const methodName = member.childForFieldName('name')?.text ?? '(anonymous)';\n const methodId = entityId(sourceFile, `${typeName}.${methodName}`);\n builder.addNode({\n id: methodId,\n label: `method ${typeName}.${methodName}`,\n sourceFile,\n sourceLocation: lineOf(member),\n });\n builder.addEdge({ source: typeId, target: methodId, relation: 'method', confidence: 'EXTRACTED' });\n methods.set(methodName, methodId);\n functionNodeMap.set(member.id, methodId);\n enclosingTypeOf.set(member.id, typeId);\n }\n }\n\n // Pass 1: top-level declarations (imports, structs, traits, free\n // functions). Impl blocks are handled in their own pass below so every\n // struct/trait name is already registered before methods attach to it.\n const implNodes: TSNode[] = [];\n for (const child of namedChildren(root)) {\n switch (child.type) {\n case 'use_declaration': {\n const arg = child.childForFieldName('argument');\n if (arg) processUseArgument(arg);\n break;\n }\n case 'struct_item':\n handleStructItem(child);\n break;\n case 'trait_item':\n handleTraitItem(child);\n break;\n case 'function_item':\n handleFunctionItem(child);\n break;\n case 'impl_item':\n implNodes.push(child);\n break;\n default:\n break;\n }\n }\n for (const impl of implNodes) handleImplItem(impl);\n\n function closestTrackedCaller(node: TSNode): string {\n let current: TSNode | null = node.parent;\n while (current) {\n const tracked = functionNodeMap.get(current.id);\n if (tracked) return tracked;\n current = current.parent;\n }\n return fileId;\n }\n\n function closestEnclosingTypeMethods(node: TSNode): Map<string, string> | undefined {\n let current: TSNode | null = node.parent;\n while (current) {\n if (current.type === 'function_item') {\n const typeId = enclosingTypeOf.get(current.id);\n if (typeId !== undefined) return typeMethods.get(typeId);\n }\n current = current.parent;\n }\n return undefined;\n }\n\n // Pass 2: calls (see the function doc comment above for the\n // EXTRACTED/INFERRED policy).\n for (const call of descendantsOfType(root, ['call_expression'])) {\n const fn = call.childForFieldName('function');\n if (!fn) continue;\n\n let targetId: string | null = null;\n let confidence: 'EXTRACTED' | 'INFERRED' = 'EXTRACTED';\n\n if (fn.type === 'identifier') {\n const name = fn.text;\n const sameFile = nameIndex.get(name);\n if (sameFile) {\n targetId = sameFile;\n } else {\n const viaImport = importIndex.get(name);\n if (viaImport) {\n targetId = viaImport.id;\n confidence = 'INFERRED';\n }\n }\n } else if (fn.type === 'field_expression') {\n const value = fn.childForFieldName('value');\n const field = fn.childForFieldName('field')?.text;\n if (value && field) {\n if (value.type === 'self') {\n const methodId = closestEnclosingTypeMethods(call)?.get(field);\n if (methodId) targetId = methodId;\n }\n }\n } else if (fn.type === 'scoped_identifier') {\n // `m::add(1, 2)` — call through a `use ... as m` module alias.\n const path = fn.childForFieldName('path')?.text;\n const name = fn.childForFieldName('name')?.text;\n if (path && name) {\n const viaImport = importIndex.get(path);\n if (viaImport) {\n targetId = viaImport.id;\n confidence = 'INFERRED';\n }\n }\n }\n\n if (!targetId) continue; // unresolved callee (builtin, external value, ...) — no noisy guess\n const callerId = closestTrackedCaller(call);\n builder.addEdge({ source: callerId, target: targetId, relation: 'calls', confidence });\n }\n\n return builder.build();\n}\n","import * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport type { Node as TSNode } from 'web-tree-sitter';\nimport type { ExtractionResult } from '../types.js';\nimport {\n ExtractionBuilder,\n descendantsOfType,\n entityId,\n externalId,\n lineOf,\n namedChildren,\n resolveModuleRef,\n toPosix,\n} from './common.js';\nimport { createParser } from './wasmLoader.js';\n\nfunction grammarForExtension(ext: string): 'typescript' | 'tsx' | 'javascript' {\n const lower = ext.toLowerCase();\n if (lower === '.tsx') return 'tsx';\n if (lower === '.jsx') return 'javascript';\n if (lower === '.ts' || lower === '.mts' || lower === '.cts') return 'typescript';\n return 'javascript'; // .js / .mjs / .cjs\n}\n\n/** Strip the surrounding quotes tree-sitter keeps on a `string` node's text. */\nfunction stripQuotes(text: string): string {\n if (text.length >= 2) {\n const first = text[0];\n const last = text[text.length - 1];\n if ((first === '\"' || first === \"'\" || first === '`') && first === last) {\n return text.slice(1, -1);\n }\n }\n return text;\n}\n\n/** The sole string-literal argument of a call, if that's exactly what it has (used for `require('x')` / `import('x')`). */\nfunction firstStringArgument(call: TSNode): string | null {\n const args = call.childForFieldName('arguments');\n if (!args) return null;\n const first = namedChildren(args)[0];\n if (!first || first.type !== 'string') return null;\n return stripQuotes(first.text);\n}\n\n/**\n * Structural extraction for .ts/.tsx/.js/.jsx via web-tree-sitter (WASM,\n * no native compilation, no eval/exec of source content).\n *\n * Pattern: parse -> walk the AST for top-level functions/classes/\n * interfaces/const-bound functions/imports/re-exports (pass 1) -> walk all\n * `call_expression`s and resolve each callee against what pass 1 saw\n * (pass 2). A same-file callee is EXTRACTED; a callee that resolves only\n * through an imported local binding (e.g. calling a function you imported,\n * or a member on a namespace import) is emitted as INFERRED — this is the\n * \"cross-file second pass\" placeholder described in the master prompt §3.\n * It intentionally does not open and parse the imported file to confirm\n * the target; a real multi-file resolver is future work (see\n * ARCHITECTURE.md). An unresolvable callee (a builtin, a call on some\n * arbitrary local value, etc.) produces no edge at all rather than a noisy\n * guess.\n */\nexport async function extractTypeScript(filePath: string, displayPath?: string): Promise<ExtractionResult> {\n const ext = path.extname(filePath);\n const grammar = grammarForExtension(ext);\n const parser = await createParser(grammar);\n\n const raw = await fs.readFile(filePath);\n const content = raw.toString('utf-8'); // replacement-decoded — never throws on invalid bytes\n\n const tree = parser.parse(content);\n if (!tree) {\n throw new Error(`extractTypeScript: parser produced no tree for ${filePath}`);\n }\n const root = tree.rootNode;\n\n const sourceFile = toPosix(displayPath ?? filePath);\n const builder = new ExtractionBuilder();\n const fileId = sourceFile;\n builder.addNode({ id: fileId, label: sourceFile, sourceFile, sourceLocation: 'L1' });\n\n /** Declared name (function/class/interface/top-level const) -> our graph id. */\n const nameIndex = new Map<string, string>();\n /** tree-sitter node id -> our graph id, for every function-like entity we track. */\n const functionNodeMap = new Map<number, string>();\n /** tree-sitter class_declaration node id -> method name -> our graph id. */\n const classMethods = new Map<number, Map<string, string>>();\n /** tree-sitter method_definition node id -> its enclosing class's node id. */\n const enclosingClassOf = new Map<number, number>();\n\n interface ImportBinding {\n ref: ReturnType<typeof resolveModuleRef>;\n /** The name as declared in the *source* module — undefined for namespace/default/require-whole\n * bindings, where the local name tells us nothing about what the target file actually calls it. */\n importedName?: string;\n kind: 'named' | 'namespace' | 'default';\n }\n /** local binding name (import, or CommonJS require()) -> where it came from. */\n const importIndex = new Map<string, ImportBinding>();\n\n function addModuleNode(ref: ReturnType<typeof resolveModuleRef>): void {\n if (builder.hasNode(ref.id)) return;\n builder.addNode({\n id: ref.id,\n label: ref.label,\n sourceFile: ref.external ? '<external>' : ref.id,\n sourceLocation: 'L1',\n });\n }\n\n /**\n * Resolve an import/require binding to the most specific target id we can\n * reasonably guess without opening the target file: a named import points\n * at the source module's *own* entityId for the name it was declared\n * under there (not the local alias here) — the same deterministic id\n * scheme means this will actually line up with the real node once that\n * file is extracted too. A namespace/require-whole binding used via\n * member access (`ns.foo()`) does the same with the accessed property\n * name. External packages get the same entity-level guess\n * (`module:pkg::name`): the cross-file resolution pass grounds it when\n * the package is the repo's own published name (tests importing the\n * public entry) and collapses it back to the plain module node otherwise,\n * so truly-external imports end up exactly where they did before.\n * Anything else (default import, bare namespace call) falls back to the\n * module node itself.\n */\n function importTargetId(binding: ImportBinding, property?: string): string {\n if (binding.kind === 'named' && binding.importedName) {\n return entityId(binding.ref.id, binding.importedName);\n }\n if (binding.kind === 'namespace' && property) {\n return entityId(binding.ref.id, property);\n }\n return binding.ref.id;\n }\n\n function resolveHeritageTarget(name: string): string {\n const resolved = nameIndex.get(name);\n if (resolved) return resolved;\n const extId = externalId(name);\n if (!builder.hasNode(extId)) {\n builder.addNode({ id: extId, label: name, sourceFile: '<external>', sourceLocation: 'L0' });\n }\n return extId;\n }\n\n function handleFunctionDeclaration(node: TSNode): void {\n const name = node.childForFieldName('name')?.text ?? '(anonymous)';\n const id = entityId(sourceFile, name);\n builder.addNode({ id, label: `function ${name}`, sourceFile, sourceLocation: lineOf(node) });\n builder.addEdge({ source: fileId, target: id, relation: 'contains', confidence: 'EXTRACTED' });\n nameIndex.set(name, id);\n functionNodeMap.set(node.id, id);\n }\n\n /** `const foo = require('bar')` / `const { a, b: c } = require('bar')` — register bindings only; pass 2 emits the actual `imports` edge when it walks this same call_expression. */\n function registerRequireBinding(nameNode: TSNode, ref: ReturnType<typeof resolveModuleRef>): void {\n if (nameNode.type === 'identifier') {\n importIndex.set(nameNode.text, { ref, kind: 'namespace' });\n return;\n }\n if (nameNode.type === 'object_pattern') {\n for (const prop of namedChildren(nameNode)) {\n if (prop.type === 'shorthand_property_identifier_pattern') {\n importIndex.set(prop.text, { ref, importedName: prop.text, kind: 'named' });\n } else if (prop.type === 'pair_pattern') {\n const key = prop.childForFieldName('key')?.text;\n const value = prop.childForFieldName('value')?.text;\n if (key && value) importIndex.set(value, { ref, importedName: key, kind: 'named' });\n }\n }\n }\n }\n\n /** Peel `as`/`satisfies`/`!`/parens off an initializer — `((s) => impl(s)) as CreateStore` is still a function. */\n function unwrapExpression(node: TSNode): TSNode {\n let current = node;\n while (\n current.type === 'as_expression' ||\n current.type === 'satisfies_expression' ||\n current.type === 'non_null_expression' ||\n current.type === 'parenthesized_expression'\n ) {\n const inner = namedChildren(current)[0];\n if (!inner) break;\n current = inner;\n }\n return current;\n }\n\n function handleTopLevelVariableFunctions(node: TSNode): void {\n const isExported = node.parent?.type === 'export_statement';\n\n for (const declarator of namedChildren(node)) {\n if (declarator.type !== 'variable_declarator') continue;\n const value = declarator.childForFieldName('value');\n if (!value) continue;\n const core = unwrapExpression(value);\n\n if (core.type === 'arrow_function' || core.type === 'function_expression') {\n const name = declarator.childForFieldName('name')?.text;\n if (!name) continue;\n const id = entityId(sourceFile, name);\n builder.addNode({ id, label: `function ${name}`, sourceFile, sourceLocation: lineOf(declarator) });\n builder.addEdge({ source: fileId, target: id, relation: 'contains', confidence: 'EXTRACTED' });\n nameIndex.set(name, id);\n functionNodeMap.set(core.id, id);\n continue;\n }\n\n if (core.type === 'call_expression') {\n const callee = core.childForFieldName('function');\n const specifier = callee?.type === 'identifier' && callee.text === 'require' ? firstStringArgument(core) : null;\n if (specifier) {\n const nameNode = declarator.childForFieldName('name');\n if (nameNode) {\n const ref = resolveModuleRef(sourceFile, specifier);\n addModuleNode(ref);\n registerRequireBinding(nameNode, ref);\n }\n continue;\n }\n }\n\n // Any other EXPORTED const is public API surface and needs a node —\n // `export const devtools = devtoolsImpl as unknown as Devtools` is\n // how real packages publish their entry points, and without a node\n // here, barrel re-exports and callers can never reach it.\n if (isExported) {\n const name = declarator.childForFieldName('name')?.text;\n if (!name) continue;\n const id = entityId(sourceFile, name);\n builder.addNode({ id, label: `const ${name}`, sourceFile, sourceLocation: lineOf(declarator) });\n builder.addEdge({ source: fileId, target: id, relation: 'contains', confidence: 'EXTRACTED' });\n nameIndex.set(name, id);\n if (core.type === 'identifier') {\n const aliased = nameIndex.get(core.text);\n if (aliased !== undefined && aliased !== id) {\n builder.addEdge({ source: id, target: aliased, relation: 'references', confidence: 'EXTRACTED' });\n }\n }\n }\n }\n }\n\n function handleInterfaceDeclaration(node: TSNode): void {\n const name = node.childForFieldName('name')?.text ?? '(anonymous)';\n const id = entityId(sourceFile, name);\n builder.addNode({ id, label: `interface ${name}`, sourceFile, sourceLocation: lineOf(node) });\n builder.addEdge({ source: fileId, target: id, relation: 'contains', confidence: 'EXTRACTED' });\n nameIndex.set(name, id);\n }\n\n function handleClassDeclaration(node: TSNode): void {\n const name = node.childForFieldName('name')?.text ?? '(anonymous)';\n const classId = entityId(sourceFile, name);\n builder.addNode({ id: classId, label: `class ${name}`, sourceFile, sourceLocation: lineOf(node) });\n builder.addEdge({ source: fileId, target: classId, relation: 'contains', confidence: 'EXTRACTED' });\n nameIndex.set(name, classId);\n functionNodeMap.set(node.id, classId);\n\n const heritage = namedChildren(node).find((c) => c.type === 'class_heritage');\n if (heritage) {\n for (const clause of namedChildren(heritage)) {\n if (clause.type === 'extends_clause') {\n const base = clause.childForFieldName('value')?.text;\n if (base) {\n builder.addEdge({\n source: classId,\n target: resolveHeritageTarget(base),\n relation: 'inherits',\n confidence: 'EXTRACTED',\n });\n }\n } else if (clause.type === 'implements_clause') {\n for (const iface of namedChildren(clause)) {\n builder.addEdge({\n source: classId,\n target: resolveHeritageTarget(iface.text),\n relation: 'implements',\n confidence: 'EXTRACTED',\n });\n }\n }\n }\n }\n\n const methods = new Map<string, string>();\n classMethods.set(node.id, methods);\n\n const body = node.childForFieldName('body');\n if (body) {\n for (const member of namedChildren(body)) {\n if (member.type !== 'method_definition') continue;\n const methodName = member.childForFieldName('name')?.text ?? '(anonymous)';\n const methodId = entityId(sourceFile, `${name}.${methodName}`);\n builder.addNode({\n id: methodId,\n label: `method ${name}.${methodName}`,\n sourceFile,\n sourceLocation: lineOf(member),\n });\n builder.addEdge({ source: classId, target: methodId, relation: 'method', confidence: 'EXTRACTED' });\n methods.set(methodName, methodId);\n functionNodeMap.set(member.id, methodId);\n enclosingClassOf.set(member.id, node.id);\n }\n }\n }\n\n function handleImport(node: TSNode): void {\n const sourceNode = node.childForFieldName('source');\n if (!sourceNode) return;\n const ref = resolveModuleRef(sourceFile, stripQuotes(sourceNode.text));\n addModuleNode(ref);\n\n const clause = namedChildren(node).find((c) => c.type === 'import_clause');\n if (!clause) return; // side-effect-only import, e.g. `import './setup.js'`\n\n let sawNamed = false;\n let sawWhole = false;\n\n for (const child of namedChildren(clause)) {\n if (child.type === 'named_imports') {\n sawNamed = true;\n for (const specifierNode of namedChildren(child)) {\n const importedName = specifierNode.childForFieldName('name')?.text;\n const localName = specifierNode.childForFieldName('alias')?.text ?? importedName;\n if (localName) importIndex.set(localName, { ref, importedName, kind: 'named' });\n }\n } else if (child.type === 'namespace_import') {\n sawWhole = true;\n const localName = namedChildren(child)[0]?.text;\n if (localName) importIndex.set(localName, { ref, kind: 'namespace' });\n } else if (child.type === 'identifier') {\n sawWhole = true;\n importIndex.set(child.text, { ref, kind: 'default' });\n }\n }\n\n if (sawNamed) {\n builder.addEdge({ source: fileId, target: ref.id, relation: 'imports_from', confidence: 'EXTRACTED' });\n }\n if (sawWhole) {\n builder.addEdge({ source: fileId, target: ref.id, relation: 'imports', confidence: 'EXTRACTED' });\n }\n }\n\n function handleReExport(node: TSNode): void {\n const sourceNode = node.childForFieldName('source');\n if (!sourceNode) return;\n const ref = resolveModuleRef(sourceFile, stripQuotes(sourceNode.text));\n addModuleNode(ref);\n builder.addEdge({ source: fileId, target: ref.id, relation: 're_exports', confidence: 'EXTRACTED' });\n }\n\n function unwrapExport(node: TSNode): TSNode | null {\n if (node.type !== 'export_statement') return node;\n return node.childForFieldName('declaration');\n }\n\n // Pass 1: top-level declarations (functions, classes, interfaces,\n // const-bound functions, imports, re-exports).\n for (const child of namedChildren(root)) {\n if (child.type === 'import_statement') {\n handleImport(child);\n continue;\n }\n if (child.type === 'export_statement' && child.childForFieldName('source')) {\n handleReExport(child);\n continue;\n }\n\n const effective = unwrapExport(child);\n if (!effective) continue;\n\n switch (effective.type) {\n case 'function_declaration':\n case 'generator_function_declaration':\n handleFunctionDeclaration(effective);\n break;\n case 'class_declaration':\n handleClassDeclaration(effective);\n break;\n case 'interface_declaration':\n handleInterfaceDeclaration(effective);\n break;\n case 'lexical_declaration':\n case 'variable_declaration':\n handleTopLevelVariableFunctions(effective);\n break;\n default:\n break;\n }\n }\n\n function closestTrackedCaller(node: TSNode): string {\n let current: TSNode | null = node.parent;\n while (current) {\n const tracked = functionNodeMap.get(current.id);\n if (tracked) return tracked;\n current = current.parent;\n }\n return fileId;\n }\n\n function closestEnclosingClassMethods(node: TSNode): Map<string, string> | undefined {\n let current: TSNode | null = node.parent;\n while (current) {\n if (current.type === 'method_definition') {\n const classNodeId = enclosingClassOf.get(current.id);\n if (classNodeId !== undefined) return classMethods.get(classNodeId);\n }\n current = current.parent;\n }\n return undefined;\n }\n\n // Pass 2: calls (see the function doc comment above for the\n // EXTRACTED/INFERRED policy).\n for (const call of descendantsOfType(root, ['call_expression'])) {\n const fn = call.childForFieldName('function');\n if (!fn) continue;\n\n // CommonJS `require('x')` and dynamic `import('x')` are import\n // expressions wearing a call's clothing — treat them as `imports`\n // edges (module-level, EXTRACTED) rather than `calls`, wherever in the\n // tree they occur (module scope, or lazily inside a function).\n if ((fn.type === 'identifier' && fn.text === 'require') || fn.type === 'import') {\n const specifier = firstStringArgument(call);\n if (specifier) {\n const ref = resolveModuleRef(sourceFile, specifier);\n addModuleNode(ref);\n builder.addEdge({\n source: closestTrackedCaller(call),\n target: ref.id,\n relation: 'imports',\n confidence: 'EXTRACTED',\n });\n continue;\n }\n }\n\n let targetId: string | null = null;\n let confidence: 'EXTRACTED' | 'INFERRED' = 'EXTRACTED';\n\n if (fn.type === 'identifier') {\n const name = fn.text;\n const sameFile = nameIndex.get(name);\n if (sameFile) {\n targetId = sameFile;\n } else {\n const binding = importIndex.get(name);\n if (binding) {\n targetId = importTargetId(binding);\n confidence = 'INFERRED';\n }\n }\n } else if (fn.type === 'member_expression') {\n const object = fn.childForFieldName('object');\n const property = fn.childForFieldName('property')?.text;\n if (object && property) {\n if (object.type === 'this') {\n const methodId = closestEnclosingClassMethods(call)?.get(property);\n if (methodId) targetId = methodId;\n } else if (object.type === 'identifier') {\n const binding = importIndex.get(object.text);\n if (binding) {\n targetId = importTargetId(binding, property);\n confidence = 'INFERRED';\n }\n }\n }\n }\n\n if (!targetId) continue; // unresolved callee (builtin, external value, ...) — no noisy guess\n const callerId = closestTrackedCaller(call);\n builder.addEdge({ source: callerId, target: targetId, relation: 'calls', confidence });\n }\n\n return builder.build();\n}\n","import Graph from 'graphology';\nimport { validateExtraction } from './schema.js';\nimport type { Confidence, ExtractionResult } from './types.js';\n\nconst CONFIDENCE_RANK: Record<Confidence, number> = { EXTRACTED: 3, INFERRED: 2, AMBIGUOUS: 1 };\n\nfunction strongerConfidence(a: Confidence, b: Confidence): Confidence {\n return CONFIDENCE_RANK[a] >= CONFIDENCE_RANK[b] ? a : b;\n}\n\nfunction ensureNode(graph: Graph, id: string): void {\n if (graph.hasNode(id)) return;\n // An edge endpoint that never appeared in any extraction's `nodes` array —\n // shouldn't happen with a well-behaved extractor, but auto-vivify a\n // minimal placeholder rather than let addEdge throw and abort the merge.\n graph.addNode(id, { label: id, sourceFile: '<unknown>', sourceLocation: 'L0' });\n}\n\n/**\n * Merge per-file extraction results into one graphology graph.\n *\n * Every extraction is validated against the ExtractionResult schema before\n * anything is added to the graph — a single malformed extraction throws\n * (via validateExtraction()/ExtractionValidationError) before any node from\n * *any* extraction is merged, so a bad extractor can never silently\n * corrupt a graph that also contains good data.\n *\n * Nodes and edges are sorted before being added so the resulting graph (and\n * the graph.json ultimately exported from it) is deterministic regardless\n * of the order files were extracted in. Duplicate edges — same\n * source/target/relation, e.g. two different call sites resolving to the\n * same callee — are merged into a single edge, keeping the strongest\n * confidence seen (EXTRACTED > INFERRED > AMBIGUOUS) rather than being\n * counted as parallel edges (the schema has no call-count/weight field, so\n * \"A calls B\" is either true or it isn't). Multiple distinct relations\n * between the same pair (e.g. a file both `imports` and `imports_from` the\n * same module) are kept as separate edges.\n */\nexport function buildGraph(extractions: ExtractionResult[]): Graph {\n const graph = new Graph({ type: 'directed', multi: true, allowSelfLoops: true });\n\n const validated = extractions.map((extraction, index) =>\n validateExtraction(extraction, `extraction #${index}`),\n );\n\n const allNodes = validated.flatMap((extraction) => extraction.nodes);\n const allEdges = validated.flatMap((extraction) => extraction.edges);\n\n const sortedNodes = [...allNodes].sort((a, b) => a.id.localeCompare(b.id));\n for (const node of sortedNodes) {\n if (graph.hasNode(node.id)) continue;\n graph.addNode(node.id, {\n label: node.label,\n sourceFile: node.sourceFile,\n sourceLocation: node.sourceLocation,\n });\n }\n\n const sortedEdges = [...allEdges].sort(\n (a, b) =>\n a.source.localeCompare(b.source) ||\n a.target.localeCompare(b.target) ||\n a.relation.localeCompare(b.relation),\n );\n\n for (const edge of sortedEdges) {\n ensureNode(graph, edge.source);\n ensureNode(graph, edge.target);\n\n const key = `${edge.source}|${edge.relation}|${edge.target}`;\n if (graph.hasEdge(key)) {\n const existing = graph.getEdgeAttribute(key, 'confidence') as Confidence;\n graph.setEdgeAttribute(key, 'confidence', strongerConfidence(existing, edge.confidence));\n continue;\n }\n graph.addEdgeWithKey(key, edge.source, edge.target, {\n relation: edge.relation,\n confidence: edge.confidence,\n });\n }\n\n return graph;\n}\n","import { z } from 'zod';\nimport type { ExtractionResult } from './types.js';\n\n/**\n * Runtime schema for ExtractionResult (see types.ts + master prompt §2).\n * Every extractor's output is validated against this before buildGraph()\n * merges it — a malformed extractor must fail loudly, never silently\n * corrupt the graph.\n */\nexport const ConfidenceSchema = z.enum(['EXTRACTED', 'INFERRED', 'AMBIGUOUS']);\n\nexport const RelationSchema = z.enum([\n 'calls',\n 'imports',\n 'imports_from',\n 'inherits',\n 'implements',\n 'mixes_in',\n 'embeds',\n 'references',\n 'contains',\n 'method',\n 're_exports',\n]);\n\nexport const GraphNodeSchema = z.object({\n id: z.string().min(1, 'node id must be non-empty'),\n label: z.string(),\n sourceFile: z.string(),\n sourceLocation: z.string(),\n});\n\nexport const GraphEdgeSchema = z.object({\n source: z.string().min(1, 'edge source must be non-empty'),\n target: z.string().min(1, 'edge target must be non-empty'),\n relation: RelationSchema,\n confidence: ConfidenceSchema,\n});\n\nexport const ExtractionResultSchema = z.object({\n nodes: z.array(GraphNodeSchema),\n edges: z.array(GraphEdgeSchema),\n});\n\nexport interface ExtractionValidationIssue {\n path: Array<string | number>;\n message: string;\n}\n\n/** Thrown by validateExtraction() on schema mismatch. Carries the raw zod issues. */\nexport class ExtractionValidationError extends Error {\n readonly issues: ExtractionValidationIssue[];\n\n constructor(message: string, issues: ExtractionValidationIssue[]) {\n super(message);\n this.name = 'ExtractionValidationError';\n this.issues = issues;\n }\n}\n\n/**\n * Validate an unknown value (typically an extractor's return value) against\n * the ExtractionResult schema. Throws ExtractionValidationError with a clear,\n * human-readable message on mismatch instead of letting malformed data reach\n * buildGraph().\n */\nexport function validateExtraction(value: unknown, context?: string): ExtractionResult {\n const result = ExtractionResultSchema.safeParse(value);\n if (!result.success) {\n const label = context ? ` (${context})` : '';\n const issues: ExtractionValidationIssue[] = result.error.issues.map((issue) => ({\n path: issue.path as Array<string | number>,\n message: issue.message,\n }));\n const details = issues\n .map((issue) => `${issue.path.join('.') || '<root>'}: ${issue.message}`)\n .join('; ');\n throw new ExtractionValidationError(`Invalid ExtractionResult${label}: ${details}`, issues);\n }\n return result.data;\n}\n","import * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport type { ExtractionResult } from './types.js';\n\n/**\n * Cross-file reference resolution — the pass the per-file extractors can't\n * do alone. An extractor guesses an import target's id from the specifier\n * text (`import { scoreNodes } from './query.js'` → `src/query.js::scoreNodes`)\n * without opening the target file, so in a TypeScript repo the guess carries\n * the wrong extension (`.js` vs the real `src/query.ts`), and extensionless\n * or directory imports (`'./utils'` → `src/utils`) miss entirely. Once every\n * file is extracted we know the full set of real node ids, so guessed ids\n * that don't exist can be re-pointed at the single real node they were\n * clearly aiming for — turning phantom auto-vivified endpoints into edges\n * that reach the actual definition (this is what makes `graphify affected`\n * see cross-file callers).\n *\n * Three progressively-later phases, because each needs the previous one's\n * grounding:\n * 1. path guesses — extension/index variants of relative imports;\n * 2. re-export alias maps — built from the (now-grounded) `re_exports`\n * edges of barrel files;\n * 3. barrel-aware names — `module:<own-pkg>/sub::name` (tests importing\n * the published entry) and `<barrel>::name` follow the alias map to\n * the defining module, so a call through a barrel reaches the real\n * definition, not the barrel. Truly-external `module:pkg::name`\n * guesses collapse back to the plain `module:pkg` node.\n *\n * Deliberately conservative: a guess is only re-pointed when exactly ONE\n * real candidate matches; anything ambiguous or unknown is left alone\n * (buildGraph auto-vivifies it as before). Edge confidence is untouched —\n * the call target is still inferred, it just lands on a real node now.\n */\n\nconst CODE_EXTENSIONS = [\n '.ts', '.tsx', '.mts', '.cts',\n '.js', '.jsx', '.mjs', '.cjs',\n '.py', '.go', '.rs', '.java', '.cs', '.rb',\n];\n\n/** Ids that name things outside the extracted file set — never remap candidates. */\nfunction isOpaque(id: string): boolean {\n return id.startsWith('module:') || id.startsWith('external:') || id.startsWith('db:');\n}\n\nexport interface ResolveOptions {\n /**\n * The scanned package's own name(s) (from package.json). Tests very\n * commonly import the package's PUBLIC entry (`import { persist } from\n * 'zustand/middleware'`) rather than a relative path — without this,\n * those land on an opaque `module:` node and the test never connects to\n * the source it exercises (so `graphify tests` under-selects).\n */\n selfNames?: string[];\n}\n\n/** Where a self-import's subpath usually lives in the source tree. */\nconst SELF_IMPORT_STEMS = (subpath: string): string[] =>\n subpath === ''\n ? ['index', 'src/index', 'lib/index', 'source/index', 'src/main']\n : [\n subpath,\n `src/${subpath}`,\n `lib/${subpath}`,\n `source/${subpath}`,\n `${subpath}/index`,\n `src/${subpath}/index`,\n `lib/${subpath}/index`,\n ];\n\n/** Candidate real files for `module:<selfName>[/subpath]`. */\nfunction selfImportCandidates(spec: string, selfNames: string[]): string[] | null {\n const selfName = selfNames.find((n) => spec === n || spec.startsWith(`${n}/`));\n if (selfName === undefined) return null;\n const subpath = spec === selfName ? '' : spec.slice(selfName.length + 1);\n return SELF_IMPORT_STEMS(subpath).flatMap((stem) => CODE_EXTENSIONS.map((ext) => `${stem}${ext}`));\n}\n\n/** The scanned root's own package name(s), for ResolveOptions.selfNames. Missing/invalid package.json -> []. */\nexport async function readSelfNames(root: string): Promise<string[]> {\n try {\n const pkg = JSON.parse(await fs.readFile(path.join(root, 'package.json'), 'utf-8')) as { name?: unknown };\n return typeof pkg.name === 'string' && pkg.name.length > 0 ? [pkg.name] : [];\n } catch {\n return [];\n }\n}\n\nfunction stripKnownExtension(p: string): string | null {\n for (const ext of CODE_EXTENSIONS) {\n if (p.endsWith(ext)) return p.slice(0, -ext.length);\n }\n return null;\n}\n\n/** All the real file paths a guessed path could have meant: other extensions on the same stem, or the directory's index file. */\nfunction candidatePaths(guessed: string): string[] {\n const stem = stripKnownExtension(guessed) ?? guessed;\n const candidates: string[] = [];\n for (const ext of CODE_EXTENSIONS) candidates.push(`${stem}${ext}`);\n for (const ext of CODE_EXTENSIONS) candidates.push(`${guessed}/index${ext}`);\n if (stem !== guessed) {\n for (const ext of CODE_EXTENSIONS) candidates.push(`${stem}/index${ext}`);\n }\n return candidates.filter((c) => c !== guessed);\n}\n\n/** The unique member of `candidates` present in `real`, or null when none/ambiguous. */\nfunction uniqueMatch(candidates: string[], real: ReadonlySet<string>): string | null {\n const matches = new Set<string>();\n for (const candidate of candidates) {\n if (real.has(candidate)) matches.add(candidate);\n }\n return matches.size === 1 ? ([...matches][0] as string) : null;\n}\n\nexport interface ResolveStats {\n /** Edge endpoints re-pointed from a guessed id to a real node id. */\n resolvedEndpoints: number;\n /** Placeholder module nodes dropped because the real file node replaced them. */\n droppedPlaceholders: number;\n}\n\n/**\n * Mutates `extractions` in place: re-points guessed edge endpoints at real\n * node ids and drops the placeholder module nodes those guesses created.\n */\nexport function resolveCrossFileReferences(\n extractions: ExtractionResult[],\n options: ResolveOptions = {},\n): ResolveStats {\n const selfNames = options.selfNames ?? [];\n\n const realIds = new Set<string>();\n const realFiles = new Set<string>();\n for (const extraction of extractions) {\n for (const node of extraction.nodes) realIds.add(node.id);\n // Every extractor seeds its own file node FIRST (id === sourceFile) —\n // the only reliable signal for pure re-export barrels, which have no\n // entities or contains edges but are exactly what self-imports like\n // 'zustand/middleware' point at.\n const first = extraction.nodes[0];\n if (first && first.id === first.sourceFile && !isOpaque(first.id)) {\n realFiles.add(first.id);\n }\n for (const node of extraction.nodes) {\n const sep = node.id.indexOf('::');\n if (sep > 0) realFiles.add(node.id.slice(0, sep));\n }\n for (const edge of extraction.edges) {\n if (edge.relation === 'contains') realFiles.add(edge.source);\n }\n }\n\n const remap = new Map<string, string>();\n let resolvedEndpoints = 0;\n\n const applyRemap = (resolveId: (id: string) => string | null): void => {\n for (const extraction of extractions) {\n for (const edge of extraction.edges) {\n const source = resolveId(edge.source);\n if (source !== null) {\n edge.source = source;\n resolvedEndpoints++;\n }\n const target = resolveId(edge.target);\n if (target !== null) {\n edge.target = target;\n resolvedEndpoints++;\n }\n }\n }\n };\n\n // ---- Phase 1: path guesses (relative imports, wrong extension / index) ----\n const resolvePathId = (id: string): string | null => {\n if (isOpaque(id)) return null;\n const cached = remap.get(id);\n if (cached !== undefined) return cached;\n\n const sep = id.indexOf('::');\n let resolved: string | null;\n if (sep > 0) {\n // Guessed entity: only ever a phantom (extractors never create nodes\n // for these), so an existing id needs no fixing.\n if (realIds.has(id)) return null;\n const guessedPath = id.slice(0, sep);\n const name = id.slice(sep);\n resolved = uniqueMatch(candidatePaths(guessedPath).map((p) => `${p}${name}`), realIds);\n } else {\n // Guessed module/file: the extractor DID add a placeholder node for\n // it, so it is in realIds — what matters is whether it's a really\n // extracted file. Check against realFiles, and remap only onto real\n // files so a file reference never lands on some non-file node.\n if (realFiles.has(id)) return null;\n resolved = uniqueMatch(candidatePaths(id), realFiles);\n }\n if (resolved !== null) remap.set(id, resolved);\n return resolved;\n };\n applyRemap(resolvePathId);\n\n // ---- Phase 2: re-export alias maps from the now-grounded barrel edges ----\n /** `<barrelFile>|<name>` -> the real entity that name re-exports. */\n const namedAlias = new Map<string, string>();\n /** barrelFile -> files it star-re-exports (`export * from './x'`). */\n const starTargets = new Map<string, string[]>();\n for (const extraction of extractions) {\n for (const edge of extraction.edges) {\n if (edge.relation !== 're_exports' || !realFiles.has(edge.source)) continue;\n const sep = edge.target.lastIndexOf('::');\n if (sep > 0 && realIds.has(edge.target)) {\n namedAlias.set(`${edge.source}|${edge.target.slice(sep + 2)}`, edge.target);\n } else if (sep < 0 && realFiles.has(edge.target)) {\n const targets = starTargets.get(edge.source) ?? [];\n targets.push(edge.target);\n starTargets.set(edge.source, targets);\n }\n }\n }\n\n /** Follow `name` through a barrel file: direct definition, named re-export, or star re-export. */\n const throughBarrel = (file: string, name: string): string | null => {\n const direct = `${file}::${name}`;\n if (realIds.has(direct)) return direct;\n const aliased = namedAlias.get(`${file}|${name}`);\n if (aliased !== undefined) return aliased;\n const viaStar = (starTargets.get(file) ?? [])\n .map((sf) => `${sf}::${name}`)\n .filter((id) => realIds.has(id));\n return viaStar.length === 1 ? (viaStar[0] as string) : null;\n };\n\n // ---- Phase 3: barrel-aware names ----\n const resolveBarrelId = (id: string): string | null => {\n const cached = remap.get(id);\n if (cached !== undefined) return cached;\n\n if (id.startsWith('module:')) {\n const spec = id.slice('module:'.length);\n const sep = spec.indexOf('::');\n const moduleSpec = sep > 0 ? spec.slice(0, sep) : spec;\n const name = sep > 0 ? spec.slice(sep + 2) : null;\n\n const candidates = selfImportCandidates(moduleSpec, selfNames);\n if (candidates === null) {\n // Truly external. Entity-level guesses (`module:react::useState`)\n // collapse back to the plain module node so external imports look\n // exactly like they always did; plain module ids stay opaque.\n if (name === null) return null;\n remap.set(id, `module:${moduleSpec}`);\n return `module:${moduleSpec}`;\n }\n\n const file = uniqueMatch(candidates, realFiles);\n let resolved: string | null = null;\n if (file !== null) {\n resolved = name !== null ? (throughBarrel(file, name) ?? file) : file;\n } else if (name !== null) {\n // Can't place the file — at least collapse the phantom entity.\n resolved = `module:${moduleSpec}`;\n }\n if (resolved !== null) remap.set(id, resolved);\n return resolved;\n }\n\n // Relative-path guess that phase 1 couldn't ground: the name may live\n // behind a barrel (`src/index.ts::queryGraph` -> the re-exported def).\n const sep = id.indexOf('::');\n if (sep > 0 && !realIds.has(id)) {\n const guessedPath = id.slice(0, sep);\n const name = id.slice(sep + 2);\n const files = [guessedPath, ...candidatePaths(guessedPath)].filter((f) => realFiles.has(f));\n const resolvedSet = new Set(files.map((f) => throughBarrel(f, name)).filter((r): r is string => r !== null));\n if (resolvedSet.size === 1) {\n const resolved = [...resolvedSet][0] as string;\n remap.set(id, resolved);\n return resolved;\n }\n }\n return null;\n };\n applyRemap(resolveBarrelId);\n\n // Placeholder module nodes (added by extractors for guessed same-repo\n // imports) whose id was remapped now duplicate the real file node — drop\n // them so they don't linger as isolated near-duplicates.\n let droppedPlaceholders = 0;\n for (const extraction of extractions) {\n const before = extraction.nodes.length;\n extraction.nodes = extraction.nodes.filter((node) => !remap.has(node.id));\n droppedPlaceholders += before - extraction.nodes.length;\n }\n\n return { resolvedEndpoints, droppedPlaceholders };\n}\n","import { createHash } from 'node:crypto';\nimport Graph from 'graphology';\n// A pure-JS, graphology-native Leiden implementation — extracted from the\n// upstream graphology monorepo's own (never separately published)\n// src/communities-leiden, repackaged with an optional `maxIterations` cap.\n// No native compilation (no .node bindings) — same \"no native\n// compilation\" constraint as the rest of this package. See v2 notes below.\nimport leiden from '@aflsolutions/graphology-communities-leiden';\nimport louvain from 'graphology-communities-louvain';\n\n/** Fixed seed so repeated runs on the same graph explore ties identically. */\nconst FIXED_SEED = 0x5eed_1234;\n\n/** mulberry32 — small, dependency-free, deterministic PRNG. */\nfunction mulberry32(seed: number): () => number {\n let a = seed >>> 0;\n return function next(): number {\n a = (a + 0x6d2b79f5) | 0;\n let t = Math.imul(a ^ (a >>> 15), 1 | a);\n t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n };\n}\n\ninterface EdgeEntry {\n key: string;\n source: string;\n target: string;\n attributes: Record<string, unknown>;\n}\n\n/**\n * Build a copy of `graph` with nodes and edges (re-)inserted in sorted\n * order, so the clustering algorithm's own internal iteration — and\n * therefore its tie-breaking — is fed a canonical order regardless of how\n * the input graph happened to be constructed (master prompt §4: \"sort\n * nodes/edges before feeding the algorithm\").\n */\nfunction sortedWorkingCopy(graph: Graph): Graph {\n const copy = new Graph({ type: graph.type, multi: graph.multi, allowSelfLoops: graph.allowSelfLoops });\n\n const nodeIds = graph.nodes().sort((a, b) => a.localeCompare(b));\n for (const id of nodeIds) {\n copy.addNode(id, { ...graph.getNodeAttributes(id) });\n }\n\n const edgeEntries: EdgeEntry[] = [];\n graph.forEachEdge((edge, attributes, source, target) => {\n edgeEntries.push({ key: edge, source, target, attributes });\n });\n edgeEntries.sort(\n (a, b) =>\n a.source.localeCompare(b.source) ||\n a.target.localeCompare(b.target) ||\n String(a.attributes.relation).localeCompare(String(b.attributes.relation)),\n );\n for (const entry of edgeEntries) {\n copy.addEdgeWithKey(entry.key, entry.source, entry.target, { ...entry.attributes });\n }\n\n return copy;\n}\n\nexport type ClusterAlgorithm = 'louvain' | 'leiden';\n\nexport interface ClusterOptions {\n /**\n * `louvain` (default, v1 behavior, unchanged) or `leiden` (v2: better\n * community quality / guaranteed well-connectedness, via\n * `@aflsolutions/graphology-communities-leiden` — see master prompt's\n * v2 upgrade ideas, \"Real Leiden clustering\"). Both run deterministically\n * against a sorted working copy with the same fixed-seed PRNG.\n */\n algorithm?: ClusterAlgorithm;\n /**\n * Leiden-only: hard cap on outer iterations, for very large graphs where\n * full convergence is expensive and the last iterations buy little\n * additional modularity. Ignored for `algorithm: 'louvain'`.\n */\n maxIterations?: number;\n}\n\n/**\n * @aflsolutions/graphology-communities-leiden (like upstream graphology's\n * own Leiden) only implements the undirected case — it throws on a graph\n * whose edges are all directed. Community detection is inherently an\n * undirected-connectivity notion anyway (classic Louvain/Leiden\n * modularity is defined over undirected graphs), so we run Leiden against\n * an undirected copy and copy the resulting `community` assignment back\n * onto `working` by node id.\n */\nfunction toUndirectedCopy(graph: Graph): Graph {\n const copy = new Graph({ type: 'undirected', multi: true, allowSelfLoops: graph.allowSelfLoops });\n graph.forEachNode((nodeId, attributes) => copy.addNode(nodeId, { ...attributes }));\n graph.forEachEdge((edgeKey, attributes, source, target) => {\n copy.addEdgeWithKey(edgeKey, source, target, { ...attributes });\n });\n return copy;\n}\n\nfunction runAlgorithm(working: Graph, options: ClusterOptions): void {\n const rng = mulberry32(FIXED_SEED);\n if (options.algorithm === 'leiden') {\n const undirected = toUndirectedCopy(working);\n leiden.assign(undirected, { rng, maxIterations: options.maxIterations ?? 0 });\n undirected.forEachNode((nodeId, attributes) => {\n working.setNodeAttribute(nodeId, 'community', attributes.community);\n });\n return;\n }\n louvain.assign(working, { rng });\n}\n\n/**\n * Community detection — Louvain by default (v1, unchanged), or Leiden\n * (v2, `{ algorithm: 'leiden' }`) for better-quality, guaranteed\n * well-connected communities on the same graph. Deterministic: runs\n * against a sorted working copy with a fixed RNG seed, then copies the\n * resulting `community` assignment back onto the original graph by node id\n * (so `cluster()` still mutates and returns the graph instance it was\n * given). Labels each community after its highest-degree (\"hub\") member;\n * no LLM required for a usable baseline. Also stamps a `communityHash`\n * (sha256 of the community's sorted member ids) so `--cluster-only` can\n * tell which communities actually changed vs. merely being relabeled with\n * a different arbitrary index next run.\n */\nexport function cluster(graph: Graph, options: ClusterOptions = {}): Graph {\n if (graph.order === 0) return graph;\n\n const working = sortedWorkingCopy(graph);\n runAlgorithm(working, options);\n\n // Highest-degree member per community, computed on the sorted copy so\n // ties break on node id deterministically.\n const hubs = new Map<number, { id: string; degree: number }>();\n working.forEachNode((nodeId) => {\n const community = working.getNodeAttribute(nodeId, 'community') as number;\n const degree = working.degree(nodeId);\n const current = hubs.get(community);\n if (!current || degree > current.degree) {\n hubs.set(community, { id: nodeId, degree });\n }\n });\n\n const membersByCommunity = new Map<number, string[]>();\n working.forEachNode((nodeId) => {\n const community = working.getNodeAttribute(nodeId, 'community') as number;\n const list = membersByCommunity.get(community);\n if (list) list.push(nodeId);\n else membersByCommunity.set(community, [nodeId]);\n });\n\n const labelByCommunity = new Map<number, string>();\n const hashByCommunity = new Map<number, string>();\n for (const [community, members] of membersByCommunity) {\n members.sort((a, b) => a.localeCompare(b));\n hashByCommunity.set(community, createHash('sha256').update(members.join('\\n')).digest('hex'));\n\n const hub = hubs.get(community);\n const hubLabel = hub ? (working.getNodeAttribute(hub.id, 'label') as string) : undefined;\n labelByCommunity.set(community, hubLabel && hubLabel.length > 0 ? hubLabel : `community-${community}`);\n }\n\n working.forEachNode((nodeId) => {\n const community = working.getNodeAttribute(nodeId, 'community') as number;\n graph.mergeNodeAttributes(nodeId, {\n community,\n communityLabel: labelByCommunity.get(community),\n communityHash: hashByCommunity.get(community),\n });\n });\n\n return graph;\n}\n","import type Graph from 'graphology';\nimport type { Analysis, Confidence } from './types.js';\n\n/** A node needs at least this many total connections to ever be a \"god node\", regardless of graph size. */\nconst ABSOLUTE_DEGREE_FLOOR = 10;\n/** ...and needs to be at least this many times the graph's mean degree. */\nconst MEAN_DEGREE_MULTIPLIER = 3;\n/** Cap how many items of a given kind get spelled out in a single message. */\nconst MAX_LISTED = 10;\n\nfunction truncatedList(items: string[]): string {\n const shown = items.slice(0, MAX_LISTED).join(', ');\n return items.length > MAX_LISTED ? `${shown}, ...` : shown;\n}\n\n/** Connected components treating the (directed) graph as undirected — reachability via any edge direction. */\nfunction connectedComponents(graph: Graph): string[][] {\n const visited = new Set<string>();\n const components: string[][] = [];\n const sortedNodes = [...graph.nodes()].sort((a, b) => a.localeCompare(b));\n\n for (const start of sortedNodes) {\n if (visited.has(start)) continue;\n const component: string[] = [];\n const queue: string[] = [start];\n visited.add(start);\n\n while (queue.length > 0) {\n const current = queue.shift() as string;\n component.push(current);\n const neighbors = [...graph.neighbors(current)].sort((a, b) => a.localeCompare(b));\n for (const neighbor of neighbors) {\n if (!visited.has(neighbor)) {\n visited.add(neighbor);\n queue.push(neighbor);\n }\n }\n }\n\n component.sort((a, b) => a.localeCompare(b));\n components.push(component);\n }\n\n components.sort((a, b) => b.length - a.length || (a[0] ?? '').localeCompare(b[0] ?? ''));\n return components;\n}\n\nfunction labelOf(graph: Graph, id: string): string {\n return (graph.getNodeAttribute(id, 'label') as string | undefined) ?? id;\n}\n\n/**\n * Surface god-nodes (excessive fan-in/out), structural surprises (self\n * references, AMBIGUOUS edges), and open questions (isolated nodes,\n * disconnected components) for a human to review in GRAPH_REPORT.md.\n */\nexport function analyze(graph: Graph): Analysis {\n const godNodes: string[] = [];\n const surprises: string[] = [];\n const openQuestions: string[] = [];\n\n if (graph.order === 0) {\n openQuestions.push(\n 'The graph is empty — no nodes were extracted. Check detect()/extract() coverage for this codebase.',\n );\n return { godNodes, surprises, openQuestions };\n }\n\n const degreeEntries = [...graph.nodes()]\n .map((id) => ({ id, degree: graph.degree(id) }))\n .sort((a, b) => a.id.localeCompare(b.id));\n const meanDegree = degreeEntries.reduce((sum, e) => sum + e.degree, 0) / degreeEntries.length;\n const threshold = Math.max(ABSOLUTE_DEGREE_FLOOR, meanDegree * MEAN_DEGREE_MULTIPLIER);\n\n for (const { id, degree } of degreeEntries) {\n if (degree > 0 && degree >= threshold) {\n godNodes.push(id);\n surprises.push(\n `${labelOf(graph, id)} has ${degree} connections (fan-in + fan-out) — well above the graph ` +\n `average of ${meanDegree.toFixed(1)}. Likely a god node / hotspot worth reviewing for ` +\n 'excessive coupling.',\n );\n }\n }\n\n graph.forEachEdge((_edge, attributes, source, target) => {\n if (source === target) {\n surprises.push(`${labelOf(graph, source)} has a self-referential \"${String(attributes.relation)}\" edge.`);\n }\n });\n\n const ambiguousEdges: string[] = [];\n graph.forEachEdge((_edge, attributes, source, target) => {\n if ((attributes.confidence as Confidence) === 'AMBIGUOUS') {\n ambiguousEdges.push(\n `${labelOf(graph, source)} --${String(attributes.relation)}--> ${labelOf(graph, target)}`,\n );\n }\n });\n if (ambiguousEdges.length > 0) {\n ambiguousEdges.sort((a, b) => a.localeCompare(b));\n openQuestions.push(\n `${ambiguousEdges.length} edge(s) are marked AMBIGUOUS and need human review: ` +\n truncatedList(ambiguousEdges),\n );\n }\n\n const isolated = degreeEntries.filter((e) => e.degree === 0).map((e) => e.id);\n if (isolated.length > 0) {\n openQuestions.push(\n `${isolated.length} node(s) have no incoming or outgoing edges (${truncatedList(isolated)}) — ` +\n 'dead code, an entry point, or a gap in extraction?',\n );\n }\n\n const components = connectedComponents(graph);\n if (components.length > 1) {\n const largest = components[0] as string[];\n openQuestions.push(\n `The graph has ${components.length} disconnected components — the largest has ${largest.length} ` +\n 'node(s). Confirm this reflects real module boundaries rather than missed cross-file edges.',\n );\n }\n\n return { godNodes, surprises, openQuestions };\n}\n","import type Graph from 'graphology';\nimport type { Analysis } from './types.js';\n\nfunction labelOf(graph: Graph, id: string): string {\n return (graph.getNodeAttribute(id, 'label') as string | undefined) ?? id;\n}\n\nfunction bulletList(items: string[]): string {\n if (items.length === 0) return '_None found._';\n return items.map((item) => `- ${item}`).join('\\n');\n}\n\ninterface CommunitySummary {\n label: string;\n members: string[];\n}\n\nfunction summarizeCommunities(graph: Graph): CommunitySummary[] {\n const byCommunity = new Map<number, CommunitySummary>();\n graph.forEachNode((nodeId, attributes) => {\n const community = attributes.community as number | undefined;\n if (community === undefined) return;\n const label = (attributes.communityLabel as string | undefined) ?? `community-${community}`;\n const existing = byCommunity.get(community);\n if (existing) {\n existing.members.push(nodeId);\n } else {\n byCommunity.set(community, { label, members: [nodeId] });\n }\n });\n\n const summaries = [...byCommunity.values()];\n for (const summary of summaries) {\n summary.members.sort((a, b) => a.localeCompare(b));\n }\n summaries.sort((a, b) => b.members.length - a.members.length || a.label.localeCompare(b.label));\n return summaries;\n}\n\n/**\n * Render the plain-language GRAPH_REPORT.md content: a short summary,\n * community breakdown, god nodes, structural surprises, and open\n * questions — everything a human (or an agent) needs to sanity-check a\n * freshly built graph before trusting it.\n */\nexport function renderReport(graph: Graph, analysis: Analysis, now: Date = new Date()): string {\n const generatedAt = now.toISOString();\n const communities = summarizeCommunities(graph);\n\n const lines: string[] = [];\n lines.push('# Graph Report');\n lines.push('');\n lines.push(`Generated: ${generatedAt}`);\n lines.push('');\n lines.push('## Summary');\n lines.push('');\n lines.push(`- **Nodes:** ${graph.order}`);\n lines.push(`- **Edges:** ${graph.size}`);\n lines.push(`- **Communities:** ${communities.length}`);\n lines.push(`- **God nodes:** ${analysis.godNodes.length}`);\n lines.push('');\n\n lines.push('## Communities');\n lines.push('');\n if (communities.length === 0) {\n lines.push('_No communities detected (graph may be empty, or cluster() has not run yet)._');\n } else {\n for (const community of communities) {\n lines.push(`### ${community.label} (${community.members.length} member(s))`);\n lines.push('');\n const shown = community.members.slice(0, 25).map((id) => labelOf(graph, id));\n lines.push(bulletList(shown));\n if (community.members.length > 25) {\n lines.push(`- ...and ${community.members.length - 25} more`);\n }\n lines.push('');\n }\n }\n\n lines.push('## God Nodes');\n lines.push('');\n lines.push(\n 'Nodes with unusually high fan-in + fan-out relative to the rest of this graph — often a sign of a ' +\n 'shared utility, a bottleneck, or a module that has taken on too many responsibilities.',\n );\n lines.push('');\n lines.push(bulletList(analysis.godNodes.map((id) => labelOf(graph, id))));\n lines.push('');\n\n lines.push('## Structural Surprises');\n lines.push('');\n lines.push(bulletList(analysis.surprises));\n lines.push('');\n\n lines.push('## Open Questions');\n lines.push('');\n lines.push(bulletList(analysis.openQuestions));\n lines.push('');\n\n return lines.join('\\n');\n}\n","import { createRequire } from 'node:module';\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport type Graph from 'graphology';\nimport { escapeHtml, sanitizeLabel, validateGraphPath } from './security.js';\nimport type { ExportOptions } from './types.js';\n\nconst require = createRequire(import.meta.url);\n\n/** Locate the bundled, self-contained vis-network assets (no CDN, works fully offline). */\nfunction resolveVisNetworkAssets(): { jsPath: string; cssPath: string } {\n const packageJsonPath = require.resolve('vis-network/package.json');\n const root = path.dirname(packageJsonPath);\n return {\n jsPath: path.join(root, 'standalone', 'umd', 'vis-network.min.js'),\n cssPath: path.join(root, 'styles', 'vis-network.min.css'),\n };\n}\n\n/** A small, deterministic categorical palette, cycled by community index. */\nconst COMMUNITY_PALETTE = [\n '#4e79a7',\n '#f28e2b',\n '#e15759',\n '#76b7b2',\n '#59a14f',\n '#edc948',\n '#b07aa1',\n '#ff9da7',\n '#9c755f',\n '#bab0ac',\n];\n\nfunction colorForCommunity(community: number | undefined): string {\n if (community === undefined) return '#8ab4f8';\n const index = ((community % COMMUNITY_PALETTE.length) + COMMUNITY_PALETTE.length) % COMMUNITY_PALETTE.length;\n return COMMUNITY_PALETTE[index] as string;\n}\n\n/**\n * Embedding untrusted-derived strings (node labels ultimately come from\n * source file content) inside an inline <script> tag has one extra XSS\n * vector JSON.stringify() alone doesn't cover: a literal `</script>`\n * substring in the JSON text would close our script tag early and let the\n * rest be parsed as raw HTML. Escape the forward slash so that can't happen.\n */\nfunction safeInlineJson(value: unknown): string {\n return JSON.stringify(value, null, 2).replace(/<\\/(script)/gi, '<\\\\/$1');\n}\n\nfunction buildVisNodesAndEdges(graph: Graph): { nodes: unknown[]; edges: unknown[] } {\n const nodes = graph.nodes().map((id) => {\n const attributes = graph.getNodeAttributes(id);\n const rawLabel = (attributes.label as string | undefined) ?? id;\n const label = escapeHtml(sanitizeLabel(rawLabel));\n const sourceFile = escapeHtml(sanitizeLabel((attributes.sourceFile as string | undefined) ?? ''));\n const sourceLocation = escapeHtml(sanitizeLabel((attributes.sourceLocation as string | undefined) ?? ''));\n const communityLabel = escapeHtml(sanitizeLabel((attributes.communityLabel as string | undefined) ?? ''));\n return {\n id,\n label,\n title: `${label}\\n${sourceFile}${sourceLocation ? `:${sourceLocation}` : ''}${\n communityLabel ? `\\ncommunity: ${communityLabel}` : ''\n }`,\n color: colorForCommunity(attributes.community as number | undefined),\n };\n });\n\n const edges: unknown[] = [];\n graph.forEachEdge((edgeKey, attributes, source, target) => {\n const relation = escapeHtml(sanitizeLabel(String(attributes.relation ?? '')));\n const confidence = escapeHtml(sanitizeLabel(String(attributes.confidence ?? '')));\n edges.push({\n id: edgeKey,\n from: source,\n to: target,\n label: relation,\n title: `${relation} (${confidence})`,\n dashes: confidence === 'INFERRED' || confidence === 'AMBIGUOUS',\n arrows: 'to',\n });\n });\n\n return { nodes, edges };\n}\n\nasync function renderHtml(graph: Graph): Promise<string> {\n const { jsPath, cssPath } = resolveVisNetworkAssets();\n const [visJs, visCss] = await Promise.all([\n fs.readFile(jsPath, 'utf-8'),\n fs.readFile(cssPath, 'utf-8'),\n ]);\n\n const { nodes, edges } = buildVisNodesAndEdges(graph);\n const dataJson = safeInlineJson({ nodes, edges });\n\n return `<!doctype html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<title>graphify — graph.html</title>\n<style>\n html, body { margin: 0; padding: 0; height: 100%; font-family: system-ui, sans-serif; }\n #graph { width: 100%; height: 100vh; }\n ${visCss}\n</style>\n</head>\n<body>\n<div id=\"graph\"></div>\n<script>\n${visJs}\n</script>\n<script>\n(function () {\n var data = ${dataJson};\n var nodes = new vis.DataSet(data.nodes);\n var edges = new vis.DataSet(data.edges);\n var container = document.getElementById('graph');\n var network = new vis.Network(container, { nodes: nodes, edges: edges }, {\n nodes: { shape: 'dot', size: 12, font: { size: 14 } },\n edges: { smooth: { type: 'continuous' }, font: { size: 10, align: 'middle' } },\n physics: { stabilization: true },\n interaction: { hover: true, tooltipDelay: 150 },\n });\n window.__graphifyNetwork = network;\n})();\n</script>\n</body>\n</html>\n`;\n}\n\n/**\n * Write graph.json (graphology's node-link serialization, GraphRAG-ready)\n * and, per options, graph.html (vis-network, bundled inline — no CDN, works\n * fully offline) and GRAPH_REPORT.md. Every label/title embedded in\n * graph.html is passed through security.sanitizeLabel() + escapeHtml()\n * first (XSS control, see SECURITY.md).\n *\n * Obsidian vault / .graphml / Neo4j cypher export are NOT implemented in\n * v1 — if requested, exportGraph logs a clear warning and skips them\n * rather than silently doing nothing or faking output.\n */\nexport async function exportGraph(graph: Graph, options: ExportOptions, report?: string): Promise<void> {\n const outDir = path.resolve(options.outDir);\n await fs.mkdir(outDir, { recursive: true });\n\n const jsonPath = validateGraphPath('graph.json', outDir);\n await fs.writeFile(jsonPath, JSON.stringify(graph.toJSON(), null, 2), 'utf-8');\n\n if (options.html !== false) {\n const htmlPath = validateGraphPath('graph.html', outDir);\n await fs.writeFile(htmlPath, await renderHtml(graph), 'utf-8');\n }\n\n if (report !== undefined) {\n const reportPath = validateGraphPath('GRAPH_REPORT.md', outDir);\n await fs.writeFile(reportPath, report, 'utf-8');\n }\n\n const notImplemented: string[] = [];\n if (options.svg) notImplemented.push('--svg');\n if (options.graphml) notImplemented.push('--graphml');\n if (options.neo4j) notImplemented.push('--neo4j');\n if (options.obsidian) notImplemented.push('--obsidian');\n for (const flag of notImplemented) {\n console.warn(`graphify: ${flag} export is not implemented yet in v1 — skipping.`);\n }\n}\n","/**\n * Security helpers — URL validation, SSRF-guarded fetch, path guards, label\n * sanitization, prompt-injection defenses. Every control listed in\n * SECURITY.md must have a corresponding function here and a unit test in\n * tests/security.test.ts. See the master prompt §5 for the full checklist.\n */\n\nimport { createHash } from 'node:crypto';\nimport * as dns from 'node:dns';\nimport * as http from 'node:http';\nimport * as https from 'node:https';\nimport * as fs from 'node:fs';\nimport * as net from 'node:net';\nimport * as nodePath from 'node:path';\n\nconst ALLOWED_SCHEMES = new Set(['http:', 'https:']);\nconst MAX_FETCH_BYTES = 50 * 1024 * 1024;\nconst MAX_TEXT_BYTES = 10 * 1024 * 1024;\nconst MAX_LABEL_LEN = 256;\nconst MAX_REDIRECTS = 5;\nconst REQUEST_TIMEOUT_MS = 15_000;\n\n/** Hostnames that must never be reachable, regardless of what they resolve to. */\nconst BLOCKED_HOSTNAMES = new Set([\n 'metadata.google.internal',\n 'metadata.internal',\n 'metadata',\n 'metadata.azure.com',\n 'instance-data',\n 'instance-data.ec2.internal',\n]);\n\n// ---------------------------------------------------------------------------\n// IP range checks (SSRF guard core). Implemented without extra dependencies.\n// ---------------------------------------------------------------------------\n\nfunction ipv4ToInt(ip: string): number | null {\n const parts = ip.split('.');\n if (parts.length !== 4) return null;\n let result = 0;\n for (const part of parts) {\n if (!/^\\d{1,3}$/.test(part)) return null;\n const n = Number(part);\n if (n > 255) return null;\n result = (result << 8) | n;\n }\n return result >>> 0;\n}\n\nfunction ipv4InCidr(ipInt: number, cidr: string): boolean {\n const [base, prefixStr] = cidr.split('/');\n const prefix = Number(prefixStr);\n const baseInt = ipv4ToInt(base ?? '');\n if (baseInt === null) return false;\n const mask = prefix === 0 ? 0 : (~0 << (32 - prefix)) >>> 0;\n return (ipInt & mask) >>> 0 === (baseInt & mask) >>> 0;\n}\n\n/** IPv4 ranges that must never be connected to from a server-side fetch. */\nconst BLOCKED_IPV4_CIDRS = [\n '0.0.0.0/8', // \"this\" network\n '10.0.0.0/8', // private\n '100.64.0.0/10', // carrier-grade NAT (CGN)\n '127.0.0.0/8', // loopback\n '169.254.0.0/16', // link-local (covers 169.254.169.254 cloud metadata)\n '172.16.0.0/12', // private\n '192.0.0.0/24', // IETF protocol assignments\n '192.0.2.0/24', // TEST-NET-1\n '192.168.0.0/16', // private\n '198.18.0.0/15', // benchmarking\n '198.51.100.0/24', // TEST-NET-2\n '203.0.113.0/24', // TEST-NET-3\n '224.0.0.0/4', // multicast\n '240.0.0.0/4', // reserved\n '255.255.255.255/32', // broadcast\n];\n\nexport function isForbiddenIpv4(ip: string): boolean {\n const ipInt = ipv4ToInt(ip);\n if (ipInt === null) return true; // malformed -> treat as forbidden, fail closed\n return BLOCKED_IPV4_CIDRS.some((cidr) => ipv4InCidr(ipInt, cidr));\n}\n\n/** Expand a (possibly `::`-compressed) IPv6 address into 8 16-bit groups. */\nfunction expandIpv6(ip: string): number[] | null {\n const withoutZone = ip.split('%')[0] ?? '';\n const parts = withoutZone.split('::');\n if (parts.length > 2) return null;\n\n const head = parts[0] ? parts[0].split(':').filter((s) => s.length > 0) : [];\n const tail = parts.length === 2 && parts[1] ? parts[1].split(':').filter((s) => s.length > 0) : [];\n\n let missing = 0;\n if (parts.length === 2) {\n missing = 8 - head.length - tail.length;\n if (missing < 0) return null;\n } else if (head.length + tail.length !== 8) {\n return null;\n }\n\n const groupsHex = [...head, ...Array(missing).fill('0'), ...tail];\n if (groupsHex.length !== 8) return null;\n\n const groups: number[] = [];\n for (const g of groupsHex) {\n if (!/^[0-9a-fA-F]{1,4}$/.test(g)) return null;\n groups.push(parseInt(g, 16));\n }\n return groups;\n}\n\nexport function isForbiddenIpv6(ip: string): boolean {\n const lower = ip.toLowerCase();\n if (lower === '::1' || lower === '::') return true;\n\n const mapped = /^::ffff:(\\d+\\.\\d+\\.\\d+\\.\\d+)$/.exec(lower);\n if (mapped) return isForbiddenIpv4(mapped[1] as string);\n\n const groups = expandIpv6(lower);\n if (groups === null) return true; // unparsable -> fail closed\n const first = groups[0] as number;\n if ((first & 0xffc0) === 0xfe80) return true; // fe80::/10 link-local\n if ((first & 0xfe00) === 0xfc00) return true; // fc00::/7 unique local\n if ((first & 0xff00) === 0xff00) return true; // ff00::/8 multicast\n if (groups.every((g) => g === 0)) return true; // unspecified/all-zero\n return false;\n}\n\nexport function isForbiddenIp(ip: string): boolean {\n return net.isIPv6(ip) ? isForbiddenIpv6(ip) : isForbiddenIpv4(ip);\n}\n\n// ---------------------------------------------------------------------------\n// URL validation\n// ---------------------------------------------------------------------------\n\n/**\n * Validate a URL is http/https and, when the hostname is itself a literal\n * IP or a known cloud-metadata hostname, reject it synchronously. DNS-bound\n * hostnames are re-validated at connect time by safeFetch() (see below) —\n * this function alone cannot rule out DNS rebinding for a hostname that\n * currently resolves to a public IP.\n */\nexport function validateUrl(url: string): string {\n let parsed: URL;\n try {\n parsed = new URL(url);\n } catch {\n throw new Error(`Invalid URL: ${url}`);\n }\n\n if (!ALLOWED_SCHEMES.has(parsed.protocol)) {\n throw new Error(\n `URL scheme not allowed: \"${parsed.protocol}\" (allowed: ${[...ALLOWED_SCHEMES].join(', ')})`,\n );\n }\n\n const hostname = parsed.hostname.toLowerCase();\n if (BLOCKED_HOSTNAMES.has(hostname)) {\n throw new Error(`URL targets a blocked host: ${hostname}`);\n }\n\n // WHATWG URL keeps the brackets on an IPv6 literal host (e.g. \"[::1]\") —\n // strip them before checking net.isIP()/isForbiddenIp().\n const bareHost =\n hostname.startsWith('[') && hostname.endsWith(']') ? hostname.slice(1, -1) : hostname;\n if (net.isIP(bareHost) && isForbiddenIp(bareHost)) {\n throw new Error(`URL targets a forbidden IP address: ${bareHost}`);\n }\n\n return parsed.toString();\n}\n\n// ---------------------------------------------------------------------------\n// safeFetch — SSRF-guarded, size-capped, redirect-revalidating fetch\n// ---------------------------------------------------------------------------\n\nexport type LookupFn = (hostname: string) => Promise<{ address: string; family: number }>;\n\n/**\n * Resolve a hostname (or pass through a literal IP) and validate the\n * result. `lookup` defaults to the real `dns.promises.lookup` — tests\n * substitute a fake to exercise the rebind guard deterministically without\n * making a real DNS query.\n */\nexport async function resolveAndValidate(\n hostname: string,\n lookup: LookupFn = dns.promises.lookup,\n): Promise<{ address: string; family: number }> {\n if (net.isIP(hostname)) {\n if (isForbiddenIp(hostname)) {\n throw new Error(`Refusing to connect to forbidden IP: ${hostname}`);\n }\n return { address: hostname, family: net.isIPv6(hostname) ? 6 : 4 };\n }\n const result = await lookup(hostname);\n if (isForbiddenIp(result.address)) {\n throw new Error(`Refusing to connect to forbidden IP: ${hostname} -> ${result.address}`);\n }\n return result;\n}\n\nexport interface RawResponse {\n statusCode: number;\n headers: http.IncomingHttpHeaders;\n body: Buffer;\n}\n\n/** Minimal shape of the `http`/`https` modules that requestOnce() needs — narrow on purpose so tests can substitute a fake transport instead of mocking network I/O. */\nexport type RequestTransport = Pick<typeof http, 'request'>;\n\n/**\n * Issue a single HTTP(S) request, connecting to `resolvedAddress` directly\n * (via a `lookup` override) rather than re-resolving DNS at connect time —\n * this is what prevents a DNS-rebind attacker from swapping the target\n * between validation and connection (TOCTOU). Streams the body and aborts\n * once it exceeds the byte cap for its declared content type.\n */\nexport function requestOnce(\n target: URL,\n resolvedAddress: string,\n resolvedFamily: number,\n transport: RequestTransport = target.protocol === 'https:' ? https : http,\n): Promise<RawResponse> {\n return new Promise((resolve, reject) => {\n const req = transport.request(\n {\n protocol: target.protocol,\n hostname: target.hostname,\n host: target.hostname,\n port: target.port || (target.protocol === 'https:' ? 443 : 80),\n path: `${target.pathname}${target.search}`,\n method: 'GET',\n timeout: REQUEST_TIMEOUT_MS,\n headers: { 'user-agent': 'graphify/0.1', accept: '*/*' },\n // Force the connection to the address we already validated — do not\n // let Node re-resolve `target.hostname` at connect time.\n lookup: (\n _hostname: string,\n options: unknown,\n callback: (err: NodeJS.ErrnoException | null, address: string, family: number) => void,\n ) => {\n callback(null, resolvedAddress, resolvedFamily);\n },\n } as http.RequestOptions,\n (res) => {\n const statusCode = res.statusCode ?? 0;\n const contentType = String(res.headers['content-type'] ?? '');\n const isTextual = /^text\\/|json|xml|html|charset=/i.test(contentType);\n const cap = isTextual ? MAX_TEXT_BYTES : MAX_FETCH_BYTES;\n\n const chunks: Buffer[] = [];\n let total = 0;\n let aborted = false;\n\n res.on('data', (chunk: Buffer) => {\n total += chunk.length;\n if (total > cap) {\n aborted = true;\n res.destroy();\n req.destroy();\n reject(new Error(`Response exceeded ${cap} byte cap (content-type: ${contentType})`));\n return;\n }\n chunks.push(chunk);\n });\n res.on('end', () => {\n if (aborted) return;\n resolve({ statusCode, headers: res.headers, body: Buffer.concat(chunks) });\n });\n res.on('error', (err) => {\n if (!aborted) reject(err);\n });\n },\n );\n\n req.on('timeout', () => {\n req.destroy(new Error(`Request timed out after ${REQUEST_TIMEOUT_MS}ms`));\n });\n req.on('error', reject);\n req.end();\n });\n}\n\nexport interface SafeFetchDeps {\n /** Override DNS resolution + IP validation (default: resolveAndValidate). */\n resolve?: (hostname: string) => Promise<{ address: string; family: number }>;\n /** Override the actual request (default: requestOnce against real http/https). */\n request?: (target: URL, address: string, family: number) => Promise<RawResponse>;\n}\n\n/**\n * Fetch a URL with the SSRF guards from validateUrl() plus streaming size\n * caps (MAX_FETCH_BYTES / MAX_TEXT_BYTES) and a hard error on non-2xx\n * status. Every redirect hop is independently validated and re-resolved —\n * a redirect to a private/loopback/metadata address is rejected exactly\n * like a direct request would be.\n *\n * `deps` exists so tests can substitute the DNS/network collaborators with\n * deterministic fakes (see tests/security.test.ts) instead of mocking\n * Node's core modules or hitting real sockets — production callers should\n * never need to pass it.\n */\nexport async function safeFetch(url: string, deps: SafeFetchDeps = {}): Promise<Buffer> {\n const resolve = deps.resolve ?? resolveAndValidate;\n const doRequest = deps.request ?? requestOnce;\n\n let current = validateUrl(url);\n for (let hop = 0; hop <= MAX_REDIRECTS; hop++) {\n const target = new URL(current);\n const { address, family } = await resolve(target.hostname);\n const response = await doRequest(target, address, family);\n\n if (response.statusCode >= 300 && response.statusCode < 400) {\n const location = response.headers.location;\n if (!location) {\n throw new Error(`Redirect response (${response.statusCode}) missing Location header`);\n }\n const next = new URL(location, target).toString();\n current = validateUrl(next);\n continue;\n }\n\n if (response.statusCode < 200 || response.statusCode >= 300) {\n throw new Error(`Non-2xx response: ${response.statusCode}`);\n }\n\n return response.body;\n }\n throw new Error(`Too many redirects (> ${MAX_REDIRECTS}) while fetching ${url}`);\n}\n\n// ---------------------------------------------------------------------------\n// Database DSN validation (MySQL schema extraction)\n// ---------------------------------------------------------------------------\n\nexport interface ValidatedDsn {\n /**\n * Credential-free rendering (`mysql://host:port/db`). This is the ONLY\n * form that may ever appear in graph nodes, reports, logs, or errors —\n * the password exists solely inside `connection`.\n */\n safeDisplay: string;\n connection: {\n host: string;\n port: number;\n user: string;\n password: string;\n database: string;\n };\n}\n\nconst DEFAULT_MYSQL_PORT = 3306;\n\n/**\n * Parse and validate a `mysql://user:pass@host:port/database` DSN.\n *\n * Deliberately does NOT apply the SSRF IP blocklist that safeFetch()\n * enforces: connecting to a localhost/private-network database is the\n * primary legitimate use of an explicitly user-supplied DSN, unlike a URL\n * scraped out of corpus content. The security property that matters here\n * is credential containment — see ValidatedDsn.safeDisplay.\n */\nexport function validateDsn(dsn: string): ValidatedDsn {\n let parsed: URL;\n try {\n parsed = new URL(dsn);\n } catch {\n throw new Error('Invalid DSN — expected mysql://user:pass@host:port/database');\n }\n\n if (parsed.protocol !== 'mysql:') {\n throw new Error(`DSN scheme not supported: \"${parsed.protocol}\" (only mysql: is supported)`);\n }\n\n const database = decodeURIComponent(parsed.pathname.replace(/^\\//, ''));\n if (!database || database.includes('/')) {\n throw new Error('DSN must name exactly one database, e.g. mysql://localhost:3306/mydb');\n }\n if (!parsed.hostname) {\n throw new Error('DSN must include a host, e.g. mysql://localhost:3306/mydb');\n }\n\n const port = parsed.port ? Number(parsed.port) : DEFAULT_MYSQL_PORT;\n return {\n safeDisplay: `mysql://${parsed.hostname}:${port}/${database}`,\n connection: {\n host: parsed.hostname,\n port,\n user: decodeURIComponent(parsed.username) || 'root',\n password: decodeURIComponent(parsed.password),\n database,\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Path traversal guard\n// ---------------------------------------------------------------------------\n\n/**\n * Resolve `path` and require it stays inside `base` (defaults to\n * `<cwd>/graphify-out`). `base` must already exist. Throws on traversal\n * attempts (`../`, absolute escapes, symlink-resolved escapes).\n */\nexport function validateGraphPath(path: string, base?: string): string {\n const baseDir = base ?? nodePath.join(process.cwd(), 'graphify-out');\n\n let resolvedBase: string;\n try {\n resolvedBase = fs.realpathSync(baseDir);\n } catch {\n throw new Error(`Base directory does not exist: ${baseDir}`);\n }\n\n const candidate = nodePath.isAbsolute(path) ? path : nodePath.join(resolvedBase, path);\n const resolvedCandidate = nodePath.resolve(candidate);\n\n // Resolve symlinks for whichever is the deepest existing ancestor, so a\n // symlink inside an otherwise-valid path can't escape the base dir either.\n let realCandidate = resolvedCandidate;\n try {\n realCandidate = fs.realpathSync(resolvedCandidate);\n } catch {\n // Path (or part of it) may not exist yet (e.g. a file we're about to\n // write) — fall back to the lexically-resolved path for the check.\n }\n\n const relative = nodePath.relative(resolvedBase, realCandidate);\n const escapes = relative === '..' || relative.startsWith(`..${nodePath.sep}`) || nodePath.isAbsolute(relative);\n if (escapes) {\n throw new Error(`Path escapes graphify-out/: ${path}`);\n }\n\n return realCandidate;\n}\n\n// ---------------------------------------------------------------------------\n// Label sanitization (unchanged reference implementation) + HTML escaping\n// ---------------------------------------------------------------------------\n\n/** Strip control characters, cap length. Apply to every node/edge label. */\nexport function sanitizeLabel(text: string | null | undefined): string {\n if (text == null) return '';\n // eslint-disable-next-line no-control-regex -- intentional: stripping raw control chars\n const stripped = String(text).replace(/[\\x00-\\x1f\\x7f]/g, '');\n return stripped.slice(0, MAX_LABEL_LEN);\n}\n\n/**\n * HTML-escape a string. Callers must run sanitizeLabel() first for\n * length/control-char stripping, then escapeHtml() immediately before\n * embedding into graph.html (XSS control, see SECURITY.md).\n */\nexport function escapeHtml(text: string): string {\n return text\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\n}\n\n// ---------------------------------------------------------------------------\n// Prompt-injection defenses for LLM-bound file content\n// ---------------------------------------------------------------------------\n\n/**\n * Known jailbreak / chat-template sentinels that must never reach a prompt\n * unescaped, whether they occur in source files or are forged to spoof our\n * own <untrusted_source> delimiter.\n */\nconst SENTINEL_PATTERNS: RegExp[] = [\n /<\\|im_start\\|>/gi,\n /<\\|im_end\\|>/gi,\n /<\\|system\\|>/gi,\n /\\[INST\\]/gi,\n /\\[\\/INST\\]/gi,\n /<<SYS>>/gi,\n /<<\\/SYS>>/gi,\n /<\\/untrusted_source>/gi,\n /<untrusted_source/gi,\n];\n\n/**\n * Render brackets as fullwidth lookalikes (< > [ ]) so the defanged\n * echo is human-visible but no longer byte-identical to the original\n * sentinel — a naive downstream scan for the literal delimiter/sentinel\n * text will not re-match our own \"we found one\" marker.\n */\nfunction toFullwidthBrackets(text: string): string {\n return text\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\\[/g, '[')\n .replace(/\\]/g, ']');\n}\n\n/**\n * Replace known jailbreak/chat-template sentinels with a visibly defanged\n * form — never silently stripped (silent stripping can itself be an\n * injection vector if it changes meaning unexpectedly).\n */\nfunction defangSentinels(content: string): string {\n let result = content;\n for (const pattern of SENTINEL_PATTERNS) {\n result = result.replace(pattern, (match) => `[DEFANGED:${toFullwidthBrackets(match)}]`);\n }\n return result;\n}\n\n/**\n * Wrap file content for LLM prompts in a hash-stamped untrusted-source\n * delimiter and neutralize known jailbreak/chat-template sentinels. This\n * raises the bar against prompt injection; it does not eliminate it —\n * document that plainly wherever this is referenced.\n */\nexport function wrapUntrustedSource(path: string, content: string): string {\n const sha256 = createHash('sha256').update(content, 'utf8').digest('hex');\n const safePath = escapeHtml(sanitizeLabel(path));\n const defanged = defangSentinels(content);\n return `<untrusted_source path=\"${safePath}\" sha256=\"${sha256}\">\\n${defanged}\\n</untrusted_source>`;\n}\n","import * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport type Graph from 'graphology';\nimport { analyze } from './analyze.js';\nimport { buildGraph } from './build.js';\nimport { ExtractionCache } from './extractionCache.js';\nimport { cluster, type ClusterAlgorithm } from './cluster.js';\nimport { collectFiles } from './detect.js';\nimport { extract } from './extract.js';\nimport { exportGraph } from './export.js';\nimport { renderReport } from './report.js';\nimport { readSelfNames, resolveCrossFileReferences } from './resolve.js';\nimport type { Analysis, ExtractionResult, FileManifest } from './types.js';\n\nexport interface PipelineOptions {\n /** Where to write graph.json/graph.html/GRAPH_REPORT.md. Defaults to `<root>/graphify-out`. */\n outDir?: string;\n html?: boolean;\n svg?: boolean;\n graphml?: boolean;\n neo4j?: boolean;\n obsidian?: boolean;\n /** `louvain` (default, v1) or `leiden` (v2 — better community quality, see cluster.ts). */\n algorithm?: ClusterAlgorithm;\n /** Leiden-only: cap on outer iterations for very large graphs. */\n maxIterations?: number;\n /**\n * Pre-computed extractions from non-filesystem sources (e.g. a MySQL\n * schema via extractMysql()) merged into the same graph as the code.\n */\n extraExtractions?: ExtractionResult[];\n /**\n * Incremental mode: reuse cached per-file extractions (keyed by content\n * hash) and re-parse only changed files. The cache is warmed on every\n * run either way — `update` only controls whether it's read.\n */\n update?: boolean;\n /** Called with a short progress message after each stage (e.g. for CLI stderr output). */\n onProgress?: (message: string) => void;\n}\n\nexport interface PipelineResult {\n manifest: FileManifest;\n graph: Graph;\n analysis: Analysis;\n report: string;\n}\n\n/**\n * The full `detect -> extract -> build -> cluster -> analyze -> report ->\n * export` pipeline as a single library call — the CLI's default command is\n * a thin wrapper over this. Every extension registered in\n * EXTRACTOR_REGISTRY (see extract.ts) is run; files with no registered\n * extractor are skipped (not an error — see extract()'s doc comment).\n */\nexport async function runPipeline(root: string, options: PipelineOptions = {}): Promise<PipelineResult> {\n const progress = options.onProgress ?? (() => {});\n const resolvedRoot = path.resolve(root);\n\n progress(`Scanning ${resolvedRoot} ...`);\n const manifest = collectFiles(resolvedRoot);\n progress(\n `Found ${manifest.totalFiles} file(s) (${manifest.files.code.length} code, ` +\n `${manifest.skippedSensitive.length} skipped as sensitive).`,\n );\n\n const outDir = options.outDir ?? path.join(resolvedRoot, 'graphify-out');\n const cache = new ExtractionCache(outDir);\n\n progress('Extracting...');\n const extractions: ExtractionResult[] = [];\n let cacheHits = 0;\n for (const relFile of manifest.files.code.sort((a, b) => a.localeCompare(b))) {\n // Read path: relative to CWD so fs reads inside the extractor resolve\n // correctly. Display path (second arg): relative to the scan root, so\n // node ids/sourceFile are stable and portable no matter where the\n // pipeline was launched from — required for cross-project merging.\n const filePath = path.relative(process.cwd(), path.join(resolvedRoot, relFile)) || relFile;\n try {\n const key = cache.key(relFile, await fs.readFile(path.join(resolvedRoot, relFile)));\n let extraction = options.update ? await cache.get(key) : null;\n if (extraction) {\n cacheHits++;\n } else {\n extraction = await extract(filePath, relFile);\n // Cache BEFORE the resolution pass mutates edges — entries must stay pristine.\n await cache.put(key, extraction);\n }\n extractions.push(extraction);\n } catch (error) {\n progress(` extraction failed for ${relFile}: ${(error as Error).message}`);\n throw error;\n }\n }\n if (options.update) {\n progress(` cache: ${cacheHits} hit(s), ${extractions.length - cacheHits} re-extracted.`);\n }\n\n if (options.extraExtractions && options.extraExtractions.length > 0) {\n extractions.push(...options.extraExtractions);\n }\n\n progress('Resolving cross-file references...');\n const resolveStats = resolveCrossFileReferences(extractions, {\n selfNames: await readSelfNames(resolvedRoot),\n });\n if (resolveStats.resolvedEndpoints > 0) {\n progress(\n ` re-pointed ${resolveStats.resolvedEndpoints} guessed reference(s) at real nodes ` +\n `(${resolveStats.droppedPlaceholders} placeholder node(s) dropped).`,\n );\n }\n\n progress('Building graph...');\n const graph = buildGraph(extractions);\n\n progress(`Clustering (${options.algorithm ?? 'louvain'})...`);\n cluster(graph, { algorithm: options.algorithm, maxIterations: options.maxIterations });\n\n progress('Analyzing...');\n const analysis = analyze(graph);\n\n progress('Rendering report...');\n const report = renderReport(graph, analysis);\n\n progress(`Exporting to ${outDir} ...`);\n await exportGraph(\n graph,\n {\n outDir,\n html: options.html,\n svg: options.svg,\n graphml: options.graphml,\n neo4j: options.neo4j,\n obsidian: options.obsidian,\n },\n report,\n );\n\n progress('Done.');\n return { manifest, graph, analysis, report };\n}\n","import { createHash } from 'node:crypto';\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport type { ExtractionResult } from './types.js';\n\n/**\n * Per-file extraction cache — what makes `--update` (and every rebuild\n * behind a git hook or --watch) incremental. Entries are keyed by a hash of\n * the file's CONTENT plus its root-relative path: content because that's\n * what extraction depends on, path because node ids embed it. A stale entry\n * for content that changed simply never matches again; the whole directory\n * can always be deleted safely.\n */\n\nexport class ExtractionCache {\n private readonly dir: string;\n\n constructor(outDir: string) {\n this.dir = path.join(outDir, 'cache');\n }\n\n key(relFile: string, content: Buffer | string): string {\n return createHash('sha256').update(relFile).update('\u0000').update(content).digest('hex');\n }\n\n async get(key: string): Promise<ExtractionResult | null> {\n try {\n const raw = await fs.readFile(path.join(this.dir, `${key}.json`), 'utf-8');\n const parsed = JSON.parse(raw) as ExtractionResult;\n if (!Array.isArray(parsed.nodes) || !Array.isArray(parsed.edges)) return null;\n return parsed;\n } catch {\n return null;\n }\n }\n\n async put(key: string, extraction: ExtractionResult): Promise<void> {\n await fs.mkdir(this.dir, { recursive: true });\n await fs.writeFile(path.join(this.dir, `${key}.json`), JSON.stringify(extraction), 'utf-8');\n }\n}\n","import * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport Graph from 'graphology';\nimport { validateGraphPath } from './security.js';\n\n/**\n * Load a previously-exported graph.json back into a graphology Graph.\n * Always goes through security.validateGraphPath() (path-traversal guard —\n * see SECURITY.md) so a caller-supplied `outDir`/CLI arg can never make\n * this read outside the graphify-out/ directory it resolves to.\n */\nexport async function loadGraph(outDir: string = path.join(process.cwd(), 'graphify-out')): Promise<Graph> {\n const jsonPath = validateGraphPath('graph.json', outDir);\n const raw = await fs.readFile(jsonPath, 'utf-8');\n const data: unknown = JSON.parse(raw);\n return Graph.from(data as Parameters<typeof Graph.from>[0]);\n}\n","import type Graph from 'graphology';\n\n/**\n * Library-level graph queries shared by the CLI (`graphify query/path/\n * explain`) and the MCP server tools of the same name. None of this is an\n * LLM call — it's lexical node matching + graph traversal, so it works\n * fully offline and deterministically.\n */\n\nconst STOPWORDS = new Set([\n 'a', 'an', 'the', 'is', 'are', 'was', 'were', 'do', 'does', 'did', 'how',\n 'what', 'where', 'when', 'why', 'who', 'which', 'to', 'of', 'in', 'on',\n 'for', 'and', 'or', 'this', 'that', 'it', 'does', 'that\\'s',\n]);\n\n/** Insert spaces at camelCase boundaries so identifier words become separate tokens. */\nfunction splitCamelCase(text: string): string {\n return text\n .replace(/([a-z0-9])([A-Z])/g, '$1 $2')\n .replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2');\n}\n\nfunction tokenize(text: string): string[] {\n return splitCamelCase(text)\n .toLowerCase()\n .split(/[^a-z0-9]+/)\n .filter((token) => token.length > 1 && !STOPWORDS.has(token));\n}\n\n/**\n * Split an identifier-ish string (node label/id) into its word subtokens:\n * camelCase, snake_case, kebab-case, dots, and path separators all become\n * boundaries, so `src/a/fileStorage.js::saveAttachment` yields\n * `src, file, storage, js, save, attachment`.\n */\nfunction subtokenize(text: string): string[] {\n return splitCamelCase(text)\n .toLowerCase()\n .split(/[^a-z0-9]+/)\n .filter((token) => token.length > 1);\n}\n\n/** Don't run the fuzzy tier on tokens this short — too many false positives. */\nconst FUZZY_MIN_TOKEN_LEN = 3;\n/** Minimum similarity for a fuzzy match to count at all. */\nconst FUZZY_THRESHOLD = 0.7;\nconst SUBTOKEN_MATCH_SCORE = 1;\nconst SUBSTRING_MATCH_SCORE = 0.6;\nconst FUZZY_MATCH_WEIGHT = 0.5;\n\n/**\n * Optimal-string-alignment Damerau-Levenshtein distance. Chosen over\n * bigram-set similarity because the common code-search typo is a\n * transposition (\"sorceNodes\"), which OSA counts as one edit but bigram\n * overlap punishes brutally.\n */\nfunction osaDistance(a: string, b: string): number {\n let prev2: number[] = [];\n let prev: number[] = Array.from({ length: b.length + 1 }, (_, j) => j);\n let curr: number[] = new Array<number>(b.length + 1).fill(0);\n\n for (let i = 1; i <= a.length; i++) {\n curr[0] = i;\n for (let j = 1; j <= b.length; j++) {\n const substitution = a[i - 1] === b[j - 1] ? 0 : 1;\n let best = Math.min(\n (prev[j] as number) + 1,\n (curr[j - 1] as number) + 1,\n (prev[j - 1] as number) + substitution,\n );\n if (i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1]) {\n best = Math.min(best, (prev2[j - 2] as number) + 1);\n }\n curr[j] = best;\n }\n [prev2, prev, curr] = [prev, curr, new Array<number>(b.length + 1).fill(0)];\n }\n return prev[b.length] as number;\n}\n\n/** Normalized similarity in [0, 1]; short-circuits pairs whose length gap alone puts them under FUZZY_THRESHOLD. */\nfunction fuzzySimilarity(a: string, b: string): number {\n if (a === b) return 1;\n const maxLen = Math.max(a.length, b.length);\n if (maxLen === 0) return 1;\n if (Math.abs(a.length - b.length) / maxLen > 1 - FUZZY_THRESHOLD) return 0;\n return 1 - osaDistance(a, b) / maxLen;\n}\n\nexport interface NodeMatch {\n id: string;\n label: string;\n score: number;\n}\n\n/**\n * Score every node against the query's tokens. Identifier-aware and\n * typo-tolerant, in three tiers per token (best tier wins):\n *\n * 1. exact subtoken match (camelCase/snake_case-split word of the label\n * or id) — \"storage\" matches `fileStorage.js`;\n * 2. plain substring of the label/id (the original v1 behavior);\n * 3. fuzzy (Damerau-Levenshtein) match against a subtoken — \"sorce\"\n * still finds `scoreNodes`.\n *\n * Still fully lexical and deterministic — no LLM, no randomness.\n */\nexport function scoreNodes(graph: Graph, query: string): NodeMatch[] {\n const tokens = tokenize(query);\n const matches: NodeMatch[] = [];\n\n graph.forEachNode((id, attributes) => {\n const label = (attributes.label as string | undefined) ?? id;\n const haystack = `${label} ${id}`.toLowerCase();\n const subtokens = new Set(subtokenize(`${label} ${id}`));\n let score = 0;\n for (const token of tokens) {\n if (subtokens.has(token)) {\n score += SUBTOKEN_MATCH_SCORE;\n continue;\n }\n if (haystack.includes(token)) {\n score += SUBSTRING_MATCH_SCORE;\n continue;\n }\n if (token.length >= FUZZY_MIN_TOKEN_LEN) {\n let best = 0;\n for (const subtoken of subtokens) {\n const similarity = fuzzySimilarity(token, subtoken);\n if (similarity > best) best = similarity;\n }\n if (best >= FUZZY_THRESHOLD) score += best * FUZZY_MATCH_WEIGHT;\n }\n }\n if (score > 0) matches.push({ id, label, score });\n });\n\n // On equal score, real source nodes beat module:/external: placeholders —\n // \"devtools\" should resolve to the devtools middleware, not the\n // @redux-devtools package node that happens to share a subtoken.\n const placeholderRank = (id: string): number =>\n id.startsWith('module:') || id.startsWith('external:') ? 1 : 0;\n matches.sort(\n (a, b) =>\n b.score - a.score || placeholderRank(a.id) - placeholderRank(b.id) || a.id.localeCompare(b.id),\n );\n return matches;\n}\n\n/**\n * Best-effort single-node resolution: the highest-scoring lexical match,\n * or null if nothing in the graph matches at all. Deliberately does *not*\n * fall back to \"the most connected node\" — path/explain name a specific\n * node by intent, and silently substituting an unrelated one would be\n * more misleading than clearly saying \"no match\".\n */\nexport function resolveNode(graph: Graph, query: string): NodeMatch | null {\n const matches = scoreNodes(graph, query);\n return matches[0] ?? null;\n}\n\nexport interface VisitedNode {\n id: string;\n label: string;\n sourceFile: string;\n sourceLocation: string;\n depth: number;\n}\n\nexport interface TraversalEdge {\n source: string;\n target: string;\n relation: string;\n confidence: string;\n}\n\nexport interface QueryResult {\n seeds: NodeMatch[];\n visited: VisitedNode[];\n edges: TraversalEdge[];\n}\n\nexport interface QueryOptions {\n dfs?: boolean;\n /** Hard cap on how many nodes to include. Defaults to a generous ceiling derived from `tokenBudget`. */\n budget?: number;\n /** Approximate cap, in tokens (~4 chars each), on the serialized size of the result. Default 2000. */\n tokenBudget?: number;\n maxDepth?: number;\n maxSeeds?: number;\n}\n\nconst DEFAULT_MAX_DEPTH = 2;\nconst DEFAULT_MAX_SEEDS = 5;\nconst DEFAULT_BUDGET = 40;\nconst DEFAULT_TOKEN_BUDGET = 2000;\n/** When only tokenBudget is given, allow up to this many nodes per budgeted token-decile as a safety ceiling. */\nconst NODES_PER_TOKEN = 1 / 10;\n\n/**\n * Estimated token contribution of one node to the rendered result: its own\n * line (label, file, location) plus a rough allowance for the edge lines\n * that mention its id. Chars/4 is the usual serviceable approximation.\n */\nfunction nodeTokenCost(graph: Graph, id: string): number {\n const attrs = graph.getNodeAttributes(id);\n const label = (attrs.label as string | undefined) ?? id;\n const sourceFile = (attrs.sourceFile as string | undefined) ?? '';\n return Math.ceil((id.length * 2 + label.length + sourceFile.length + 24) / 4);\n}\n\n/**\n * BFS (default, broad context) or DFS (--dfs, trace a specific path)\n * traversal from the nodes whose label best matches `question`'s\n * keywords. This is lexical retrieval, not natural-language\n * understanding — it surfaces the neighborhood of the graph an agent (or\n * a human) should look at to answer the question, it does not itself\n * compose an answer.\n */\nexport function queryGraph(graph: Graph, question: string, options: QueryOptions = {}): QueryResult {\n const maxDepth = options.maxDepth ?? DEFAULT_MAX_DEPTH;\n const maxSeeds = options.maxSeeds ?? DEFAULT_MAX_SEEDS;\n const tokenBudget = options.tokenBudget ?? DEFAULT_TOKEN_BUDGET;\n const budget = options.budget ?? Math.max(DEFAULT_BUDGET, Math.ceil(tokenBudget * NODES_PER_TOKEN));\n\n const allMatches = scoreNodes(graph, question);\n const seeds = allMatches.length > 0 ? allMatches.slice(0, maxSeeds) : [];\n\n const visited = new Map<string, number>(); // id -> depth\n const frontier: Array<{ id: string; depth: number }> = seeds.map((s) => ({ id: s.id, depth: 0 }));\n let spentTokens = 0;\n for (const seed of seeds) {\n visited.set(seed.id, 0);\n spentTokens += nodeTokenCost(graph, seed.id);\n }\n\n while (frontier.length > 0 && visited.size < budget && spentTokens < tokenBudget) {\n const current = options.dfs ? (frontier.pop() as { id: string; depth: number }) : (frontier.shift() as { id: string; depth: number });\n if (current.depth >= maxDepth) continue;\n\n const neighbors = [...graph.neighbors(current.id)].sort((a, b) => a.localeCompare(b));\n for (const neighbor of neighbors) {\n if (visited.has(neighbor) || visited.size >= budget || spentTokens >= tokenBudget) continue;\n visited.set(neighbor, current.depth + 1);\n spentTokens += nodeTokenCost(graph, neighbor);\n frontier.push({ id: neighbor, depth: current.depth + 1 });\n }\n }\n\n const visitedNodes: VisitedNode[] = [...visited.entries()]\n .map(([id, depth]) => {\n const attrs = graph.getNodeAttributes(id);\n return {\n id,\n label: (attrs.label as string | undefined) ?? id,\n sourceFile: (attrs.sourceFile as string | undefined) ?? '',\n sourceLocation: (attrs.sourceLocation as string | undefined) ?? '',\n depth,\n };\n })\n .sort((a, b) => a.depth - b.depth || a.id.localeCompare(b.id));\n\n const edges: TraversalEdge[] = [];\n graph.forEachEdge((_edge, attrs, source, target) => {\n if (visited.has(source) && visited.has(target)) {\n edges.push({\n source,\n target,\n relation: String(attrs.relation),\n confidence: String(attrs.confidence),\n });\n }\n });\n edges.sort(\n (a, b) => a.source.localeCompare(b.source) || a.target.localeCompare(b.target) || a.relation.localeCompare(b.relation),\n );\n\n return enforceTokenBudget({ seeds, visited: visitedNodes, edges }, tokenBudget);\n}\n\n/**\n * The traversal-time cost estimate can't see how densely connected the\n * visited neighborhood is — a hub-heavy subgraph induces far more edge\n * lines than nodes. Enforce the budget on the *actual* result: drop the\n * deepest/last nodes (and the edges that touched them) until the\n * serialized size fits. Seeds are never dropped.\n */\nfunction enforceTokenBudget(result: QueryResult, tokenBudget: number): QueryResult {\n const cost = (value: unknown): number => Math.ceil(JSON.stringify(value).length / 4);\n\n const visited = [...result.visited];\n let edges = [...result.edges];\n let total = cost(result.seeds) + visited.reduce((s, n) => s + cost(n), 0) + edges.reduce((s, e) => s + cost(e), 0);\n\n const seedIds = new Set(result.seeds.map((s) => s.id));\n // visited is sorted by (depth, id) — pop from the end so the deepest,\n // least-central context goes first and the result stays deterministic.\n while (total > tokenBudget && visited.length > 0) {\n const last = visited[visited.length - 1] as VisitedNode;\n if (seedIds.has(last.id)) break;\n visited.pop();\n total -= cost(last);\n const remaining: TraversalEdge[] = [];\n for (const edge of edges) {\n if (edge.source === last.id || edge.target === last.id) {\n total -= cost(edge);\n } else {\n remaining.push(edge);\n }\n }\n edges = remaining;\n }\n\n return { seeds: result.seeds, visited, edges };\n}\n\nexport interface PathResult {\n from: NodeMatch;\n to: NodeMatch;\n found: boolean;\n path: string[];\n edges: TraversalEdge[];\n}\n\n/** Shortest path between the nodes that best match `fromQuery` and `toQuery` (undirected BFS — connectivity, not call direction). */\nexport function shortestPath(graph: Graph, fromQuery: string, toQuery: string): PathResult | null {\n const from = resolveNode(graph, fromQuery);\n const to = resolveNode(graph, toQuery);\n if (!from || !to) return null;\n\n if (from.id === to.id) {\n return { from, to, found: true, path: [from.id], edges: [] };\n }\n\n const predecessor = new Map<string, string>();\n const visited = new Set<string>([from.id]);\n const queue: string[] = [from.id];\n\n while (queue.length > 0) {\n const current = queue.shift() as string;\n if (current === to.id) break;\n const neighbors = [...graph.neighbors(current)].sort((a, b) => a.localeCompare(b));\n for (const neighbor of neighbors) {\n if (visited.has(neighbor)) continue;\n visited.add(neighbor);\n predecessor.set(neighbor, current);\n queue.push(neighbor);\n }\n }\n\n if (!visited.has(to.id)) {\n return { from, to, found: false, path: [], edges: [] };\n }\n\n const path: string[] = [to.id];\n let cursor = to.id;\n while (cursor !== from.id) {\n const prev = predecessor.get(cursor);\n if (!prev) break;\n path.unshift(prev);\n cursor = prev;\n }\n\n const edges: TraversalEdge[] = [];\n for (let i = 0; i < path.length - 1; i++) {\n const a = path[i] as string;\n const b = path[i + 1] as string;\n const key = graph.edges(a, b)[0] ?? graph.edges(b, a)[0];\n if (key) {\n const attrs = graph.getEdgeAttributes(key);\n edges.push({ source: a, target: b, relation: String(attrs.relation), confidence: String(attrs.confidence) });\n }\n }\n\n return { from, to, found: true, path, edges };\n}\n\nexport interface ExplainResult {\n id: string;\n label: string;\n sourceFile: string;\n sourceLocation: string;\n communityLabel?: string;\n outgoing: TraversalEdge[];\n incoming: TraversalEdge[];\n}\n\n/** Plain-language-ready explanation of the node that best matches `query`. */\nexport function explainNode(graph: Graph, query: string): ExplainResult | null {\n const match = resolveNode(graph, query);\n if (!match) return null;\n\n const attrs = graph.getNodeAttributes(match.id);\n const outgoing: TraversalEdge[] = [];\n const incoming: TraversalEdge[] = [];\n\n graph.forEachOutEdge(match.id, (_edge, edgeAttrs, source, target) => {\n outgoing.push({ source, target, relation: String(edgeAttrs.relation), confidence: String(edgeAttrs.confidence) });\n });\n graph.forEachInEdge(match.id, (_edge, edgeAttrs, source, target) => {\n incoming.push({ source, target, relation: String(edgeAttrs.relation), confidence: String(edgeAttrs.confidence) });\n });\n\n outgoing.sort((a, b) => a.target.localeCompare(b.target) || a.relation.localeCompare(b.relation));\n incoming.sort((a, b) => a.source.localeCompare(b.source) || a.relation.localeCompare(b.relation));\n\n return {\n id: match.id,\n label: match.label,\n sourceFile: (attrs.sourceFile as string | undefined) ?? '',\n sourceLocation: (attrs.sourceLocation as string | undefined) ?? '',\n communityLabel: attrs.communityLabel as string | undefined,\n outgoing,\n incoming,\n };\n}\n","import type Graph from 'graphology';\nimport { resolveNode, type NodeMatch } from './query.js';\nimport type { Confidence, Relation } from './types.js';\n\n/**\n * Reverse impact analysis — \"what breaks if I change X\". Walks *incoming*\n * dependency edges (who calls / imports / inherits from the target)\n * transitively, so depth 1 is the direct blast radius and deeper levels are\n * ripple effects. Like everything in query.ts this is lexical + structural,\n * fully offline and deterministic.\n */\n\n/**\n * Relations where `source --rel--> target` means \"source depends on target\",\n * i.e. changing the target can break the source. `contains`/`method` are\n * included because changing an entity plausibly affects its container file\n * or class signature consumers see.\n */\nconst DEPENDENCY_RELATIONS: ReadonlySet<Relation> = new Set([\n 'calls',\n 'imports',\n 'imports_from',\n 'inherits',\n 'implements',\n 'mixes_in',\n 'embeds',\n 'references',\n 're_exports',\n 'method',\n 'contains',\n] satisfies Relation[]);\n\nexport interface AffectedNode {\n id: string;\n label: string;\n sourceFile: string;\n sourceLocation: string;\n /** 1 = depends on the target directly, 2 = one step removed, ... */\n depth: number;\n /** The dependency edge that pulled this node in (this node -> something already affected). */\n via: {\n relation: Relation;\n confidence: Confidence;\n /** The already-affected node this one depends on. */\n dependsOn: string;\n };\n}\n\nexport interface ImpactResult {\n target: NodeMatch;\n affected: AffectedNode[];\n /** How many affected nodes there are per confidence tier of the edge that pulled each one in. */\n byConfidence: Record<Confidence, number>;\n maxDepth: number;\n truncated: boolean;\n}\n\nexport interface ImpactOptions {\n /** How many reverse hops to follow (default 3). */\n maxDepth?: number;\n /** Hard cap on affected nodes reported (default 200). */\n limit?: number;\n /** Restrict the traversal to these relations (default: every dependency-carrying relation). */\n relations?: Relation[];\n}\n\nconst DEFAULT_IMPACT_DEPTH = 3;\nconst DEFAULT_IMPACT_LIMIT = 200;\n\nconst CONFIDENCE_RANK: Record<Confidence, number> = { EXTRACTED: 3, INFERRED: 2, AMBIGUOUS: 1 };\n\n/**\n * Resolve `nodeQuery` to its best-matching node, then reverse-BFS over\n * incoming dependency edges. Returns null when nothing in the graph matches\n * the query at all (same contract as explainNode()).\n */\nexport function affectedBy(graph: Graph, nodeQuery: string, options: ImpactOptions = {}): ImpactResult | null {\n const target = resolveNode(graph, nodeQuery);\n if (!target) return null;\n\n const maxDepth = options.maxDepth ?? DEFAULT_IMPACT_DEPTH;\n const limit = options.limit ?? DEFAULT_IMPACT_LIMIT;\n const followed: ReadonlySet<Relation> = options.relations ? new Set(options.relations) : DEPENDENCY_RELATIONS;\n\n const affected: AffectedNode[] = [];\n const visited = new Set<string>([target.id]);\n let frontier: string[] = [target.id];\n let truncated = false;\n\n for (let depth = 1; depth <= maxDepth && frontier.length > 0 && !truncated; depth++) {\n // Collect every dependent of the current frontier before descending, so\n // each node's reported depth is its *shortest* reverse distance.\n const nextFrontier = new Map<string, AffectedNode>();\n\n for (const current of [...frontier].sort((a, b) => a.localeCompare(b))) {\n graph.forEachInEdge(current, (_edge, edgeAttrs, source) => {\n if (visited.has(source)) return;\n const relation = edgeAttrs.relation as Relation;\n if (!followed.has(relation)) return;\n\n const confidence = edgeAttrs.confidence as Confidence;\n const existing = nextFrontier.get(source);\n // Same node reachable via several edges this round: keep the\n // strongest-confidence one, mirroring buildGraph()'s merge rule.\n if (existing && CONFIDENCE_RANK[existing.via.confidence] >= CONFIDENCE_RANK[confidence]) return;\n\n const attrs = graph.getNodeAttributes(source);\n nextFrontier.set(source, {\n id: source,\n label: (attrs.label as string | undefined) ?? source,\n sourceFile: (attrs.sourceFile as string | undefined) ?? '',\n sourceLocation: (attrs.sourceLocation as string | undefined) ?? '',\n depth,\n via: { relation, confidence, dependsOn: current },\n });\n });\n }\n\n const roundNodes = [...nextFrontier.values()].sort((a, b) => a.id.localeCompare(b.id));\n for (const node of roundNodes) {\n if (affected.length >= limit) {\n truncated = true;\n break;\n }\n visited.add(node.id);\n affected.push(node);\n }\n frontier = roundNodes.filter((n) => visited.has(n.id)).map((n) => n.id);\n }\n\n const byConfidence: Record<Confidence, number> = { EXTRACTED: 0, INFERRED: 0, AMBIGUOUS: 0 };\n for (const node of affected) byConfidence[node.via.confidence] += 1;\n\n return { target, affected, byConfidence, maxDepth, truncated };\n}\n","import Graph from 'graphology';\nimport type { Confidence } from './types.js';\n\n/**\n * Cross-project graph merging — combine several already-built graphs (one\n * per repo/project) into a single queryable global graph.\n *\n * Node ids inside one project are relative-path-based (`src/a.ts::foo`), so\n * two projects' ids would collide. Every node id and sourceFile is therefore\n * prefixed with `<project>/` — EXCEPT `module:*` (bare package imports) and\n * `external:*` (unresolved reference targets) nodes, which deliberately stay\n * unprefixed and shared: two repos importing the same package meet at the\n * same node, so cross-repo bridges emerge in the merged graph instead of\n * each repo floating as a disconnected island.\n */\n\nexport interface MergeEntry {\n /** Project name used as the id/sourceFile namespace prefix. */\n name: string;\n graph: Graph;\n}\n\nconst CONFIDENCE_RANK: Record<Confidence, number> = { EXTRACTED: 3, INFERRED: 2, AMBIGUOUS: 1 };\n\nfunction strongerConfidence(a: Confidence, b: Confidence): Confidence {\n return CONFIDENCE_RANK[a] >= CONFIDENCE_RANK[b] ? a : b;\n}\n\nfunction isShared(id: string): boolean {\n // `external:` = unresolved reference targets, `module:` = bare package\n // imports (see extractors/common.ts) — both name things outside any one\n // project, so they stay unprefixed and shared across the merge.\n return id.startsWith('external:') || id.startsWith('module:');\n}\n\nfunction namespaced(project: string, id: string): string {\n return isShared(id) ? id : `${project}/${id}`;\n}\n\n/**\n * Merge the entries into one directed graph, applying the same\n * deterministic-ordering and duplicate-edge rules as buildGraph(): entries\n * are processed in name order, duplicate edges (possible via shared\n * external nodes) keep the strongest confidence, and every node carries a\n * `project` attribute (shared external nodes get `project: '(shared)'`\n * once more than one project touches them).\n */\nexport function mergeGraphs(entries: MergeEntry[]): Graph {\n const names = entries.map((e) => e.name);\n const duplicate = names.find((name, i) => names.indexOf(name) !== i);\n if (duplicate !== undefined) {\n throw new Error(`Duplicate project name in merge: \"${duplicate}\" — every entry needs a unique name.`);\n }\n\n const merged = new Graph({ type: 'directed', multi: true, allowSelfLoops: true });\n const sorted = [...entries].sort((a, b) => a.name.localeCompare(b.name));\n\n for (const { name, graph } of sorted) {\n const nodeIds = [...graph.nodes()].sort((a, b) => a.localeCompare(b));\n for (const id of nodeIds) {\n const attrs = graph.getNodeAttributes(id);\n const newId = namespaced(name, id);\n\n if (merged.hasNode(newId)) {\n // Only shared external nodes can collide across projects.\n merged.setNodeAttribute(newId, 'project', '(shared)');\n continue;\n }\n\n const sourceFile = (attrs.sourceFile as string | undefined) ?? '';\n merged.addNode(newId, {\n label: (attrs.label as string | undefined) ?? id,\n sourceFile: isShared(id) || sourceFile === '' ? sourceFile : `${name}/${sourceFile}`,\n sourceLocation: (attrs.sourceLocation as string | undefined) ?? '',\n project: name,\n });\n }\n\n const edgeKeys = [...graph.edges()].sort((a, b) => a.localeCompare(b));\n for (const edgeKey of edgeKeys) {\n const attrs = graph.getEdgeAttributes(edgeKey);\n const source = namespaced(name, graph.source(edgeKey));\n const target = namespaced(name, graph.target(edgeKey));\n const relation = String(attrs.relation);\n const confidence = attrs.confidence as Confidence;\n\n const key = `${source}|${relation}|${target}`;\n if (merged.hasEdge(key)) {\n const existing = merged.getEdgeAttribute(key, 'confidence') as Confidence;\n merged.setEdgeAttribute(key, 'confidence', strongerConfidence(existing, confidence));\n continue;\n }\n merged.addEdgeWithKey(key, source, target, { relation, confidence });\n }\n }\n\n return merged;\n}\n","import { validateDsn } from '../security.js';\nimport type { ExtractionResult, GraphEdge, GraphNode } from '../types.js';\n\n/**\n * MySQL schema extraction — introspect information_schema over a\n * user-supplied DSN and map the schema onto the same ExtractionResult shape\n * every code extractor produces, so tables/columns/foreign keys land in the\n * same graph as the code that talks to them.\n *\n * Only ever surfaces the credential-free DSN rendering (see\n * security.validateDsn()) in node attributes; the password never leaves the\n * connection config.\n */\n\n/** One `SELECT` against the live connection. Injectable so tests run on canned rows, mirroring security.ts's LookupFn pattern. */\nexport type DsnQueryFn = (sql: string, params: ReadonlyArray<string>) => Promise<Array<Record<string, unknown>>>;\n\ninterface TableRow {\n name: string;\n isView: boolean;\n}\n\nconst schemaId = (schema: string): string => `db:${schema}`;\nconst tableId = (schema: string, table: string): string => `db:${schema}::${table}`;\nconst columnId = (schema: string, table: string, column: string): string => `db:${schema}::${table}.${column}`;\n\nasync function defaultQueryFn(dsn: string): Promise<{ query: DsnQueryFn; close: () => Promise<void> }> {\n const { connection } = validateDsn(dsn);\n // Dynamic import so merely bundling/importing this module never loads the\n // mysql2 driver — it's only pulled in when a DSN is actually used.\n const mysql = await import('mysql2/promise');\n const conn = await mysql.createConnection({\n host: connection.host,\n port: connection.port,\n user: connection.user,\n password: connection.password,\n database: connection.database,\n });\n return {\n query: async (sql, params) => {\n const [rows] = await conn.execute(sql, [...params]);\n return rows as Array<Record<string, unknown>>;\n },\n close: () => conn.end(),\n };\n}\n\n/**\n * Extract the schema graph for the database named in `dsn`.\n *\n * Nodes: the schema, every table/view, every column.\n * Edges: schema `contains` table, table `contains` column, FK column\n * `references` the referenced table (EXTRACTED), view `references` its base\n * tables (EXTRACTED via VIEW_TABLE_USAGE on MySQL >= 8.0.13, INFERRED via a\n * VIEW_DEFINITION text match on older servers).\n */\nexport async function extractMysql(dsn: string, queryFn?: DsnQueryFn): Promise<ExtractionResult> {\n const { safeDisplay, connection } = validateDsn(dsn);\n const schema = connection.database;\n\n let query = queryFn;\n let close: (() => Promise<void>) | undefined;\n if (!query) {\n const live = await defaultQueryFn(dsn);\n query = live.query;\n close = live.close;\n }\n\n try {\n const nodes: GraphNode[] = [];\n const edges: GraphEdge[] = [];\n\n nodes.push({ id: schemaId(schema), label: schema, sourceFile: safeDisplay, sourceLocation: schema });\n\n const tableRows = await query(\n 'SELECT TABLE_NAME, TABLE_TYPE FROM information_schema.TABLES WHERE TABLE_SCHEMA = ? ORDER BY TABLE_NAME',\n [schema],\n );\n const tables: TableRow[] = tableRows.map((row) => ({\n name: String(row.TABLE_NAME),\n isView: String(row.TABLE_TYPE).toUpperCase() === 'VIEW',\n }));\n const tableNames = new Set(tables.map((t) => t.name));\n\n for (const table of tables) {\n nodes.push({\n id: tableId(schema, table.name),\n label: `${table.isView ? 'view' : 'table'} ${table.name}`,\n sourceFile: safeDisplay,\n sourceLocation: table.name,\n });\n edges.push({\n source: schemaId(schema),\n target: tableId(schema, table.name),\n relation: 'contains',\n confidence: 'EXTRACTED',\n });\n }\n\n const columnRows = await query(\n 'SELECT TABLE_NAME, COLUMN_NAME, COLUMN_TYPE FROM information_schema.COLUMNS ' +\n 'WHERE TABLE_SCHEMA = ? ORDER BY TABLE_NAME, ORDINAL_POSITION',\n [schema],\n );\n for (const row of columnRows) {\n const table = String(row.TABLE_NAME);\n const column = String(row.COLUMN_NAME);\n if (!tableNames.has(table)) continue;\n nodes.push({\n id: columnId(schema, table, column),\n label: `${table}.${column}: ${String(row.COLUMN_TYPE)}`,\n sourceFile: safeDisplay,\n sourceLocation: `${table}.${column}`,\n });\n edges.push({\n source: tableId(schema, table),\n target: columnId(schema, table, column),\n relation: 'contains',\n confidence: 'EXTRACTED',\n });\n }\n\n const fkRows = await query(\n 'SELECT TABLE_NAME, COLUMN_NAME, REFERENCED_TABLE_NAME FROM information_schema.KEY_COLUMN_USAGE ' +\n 'WHERE TABLE_SCHEMA = ? AND REFERENCED_TABLE_NAME IS NOT NULL ORDER BY TABLE_NAME, COLUMN_NAME',\n [schema],\n );\n for (const row of fkRows) {\n const table = String(row.TABLE_NAME);\n const column = String(row.COLUMN_NAME);\n const referenced = String(row.REFERENCED_TABLE_NAME);\n if (!tableNames.has(table) || !tableNames.has(referenced)) continue;\n edges.push({\n source: columnId(schema, table, column),\n target: tableId(schema, referenced),\n relation: 'references',\n confidence: 'EXTRACTED',\n });\n }\n\n const viewNames = tables.filter((t) => t.isView).map((t) => t.name);\n if (viewNames.length > 0) {\n await addViewEdges(query, schema, viewNames, tableNames, edges);\n }\n\n return { nodes, edges };\n } finally {\n await close?.();\n }\n}\n\n/** View -> base-table edges: VIEW_TABLE_USAGE when the server has it (MySQL >= 8.0.13), else an INFERRED VIEW_DEFINITION text match. */\nasync function addViewEdges(\n query: DsnQueryFn,\n schema: string,\n viewNames: string[],\n tableNames: ReadonlySet<string>,\n edges: GraphEdge[],\n): Promise<void> {\n try {\n const usageRows = await query(\n 'SELECT VIEW_NAME, TABLE_NAME FROM information_schema.VIEW_TABLE_USAGE ' +\n 'WHERE VIEW_SCHEMA = ? AND TABLE_SCHEMA = ? ORDER BY VIEW_NAME, TABLE_NAME',\n [schema, schema],\n );\n for (const row of usageRows) {\n const view = String(row.VIEW_NAME);\n const table = String(row.TABLE_NAME);\n if (!tableNames.has(view) || !tableNames.has(table) || view === table) continue;\n edges.push({\n source: tableId(schema, view),\n target: tableId(schema, table),\n relation: 'references',\n confidence: 'EXTRACTED',\n });\n }\n return;\n } catch {\n // Server predates VIEW_TABLE_USAGE — fall back to matching table names\n // inside the view definition text, honestly downgraded to INFERRED.\n }\n\n const definitionRows = await query(\n 'SELECT TABLE_NAME, VIEW_DEFINITION FROM information_schema.VIEWS WHERE TABLE_SCHEMA = ? ORDER BY TABLE_NAME',\n [schema],\n );\n for (const row of definitionRows) {\n const view = String(row.TABLE_NAME);\n if (!viewNames.includes(view)) continue;\n const definition = String(row.VIEW_DEFINITION ?? '').toLowerCase();\n for (const table of [...tableNames].sort((a, b) => a.localeCompare(b))) {\n if (table === view) continue;\n if (new RegExp(`\\\\b${table.toLowerCase()}\\\\b`).test(definition)) {\n edges.push({\n source: tableId(schema, view),\n target: tableId(schema, table),\n relation: 'references',\n confidence: 'INFERRED',\n });\n }\n }\n }\n}\n","import { createHash } from 'node:crypto';\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\n\n/**\n * The graph feedback loop — `graphify save-result` logs which graph nodes\n * actually helped answer a question (or led nowhere), and `graphify\n * reflect` aggregates those logs into a recency-weighted LESSONS.md an\n * agent can read at session start. This is what turns the graph from a\n * static map into one that learns which landmarks matter.\n */\n\nexport type ResultOutcome = 'useful' | 'dead_end' | 'corrected';\nexport type ResultType = 'query' | 'path' | 'explain' | 'affected';\n\nexport interface SavedResult {\n question: string;\n answer: string;\n type: ResultType;\n outcome: ResultOutcome;\n /** Node ids/labels cited in the answer. */\n nodes: string[];\n /** What the right answer was — pairs with outcome 'corrected'. */\n correction?: string;\n savedAt: string; // ISO timestamp\n}\n\nconst OUTCOMES: ReadonlySet<string> = new Set(['useful', 'dead_end', 'corrected']);\nconst TYPES: ReadonlySet<string> = new Set(['query', 'path', 'explain', 'affected']);\n\nexport function validateResult(value: Omit<SavedResult, 'savedAt'>): void {\n if (!value.question) throw new Error('save-result requires --question');\n if (!value.answer) throw new Error('save-result requires --answer');\n if (!OUTCOMES.has(value.outcome)) {\n throw new Error(`--outcome must be one of: useful, dead_end, corrected (got \"${value.outcome}\")`);\n }\n if (!TYPES.has(value.type)) {\n throw new Error(`--type must be one of: query, path, explain, affected (got \"${value.type}\")`);\n }\n if (value.outcome === 'corrected' && !value.correction) {\n throw new Error('--outcome corrected requires --correction with what the right answer was');\n }\n}\n\n/** Append one result to `<memoryDir>/result-<stamp>-<hash>.json`. Returns the file path. */\nexport async function saveResult(\n entry: Omit<SavedResult, 'savedAt'>,\n memoryDir: string,\n now: Date = new Date(),\n): Promise<string> {\n validateResult(entry);\n await fs.mkdir(memoryDir, { recursive: true });\n\n const saved: SavedResult = { ...entry, savedAt: now.toISOString() };\n const hash = createHash('sha256').update(JSON.stringify(saved)).digest('hex').slice(0, 8);\n const stamp = saved.savedAt.replace(/[:.]/g, '-');\n const filePath = path.join(memoryDir, `result-${stamp}-${hash}.json`);\n await fs.writeFile(filePath, JSON.stringify(saved, null, 2), 'utf-8');\n return filePath;\n}\n\nexport interface ReflectOptions {\n /** A result's weight halves every this many days (default 30). */\n halfLifeDays?: number;\n /** Injectable clock for deterministic tests. */\n now?: Date;\n /** Only list nodes cited usefully at least this many distinct times (default 2). */\n minCorroboration?: number;\n}\n\ninterface NodeSignal {\n useful: number;\n deadEnd: number;\n usefulCount: number;\n deadEndCount: number;\n}\n\n/** Read every result JSON under `memoryDir` (missing dir = no results). */\nexport async function loadResults(memoryDir: string): Promise<SavedResult[]> {\n let files: string[];\n try {\n files = (await fs.readdir(memoryDir)).filter((f) => f.startsWith('result-') && f.endsWith('.json'));\n } catch {\n return [];\n }\n\n const results: SavedResult[] = [];\n for (const file of files.sort((a, b) => a.localeCompare(b))) {\n try {\n const parsed = JSON.parse(await fs.readFile(path.join(memoryDir, file), 'utf-8')) as SavedResult;\n if (parsed.question && parsed.savedAt) results.push(parsed);\n } catch {\n // one corrupt file must not sink the reflection\n }\n }\n return results;\n}\n\n/** Aggregate saved results into a LESSONS.md string. Deterministic given results + options.now. */\nexport function renderLessons(results: SavedResult[], options: ReflectOptions = {}): string {\n const halfLife = options.halfLifeDays ?? 30;\n const now = options.now ?? new Date();\n const minCorroboration = options.minCorroboration ?? 2;\n\n const weightOf = (savedAt: string): number => {\n const ageDays = Math.max(0, (now.getTime() - new Date(savedAt).getTime()) / 86_400_000);\n return Math.pow(0.5, ageDays / halfLife);\n };\n\n const signals = new Map<string, NodeSignal>();\n const corrections: Array<{ question: string; correction: string; savedAt: string }> = [];\n\n for (const result of results) {\n const weight = weightOf(result.savedAt);\n for (const node of result.nodes ?? []) {\n const signal = signals.get(node) ?? { useful: 0, deadEnd: 0, usefulCount: 0, deadEndCount: 0 };\n if (result.outcome === 'useful') {\n signal.useful += weight;\n signal.usefulCount++;\n } else if (result.outcome === 'dead_end') {\n signal.deadEnd += weight;\n signal.deadEndCount++;\n }\n signals.set(node, signal);\n }\n if (result.outcome === 'corrected' && result.correction) {\n corrections.push({ question: result.question, correction: result.correction, savedAt: result.savedAt });\n }\n }\n\n const byScore = (kind: 'useful' | 'deadEnd') =>\n [...signals.entries()]\n .filter(([, s]) => (kind === 'useful' ? s.usefulCount >= minCorroboration : s.deadEndCount > 0))\n .sort((a, b) => b[1][kind] - a[1][kind] || a[0].localeCompare(b[0]))\n .slice(0, 10);\n\n const lines: string[] = [\n '# Graph lessons',\n '',\n `_Aggregated from ${results.length} saved result(s); signal half-life ${halfLife} day(s)._`,\n '',\n '## Nodes that keep answering',\n '',\n ];\n\n const useful = byScore('useful');\n if (useful.length === 0) {\n lines.push(`(none yet with >= ${minCorroboration} corroborating results — keep saving results)`);\n } else {\n for (const [node, s] of useful) {\n lines.push(`- **${node}** — score ${s.useful.toFixed(2)} across ${s.usefulCount} useful result(s)`);\n }\n }\n\n lines.push('', '## Dead ends', '');\n const deadEnds = byScore('deadEnd');\n if (deadEnds.length === 0) {\n lines.push('(none recorded)');\n } else {\n for (const [node, s] of deadEnds) {\n lines.push(`- **${node}** — score ${s.deadEnd.toFixed(2)} across ${s.deadEndCount} dead-end result(s)`);\n }\n }\n\n lines.push('', '## Corrections', '');\n if (corrections.length === 0) {\n lines.push('(none recorded)');\n } else {\n corrections.sort((a, b) => b.savedAt.localeCompare(a.savedAt));\n for (const c of corrections.slice(0, 20)) {\n lines.push(`- (${c.savedAt.slice(0, 10)}) Q: ${c.question}`);\n lines.push(` Right answer: ${c.correction}`);\n }\n }\n\n lines.push('');\n return lines.join('\\n');\n}\n","import type Graph from 'graphology';\nimport { scoreNodes } from './query.js';\n\n/**\n * `graphify context` — the working-set pack. Instead of returning node\n * names for the agent to chase (query -> then read whole files anyway),\n * this fuses the two steps: the graph knows every entity's file and line,\n * so rank the nodes relevant to the task, read just the relevant line\n * ranges, and pack the actual code into a token budget. One call returns\n * the code an agent needs to start a task.\n */\n\nexport interface ContextSnippet {\n nodeId: string;\n label: string;\n file: string;\n startLine: number;\n endLine: number;\n code: string;\n /** Why this snippet is in the pack (lexical match / neighbor-of relation). */\n reason: string;\n score: number;\n}\n\nexport interface ContextPack {\n task: string;\n snippets: ContextSnippet[];\n /** Approximate tokens used out of the budget. */\n tokens: number;\n tokenBudget: number;\n /** Ranked nodes that didn't fit the budget — the agent can pull them explicitly. */\n overflow: Array<{ nodeId: string; file: string }>;\n}\n\nexport interface ContextOptions {\n /** Approximate token cap for the pack (default 4000). */\n tokenBudget?: number;\n maxSeeds?: number;\n /** Cap on snippet length in lines (default 60). */\n maxSnippetLines?: number;\n}\n\nexport type FileReader = (path: string) => Promise<string>;\n\nconst DEFAULT_CONTEXT_BUDGET = 4000;\nconst DEFAULT_MAX_SEEDS = 8;\nconst DEFAULT_MAX_SNIPPET_LINES = 60;\n/** A neighbor inherits this fraction of the score of the node that pulled it in. */\nconst NEIGHBOR_DECAY = 0.4;\n\nconst tokensOf = (text: string): number => Math.ceil(text.length / 4);\n\nfunction lineNumberOf(sourceLocation: string): number | null {\n const match = /^L(\\d+)$/.exec(sourceLocation);\n return match ? Number(match[1]) : null;\n}\n\nfunction isReadableFile(sourceFile: string): boolean {\n return sourceFile !== '' && !sourceFile.startsWith('<') && !sourceFile.includes('://');\n}\n\ninterface RankedNode {\n id: string;\n score: number;\n reason: string;\n}\n\n/**\n * Rank nodes for the task: lexical seeds first (their match score), then\n * their graph neighbors at a decayed score, labeled with the relation that\n * connects them. Deterministic (score desc, id asc).\n */\nexport function rankForTask(graph: Graph, task: string, maxSeeds = DEFAULT_MAX_SEEDS): RankedNode[] {\n const seeds = scoreNodes(graph, task).slice(0, maxSeeds);\n const ranked = new Map<string, RankedNode>();\n for (const seed of seeds) {\n ranked.set(seed.id, { id: seed.id, score: seed.score, reason: 'matches the task' });\n }\n\n for (const seed of seeds) {\n graph.forEachEdge(seed.id, (_edge, attrs, source, target) => {\n const neighbor = source === seed.id ? target : source;\n if (ranked.has(neighbor)) return;\n const relation = String(attrs.relation);\n const direction = source === seed.id ? `${relation} ->` : `<- ${relation}`;\n ranked.set(neighbor, {\n id: neighbor,\n score: seed.score * NEIGHBOR_DECAY,\n reason: `${direction} ${seed.label}`,\n });\n });\n }\n\n return [...ranked.values()].sort((a, b) => b.score - a.score || a.id.localeCompare(b.id));\n}\n\n/**\n * Extract the snippet for a node: from its declaration line to just before\n * the next known entity in the same file (capped), so snippets align with\n * real code block boundaries without needing a parser here.\n */\nfunction snippetRange(\n startLine: number,\n fileLineCount: number,\n entityStartsInFile: number[],\n maxLines: number,\n): { start: number; end: number } {\n const nextStart = entityStartsInFile.find((l) => l > startLine);\n const hardEnd = nextStart !== undefined ? nextStart - 1 : fileLineCount;\n return { start: startLine, end: Math.min(hardEnd, startLine + maxLines - 1) };\n}\n\nexport async function buildContextPack(\n graph: Graph,\n task: string,\n readFile: FileReader,\n options: ContextOptions = {},\n): Promise<ContextPack> {\n const tokenBudget = options.tokenBudget ?? DEFAULT_CONTEXT_BUDGET;\n const maxSnippetLines = options.maxSnippetLines ?? DEFAULT_MAX_SNIPPET_LINES;\n const ranked = rankForTask(graph, task, options.maxSeeds);\n\n // Every known entity start line per file — used to end snippets at the\n // next declaration instead of an arbitrary window.\n const entityStarts = new Map<string, number[]>();\n graph.forEachNode((_id, attrs) => {\n const file = attrs.sourceFile as string | undefined;\n const line = lineNumberOf((attrs.sourceLocation as string | undefined) ?? '');\n if (file && line !== null) {\n const starts = entityStarts.get(file) ?? [];\n starts.push(line);\n entityStarts.set(file, starts);\n }\n });\n for (const starts of entityStarts.values()) starts.sort((a, b) => a - b);\n\n const fileCache = new Map<string, string[] | null>();\n const readLines = async (file: string): Promise<string[] | null> => {\n const cached = fileCache.get(file);\n if (cached !== undefined) return cached;\n let lines: string[] | null;\n try {\n lines = (await readFile(file)).split('\\n');\n } catch {\n lines = null;\n }\n fileCache.set(file, lines);\n return lines;\n };\n\n const snippets: ContextSnippet[] = [];\n const overflow: Array<{ nodeId: string; file: string }> = [];\n const coveredRanges = new Map<string, Array<{ start: number; end: number }>>();\n let tokens = 0;\n\n for (const node of ranked) {\n const attrs = graph.getNodeAttributes(node.id);\n const file = (attrs.sourceFile as string | undefined) ?? '';\n const startLine = lineNumberOf((attrs.sourceLocation as string | undefined) ?? '');\n if (!isReadableFile(file) || startLine === null) continue;\n\n const lines = await readLines(file);\n if (lines === null) continue;\n\n const { start, end } = snippetRange(startLine, lines.length, entityStarts.get(file) ?? [], maxSnippetLines);\n\n // Skip if an already-packed snippet from the same file covers this range.\n const covered = (coveredRanges.get(file) ?? []).some((r) => start >= r.start && end <= r.end);\n if (covered) continue;\n\n const code = lines.slice(start - 1, end).join('\\n');\n const cost = tokensOf(code) + 15; // header overhead\n if (tokens + cost > tokenBudget) {\n overflow.push({ nodeId: node.id, file: `${file}:L${startLine}` });\n continue;\n }\n\n tokens += cost;\n snippets.push({\n nodeId: node.id,\n label: (attrs.label as string | undefined) ?? node.id,\n file,\n startLine: start,\n endLine: end,\n code,\n reason: node.reason,\n score: node.score,\n });\n const ranges = coveredRanges.get(file) ?? [];\n ranges.push({ start, end });\n coveredRanges.set(file, ranges);\n }\n\n return { task, snippets, tokens, tokenBudget, overflow };\n}\n\n/** Render a pack as agent-ready markdown. */\nexport function renderContextPack(pack: ContextPack): string {\n const lines: string[] = [\n `# Context pack: ${pack.task}`,\n '',\n `_~${pack.tokens} of ${pack.tokenBudget} token budget, ${pack.snippets.length} snippet(s)._`,\n '',\n ];\n\n if (pack.snippets.length === 0) {\n lines.push('No matching code found — try different keywords.');\n return lines.join('\\n');\n }\n\n for (const snippet of pack.snippets) {\n lines.push(`## ${snippet.label} — \\`${snippet.file}:L${snippet.startLine}-L${snippet.endLine}\\``);\n lines.push(`_${snippet.reason}_`);\n lines.push('```');\n lines.push(snippet.code);\n lines.push('```');\n lines.push('');\n }\n\n if (pack.overflow.length > 0) {\n lines.push(`## Didn't fit the budget (${pack.overflow.length})`);\n for (const item of pack.overflow.slice(0, 15)) {\n lines.push(`- ${item.nodeId} (${item.file})`);\n }\n lines.push('');\n }\n\n return lines.join('\\n');\n}\n","import type Graph from 'graphology';\nimport { affectedBy } from './impact.js';\nimport { resolveNode } from './query.js';\nimport type { Relation } from './types.js';\n\n/**\n * `graphify tests` — structural test selection. Coverage tools need\n * instrumentation and a full test run to know what covers what; the graph\n * already knows, statically: a test file imports/calls the code it\n * exercises, so the test files inside a change's reverse blast radius are\n * exactly the ones worth running. Cross-language, no instrumentation.\n */\n\n/** Test-file naming conventions across the supported languages. */\nconst TEST_FILE_PATTERNS: RegExp[] = [\n /(^|\\/)tests?\\//, // tests/ or test/ directory\n /(^|\\/)__tests__\\//,\n /(^|\\/)spec\\//,\n /\\.test\\.[cm]?[jt]sx?$/,\n /\\.spec\\.[cm]?[jt]sx?$/,\n /(^|\\/)test_[^/]+\\.py$/,\n /_test\\.py$/,\n /_test\\.go$/,\n /Tests?\\.(java|cs)$/,\n /_spec\\.rb$/,\n /_test\\.rb$/,\n];\n\nexport function isTestFile(path: string): boolean {\n return TEST_FILE_PATTERNS.some((p) => p.test(path));\n}\n\nexport interface TestSelection {\n /** What the selection was computed for (resolved node id, or the changed files). */\n target: string;\n /** Unique test files, most directly affected first. */\n testFiles: Array<{ file: string; depth: number; via: string }>;\n /** How many non-test nodes were in the blast radius (context for confidence). */\n affectedNodeCount: number;\n /**\n * `usage` — selected by following actual use (calls/inheritance), tight;\n * `import-reachability` — the broad fallback: anything that can reach the\n * target through imports/re-exports, which over-includes files that share\n * a barrel entry with the target.\n */\n precision: 'usage' | 'import-reachability';\n}\n\nconst TEST_REACH_DEPTH = 4;\nconst TEST_REACH_LIMIT = 2000;\n\n/** Relations that mean \"actually uses it\", as opposed to \"can merely reach it through an import\". */\nconst USAGE_RELATIONS: Relation[] = ['calls', 'inherits', 'implements', 'mixes_in', 'embeds', 'references'];\n\nfunction selectionFromImpact(\n graph: Graph,\n targetIds: string[],\n targetLabel: string,\n relations?: Relation[],\n): TestSelection {\n const best = new Map<string, { depth: number; via: string }>();\n let affectedNodeCount = 0;\n\n for (const id of targetIds) {\n const impact = affectedBy(graph, id, { maxDepth: TEST_REACH_DEPTH, limit: TEST_REACH_LIMIT, relations });\n if (!impact) continue;\n affectedNodeCount += impact.affected.length;\n for (const node of impact.affected) {\n if (!isTestFile(node.sourceFile)) continue;\n const existing = best.get(node.sourceFile);\n if (!existing || node.depth < existing.depth) {\n best.set(node.sourceFile, { depth: node.depth, via: node.via.dependsOn });\n }\n }\n }\n\n const testFiles = [...best.entries()]\n .map(([file, info]) => ({ file, depth: info.depth, via: info.via }))\n .sort((a, b) => a.depth - b.depth || a.file.localeCompare(b.file));\n\n return {\n target: targetLabel,\n testFiles,\n affectedNodeCount,\n precision: relations ? 'usage' : 'import-reachability',\n };\n}\n\n/** A file node's entities (so a usage-relation traversal has call targets to start from). */\nfunction entityRootsOf(graph: Graph, id: string): string[] {\n if (id.includes('::')) return [id];\n const roots: string[] = [];\n graph.forEachOutEdge(id, (_edge, attrs, _source, target) => {\n if (String(attrs.relation) === 'contains') roots.push(target);\n });\n roots.sort((a, b) => a.localeCompare(b));\n return roots.length > 0 ? roots : [id];\n}\n\n/**\n * Test files reachable (reverse) from the node best matching `nodeQuery`.\n * Tries a tight usage-relation pass first (tests that actually CALL the\n * target — precise even when many files share a barrel entry point); falls\n * back to full import-reachability when usage finds nothing. Null if\n * nothing matches the query.\n */\nexport function testsForNode(graph: Graph, nodeQuery: string): TestSelection | null {\n const match = resolveNode(graph, nodeQuery);\n if (!match) return null;\n\n const precise = selectionFromImpact(graph, entityRootsOf(graph, match.id), match.id, USAGE_RELATIONS);\n if (precise.testFiles.length > 0) return precise;\n\n return selectionFromImpact(graph, [match.id], match.id);\n}\n\n/**\n * Test files reachable from any of the given changed files (as reported by\n * `git diff --name-only`). Changed test files select themselves. Unknown\n * files (not in the graph) are skipped.\n */\nexport function testsForChangedFiles(graph: Graph, changedFiles: string[]): TestSelection {\n const fileIds: string[] = [];\n const selfSelected = new Map<string, { depth: number; via: string }>();\n\n for (const file of changedFiles) {\n if (isTestFile(file)) {\n selfSelected.set(file, { depth: 0, via: '(changed directly)' });\n continue;\n }\n if (graph.hasNode(file)) fileIds.push(file);\n }\n\n const label = changedFiles.join(', ');\n const preciseRoots = fileIds.flatMap((f) => entityRootsOf(graph, f));\n let selection = selectionFromImpact(graph, preciseRoots, label, USAGE_RELATIONS);\n if (selection.testFiles.length === 0) {\n selection = selectionFromImpact(graph, fileIds, label);\n }\n for (const [file, info] of selfSelected) {\n if (!selection.testFiles.some((t) => t.file === file)) {\n selection.testFiles.push({ file, depth: info.depth, via: info.via });\n }\n }\n selection.testFiles.sort((a, b) => a.depth - b.depth || a.file.localeCompare(b.file));\n return selection;\n}\n","import { execFile } from 'node:child_process';\nimport * as fs from 'node:fs/promises';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport { promisify } from 'node:util';\nimport type Graph from 'graphology';\nimport { buildGraph } from './build.js';\nimport { collectFiles } from './detect.js';\nimport { extract } from './extract.js';\nimport { affectedBy } from './impact.js';\nimport { readSelfNames, resolveCrossFileReferences } from './resolve.js';\nimport { testsForNode } from './testmap.js';\nimport type { ExtractionResult } from './types.js';\n\nconst execFileAsync = promisify(execFile);\n\n/**\n * `graphify review` — semantic graph diff between two git revisions.\n * Full structural extraction is sub-second, so instead of parsing text\n * diffs we build the graph at both revs and diff the graphs: which symbols\n * appeared, disappeared, or got rewired — each with its blast radius and\n * the test files worth running. One command answers both \"what changed\n * since I was last here\" and \"review this PR structurally\".\n */\n\nexport interface ChangedSymbol {\n id: string;\n label: string;\n sourceFile: string;\n /** Everything that depends on this symbol (computed in the graph where it exists). */\n blastRadius: number;\n /** Test files reachable from it. */\n tests: string[];\n}\n\nexport interface RewiredSymbol extends ChangedSymbol {\n gainedEdges: string[];\n lostEdges: string[];\n}\n\nexport interface GraphDiff {\n base: string;\n head: string;\n added: ChangedSymbol[];\n removed: ChangedSymbol[];\n rewired: RewiredSymbol[];\n}\n\n/** Extract a graph from a directory without exporting anything. */\nexport async function graphForDirectory(root: string): Promise<Graph> {\n const manifest = collectFiles(root);\n const extractions: ExtractionResult[] = [];\n for (const relFile of manifest.files.code.sort((a, b) => a.localeCompare(b))) {\n extractions.push(await extract(path.join(root, relFile), relFile));\n }\n resolveCrossFileReferences(extractions, { selfNames: await readSelfNames(root) });\n return buildGraph(extractions);\n}\n\n/** `git archive <rev> | tar -x` into a fresh temp dir — tracked files only, no worktree pollution. */\nasync function checkoutRev(repoRoot: string, rev: string): Promise<string> {\n const dest = await fs.mkdtemp(path.join(os.tmpdir(), `graphify-review-${rev.replace(/[^a-zA-Z0-9]/g, '_')}-`));\n const { stdout } = await execFileAsync(\n 'git',\n ['-C', repoRoot, 'archive', '--format=tar', rev],\n { encoding: 'buffer', maxBuffer: 512 * 1024 * 1024 },\n );\n await new Promise<void>((resolve, reject) => {\n const tar = execFile('tar', ['-x', '-C', dest], (error) => (error ? reject(error) : resolve()));\n tar.stdin?.end(stdout);\n });\n return dest;\n}\n\n/** Signature of a node's edge set, for rewire detection. */\nfunction edgeSignature(graph: Graph, id: string): Set<string> {\n const signature = new Set<string>();\n graph.forEachOutEdge(id, (_e, attrs, _s, target) => signature.add(`-> ${String(attrs.relation)} ${target}`));\n graph.forEachInEdge(id, (_e, attrs, source) => signature.add(`<- ${String(attrs.relation)} ${source}`));\n return signature;\n}\n\nfunction describeSymbol(graph: Graph, id: string): ChangedSymbol {\n const attrs = graph.getNodeAttributes(id);\n const impact = affectedBy(graph, id, { maxDepth: 3 });\n const tests = testsForNode(graph, id);\n return {\n id,\n label: (attrs.label as string | undefined) ?? id,\n sourceFile: (attrs.sourceFile as string | undefined) ?? '',\n blastRadius: impact?.affected.length ?? 0,\n tests: tests?.testFiles.map((t) => t.file) ?? [],\n };\n}\n\n/** Entity nodes only — file add/removes are visible from the entities inside them, and file nodes double-count. */\nfunction entityIds(graph: Graph): Set<string> {\n const ids = new Set<string>();\n graph.forEachNode((id) => {\n if (id.includes('::')) ids.add(id);\n });\n return ids;\n}\n\nexport function diffGraphs(baseGraph: Graph, headGraph: Graph, base: string, head: string): GraphDiff {\n const baseIds = entityIds(baseGraph);\n const headIds = entityIds(headGraph);\n\n const added: ChangedSymbol[] = [];\n const removed: ChangedSymbol[] = [];\n const rewired: RewiredSymbol[] = [];\n\n for (const id of [...headIds].sort((a, b) => a.localeCompare(b))) {\n if (!baseIds.has(id)) {\n added.push(describeSymbol(headGraph, id));\n continue;\n }\n const before = edgeSignature(baseGraph, id);\n const after = edgeSignature(headGraph, id);\n const gained = [...after].filter((e) => !before.has(e)).sort((a, b) => a.localeCompare(b));\n const lost = [...before].filter((e) => !after.has(e)).sort((a, b) => a.localeCompare(b));\n if (gained.length > 0 || lost.length > 0) {\n rewired.push({ ...describeSymbol(headGraph, id), gainedEdges: gained, lostEdges: lost });\n }\n }\n\n for (const id of [...baseIds].sort((a, b) => a.localeCompare(b))) {\n if (!headIds.has(id)) removed.push(describeSymbol(baseGraph, id));\n }\n\n return { base, head, added, removed, rewired };\n}\n\n/** Diff two revisions of the repo at `repoRoot`. `head` defaults to the working head via a second archive of HEAD. */\nexport async function reviewRevisions(repoRoot: string, base: string, head = 'HEAD'): Promise<GraphDiff> {\n const [baseDir, headDir] = await Promise.all([checkoutRev(repoRoot, base), checkoutRev(repoRoot, head)]);\n try {\n const [baseGraph, headGraph] = [await graphForDirectory(baseDir), await graphForDirectory(headDir)];\n return diffGraphs(baseGraph, headGraph, base, head);\n } finally {\n await Promise.all([\n fs.rm(baseDir, { recursive: true, force: true }),\n fs.rm(headDir, { recursive: true, force: true }),\n ]);\n }\n}\n\nexport function renderReview(diff: GraphDiff): string {\n const lines: string[] = [\n `# Structural review: ${diff.base}..${diff.head}`,\n '',\n `${diff.added.length} symbol(s) added, ${diff.removed.length} removed, ${diff.rewired.length} rewired.`,\n '',\n ];\n\n const section = (title: string, symbols: ChangedSymbol[]): void => {\n lines.push(`## ${title} (${symbols.length})`, '');\n if (symbols.length === 0) {\n lines.push('(none)', '');\n return;\n }\n for (const s of symbols) {\n const tests = s.tests.length > 0 ? ` | tests: ${s.tests.join(', ')}` : ' | tests: none found';\n lines.push(`- **${s.label}** (${s.sourceFile}) — blast radius ${s.blastRadius}${tests}`);\n const r = s as RewiredSymbol;\n if (r.gainedEdges) {\n for (const e of r.gainedEdges.slice(0, 5)) lines.push(` - gained: ${e}`);\n for (const e of r.lostEdges.slice(0, 5)) lines.push(` - lost: ${e}`);\n }\n }\n lines.push('');\n };\n\n section('Removed — check every caller', diff.removed);\n section('Rewired — dependencies changed', diff.rewired);\n section('Added', diff.added);\n\n const allTests = new Set<string>();\n for (const s of [...diff.removed, ...diff.rewired, ...diff.added]) {\n for (const t of s.tests) allTests.add(t);\n }\n lines.push(`## Suggested test run (${allTests.size} file(s))`, '');\n for (const t of [...allTests].sort((a, b) => a.localeCompare(b))) lines.push(`- ${t}`);\n lines.push('');\n\n return lines.join('\\n');\n}\n","import type Graph from 'graphology';\n\n/**\n * `graphify check` — architecture guardrails. Declarative dependency rules\n * checked against the graph's edges, with CI-friendly results: an agent (or\n * a pipeline) can verify an edit didn't violate the architecture before it\n * lands. Cross-language, because the graph already is.\n */\n\nexport interface DependencyRule {\n /** Short rule name shown in violations. */\n name: string;\n /** Glob over the depending file (edge source's sourceFile). */\n from: string;\n /** Globs the dependency target's file must NOT match. */\n disallow: string[];\n /** Optional human explanation echoed with violations. */\n reason?: string;\n}\n\nexport interface RulesConfig {\n rules: DependencyRule[];\n}\n\nexport interface Violation {\n rule: string;\n reason?: string;\n fromFile: string;\n fromNode: string;\n toFile: string;\n toNode: string;\n relation: string;\n}\n\n/** Relations that constitute a dependency for rule purposes. */\nconst DEPENDENCY_RELATIONS = new Set([\n 'calls', 'imports', 'imports_from', 'inherits', 'implements', 'mixes_in', 'embeds', 're_exports',\n]);\n\n/**\n * Minimal glob: `**` crosses directories, `*` stays within one segment.\n * Anchored on both ends. Enough for path rules without a dependency.\n */\nexport function globToRegExp(glob: string): RegExp {\n const escaped = glob.replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&');\n const pattern = escaped.replace(/\\*\\*|\\*|\\?/g, (token) =>\n token === '**' ? '.*' : token === '*' ? '[^/]*' : '[^/]',\n );\n return new RegExp(`^${pattern}$`);\n}\n\nexport function validateRules(value: unknown): RulesConfig {\n const config = value as RulesConfig;\n if (!config || !Array.isArray(config.rules)) {\n throw new Error('Rules file must be JSON of shape { \"rules\": [{ \"name\", \"from\", \"disallow\": [...] }] }');\n }\n for (const rule of config.rules) {\n if (!rule.name || typeof rule.from !== 'string' || !Array.isArray(rule.disallow)) {\n throw new Error(`Malformed rule \"${rule.name ?? '(unnamed)'}\" — need name, from, and disallow[].`);\n }\n }\n return config;\n}\n\n/** Check every dependency edge in the graph against the rules. Deterministic ordering. */\nexport function checkRules(graph: Graph, config: RulesConfig): Violation[] {\n const compiled = config.rules.map((rule) => ({\n rule,\n from: globToRegExp(rule.from),\n disallow: rule.disallow.map(globToRegExp),\n }));\n\n const violations: Violation[] = [];\n graph.forEachEdge((_edge, attrs, source, target) => {\n const relation = String(attrs.relation);\n if (!DEPENDENCY_RELATIONS.has(relation)) return;\n\n const fromFile = (graph.getNodeAttribute(source, 'sourceFile') as string | undefined) ?? '';\n const toFile = (graph.getNodeAttribute(target, 'sourceFile') as string | undefined) ?? '';\n if (!fromFile || !toFile || fromFile === toFile) return;\n\n for (const { rule, from, disallow } of compiled) {\n if (!from.test(fromFile)) continue;\n if (disallow.some((d) => d.test(toFile))) {\n violations.push({\n rule: rule.name,\n reason: rule.reason,\n fromFile,\n fromNode: source,\n toFile,\n toNode: target,\n relation,\n });\n }\n }\n });\n\n violations.sort(\n (a, b) =>\n a.rule.localeCompare(b.rule) ||\n a.fromFile.localeCompare(b.fromFile) ||\n a.toFile.localeCompare(b.toFile) ||\n a.fromNode.localeCompare(b.fromNode),\n );\n return violations;\n}\n"],"mappings":"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","names":["path","fs","path","require","fs","fs","fs","fs","fs","path","fs","path","stripQuotes","Graph","fs","path","CODE_EXTENSIONS","sep","import_graphology","Graph","leiden","louvain","labelOf","import_node_module","fs","path","import_node_crypto","fs","path","relative","require","fs","path","import_node_crypto","fs","path","fs","path","import_graphology","Graph","path","CONFIDENCE_RANK","import_graphology","CONFIDENCE_RANK","strongerConfidence","Graph","import_node_crypto","fs","path","DEFAULT_MAX_SEEDS","readFile","path","fs","path","resolve","DEPENDENCY_RELATIONS"]}
|