@abdulmunimjemal/codescope 0.1.0 → 0.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/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts","../src/format.ts","../src/indexer.ts","../src/languages.ts","../src/parser.ts","../src/mcp.ts","../src/version.ts","../src/store.ts","../src/watcher.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { mkdirSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport pc from \"picocolors\";\nimport * as fmt from \"./format.js\";\nimport { Indexer } from \"./indexer.js\";\nimport { runStdioServer } from \"./mcp.js\";\nimport { GraphStore } from \"./store.js\";\nimport type { SymbolKind } from \"./types.js\";\nimport { VERSION } from \"./version.js\";\nimport { watch } from \"./watcher.js\";\n\ninterface Flags {\n positional: string[];\n path?: string;\n db?: string;\n memory: boolean;\n kind?: string;\n limit?: number;\n depth?: number;\n}\n\nconst HELP = `codescope ${VERSION} — local-first codebase knowledge-graph MCP server\n\nUsage:\n codescope <command> [path] [options]\n\nCommands:\n mcp [path] Index, watch for changes, and serve the graph over MCP (stdio).\n This is what you wire into Claude Code / Cursor / Codex.\n index [path] Build (or refresh) the on-disk graph and print stats.\n watch [path] Index, then keep the graph fresh as files change (logs updates).\n stats [path] Show counts for the indexed graph.\n search <query> [path] Fuzzy-search symbol names.\n get <name> [path] Look up a definition by exact name.\n callers <name> [path] List callers of a function/method.\n neighborhood <name> Show the call neighbourhood around a symbol.\n\nOptions:\n --path <dir> Repository root (default: current directory or the positional path).\n --db <file> SQLite graph location (default: <root>/.codescope/graph.db).\n --memory Use an in-memory graph (not persisted).\n --kind <kind> Restrict search to: function|method|class|interface|type|enum|variable.\n --limit <n> Max results (default 50).\n --depth <n> neighbourhood hops (default 2).\n -h, --help Show this help.\n -v, --version Show version.\n\nExamples:\n codescope index .\n codescope search useState\n codescope neighborhood handleRequest --depth 3\n codescope mcp . # add this command to your agent's MCP config\n`;\n\nfunction parseArgs(argv: string[]): Flags {\n const flags: Flags = { positional: [], memory: false };\n for (let i = 0; i < argv.length; i++) {\n const arg = argv[i] as string;\n switch (arg) {\n case \"--memory\":\n flags.memory = true;\n break;\n case \"--path\":\n flags.path = argv[++i];\n break;\n case \"--db\":\n flags.db = argv[++i];\n break;\n case \"--kind\":\n flags.kind = argv[++i];\n break;\n case \"--limit\":\n flags.limit = Number(argv[++i]);\n break;\n case \"--depth\":\n flags.depth = Number(argv[++i]);\n break;\n default:\n flags.positional.push(arg);\n }\n }\n return flags;\n}\n\nfunction rootDir(flags: Flags, positionalRootIndex = 0): string {\n return resolve(flags.path ?? flags.positional[positionalRootIndex] ?? \".\");\n}\n\nfunction openStore(root: string, flags: Flags): GraphStore {\n if (flags.memory) return new GraphStore(\":memory:\");\n const dir = resolve(root, \".codescope\");\n mkdirSync(dir, { recursive: true });\n return new GraphStore(flags.db ?? resolve(dir, \"graph.db\"));\n}\n\n/** Ensure the graph is populated; index on demand for query commands. */\nasync function ensureIndexed(indexer: Indexer, store: GraphStore): Promise<void> {\n if (store.stats().files === 0) {\n await indexer.indexAll();\n }\n}\n\nasync function cmdIndex(root: string, flags: Flags): Promise<void> {\n const store = openStore(root, flags);\n const indexer = new Indexer(store, root);\n process.stderr.write(pc.dim(`Indexing ${root} …\\n`));\n const result = await indexer.indexAll();\n const { files, symbols, refs } = store.stats();\n process.stdout.write(\n `${pc.green(\"✓\")} indexed ${pc.bold(String(result.indexed))} files ` +\n `(${result.skipped} unchanged, ${result.removed} removed) in ${result.durationMs}ms\\n` +\n ` ${files} files · ${symbols} symbols · ${refs} refs\\n`,\n );\n if (result.errors.length > 0) {\n process.stderr.write(pc.yellow(` ${result.errors.length} file(s) failed to parse\\n`));\n }\n store.close();\n}\n\nasync function cmdStats(root: string, flags: Flags): Promise<void> {\n const store = openStore(root, flags);\n const indexer = new Indexer(store, root);\n await ensureIndexed(indexer, store);\n process.stdout.write(`${fmt.formatStats(store.stats())}\\n`);\n store.close();\n}\n\nasync function cmdQuery(command: string, root: string, flags: Flags): Promise<void> {\n const term = flags.positional[0];\n if (!term) fail(`'${command}' needs an argument. See --help.`);\n const store = openStore(root, flags);\n const indexer = new Indexer(store, root);\n await ensureIndexed(indexer, store);\n\n let out: string;\n switch (command) {\n case \"search\":\n out = fmt.formatSymbols(\n store.searchSymbols(term, { kind: flags.kind as SymbolKind | undefined, limit: flags.limit }),\n );\n break;\n case \"get\":\n out = fmt.formatSymbols(store.getSymbol(term, { limit: flags.limit }));\n break;\n case \"callers\":\n out = fmt.formatRefs(store.findCallers(term, { limit: flags.limit }));\n break;\n case \"neighborhood\":\n out = fmt.formatNeighborhood(store.neighborhood(term, { depth: flags.depth, limit: flags.limit }));\n break;\n default:\n out = \"\";\n }\n process.stdout.write(`${out}\\n`);\n store.close();\n}\n\nasync function cmdWatch(root: string, flags: Flags): Promise<void> {\n const store = openStore(root, flags);\n const indexer = new Indexer(store, root);\n process.stderr.write(pc.dim(`Indexing ${root} …\\n`));\n await indexer.indexAll();\n process.stderr.write(`${pc.green(\"✓\")} watching for changes (ctrl-c to stop)\\n`);\n watch(indexer, {\n onChange: (rel, action) =>\n process.stderr.write(`${action === \"indexed\" ? pc.cyan(\"↻\") : pc.red(\"✗\")} ${rel}\\n`),\n onError: (err) => process.stderr.write(pc.yellow(`watch error: ${String(err)}\\n`)),\n });\n await new Promise(() => {}); // run until interrupted\n}\n\nasync function cmdMcp(root: string, flags: Flags): Promise<void> {\n // stdout is the MCP transport — every human-readable byte must go to stderr.\n const store = openStore(root, flags);\n const indexer = new Indexer(store, root);\n process.stderr.write(pc.dim(`codescope: indexing ${root} …\\n`));\n const result = await indexer.indexAll();\n process.stderr.write(\n pc.dim(`codescope: ${result.indexed} files indexed, watching for changes\\n`),\n );\n watch(indexer, {\n onChange: (rel, action) => process.stderr.write(pc.dim(`codescope: ${action} ${rel}\\n`)),\n onError: (err) => process.stderr.write(pc.yellow(`codescope: watch error ${String(err)}\\n`)),\n });\n await runStdioServer(store);\n}\n\nfunction fail(message: string): never {\n process.stderr.write(`${pc.red(\"error:\")} ${message}\\n`);\n process.exit(1);\n}\n\nasync function main(): Promise<void> {\n const argv = process.argv.slice(2);\n if (argv.length === 0 || argv[0] === \"-h\" || argv[0] === \"--help\" || argv[0] === \"help\") {\n process.stdout.write(HELP);\n return;\n }\n if (argv[0] === \"-v\" || argv[0] === \"--version\" || argv[0] === \"version\") {\n process.stdout.write(`${VERSION}\\n`);\n return;\n }\n\n const command = argv[0] as string;\n const flags = parseArgs(argv.slice(1));\n\n switch (command) {\n case \"index\":\n return cmdIndex(rootDir(flags), flags);\n case \"stats\":\n return cmdStats(rootDir(flags), flags);\n case \"search\":\n case \"get\":\n case \"callers\":\n case \"neighborhood\":\n // positional[0] is the term; the optional repo path is positional[1].\n return cmdQuery(command, resolve(flags.path ?? flags.positional[1] ?? \".\"), flags);\n case \"watch\":\n return cmdWatch(rootDir(flags), flags);\n case \"mcp\":\n return cmdMcp(rootDir(flags), flags);\n default:\n fail(`unknown command '${command}'. See --help.`);\n }\n}\n\nmain().catch((err) => fail(err instanceof Error ? err.message : String(err)));\n","import type { IndexStats, Neighborhood, RefRow, SymbolRow } from \"./types.js\";\n\n/**\n * Compact, line-oriented renderers. The whole point of codescope is to hand an\n * agent the *answer* in as few tokens as possible, so these favour terse,\n * grep-like lines over verbose prose or JSON.\n */\n\nfunction symbolLine(s: SymbolRow): string {\n const loc = `${s.file}:${s.startRow + 1}`;\n const container = s.container ? `${s.container}.` : \"\";\n const exp = s.exported ? \"export \" : \"\";\n const sig = s.signature ? ` · ${s.signature}` : \"\";\n return `${s.kind} ${exp}${container}${s.name} — ${loc}${sig}`;\n}\n\nexport function formatSymbols(rows: SymbolRow[]): string {\n if (rows.length === 0) return \"No matching symbols.\";\n return rows.map(symbolLine).join(\"\\n\");\n}\n\nexport function formatRefs(rows: RefRow[]): string {\n if (rows.length === 0) return \"No references.\";\n return rows\n .map((r) => {\n const where = r.fromSymbol ? `${r.fromSymbol}` : \"(top level)\";\n return `${where} → ${r.name} [${r.kind}] — ${r.file}:${r.startRow + 1}`;\n })\n .join(\"\\n\");\n}\n\nexport function formatNeighborhood(n: Neighborhood): string {\n const lines: string[] = [`neighbourhood of ${n.root}:`];\n lines.push(\"\", \"definitions:\");\n if (n.nodes.length === 0) lines.push(\" (none indexed)\");\n else for (const s of n.nodes) lines.push(` ${symbolLine(s)}`);\n if (n.edges.length > 0) {\n lines.push(\"\", \"call edges:\");\n for (const e of n.edges) lines.push(` ${e.from} → ${e.to}`);\n }\n if (n.unresolved.length > 0) {\n lines.push(\"\", `unresolved (referenced, not defined in index): ${n.unresolved.join(\", \")}`);\n }\n return lines.join(\"\\n\");\n}\n\nexport function formatStats(s: IndexStats): string {\n const kinds = Object.entries(s.byKind)\n .sort((a, b) => b[1] - a[1])\n .map(([k, n]) => `${k}=${n}`)\n .join(\" \");\n const langs = Object.entries(s.byLang)\n .sort((a, b) => b[1] - a[1])\n .map(([k, n]) => `${k}=${n}`)\n .join(\" \");\n return [\n `files: ${s.files}`,\n `symbols: ${s.symbols} (${kinds || \"none\"})`,\n `refs: ${s.refs}`,\n `langs: ${langs || \"none\"}`,\n ].join(\"\\n\");\n}\n","import { createHash } from \"node:crypto\";\nimport { readFileSync } from \"node:fs\";\nimport { readFile, stat } from \"node:fs/promises\";\nimport { relative, resolve, sep } from \"node:path\";\nimport ignore, { type Ignore } from \"ignore\";\nimport { glob } from \"tinyglobby\";\nimport { SUPPORTED_EXTENSIONS, languageForPath } from \"./languages.js\";\nimport { parseSource } from \"./parser.js\";\nimport type { GraphStore } from \"./store.js\";\nimport type { IndexRunResult } from \"./types.js\";\n\n/** Directories never worth indexing, regardless of .gitignore. */\nconst DEFAULT_IGNORES = [\n \"**/node_modules/**\",\n \"**/.git/**\",\n \"**/dist/**\",\n \"**/build/**\",\n \"**/coverage/**\",\n \"**/.codescope/**\",\n \"**/.next/**\",\n \"**/out/**\",\n \"**/target/**\",\n \"**/.venv/**\",\n \"**/venv/**\",\n \"**/vendor/**\",\n \"**/__pycache__/**\",\n];\n\nexport interface IndexOptions {\n /** Extra glob patterns to ignore. */\n ignore?: string[];\n /** Honour the repo's root `.gitignore` (default: true). */\n gitignore?: boolean;\n}\n\nexport type FileIndexOutcome = \"indexed\" | \"skipped\" | \"unsupported\";\n\n/**\n * Walks a repository and keeps a {@link GraphStore} in sync with it. Every\n * operation is per-file and content-hash gated, so a full re-scan skips\n * unchanged files and a single-file update touches only that file.\n */\nexport class Indexer {\n readonly root: string;\n\n constructor(\n private readonly store: GraphStore,\n root: string,\n ) {\n this.root = resolve(root);\n }\n\n /** Index every supported, non-ignored file and prune deleted ones. */\n async indexAll(opts: IndexOptions = {}): Promise<IndexRunResult> {\n const start = Date.now();\n const result: IndexRunResult = {\n indexed: 0,\n skipped: 0,\n removed: 0,\n errors: [],\n durationMs: 0,\n };\n\n const files = await this.listSourceFiles(opts);\n const present = new Set<string>();\n\n for (const abs of files) {\n present.add(this.rel(abs));\n try {\n const outcome = await this.indexFile(abs, start);\n if (outcome === \"indexed\") result.indexed++;\n else if (outcome === \"skipped\") result.skipped++;\n } catch (err) {\n result.errors.push({ file: this.rel(abs), error: errorMessage(err) });\n }\n }\n\n for (const known of this.store.listFiles()) {\n if (!present.has(known) && this.store.removeFile(known)) result.removed++;\n }\n\n result.durationMs = Date.now() - start;\n return result;\n }\n\n /** Index a single file by absolute path. Cheap when the content is unchanged. */\n async indexFile(abs: string, now = Date.now()): Promise<FileIndexOutcome> {\n const lang = languageForPath(abs);\n if (!lang) return \"unsupported\";\n\n const rel = this.rel(abs);\n const content = await readFile(abs, \"utf8\");\n const hash = sha1(content);\n if (this.store.getFileHash(rel) === hash) return \"skipped\";\n\n const mtime = await fileMtime(abs, now);\n const { symbols, refs } = await parseSource(lang.id, content);\n this.store.replaceFile(\n { path: rel, lang: lang.id, hash, size: content.length, mtime },\n symbols,\n refs,\n now,\n );\n return \"indexed\";\n }\n\n /** Drop a file from the graph by absolute path. */\n removeFile(abs: string): boolean {\n return this.store.removeFile(this.rel(abs));\n }\n\n /** Repo-relative, POSIX-separated path used as the stable graph key. */\n rel(abs: string): string {\n return relative(this.root, resolve(abs)).split(sep).join(\"/\");\n }\n\n private async listSourceFiles(opts: IndexOptions): Promise<string[]> {\n const patterns = SUPPORTED_EXTENSIONS.map((ext) => `**/*${ext}`);\n const files = await glob(patterns, {\n cwd: this.root,\n absolute: true,\n ignore: [...DEFAULT_IGNORES, ...(opts.ignore ?? [])],\n dot: false,\n });\n\n if (opts.gitignore === false) return files;\n const ig = this.loadGitignore();\n if (!ig) return files;\n return files.filter((f) => {\n const rel = this.rel(f);\n return rel.length > 0 && !ig.ignores(rel);\n });\n }\n\n private loadGitignore(): Ignore | null {\n try {\n const content = readFileSync(resolve(this.root, \".gitignore\"), \"utf8\");\n return ignore().add(content);\n } catch {\n return null;\n }\n }\n}\n\nfunction sha1(content: string): string {\n return createHash(\"sha1\").update(content).digest(\"hex\");\n}\n\nasync function fileMtime(abs: string, fallback: number): Promise<number> {\n try {\n const st = await stat(abs);\n return Math.floor(st.mtimeMs);\n } catch {\n return fallback;\n }\n}\n\nfunction errorMessage(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n","import type { SymbolKind } from \"./types.js\";\n\n/**\n * Per-language configuration driving the AST walk in {@link ./parser.ts}.\n *\n * Rather than maintain a tree-sitter query (`.scm`) per grammar, we walk the\n * tree once and classify nodes by `type` using these tables. Grammars disagree\n * on a lot — C buries a function's name inside nested declarators, Java and Ruby\n * hang the callee straight off the call node, Go/Rust/C++ each use a different\n * \"member access\" node — so definitions, calls, and imports are all described\n * declaratively here and interpreted by a single generic walker.\n */\n\nexport type NameStrategy = \"field\" | \"c_declarator\";\n\nexport interface DefRule {\n kind: SymbolKind;\n /** How to read the definition's name (default: the `name` field). */\n name?: NameStrategy;\n}\n\nexport interface CallRule {\n /** AST node type for this kind of call. */\n type: string;\n /** Field holding the callee expression (for `foo()` / `a.foo()` forms). */\n fnField?: string;\n /** Callee-expression node types that mean \"method call\". */\n memberTypes?: string[];\n /** Field on a member node holding the method name. */\n memberField?: string;\n /** Callee-expression node types that are path-qualified (`a::b`). */\n scopedTypes?: string[];\n /** Field on a scoped node holding the final name. */\n scopedField?: string;\n /** The call node holds the callee name directly in this field (Java/Ruby). */\n nameField?: string;\n /** Presence of this field on the call node marks it a method call. */\n receiverField?: string;\n /** Force the ref kind regardless of shape. */\n forceKind?: \"call\" | \"method\";\n}\n\nexport interface ImportRule {\n type: string;\n /** Read the import target from this field's text. */\n field?: string;\n /** Collect import targets from named children of these types. */\n childTypes?: string[];\n}\n\nexport interface LanguageConfig {\n id: string;\n wasm: string;\n defs: Record<string, DefRule>;\n /** Bindings (`const x = …`) that become `function` symbols when assigned a function. */\n functionBindings: Set<string>;\n /** A nested `function` whose enclosing definition is a class becomes a `method`. */\n nestedFunctionsAreMethods: boolean;\n callRules: CallRule[];\n importRules: ImportRule[];\n /** Node types whose presence as an ancestor marks a definition as exported. */\n exportTypes: Set<string>;\n}\n\nconst JS_CALLS: CallRule[] = [\n { type: \"call_expression\", fnField: \"function\", memberTypes: [\"member_expression\"], memberField: \"property\" },\n];\n\nconst typescript: LanguageConfig = {\n id: \"typescript\",\n wasm: \"typescript\",\n defs: {\n function_declaration: { kind: \"function\" },\n generator_function_declaration: { kind: \"function\" },\n function_signature: { kind: \"function\" },\n method_definition: { kind: \"method\" },\n method_signature: { kind: \"method\" },\n class_declaration: { kind: \"class\" },\n abstract_class_declaration: { kind: \"class\" },\n interface_declaration: { kind: \"interface\" },\n type_alias_declaration: { kind: \"type\" },\n enum_declaration: { kind: \"enum\" },\n },\n functionBindings: new Set([\"variable_declarator\", \"public_field_definition\"]),\n nestedFunctionsAreMethods: false,\n callRules: JS_CALLS,\n importRules: [{ type: \"import_statement\", field: \"source\" }],\n exportTypes: new Set([\"export_statement\"]),\n};\n\nconst tsx: LanguageConfig = { ...typescript, id: \"tsx\", wasm: \"tsx\" };\n\nconst javascript: LanguageConfig = {\n id: \"javascript\",\n wasm: \"javascript\",\n defs: {\n function_declaration: { kind: \"function\" },\n generator_function_declaration: { kind: \"function\" },\n method_definition: { kind: \"method\" },\n class_declaration: { kind: \"class\" },\n },\n functionBindings: new Set([\"variable_declarator\", \"field_definition\"]),\n nestedFunctionsAreMethods: false,\n callRules: JS_CALLS,\n importRules: [{ type: \"import_statement\", field: \"source\" }],\n exportTypes: new Set([\"export_statement\"]),\n};\n\nconst python: LanguageConfig = {\n id: \"python\",\n wasm: \"python\",\n defs: {\n function_definition: { kind: \"function\" },\n class_definition: { kind: \"class\" },\n },\n functionBindings: new Set(),\n nestedFunctionsAreMethods: false,\n callRules: [{ type: \"call\", fnField: \"function\", memberTypes: [\"attribute\"], memberField: \"attribute\" }],\n importRules: [\n { type: \"import_statement\", childTypes: [\"dotted_name\", \"aliased_import\"] },\n { type: \"import_from_statement\", field: \"module_name\" },\n ],\n exportTypes: new Set(),\n};\n\nconst go: LanguageConfig = {\n id: \"go\",\n wasm: \"go\",\n defs: {\n function_declaration: { kind: \"function\" },\n method_declaration: { kind: \"method\" },\n type_spec: { kind: \"class\" },\n },\n functionBindings: new Set(),\n nestedFunctionsAreMethods: false,\n callRules: [\n { type: \"call_expression\", fnField: \"function\", memberTypes: [\"selector_expression\"], memberField: \"field\" },\n ],\n importRules: [{ type: \"import_spec\", field: \"path\" }],\n exportTypes: new Set(),\n};\n\nconst rust: LanguageConfig = {\n id: \"rust\",\n wasm: \"rust\",\n defs: {\n function_item: { kind: \"function\" },\n struct_item: { kind: \"class\" },\n union_item: { kind: \"class\" },\n enum_item: { kind: \"enum\" },\n trait_item: { kind: \"interface\" },\n type_item: { kind: \"type\" },\n },\n functionBindings: new Set(),\n nestedFunctionsAreMethods: false,\n callRules: [\n {\n type: \"call_expression\",\n fnField: \"function\",\n memberTypes: [\"field_expression\"],\n memberField: \"field\",\n scopedTypes: [\"scoped_identifier\"],\n scopedField: \"name\",\n },\n ],\n importRules: [{ type: \"use_declaration\", field: \"argument\" }],\n exportTypes: new Set(),\n};\n\nconst java: LanguageConfig = {\n id: \"java\",\n wasm: \"java\",\n defs: {\n class_declaration: { kind: \"class\" },\n interface_declaration: { kind: \"interface\" },\n enum_declaration: { kind: \"enum\" },\n record_declaration: { kind: \"class\" },\n method_declaration: { kind: \"method\" },\n constructor_declaration: { kind: \"method\" },\n },\n functionBindings: new Set(),\n nestedFunctionsAreMethods: false,\n callRules: [{ type: \"method_invocation\", nameField: \"name\", receiverField: \"object\" }],\n importRules: [{ type: \"import_declaration\", childTypes: [\"scoped_identifier\", \"identifier\"] }],\n exportTypes: new Set(),\n};\n\nconst ruby: LanguageConfig = {\n id: \"ruby\",\n wasm: \"ruby\",\n defs: {\n method: { kind: \"method\" },\n singleton_method: { kind: \"method\" },\n class: { kind: \"class\" },\n module: { kind: \"class\" },\n },\n functionBindings: new Set(),\n nestedFunctionsAreMethods: false,\n callRules: [{ type: \"call\", nameField: \"method\", receiverField: \"receiver\" }],\n importRules: [],\n exportTypes: new Set(),\n};\n\nconst c: LanguageConfig = {\n id: \"c\",\n wasm: \"c\",\n defs: {\n function_definition: { kind: \"function\", name: \"c_declarator\" },\n struct_specifier: { kind: \"class\" },\n union_specifier: { kind: \"class\" },\n enum_specifier: { kind: \"enum\" },\n },\n functionBindings: new Set(),\n nestedFunctionsAreMethods: false,\n callRules: [\n { type: \"call_expression\", fnField: \"function\", memberTypes: [\"field_expression\"], memberField: \"field\" },\n ],\n importRules: [{ type: \"preproc_include\", field: \"path\" }],\n exportTypes: new Set(),\n};\n\nconst cpp: LanguageConfig = {\n id: \"cpp\",\n wasm: \"cpp\",\n defs: {\n function_definition: { kind: \"function\", name: \"c_declarator\" },\n class_specifier: { kind: \"class\" },\n struct_specifier: { kind: \"class\" },\n enum_specifier: { kind: \"enum\" },\n },\n functionBindings: new Set(),\n nestedFunctionsAreMethods: true,\n callRules: [\n { type: \"call_expression\", fnField: \"function\", memberTypes: [\"field_expression\"], memberField: \"field\" },\n ],\n importRules: [{ type: \"preproc_include\", field: \"path\" }],\n exportTypes: new Set(),\n};\n\nconst csharp: LanguageConfig = {\n id: \"csharp\",\n wasm: \"c_sharp\",\n defs: {\n class_declaration: { kind: \"class\" },\n struct_declaration: { kind: \"class\" },\n interface_declaration: { kind: \"interface\" },\n enum_declaration: { kind: \"enum\" },\n record_declaration: { kind: \"class\" },\n method_declaration: { kind: \"method\" },\n constructor_declaration: { kind: \"method\" },\n },\n functionBindings: new Set(),\n nestedFunctionsAreMethods: false,\n callRules: [\n {\n type: \"invocation_expression\",\n fnField: \"function\",\n memberTypes: [\"member_access_expression\"],\n memberField: \"name\",\n },\n ],\n importRules: [{ type: \"using_directive\", childTypes: [\"identifier\", \"qualified_name\"] }],\n exportTypes: new Set(),\n};\n\nconst php: LanguageConfig = {\n id: \"php\",\n wasm: \"php\",\n defs: {\n function_definition: { kind: \"function\" },\n method_declaration: { kind: \"method\" },\n class_declaration: { kind: \"class\" },\n interface_declaration: { kind: \"interface\" },\n trait_declaration: { kind: \"class\" },\n enum_declaration: { kind: \"enum\" },\n },\n functionBindings: new Set(),\n nestedFunctionsAreMethods: false,\n callRules: [\n { type: \"function_call_expression\", fnField: \"function\" },\n { type: \"member_call_expression\", nameField: \"name\", forceKind: \"method\" },\n { type: \"scoped_call_expression\", nameField: \"name\", forceKind: \"method\" },\n ],\n importRules: [{ type: \"namespace_use_declaration\", childTypes: [\"namespace_use_clause\"] }],\n exportTypes: new Set(),\n};\n\n/** All languages codescope can parse, keyed by config id. */\nexport const LANGUAGES: Record<string, LanguageConfig> = {\n typescript,\n tsx,\n javascript,\n python,\n go,\n rust,\n java,\n ruby,\n c,\n cpp,\n csharp,\n php,\n};\n\n/** File extension → language id. */\nconst EXT_TO_LANG: Record<string, string> = {\n \".ts\": \"typescript\",\n \".mts\": \"typescript\",\n \".cts\": \"typescript\",\n \".tsx\": \"tsx\",\n \".js\": \"javascript\",\n \".mjs\": \"javascript\",\n \".cjs\": \"javascript\",\n \".jsx\": \"javascript\",\n \".py\": \"python\",\n \".pyi\": \"python\",\n \".go\": \"go\",\n \".rs\": \"rust\",\n \".java\": \"java\",\n \".rb\": \"ruby\",\n \".c\": \"c\",\n \".h\": \"c\",\n \".cc\": \"cpp\",\n \".cpp\": \"cpp\",\n \".cxx\": \"cpp\",\n \".hpp\": \"cpp\",\n \".hh\": \"cpp\",\n \".cs\": \"csharp\",\n \".php\": \"php\",\n};\n\n/** The set of file extensions codescope indexes (with leading dot). */\nexport const SUPPORTED_EXTENSIONS: readonly string[] = Object.keys(EXT_TO_LANG);\n\n/** Resolve a language config from a file path, or `undefined` if unsupported. */\nexport function languageForPath(path: string): LanguageConfig | undefined {\n const dot = path.lastIndexOf(\".\");\n if (dot === -1) return undefined;\n const ext = path.slice(dot).toLowerCase();\n const id = EXT_TO_LANG[ext];\n return id ? LANGUAGES[id] : undefined;\n}\n","import { createRequire } from \"node:module\";\nimport Parser from \"web-tree-sitter\";\nimport {\n LANGUAGES,\n type CallRule,\n type DefRule,\n type ImportRule,\n type LanguageConfig,\n} from \"./languages.js\";\nimport type { ParsedRef, ParsedSymbol, ParseResult, SymbolKind } from \"./types.js\";\n\nconst require = createRequire(import.meta.url);\n\nlet initPromise: Promise<void> | null = null;\nconst parserCache = new Map<string, Parser>();\n\n/** Resolve a grammar wasm shipped by `tree-sitter-wasms`. */\nfunction grammarPath(wasm: string): string {\n return require.resolve(`tree-sitter-wasms/out/tree-sitter-${wasm}.wasm`);\n}\n\nasync function ensureInit(): Promise<void> {\n if (!initPromise) initPromise = Parser.init();\n await initPromise;\n}\n\n/** Lazily load (and cache) a configured parser for a language. */\nasync function getParser(lang: LanguageConfig): Promise<Parser> {\n const cached = parserCache.get(lang.id);\n if (cached) return cached;\n await ensureInit();\n const language = await Parser.Language.load(grammarPath(lang.wasm));\n const parser = new Parser();\n parser.setLanguage(language);\n parserCache.set(lang.id, parser);\n return parser;\n}\n\nconst FUNCTION_VALUE_TYPES = new Set([\n \"arrow_function\",\n \"function\",\n \"function_expression\",\n \"generator_function\",\n]);\n\n/** Parse a source string into symbols and references. */\nexport async function parseSource(langId: string, source: string): Promise<ParseResult> {\n const lang = LANGUAGES[langId];\n if (!lang) throw new Error(`Unknown language: ${langId}`);\n const parser = await getParser(lang);\n const tree = parser.parse(source);\n const symbols: ParsedSymbol[] = [];\n const refs: ParsedRef[] = [];\n if (tree?.rootNode) {\n walk(tree.rootNode, lang, null, null, symbols, refs);\n tree.delete();\n }\n return { lang: lang.id, symbols, refs };\n}\n\nfunction walk(\n node: Parser.SyntaxNode,\n lang: LanguageConfig,\n container: string | null,\n containerKind: SymbolKind | null,\n symbols: ParsedSymbol[],\n refs: ParsedRef[],\n): void {\n let childContainer = container;\n let childContainerKind = containerKind;\n\n const rule = classify(node, lang);\n const call = lang.callRules.find((r) => r.type === node.type);\n const imp = lang.importRules.find((r) => r.type === node.type);\n\n if (rule) {\n const sym = buildSymbol(node, rule, container, containerKind, lang);\n if (sym) {\n symbols.push(sym);\n childContainer = sym.name;\n childContainerKind = sym.kind;\n }\n } else if (call) {\n const ref = extractCall(node, call, container);\n if (ref) refs.push(ref);\n } else if (imp) {\n for (const ref of extractImports(node, imp, container)) refs.push(ref);\n }\n\n for (const child of node.namedChildren) {\n walk(child, lang, childContainer, childContainerKind, symbols, refs);\n }\n}\n\nfunction classify(node: Parser.SyntaxNode, lang: LanguageConfig): DefRule | null {\n const direct = lang.defs[node.type];\n if (direct) return direct;\n if (lang.functionBindings.has(node.type)) {\n const value = node.childForFieldName(\"value\");\n if (value && FUNCTION_VALUE_TYPES.has(value.type)) return { kind: \"function\" };\n }\n return null;\n}\n\nfunction buildSymbol(\n node: Parser.SyntaxNode,\n rule: DefRule,\n container: string | null,\n containerKind: SymbolKind | null,\n lang: LanguageConfig,\n): ParsedSymbol | null {\n const name = symbolName(node, rule.name ?? \"field\");\n if (!name) return null;\n let kind = rule.kind;\n if (kind === \"function\" && lang.nestedFunctionsAreMethods && containerKind === \"class\") {\n kind = \"method\";\n }\n return {\n name,\n kind,\n container,\n exported: isExported(node, lang),\n signature: signatureOf(node),\n startRow: node.startPosition.row,\n startCol: node.startPosition.column,\n endRow: node.endPosition.row,\n endCol: node.endPosition.column,\n startByte: node.startIndex,\n endByte: node.endIndex,\n };\n}\n\nfunction symbolName(node: Parser.SyntaxNode, strategy: DefRule[\"name\"]): string | null {\n if (strategy === \"c_declarator\") return cDeclaratorName(node);\n return node.childForFieldName(\"name\")?.text ?? null;\n}\n\n/** Dig through C/C++ declarator chains (`int *foo(...)`) to the actual name. */\nfunction cDeclaratorName(node: Parser.SyntaxNode): string | null {\n let decl = node.childForFieldName(\"declarator\");\n for (let i = 0; decl && i < 10; i++) {\n if (decl.type === \"identifier\" || decl.type === \"field_identifier\") return decl.text;\n if (decl.type === \"qualified_identifier\" || decl.type === \"destructor_name\") {\n return decl.childForFieldName(\"name\")?.text ?? decl.text;\n }\n const inner = decl.childForFieldName(\"declarator\");\n if (!inner) break;\n decl = inner;\n }\n return null;\n}\n\n/** A definition is exported if an `export` statement directly wraps it. */\nfunction isExported(node: Parser.SyntaxNode, lang: LanguageConfig): boolean {\n if (lang.exportTypes.size === 0) return false;\n let cur = node.parent;\n for (let i = 0; cur && i < 2; i++) {\n if (lang.exportTypes.has(cur.type)) return true;\n cur = cur.parent;\n }\n return false;\n}\n\n/** The declaration text up to (but not including) the body, on one line. */\nfunction signatureOf(node: Parser.SyntaxNode): string | null {\n const body = node.childForFieldName(\"body\");\n const raw = body\n ? node.text.slice(0, body.startIndex - node.startIndex)\n : node.text;\n const text = raw.replace(/\\s+/g, \" \").trim();\n if (!text) return null;\n return text.length > 240 ? `${text.slice(0, 239)}…` : text;\n}\n\nfunction extractCall(\n node: Parser.SyntaxNode,\n rule: CallRule,\n container: string | null,\n): ParsedRef | null {\n let name: string | null = null;\n let kind: \"call\" | \"method\" = \"call\";\n\n if (rule.nameField) {\n // The call node carries the callee name directly (Java/Ruby/PHP member).\n name = node.childForFieldName(rule.nameField)?.text ?? null;\n if (rule.receiverField && node.childForFieldName(rule.receiverField)) kind = \"method\";\n } else if (rule.fnField) {\n const fn = node.childForFieldName(rule.fnField);\n if (fn) {\n if (rule.memberTypes?.includes(fn.type)) {\n name = fn.childForFieldName(rule.memberField ?? \"\")?.text ?? null;\n kind = \"method\";\n } else if (rule.scopedTypes?.includes(fn.type)) {\n name = fn.childForFieldName(rule.scopedField ?? \"\")?.text ?? null;\n } else if (fn.type === \"identifier\" || fn.type === \"name\") {\n name = fn.text;\n }\n }\n }\n\n if (rule.forceKind) kind = rule.forceKind;\n if (!name) return null;\n return {\n fromSymbol: container,\n name,\n kind,\n startRow: node.startPosition.row,\n startCol: node.startPosition.column,\n };\n}\n\nfunction extractImports(\n node: Parser.SyntaxNode,\n rule: ImportRule,\n container: string | null,\n): ParsedRef[] {\n const out: ParsedRef[] = [];\n const add = (spec: string | null | undefined): void => {\n const name = spec ? unquote(spec) : \"\";\n if (name) {\n out.push({\n fromSymbol: container,\n name,\n kind: \"import\",\n startRow: node.startPosition.row,\n startCol: node.startPosition.column,\n });\n }\n };\n\n if (rule.field) {\n add(node.childForFieldName(rule.field)?.text);\n }\n if (rule.childTypes) {\n for (const child of node.namedChildren) {\n if (!rule.childTypes.includes(child.type)) continue;\n // python `import x as y` exposes the real module under the `name` field\n if (child.type === \"aliased_import\") add(child.childForFieldName(\"name\")?.text);\n else add(child.text);\n }\n }\n return out;\n}\n\nfunction unquote(text: string): string {\n const t = text.trim();\n if (t.length >= 2) {\n const first = t[0];\n const last = t[t.length - 1];\n if ((first === '\"' || first === \"'\" || first === \"`\") && first === last) {\n return t.slice(1, -1);\n }\n // C/C++ include targets: <stdio.h>\n if (first === \"<\" && last === \">\") return t.slice(1, -1);\n }\n return t;\n}\n\n/** Test helper: drop cached parsers so a fresh init can be exercised. */\nexport function _resetParsers(): void {\n parserCache.clear();\n initPromise = null;\n}\n","import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { z } from \"zod\";\nimport * as fmt from \"./format.js\";\nimport type { GraphStore } from \"./store.js\";\nimport { VERSION } from \"./version.js\";\n\nconst KIND = z.enum([\"function\", \"method\", \"class\", \"interface\", \"type\", \"enum\", \"variable\"]);\n\nfunction textResult(text: string): { content: Array<{ type: \"text\"; text: string }> } {\n return { content: [{ type: \"text\", text }] };\n}\n\n/**\n * Build the codescope MCP server over an already-populated {@link GraphStore}.\n * Tool descriptions are written *for the agent*: they nudge it to query the\n * graph instead of grepping and reading whole files.\n */\nexport function createServer(store: GraphStore): McpServer {\n const server = new McpServer({ name: \"codescope\", version: VERSION });\n\n server.registerTool(\n \"search_symbols\",\n {\n title: \"Search code symbols\",\n description:\n \"Fuzzy-search definitions (functions, classes, methods, interfaces, types, enums) by name across the whole repo. Prefer this over grep/glob/read when locating where something is defined — it returns exact file:line locations and signatures in a few tokens.\",\n inputSchema: {\n query: z.string().describe(\"substring to match against symbol names\"),\n kind: KIND.optional().describe(\"restrict to one symbol kind\"),\n limit: z.number().int().positive().max(500).optional(),\n },\n },\n async ({ query, kind, limit }) =>\n textResult(fmt.formatSymbols(store.searchSymbols(query, { kind, limit }))),\n );\n\n server.registerTool(\n \"get_symbol\",\n {\n title: \"Get a symbol definition\",\n description:\n \"Look up a definition by its exact name. Returns each matching definition's kind, file:line, and signature. Use this to jump straight to a definition instead of reading files.\",\n inputSchema: {\n name: z.string().describe(\"exact symbol name\"),\n limit: z.number().int().positive().max(500).optional(),\n },\n },\n async ({ name, limit }) => textResult(fmt.formatSymbols(store.getSymbol(name, { limit }))),\n );\n\n server.registerTool(\n \"find_callers\",\n {\n title: \"Find callers\",\n description:\n \"List the symbols that call a given function/method name, with file:line. Use this to trace impact and call sites without scanning files.\",\n inputSchema: {\n name: z.string().describe(\"the called function/method name\"),\n limit: z.number().int().positive().max(500).optional(),\n },\n },\n async ({ name, limit }) => textResult(fmt.formatRefs(store.findCallers(name, { limit }))),\n );\n\n server.registerTool(\n \"find_references\",\n {\n title: \"Find references\",\n description:\n \"List all references (calls and imports) to a name. Useful for understanding how widely something is used.\",\n inputSchema: {\n name: z.string(),\n kind: z.enum([\"call\", \"method\", \"import\"]).optional(),\n limit: z.number().int().positive().max(500).optional(),\n },\n },\n async ({ name, kind, limit }) =>\n textResult(fmt.formatRefs(store.findReferences(name, { kind, limit }))),\n );\n\n server.registerTool(\n \"file_outline\",\n {\n title: \"Outline a file\",\n description:\n \"List every symbol defined in a file, in source order, with signatures. A compact alternative to reading the whole file when you only need its shape.\",\n inputSchema: {\n path: z.string().describe(\"repo-relative file path\"),\n },\n },\n async ({ path }) => textResult(fmt.formatSymbols(store.fileOutline(path))),\n );\n\n server.registerTool(\n \"neighborhood\",\n {\n title: \"Call neighbourhood\",\n description:\n \"Return the call neighbourhood around a symbol — its callers and callees expanded a few hops — as a compact subgraph. This is the high-leverage tool: it gives you the relevant slice of the codebase for a change without reading dozens of files.\",\n inputSchema: {\n name: z.string(),\n depth: z.number().int().min(1).max(5).optional().describe(\"hops to expand (default 2)\"),\n limit: z.number().int().positive().max(200).optional(),\n },\n },\n async ({ name, depth, limit }) =>\n textResult(fmt.formatNeighborhood(store.neighborhood(name, { depth, limit }))),\n );\n\n server.registerTool(\n \"stats\",\n {\n title: \"Graph stats\",\n description: \"Summary counts for the indexed graph (files, symbols, refs, by kind and language).\",\n inputSchema: {},\n },\n async () => textResult(fmt.formatStats(store.stats())),\n );\n\n return server;\n}\n\n/** Connect a codescope server to stdio (the transport coding agents speak). */\nexport async function runStdioServer(store: GraphStore): Promise<void> {\n const server = createServer(store);\n const transport = new StdioServerTransport();\n await server.connect(transport);\n}\n","/** The codescope version. Kept in sync with package.json at release time. */\nexport const VERSION = \"0.1.0\";\n","import Database from \"better-sqlite3\";\nimport type {\n IndexStats,\n Neighborhood,\n ParsedRef,\n ParsedSymbol,\n RefRow,\n SymbolKind,\n SymbolRow,\n} from \"./types.js\";\n\nexport interface FileMeta {\n path: string;\n lang: string;\n hash: string;\n size: number;\n mtime: number;\n}\n\nconst SCHEMA = `\nCREATE TABLE IF NOT EXISTS files (\n id INTEGER PRIMARY KEY,\n path TEXT NOT NULL UNIQUE,\n lang TEXT NOT NULL,\n hash TEXT NOT NULL,\n size INTEGER NOT NULL,\n mtime INTEGER NOT NULL,\n indexed_at INTEGER NOT NULL\n);\nCREATE TABLE IF NOT EXISTS symbols (\n id INTEGER PRIMARY KEY,\n file_id INTEGER NOT NULL REFERENCES files(id) ON DELETE CASCADE,\n name TEXT NOT NULL,\n kind TEXT NOT NULL,\n container TEXT,\n exported INTEGER NOT NULL DEFAULT 0,\n signature TEXT,\n start_row INTEGER NOT NULL,\n start_col INTEGER NOT NULL,\n end_row INTEGER NOT NULL,\n end_col INTEGER NOT NULL,\n start_byte INTEGER NOT NULL,\n end_byte INTEGER NOT NULL\n);\nCREATE TABLE IF NOT EXISTS refs (\n id INTEGER PRIMARY KEY,\n file_id INTEGER NOT NULL REFERENCES files(id) ON DELETE CASCADE,\n from_symbol TEXT,\n name TEXT NOT NULL,\n kind TEXT NOT NULL,\n start_row INTEGER NOT NULL,\n start_col INTEGER NOT NULL\n);\nCREATE INDEX IF NOT EXISTS idx_symbols_name ON symbols(name);\nCREATE INDEX IF NOT EXISTS idx_symbols_file ON symbols(file_id);\nCREATE INDEX IF NOT EXISTS idx_symbols_kind ON symbols(kind);\nCREATE INDEX IF NOT EXISTS idx_refs_name ON refs(name);\nCREATE INDEX IF NOT EXISTS idx_refs_file ON refs(file_id);\nCREATE INDEX IF NOT EXISTS idx_refs_from ON refs(from_symbol);\n\n-- Trigram FTS index for fast substring symbol search at scale. Kept in sync\n-- manually (rowid = symbols.id) so it survives the per-file replace/delete path.\nCREATE VIRTUAL TABLE IF NOT EXISTS symbols_fts USING fts5(name, tokenize='trigram');\n`;\n\ninterface SymbolDbRow {\n id: number;\n file: string;\n name: string;\n kind: string;\n container: string | null;\n exported: number;\n signature: string | null;\n start_row: number;\n start_col: number;\n end_row: number;\n end_col: number;\n}\n\ninterface RefDbRow {\n id: number;\n file: string;\n from_symbol: string | null;\n name: string;\n kind: string;\n start_row: number;\n start_col: number;\n}\n\nconst SYMBOL_COLUMNS = `\n s.id, f.path AS file, s.name, s.kind, s.container, s.exported, s.signature,\n s.start_row, s.start_col, s.end_row, s.end_col`;\n\n/**\n * The on-disk (or in-memory) code graph. All writes go through\n * {@link GraphStore.replaceFile} / {@link GraphStore.removeFile}, which operate\n * on a single file at a time so incremental updates stay O(file), not O(repo).\n */\nexport class GraphStore {\n readonly db: Database.Database;\n\n constructor(location = \":memory:\") {\n this.db = new Database(location);\n this.db.pragma(\"journal_mode = WAL\");\n this.db.pragma(\"foreign_keys = ON\");\n this.db.exec(SCHEMA);\n }\n\n /** The content hash of an already-indexed file, if present. */\n getFileHash(path: string): string | undefined {\n const row = this.db\n .prepare<[string], { hash: string }>(\"SELECT hash FROM files WHERE path = ?\")\n .get(path);\n return row?.hash;\n }\n\n /** All indexed file paths. */\n listFiles(): string[] {\n return this.db\n .prepare<[], { path: string }>(\"SELECT path FROM files ORDER BY path\")\n .all()\n .map((r) => r.path);\n }\n\n /** Insert or replace a file and all of its symbols/refs in one transaction. */\n replaceFile(meta: FileMeta, symbols: ParsedSymbol[], refs: ParsedRef[], now: number): void {\n this.transaction(() => {\n this.dropFtsForFile(meta.path);\n this.db.prepare(\"DELETE FROM files WHERE path = ?\").run(meta.path);\n const fileId = Number(\n this.db\n .prepare(\n \"INSERT INTO files (path, lang, hash, size, mtime, indexed_at) VALUES (?, ?, ?, ?, ?, ?)\",\n )\n .run(meta.path, meta.lang, meta.hash, meta.size, meta.mtime, now).lastInsertRowid,\n );\n\n const insSym = this.db.prepare(\n `INSERT INTO symbols\n (file_id, name, kind, container, exported, signature,\n start_row, start_col, end_row, end_col, start_byte, end_byte)\n VALUES (@file_id, @name, @kind, @container, @exported, @signature,\n @start_row, @start_col, @end_row, @end_col, @start_byte, @end_byte)`,\n );\n const insFts = this.db.prepare(\"INSERT INTO symbols_fts(rowid, name) VALUES (?, ?)\");\n for (const s of symbols) {\n const symId = insSym.run({\n file_id: fileId,\n name: s.name,\n kind: s.kind,\n container: s.container,\n exported: s.exported ? 1 : 0,\n signature: s.signature,\n start_row: s.startRow,\n start_col: s.startCol,\n end_row: s.endRow,\n end_col: s.endCol,\n start_byte: s.startByte,\n end_byte: s.endByte,\n }).lastInsertRowid;\n insFts.run(symId, s.name);\n }\n\n const insRef = this.db.prepare(\n `INSERT INTO refs (file_id, from_symbol, name, kind, start_row, start_col)\n VALUES (@file_id, @from_symbol, @name, @kind, @start_row, @start_col)`,\n );\n for (const r of refs) {\n insRef.run({\n file_id: fileId,\n from_symbol: r.fromSymbol,\n name: r.name,\n kind: r.kind,\n start_row: r.startRow,\n start_col: r.startCol,\n });\n }\n });\n }\n\n /** Remove a file and its symbols/refs. Returns true if anything was deleted. */\n removeFile(path: string): boolean {\n return this.transactionResult(() => {\n this.dropFtsForFile(path);\n return this.db.prepare(\"DELETE FROM files WHERE path = ?\").run(path).changes > 0;\n });\n }\n\n /** Remove the FTS rows for a file's current symbols (call before deleting it). */\n private dropFtsForFile(path: string): void {\n const ids = this.db\n .prepare<[string], { id: number }>(\n \"SELECT s.id FROM symbols s JOIN files f ON f.id = s.file_id WHERE f.path = ?\",\n )\n .all(path);\n if (ids.length === 0) return;\n const del = this.db.prepare(\"DELETE FROM symbols_fts WHERE rowid = ?\");\n for (const { id } of ids) del.run(id);\n }\n\n // ── Queries ────────────────────────────────────────────────────────────\n\n /**\n * Fuzzy substring search over symbol names. Queries of 3+ characters use the\n * trigram FTS index (fast at scale); shorter queries fall back to LIKE since\n * trigram matching needs at least three characters.\n */\n searchSymbols(query: string, opts: { kind?: SymbolKind; limit?: number } = {}): SymbolRow[] {\n const limit = clampLimit(opts.limit);\n if (query.trim().length >= 3) {\n const match = `\"${query.replace(/\"/g, '\"\"')}\"`;\n const rows = opts.kind\n ? this.db\n .prepare<[string, string, number], SymbolDbRow>(\n `SELECT ${SYMBOL_COLUMNS} FROM symbols_fts ft\n JOIN symbols s ON s.id = ft.rowid JOIN files f ON f.id = s.file_id\n WHERE symbols_fts MATCH ? AND s.kind = ?\n ORDER BY s.exported DESC, length(s.name), s.name LIMIT ?`,\n )\n .all(match, opts.kind, limit)\n : this.db\n .prepare<[string, number], SymbolDbRow>(\n `SELECT ${SYMBOL_COLUMNS} FROM symbols_fts ft\n JOIN symbols s ON s.id = ft.rowid JOIN files f ON f.id = s.file_id\n WHERE symbols_fts MATCH ?\n ORDER BY s.exported DESC, length(s.name), s.name LIMIT ?`,\n )\n .all(match, limit);\n return rows.map(toSymbolRow);\n }\n\n const like = `%${escapeLike(query)}%`;\n const rows = opts.kind\n ? this.db\n .prepare<[string, string, number], SymbolDbRow>(\n `SELECT ${SYMBOL_COLUMNS} FROM symbols s JOIN files f ON f.id = s.file_id\n WHERE s.name LIKE ? ESCAPE '\\\\' AND s.kind = ?\n ORDER BY s.exported DESC, length(s.name), s.name LIMIT ?`,\n )\n .all(like, opts.kind, limit)\n : this.db\n .prepare<[string, number], SymbolDbRow>(\n `SELECT ${SYMBOL_COLUMNS} FROM symbols s JOIN files f ON f.id = s.file_id\n WHERE s.name LIKE ? ESCAPE '\\\\'\n ORDER BY s.exported DESC, length(s.name), s.name LIMIT ?`,\n )\n .all(like, limit);\n return rows.map(toSymbolRow);\n }\n\n /** Exact-name definition lookup. */\n getSymbol(name: string, opts: { limit?: number } = {}): SymbolRow[] {\n return this.db\n .prepare<[string, number], SymbolDbRow>(\n `SELECT ${SYMBOL_COLUMNS} FROM symbols s JOIN files f ON f.id = s.file_id\n WHERE s.name = ? ORDER BY s.exported DESC, f.path LIMIT ?`,\n )\n .all(name, clampLimit(opts.limit))\n .map(toSymbolRow);\n }\n\n /** Symbols that call a given name (both bare `foo()` and `x.foo()`). */\n findCallers(name: string, opts: { limit?: number } = {}): RefRow[] {\n return this.db\n .prepare<[string, number], RefDbRow>(\n `SELECT r.id, f.path AS file, r.from_symbol, r.name, r.kind, r.start_row, r.start_col\n FROM refs r JOIN files f ON f.id = r.file_id\n WHERE r.name = ? AND r.kind IN ('call', 'method')\n ORDER BY f.path, r.start_row LIMIT ?`,\n )\n .all(name, clampLimit(opts.limit))\n .map(toRefRow);\n }\n\n /** All references (calls + imports) to a name. */\n findReferences(\n name: string,\n opts: { kind?: \"call\" | \"method\" | \"import\"; limit?: number } = {},\n ): RefRow[] {\n const limit = clampLimit(opts.limit);\n const rows = opts.kind\n ? this.db\n .prepare<[string, string, number], RefDbRow>(\n `SELECT r.id, f.path AS file, r.from_symbol, r.name, r.kind, r.start_row, r.start_col\n FROM refs r JOIN files f ON f.id = r.file_id\n WHERE r.name = ? AND r.kind = ? ORDER BY f.path, r.start_row LIMIT ?`,\n )\n .all(name, opts.kind, limit)\n : this.db\n .prepare<[string, number], RefDbRow>(\n `SELECT r.id, f.path AS file, r.from_symbol, r.name, r.kind, r.start_row, r.start_col\n FROM refs r JOIN files f ON f.id = r.file_id\n WHERE r.name = ? ORDER BY f.path, r.start_row LIMIT ?`,\n )\n .all(name, limit);\n return rows.map(toRefRow);\n }\n\n /** The symbols defined in a file, in source order. */\n fileOutline(path: string): SymbolRow[] {\n return this.db\n .prepare<[string], SymbolDbRow>(\n `SELECT ${SYMBOL_COLUMNS} FROM symbols s JOIN files f ON f.id = s.file_id\n WHERE f.path = ? ORDER BY s.start_row, s.start_col`,\n )\n .all(path)\n .map(toSymbolRow);\n }\n\n /** Distinct (callee, callKind) pairs invoked from inside symbols named `from`. */\n private calleesOf(from: string): Array<{ name: string; kind: \"call\" | \"method\" }> {\n return this.db\n .prepare<[string], { name: string; kind: \"call\" | \"method\" }>(\n \"SELECT DISTINCT name, kind FROM refs WHERE from_symbol = ? AND kind IN ('call','method')\",\n )\n .all(from);\n }\n\n /** Distinct caller symbol names that invoke `name`. */\n private callersOf(name: string): string[] {\n return this.db\n .prepare<[string], { from_symbol: string }>(\n \"SELECT DISTINCT from_symbol FROM refs WHERE name = ? AND kind IN ('call','method') AND from_symbol IS NOT NULL\",\n )\n .all(name)\n .map((r) => r.from_symbol);\n }\n\n /**\n * Resolve a callee name to project definitions, honouring how it was called:\n * a bare `foo()` resolves to non-method symbols, an `x.foo()` resolves to\n * methods. Ambiguous names (more than `ambiguityCap` definitions — typically\n * library-ish names like `push`/`map`) are treated as unresolved so they\n * don't blow up the neighbourhood. Returns `null` when nothing resolves.\n */\n private resolveCallee(\n name: string,\n callKind: \"call\" | \"method\",\n ambiguityCap: number,\n ): SymbolRow[] | null {\n const defs = this.getSymbol(name, { limit: ambiguityCap + 1 }).filter((d) =>\n callKind === \"method\" ? d.kind === \"method\" : d.kind !== \"method\",\n );\n if (defs.length === 0 || defs.length > ambiguityCap) return null;\n return defs;\n }\n\n /**\n * A bounded call neighbourhood around `name`: callers and callees expanded\n * breadth-first up to `depth`. Only edges between *resolvable project\n * symbols* are followed, so the result is the relevant slice of the codebase\n * — the payload a coding agent reads instead of grepping the whole repo.\n */\n neighborhood(\n name: string,\n opts: { depth?: number; limit?: number; maxFanout?: number; ambiguityCap?: number } = {},\n ): Neighborhood {\n const depth = Math.max(1, Math.min(opts.depth ?? 2, 5));\n const limit = clampLimit(opts.limit, 200);\n const maxFanout = opts.maxFanout ?? 25;\n const ambiguityCap = opts.ambiguityCap ?? 4;\n\n const seen = new Set<string>([name]);\n const edges: Array<{ from: string; to: string }> = [];\n const edgeKeys = new Set<string>();\n let frontier = [name];\n\n for (let d = 0; d < depth && frontier.length > 0 && seen.size < limit; d++) {\n const next = new Set<string>();\n for (const node of frontier) {\n let fanout = 0;\n for (const callee of this.calleesOf(node)) {\n if (fanout >= maxFanout) break;\n if (!this.resolveCallee(callee.name, callee.kind, ambiguityCap)) continue;\n fanout++;\n addEdge(edges, edgeKeys, node, callee.name);\n if (!seen.has(callee.name) && seen.size < limit) {\n seen.add(callee.name);\n next.add(callee.name);\n }\n }\n let callerFanout = 0;\n for (const caller of this.callersOf(node)) {\n if (callerFanout >= maxFanout) break;\n callerFanout++;\n addEdge(edges, edgeKeys, caller, node);\n if (!seen.has(caller) && seen.size < limit) {\n seen.add(caller);\n next.add(caller);\n }\n }\n }\n frontier = [...next];\n }\n\n const nodes: SymbolRow[] = [];\n const unresolved: string[] = [];\n for (const n of seen) {\n const defs = this.getSymbol(n, { limit: 5 });\n if (defs.length > 0) nodes.push(...defs);\n else unresolved.push(n);\n }\n return { root: name, nodes, edges, unresolved };\n }\n\n /** Aggregate counts for the whole graph. */\n stats(): IndexStats {\n const files = this.count(\"SELECT COUNT(*) AS n FROM files\");\n const symbols = this.count(\"SELECT COUNT(*) AS n FROM symbols\");\n const refs = this.count(\"SELECT COUNT(*) AS n FROM refs\");\n const byKind: Record<string, number> = {};\n for (const r of this.db\n .prepare<[], { kind: string; n: number }>(\n \"SELECT kind, COUNT(*) AS n FROM symbols GROUP BY kind\",\n )\n .all()) {\n byKind[r.kind] = r.n;\n }\n const byLang: Record<string, number> = {};\n for (const r of this.db\n .prepare<[], { lang: string; n: number }>(\n \"SELECT lang, COUNT(*) AS n FROM files GROUP BY lang\",\n )\n .all()) {\n byLang[r.lang] = r.n;\n }\n return { files, symbols, refs, byKind, byLang };\n }\n\n close(): void {\n this.db.close();\n }\n\n private count(sql: string): number {\n return this.db.prepare<[], { n: number }>(sql).get()?.n ?? 0;\n }\n\n private transaction(fn: () => void): void {\n this.db.transaction(fn)();\n }\n\n private transactionResult<T>(fn: () => T): T {\n return this.db.transaction(fn)();\n }\n}\n\nfunction addEdge(\n edges: Array<{ from: string; to: string }>,\n keys: Set<string>,\n from: string,\n to: string,\n): void {\n const key = `${from}\u0000${to}`;\n if (!keys.has(key)) {\n keys.add(key);\n edges.push({ from, to });\n }\n}\n\nfunction clampLimit(limit: number | undefined, max = 500): number {\n if (!limit || limit <= 0) return 50;\n return Math.min(limit, max);\n}\n\nfunction escapeLike(s: string): string {\n return s.replace(/[\\\\%_]/g, (c) => `\\\\${c}`);\n}\n\nfunction toSymbolRow(r: SymbolDbRow): SymbolRow {\n return {\n id: r.id,\n file: r.file,\n name: r.name,\n kind: r.kind as SymbolKind,\n container: r.container,\n exported: r.exported === 1,\n signature: r.signature,\n startRow: r.start_row,\n startCol: r.start_col,\n endRow: r.end_row,\n endCol: r.end_col,\n };\n}\n\nfunction toRefRow(r: RefDbRow): RefRow {\n return {\n id: r.id,\n file: r.file,\n fromSymbol: r.from_symbol,\n name: r.name,\n kind: r.kind as RefRow[\"kind\"],\n startRow: r.start_row,\n startCol: r.start_col,\n };\n}\n","import { watch as chokidarWatch } from \"chokidar\";\nimport { languageForPath } from \"./languages.js\";\nimport type { Indexer } from \"./indexer.js\";\n\nexport interface WatchEvents {\n /** A file was (re-)indexed or removed from the graph. */\n onChange?: (relPath: string, action: \"indexed\" | \"removed\") => void;\n onError?: (error: unknown) => void;\n /** Fired once the initial scan has settled and the watcher is live. */\n onReady?: () => void;\n}\n\nexport interface WatchOptions {\n /** Force polling — slower but deterministic, useful in tests/CI. */\n usePolling?: boolean;\n /** Polling interval in ms when `usePolling` is set. */\n interval?: number;\n}\n\nexport interface WatchHandle {\n close: () => Promise<void>;\n}\n\nconst IGNORED = /(?:^|[\\\\/])(?:node_modules|\\.git|dist|build|coverage|\\.codescope|target|__pycache__)(?:[\\\\/]|$)/;\n\n/**\n * Watch the indexer's root and keep the graph fresh as files change. This is\n * codescope's differentiator: the agent never reads a stale graph because the\n * graph re-indexes the touched file (and only that file) on save.\n */\nexport function watch(indexer: Indexer, events: WatchEvents = {}, opts: WatchOptions = {}): WatchHandle {\n const watcher = chokidarWatch(indexer.root, {\n ignoreInitial: true,\n ignored: (path: string) => IGNORED.test(path),\n usePolling: opts.usePolling,\n interval: opts.interval,\n });\n\n const onUpsert = (abs: string): void => {\n if (!languageForPath(abs)) return;\n indexer\n .indexFile(abs)\n .then((outcome) => {\n if (outcome === \"indexed\") events.onChange?.(indexer.rel(abs), \"indexed\");\n })\n .catch((err) => events.onError?.(err));\n };\n\n watcher\n .on(\"add\", onUpsert)\n .on(\"change\", onUpsert)\n .on(\"unlink\", (abs: string) => {\n if (indexer.removeFile(abs)) events.onChange?.(indexer.rel(abs), \"removed\");\n })\n .on(\"error\", (err: unknown) => events.onError?.(err))\n .on(\"ready\", () => events.onReady?.());\n\n return {\n close: () => watcher.close(),\n };\n}\n"],"mappings":"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","names":["resolve","require","rows","c","resolve"]}
1
+ {"version":3,"sources":["../src/cli.ts","../src/format.ts","../src/indexer.ts","../src/languages.ts","../src/parser.ts","../src/mcp.ts","../src/version.ts","../src/store.ts","../src/watcher.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { mkdirSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport pc from \"picocolors\";\nimport * as fmt from \"./format.js\";\nimport { Indexer } from \"./indexer.js\";\nimport { runStdioServer } from \"./mcp.js\";\nimport { GraphStore } from \"./store.js\";\nimport type { SymbolKind } from \"./types.js\";\nimport { VERSION } from \"./version.js\";\nimport { watch } from \"./watcher.js\";\n\ninterface Flags {\n positional: string[];\n path?: string;\n db?: string;\n memory: boolean;\n kind?: string;\n limit?: number;\n depth?: number;\n}\n\nconst HELP = `codescope ${VERSION} — local-first codebase knowledge-graph MCP server\n\nUsage:\n codescope <command> [path] [options]\n\nCommands:\n mcp [path] Index, watch for changes, and serve the graph over MCP (stdio).\n This is what you wire into Claude Code / Cursor / Codex.\n index [path] Build (or refresh) the on-disk graph and print stats.\n watch [path] Index, then keep the graph fresh as files change (logs updates).\n stats [path] Show counts for the indexed graph.\n search <query> [path] Fuzzy-search symbol names.\n get <name> [path] Look up a definition by exact name.\n callers <name> [path] List callers of a function/method.\n callees <name> [path] List what a function/method calls.\n impact <name> [path] Transitive callers (blast radius) of a symbol.\n context <query> [path] Ranked relevance map for a task (matches + neighbours).\n neighborhood <name> Show the call neighbourhood around a symbol.\n\nOptions:\n --path <dir> Repository root (default: current directory or the positional path).\n --db <file> SQLite graph location (default: <root>/.codescope/graph.db).\n --memory Use an in-memory graph (not persisted).\n --kind <kind> Restrict search to: function|method|class|interface|type|enum|variable.\n --limit <n> Max results (default 50).\n --depth <n> neighbourhood hops (default 2).\n -h, --help Show this help.\n -v, --version Show version.\n\nExamples:\n codescope index .\n codescope search useState\n codescope neighborhood handleRequest --depth 3\n codescope mcp . # add this command to your agent's MCP config\n`;\n\nfunction parseArgs(argv: string[]): Flags {\n const flags: Flags = { positional: [], memory: false };\n for (let i = 0; i < argv.length; i++) {\n const arg = argv[i] as string;\n switch (arg) {\n case \"--memory\":\n flags.memory = true;\n break;\n case \"--path\":\n flags.path = argv[++i];\n break;\n case \"--db\":\n flags.db = argv[++i];\n break;\n case \"--kind\":\n flags.kind = argv[++i];\n break;\n case \"--limit\":\n flags.limit = Number(argv[++i]);\n break;\n case \"--depth\":\n flags.depth = Number(argv[++i]);\n break;\n default:\n flags.positional.push(arg);\n }\n }\n return flags;\n}\n\nfunction rootDir(flags: Flags, positionalRootIndex = 0): string {\n return resolve(flags.path ?? flags.positional[positionalRootIndex] ?? \".\");\n}\n\nfunction openStore(root: string, flags: Flags): GraphStore {\n if (flags.memory) return new GraphStore(\":memory:\");\n const dir = resolve(root, \".codescope\");\n mkdirSync(dir, { recursive: true });\n return new GraphStore(flags.db ?? resolve(dir, \"graph.db\"));\n}\n\n/** Ensure the graph is populated; index on demand for query commands. */\nasync function ensureIndexed(indexer: Indexer, store: GraphStore): Promise<void> {\n if (store.stats().files === 0) {\n await indexer.indexAll();\n }\n}\n\nasync function cmdIndex(root: string, flags: Flags): Promise<void> {\n const store = openStore(root, flags);\n const indexer = new Indexer(store, root);\n process.stderr.write(pc.dim(`Indexing ${root} …\\n`));\n const result = await indexer.indexAll();\n const { files, symbols, refs } = store.stats();\n process.stdout.write(\n `${pc.green(\"✓\")} indexed ${pc.bold(String(result.indexed))} files ` +\n `(${result.skipped} unchanged, ${result.removed} removed) in ${result.durationMs}ms\\n` +\n ` ${files} files · ${symbols} symbols · ${refs} refs\\n`,\n );\n if (result.errors.length > 0) {\n process.stderr.write(pc.yellow(` ${result.errors.length} file(s) failed to parse\\n`));\n }\n store.close();\n}\n\nasync function cmdStats(root: string, flags: Flags): Promise<void> {\n const store = openStore(root, flags);\n const indexer = new Indexer(store, root);\n await ensureIndexed(indexer, store);\n process.stdout.write(`${fmt.formatStats(store.stats())}\\n`);\n store.close();\n}\n\nasync function cmdQuery(command: string, root: string, flags: Flags): Promise<void> {\n const term = flags.positional[0];\n if (!term) fail(`'${command}' needs an argument. See --help.`);\n const store = openStore(root, flags);\n const indexer = new Indexer(store, root);\n await ensureIndexed(indexer, store);\n\n let out: string;\n switch (command) {\n case \"search\":\n out = fmt.formatSymbols(\n store.searchSymbols(term, { kind: flags.kind as SymbolKind | undefined, limit: flags.limit }),\n );\n break;\n case \"get\":\n out = fmt.formatSymbols(store.getSymbol(term, { limit: flags.limit }));\n break;\n case \"callers\":\n out = fmt.formatRefs(store.findCallers(term, { limit: flags.limit }));\n break;\n case \"callees\":\n out = fmt.formatSymbols(store.findCallees(term, { limit: flags.limit }));\n break;\n case \"impact\":\n out = fmt.formatImpact(store.impact(term, { depth: flags.depth, limit: flags.limit }));\n break;\n case \"context\":\n out = fmt.formatContext(store.context(term, { maxSymbols: flags.limit }));\n break;\n case \"neighborhood\":\n out = fmt.formatNeighborhood(store.neighborhood(term, { depth: flags.depth, limit: flags.limit }));\n break;\n default:\n out = \"\";\n }\n process.stdout.write(`${out}\\n`);\n store.close();\n}\n\nasync function cmdWatch(root: string, flags: Flags): Promise<void> {\n const store = openStore(root, flags);\n const indexer = new Indexer(store, root);\n process.stderr.write(pc.dim(`Indexing ${root} …\\n`));\n await indexer.indexAll();\n process.stderr.write(`${pc.green(\"✓\")} watching for changes (ctrl-c to stop)\\n`);\n watch(indexer, {\n onChange: (rel, action) =>\n process.stderr.write(`${action === \"indexed\" ? pc.cyan(\"↻\") : pc.red(\"✗\")} ${rel}\\n`),\n onError: (err) => process.stderr.write(pc.yellow(`watch error: ${String(err)}\\n`)),\n });\n await new Promise(() => {}); // run until interrupted\n}\n\nasync function cmdMcp(root: string, flags: Flags): Promise<void> {\n // stdout is the MCP transport — every human-readable byte must go to stderr.\n const store = openStore(root, flags);\n const indexer = new Indexer(store, root);\n process.stderr.write(pc.dim(`codescope: indexing ${root} …\\n`));\n const result = await indexer.indexAll();\n process.stderr.write(\n pc.dim(`codescope: ${result.indexed} files indexed, watching for changes\\n`),\n );\n watch(indexer, {\n onChange: (rel, action) => process.stderr.write(pc.dim(`codescope: ${action} ${rel}\\n`)),\n onError: (err) => process.stderr.write(pc.yellow(`codescope: watch error ${String(err)}\\n`)),\n });\n await runStdioServer(store);\n}\n\nfunction fail(message: string): never {\n process.stderr.write(`${pc.red(\"error:\")} ${message}\\n`);\n process.exit(1);\n}\n\nasync function main(): Promise<void> {\n const argv = process.argv.slice(2);\n if (argv.length === 0 || argv[0] === \"-h\" || argv[0] === \"--help\" || argv[0] === \"help\") {\n process.stdout.write(HELP);\n return;\n }\n if (argv[0] === \"-v\" || argv[0] === \"--version\" || argv[0] === \"version\") {\n process.stdout.write(`${VERSION}\\n`);\n return;\n }\n\n const command = argv[0] as string;\n const flags = parseArgs(argv.slice(1));\n\n switch (command) {\n case \"index\":\n return cmdIndex(rootDir(flags), flags);\n case \"stats\":\n return cmdStats(rootDir(flags), flags);\n case \"search\":\n case \"get\":\n case \"callers\":\n case \"callees\":\n case \"impact\":\n case \"context\":\n case \"neighborhood\":\n // positional[0] is the term; the optional repo path is positional[1].\n return cmdQuery(command, resolve(flags.path ?? flags.positional[1] ?? \".\"), flags);\n case \"watch\":\n return cmdWatch(rootDir(flags), flags);\n case \"mcp\":\n return cmdMcp(rootDir(flags), flags);\n default:\n fail(`unknown command '${command}'. See --help.`);\n }\n}\n\nmain().catch((err) => fail(err instanceof Error ? err.message : String(err)));\n","import type {\n ContextBundle,\n ImpactRow,\n IndexStats,\n Neighborhood,\n RefRow,\n SymbolRow,\n} from \"./types.js\";\n\n/**\n * Compact, line-oriented renderers. The whole point of codescope is to hand an\n * agent the *answer* in as few tokens as possible, so these favour terse,\n * grep-like lines over verbose prose or JSON.\n */\n\n/** Keep signatures short — agents pay per token; full detail is one query away. */\nfunction shortSig(sig: string | null): string {\n if (!sig) return \"\";\n const s = sig.length > 88 ? `${sig.slice(0, 87)}…` : sig;\n return ` · ${s}`;\n}\n\nfunction symbolLine(s: SymbolRow): string {\n const loc = `${s.file}:${s.startRow + 1}`;\n const container = s.container ? `${s.container}.` : \"\";\n const exp = s.exported ? \"export \" : \"\";\n return `${s.kind} ${exp}${container}${s.name} — ${loc}${shortSig(s.signature)}`;\n}\n\nexport function formatSymbols(rows: SymbolRow[]): string {\n if (rows.length === 0) return \"No matching symbols.\";\n return rows.map(symbolLine).join(\"\\n\");\n}\n\nexport function formatRefs(rows: RefRow[]): string {\n if (rows.length === 0) return \"No references.\";\n // The referenced name is the query itself, so don't repeat it on every line.\n return rows\n .map((r) => {\n const where = r.fromSymbol ?? \"(top level)\";\n return `${r.file}:${r.startRow + 1} ${where}`;\n })\n .join(\"\\n\");\n}\n\nexport function formatNeighborhood(n: Neighborhood): string {\n const lines: string[] = [`neighbourhood of ${n.root}:`];\n lines.push(\"\", \"definitions:\");\n if (n.nodes.length === 0) lines.push(\" (none indexed)\");\n else for (const s of n.nodes) lines.push(` ${symbolLine(s)}`);\n if (n.edges.length > 0) {\n lines.push(\"\", \"call edges:\");\n for (const e of n.edges) lines.push(` ${e.from} → ${e.to}`);\n }\n if (n.unresolved.length > 0) {\n lines.push(\"\", `unresolved (referenced, not defined in index): ${n.unresolved.join(\", \")}`);\n }\n return lines.join(\"\\n\");\n}\n\nexport function formatImpact(rows: ImpactRow[]): string {\n if (rows.length === 0) return \"No callers — changing this is low-risk.\";\n return rows.map((r) => `[${r.distance} hop] ${symbolLine(r)}`).join(\"\\n\");\n}\n\nexport function formatContext(b: ContextBundle): string {\n const lines: string[] = [`context for \"${b.query}\":`, \"\", \"matches:\"];\n if (b.seeds.length === 0) lines.push(\" (no symbols matched)\");\n else for (const s of b.seeds) lines.push(` ${symbolLine(s)}`);\n if (b.related.length > 0) {\n lines.push(\"\", \"related (ranked by call-site centrality):\");\n for (const s of b.related) lines.push(` ${symbolLine(s)}`);\n }\n if (b.edges.length > 0) {\n lines.push(\"\", \"call edges:\");\n for (const e of b.edges) lines.push(` ${e.from} → ${e.to}`);\n }\n return lines.join(\"\\n\");\n}\n\nexport function formatStats(s: IndexStats): string {\n const kinds = Object.entries(s.byKind)\n .sort((a, b) => b[1] - a[1])\n .map(([k, n]) => `${k}=${n}`)\n .join(\" \");\n const langs = Object.entries(s.byLang)\n .sort((a, b) => b[1] - a[1])\n .map(([k, n]) => `${k}=${n}`)\n .join(\" \");\n return [\n `files: ${s.files}`,\n `symbols: ${s.symbols} (${kinds || \"none\"})`,\n `refs: ${s.refs}`,\n `langs: ${langs || \"none\"}`,\n ].join(\"\\n\");\n}\n","import { createHash } from \"node:crypto\";\nimport { readFileSync } from \"node:fs\";\nimport { readFile, stat } from \"node:fs/promises\";\nimport { relative, resolve, sep } from \"node:path\";\nimport ignore, { type Ignore } from \"ignore\";\nimport { glob } from \"tinyglobby\";\nimport { SUPPORTED_EXTENSIONS, languageForPath } from \"./languages.js\";\nimport { parseSource } from \"./parser.js\";\nimport type { GraphStore } from \"./store.js\";\nimport type { IndexRunResult } from \"./types.js\";\n\n/** Directories never worth indexing, regardless of .gitignore. */\nconst DEFAULT_IGNORES = [\n \"**/node_modules/**\",\n \"**/.git/**\",\n \"**/dist/**\",\n \"**/build/**\",\n \"**/coverage/**\",\n \"**/.codescope/**\",\n \"**/.next/**\",\n \"**/out/**\",\n \"**/target/**\",\n \"**/.venv/**\",\n \"**/venv/**\",\n \"**/vendor/**\",\n \"**/__pycache__/**\",\n];\n\nexport interface IndexOptions {\n /** Extra glob patterns to ignore. */\n ignore?: string[];\n /** Honour the repo's root `.gitignore` (default: true). */\n gitignore?: boolean;\n}\n\nexport type FileIndexOutcome = \"indexed\" | \"skipped\" | \"unsupported\";\n\n/**\n * Walks a repository and keeps a {@link GraphStore} in sync with it. Every\n * operation is per-file and content-hash gated, so a full re-scan skips\n * unchanged files and a single-file update touches only that file.\n */\nexport class Indexer {\n readonly root: string;\n\n constructor(\n private readonly store: GraphStore,\n root: string,\n ) {\n this.root = resolve(root);\n }\n\n /** Index every supported, non-ignored file and prune deleted ones. */\n async indexAll(opts: IndexOptions = {}): Promise<IndexRunResult> {\n const start = Date.now();\n const result: IndexRunResult = {\n indexed: 0,\n skipped: 0,\n removed: 0,\n errors: [],\n durationMs: 0,\n };\n\n const files = await this.listSourceFiles(opts);\n const present = new Set<string>();\n\n for (const abs of files) {\n present.add(this.rel(abs));\n try {\n const outcome = await this.indexFile(abs, start);\n if (outcome === \"indexed\") result.indexed++;\n else if (outcome === \"skipped\") result.skipped++;\n } catch (err) {\n result.errors.push({ file: this.rel(abs), error: errorMessage(err) });\n }\n }\n\n for (const known of this.store.listFiles()) {\n if (!present.has(known) && this.store.removeFile(known)) result.removed++;\n }\n\n result.durationMs = Date.now() - start;\n return result;\n }\n\n /** Index a single file by absolute path. Cheap when the content is unchanged. */\n async indexFile(abs: string, now = Date.now()): Promise<FileIndexOutcome> {\n const lang = languageForPath(abs);\n if (!lang) return \"unsupported\";\n\n const rel = this.rel(abs);\n const content = await readFile(abs, \"utf8\");\n const hash = sha1(content);\n if (this.store.getFileHash(rel) === hash) return \"skipped\";\n\n const mtime = await fileMtime(abs, now);\n const { symbols, refs } = await parseSource(lang.id, content);\n this.store.replaceFile(\n { path: rel, lang: lang.id, hash, size: content.length, mtime },\n symbols,\n refs,\n now,\n );\n return \"indexed\";\n }\n\n /** Drop a file from the graph by absolute path. */\n removeFile(abs: string): boolean {\n return this.store.removeFile(this.rel(abs));\n }\n\n /** Repo-relative, POSIX-separated path used as the stable graph key. */\n rel(abs: string): string {\n return relative(this.root, resolve(abs)).split(sep).join(\"/\");\n }\n\n private async listSourceFiles(opts: IndexOptions): Promise<string[]> {\n const patterns = SUPPORTED_EXTENSIONS.map((ext) => `**/*${ext}`);\n const files = await glob(patterns, {\n cwd: this.root,\n absolute: true,\n ignore: [...DEFAULT_IGNORES, ...(opts.ignore ?? [])],\n dot: false,\n });\n\n if (opts.gitignore === false) return files;\n const ig = this.loadGitignore();\n if (!ig) return files;\n return files.filter((f) => {\n const rel = this.rel(f);\n return rel.length > 0 && !ig.ignores(rel);\n });\n }\n\n private loadGitignore(): Ignore | null {\n try {\n const content = readFileSync(resolve(this.root, \".gitignore\"), \"utf8\");\n return ignore().add(content);\n } catch {\n return null;\n }\n }\n}\n\nfunction sha1(content: string): string {\n return createHash(\"sha1\").update(content).digest(\"hex\");\n}\n\nasync function fileMtime(abs: string, fallback: number): Promise<number> {\n try {\n const st = await stat(abs);\n return Math.floor(st.mtimeMs);\n } catch {\n return fallback;\n }\n}\n\nfunction errorMessage(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n","import type { SymbolKind } from \"./types.js\";\n\n/**\n * Per-language configuration driving the AST walk in {@link ./parser.ts}.\n *\n * Rather than maintain a tree-sitter query (`.scm`) per grammar, we walk the\n * tree once and classify nodes by `type` using these tables. Grammars disagree\n * on a lot — C buries a function's name inside nested declarators, Java and Ruby\n * hang the callee straight off the call node, Go/Rust/C++ each use a different\n * \"member access\" node — so definitions, calls, and imports are all described\n * declaratively here and interpreted by a single generic walker.\n */\n\nexport type NameStrategy = \"field\" | \"c_declarator\";\n\nexport interface DefRule {\n kind: SymbolKind;\n /** How to read the definition's name (default: the `name` field). */\n name?: NameStrategy;\n}\n\nexport interface CallRule {\n /** AST node type for this kind of call. */\n type: string;\n /** Field holding the callee expression (for `foo()` / `a.foo()` forms). */\n fnField?: string;\n /** Callee-expression node types that mean \"method call\". */\n memberTypes?: string[];\n /** Field on a member node holding the method name. */\n memberField?: string;\n /** Callee-expression node types that are path-qualified (`a::b`). */\n scopedTypes?: string[];\n /** Field on a scoped node holding the final name. */\n scopedField?: string;\n /** The call node holds the callee name directly in this field (Java/Ruby). */\n nameField?: string;\n /** Presence of this field on the call node marks it a method call. */\n receiverField?: string;\n /** Force the ref kind regardless of shape. */\n forceKind?: \"call\" | \"method\";\n}\n\nexport interface ImportRule {\n type: string;\n /** Read the import target from this field's text. */\n field?: string;\n /** Collect import targets from named children of these types. */\n childTypes?: string[];\n}\n\nexport interface LanguageConfig {\n id: string;\n wasm: string;\n defs: Record<string, DefRule>;\n /** Bindings (`const x = …`) that become `function` symbols when assigned a function. */\n functionBindings: Set<string>;\n /** A nested `function` whose enclosing definition is a class becomes a `method`. */\n nestedFunctionsAreMethods: boolean;\n callRules: CallRule[];\n importRules: ImportRule[];\n /** Node types whose presence as an ancestor marks a definition as exported. */\n exportTypes: Set<string>;\n}\n\nconst JS_CALLS: CallRule[] = [\n { type: \"call_expression\", fnField: \"function\", memberTypes: [\"member_expression\"], memberField: \"property\" },\n];\n\nconst typescript: LanguageConfig = {\n id: \"typescript\",\n wasm: \"typescript\",\n defs: {\n function_declaration: { kind: \"function\" },\n generator_function_declaration: { kind: \"function\" },\n function_signature: { kind: \"function\" },\n method_definition: { kind: \"method\" },\n method_signature: { kind: \"method\" },\n class_declaration: { kind: \"class\" },\n abstract_class_declaration: { kind: \"class\" },\n interface_declaration: { kind: \"interface\" },\n type_alias_declaration: { kind: \"type\" },\n enum_declaration: { kind: \"enum\" },\n },\n functionBindings: new Set([\"variable_declarator\", \"public_field_definition\"]),\n nestedFunctionsAreMethods: false,\n callRules: JS_CALLS,\n importRules: [{ type: \"import_statement\", field: \"source\" }],\n exportTypes: new Set([\"export_statement\"]),\n};\n\nconst tsx: LanguageConfig = { ...typescript, id: \"tsx\", wasm: \"tsx\" };\n\nconst javascript: LanguageConfig = {\n id: \"javascript\",\n wasm: \"javascript\",\n defs: {\n function_declaration: { kind: \"function\" },\n generator_function_declaration: { kind: \"function\" },\n method_definition: { kind: \"method\" },\n class_declaration: { kind: \"class\" },\n },\n functionBindings: new Set([\"variable_declarator\", \"field_definition\"]),\n nestedFunctionsAreMethods: false,\n callRules: JS_CALLS,\n importRules: [{ type: \"import_statement\", field: \"source\" }],\n exportTypes: new Set([\"export_statement\"]),\n};\n\nconst python: LanguageConfig = {\n id: \"python\",\n wasm: \"python\",\n defs: {\n function_definition: { kind: \"function\" },\n class_definition: { kind: \"class\" },\n },\n functionBindings: new Set(),\n nestedFunctionsAreMethods: false,\n callRules: [{ type: \"call\", fnField: \"function\", memberTypes: [\"attribute\"], memberField: \"attribute\" }],\n importRules: [\n { type: \"import_statement\", childTypes: [\"dotted_name\", \"aliased_import\"] },\n { type: \"import_from_statement\", field: \"module_name\" },\n ],\n exportTypes: new Set(),\n};\n\nconst go: LanguageConfig = {\n id: \"go\",\n wasm: \"go\",\n defs: {\n function_declaration: { kind: \"function\" },\n method_declaration: { kind: \"method\" },\n type_spec: { kind: \"class\" },\n },\n functionBindings: new Set(),\n nestedFunctionsAreMethods: false,\n callRules: [\n { type: \"call_expression\", fnField: \"function\", memberTypes: [\"selector_expression\"], memberField: \"field\" },\n ],\n importRules: [{ type: \"import_spec\", field: \"path\" }],\n exportTypes: new Set(),\n};\n\nconst rust: LanguageConfig = {\n id: \"rust\",\n wasm: \"rust\",\n defs: {\n function_item: { kind: \"function\" },\n struct_item: { kind: \"class\" },\n union_item: { kind: \"class\" },\n enum_item: { kind: \"enum\" },\n trait_item: { kind: \"interface\" },\n type_item: { kind: \"type\" },\n },\n functionBindings: new Set(),\n nestedFunctionsAreMethods: false,\n callRules: [\n {\n type: \"call_expression\",\n fnField: \"function\",\n memberTypes: [\"field_expression\"],\n memberField: \"field\",\n scopedTypes: [\"scoped_identifier\"],\n scopedField: \"name\",\n },\n ],\n importRules: [{ type: \"use_declaration\", field: \"argument\" }],\n exportTypes: new Set(),\n};\n\nconst java: LanguageConfig = {\n id: \"java\",\n wasm: \"java\",\n defs: {\n class_declaration: { kind: \"class\" },\n interface_declaration: { kind: \"interface\" },\n enum_declaration: { kind: \"enum\" },\n record_declaration: { kind: \"class\" },\n method_declaration: { kind: \"method\" },\n constructor_declaration: { kind: \"method\" },\n },\n functionBindings: new Set(),\n nestedFunctionsAreMethods: false,\n callRules: [{ type: \"method_invocation\", nameField: \"name\", receiverField: \"object\" }],\n importRules: [{ type: \"import_declaration\", childTypes: [\"scoped_identifier\", \"identifier\"] }],\n exportTypes: new Set(),\n};\n\nconst ruby: LanguageConfig = {\n id: \"ruby\",\n wasm: \"ruby\",\n defs: {\n method: { kind: \"method\" },\n singleton_method: { kind: \"method\" },\n class: { kind: \"class\" },\n module: { kind: \"class\" },\n },\n functionBindings: new Set(),\n nestedFunctionsAreMethods: false,\n callRules: [{ type: \"call\", nameField: \"method\", receiverField: \"receiver\" }],\n importRules: [],\n exportTypes: new Set(),\n};\n\nconst c: LanguageConfig = {\n id: \"c\",\n wasm: \"c\",\n defs: {\n function_definition: { kind: \"function\", name: \"c_declarator\" },\n struct_specifier: { kind: \"class\" },\n union_specifier: { kind: \"class\" },\n enum_specifier: { kind: \"enum\" },\n },\n functionBindings: new Set(),\n nestedFunctionsAreMethods: false,\n callRules: [\n { type: \"call_expression\", fnField: \"function\", memberTypes: [\"field_expression\"], memberField: \"field\" },\n ],\n importRules: [{ type: \"preproc_include\", field: \"path\" }],\n exportTypes: new Set(),\n};\n\nconst cpp: LanguageConfig = {\n id: \"cpp\",\n wasm: \"cpp\",\n defs: {\n function_definition: { kind: \"function\", name: \"c_declarator\" },\n class_specifier: { kind: \"class\" },\n struct_specifier: { kind: \"class\" },\n enum_specifier: { kind: \"enum\" },\n },\n functionBindings: new Set(),\n nestedFunctionsAreMethods: true,\n callRules: [\n { type: \"call_expression\", fnField: \"function\", memberTypes: [\"field_expression\"], memberField: \"field\" },\n ],\n importRules: [{ type: \"preproc_include\", field: \"path\" }],\n exportTypes: new Set(),\n};\n\nconst csharp: LanguageConfig = {\n id: \"csharp\",\n wasm: \"c_sharp\",\n defs: {\n class_declaration: { kind: \"class\" },\n struct_declaration: { kind: \"class\" },\n interface_declaration: { kind: \"interface\" },\n enum_declaration: { kind: \"enum\" },\n record_declaration: { kind: \"class\" },\n method_declaration: { kind: \"method\" },\n constructor_declaration: { kind: \"method\" },\n },\n functionBindings: new Set(),\n nestedFunctionsAreMethods: false,\n callRules: [\n {\n type: \"invocation_expression\",\n fnField: \"function\",\n memberTypes: [\"member_access_expression\"],\n memberField: \"name\",\n },\n ],\n importRules: [{ type: \"using_directive\", childTypes: [\"identifier\", \"qualified_name\"] }],\n exportTypes: new Set(),\n};\n\nconst php: LanguageConfig = {\n id: \"php\",\n wasm: \"php\",\n defs: {\n function_definition: { kind: \"function\" },\n method_declaration: { kind: \"method\" },\n class_declaration: { kind: \"class\" },\n interface_declaration: { kind: \"interface\" },\n trait_declaration: { kind: \"class\" },\n enum_declaration: { kind: \"enum\" },\n },\n functionBindings: new Set(),\n nestedFunctionsAreMethods: false,\n callRules: [\n { type: \"function_call_expression\", fnField: \"function\" },\n { type: \"member_call_expression\", nameField: \"name\", forceKind: \"method\" },\n { type: \"scoped_call_expression\", nameField: \"name\", forceKind: \"method\" },\n ],\n importRules: [{ type: \"namespace_use_declaration\", childTypes: [\"namespace_use_clause\"] }],\n exportTypes: new Set(),\n};\n\n/** All languages codescope can parse, keyed by config id. */\nexport const LANGUAGES: Record<string, LanguageConfig> = {\n typescript,\n tsx,\n javascript,\n python,\n go,\n rust,\n java,\n ruby,\n c,\n cpp,\n csharp,\n php,\n};\n\n/** File extension → language id. */\nconst EXT_TO_LANG: Record<string, string> = {\n \".ts\": \"typescript\",\n \".mts\": \"typescript\",\n \".cts\": \"typescript\",\n \".tsx\": \"tsx\",\n \".js\": \"javascript\",\n \".mjs\": \"javascript\",\n \".cjs\": \"javascript\",\n \".jsx\": \"javascript\",\n \".py\": \"python\",\n \".pyi\": \"python\",\n \".go\": \"go\",\n \".rs\": \"rust\",\n \".java\": \"java\",\n \".rb\": \"ruby\",\n \".c\": \"c\",\n \".h\": \"c\",\n \".cc\": \"cpp\",\n \".cpp\": \"cpp\",\n \".cxx\": \"cpp\",\n \".hpp\": \"cpp\",\n \".hh\": \"cpp\",\n \".cs\": \"csharp\",\n \".php\": \"php\",\n};\n\n/** The set of file extensions codescope indexes (with leading dot). */\nexport const SUPPORTED_EXTENSIONS: readonly string[] = Object.keys(EXT_TO_LANG);\n\n/** Resolve a language config from a file path, or `undefined` if unsupported. */\nexport function languageForPath(path: string): LanguageConfig | undefined {\n const dot = path.lastIndexOf(\".\");\n if (dot === -1) return undefined;\n const ext = path.slice(dot).toLowerCase();\n const id = EXT_TO_LANG[ext];\n return id ? LANGUAGES[id] : undefined;\n}\n","import { createRequire } from \"node:module\";\nimport Parser from \"web-tree-sitter\";\nimport {\n LANGUAGES,\n type CallRule,\n type DefRule,\n type ImportRule,\n type LanguageConfig,\n} from \"./languages.js\";\nimport type { ParsedRef, ParsedSymbol, ParseResult, SymbolKind } from \"./types.js\";\n\nconst require = createRequire(import.meta.url);\n\nlet initPromise: Promise<void> | null = null;\nconst parserCache = new Map<string, Parser>();\n\n/** Resolve a grammar wasm shipped by `tree-sitter-wasms`. */\nfunction grammarPath(wasm: string): string {\n return require.resolve(`tree-sitter-wasms/out/tree-sitter-${wasm}.wasm`);\n}\n\nasync function ensureInit(): Promise<void> {\n if (!initPromise) initPromise = Parser.init();\n await initPromise;\n}\n\n/** Lazily load (and cache) a configured parser for a language. */\nasync function getParser(lang: LanguageConfig): Promise<Parser> {\n const cached = parserCache.get(lang.id);\n if (cached) return cached;\n await ensureInit();\n const language = await Parser.Language.load(grammarPath(lang.wasm));\n const parser = new Parser();\n parser.setLanguage(language);\n parserCache.set(lang.id, parser);\n return parser;\n}\n\nconst FUNCTION_VALUE_TYPES = new Set([\n \"arrow_function\",\n \"function\",\n \"function_expression\",\n \"generator_function\",\n]);\n\n/** Parse a source string into symbols and references. */\nexport async function parseSource(langId: string, source: string): Promise<ParseResult> {\n const lang = LANGUAGES[langId];\n if (!lang) throw new Error(`Unknown language: ${langId}`);\n const parser = await getParser(lang);\n const tree = parser.parse(source);\n const symbols: ParsedSymbol[] = [];\n const refs: ParsedRef[] = [];\n if (tree?.rootNode) {\n walk(tree.rootNode, lang, null, null, symbols, refs);\n tree.delete();\n }\n return { lang: lang.id, symbols, refs };\n}\n\nfunction walk(\n node: Parser.SyntaxNode,\n lang: LanguageConfig,\n container: string | null,\n containerKind: SymbolKind | null,\n symbols: ParsedSymbol[],\n refs: ParsedRef[],\n): void {\n let childContainer = container;\n let childContainerKind = containerKind;\n\n const rule = classify(node, lang);\n const call = lang.callRules.find((r) => r.type === node.type);\n const imp = lang.importRules.find((r) => r.type === node.type);\n\n if (rule) {\n const sym = buildSymbol(node, rule, container, containerKind, lang);\n if (sym) {\n symbols.push(sym);\n childContainer = sym.name;\n childContainerKind = sym.kind;\n }\n } else if (call) {\n const ref = extractCall(node, call, container);\n if (ref) refs.push(ref);\n } else if (imp) {\n for (const ref of extractImports(node, imp, container)) refs.push(ref);\n }\n\n for (const child of node.namedChildren) {\n walk(child, lang, childContainer, childContainerKind, symbols, refs);\n }\n}\n\nfunction classify(node: Parser.SyntaxNode, lang: LanguageConfig): DefRule | null {\n const direct = lang.defs[node.type];\n if (direct) return direct;\n if (lang.functionBindings.has(node.type)) {\n const value = node.childForFieldName(\"value\");\n if (value && FUNCTION_VALUE_TYPES.has(value.type)) return { kind: \"function\" };\n }\n return null;\n}\n\nfunction buildSymbol(\n node: Parser.SyntaxNode,\n rule: DefRule,\n container: string | null,\n containerKind: SymbolKind | null,\n lang: LanguageConfig,\n): ParsedSymbol | null {\n const name = symbolName(node, rule.name ?? \"field\");\n if (!name) return null;\n let kind = rule.kind;\n if (kind === \"function\" && lang.nestedFunctionsAreMethods && containerKind === \"class\") {\n kind = \"method\";\n }\n return {\n name,\n kind,\n container,\n exported: isExported(node, lang),\n signature: signatureOf(node),\n startRow: node.startPosition.row,\n startCol: node.startPosition.column,\n endRow: node.endPosition.row,\n endCol: node.endPosition.column,\n startByte: node.startIndex,\n endByte: node.endIndex,\n };\n}\n\nfunction symbolName(node: Parser.SyntaxNode, strategy: DefRule[\"name\"]): string | null {\n if (strategy === \"c_declarator\") return cDeclaratorName(node);\n return node.childForFieldName(\"name\")?.text ?? null;\n}\n\n/** Dig through C/C++ declarator chains (`int *foo(...)`) to the actual name. */\nfunction cDeclaratorName(node: Parser.SyntaxNode): string | null {\n let decl = node.childForFieldName(\"declarator\");\n for (let i = 0; decl && i < 10; i++) {\n if (decl.type === \"identifier\" || decl.type === \"field_identifier\") return decl.text;\n if (decl.type === \"qualified_identifier\" || decl.type === \"destructor_name\") {\n return decl.childForFieldName(\"name\")?.text ?? decl.text;\n }\n const inner = decl.childForFieldName(\"declarator\");\n if (!inner) break;\n decl = inner;\n }\n return null;\n}\n\n/** A definition is exported if an `export` statement directly wraps it. */\nfunction isExported(node: Parser.SyntaxNode, lang: LanguageConfig): boolean {\n if (lang.exportTypes.size === 0) return false;\n let cur = node.parent;\n for (let i = 0; cur && i < 2; i++) {\n if (lang.exportTypes.has(cur.type)) return true;\n cur = cur.parent;\n }\n return false;\n}\n\n/** The declaration text up to (but not including) the body, on one line. */\nfunction signatureOf(node: Parser.SyntaxNode): string | null {\n const body = node.childForFieldName(\"body\");\n const raw = body\n ? node.text.slice(0, body.startIndex - node.startIndex)\n : node.text;\n const text = raw.replace(/\\s+/g, \" \").trim();\n if (!text) return null;\n return text.length > 240 ? `${text.slice(0, 239)}…` : text;\n}\n\nfunction extractCall(\n node: Parser.SyntaxNode,\n rule: CallRule,\n container: string | null,\n): ParsedRef | null {\n let name: string | null = null;\n let kind: \"call\" | \"method\" = \"call\";\n\n if (rule.nameField) {\n // The call node carries the callee name directly (Java/Ruby/PHP member).\n name = node.childForFieldName(rule.nameField)?.text ?? null;\n if (rule.receiverField && node.childForFieldName(rule.receiverField)) kind = \"method\";\n } else if (rule.fnField) {\n const fn = node.childForFieldName(rule.fnField);\n if (fn) {\n if (rule.memberTypes?.includes(fn.type)) {\n name = fn.childForFieldName(rule.memberField ?? \"\")?.text ?? null;\n kind = \"method\";\n } else if (rule.scopedTypes?.includes(fn.type)) {\n name = fn.childForFieldName(rule.scopedField ?? \"\")?.text ?? null;\n } else if (fn.type === \"identifier\" || fn.type === \"name\") {\n name = fn.text;\n }\n }\n }\n\n if (rule.forceKind) kind = rule.forceKind;\n if (!name) return null;\n return {\n fromSymbol: container,\n name,\n kind,\n startRow: node.startPosition.row,\n startCol: node.startPosition.column,\n };\n}\n\nfunction extractImports(\n node: Parser.SyntaxNode,\n rule: ImportRule,\n container: string | null,\n): ParsedRef[] {\n const out: ParsedRef[] = [];\n const add = (spec: string | null | undefined): void => {\n const name = spec ? unquote(spec) : \"\";\n if (name) {\n out.push({\n fromSymbol: container,\n name,\n kind: \"import\",\n startRow: node.startPosition.row,\n startCol: node.startPosition.column,\n });\n }\n };\n\n if (rule.field) {\n add(node.childForFieldName(rule.field)?.text);\n }\n if (rule.childTypes) {\n for (const child of node.namedChildren) {\n if (!rule.childTypes.includes(child.type)) continue;\n // python `import x as y` exposes the real module under the `name` field\n if (child.type === \"aliased_import\") add(child.childForFieldName(\"name\")?.text);\n else add(child.text);\n }\n }\n return out;\n}\n\nfunction unquote(text: string): string {\n const t = text.trim();\n if (t.length >= 2) {\n const first = t[0];\n const last = t[t.length - 1];\n if ((first === '\"' || first === \"'\" || first === \"`\") && first === last) {\n return t.slice(1, -1);\n }\n // C/C++ include targets: <stdio.h>\n if (first === \"<\" && last === \">\") return t.slice(1, -1);\n }\n return t;\n}\n\n/** Test helper: drop cached parsers so a fresh init can be exercised. */\nexport function _resetParsers(): void {\n parserCache.clear();\n initPromise = null;\n}\n","import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { z } from \"zod\";\nimport * as fmt from \"./format.js\";\nimport type { GraphStore } from \"./store.js\";\nimport { VERSION } from \"./version.js\";\n\nconst KIND = z.enum([\"function\", \"method\", \"class\", \"interface\", \"type\", \"enum\", \"variable\"]);\n\nfunction textResult(text: string): { content: Array<{ type: \"text\"; text: string }> } {\n return { content: [{ type: \"text\", text }] };\n}\n\n/**\n * Build the codescope MCP server over an already-populated {@link GraphStore}.\n * Tool descriptions are written *for the agent*: they nudge it to query the\n * graph instead of grepping and reading whole files.\n */\nexport function createServer(store: GraphStore): McpServer {\n const server = new McpServer({ name: \"codescope\", version: VERSION });\n\n server.registerTool(\n \"search_symbols\",\n {\n title: \"Search code symbols\",\n description:\n \"Fuzzy-search definitions (functions, classes, methods, interfaces, types, enums) by name across the whole repo. Prefer this over grep/glob/read when locating where something is defined — it returns exact file:line locations and signatures in a few tokens.\",\n inputSchema: {\n query: z.string().describe(\"substring to match against symbol names\"),\n kind: KIND.optional().describe(\"restrict to one symbol kind\"),\n limit: z.number().int().positive().max(500).optional(),\n },\n },\n async ({ query, kind, limit }) =>\n textResult(fmt.formatSymbols(store.searchSymbols(query, { kind, limit }))),\n );\n\n server.registerTool(\n \"get_symbol\",\n {\n title: \"Get a symbol definition\",\n description:\n \"Look up a definition by its exact name. Returns each matching definition's kind, file:line, and signature. Use this to jump straight to a definition instead of reading files.\",\n inputSchema: {\n name: z.string().describe(\"exact symbol name\"),\n limit: z.number().int().positive().max(500).optional(),\n },\n },\n async ({ name, limit }) => textResult(fmt.formatSymbols(store.getSymbol(name, { limit }))),\n );\n\n server.registerTool(\n \"find_callers\",\n {\n title: \"Find callers\",\n description:\n \"List the symbols that call a given function/method name, with file:line. Use this to trace impact and call sites without scanning files.\",\n inputSchema: {\n name: z.string().describe(\"the called function/method name\"),\n limit: z.number().int().positive().max(500).optional(),\n },\n },\n async ({ name, limit }) => textResult(fmt.formatRefs(store.findCallers(name, { limit }))),\n );\n\n server.registerTool(\n \"find_callees\",\n {\n title: \"Find callees\",\n description:\n \"List the functions/methods that a given symbol calls (resolved to their definitions). The outgoing side of the call graph — what this symbol depends on.\",\n inputSchema: {\n name: z.string().describe(\"the calling function/method name\"),\n limit: z.number().int().positive().max(500).optional(),\n },\n },\n async ({ name, limit }) => textResult(fmt.formatSymbols(store.findCallees(name, { limit }))),\n );\n\n server.registerTool(\n \"impact\",\n {\n title: \"Change impact / blast radius\",\n description:\n \"Show the transitive callers of a symbol — everything that could be affected if you change it — annotated with hop distance. Use before editing a widely-used function.\",\n inputSchema: {\n name: z.string(),\n depth: z.number().int().min(1).max(6).optional().describe(\"hops to expand (default 3)\"),\n limit: z.number().int().positive().max(300).optional(),\n },\n },\n async ({ name, depth, limit }) => textResult(fmt.formatImpact(store.impact(name, { depth, limit }))),\n );\n\n server.registerTool(\n \"context\",\n {\n title: \"Build task context\",\n description:\n \"Given a task or feature query, return a compact, ranked relevance map: the matching symbols plus their immediate call neighbourhood, ordered by how widely each is called. The fastest way to orient an agent before a change — graph facts instead of reading files.\",\n inputSchema: {\n query: z.string().describe(\"a task description or symbol/feature name\"),\n maxSymbols: z.number().int().min(5).max(100).optional().describe(\"cap on symbols (default 30)\"),\n },\n },\n async ({ query, maxSymbols }) => textResult(fmt.formatContext(store.context(query, { maxSymbols }))),\n );\n\n server.registerTool(\n \"find_references\",\n {\n title: \"Find references\",\n description:\n \"List all references (calls and imports) to a name. Useful for understanding how widely something is used.\",\n inputSchema: {\n name: z.string(),\n kind: z.enum([\"call\", \"method\", \"import\"]).optional(),\n limit: z.number().int().positive().max(500).optional(),\n },\n },\n async ({ name, kind, limit }) =>\n textResult(fmt.formatRefs(store.findReferences(name, { kind, limit }))),\n );\n\n server.registerTool(\n \"file_outline\",\n {\n title: \"Outline a file\",\n description:\n \"List every symbol defined in a file, in source order, with signatures. A compact alternative to reading the whole file when you only need its shape.\",\n inputSchema: {\n path: z.string().describe(\"repo-relative file path\"),\n },\n },\n async ({ path }) => textResult(fmt.formatSymbols(store.fileOutline(path))),\n );\n\n server.registerTool(\n \"neighborhood\",\n {\n title: \"Call neighbourhood\",\n description:\n \"Return the call neighbourhood around a symbol — its callers and callees expanded a few hops — as a compact subgraph. This is the high-leverage tool: it gives you the relevant slice of the codebase for a change without reading dozens of files.\",\n inputSchema: {\n name: z.string(),\n depth: z.number().int().min(1).max(5).optional().describe(\"hops to expand (default 2)\"),\n limit: z.number().int().positive().max(200).optional(),\n },\n },\n async ({ name, depth, limit }) =>\n textResult(fmt.formatNeighborhood(store.neighborhood(name, { depth, limit }))),\n );\n\n server.registerTool(\n \"stats\",\n {\n title: \"Graph stats\",\n description: \"Summary counts for the indexed graph (files, symbols, refs, by kind and language).\",\n inputSchema: {},\n },\n async () => textResult(fmt.formatStats(store.stats())),\n );\n\n return server;\n}\n\n/** Connect a codescope server to stdio (the transport coding agents speak). */\nexport async function runStdioServer(store: GraphStore): Promise<void> {\n const server = createServer(store);\n const transport = new StdioServerTransport();\n await server.connect(transport);\n}\n","/** The codescope version. Kept in sync with package.json at release time. */\nexport const VERSION = \"0.2.0\";\n","import Database from \"better-sqlite3\";\nimport type {\n ContextBundle,\n ImpactRow,\n IndexStats,\n Neighborhood,\n ParsedRef,\n ParsedSymbol,\n RefRow,\n SymbolKind,\n SymbolRow,\n} from \"./types.js\";\n\nexport interface FileMeta {\n path: string;\n lang: string;\n hash: string;\n size: number;\n mtime: number;\n}\n\nconst SCHEMA = `\nCREATE TABLE IF NOT EXISTS files (\n id INTEGER PRIMARY KEY,\n path TEXT NOT NULL UNIQUE,\n lang TEXT NOT NULL,\n hash TEXT NOT NULL,\n size INTEGER NOT NULL,\n mtime INTEGER NOT NULL,\n indexed_at INTEGER NOT NULL\n);\nCREATE TABLE IF NOT EXISTS symbols (\n id INTEGER PRIMARY KEY,\n file_id INTEGER NOT NULL REFERENCES files(id) ON DELETE CASCADE,\n name TEXT NOT NULL,\n kind TEXT NOT NULL,\n container TEXT,\n exported INTEGER NOT NULL DEFAULT 0,\n signature TEXT,\n start_row INTEGER NOT NULL,\n start_col INTEGER NOT NULL,\n end_row INTEGER NOT NULL,\n end_col INTEGER NOT NULL,\n start_byte INTEGER NOT NULL,\n end_byte INTEGER NOT NULL\n);\nCREATE TABLE IF NOT EXISTS refs (\n id INTEGER PRIMARY KEY,\n file_id INTEGER NOT NULL REFERENCES files(id) ON DELETE CASCADE,\n from_symbol TEXT,\n name TEXT NOT NULL,\n kind TEXT NOT NULL,\n start_row INTEGER NOT NULL,\n start_col INTEGER NOT NULL\n);\nCREATE INDEX IF NOT EXISTS idx_symbols_name ON symbols(name);\nCREATE INDEX IF NOT EXISTS idx_symbols_file ON symbols(file_id);\nCREATE INDEX IF NOT EXISTS idx_symbols_kind ON symbols(kind);\nCREATE INDEX IF NOT EXISTS idx_refs_name ON refs(name);\nCREATE INDEX IF NOT EXISTS idx_refs_file ON refs(file_id);\nCREATE INDEX IF NOT EXISTS idx_refs_from ON refs(from_symbol);\n\n-- Trigram FTS index for fast substring symbol search at scale. Kept in sync\n-- manually (rowid = symbols.id) so it survives the per-file replace/delete path.\nCREATE VIRTUAL TABLE IF NOT EXISTS symbols_fts USING fts5(name, tokenize='trigram');\n`;\n\ninterface SymbolDbRow {\n id: number;\n file: string;\n name: string;\n kind: string;\n container: string | null;\n exported: number;\n signature: string | null;\n start_row: number;\n start_col: number;\n end_row: number;\n end_col: number;\n}\n\ninterface RefDbRow {\n id: number;\n file: string;\n from_symbol: string | null;\n name: string;\n kind: string;\n start_row: number;\n start_col: number;\n}\n\nconst SYMBOL_COLUMNS = `\n s.id, f.path AS file, s.name, s.kind, s.container, s.exported, s.signature,\n s.start_row, s.start_col, s.end_row, s.end_col`;\n\n/**\n * The on-disk (or in-memory) code graph. All writes go through\n * {@link GraphStore.replaceFile} / {@link GraphStore.removeFile}, which operate\n * on a single file at a time so incremental updates stay O(file), not O(repo).\n */\nexport class GraphStore {\n readonly db: Database.Database;\n\n constructor(location = \":memory:\") {\n this.db = new Database(location);\n this.db.pragma(\"journal_mode = WAL\");\n this.db.pragma(\"foreign_keys = ON\");\n this.db.exec(SCHEMA);\n }\n\n /** The content hash of an already-indexed file, if present. */\n getFileHash(path: string): string | undefined {\n const row = this.db\n .prepare<[string], { hash: string }>(\"SELECT hash FROM files WHERE path = ?\")\n .get(path);\n return row?.hash;\n }\n\n /** All indexed file paths. */\n listFiles(): string[] {\n return this.db\n .prepare<[], { path: string }>(\"SELECT path FROM files ORDER BY path\")\n .all()\n .map((r) => r.path);\n }\n\n /** Insert or replace a file and all of its symbols/refs in one transaction. */\n replaceFile(meta: FileMeta, symbols: ParsedSymbol[], refs: ParsedRef[], now: number): void {\n this.transaction(() => {\n this.dropFtsForFile(meta.path);\n this.db.prepare(\"DELETE FROM files WHERE path = ?\").run(meta.path);\n const fileId = Number(\n this.db\n .prepare(\n \"INSERT INTO files (path, lang, hash, size, mtime, indexed_at) VALUES (?, ?, ?, ?, ?, ?)\",\n )\n .run(meta.path, meta.lang, meta.hash, meta.size, meta.mtime, now).lastInsertRowid,\n );\n\n const insSym = this.db.prepare(\n `INSERT INTO symbols\n (file_id, name, kind, container, exported, signature,\n start_row, start_col, end_row, end_col, start_byte, end_byte)\n VALUES (@file_id, @name, @kind, @container, @exported, @signature,\n @start_row, @start_col, @end_row, @end_col, @start_byte, @end_byte)`,\n );\n const insFts = this.db.prepare(\"INSERT INTO symbols_fts(rowid, name) VALUES (?, ?)\");\n for (const s of symbols) {\n const symId = insSym.run({\n file_id: fileId,\n name: s.name,\n kind: s.kind,\n container: s.container,\n exported: s.exported ? 1 : 0,\n signature: s.signature,\n start_row: s.startRow,\n start_col: s.startCol,\n end_row: s.endRow,\n end_col: s.endCol,\n start_byte: s.startByte,\n end_byte: s.endByte,\n }).lastInsertRowid;\n insFts.run(symId, s.name);\n }\n\n const insRef = this.db.prepare(\n `INSERT INTO refs (file_id, from_symbol, name, kind, start_row, start_col)\n VALUES (@file_id, @from_symbol, @name, @kind, @start_row, @start_col)`,\n );\n for (const r of refs) {\n insRef.run({\n file_id: fileId,\n from_symbol: r.fromSymbol,\n name: r.name,\n kind: r.kind,\n start_row: r.startRow,\n start_col: r.startCol,\n });\n }\n });\n }\n\n /** Remove a file and its symbols/refs. Returns true if anything was deleted. */\n removeFile(path: string): boolean {\n return this.transactionResult(() => {\n this.dropFtsForFile(path);\n return this.db.prepare(\"DELETE FROM files WHERE path = ?\").run(path).changes > 0;\n });\n }\n\n /** Remove the FTS rows for a file's current symbols (call before deleting it). */\n private dropFtsForFile(path: string): void {\n const ids = this.db\n .prepare<[string], { id: number }>(\n \"SELECT s.id FROM symbols s JOIN files f ON f.id = s.file_id WHERE f.path = ?\",\n )\n .all(path);\n if (ids.length === 0) return;\n const del = this.db.prepare(\"DELETE FROM symbols_fts WHERE rowid = ?\");\n for (const { id } of ids) del.run(id);\n }\n\n // ── Queries ────────────────────────────────────────────────────────────\n\n /**\n * Fuzzy substring search over symbol names. Queries of 3+ characters use the\n * trigram FTS index (fast at scale); shorter queries fall back to LIKE since\n * trigram matching needs at least three characters.\n */\n searchSymbols(query: string, opts: { kind?: SymbolKind; limit?: number } = {}): SymbolRow[] {\n const limit = clampLimit(opts.limit);\n if (query.trim().length >= 3) {\n const match = `\"${query.replace(/\"/g, '\"\"')}\"`;\n const rows = opts.kind\n ? this.db\n .prepare<[string, string, number], SymbolDbRow>(\n `SELECT ${SYMBOL_COLUMNS} FROM symbols_fts ft\n JOIN symbols s ON s.id = ft.rowid JOIN files f ON f.id = s.file_id\n WHERE symbols_fts MATCH ? AND s.kind = ?\n ORDER BY s.exported DESC, length(s.name), s.name LIMIT ?`,\n )\n .all(match, opts.kind, limit)\n : this.db\n .prepare<[string, number], SymbolDbRow>(\n `SELECT ${SYMBOL_COLUMNS} FROM symbols_fts ft\n JOIN symbols s ON s.id = ft.rowid JOIN files f ON f.id = s.file_id\n WHERE symbols_fts MATCH ?\n ORDER BY s.exported DESC, length(s.name), s.name LIMIT ?`,\n )\n .all(match, limit);\n return rows.map(toSymbolRow);\n }\n\n const like = `%${escapeLike(query)}%`;\n const rows = opts.kind\n ? this.db\n .prepare<[string, string, number], SymbolDbRow>(\n `SELECT ${SYMBOL_COLUMNS} FROM symbols s JOIN files f ON f.id = s.file_id\n WHERE s.name LIKE ? ESCAPE '\\\\' AND s.kind = ?\n ORDER BY s.exported DESC, length(s.name), s.name LIMIT ?`,\n )\n .all(like, opts.kind, limit)\n : this.db\n .prepare<[string, number], SymbolDbRow>(\n `SELECT ${SYMBOL_COLUMNS} FROM symbols s JOIN files f ON f.id = s.file_id\n WHERE s.name LIKE ? ESCAPE '\\\\'\n ORDER BY s.exported DESC, length(s.name), s.name LIMIT ?`,\n )\n .all(like, limit);\n return rows.map(toSymbolRow);\n }\n\n /** Exact-name definition lookup. */\n getSymbol(name: string, opts: { limit?: number } = {}): SymbolRow[] {\n return this.db\n .prepare<[string, number], SymbolDbRow>(\n `SELECT ${SYMBOL_COLUMNS} FROM symbols s JOIN files f ON f.id = s.file_id\n WHERE s.name = ? ORDER BY s.exported DESC, f.path LIMIT ?`,\n )\n .all(name, clampLimit(opts.limit))\n .map(toSymbolRow);\n }\n\n /**\n * Distinct callers of a name (both bare `foo()` and `x.foo()`). Multiple call\n * sites from the same caller in the same file collapse to one row — fewer\n * tokens and a more useful \"who depends on this\" answer.\n */\n findCallers(name: string, opts: { limit?: number } = {}): RefRow[] {\n return this.db\n .prepare<[string, number], RefDbRow>(\n `SELECT MIN(r.id) AS id, f.path AS file, r.from_symbol, r.name,\n MIN(r.kind) AS kind, MIN(r.start_row) AS start_row, MIN(r.start_col) AS start_col\n FROM refs r JOIN files f ON f.id = r.file_id\n WHERE r.name = ? AND r.kind IN ('call', 'method')\n GROUP BY f.path, r.from_symbol\n ORDER BY f.path, start_row LIMIT ?`,\n )\n .all(name, clampLimit(opts.limit))\n .map(toRefRow);\n }\n\n /** The definitions that a symbol calls, resolved kind-aware to project symbols. */\n findCallees(name: string, opts: { limit?: number } = {}): SymbolRow[] {\n const limit = clampLimit(opts.limit);\n const out: SymbolRow[] = [];\n const seen = new Set<string>();\n for (const callee of this.calleesOf(name)) {\n const defs = this.resolveCallee(callee.name, callee.kind, 6);\n if (!defs) continue;\n for (const d of defs) {\n const key = `${d.name}@${d.file}:${d.startRow}`;\n if (!seen.has(key)) {\n seen.add(key);\n out.push(d);\n if (out.length >= limit) return out;\n }\n }\n }\n return out;\n }\n\n /** How many call sites reference this name (popularity / centrality signal). */\n callerCount(name: string): number {\n return (\n this.db\n .prepare<[string], { n: number }>(\n \"SELECT COUNT(*) AS n FROM refs WHERE name = ? AND kind IN ('call','method')\",\n )\n .get(name)?.n ?? 0\n );\n }\n\n /**\n * The blast radius of changing a symbol: its transitive callers, breadth-first,\n * annotated with hop distance and ordered nearest-first. Answers \"what could\n * break if I change this?\" without reading the codebase.\n */\n impact(name: string, opts: { depth?: number; limit?: number } = {}): ImpactRow[] {\n const depth = Math.max(1, Math.min(opts.depth ?? 3, 6));\n const limit = clampLimit(opts.limit, 300);\n const distance = new Map<string, number>([[name, 0]]);\n let frontier = [name];\n for (let d = 0; d < depth && frontier.length > 0 && distance.size < limit; d++) {\n const next: string[] = [];\n for (const node of frontier) {\n for (const caller of this.callersOf(node)) {\n if (!distance.has(caller)) {\n distance.set(caller, d + 1);\n next.push(caller);\n }\n }\n }\n frontier = next;\n }\n const out: ImpactRow[] = [];\n for (const [n, dist] of distance) {\n if (dist === 0) continue; // exclude the symbol itself\n for (const def of this.getSymbol(n, { limit: 3 })) out.push({ ...def, distance: dist });\n }\n out.sort((a, b) => a.distance - b.distance || a.file.localeCompare(b.file));\n return out.slice(0, limit);\n }\n\n /**\n * A token-budgeted relevance map for a task: the symbols matching `query` plus\n * their immediate call neighbourhood, ranked by call-site centrality, capped at\n * `maxSymbols`. This is the slice of the codebase an agent needs to start a\n * change — delivered as graph facts, not file dumps.\n */\n context(query: string, opts: { maxSymbols?: number } = {}): ContextBundle {\n const maxSymbols = Math.max(5, Math.min(opts.maxSymbols ?? 30, 100));\n const seeds = this.searchSymbols(query, { limit: Math.min(8, maxSymbols) });\n const picked = new Map<string, SymbolRow>();\n const key = (s: SymbolRow): string => `${s.name}@${s.file}:${s.startRow}`;\n for (const s of seeds) picked.set(key(s), s);\n\n // Gather neighbours of each seed, ranked by how widely they are called.\n const candidates = new Map<string, { row: SymbolRow; score: number }>();\n const edges: Array<{ from: string; to: string }> = [];\n const edgeKeys = new Set<string>();\n for (const seed of seeds) {\n for (const callee of this.findCallees(seed.name, { limit: 15 })) {\n addEdge(edges, edgeKeys, seed.name, callee.name);\n const k = key(callee);\n if (!picked.has(k) && !candidates.has(k)) {\n candidates.set(k, { row: callee, score: this.callerCount(callee.name) });\n }\n }\n for (const caller of this.findCallers(seed.name, { limit: 15 })) {\n if (!caller.fromSymbol) continue;\n addEdge(edges, edgeKeys, caller.fromSymbol, seed.name);\n for (const def of this.getSymbol(caller.fromSymbol, { limit: 1 })) {\n const k = key(def);\n if (!picked.has(k) && !candidates.has(k)) {\n candidates.set(k, { row: def, score: this.callerCount(def.name) });\n }\n }\n }\n }\n\n const related = [...candidates.values()]\n .sort((a, b) => b.score - a.score)\n .slice(0, Math.max(0, maxSymbols - picked.size))\n .map((c) => c.row);\n\n const keptNames = new Set([...seeds, ...related].map((s) => s.name));\n return {\n query,\n seeds,\n related,\n edges: edges.filter((e) => keptNames.has(e.from) && keptNames.has(e.to)),\n };\n }\n\n /** All references (calls + imports) to a name. */\n findReferences(\n name: string,\n opts: { kind?: \"call\" | \"method\" | \"import\"; limit?: number } = {},\n ): RefRow[] {\n const limit = clampLimit(opts.limit);\n const rows = opts.kind\n ? this.db\n .prepare<[string, string, number], RefDbRow>(\n `SELECT r.id, f.path AS file, r.from_symbol, r.name, r.kind, r.start_row, r.start_col\n FROM refs r JOIN files f ON f.id = r.file_id\n WHERE r.name = ? AND r.kind = ? ORDER BY f.path, r.start_row LIMIT ?`,\n )\n .all(name, opts.kind, limit)\n : this.db\n .prepare<[string, number], RefDbRow>(\n `SELECT r.id, f.path AS file, r.from_symbol, r.name, r.kind, r.start_row, r.start_col\n FROM refs r JOIN files f ON f.id = r.file_id\n WHERE r.name = ? ORDER BY f.path, r.start_row LIMIT ?`,\n )\n .all(name, limit);\n return rows.map(toRefRow);\n }\n\n /** The symbols defined in a file, in source order. */\n fileOutline(path: string): SymbolRow[] {\n return this.db\n .prepare<[string], SymbolDbRow>(\n `SELECT ${SYMBOL_COLUMNS} FROM symbols s JOIN files f ON f.id = s.file_id\n WHERE f.path = ? ORDER BY s.start_row, s.start_col`,\n )\n .all(path)\n .map(toSymbolRow);\n }\n\n /** Distinct (callee, callKind) pairs invoked from inside symbols named `from`. */\n private calleesOf(from: string): Array<{ name: string; kind: \"call\" | \"method\" }> {\n return this.db\n .prepare<[string], { name: string; kind: \"call\" | \"method\" }>(\n \"SELECT DISTINCT name, kind FROM refs WHERE from_symbol = ? AND kind IN ('call','method')\",\n )\n .all(from);\n }\n\n /** Distinct caller symbol names that invoke `name`. */\n private callersOf(name: string): string[] {\n return this.db\n .prepare<[string], { from_symbol: string }>(\n \"SELECT DISTINCT from_symbol FROM refs WHERE name = ? AND kind IN ('call','method') AND from_symbol IS NOT NULL\",\n )\n .all(name)\n .map((r) => r.from_symbol);\n }\n\n /**\n * Resolve a callee name to project definitions, honouring how it was called:\n * a bare `foo()` resolves to non-method symbols, an `x.foo()` resolves to\n * methods. Ambiguous names (more than `ambiguityCap` definitions — typically\n * library-ish names like `push`/`map`) are treated as unresolved so they\n * don't blow up the neighbourhood. Returns `null` when nothing resolves.\n */\n private resolveCallee(\n name: string,\n callKind: \"call\" | \"method\",\n ambiguityCap: number,\n ): SymbolRow[] | null {\n const defs = this.getSymbol(name, { limit: ambiguityCap + 1 }).filter((d) =>\n callKind === \"method\" ? d.kind === \"method\" : d.kind !== \"method\",\n );\n if (defs.length === 0 || defs.length > ambiguityCap) return null;\n return defs;\n }\n\n /**\n * A bounded call neighbourhood around `name`: callers and callees expanded\n * breadth-first up to `depth`. Only edges between *resolvable project\n * symbols* are followed, so the result is the relevant slice of the codebase\n * — the payload a coding agent reads instead of grepping the whole repo.\n */\n neighborhood(\n name: string,\n opts: { depth?: number; limit?: number; maxFanout?: number; ambiguityCap?: number } = {},\n ): Neighborhood {\n const depth = Math.max(1, Math.min(opts.depth ?? 2, 5));\n const limit = clampLimit(opts.limit, 200);\n const maxFanout = opts.maxFanout ?? 25;\n const ambiguityCap = opts.ambiguityCap ?? 4;\n\n const seen = new Set<string>([name]);\n const edges: Array<{ from: string; to: string }> = [];\n const edgeKeys = new Set<string>();\n let frontier = [name];\n\n for (let d = 0; d < depth && frontier.length > 0 && seen.size < limit; d++) {\n const next = new Set<string>();\n for (const node of frontier) {\n let fanout = 0;\n for (const callee of this.calleesOf(node)) {\n if (fanout >= maxFanout) break;\n if (!this.resolveCallee(callee.name, callee.kind, ambiguityCap)) continue;\n fanout++;\n addEdge(edges, edgeKeys, node, callee.name);\n if (!seen.has(callee.name) && seen.size < limit) {\n seen.add(callee.name);\n next.add(callee.name);\n }\n }\n let callerFanout = 0;\n for (const caller of this.callersOf(node)) {\n if (callerFanout >= maxFanout) break;\n callerFanout++;\n addEdge(edges, edgeKeys, caller, node);\n if (!seen.has(caller) && seen.size < limit) {\n seen.add(caller);\n next.add(caller);\n }\n }\n }\n frontier = [...next];\n }\n\n const nodes: SymbolRow[] = [];\n const unresolved: string[] = [];\n for (const n of seen) {\n const defs = this.getSymbol(n, { limit: 5 });\n if (defs.length > 0) nodes.push(...defs);\n else unresolved.push(n);\n }\n return { root: name, nodes, edges, unresolved };\n }\n\n /** Aggregate counts for the whole graph. */\n stats(): IndexStats {\n const files = this.count(\"SELECT COUNT(*) AS n FROM files\");\n const symbols = this.count(\"SELECT COUNT(*) AS n FROM symbols\");\n const refs = this.count(\"SELECT COUNT(*) AS n FROM refs\");\n const byKind: Record<string, number> = {};\n for (const r of this.db\n .prepare<[], { kind: string; n: number }>(\n \"SELECT kind, COUNT(*) AS n FROM symbols GROUP BY kind\",\n )\n .all()) {\n byKind[r.kind] = r.n;\n }\n const byLang: Record<string, number> = {};\n for (const r of this.db\n .prepare<[], { lang: string; n: number }>(\n \"SELECT lang, COUNT(*) AS n FROM files GROUP BY lang\",\n )\n .all()) {\n byLang[r.lang] = r.n;\n }\n return { files, symbols, refs, byKind, byLang };\n }\n\n close(): void {\n this.db.close();\n }\n\n private count(sql: string): number {\n return this.db.prepare<[], { n: number }>(sql).get()?.n ?? 0;\n }\n\n private transaction(fn: () => void): void {\n this.db.transaction(fn)();\n }\n\n private transactionResult<T>(fn: () => T): T {\n return this.db.transaction(fn)();\n }\n}\n\nfunction addEdge(\n edges: Array<{ from: string; to: string }>,\n keys: Set<string>,\n from: string,\n to: string,\n): void {\n const key = `${from}\u0000${to}`;\n if (!keys.has(key)) {\n keys.add(key);\n edges.push({ from, to });\n }\n}\n\nfunction clampLimit(limit: number | undefined, max = 500): number {\n if (!limit || limit <= 0) return 50;\n return Math.min(limit, max);\n}\n\nfunction escapeLike(s: string): string {\n return s.replace(/[\\\\%_]/g, (c) => `\\\\${c}`);\n}\n\nfunction toSymbolRow(r: SymbolDbRow): SymbolRow {\n return {\n id: r.id,\n file: r.file,\n name: r.name,\n kind: r.kind as SymbolKind,\n container: r.container,\n exported: r.exported === 1,\n signature: r.signature,\n startRow: r.start_row,\n startCol: r.start_col,\n endRow: r.end_row,\n endCol: r.end_col,\n };\n}\n\nfunction toRefRow(r: RefDbRow): RefRow {\n return {\n id: r.id,\n file: r.file,\n fromSymbol: r.from_symbol,\n name: r.name,\n kind: r.kind as RefRow[\"kind\"],\n startRow: r.start_row,\n startCol: r.start_col,\n };\n}\n","import { watch as chokidarWatch } from \"chokidar\";\nimport { languageForPath } from \"./languages.js\";\nimport type { Indexer } from \"./indexer.js\";\n\nexport interface WatchEvents {\n /** A file was (re-)indexed or removed from the graph. */\n onChange?: (relPath: string, action: \"indexed\" | \"removed\") => void;\n onError?: (error: unknown) => void;\n /** Fired once the initial scan has settled and the watcher is live. */\n onReady?: () => void;\n}\n\nexport interface WatchOptions {\n /** Force polling — slower but deterministic, useful in tests/CI. */\n usePolling?: boolean;\n /** Polling interval in ms when `usePolling` is set. */\n interval?: number;\n}\n\nexport interface WatchHandle {\n close: () => Promise<void>;\n}\n\nconst IGNORED = /(?:^|[\\\\/])(?:node_modules|\\.git|dist|build|coverage|\\.codescope|target|__pycache__)(?:[\\\\/]|$)/;\n\n/**\n * Watch the indexer's root and keep the graph fresh as files change. This is\n * codescope's differentiator: the agent never reads a stale graph because the\n * graph re-indexes the touched file (and only that file) on save.\n */\nexport function watch(indexer: Indexer, events: WatchEvents = {}, opts: WatchOptions = {}): WatchHandle {\n const watcher = chokidarWatch(indexer.root, {\n ignoreInitial: true,\n ignored: (path: string) => IGNORED.test(path),\n usePolling: opts.usePolling,\n interval: opts.interval,\n });\n\n const onUpsert = (abs: string): void => {\n if (!languageForPath(abs)) return;\n indexer\n .indexFile(abs)\n .then((outcome) => {\n if (outcome === \"indexed\") events.onChange?.(indexer.rel(abs), \"indexed\");\n })\n .catch((err) => events.onError?.(err));\n };\n\n watcher\n .on(\"add\", onUpsert)\n .on(\"change\", onUpsert)\n .on(\"unlink\", (abs: string) => {\n if (indexer.removeFile(abs)) events.onChange?.(indexer.rel(abs), \"removed\");\n })\n .on(\"error\", (err: unknown) => events.onError?.(err))\n .on(\"ready\", () => events.onReady?.());\n\n return {\n close: () => watcher.close(),\n };\n}\n"],"mappings":"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","names":["resolve","require","rows","c","resolve"]}
package/dist/index.d.ts CHANGED
@@ -93,6 +93,20 @@ interface Neighborhood {
93
93
  /** Names referenced in the graph that have no definition in the index. */
94
94
  unresolved: string[];
95
95
  }
96
+ /** A symbol in a blast-radius result, with its hop distance from the root. */
97
+ type ImpactRow = SymbolRow & {
98
+ distance: number;
99
+ };
100
+ /** A token-budgeted task-context map: seed matches + ranked neighbours + edges. */
101
+ interface ContextBundle {
102
+ query: string;
103
+ seeds: SymbolRow[];
104
+ related: SymbolRow[];
105
+ edges: Array<{
106
+ from: string;
107
+ to: string;
108
+ }>;
109
+ }
96
110
  interface IndexStats {
97
111
  files: number;
98
112
  symbols: number;
@@ -149,10 +163,38 @@ declare class GraphStore {
149
163
  getSymbol(name: string, opts?: {
150
164
  limit?: number;
151
165
  }): SymbolRow[];
152
- /** Symbols that call a given name (both bare `foo()` and `x.foo()`). */
166
+ /**
167
+ * Distinct callers of a name (both bare `foo()` and `x.foo()`). Multiple call
168
+ * sites from the same caller in the same file collapse to one row — fewer
169
+ * tokens and a more useful "who depends on this" answer.
170
+ */
153
171
  findCallers(name: string, opts?: {
154
172
  limit?: number;
155
173
  }): RefRow[];
174
+ /** The definitions that a symbol calls, resolved kind-aware to project symbols. */
175
+ findCallees(name: string, opts?: {
176
+ limit?: number;
177
+ }): SymbolRow[];
178
+ /** How many call sites reference this name (popularity / centrality signal). */
179
+ callerCount(name: string): number;
180
+ /**
181
+ * The blast radius of changing a symbol: its transitive callers, breadth-first,
182
+ * annotated with hop distance and ordered nearest-first. Answers "what could
183
+ * break if I change this?" without reading the codebase.
184
+ */
185
+ impact(name: string, opts?: {
186
+ depth?: number;
187
+ limit?: number;
188
+ }): ImpactRow[];
189
+ /**
190
+ * A token-budgeted relevance map for a task: the symbols matching `query` plus
191
+ * their immediate call neighbourhood, ranked by call-site centrality, capped at
192
+ * `maxSymbols`. This is the slice of the codebase an agent needs to start a
193
+ * change — delivered as graph facts, not file dumps.
194
+ */
195
+ context(query: string, opts?: {
196
+ maxSymbols?: number;
197
+ }): ContextBundle;
156
198
  /** All references (calls + imports) to a name. */
157
199
  findReferences(name: string, opts?: {
158
200
  kind?: "call" | "method" | "import";
@@ -321,17 +363,21 @@ declare function runStdioServer(store: GraphStore): Promise<void>;
321
363
  declare function formatSymbols(rows: SymbolRow[]): string;
322
364
  declare function formatRefs(rows: RefRow[]): string;
323
365
  declare function formatNeighborhood(n: Neighborhood): string;
366
+ declare function formatImpact(rows: ImpactRow[]): string;
367
+ declare function formatContext(b: ContextBundle): string;
324
368
  declare function formatStats(s: IndexStats): string;
325
369
 
370
+ declare const format_formatContext: typeof formatContext;
371
+ declare const format_formatImpact: typeof formatImpact;
326
372
  declare const format_formatNeighborhood: typeof formatNeighborhood;
327
373
  declare const format_formatRefs: typeof formatRefs;
328
374
  declare const format_formatStats: typeof formatStats;
329
375
  declare const format_formatSymbols: typeof formatSymbols;
330
376
  declare namespace format {
331
- export { format_formatNeighborhood as formatNeighborhood, format_formatRefs as formatRefs, format_formatStats as formatStats, format_formatSymbols as formatSymbols };
377
+ export { format_formatContext as formatContext, format_formatImpact as formatImpact, format_formatNeighborhood as formatNeighborhood, format_formatRefs as formatRefs, format_formatStats as formatStats, format_formatSymbols as formatSymbols };
332
378
  }
333
379
 
334
380
  /** The codescope version. Kept in sync with package.json at release time. */
335
- declare const VERSION = "0.1.0";
381
+ declare const VERSION = "0.2.0";
336
382
 
337
- export { type FileIndexOutcome, type FileMeta, GraphStore, type IndexOptions, type IndexRunResult, type IndexStats, Indexer, LANGUAGES, type LanguageConfig, type Neighborhood, type ParseResult, type ParsedRef, type ParsedSymbol, type RefKind, type RefRow, SUPPORTED_EXTENSIONS, type SymbolKind, type SymbolRow, VERSION, type WatchEvents, type WatchHandle, type WatchOptions, createServer, format, languageForPath, parseSource, runStdioServer, watch };
383
+ export { type ContextBundle, type FileIndexOutcome, type FileMeta, GraphStore, type ImpactRow, type IndexOptions, type IndexRunResult, type IndexStats, Indexer, LANGUAGES, type LanguageConfig, type Neighborhood, type ParseResult, type ParsedRef, type ParsedSymbol, type RefKind, type RefRow, SUPPORTED_EXTENSIONS, type SymbolKind, type SymbolRow, VERSION, type WatchEvents, type WatchHandle, type WatchOptions, createServer, format, languageForPath, parseSource, runStdioServer, watch };