@leanlabsinnov/codegraph 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/dist/bin.js +2 -2
- package/dist/{chunk-VFE242Y7.js → chunk-2TORJYBO.js} +53 -41
- package/dist/chunk-2TORJYBO.js.map +1 -0
- package/dist/{chunk-AMJXGXLM.js → chunk-36AWRLQ6.js} +36 -42
- package/dist/chunk-36AWRLQ6.js.map +1 -0
- package/dist/index.js +2 -2
- package/dist/{src-7P6XREHJ.js → src-PDNTANJD.js} +4 -4
- package/package.json +3 -3
- package/dist/chunk-AMJXGXLM.js.map +0 -1
- package/dist/chunk-VFE242Y7.js.map +0 -1
- /package/dist/{src-7P6XREHJ.js.map → src-PDNTANJD.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/config-store.ts","../src/ui.ts","../src/program.ts","../src/commands/config.ts","../src/commands/doctor.ts","../src/commands/index.ts","../../ingestion/src/parser.ts","../../ingestion/src/extractors/extract.ts","../../ingestion/src/walker.ts","../../ingestion/src/extractors/routes.ts","../../ingestion/src/extractors/resolve.ts","../../ingestion/src/orchestrator.ts","../../ingestion/src/embedder.ts","../../ingestion/src/repo-walker.ts","../src/repo-id.ts","../../mcp-server/src/bootstrap.ts","../../mcp-server/src/cache.ts","../../mcp-server/src/config.ts","../../mcp-server/src/server.ts","../../mcp-server/src/tools/affected-by.ts","../../mcp-server/src/tools/util.ts","../../mcp-server/src/tools/blast-radius.ts","../../mcp-server/src/tools/find-callers.ts","../../mcp-server/src/tools/find-file.ts","../../mcp-server/src/tools/get-component-tree.ts","../../mcp-server/src/tools/get-dependencies.ts","../../mcp-server/src/tools/get-file-context.ts","../../mcp-server/src/tools/nl-query.ts","../../mcp-server/src/cypher-guard.ts","../../mcp-server/src/tools/search-semantic.ts","../../mcp-server/src/tools/search-symbol.ts","../../mcp-server/src/tools/index.ts","../../mcp-server/src/logger.ts","../src/commands/serve.ts"],"sourcesContent":["import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { type CodegraphConfig, DEFAULT_CONFIG } from \"@codegraph/shared\";\n\nconst CONFIG_DIR = path.join(os.homedir(), \".codegraph\");\nconst CONFIG_FILE = path.join(CONFIG_DIR, \"config.json\");\n\nexport function configPath(): string {\n return CONFIG_FILE;\n}\n\nexport async function loadConfig(): Promise<CodegraphConfig> {\n try {\n const raw = await readFile(CONFIG_FILE, \"utf8\");\n const parsed = JSON.parse(raw) as Partial<CodegraphConfig>;\n return mergeConfig(DEFAULT_CONFIG, parsed);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") {\n return DEFAULT_CONFIG;\n }\n throw err;\n }\n}\n\nexport async function saveConfig(config: CodegraphConfig): Promise<void> {\n await mkdir(CONFIG_DIR, { recursive: true });\n await writeFile(CONFIG_FILE, `${JSON.stringify(config, null, 2)}\\n`, \"utf8\");\n}\n\nfunction mergeConfig(base: CodegraphConfig, override: Partial<CodegraphConfig>): CodegraphConfig {\n return {\n llm: {\n ...base.llm,\n ...(override.llm ?? {}),\n generation: { ...base.llm.generation, ...(override.llm?.generation ?? {}) },\n embeddings: { ...base.llm.embeddings, ...(override.llm?.embeddings ?? {}) },\n },\n server: { ...base.server, ...(override.server ?? {}) },\n data: { ...base.data, ...(override.data ?? {}) },\n };\n}\n","import boxen from \"boxen\";\nimport Table from \"cli-table3\";\nimport kleur from \"kleur\";\nimport ora, { type Ora } from \"ora\";\n\n/**\n * Shared terminal-UI helpers used by every CLI command. Keeping them in one place means\n * the look-and-feel stays consistent and tests can replace them with no-ops if needed.\n */\n\n/** ASCII wordmark printed by the banner box. Roman font, stripped of trailing whitespace. */\nconst ASCII_LOGO = ` ___ _ ___ _\n / __\\\\___ __| | ___ / _ \\\\_ __ __ _ _ __ | |__\n / / / _ \\\\ / _\\` |/ _ \\\\/ /_\\\\/ '__/ _\\` | '_ \\\\| '_ \\\\\n/ /__| (_) | (_| | __/ /_\\\\\\\\| | | (_| | |_) | | | |\n\\\\____/\\\\___/ \\\\__,_|\\\\___\\\\____/|_| \\\\__,_| .__/|_| |_|\n |_|`;\n\nconst TAGLINE = \"Live, queryable knowledge graph for your codebase.\";\n\n/** First-run / --help banner. Quiet in non-TTY contexts so it doesn't pollute pipes. */\nexport function printBanner(): void {\n if (!process.stdout.isTTY) return;\n const body = `${kleur.cyan(ASCII_LOGO)}\\n\\n${kleur.dim(TAGLINE)}`;\n process.stdout.write(\n `${boxen(body, {\n padding: { top: 0, bottom: 0, left: 2, right: 2 },\n margin: { top: 0, bottom: 1, left: 0, right: 0 },\n borderStyle: \"round\",\n borderColor: \"cyan\",\n title: kleur.bold(\"codegraph\"),\n titleAlignment: \"left\",\n })}\\n`,\n );\n}\n\n/**\n * Create an `ora` spinner that disables itself when not on a TTY (so CI logs stay clean)\n * and renders consistent prefix-text formatting.\n */\nexport function makeSpinner(text: string): Ora {\n return ora({\n text,\n color: \"cyan\",\n spinner: \"dots\",\n isEnabled: process.stdout.isTTY === true,\n });\n}\n\n/**\n * Minimal text-mode progress bar. Re-renders in place on the same line; falls back to a\n * dim per-step line in non-TTY contexts (CI logs).\n */\nexport class ProgressBar {\n private lastRender = 0;\n private readonly width: number;\n constructor(\n private readonly label: string,\n private readonly total: number,\n width = 28,\n ) {\n this.width = width;\n }\n\n update(current: number): void {\n if (this.total <= 0) return;\n if (process.stdout.isTTY !== true) {\n // Non-TTY: print every 25th step so logs stay short but show progress.\n if (current === this.total || current - this.lastRender >= 25) {\n process.stdout.write(`${kleur.dim(`${this.label}: ${current}/${this.total}`)}\\n`);\n this.lastRender = current;\n }\n return;\n }\n const ratio = Math.min(1, current / this.total);\n const filled = Math.round(ratio * this.width);\n const bar = `${\"█\".repeat(filled)}${\"░\".repeat(this.width - filled)}`;\n const pct = `${(ratio * 100).toFixed(0).padStart(3)}%`;\n process.stdout.write(\n `\\r${kleur.cyan(this.label.padEnd(10))} ${kleur.cyan(bar)} ${pct} ${current}/${this.total}`,\n );\n if (current >= this.total) process.stdout.write(\"\\n\");\n }\n\n done(): void {\n this.update(this.total);\n }\n}\n\n/** Render the `codegraph status` output as two compact tables plus a coverage line. */\nexport function renderStatusTables(\n repoId: string,\n stats: { nodes: Record<string, number>; edges: Record<string, number>; embeddingCoverage: number },\n): string {\n const nodeTable = new Table({\n head: [kleur.bold(\"Node kind\"), kleur.bold(\"Count\")],\n colAligns: [\"left\", \"right\"],\n style: { head: [], border: [\"grey\"] },\n });\n for (const [kind, count] of Object.entries(stats.nodes)) {\n nodeTable.push([kind, count]);\n }\n const edgeTable = new Table({\n head: [kleur.bold(\"Edge kind\"), kleur.bold(\"Count\")],\n colAligns: [\"left\", \"right\"],\n style: { head: [], border: [\"grey\"] },\n });\n for (const [kind, count] of Object.entries(stats.edges)) {\n edgeTable.push([kind, count]);\n }\n const coverage = `${kleur.bold(\"Embedding coverage:\")} ${kleur.cyan(\n `${(stats.embeddingCoverage * 100).toFixed(1)}%`,\n )}`;\n return [kleur.bold(`Status for ${repoId}`), \"\", nodeTable.toString(), edgeTable.toString(), coverage].join(\"\\n\");\n}\n\n/** Render a pretty error block. Used by the top-level bin.ts catch. */\nexport function renderError(err: unknown, opts: { verbose: boolean } = { verbose: false }): string {\n const message = err instanceof Error ? err.message : String(err);\n const hint = friendlyHint(message);\n const lines = [kleur.red().bold(\"✗ codegraph hit an error\"), \"\", kleur.red(message)];\n if (hint) {\n lines.push(\"\", kleur.yellow(\"hint: \"), kleur.yellow(hint));\n }\n if (opts.verbose && err instanceof Error && err.stack) {\n lines.push(\"\", kleur.dim(err.stack));\n } else if (err instanceof Error) {\n lines.push(\"\", kleur.dim(\"(re-run with --verbose for a full stack trace)\"));\n }\n return boxen(lines.join(\"\\n\"), {\n padding: 1,\n borderColor: \"red\",\n borderStyle: \"round\",\n });\n}\n\n/**\n * Map common error messages to specific, actionable hints. Keeps support load down by\n * answering the most common Slack pings inline.\n */\nfunction friendlyHint(message: string): string | null {\n if (/OPENAI_API_KEY/i.test(message) || /api key/i.test(message)) {\n return \"Set OPENAI_API_KEY in your shell (or switch to local-ollama with `codegraph config llm set local-ollama`).\";\n }\n if (/ANTHROPIC_API_KEY/i.test(message)) {\n return \"Set ANTHROPIC_API_KEY, or switch presets via `codegraph config llm set <preset>`.\";\n }\n if (/GOOGLE_GENERATIVE_AI_API_KEY/i.test(message)) {\n return \"Set GOOGLE_GENERATIVE_AI_API_KEY, or switch presets via `codegraph config llm set <preset>`.\";\n }\n if (/ECONNREFUSED/.test(message) && /11434/.test(message)) {\n return \"Ollama isn't running on :11434. Start it with `ollama serve`, or switch to a hosted provider.\";\n }\n if (/EACCES|permission denied/i.test(message)) {\n return \"Codegraph stores data in ~/.codegraph. Check that the directory is writable.\";\n }\n if (/database is locked/i.test(message) || /Lock file/i.test(message)) {\n return \"Another `codegraph` process holds the Kuzu DB. Stop it (or remove ~/.codegraph/graph/.lock) before retrying.\";\n }\n if (/Unknown preset/i.test(message)) {\n return \"Run `codegraph config llm set` with no args for an interactive prompt.\";\n }\n return null;\n}\n\n/** Highlighted success banner for the serve command. */\nexport function renderServeBanner(url: string, tokenHint: string): string {\n const body = [\n `${kleur.green(\"✓\")} codegraph mcp listening on ${kleur.cyan(url)}`,\n \"\",\n kleur.dim(tokenHint),\n kleur.dim(\"Ctrl-C to stop.\"),\n ].join(\"\\n\");\n return boxen(body, {\n padding: { top: 0, bottom: 0, left: 2, right: 2 },\n margin: { top: 1, bottom: 1, left: 0, right: 0 },\n borderColor: \"green\",\n borderStyle: \"round\",\n });\n}\n","import { Command } from \"commander\";\nimport { runConfigLlmSet, runConfigLlmTest, runConfigShow } from \"./commands/config.js\";\nimport { runDoctorCommand } from \"./commands/doctor.js\";\nimport { runIndexCommand, runStatusCommand } from \"./commands/index.js\";\nimport { runServeCommand } from \"./commands/serve.js\";\nimport { printBanner } from \"./ui.js\";\n\nexport function buildProgram(): Command {\n const program = new Command();\n program\n .name(\"codegraph\")\n .description(\"Live, queryable knowledge graph for your codebase\")\n .version(\"0.1.0\")\n .option(\"--verbose\", \"Print full stack traces on error\")\n .hook(\"preAction\", (thisCommand) => {\n // Promote `--verbose` to an env var so the top-level error handler in bin.ts can\n // pick it up without threading it through every command.\n const opts = thisCommand.optsWithGlobals();\n if (opts.verbose) process.env.CODEGRAPH_VERBOSE = \"1\";\n });\n\n // Print the banner on bare `codegraph` (no subcommand) and on `--help`.\n program.on(\"--help\", () => {\n printBanner();\n });\n\n program\n .command(\"index\")\n .description(\"Parse a JS/TS repo into the local embedded graph\")\n .argument(\"<path>\", \"Path to the repo root\")\n .option(\"--no-embed\", \"Skip the embedding pass (faster, no LLM calls)\")\n .action(async (repoPath: string, opts: { embed?: boolean }) => {\n await runIndexCommand({ repoPath, noEmbed: opts.embed === false });\n });\n\n program\n .command(\"status\")\n .description(\"Show node/edge counts and embedding coverage for a repo\")\n .argument(\"<path>\", \"Path to the repo root\")\n .action(async (repoPath: string) => {\n await runStatusCommand({ repoPath });\n });\n\n program\n .command(\"serve\")\n .description(\"Boot the local MCP server (default port 3748)\")\n .option(\"--port <port>\", \"TCP port to bind\", (v) => Number(v))\n .option(\"--host <host>\", \"Host to bind (default 127.0.0.1)\")\n .option(\"--db-path <path>\", \"Override the embedded Kuzu graph directory\")\n .action(async (opts: { port?: number; host?: string; dbPath?: string }) => {\n await runServeCommand({\n ...(opts.port !== undefined ? { port: opts.port } : {}),\n ...(opts.host !== undefined ? { host: opts.host } : {}),\n ...(opts.dbPath !== undefined ? { dbPath: opts.dbPath } : {}),\n });\n });\n\n program\n .command(\"doctor\")\n .description(\"Check environment, config, LLM credentials, and Kuzu DB health\")\n .action(async () => {\n await runDoctorCommand();\n });\n\n const configCmd = program.command(\"config\").description(\"Manage ~/.codegraph/config.json\");\n configCmd\n .command(\"show\")\n .description(\"Print the resolved config\")\n .action(async () => {\n await runConfigShow();\n });\n const llmCmd = configCmd.command(\"llm\").description(\"Configure the LLM router\");\n llmCmd\n .command(\"set [preset]\")\n .description(\n \"Set LLM preset: managed-stub | byo-openai | byo-anthropic | byo-google | local-ollama. Omit the preset to pick interactively.\",\n )\n .action(async (preset?: string) => {\n await runConfigLlmSet(preset);\n });\n llmCmd\n .command(\"test\")\n .description(\"Run a 5-token generation + 1 embedding call against the current config\")\n .action(async () => {\n await runConfigLlmTest();\n });\n\n return program;\n}\n","import { password, select } from \"@inquirer/prompts\";\nimport { createLlmRouter, namespaceLabel } from \"@codegraph/llm-router\";\nimport { LLM_PRESETS } from \"@codegraph/shared\";\nimport kleur from \"kleur\";\nimport { configPath, loadConfig, saveConfig } from \"../config-store.js\";\nimport { makeSpinner } from \"../ui.js\";\n\nexport async function runConfigShow(): Promise<void> {\n const config = await loadConfig();\n console.log(kleur.dim(`config file: ${configPath()}`));\n console.log(JSON.stringify(config, null, 2));\n}\n\n/**\n * If called with a preset arg, applies it non-interactively. Otherwise launches an\n * interactive picker (preset + optional API key) - this is the path the first-run\n * onboarding takes.\n */\nexport async function runConfigLlmSet(presetArg?: string): Promise<void> {\n const presetKeys = Object.keys(LLM_PRESETS);\n let preset = presetArg;\n if (!preset) {\n preset = await select({\n message: \"Which LLM preset?\",\n choices: presetKeys.map((id) => ({\n name: id,\n value: id,\n description: describePreset(id),\n })),\n });\n }\n const lookup = LLM_PRESETS[preset];\n if (!lookup) {\n throw new Error(`Unknown preset \"${preset}\". Available: ${presetKeys.join(\", \")}`);\n }\n const config = await loadConfig();\n config.llm = { ...config.llm, ...lookup };\n await saveConfig(config);\n console.log(kleur.green(`✓ saved preset \"${preset}\" to ${configPath()}`));\n console.log(kleur.dim(`embedding namespace: ${namespaceLabel(config.llm)}`));\n\n if (!presetArg) {\n await maybePromptForApiKey(preset);\n }\n}\n\n/**\n * Best-effort prompt for the API key the chosen preset needs. We persist it via a stdout\n * hint rather than writing it to disk - shell history / env vars are still the right place\n * for secrets.\n */\nasync function maybePromptForApiKey(preset: string): Promise<void> {\n const envVar = apiKeyEnvVarFor(preset);\n if (!envVar) return;\n if (process.env[envVar]) {\n console.log(kleur.dim(`✓ ${envVar} already set in environment`));\n return;\n }\n const provideNow = await select({\n message: `${envVar} is not set. Provide it now?`,\n choices: [\n { name: \"Yes (paste; I'll print the export line)\", value: \"yes\" },\n { name: \"No, I'll set it later\", value: \"no\" },\n ],\n });\n if (provideNow !== \"yes\") {\n console.log(\n kleur.yellow(`! Set ${envVar} in your shell before running \\`codegraph index\\``),\n );\n return;\n }\n const value = await password({ message: `${envVar} value (input hidden)`, mask: \"*\" });\n if (!value) return;\n console.log(kleur.dim(\"Add this to your ~/.zshrc or ~/.bashrc:\"));\n console.log(kleur.cyan(` export ${envVar}=${value}`));\n}\n\nfunction apiKeyEnvVarFor(preset: string): string | null {\n if (preset === \"byo-openai\" || preset === \"managed-stub\") return \"OPENAI_API_KEY\";\n if (preset === \"byo-anthropic\") return \"ANTHROPIC_API_KEY\";\n if (preset === \"byo-google\") return \"GOOGLE_GENERATIVE_AI_API_KEY\";\n return null;\n}\n\nfunction describePreset(id: string): string {\n switch (id) {\n case \"managed-stub\":\n return \"Phase-2 placeholder - same as BYO OpenAI\";\n case \"byo-openai\":\n return \"Your own OpenAI key (gpt-4o-mini + text-embedding-3-small)\";\n case \"byo-anthropic\":\n return \"Anthropic for gen, OpenAI for embeddings\";\n case \"byo-google\":\n return \"Gemini for gen + Google embeddings\";\n case \"local-ollama\":\n return \"Fully local via Ollama (qwen2.5-coder + nomic-embed-text)\";\n default:\n return \"\";\n }\n}\n\nexport async function runConfigLlmTest(): Promise<void> {\n const config = await loadConfig();\n console.log(kleur.dim(\"testing llm config:\"));\n console.log(kleur.dim(` mode ${config.llm.mode}`));\n console.log(\n kleur.dim(` generate ${config.llm.generation.provider}:${config.llm.generation.model}`),\n );\n console.log(\n kleur.dim(` embed ${config.llm.embeddings.provider}:${config.llm.embeddings.model}`),\n );\n const spinner = makeSpinner(\"Calling provider\").start();\n try {\n const router = await createLlmRouter({ config: config.llm });\n const result = await router.selfTest();\n spinner.succeed(\"LLM provider reachable\");\n console.log(` embed dims: ${result.embedDims}`);\n console.log(` embed latency: ${result.embedLatencyMs}ms`);\n console.log(` generate latency: ${result.generateLatencyMs}ms`);\n console.log(` namespace: ${namespaceLabel(config.llm)}`);\n } catch (err) {\n spinner.fail(\"LLM provider unreachable\");\n throw err;\n }\n}\n","import { access, constants, mkdir } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\nimport { defaultDbPath, GraphDb } from \"@codegraph/graph-db\";\nimport { createLlmRouter } from \"@codegraph/llm-router\";\nimport kleur from \"kleur\";\nimport { configPath, loadConfig } from \"../config-store.js\";\n\ninterface Check {\n name: string;\n status: \"ok\" | \"warn\" | \"fail\";\n detail: string;\n}\n\n/**\n * `codegraph doctor` is a one-shot health check: Node version, config presence, LLM\n * provider credentials, Kuzu DB path writability, plus a tiny self-test against the\n * configured LLM. Designed to be the first thing we ask new users to run when they hit\n * a problem - it should print enough context to triage almost anything in support.\n */\nexport async function runDoctorCommand(): Promise<void> {\n const checks: Check[] = [];\n checks.push(checkNodeVersion());\n\n let config: Awaited<ReturnType<typeof loadConfig>> | null = null;\n try {\n config = await loadConfig();\n checks.push({ name: \"config file\", status: \"ok\", detail: configPath() });\n } catch (err) {\n checks.push({\n name: \"config file\",\n status: \"fail\",\n detail: err instanceof Error ? err.message : String(err),\n });\n }\n\n const dbPath = config?.data.dbPath ?? defaultDbPath();\n checks.push(await checkWritable(\"graph dir\", dbPath));\n\n if (config) {\n checks.push(checkApiKey(config.llm.generation.provider));\n if (config.llm.embeddings.provider !== config.llm.generation.provider) {\n checks.push(checkApiKey(config.llm.embeddings.provider));\n }\n }\n\n if (config) {\n checks.push(await selfTestLlm(config));\n checks.push(await selfTestKuzu(dbPath, config.llm.embeddings.dimension));\n }\n\n let failed = 0;\n let warned = 0;\n for (const c of checks) {\n const icon =\n c.status === \"ok\" ? kleur.green(\"✓\") : c.status === \"warn\" ? kleur.yellow(\"!\") : kleur.red(\"✗\");\n const name = c.name.padEnd(18);\n const detail = c.status === \"ok\" ? kleur.dim(c.detail) : c.detail;\n console.log(`${icon} ${name} ${detail}`);\n if (c.status === \"fail\") failed++;\n if (c.status === \"warn\") warned++;\n }\n console.log();\n if (failed > 0) {\n console.log(kleur.red().bold(`${failed} check(s) failed; codegraph won't work as-is.`));\n process.exitCode = 1;\n return;\n }\n if (warned > 0) {\n console.log(kleur.yellow(`${warned} warning(s); core flows work, optional features may not.`));\n return;\n }\n console.log(kleur.green().bold(\"All checks passed. You're ready to `codegraph index <repo>`.\"));\n}\n\nfunction checkNodeVersion(): Check {\n const version = process.versions.node;\n const major = Number(version.split(\".\")[0] ?? 0);\n if (major >= 20) {\n return { name: \"node version\", status: \"ok\", detail: `v${version}` };\n }\n return {\n name: \"node version\",\n status: \"fail\",\n detail: `v${version} (codegraph requires >= 20)`,\n };\n}\n\nasync function checkWritable(name: string, path: string): Promise<Check> {\n try {\n await mkdir(dirname(path), { recursive: true });\n try {\n await access(path, constants.W_OK);\n } catch {\n // Doesn't exist yet - that's fine as long as the parent is writable.\n await access(dirname(path), constants.W_OK);\n }\n return { name, status: \"ok\", detail: path };\n } catch (err) {\n return {\n name,\n status: \"fail\",\n detail: `${path} (${err instanceof Error ? err.message : String(err)})`,\n };\n }\n}\n\nfunction checkApiKey(provider: string): Check {\n const envVar = providerEnvVar(provider);\n if (envVar === null) {\n return { name: `${provider} key`, status: \"ok\", detail: \"(no key needed)\" };\n }\n if (process.env[envVar]) {\n return { name: envVar, status: \"ok\", detail: \"set\" };\n }\n return {\n name: envVar,\n status: \"fail\",\n detail: `unset (export ${envVar}=... or switch presets)`,\n };\n}\n\nfunction providerEnvVar(provider: string): string | null {\n if (provider === \"openai\") return \"OPENAI_API_KEY\";\n if (provider === \"anthropic\") return \"ANTHROPIC_API_KEY\";\n if (provider === \"google\") return \"GOOGLE_GENERATIVE_AI_API_KEY\";\n return null;\n}\n\nasync function selfTestLlm(\n config: Awaited<ReturnType<typeof loadConfig>>,\n): Promise<Check> {\n try {\n const router = await createLlmRouter({ config: config.llm });\n const result = await router.selfTest();\n return {\n name: \"llm round-trip\",\n status: \"ok\",\n detail: `embed=${result.embedLatencyMs}ms gen=${result.generateLatencyMs}ms`,\n };\n } catch (err) {\n return {\n name: \"llm round-trip\",\n status: \"fail\",\n detail: err instanceof Error ? err.message : String(err),\n };\n }\n}\n\nasync function selfTestKuzu(dbPath: string, embeddingDimension: number): Promise<Check> {\n const db = new GraphDb({ dbPath, embeddingDimension });\n try {\n await db.connect();\n await db.migrate();\n const result = await db.query<{ result: number }>(\"RETURN 1 AS result\");\n // Capture the vector-index status BEFORE close() since close drops the flag along\n // with the connection state.\n const vectorReady = db.hasVectorIndex();\n await db.close();\n if (result.data[0]?.result === 1) {\n return {\n name: \"kuzu round-trip\",\n status: vectorReady ? \"ok\" : \"warn\",\n detail: vectorReady\n ? \"ok (vector index ready)\"\n : \"ok (vector extension missing; semantic search disabled)\",\n };\n }\n return { name: \"kuzu round-trip\", status: \"fail\", detail: \"unexpected result\" };\n } catch (err) {\n await db.close().catch(() => {});\n return {\n name: \"kuzu round-trip\",\n status: \"fail\",\n detail: err instanceof Error ? err.message : String(err),\n };\n }\n}\n","import path from \"node:path\";\nimport { GraphDb, defaultDbPath } from \"@codegraph/graph-db\";\nimport { indexRepo } from \"@codegraph/ingestion\";\nimport { createLlmRouter } from \"@codegraph/llm-router\";\nimport kleur from \"kleur\";\nimport { loadConfig } from \"../config-store.js\";\nimport { repoIdFromPath } from \"../repo-id.js\";\nimport { ProgressBar, makeSpinner, renderStatusTables } from \"../ui.js\";\n\nexport interface IndexCommandOptions {\n repoPath: string;\n noEmbed?: boolean;\n}\n\n/**\n * Walks a repository, parses it, optionally embeds every symbol, and writes everything\n * into the embedded Kuzu graph. The command is split into three visible phases - walk,\n * parse, embed - each wrapped in an `ora` spinner so the user sees liveness without\n * scrollbar spam.\n */\nexport async function runIndexCommand(opts: IndexCommandOptions): Promise<void> {\n const config = await loadConfig();\n const absolutePath = path.resolve(opts.repoPath);\n const repoId = repoIdFromPath(absolutePath);\n const dbPath = config.data.dbPath ?? defaultDbPath();\n\n console.log(kleur.dim(`repo: ${absolutePath}`));\n console.log(kleur.dim(`id: ${repoId}`));\n console.log(kleur.dim(`graph: ${dbPath}`));\n console.log(\n kleur.dim(\n `llm: ${config.llm.mode} / gen=${config.llm.generation.provider}:${config.llm.generation.model} / embed=${config.llm.embeddings.provider}:${config.llm.embeddings.model}`,\n ),\n );\n console.log();\n\n const graphDb = new GraphDb({\n dbPath,\n embeddingDimension: config.llm.embeddings.dimension,\n });\n\n const connectSpinner = makeSpinner(\"Opening graph\").start();\n try {\n await graphDb.connect();\n await graphDb.migrate();\n connectSpinner.succeed(`Graph ready ${kleur.dim(`(${dbPath})`)}`);\n } catch (err) {\n connectSpinner.fail(\"Failed to open graph\");\n throw err;\n }\n\n let router: Awaited<ReturnType<typeof createLlmRouter>> | undefined;\n if (!opts.noEmbed) {\n const llmSpinner = makeSpinner(\"Initialising LLM router\").start();\n try {\n router = await createLlmRouter({ config: config.llm });\n llmSpinner.succeed(\"LLM router initialised\");\n } catch (err) {\n llmSpinner.warn(\n `LLM router init failed; continuing without embeddings (${err instanceof Error ? err.message : String(err)})`,\n );\n router = undefined;\n }\n }\n\n let parseBar: ProgressBar | null = null;\n let embedBar: ProgressBar | null = null;\n\n const result = await indexRepo({\n repoId,\n repoPath: absolutePath,\n graphDb,\n ...(router ? { router } : {}),\n skipEmbeddings: opts.noEmbed === true || router === undefined,\n onProgress: (event) => {\n if (event.type === \"walk\") {\n console.log(kleur.dim(`walked ${event.files} files`));\n }\n if (event.type === \"parse\") {\n if (!parseBar) parseBar = new ProgressBar(\"parsing\", event.total);\n parseBar.update(event.parsed);\n }\n if (event.type === \"upsert\") {\n console.log(\n kleur.dim(`upserted ${event.nodes} nodes, ${event.edges} edges`),\n );\n }\n if (event.type === \"embed\") {\n if (!embedBar) embedBar = new ProgressBar(\"embedding\", event.total);\n embedBar.update(event.embedded);\n }\n },\n });\n\n parseBar?.done();\n embedBar?.done();\n await graphDb.close();\n\n console.log();\n console.log(\n kleur.green().bold(\n `✓ Indexed ${result.nodes} nodes, ${result.edges} edges in ${(result.durationMs / 1000).toFixed(2)}s`,\n ),\n );\n console.log(\n kleur.dim(\n ` parsed=${result.parsedFiles} failed=${result.failedFiles} embeddings=${result.embeddings} dropped_edges=${result.droppedEdges}`,\n ),\n );\n}\n\nexport interface StatusCommandOptions {\n repoPath: string;\n}\n\nexport async function runStatusCommand(opts: StatusCommandOptions): Promise<void> {\n const config = await loadConfig();\n const absolutePath = path.resolve(opts.repoPath);\n const repoId = repoIdFromPath(absolutePath);\n const graphDb = new GraphDb({\n dbPath: config.data.dbPath ?? defaultDbPath(),\n embeddingDimension: config.llm.embeddings.dimension,\n });\n const spinner = makeSpinner(\"Reading graph\").start();\n try {\n await graphDb.connect();\n const stats = await graphDb.stats(repoId);\n await graphDb.close();\n spinner.stop();\n console.log(renderStatusTables(repoId, stats));\n } catch (err) {\n spinner.fail(\"Failed to read graph\");\n throw err;\n }\n}\n","import { readFile } from \"node:fs/promises\";\nimport { createRequire } from \"node:module\";\nimport { extname, dirname, join } from \"node:path\";\nimport Parser from \"web-tree-sitter\";\nimport type { Language as LanguageKind } from \"@codegraph/shared\";\n\nconst require = createRequire(import.meta.url);\n\n/** Maps our `Language` union to the wasm grammar bundled by `tree-sitter-wasms`. */\nconst GRAMMAR_FILE: Record<LanguageKind, string> = {\n typescript: \"tree-sitter-typescript.wasm\",\n tsx: \"tree-sitter-tsx.wasm\",\n javascript: \"tree-sitter-javascript.wasm\",\n jsx: \"tree-sitter-javascript.wasm\",\n};\n\nlet initPromise: Promise<void> | null = null;\nconst languageCache = new Map<LanguageKind, Parser.Language>();\n\nasync function ensureInit(): Promise<void> {\n if (!initPromise) initPromise = Parser.init();\n await initPromise;\n}\n\nfunction grammarPath(lang: LanguageKind): string {\n let pkgRoot: string;\n try {\n pkgRoot = dirname(require.resolve(\"tree-sitter-wasms/package.json\"));\n } catch {\n // Fallback for environments where tree-sitter-wasms is not installed\n pkgRoot = join(dirname(require.resolve(\"web-tree-sitter\")), \"..\", \"tree-sitter-wasms\");\n }\n return join(pkgRoot, \"out\", GRAMMAR_FILE[lang]);\n}\n\nexport async function loadLanguage(lang: LanguageKind): Promise<Parser.Language> {\n await ensureInit();\n const cached = languageCache.get(lang);\n if (cached) return cached;\n const buffer = await readFile(grammarPath(lang));\n // Load from Uint8Array; web-tree-sitter's fetch fallback doesn't work in plain Node.\n const loaded = await Parser.Language.load(new Uint8Array(buffer));\n languageCache.set(lang, loaded);\n return loaded;\n}\n\nexport function detectLanguage(filePath: string): LanguageKind | null {\n const ext = extname(filePath).toLowerCase();\n switch (ext) {\n case \".ts\":\n return \"typescript\";\n case \".tsx\":\n return \"tsx\";\n case \".js\":\n case \".mjs\":\n case \".cjs\":\n return \"javascript\";\n case \".jsx\":\n return \"jsx\";\n default:\n return null;\n }\n}\n\nexport interface ParsedFile {\n tree: Parser.Tree;\n rootNode: Parser.SyntaxNode;\n language: LanguageKind;\n source: string;\n}\n\nexport async function parseSource(source: string, language: LanguageKind): Promise<ParsedFile> {\n const lang = await loadLanguage(language);\n const parser = new Parser();\n parser.setLanguage(lang);\n const tree = parser.parse(source);\n if (!tree) {\n throw new Error(`tree-sitter failed to parse ${language} source`);\n }\n return {\n tree,\n rootNode: tree.rootNode,\n language,\n source,\n };\n}\n","import { createHash } from \"node:crypto\";\nimport { basename } from \"node:path\";\nimport Parser from \"web-tree-sitter\";\n\ntype SyntaxNode = Parser.SyntaxNode;\nimport {\n type GraphEdge,\n type GraphNode,\n type Language,\n makeFileId,\n makeNodeId,\n} from \"@codegraph/shared\";\nimport { parseSource } from \"../parser.js\";\nimport {\n endLine,\n findChildByType,\n findChildrenByType,\n isPascalCase,\n leadingCommentFor,\n nodeText,\n startLine,\n walk,\n} from \"../walker.js\";\nimport { detectRoutes } from \"./routes.js\";\n\nexport interface ExtractFileInput {\n repoId: string;\n /** Path of the file *relative to the repo root*. Drives node ids. */\n relativePath: string;\n /** Absolute path on disk, used for ROUTE framework detection. */\n absolutePath: string;\n language: Language;\n source: string;\n}\n\nexport interface ExtractFileResult {\n file: GraphNode;\n nodes: GraphNode[];\n edges: GraphEdge[];\n}\n\n/**\n * Top-level extraction. Returns the file node, every symbol declared in the\n * file, and every edge that can be derived without cross-file knowledge.\n *\n * Some edges (CALLS, INHERITS, RENDERS) are emitted with\n * `unresolvedTargetName` set. The orchestrator resolves them against the\n * full symbol table after all files are parsed.\n */\nexport async function extractFile(input: ExtractFileInput): Promise<ExtractFileResult> {\n const parsed = await parseSource(input.source, input.language);\n\n const fileId = makeFileId({ repoId: input.repoId, path: input.relativePath });\n const file: GraphNode = {\n id: fileId,\n kind: \"File\",\n repoId: input.repoId,\n name: basename(input.relativePath),\n path: input.relativePath,\n lineStart: 1,\n lineEnd: Math.max(1, parsed.rootNode.endPosition.row + 1),\n language: input.language,\n sizeBytes: Buffer.byteLength(input.source, \"utf8\"),\n contentHash: sha1(input.source),\n };\n\n const nodes: GraphNode[] = [];\n const edges: GraphEdge[] = [];\n\n // Per-file map of declared symbol names -> ids. Lets us resolve\n // intra-file CALLS / RENDERS edges immediately and emit cross-file ones\n // as unresolved.\n const localSymbols = new Map<string, string>();\n\n // Pass 1: symbol declarations + DEFINES + EXPORTS + INHERITS.\n for (const node of walk(parsed.rootNode)) {\n const symbol = extractSymbol(node, input, parsed.source);\n if (!symbol) continue;\n nodes.push(symbol.node);\n localSymbols.set(symbol.node.name, symbol.node.id);\n edges.push({ kind: \"DEFINES\", fromId: fileId, toId: symbol.node.id });\n if (symbol.node.isExported) {\n edges.push({ kind: \"EXPORTS\", fromId: fileId, toId: symbol.node.id });\n }\n if (symbol.parentClass) {\n edges.push({\n kind: \"INHERITS\",\n fromId: symbol.node.id,\n toId: \"\",\n unresolvedTargetName: symbol.parentClass,\n });\n }\n }\n\n // Pass 2: imports - emit IMPORTS edges from the *file* to the resolved\n // target path. The orchestrator turns the path into a target node id.\n for (const node of walk(parsed.rootNode)) {\n if (node.type === \"import_statement\") {\n const src = findChildByType(node, \"string\");\n if (!src) continue;\n const raw = nodeText(src, parsed.source);\n const target = raw.slice(1, -1);\n edges.push({\n kind: \"IMPORTS\",\n fromId: fileId,\n toId: \"\",\n line: startLine(node),\n fromPath: input.relativePath,\n toPath: target,\n unresolvedTargetName: target,\n });\n }\n }\n\n // Pass 3: shallow CALLS edges. We walk every call_expression and emit an\n // edge from the *enclosing* symbol to the callee identifier. Cross-file\n // resolution happens later; here we just record the name.\n for (const node of walk(parsed.rootNode)) {\n if (node.type !== \"call_expression\") continue;\n const callee = node.childForFieldName(\"function\");\n if (!callee) continue;\n const calleeName = extractCalleeName(callee, parsed.source);\n if (!calleeName) continue;\n const enclosing = findEnclosingSymbolId(node, input, parsed.source, localSymbols);\n if (!enclosing) continue;\n edges.push({\n kind: \"CALLS\",\n fromId: enclosing,\n toId: \"\",\n line: startLine(node),\n unresolvedTargetName: calleeName,\n });\n }\n\n // Pass 4: JSX renders edges. PascalCase opening / self-closing elements\n // are component usage; lowercase tags are HTML and are ignored.\n if (input.language === \"tsx\" || input.language === \"jsx\") {\n for (const node of walk(parsed.rootNode)) {\n if (node.type !== \"jsx_opening_element\" && node.type !== \"jsx_self_closing_element\") continue;\n const ident = node.childForFieldName(\"name\") ?? findChildByType(node, \"identifier\");\n if (!ident) continue;\n const tag = nodeText(ident, parsed.source);\n if (!isPascalCase(tag)) continue;\n const enclosing = findEnclosingSymbolId(node, input, parsed.source, localSymbols);\n if (!enclosing) continue;\n edges.push({\n kind: \"RENDERS\",\n fromId: enclosing,\n toId: \"\",\n line: startLine(node),\n unresolvedTargetName: tag,\n });\n }\n }\n\n // Pass 5: route detection (Express handlers + Next.js file-system routes).\n const routes = detectRoutes({\n repoId: input.repoId,\n relativePath: input.relativePath,\n absolutePath: input.absolutePath,\n fileId,\n rootNode: parsed.rootNode,\n source: parsed.source,\n language: input.language,\n });\n for (const route of routes) {\n nodes.push(route);\n edges.push({ kind: \"DEFINES\", fromId: fileId, toId: route.id });\n }\n\n return { file, nodes, edges };\n}\n\ninterface ExtractedSymbol {\n node: GraphNode;\n parentClass?: string;\n}\n\nfunction extractSymbol(\n node: SyntaxNode,\n input: ExtractFileInput,\n source: string,\n): ExtractedSymbol | null {\n switch (node.type) {\n case \"function_declaration\":\n case \"generator_function_declaration\":\n return functionFromDeclaration(node, input, source);\n case \"class_declaration\":\n return classFromDeclaration(node, input, source);\n case \"interface_declaration\":\n return interfaceFromDeclaration(node, input, source, \"Interface\");\n case \"type_alias_declaration\":\n return interfaceFromDeclaration(node, input, source, \"Interface\");\n case \"lexical_declaration\":\n case \"variable_declaration\":\n return variableOrArrowFromDeclaration(node, input, source);\n default:\n return null;\n }\n}\n\nfunction functionFromDeclaration(\n node: SyntaxNode,\n input: ExtractFileInput,\n source: string,\n): ExtractedSymbol | null {\n const nameNode = node.childForFieldName(\"name\");\n if (!nameNode) return null;\n const name = nodeText(nameNode, source);\n const line = startLine(node);\n const id = makeNodeId({\n repoId: input.repoId,\n kind: \"Function\",\n path: input.relativePath,\n name,\n line,\n });\n return {\n node: {\n id,\n kind: \"Function\",\n repoId: input.repoId,\n name,\n path: input.relativePath,\n lineStart: line,\n lineEnd: endLine(node),\n signature: extractSignature(node, source),\n leadingComment: leadingCommentFor(parentForLeadingComment(node), source),\n isExported: isExported(node),\n isAsync: hasAsyncModifier(node, source),\n },\n };\n}\n\nfunction classFromDeclaration(\n node: SyntaxNode,\n input: ExtractFileInput,\n source: string,\n): ExtractedSymbol | null {\n const nameNode = node.childForFieldName(\"name\");\n if (!nameNode) return null;\n const name = nodeText(nameNode, source);\n const line = startLine(node);\n const isComponent = looksLikeComponentClass(node, name, source);\n const kind = isComponent ? \"Component\" : \"Class\";\n const id = makeNodeId({\n repoId: input.repoId,\n kind,\n path: input.relativePath,\n name,\n line,\n });\n const parentClass = extractExtendsName(node, source);\n return {\n node: {\n id,\n kind,\n repoId: input.repoId,\n name,\n path: input.relativePath,\n lineStart: line,\n lineEnd: endLine(node),\n signature: `class ${name}${parentClass ? ` extends ${parentClass}` : \"\"}`,\n leadingComment: leadingCommentFor(parentForLeadingComment(node), source),\n isExported: isExported(node),\n },\n ...(parentClass !== undefined ? { parentClass } : {}),\n };\n}\n\nfunction interfaceFromDeclaration(\n node: SyntaxNode,\n input: ExtractFileInput,\n source: string,\n kind: \"Interface\",\n): ExtractedSymbol | null {\n const nameNode = node.childForFieldName(\"name\");\n if (!nameNode) return null;\n const name = nodeText(nameNode, source);\n const line = startLine(node);\n const id = makeNodeId({\n repoId: input.repoId,\n kind,\n path: input.relativePath,\n name,\n line,\n });\n return {\n node: {\n id,\n kind,\n repoId: input.repoId,\n name,\n path: input.relativePath,\n lineStart: line,\n lineEnd: endLine(node),\n signature: nodeText(node, source).split(\"\\n\")[0]?.slice(0, 200) ?? \"\",\n leadingComment: leadingCommentFor(parentForLeadingComment(node), source),\n isExported: isExported(node),\n },\n };\n}\n\n/**\n * Handles `const x = () => ...` and `const X = () => <jsx/>`. The lexical\n * declaration may contain multiple declarators; we emit one symbol per\n * named declarator. Functions vs Components are distinguished by\n * PascalCase + JSX return value heuristic.\n */\nfunction variableOrArrowFromDeclaration(\n node: SyntaxNode,\n input: ExtractFileInput,\n source: string,\n): ExtractedSymbol | null {\n const declarators = findChildrenByType(node, \"variable_declarator\");\n if (declarators.length === 0) return null;\n // We can only return one symbol from this entry point. The walk visits\n // each declarator separately too, so picking the first preserves data\n // for \"const a = 1, b = 2\"-style edge cases.\n const decl = declarators[0];\n if (!decl) return null;\n const nameNode = decl.childForFieldName(\"name\");\n const value = decl.childForFieldName(\"value\");\n if (!nameNode) return null;\n const name = nodeText(nameNode, source);\n const line = startLine(decl);\n\n const isArrow = value?.type === \"arrow_function\" || value?.type === \"function_expression\";\n if (isArrow) {\n const isComponent = isPascalCase(name) && containsJsx(value);\n const kind = isComponent ? \"Component\" : \"Function\";\n const id = makeNodeId({\n repoId: input.repoId,\n kind,\n path: input.relativePath,\n name,\n line,\n });\n return {\n node: {\n id,\n kind,\n repoId: input.repoId,\n name,\n path: input.relativePath,\n lineStart: line,\n lineEnd: endLine(decl),\n signature: extractSignature(value, source),\n leadingComment: leadingCommentFor(node, source),\n isExported: isExported(node),\n ...(kind === \"Function\" ? { isArrow: true } : {}),\n },\n };\n }\n\n const id = makeNodeId({\n repoId: input.repoId,\n kind: \"Variable\",\n path: input.relativePath,\n name,\n line,\n });\n return {\n node: {\n id,\n kind: \"Variable\",\n repoId: input.repoId,\n name,\n path: input.relativePath,\n lineStart: line,\n lineEnd: endLine(decl),\n signature: nodeText(decl, source).split(\"\\n\")[0]?.slice(0, 200) ?? \"\",\n leadingComment: leadingCommentFor(node, source),\n isExported: isExported(node),\n },\n };\n}\n\nfunction extractSignature(node: SyntaxNode | null, source: string): string {\n if (!node) return \"\";\n const params = node.childForFieldName(\"parameters\");\n const ret = node.childForFieldName(\"return_type\");\n const name = node.childForFieldName(\"name\");\n const head = name ? nodeText(name, source) : \"\";\n const ps = params ? nodeText(params, source) : \"()\";\n const rs = ret ? ` ${nodeText(ret, source)}` : \"\";\n return `${head}${ps}${rs}`.trim().slice(0, 200);\n}\n\nfunction extractCalleeName(callee: SyntaxNode, source: string): string | null {\n if (callee.type === \"identifier\") return nodeText(callee, source);\n if (callee.type === \"member_expression\") {\n const property = callee.childForFieldName(\"property\");\n if (property) return nodeText(property, source);\n }\n return null;\n}\n\nfunction extractExtendsName(classNode: SyntaxNode, source: string): string | undefined {\n const heritage = findChildByType(classNode, \"class_heritage\");\n if (!heritage) return undefined;\n const extendsClause = findChildByType(heritage, \"extends_clause\");\n if (!extendsClause) {\n // tree-sitter-typescript flattens heritage differently; check direct\n // identifier children of class_heritage as a fallback.\n const ident = findChildByType(heritage, \"identifier\");\n if (ident) return nodeText(ident, source);\n return undefined;\n }\n const ident =\n findChildByType(extendsClause, \"identifier\") ??\n findChildByType(extendsClause, \"member_expression\");\n return ident ? nodeText(ident, source) : undefined;\n}\n\nfunction looksLikeComponentClass(classNode: SyntaxNode, name: string, source: string): boolean {\n if (!isPascalCase(name)) return false;\n const parent = extractExtendsName(classNode, source) ?? \"\";\n return /(?:^|\\.)Component$|PureComponent$/.test(parent);\n}\n\nfunction containsJsx(node: SyntaxNode | null): boolean {\n if (!node) return false;\n for (const child of walk(node)) {\n if (\n child.type === \"jsx_element\" ||\n child.type === \"jsx_self_closing_element\" ||\n child.type === \"jsx_fragment\"\n ) {\n return true;\n }\n }\n return false;\n}\n\nfunction hasAsyncModifier(node: SyntaxNode, source: string): boolean {\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (!child) continue;\n if (child.type === \"async\" || nodeText(child, source) === \"async\") return true;\n // Stop after we leave the declaration's modifier head.\n if (child.type === \"function\" || child.type === \"class\") return false;\n }\n return false;\n}\n\nfunction isExported(node: SyntaxNode): boolean {\n let cursor: SyntaxNode | null = node.parent;\n while (cursor) {\n if (cursor.type === \"export_statement\") return true;\n if (cursor.type === \"program\") return false;\n cursor = cursor.parent;\n }\n return false;\n}\n\n/**\n * When fetching a leading comment, we want the comment *above* the\n * `export` wrapper, not above the inner declaration. So we hop up to the\n * outermost export_statement before looking for siblings.\n */\nfunction parentForLeadingComment(node: SyntaxNode): SyntaxNode {\n let cursor: SyntaxNode = node;\n while (cursor.parent && cursor.parent.type === \"export_statement\") {\n cursor = cursor.parent;\n }\n return cursor;\n}\n\nfunction findEnclosingSymbolId(\n node: SyntaxNode,\n input: ExtractFileInput,\n source: string,\n localSymbols: Map<string, string>,\n): string | null {\n let cursor: SyntaxNode | null = node.parent;\n while (cursor) {\n if (\n cursor.type === \"function_declaration\" ||\n cursor.type === \"method_definition\" ||\n cursor.type === \"class_declaration\" ||\n cursor.type === \"arrow_function\" ||\n cursor.type === \"function_expression\"\n ) {\n const name = enclosingDeclarationName(cursor, source);\n if (name) {\n const id = localSymbols.get(name);\n if (id) return id;\n }\n }\n cursor = cursor.parent;\n }\n // Falls back to the file node so module-level expressions still get a\n // sensible \"from\" endpoint.\n return makeFileId({ repoId: input.repoId, path: input.relativePath });\n}\n\nfunction enclosingDeclarationName(node: SyntaxNode, source: string): string | null {\n const nameField = node.childForFieldName(\"name\");\n if (nameField) return nodeText(nameField, source);\n // Arrow functions and function expressions carry their name on the\n // surrounding variable_declarator.\n let cursor: SyntaxNode | null = node.parent;\n while (cursor) {\n if (cursor.type === \"variable_declarator\") {\n const declName = cursor.childForFieldName(\"name\");\n if (declName) return nodeText(declName, source);\n return null;\n }\n if (cursor.type === \"function_declaration\" || cursor.type === \"class_declaration\") return null;\n cursor = cursor.parent;\n }\n return null;\n}\n\nfunction sha1(s: string): string {\n return createHash(\"sha1\").update(s).digest(\"hex\");\n}\n","import Parser from \"web-tree-sitter\";\n\ntype SyntaxNode = Parser.SyntaxNode;\n\n/**\n * Lazy depth-first walk that yields every descendant. Excludes the root\n * itself. Used by extractors to find symbols anywhere in a file without\n * stitching together SyntaxNode cursor APIs.\n */\nexport function* walk(node: SyntaxNode): Generator<SyntaxNode> {\n const stack: SyntaxNode[] = [];\n for (let i = node.namedChildCount - 1; i >= 0; i--) {\n const child = node.namedChild(i);\n if (child) stack.push(child);\n }\n while (stack.length > 0) {\n const current = stack.pop();\n if (!current) continue;\n yield current;\n for (let i = current.namedChildCount - 1; i >= 0; i--) {\n const child = current.namedChild(i);\n if (child) stack.push(child);\n }\n }\n}\n\nexport function findChildByType(node: SyntaxNode, type: string): SyntaxNode | null {\n for (let i = 0; i < node.namedChildCount; i++) {\n const child = node.namedChild(i);\n if (child && child.type === type) return child;\n }\n return null;\n}\n\nexport function findChildrenByType(node: SyntaxNode, type: string): SyntaxNode[] {\n const out: SyntaxNode[] = [];\n for (let i = 0; i < node.namedChildCount; i++) {\n const child = node.namedChild(i);\n if (child && child.type === type) out.push(child);\n }\n return out;\n}\n\nexport function nodeText(node: SyntaxNode, source: string): string {\n return source.slice(node.startIndex, node.endIndex);\n}\n\n/**\n * Tree-sitter line numbers are 0-indexed; we surface 1-indexed numbers\n * everywhere downstream so they match what editors and stack traces use.\n */\nexport function startLine(node: SyntaxNode): number {\n return node.startPosition.row + 1;\n}\n\nexport function endLine(node: SyntaxNode): number {\n return node.endPosition.row + 1;\n}\n\n/**\n * Returns the leading line-comment block immediately above `node`, joined\n * into a single string. Empty string when no comment is found.\n */\nexport function leadingCommentFor(node: SyntaxNode, source: string): string {\n let cursor: SyntaxNode | null = node.previousNamedSibling;\n const lines: string[] = [];\n while (cursor && /comment/.test(cursor.type)) {\n lines.unshift(stripCommentMarkers(nodeText(cursor, source)));\n cursor = cursor.previousNamedSibling;\n }\n return lines.join(\"\\n\").trim();\n}\n\nfunction stripCommentMarkers(text: string): string {\n return text\n .replace(/^\\/\\*+/, \"\")\n .replace(/\\*+\\/$/, \"\")\n .replace(/^\\/\\//gm, \"\")\n .replace(/^\\s*\\*/gm, \"\")\n .trim();\n}\n\nexport function isPascalCase(name: string): boolean {\n return /^[A-Z][A-Za-z0-9]*$/.test(name);\n}\n","import Parser from \"web-tree-sitter\";\n\ntype SyntaxNode = Parser.SyntaxNode;\nimport { type GraphNode, type Language, makeNodeId } from \"@codegraph/shared\";\nimport { endLine, findChildByType, nodeText, startLine, walk } from \"../walker.js\";\n\nconst EXPRESS_METHODS = new Set([\n \"get\",\n \"post\",\n \"put\",\n \"patch\",\n \"delete\",\n \"options\",\n \"head\",\n \"all\",\n \"use\",\n]);\n\nconst HTTP_VERBS = new Set([\n \"GET\",\n \"POST\",\n \"PUT\",\n \"PATCH\",\n \"DELETE\",\n \"OPTIONS\",\n \"HEAD\",\n]);\n\nexport interface DetectRoutesInput {\n repoId: string;\n relativePath: string;\n absolutePath: string;\n fileId: string;\n rootNode: SyntaxNode;\n source: string;\n language: Language;\n}\n\n/**\n * Returns Route nodes for:\n * 1. Express `app.get('/x', handler)` / `router.post(...)` patterns.\n * 2. Next.js App Router `app/**\\/route.ts` exports (`GET`, `POST`, ...).\n * 3. Next.js Pages Router `pages/api/**` default exports.\n */\nexport function detectRoutes(input: DetectRoutesInput): GraphNode[] {\n return [\n ...detectExpressRoutes(input),\n ...detectNextAppRouterRoutes(input),\n ...detectNextPagesApiRoutes(input),\n ];\n}\n\nfunction detectExpressRoutes(input: DetectRoutesInput): GraphNode[] {\n const out: GraphNode[] = [];\n for (const node of walk(input.rootNode)) {\n if (node.type !== \"call_expression\") continue;\n const callee = node.childForFieldName(\"function\");\n if (!callee || callee.type !== \"member_expression\") continue;\n const obj = callee.childForFieldName(\"object\");\n const prop = callee.childForFieldName(\"property\");\n if (!obj || !prop) continue;\n const method = nodeText(prop, input.source).toLowerCase();\n if (!EXPRESS_METHODS.has(method)) continue;\n const args = node.childForFieldName(\"arguments\");\n if (!args) continue;\n const firstArg = args.namedChild(0);\n if (!firstArg || firstArg.type !== \"string\") continue;\n const routePath = stripQuotes(nodeText(firstArg, input.source));\n if (!routePath.startsWith(\"/\")) continue;\n const line = startLine(node);\n const name = `${method.toUpperCase()} ${routePath}`;\n out.push({\n id: makeNodeId({\n repoId: input.repoId,\n kind: \"Route\",\n path: input.relativePath,\n name,\n line,\n }),\n kind: \"Route\",\n repoId: input.repoId,\n name,\n path: input.relativePath,\n lineStart: line,\n lineEnd: endLine(node),\n method: method.toUpperCase(),\n routePath,\n framework: \"express\",\n });\n }\n return out;\n}\n\nfunction detectNextAppRouterRoutes(input: DetectRoutesInput): GraphNode[] {\n if (!/(^|\\/)app\\/.+\\/route\\.(ts|tsx|js|jsx|mjs|cjs)$/.test(input.relativePath)) return [];\n const routePath = appRoutePathFor(input.relativePath);\n const out: GraphNode[] = [];\n for (const node of walk(input.rootNode)) {\n if (node.type !== \"export_statement\") continue;\n // `export async function GET(...)` or `export const GET = ...`\n const decl = findChildByType(node, \"function_declaration\") ?? findChildByType(node, \"lexical_declaration\");\n if (!decl) continue;\n const name = extractTopLevelName(decl, input.source);\n if (!name || !HTTP_VERBS.has(name)) continue;\n const line = startLine(node);\n out.push({\n id: makeNodeId({\n repoId: input.repoId,\n kind: \"Route\",\n path: input.relativePath,\n name: `${name} ${routePath}`,\n line,\n }),\n kind: \"Route\",\n repoId: input.repoId,\n name: `${name} ${routePath}`,\n path: input.relativePath,\n lineStart: line,\n lineEnd: endLine(node),\n method: name,\n routePath,\n framework: \"next-app\",\n });\n }\n return out;\n}\n\nfunction detectNextPagesApiRoutes(input: DetectRoutesInput): GraphNode[] {\n if (!/(^|\\/)pages\\/api\\//.test(input.relativePath)) return [];\n const routePath = pagesApiPathFor(input.relativePath);\n // Pages API uses a default-exported handler that responds to all verbs.\n for (const node of walk(input.rootNode)) {\n if (node.type !== \"export_statement\") continue;\n const text = nodeText(node, input.source);\n if (!/default/.test(text)) continue;\n const line = startLine(node);\n return [\n {\n id: makeNodeId({\n repoId: input.repoId,\n kind: \"Route\",\n path: input.relativePath,\n name: `ANY ${routePath}`,\n line,\n }),\n kind: \"Route\",\n repoId: input.repoId,\n name: `ANY ${routePath}`,\n path: input.relativePath,\n lineStart: line,\n lineEnd: endLine(node),\n method: \"ANY\",\n routePath,\n framework: \"next-pages\",\n },\n ];\n }\n return [];\n}\n\nfunction stripQuotes(s: string): string {\n return s.replace(/^[\"'`]/, \"\").replace(/[\"'`]$/, \"\");\n}\n\nfunction extractTopLevelName(decl: SyntaxNode, source: string): string | null {\n if (decl.type === \"function_declaration\") {\n const name = decl.childForFieldName(\"name\");\n return name ? nodeText(name, source) : null;\n }\n if (decl.type === \"lexical_declaration\") {\n const declarator = findChildByType(decl, \"variable_declarator\");\n if (!declarator) return null;\n const name = declarator.childForFieldName(\"name\");\n return name ? nodeText(name, source) : null;\n }\n return null;\n}\n\nfunction appRoutePathFor(relativePath: string): string {\n // app/(group)/users/[id]/route.ts -> /users/:id\n const idx = relativePath.indexOf(\"app/\");\n const tail = idx >= 0 ? relativePath.slice(idx + \"app/\".length) : relativePath;\n const segments = tail\n .replace(/\\/route\\.[^/]+$/, \"\")\n .split(\"/\")\n .filter((seg) => seg.length > 0 && !/^\\(.*\\)$/.test(seg)) // strip route groups\n .map((seg) => seg.replace(/^\\[\\.\\.\\.(.+)\\]$/, \":$1*\").replace(/^\\[(.+)\\]$/, \":$1\"));\n return `/${segments.join(\"/\")}` || \"/\";\n}\n\nfunction pagesApiPathFor(relativePath: string): string {\n const idx = relativePath.indexOf(\"pages/api/\");\n const tail = idx >= 0 ? relativePath.slice(idx + \"pages/api/\".length) : relativePath;\n const base = tail.replace(/\\.[^/.]+$/, \"\");\n const segments = base\n .split(\"/\")\n .filter((seg) => seg.length > 0)\n .map((seg) =>\n seg\n .replace(/^\\[\\.\\.\\.(.+)\\]$/, \":$1*\")\n .replace(/^\\[(.+)\\]$/, \":$1\")\n .replace(/^index$/, \"\"),\n )\n .filter((seg) => seg.length > 0);\n return `/api/${segments.join(\"/\")}`.replace(/\\/+$/, \"\") || \"/api\";\n}\n","import path from \"node:path\";\nimport { type GraphEdge, type GraphNode, makeFileId } from \"@codegraph/shared\";\n\nexport interface ResolveInput {\n repoId: string;\n /** All nodes from all parsed files in the current index pass. */\n nodes: GraphNode[];\n /** All edges with `unresolvedTargetName` set on IMPORTS/CALLS/RENDERS/INHERITS. */\n edges: GraphEdge[];\n /** Repo paths of files that successfully parsed, used for IMPORTS resolution. */\n knownFilePaths: Set<string>;\n}\n\nexport interface ResolveResult {\n resolved: GraphEdge[];\n dropped: number;\n}\n\nconst EXTENSIONS = [\".ts\", \".tsx\", \".js\", \".jsx\", \".mjs\", \".cjs\"];\n\n/**\n * Second pass that converts the *names* captured during single-file\n * extraction into concrete `toId` values. Edges whose target can't be\n * resolved are dropped silently (and counted in `dropped`) - they\n * commonly point at npm packages or unindexed code.\n */\nexport function resolveEdges(input: ResolveInput): ResolveResult {\n // Symbol lookup by name. When the same name appears in multiple files,\n // the first one wins; Phase 4's LSP integration will replace this with\n // type-aware resolution.\n const byName = new Map<string, string>();\n // Function/class/component/etc -> first node id with that name.\n for (const n of input.nodes) {\n if (n.kind === \"File\") continue;\n if (!byName.has(n.name)) byName.set(n.name, n.id);\n }\n\n const out: GraphEdge[] = [];\n let dropped = 0;\n\n for (const edge of input.edges) {\n if (edge.toId) {\n out.push(edge);\n continue;\n }\n if (!edge.unresolvedTargetName) {\n dropped++;\n continue;\n }\n if (edge.kind === \"IMPORTS\") {\n const resolved = resolveImportPath({\n repoId: input.repoId,\n fromPath: edge.fromPath ?? \"\",\n spec: edge.unresolvedTargetName,\n known: input.knownFilePaths,\n });\n if (!resolved) {\n dropped++;\n continue;\n }\n const targetId = makeFileId({ repoId: input.repoId, path: resolved });\n const { unresolvedTargetName: _unused, ...rest } = edge;\n out.push({ ...rest, toId: targetId, toPath: resolved });\n continue;\n }\n const targetId = byName.get(edge.unresolvedTargetName);\n if (!targetId) {\n dropped++;\n continue;\n }\n const { unresolvedTargetName: _unused, ...rest } = edge;\n out.push({ ...rest, toId: targetId });\n }\n\n return { resolved: out, dropped };\n}\n\ninterface ResolveImportInput {\n repoId: string;\n fromPath: string;\n spec: string;\n known: Set<string>;\n}\n\nfunction resolveImportPath(input: ResolveImportInput): string | null {\n const { fromPath, spec, known } = input;\n if (!spec.startsWith(\".\") && !spec.startsWith(\"/\")) return null;\n const baseDir = path.posix.dirname(toPosix(fromPath));\n const joined = path.posix.normalize(path.posix.join(baseDir, toPosix(spec)));\n // Modern ESM convention writes `./foo.js` even though the source file is\n // `./foo.ts`. So we try the literal path, the path with its extension\n // swapped for each candidate, the bare path with each extension, and\n // finally `/index.<ext>` for directory imports.\n const candidates: string[] = [joined];\n const ext = path.posix.extname(joined);\n const stem = ext ? joined.slice(0, -ext.length) : joined;\n for (const e of EXTENSIONS) candidates.push(`${stem}${e}`);\n for (const e of EXTENSIONS) candidates.push(`${stem}/index${e}`);\n for (const c of candidates) {\n if (known.has(c)) return c;\n }\n return null;\n}\n\nfunction toPosix(p: string): string {\n return p.split(path.sep).join(\"/\");\n}\n","import { readFile, stat } from \"node:fs/promises\";\nimport { cpus } from \"node:os\";\nimport { join } from \"node:path\";\nimport { createHash } from \"node:crypto\";\nimport ignore from \"ignore\";\nimport type { GraphDb, UpsertEdgeInput, UpsertNodeInput } from \"@codegraph/graph-db\";\nimport type { LlmRouter } from \"@codegraph/llm-router\";\nimport type { GraphEdge, GraphNode } from \"@codegraph/shared\";\nimport { embedNodes, type EmbeddedNode } from \"./embedder.js\";\nimport { extractFile, resolveEdges } from \"./extractors/index.js\";\nimport { detectLanguage } from \"./parser.js\";\nimport { walkRepo } from \"./repo-walker.js\";\n\nexport interface IndexRepoOptions {\n repoId: string;\n repoPath: string;\n graphDb: GraphDb;\n router?: LlmRouter;\n /** Parallelism for in-process parsing. Defaults to `os.cpus().length`. */\n parallelism?: number;\n /** Set to false in tests to skip the (slow) embedding network call. */\n skipEmbeddings?: boolean;\n onProgress?: (e: ProgressEvent) => void;\n}\n\nexport type ProgressEvent =\n | { type: \"walk\"; files: number }\n | { type: \"parse\"; parsed: number; total: number }\n | { type: \"embed\"; embedded: number; total: number }\n | { type: \"upsert\"; nodes: number; edges: number };\n\nexport interface IndexResult {\n durationMs: number;\n parsedFiles: number;\n failedFiles: number;\n nodes: number;\n edges: number;\n embeddings: number;\n droppedEdges: number;\n}\n\n/**\n * Top-level indexer. Sequence:\n * 1. Walk the repo (gitignore-aware), classify by language.\n * 2. Parse + extract per file with bounded concurrency.\n * 3. Resolve cross-file edge targets (CALLS / RENDERS / IMPORTS / INHERITS).\n * 4. Upsert nodes + edges into FalkorDB.\n * 5. Embed every non-File node in batches of 100, upsert embeddings.\n *\n * Phase 1 is a full-repo index. Incremental re-index lands in Phase 3 with\n * the webhook flow.\n */\nexport async function indexRepo(opts: IndexRepoOptions): Promise<IndexResult> {\n const start = Date.now();\n const parallelism = Math.max(1, opts.parallelism ?? cpus().length);\n\n const files = await walkRepo(opts.repoPath);\n opts.onProgress?.({ type: \"walk\", files: files.length });\n\n const parsable = files\n .map((rel) => ({ rel, language: detectLanguage(rel) }))\n .filter((f): f is { rel: string; language: NonNullable<ReturnType<typeof detectLanguage>> } =>\n f.language !== null,\n );\n\n const knownFilePaths = new Set(parsable.map((f) => f.rel));\n\n const allNodes: GraphNode[] = [];\n const allEdges: GraphEdge[] = [];\n let parsedCount = 0;\n let failed = 0;\n\n await runWithConcurrency(parsable, parallelism, async (entry) => {\n const abs = join(opts.repoPath, entry.rel);\n try {\n const source = await readFile(abs, \"utf8\");\n const result = await extractFile({\n repoId: opts.repoId,\n relativePath: entry.rel,\n absolutePath: abs,\n language: entry.language,\n source,\n });\n allNodes.push(result.file, ...result.nodes);\n allEdges.push(...result.edges);\n } catch (_err) {\n // Parse failures are non-fatal; we surface the count in IndexResult so\n // CI can flag if it spikes.\n failed++;\n } finally {\n parsedCount++;\n opts.onProgress?.({ type: \"parse\", parsed: parsedCount, total: parsable.length });\n }\n });\n\n const { resolved, dropped } = resolveEdges({\n repoId: opts.repoId,\n nodes: allNodes,\n edges: allEdges,\n knownFilePaths,\n });\n\n // Wipe the repo's existing slice before writing so we don't accumulate\n // stale nodes from deleted source files.\n await opts.graphDb.deleteByRepo(opts.repoId);\n // GraphNode's discriminated union lacks the index signature UpsertNodeInput\n // carries; values are structurally compatible at runtime.\n await opts.graphDb.upsertNodes(allNodes as unknown as UpsertNodeInput[]);\n await opts.graphDb.upsertEdges(resolved as unknown as UpsertEdgeInput[]);\n opts.onProgress?.({ type: \"upsert\", nodes: allNodes.length, edges: resolved.length });\n\n let embeddingCount = 0;\n if (!opts.skipEmbeddings && opts.router) {\n const embedded = await embedNodes(allNodes, {\n router: opts.router,\n onBatch: ({ embedded, total }) =>\n opts.onProgress?.({ type: \"embed\", embedded, total }),\n });\n await persistEmbeddings(opts.graphDb, embedded);\n embeddingCount = embedded.length;\n }\n\n return {\n durationMs: Date.now() - start,\n parsedFiles: parsedCount - failed,\n failedFiles: failed,\n nodes: allNodes.length,\n edges: resolved.length,\n embeddings: embeddingCount,\n droppedEdges: dropped,\n };\n}\n\n/**\n * Pushes embeddings back onto their nodes via a batched UNWIND query so we don't pay N\n * round-trips. Kuzu stores fixed-size FLOAT[N] vectors natively - we pass the array as-is\n * and rely on the embedded driver's parameter coercion.\n */\nasync function persistEmbeddings(graphDb: GraphDb, embedded: EmbeddedNode[]): Promise<void> {\n if (embedded.length === 0) return;\n const BATCH = 100;\n for (let i = 0; i < embedded.length; i += BATCH) {\n const batch = embedded.slice(i, i + BATCH);\n await graphDb.query(\n `\n UNWIND $batch AS e\n MATCH (n:Symbol { id: e.id })\n SET n.embedding = e.embedding,\n n.embeddingNamespace = e.embeddingNamespace\n `,\n { batch },\n );\n }\n}\n\n/**\n * Lightweight concurrency runner. We deliberately avoid `workerpool` here\n * because tree-sitter wasm initialization in worker_threads requires per-\n * worker grammar reloads, which is a regression for the small repos this\n * tool targets in Phase 1. Switching to true OS threads is a Phase 4\n * optimization once profiling shows we're CPU-bound on multi-million-LOC\n * repos.\n */\nasync function runWithConcurrency<T>(\n items: readonly T[],\n concurrency: number,\n fn: (item: T) => Promise<void>,\n): Promise<void> {\n let cursor = 0;\n const runners = Array.from({ length: Math.min(concurrency, items.length) }, async () => {\n while (cursor < items.length) {\n const i = cursor++;\n const item = items[i];\n if (item === undefined) continue;\n await fn(item);\n }\n });\n await Promise.all(runners);\n}\n\n/** Stable content hash used to skip re-parsing unchanged files later. */\nexport function hashFileContent(source: string): string {\n return createHash(\"sha1\").update(source).digest(\"hex\");\n}\n\n/** Helper for callers who only want a stat-based size. */\nexport async function fileSize(absolutePath: string): Promise<number> {\n const s = await stat(absolutePath);\n return s.size;\n}\n\n/** Used by smoke tests / docs to verify that ignore globs apply. */\nexport function buildIgnoreFilter(patterns: readonly string[]) {\n return ignore().add(patterns as string[]);\n}\n","import type { LlmRouter } from \"@codegraph/llm-router\";\nimport type { GraphNode } from \"@codegraph/shared\";\n\nexport interface EmbedderOptions {\n router: LlmRouter;\n /** Max items per `embed()` call. Defaults to 100 per the build plan. */\n batchSize?: number;\n /** Hook for progress reporting from the CLI. */\n onBatch?: (info: { batchIndex: number; total: number; embedded: number }) => void;\n}\n\nexport interface EmbeddedNode {\n id: string;\n embedding: number[];\n embeddingNamespace: string;\n}\n\n/**\n * Embedding input format from the build plan:\n * `${kind} ${name}\\n${signature}\\n${leadingComment}`\n *\n * File nodes are excluded - we embed *symbols*, not raw files.\n */\nexport function buildEmbeddingInput(node: GraphNode): string {\n const sig = node.signature ?? \"\";\n const comment = node.leadingComment ?? \"\";\n return `${node.kind} ${node.name}\\n${sig}\\n${comment}`.trim();\n}\n\nexport async function embedNodes(\n nodes: GraphNode[],\n opts: EmbedderOptions,\n): Promise<EmbeddedNode[]> {\n const batchSize = opts.batchSize ?? 100;\n const candidates = nodes.filter((n) => n.kind !== \"File\");\n const result: EmbeddedNode[] = [];\n const total = Math.ceil(candidates.length / batchSize);\n const namespace = `${opts.router.config.embeddingNamespace.provider}:${opts.router.config.embeddingNamespace.model}:${opts.router.config.embeddingNamespace.dimension}`;\n for (let i = 0; i < candidates.length; i += batchSize) {\n const slice = candidates.slice(i, i + batchSize);\n const inputs = slice.map(buildEmbeddingInput);\n const vectors = await opts.router.embed(inputs);\n for (let j = 0; j < slice.length; j++) {\n const node = slice[j];\n const vec = vectors[j];\n if (!node || !vec) continue;\n result.push({ id: node.id, embedding: vec, embeddingNamespace: namespace });\n }\n opts.onBatch?.({\n batchIndex: i / batchSize,\n total,\n embedded: result.length,\n });\n }\n return result;\n}\n","import { readFile, readdir, stat } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport ignore, { type Ignore } from \"ignore\";\n\n/** Directories we never traverse regardless of .gitignore contents. */\nconst ALWAYS_SKIP_DIRS = new Set([\n \".git\",\n \"node_modules\",\n \".next\",\n \"dist\",\n \"build\",\n \"out\",\n \".turbo\",\n \".cache\",\n \"coverage\",\n \".idea\",\n \".vscode\",\n]);\n\n/**\n * DFS over `root`. Honors the *root* `.gitignore` and the always-skip\n * directory set above. Nested `.gitignore` files (e.g. one inside\n * `packages/foo/`) are intentionally ignored for Phase 1 simplicity -\n * monorepos hit this limitation rarely because the root file usually\n * captures shared exclusions. Returns repo-relative POSIX paths.\n */\nexport async function walkRepo(root: string): Promise<string[]> {\n const base = path.resolve(root);\n const matcher = ignore();\n await loadGitignoreInto(matcher, base);\n const out: string[] = [];\n await walkDir(base, \"\", matcher, out);\n return out.sort();\n}\n\nasync function walkDir(\n absDir: string,\n relDir: string,\n ig: Ignore,\n out: string[],\n): Promise<void> {\n let entries: import(\"node:fs\").Dirent<string>[];\n try {\n entries = await readdir(absDir, { withFileTypes: true, encoding: \"utf8\" });\n } catch {\n return;\n }\n for (const entry of entries) {\n const name = entry.name;\n const rel = relDir ? `${relDir}/${name}` : name;\n const abs = path.join(absDir, name);\n if (entry.isDirectory()) {\n if (ALWAYS_SKIP_DIRS.has(name)) continue;\n // `ignore` expects a trailing slash to test directories.\n if (ig.ignores(`${rel}/`)) continue;\n await walkDir(abs, rel, ig, out);\n } else if (entry.isFile()) {\n if (ig.ignores(rel)) continue;\n const s = await safeStat(abs);\n if (s && s.size > 2_000_000) continue;\n out.push(rel);\n }\n }\n}\n\nasync function loadGitignoreInto(ig: Ignore, absDir: string): Promise<void> {\n const file = path.join(absDir, \".gitignore\");\n try {\n const text = await readFile(file, \"utf8\");\n ig.add(text);\n } catch {\n // Missing or unreadable .gitignore - fine.\n }\n}\n\nasync function safeStat(p: string): Promise<Awaited<ReturnType<typeof stat>> | null> {\n try {\n return await stat(p);\n } catch {\n return null;\n }\n}\n","import { createHash } from \"node:crypto\";\nimport path from \"node:path\";\n\n/**\n * Deterministic, human-readable repo identifier based on the absolute path.\n * Falls back to a short hash for collisions or weird path characters.\n *\n * /Users/x/Code/codegraph -> codegraph-aab12cd3\n */\nexport function repoIdFromPath(absPath: string): string {\n const base = path.basename(path.resolve(absPath));\n const sha = createHash(\"sha1\").update(path.resolve(absPath)).digest(\"hex\").slice(0, 8);\n const safe = base.replace(/[^A-Za-z0-9_-]/g, \"_\");\n return `${safe}-${sha}`;\n}\n","import { DEFAULT_CONFIG } from \"@codegraph/shared\";\nimport { InMemoryCache } from \"./cache.js\";\nimport {\n defaultConfigPath,\n readCodegraphConfig,\n resolveDbPath,\n resolveServerConfig,\n} from \"./config.js\";\nimport { createConsoleLogger } from \"./logger.js\";\nimport { type StartedSseServer, startSseServer } from \"./server.js\";\nimport type { GraphClient, LlmRouter, ServerConfig, ToolDeps } from \"./types.js\";\n\nexport interface StartMcpServerOptions {\n /** Port override; defaults to the value in config or {@link MCP_PORT}. */\n port?: number;\n host?: string;\n configPath?: string;\n /** Optional override for the embedded Kuzu graph directory. */\n dbPath?: string;\n /** Custom deps for tests; if provided, skips loading Phase-1 packages. */\n deps?: Partial<ToolDeps>;\n}\n\n/**\n * High-level CLI-facing helper. Reads `~/.codegraph/config.json`, wires up the embedded\n * Kuzu graph client and the LLM router from the Phase-1 packages, and boots the SSE\n * server. The tool-result cache is an in-process LRU; we no longer require Redis.\n *\n * Returns the running {@link StartedSseServer} so the caller can await graceful shutdown.\n */\nexport async function startMcpServer(\n portOrOptions?: number | StartMcpServerOptions,\n): Promise<StartedSseServer> {\n const options: StartMcpServerOptions =\n typeof portOrOptions === \"number\" ? { port: portOrOptions } : (portOrOptions ?? {});\n const logger = createConsoleLogger();\n\n const overrides: Partial<ServerConfig> = {};\n if (options.port !== undefined) overrides.port = options.port;\n if (options.host !== undefined) overrides.host = options.host;\n\n const { config, configPath, created } = await resolveServerConfig({\n ...(options.configPath !== undefined ? { configPath: options.configPath } : {}),\n overrides,\n });\n if (created) logger.info(\"generated new bearer token\", { configPath });\n\n const fileConfig = await readCodegraphConfig(options.configPath ?? defaultConfigPath());\n const dbPath = options.dbPath ?? resolveDbPath(fileConfig);\n\n const cache = options.deps?.cache ?? new InMemoryCache();\n const graph = options.deps?.graph ?? (await loadGraphClient(dbPath));\n const llm = options.deps?.llm ?? (await loadLlmRouter(options.configPath ?? defaultConfigPath()));\n\n const deps: ToolDeps = {\n graph,\n llm,\n cache,\n cacheTtlSeconds: config.cacheTtlSeconds,\n logger,\n };\n return startSseServer({ deps, config });\n}\n\n/** Dynamic import wrapper around `@codegraph/graph-db`. */\nasync function loadGraphClient(dbPath: string | undefined): Promise<GraphClient> {\n let mod: Record<string, unknown>;\n try {\n mod = (await import(\"@codegraph/graph-db\")) as Record<string, unknown>;\n } catch (err) {\n throw new Error(\n `Failed to import @codegraph/graph-db. Run \\`pnpm -r build\\` first. Underlying error: ${\n err instanceof Error ? err.message : String(err)\n }`,\n );\n }\n const GraphDb = mod.GraphDb as\n | (new (opts: { dbPath?: string }) => GraphDbLike)\n | undefined;\n if (typeof GraphDb !== \"function\") {\n throw new Error(\"@codegraph/graph-db has no `GraphDb` export.\");\n }\n const db = new GraphDb(dbPath !== undefined ? { dbPath } : {});\n await db.connect();\n await db.migrate();\n return {\n async query<T extends Record<string, unknown>>(\n cypher: string,\n params?: Record<string, unknown>,\n ): Promise<T[]> {\n const r = await db.query<T>(cypher, params ?? {});\n return r.data;\n },\n async close() {\n await db.close();\n },\n };\n}\n\ninterface GraphDbLike {\n connect(): Promise<void>;\n close(): Promise<void>;\n migrate(): Promise<void>;\n query<T extends Record<string, unknown> = Record<string, unknown>>(\n cypher: string,\n params?: Record<string, unknown>,\n ): Promise<{ data: T[] }>;\n}\n\n/** Dynamic import wrapper around `@codegraph/llm-router`. */\nasync function loadLlmRouter(configPath: string): Promise<LlmRouter> {\n let mod: Record<string, unknown>;\n try {\n mod = (await import(\"@codegraph/llm-router\")) as Record<string, unknown>;\n } catch (err) {\n throw new Error(\n `Failed to import @codegraph/llm-router. Run \\`pnpm -r build\\` first. Underlying error: ${\n err instanceof Error ? err.message : String(err)\n }`,\n );\n }\n const createLlmRouter = mod.createLlmRouter as\n | ((opts: {\n config?: unknown;\n configPath?: string;\n }) => Promise<RouterLike> | RouterLike)\n | undefined;\n if (typeof createLlmRouter !== \"function\") {\n throw new Error(\"@codegraph/llm-router has no `createLlmRouter` export.\");\n }\n // Read the persisted llm config out of the codegraph config file. If it's missing\n // (user ran `codegraph serve` before ever calling `codegraph config llm set`), fall\n // back to the shared DEFAULT_CONFIG so we at least surface a useful \"missing API key\"\n // error rather than a `Cannot read properties of undefined`.\n const fileConfig = await readCodegraphConfig(configPath);\n const llmConfig =\n (fileConfig.llm as { generation?: unknown; embeddings?: unknown } | undefined) ??\n undefined;\n const effectiveConfig =\n llmConfig && llmConfig.generation && llmConfig.embeddings ? llmConfig : DEFAULT_CONFIG.llm;\n const router = await createLlmRouter({\n config: effectiveConfig as unknown,\n configPath,\n });\n return adaptLlmRouter(router);\n}\n\ninterface RouterLike {\n embed(texts: string[]): Promise<number[][]>;\n generate(opts: {\n system?: string;\n messages: { role: \"system\" | \"user\" | \"assistant\"; content: string }[];\n maxTokens?: number;\n temperature?: number;\n }): Promise<string>;\n config?: {\n embeddingNamespace?: { provider: string; model: string; dimension: number };\n embeddings?: { provider: string; model: string; dimension: number };\n };\n}\n\nfunction adaptLlmRouter(router: RouterLike): LlmRouter {\n const ns =\n router.config?.embeddingNamespace ??\n (router.config?.embeddings\n ? {\n provider: router.config.embeddings.provider,\n model: router.config.embeddings.model,\n dimension: router.config.embeddings.dimension,\n }\n : { provider: \"unknown\", model: \"unknown\", dimension: 0 });\n return {\n embed: (texts) => router.embed(texts),\n generate: (opts) => router.generate(opts),\n embeddingNamespace: ns,\n };\n}\n","import { createHash } from \"node:crypto\";\nimport type { ToolCache } from \"./types.js\";\n\n/** Build a stable cache key from a tool name and arguments. */\nexport function buildCacheKey(toolName: string, args: unknown, namespace = \"v1\"): string {\n const serialized = stableStringify(args);\n const hash = createHash(\"sha1\").update(serialized).digest(\"hex\");\n return `codegraph:${namespace}:tool:${toolName}:${hash}`;\n}\n\n/** Deterministic JSON.stringify that sorts object keys. */\nfunction stableStringify(value: unknown): string {\n return JSON.stringify(value, (_key, v) => {\n if (v && typeof v === \"object\" && !Array.isArray(v)) {\n const sorted: Record<string, unknown> = {};\n for (const key of Object.keys(v as Record<string, unknown>).sort()) {\n sorted[key] = (v as Record<string, unknown>)[key];\n }\n return sorted;\n }\n return v;\n });\n}\n\n/**\n * In-memory TTL cache. Used everywhere now that we no longer run a separate Redis service.\n *\n * Per-process is fine for the single-user local tool: every MCP server boot starts with a\n * cold cache, which trades a few extra Cypher queries for one fewer process to manage.\n */\nexport class InMemoryCache implements ToolCache {\n private store = new Map<string, { value: string; expiresAt: number }>();\n\n async get(key: string): Promise<string | null> {\n const entry = this.store.get(key);\n if (!entry) return null;\n if (entry.expiresAt <= Date.now()) {\n this.store.delete(key);\n return null;\n }\n return entry.value;\n }\n\n async set(key: string, value: string, ttlSeconds: number): Promise<void> {\n this.store.set(key, { value, expiresAt: Date.now() + ttlSeconds * 1000 });\n }\n\n async close(): Promise<void> {\n this.store.clear();\n }\n}\n\n/**\n * Returns a cached value or computes it via `compute`, storing the result with the given TTL.\n * Errors from the cache layer are swallowed - compute is still called, just uncached.\n */\nexport async function memoizeJson<T>(\n cache: ToolCache,\n key: string,\n ttlSeconds: number,\n compute: () => Promise<T>,\n): Promise<T> {\n const cached = await cache.get(key);\n if (cached !== null) {\n try {\n return JSON.parse(cached) as T;\n } catch {\n // corrupt cache entry; fall through and recompute\n }\n }\n const value = await compute();\n await cache.set(key, JSON.stringify(value), ttlSeconds);\n return value;\n}\n","import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { dirname, resolve } from \"node:path\";\nimport { generateBearerToken } from \"./server.js\";\nimport type { ServerConfig } from \"./types.js\";\n\n/**\n * Persisted config file shape. Stays intentionally permissive so we can interoperate with\n * the Phase-1 `~/.codegraph/config.json` that `@codegraph/llm-router` writes.\n *\n * - `mcpToken` is the legacy/Phase-1 location for the bearer token.\n * - `server.bearerToken` is the Phase-2 location. Both are accepted on read; new writes\n * populate both fields to avoid one writer clobbering another reader.\n * - `data.dbPath` is the optional override for the embedded Kuzu graph directory.\n */\nexport interface CodegraphConfigFile {\n llm?: Record<string, unknown>;\n data?: { dbPath?: string };\n server?: {\n host?: string;\n port?: number;\n bearerToken?: string;\n cacheTtlSeconds?: number;\n };\n /** Phase-1 alias for `server.bearerToken`. Treated as authoritative if both are set. */\n mcpToken?: string;\n [extra: string]: unknown;\n}\n\n/** Default MCP listen port. Used by both server boot and clients via {@link MCP_PORT}. */\nexport const MCP_PORT = 3748;\nconst DEFAULT_HOST = \"127.0.0.1\";\nconst DEFAULT_TTL = 30;\n\nexport function defaultConfigPath(): string {\n return resolve(homedir(), \".codegraph\", \"config.json\");\n}\n\nexport async function readCodegraphConfig(\n path: string = defaultConfigPath(),\n): Promise<CodegraphConfigFile> {\n try {\n const raw = await readFile(path, \"utf8\");\n return JSON.parse(raw) as CodegraphConfigFile;\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") return {};\n throw err;\n }\n}\n\nexport async function writeCodegraphConfig(\n config: CodegraphConfigFile,\n path: string = defaultConfigPath(),\n): Promise<void> {\n await mkdir(dirname(path), { recursive: true });\n await writeFile(path, `${JSON.stringify(config, null, 2)}\\n`, \"utf8\");\n}\n\n/**\n * Resolve runtime server config from (in order): CLI overrides, config file,\n * environment variables, then hard-coded defaults. Generates and persists a bearer token\n * the first time so users don't have to think about it.\n */\nexport async function resolveServerConfig(opts: {\n configPath?: string;\n overrides?: Partial<ServerConfig>;\n}): Promise<{ config: ServerConfig; configPath: string; created: boolean }> {\n const path = opts.configPath ?? defaultConfigPath();\n const fileConfig = await readCodegraphConfig(path);\n const env = process.env;\n\n let bearerToken =\n opts.overrides?.bearerToken ??\n fileConfig.mcpToken ??\n fileConfig.server?.bearerToken ??\n env.CODEGRAPH_BEARER_TOKEN ??\n \"\";\n let created = false;\n if (!bearerToken) {\n bearerToken = generateBearerToken();\n created = true;\n await writeCodegraphConfig(\n {\n ...fileConfig,\n mcpToken: bearerToken,\n server: { ...(fileConfig.server ?? {}), bearerToken },\n },\n path,\n );\n }\n\n const config: ServerConfig = {\n host: opts.overrides?.host ?? fileConfig.server?.host ?? env.CODEGRAPH_HOST ?? DEFAULT_HOST,\n port:\n opts.overrides?.port ??\n fileConfig.server?.port ??\n (env.CODEGRAPH_PORT ? Number(env.CODEGRAPH_PORT) : MCP_PORT),\n bearerToken,\n cacheTtlSeconds:\n opts.overrides?.cacheTtlSeconds ??\n fileConfig.server?.cacheTtlSeconds ??\n (env.CODEGRAPH_CACHE_TTL ? Number(env.CODEGRAPH_CACHE_TTL) : DEFAULT_TTL),\n };\n return { config, configPath: path, created };\n}\n\n/**\n * Resolve the on-disk Kuzu database path from (in order): the config file, the\n * `CODEGRAPH_DB_PATH` env var, then `undefined` (which lets `@codegraph/graph-db` fall\n * back to its own `~/.codegraph/graph` default).\n */\nexport function resolveDbPath(fileConfig: CodegraphConfigFile): string | undefined {\n return fileConfig.data?.dbPath ?? process.env.CODEGRAPH_DB_PATH ?? undefined;\n}\n","import { randomUUID } from \"node:crypto\";\nimport type { Server as HttpServer } from \"node:http\";\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { SSEServerTransport } from \"@modelcontextprotocol/sdk/server/sse.js\";\nimport express, { type Request, type Response, type NextFunction } from \"express\";\nimport { registerAllTools } from \"./tools/index.js\";\nimport type { Logger, ServerConfig, ToolDeps } from \"./types.js\";\n\nexport interface CreateMcpServerOptions {\n deps: ToolDeps;\n /** Optional name/version override; defaults to \"codegraph\" / package version. */\n serverInfo?: { name: string; version: string } | undefined;\n}\n\n/** Build an MCP server, register every Phase-2 tool, and return it (unconnected). */\nexport function createMcpServer(opts: CreateMcpServerOptions): McpServer {\n const info = opts.serverInfo ?? { name: \"codegraph\", version: \"0.0.0\" };\n const server = new McpServer(info, {\n capabilities: { tools: {}, logging: {} },\n });\n registerAllTools(server, opts.deps);\n return server;\n}\n\nexport interface StartSseServerOptions {\n deps: ToolDeps;\n config: ServerConfig;\n serverInfo?: { name: string; version: string } | undefined;\n}\n\nexport interface StartedSseServer {\n /** Underlying Node HTTP server. */\n httpServer: HttpServer;\n /** Resolved listen address (handy when port=0 in tests). */\n address: { host: string; port: number };\n /** Graceful shutdown: close transports, then HTTP server, then deps. */\n close(): Promise<void>;\n}\n\n/**\n * Boot an HTTP server that exposes the MCP protocol over SSE on `${host}:${port}`.\n *\n * Endpoints (per the v1.x SDK example):\n * GET /mcp - establish SSE stream\n * POST /messages - client -> server JSON-RPC messages\n * GET /healthz - unauthenticated liveness probe\n *\n * Every authenticated request must include `Authorization: Bearer <token>`.\n */\nexport async function startSseServer(opts: StartSseServerOptions): Promise<StartedSseServer> {\n const { deps, config } = opts;\n const logger: Logger | undefined = deps.logger;\n const app = express();\n app.use(express.json({ limit: \"2mb\" }));\n\n app.get(\"/healthz\", (_req, res) => {\n res.status(200).json({ ok: true });\n });\n\n app.use(bearerAuthMiddleware(config.bearerToken, logger));\n\n const transports = new Map<string, SSEServerTransport>();\n\n app.get(\"/mcp\", async (_req: Request, res: Response) => {\n let transport: SSEServerTransport;\n try {\n transport = new SSEServerTransport(\"/messages\", res);\n } catch (err) {\n logger?.error(\"failed to create SSE transport\", {\n error: err instanceof Error ? err.message : String(err),\n });\n if (!res.headersSent) res.status(500).send(\"Failed to establish SSE stream\");\n return;\n }\n const sessionId = transport.sessionId;\n transports.set(sessionId, transport);\n transport.onclose = () => {\n transports.delete(sessionId);\n logger?.info(\"sse session closed\", { sessionId });\n };\n\n const server = createMcpServer({ deps, serverInfo: opts.serverInfo });\n try {\n await server.connect(transport);\n logger?.info(\"sse session opened\", { sessionId });\n } catch (err) {\n logger?.error(\"server.connect failed\", {\n sessionId,\n error: err instanceof Error ? err.message : String(err),\n });\n transports.delete(sessionId);\n if (!res.headersSent) res.status(500).send(\"MCP connect failed\");\n }\n });\n\n app.post(\"/messages\", async (req: Request, res: Response) => {\n const sessionId = req.query.sessionId as string | undefined;\n if (!sessionId) {\n res.status(400).json({ error: \"Missing sessionId query parameter\" });\n return;\n }\n const transport = transports.get(sessionId);\n if (!transport) {\n res.status(404).json({ error: \"No active session for sessionId\" });\n return;\n }\n try {\n await transport.handlePostMessage(req, res, req.body);\n } catch (err) {\n logger?.error(\"handlePostMessage failed\", {\n sessionId,\n error: err instanceof Error ? err.message : String(err),\n });\n if (!res.headersSent) res.status(500).json({ error: \"Failed to handle message\" });\n }\n });\n\n const httpServer = await new Promise<HttpServer>((resolve, reject) => {\n const srv = app.listen(config.port, config.host, () => resolve(srv)).on(\"error\", reject);\n });\n\n const address = httpServer.address();\n if (address === null || typeof address === \"string\") {\n throw new Error(\"HTTP server bound to unexpected address\");\n }\n logger?.info(\"codegraph mcp server listening\", {\n host: address.address,\n port: address.port,\n tools: 10,\n });\n\n const started: StartedSseServer = {\n httpServer,\n address: { host: address.address, port: address.port },\n async close() {\n for (const [id, t] of transports) {\n try {\n await t.close();\n } catch {\n // best-effort\n }\n transports.delete(id);\n }\n await new Promise<void>((resolve, reject) => {\n httpServer.close((err) => (err ? reject(err) : resolve()));\n });\n await deps.cache.close?.();\n await deps.graph.close?.();\n },\n };\n return started;\n}\n\nfunction bearerAuthMiddleware(expectedToken: string, logger?: Logger) {\n return (req: Request, res: Response, next: NextFunction): void => {\n const header = req.header(\"authorization\") ?? req.header(\"Authorization\");\n if (!header || !header.toLowerCase().startsWith(\"bearer \")) {\n logger?.warn(\"auth missing\", { path: req.path });\n res.status(401).json({ error: \"Missing bearer token\" });\n return;\n }\n const presented = header.slice(\"bearer \".length).trim();\n if (!safeEqual(presented, expectedToken)) {\n logger?.warn(\"auth rejected\", { path: req.path });\n res.status(403).json({ error: \"Invalid bearer token\" });\n return;\n }\n next();\n };\n}\n\n/** Constant-time string compare to avoid timing leaks on the bearer token check. */\nfunction safeEqual(a: string, b: string): boolean {\n if (a.length !== b.length) return false;\n let diff = 0;\n for (let i = 0; i < a.length; i++) {\n diff |= a.charCodeAt(i) ^ b.charCodeAt(i);\n }\n return diff === 0;\n}\n\n/** Generate a fresh bearer token (32 hex chars). */\nexport function generateBearerToken(): string {\n return randomUUID().replace(/-/g, \"\");\n}\n","import { z } from \"zod\";\nimport type { ToolDefinition } from \"./types.js\";\nimport { cachedJsonResult } from \"./util.js\";\n\nconst inputSchema = {\n symbol: z.string().min(1).describe(\"Symbol name. Use `path` for the file when ambiguous.\"),\n path: z.string().optional().describe(\"Optional file path to disambiguate the symbol.\"),\n depth: z.number().int().positive().max(6).default(3),\n limit: z.number().int().positive().max(500).default(200),\n};\n\nexport const affectedByTool: ToolDefinition<typeof inputSchema> = {\n name: \"affected_by\",\n config: {\n title: \"Affected By\",\n description:\n \"Reverse-BFS over CALLS and IMPORTS edges to surface every symbol or file whose behaviour could be affected by changing the given symbol. Depth-limited to keep query bounded.\",\n inputSchema,\n annotations: { readOnlyHint: true, idempotentHint: true },\n },\n handler: async ({ symbol, path, depth, limit }, deps) =>\n cachedJsonResult(\"affected_by\", { symbol, path, depth, limit }, deps, async () => {\n const where = path\n ? \"WHERE target.name = $symbol AND target.path = $path\"\n : \"WHERE target.name = $symbol\";\n const rows = await deps.graph.query(\n `MATCH (target:Symbol) ${where}\n WITH target\n MATCH path = (affected:Symbol)-[:CALLS|IMPORTS*1..${depth}]->(target)\n WITH DISTINCT affected, min(length(path)) AS distance\n RETURN affected.id AS id, affected.name AS name, affected.kind AS kind,\n affected.path AS path, distance\n ORDER BY distance ASC, affected.path ASC LIMIT $limit`,\n { symbol, path: path ?? null, limit },\n );\n return { symbol, path: path ?? null, depth, count: rows.length, affected: rows };\n }),\n};\n","import type { CallToolResult } from \"@modelcontextprotocol/sdk/types.js\";\nimport { buildCacheKey, memoizeJson } from \"../cache.js\";\nimport type { ToolDeps } from \"../types.js\";\n\n/** Default tool-result TTL, per the Phase-2 plan. */\nexport const DEFAULT_TOOL_TTL_SECONDS = 30;\n\n/** Wrap a JSON-serializable payload into the MCP `CallToolResult` shape. */\nexport function jsonResult(payload: unknown, extra?: { isError?: boolean }): CallToolResult {\n const text = JSON.stringify(payload, null, 2);\n const base = {\n content: [{ type: \"text\" as const, text }],\n structuredContent: isStructuredContent(payload) ? payload : { result: payload },\n };\n return extra?.isError ? { ...base, isError: true } : base;\n}\n\nfunction isStructuredContent(value: unknown): value is { [key: string]: unknown } {\n return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\n/** Memoized JSON result helper. */\nexport async function cachedJsonResult<TArgs, TResult>(\n toolName: string,\n args: TArgs,\n deps: ToolDeps,\n compute: () => Promise<TResult>,\n): Promise<CallToolResult> {\n const key = buildCacheKey(toolName, args);\n const ttl = deps.cacheTtlSeconds ?? DEFAULT_TOOL_TTL_SECONDS;\n const value = await memoizeJson(deps.cache, key, ttl, compute);\n return jsonResult(value);\n}\n","import { z } from \"zod\";\nimport type { ToolDefinition } from \"./types.js\";\nimport { cachedJsonResult } from \"./util.js\";\n\nconst inputSchema = {\n symbol: z.string().min(1).describe(\"Symbol name to compute the blast radius for.\"),\n path: z.string().optional().describe(\"Optional file path to disambiguate the symbol.\"),\n depth: z.number().int().positive().max(6).default(4),\n sampleSize: z.number().int().positive().max(50).default(10),\n};\n\nexport const blastRadiusTool: ToolDefinition<typeof inputSchema> = {\n name: \"blast_radius\",\n config: {\n title: \"Blast Radius\",\n description:\n \"Reverse-BFS over CALLS, IMPORTS, and RENDERS edges to count the total number of upstream dependents, plus a small sample to give the agent context.\",\n inputSchema,\n annotations: { readOnlyHint: true, idempotentHint: true },\n },\n handler: async ({ symbol, path, depth, sampleSize }, deps) =>\n cachedJsonResult(\"blast_radius\", { symbol, path, depth, sampleSize }, deps, async () => {\n const where = path\n ? \"WHERE target.name = $symbol AND target.path = $path\"\n : \"WHERE target.name = $symbol\";\n const [stats] = await deps.graph.query<{ total: number }>(\n `MATCH (target:Symbol) ${where}\n WITH target\n MATCH (dependent:Symbol)-[:CALLS|IMPORTS|RENDERS*1..${depth}]->(target)\n RETURN count(DISTINCT dependent) AS total`,\n { symbol, path: path ?? null },\n );\n const sample = await deps.graph.query(\n `MATCH (target:Symbol) ${where}\n WITH target\n MATCH p = (dependent:Symbol)-[:CALLS|IMPORTS|RENDERS*1..${depth}]->(target)\n WITH DISTINCT dependent, min(length(p)) AS distance\n RETURN dependent.id AS id, dependent.name AS name, dependent.kind AS kind,\n dependent.path AS path, distance\n ORDER BY distance ASC, dependent.path ASC LIMIT $sampleSize`,\n { symbol, path: path ?? null, sampleSize },\n );\n return {\n symbol,\n path: path ?? null,\n depth,\n totalDependents: stats?.total ?? 0,\n sample,\n };\n }),\n};\n","import { z } from \"zod\";\nimport type { ToolDefinition } from \"./types.js\";\nimport { cachedJsonResult } from \"./util.js\";\n\nconst inputSchema = {\n name: z.string().min(1).describe(\"Exact symbol name to find callers of.\"),\n limit: z.number().int().positive().max(500).default(100),\n};\n\nexport const findCallersTool: ToolDefinition<typeof inputSchema> = {\n name: \"find_callers\",\n config: {\n title: \"Find Callers\",\n description:\n \"Return symbols that have a CALLS edge to the named target. Uses Phase-1 heuristic edges (identifier-position match).\",\n inputSchema,\n annotations: { readOnlyHint: true, idempotentHint: true },\n },\n handler: async ({ name, limit }, deps) =>\n cachedJsonResult(\"find_callers\", { name, limit }, deps, async () => {\n const rows = await deps.graph.query(\n `MATCH (caller:Symbol)-[:CALLS]->(callee:Symbol)\n WHERE callee.name = $name\n RETURN caller.id AS id, caller.name AS name, caller.kind AS kind,\n caller.path AS path, caller.lineStart AS line\n ORDER BY caller.path, caller.lineStart LIMIT $limit`,\n { name, limit },\n );\n return { name, count: rows.length, callers: rows };\n }),\n};\n","import { z } from \"zod\";\nimport type { ToolDefinition } from \"./types.js\";\nimport { cachedJsonResult } from \"./util.js\";\n\nconst inputSchema = {\n fragment: z.string().min(1).describe(\"Substring to match against file paths.\"),\n limit: z.number().int().positive().max(200).default(50),\n};\n\nexport const findFileTool: ToolDefinition<typeof inputSchema> = {\n name: \"find_file\",\n config: {\n title: \"Find File\",\n description: \"Locate files in the indexed repo by a substring of their path.\",\n inputSchema,\n annotations: { readOnlyHint: true, idempotentHint: true },\n },\n handler: async ({ fragment, limit }, deps) =>\n cachedJsonResult(\"find_file\", { fragment, limit }, deps, async () => {\n const rows = await deps.graph.query(\n `MATCH (f:Symbol)\n WHERE f.kind = 'File' AND lower(f.path) CONTAINS lower($q)\n RETURN f.id AS id, f.path AS path, f.name AS name\n ORDER BY f.path LIMIT $limit`,\n { q: fragment, limit },\n );\n return { fragment, count: rows.length, matches: rows };\n }),\n};\n","import { z } from \"zod\";\nimport type { ToolDefinition } from \"./types.js\";\nimport { cachedJsonResult } from \"./util.js\";\n\nconst inputSchema = {\n name: z.string().min(1).describe(\"Component name (PascalCase).\"),\n depth: z.number().int().positive().max(8).default(4),\n};\n\nexport const getComponentTreeTool: ToolDefinition<typeof inputSchema> = {\n name: \"get_component_tree\",\n config: {\n title: \"Get Component Tree\",\n description:\n \"Recursively walk RENDERS edges from the named component, returning the rendered descendants up to the requested depth.\",\n inputSchema,\n annotations: { readOnlyHint: true, idempotentHint: true },\n },\n handler: async ({ name, depth }, deps) =>\n cachedJsonResult(\"get_component_tree\", { name, depth }, deps, async () => {\n const rows = await deps.graph.query(\n `MATCH (root:Symbol {kind: 'Component', name: $name})\n OPTIONAL MATCH path = (root)-[:RENDERS*1..${depth}]->(child:Symbol)\n WHERE child.kind = 'Component'\n WITH root, collect(DISTINCT { name: child.name, id: child.id, path: child.path, depth: length(path) }) AS children\n RETURN root.id AS rootId, root.name AS rootName, root.path AS rootPath, children`,\n { name },\n );\n return { name, depth, tree: rows[0] ?? null };\n }),\n};\n","import { z } from \"zod\";\nimport type { ToolDefinition } from \"./types.js\";\nimport { cachedJsonResult } from \"./util.js\";\n\nconst inputSchema = {\n path: z.string().min(1).describe(\"Repo-relative file path.\"),\n depth: z.number().int().positive().max(8).default(4),\n limit: z.number().int().positive().max(500).default(200),\n};\n\nexport const getDependenciesTool: ToolDefinition<typeof inputSchema> = {\n name: \"get_dependencies\",\n config: {\n title: \"Get Dependencies\",\n description:\n \"Forward-BFS over IMPORTS edges, returning every file transitively imported by the given path, with depth.\",\n inputSchema,\n annotations: { readOnlyHint: true, idempotentHint: true },\n },\n handler: async ({ path, depth, limit }, deps) =>\n cachedJsonResult(\"get_dependencies\", { path, depth, limit }, deps, async () => {\n const rows = await deps.graph.query(\n `MATCH (root:Symbol)\n WHERE root.kind = 'File' AND root.path = $path\n OPTIONAL MATCH p = (root)-[:IMPORTS*1..${depth}]->(dep:Symbol)\n WHERE dep.kind = 'File'\n WITH DISTINCT dep, min(length(p)) AS distance\n WHERE dep IS NOT NULL\n RETURN dep.id AS id, dep.path AS path, distance\n ORDER BY distance ASC, dep.path ASC LIMIT $limit`,\n { path, limit },\n );\n return { path, depth, count: rows.length, dependencies: rows };\n }),\n};\n","import { z } from \"zod\";\nimport type { ToolDefinition } from \"./types.js\";\nimport { cachedJsonResult } from \"./util.js\";\n\nconst inputSchema = {\n path: z.string().min(1).describe(\"Repo-relative file path.\"),\n symbolLimit: z.number().int().positive().max(500).default(100),\n};\n\nexport const getFileContextTool: ToolDefinition<typeof inputSchema> = {\n name: \"get_file_context\",\n config: {\n title: \"Get File Context\",\n description:\n \"Return the file's defined symbols, imported files, exported symbols, and the files that import it.\",\n inputSchema,\n annotations: { readOnlyHint: true, idempotentHint: true },\n },\n handler: async ({ path, symbolLimit }, deps) =>\n cachedJsonResult(\"get_file_context\", { path, symbolLimit }, deps, async () => {\n const fileRows = await deps.graph.query(\n `MATCH (f:Symbol)\n WHERE f.kind = 'File' AND f.path = $path\n RETURN f.id AS id, f.path AS path, f.name AS name LIMIT 1`,\n { path },\n );\n if (fileRows.length === 0) {\n return { path, found: false };\n }\n const [defined, imports, exports, importers] = await Promise.all([\n deps.graph.query(\n `MATCH (f:Symbol)-[:DEFINES]->(s:Symbol)\n WHERE f.kind = 'File' AND f.path = $path\n RETURN s.id AS id, s.name AS name, s.kind AS kind, s.lineStart AS line, s.signature AS signature\n ORDER BY s.lineStart LIMIT $limit`,\n { path, limit: symbolLimit },\n ),\n deps.graph.query(\n `MATCH (f:Symbol)-[:IMPORTS]->(t:Symbol)\n WHERE f.kind = 'File' AND t.kind = 'File' AND f.path = $path\n RETURN DISTINCT t.path AS path ORDER BY t.path`,\n { path },\n ),\n deps.graph.query(\n `MATCH (f:Symbol)-[:EXPORTS]->(s:Symbol)\n WHERE f.kind = 'File' AND f.path = $path\n RETURN s.id AS id, s.name AS name, s.kind AS kind, s.lineStart AS line\n ORDER BY s.name`,\n { path },\n ),\n deps.graph.query(\n `MATCH (other:Symbol)-[:IMPORTS]->(f:Symbol)\n WHERE other.kind = 'File' AND f.kind = 'File' AND f.path = $path\n RETURN DISTINCT other.path AS path ORDER BY other.path`,\n { path },\n ),\n ]);\n return {\n path,\n found: true,\n file: fileRows[0],\n definedSymbols: defined,\n importsFiles: imports,\n exportedSymbols: exports,\n importedBy: importers,\n };\n }),\n};\n","import { z } from \"zod\";\nimport { validateReadOnlyCypher } from \"../cypher-guard.js\";\nimport type { ToolDefinition } from \"./types.js\";\nimport { cachedJsonResult, jsonResult } from \"./util.js\";\n\nconst inputSchema = {\n question: z.string().min(1).describe(\"Natural-language question about the codebase.\"),\n limit: z\n .number()\n .int()\n .positive()\n .max(200)\n .default(50)\n .describe(\"Row cap injected into the generated query as $limit.\"),\n};\n\nconst SYSTEM_PROMPT = `You translate natural-language questions about a code graph into a single Cypher query.\n\nSchema (Kuzu):\n- Single node table: \\`Symbol\\`. Distinguish kinds via the \\`kind\\` STRING column.\n Valid kinds: File, Function, Class, Interface, Component, Route, Variable.\n- Edge tables (each FROM Symbol TO Symbol): IMPORTS, CALLS, RENDERS, INHERITS, DEFINES, EXPORTS.\n- Useful Symbol columns: id, kind, repoId, name, path, lineStart, lineEnd, signature, leadingComment.\n\nExamples:\n // All files imported by app.ts:\n MATCH (a:Symbol)-[:IMPORTS]->(b:Symbol)\n WHERE a.kind = 'File' AND a.path = 'app.ts' AND b.kind = 'File'\n RETURN b.path LIMIT $limit\n\n // What calls useAuth?\n MATCH (caller:Symbol)-[:CALLS]->(callee:Symbol)\n WHERE callee.name = 'useAuth'\n RETURN caller.name, caller.path, caller.kind LIMIT $limit\n\nConstraints you MUST follow:\n- Produce exactly ONE statement.\n- It must be read-only: only MATCH / OPTIONAL MATCH / WITH / UNWIND / RETURN clauses.\n- Do not use CREATE, MERGE, DELETE, SET, REMOVE, DROP, FOREACH, CALL { ... }, or procedure CALLs.\n- Always include a LIMIT (use the $limit parameter that will be passed in).\n- Use \\`s.kind = 'File'\\` style filters - do NOT use multi-label syntax like \\`(s:File)\\`.\n- Return useful columns named clearly (id, name, kind, path, line, score, etc.).\n- Output ONLY the Cypher query. No prose, no markdown fences.`;\n\nexport const nlQueryTool: ToolDefinition<typeof inputSchema> = {\n name: \"nl_query\",\n config: {\n title: \"Natural-Language Cypher Query\",\n description:\n \"Translate a natural-language question into Cypher via the configured LLM, validate it against a read-only allowlist, then execute it on the graph.\",\n inputSchema,\n annotations: { readOnlyHint: true, openWorldHint: true },\n },\n handler: async ({ question, limit }, deps) => {\n const rawCypher = await deps.llm.generate({\n system: SYSTEM_PROMPT,\n messages: [{ role: \"user\", content: question }],\n temperature: 0,\n maxTokens: 400,\n });\n const cypher = stripCodeFence(rawCypher).trim();\n const guard = validateReadOnlyCypher(cypher);\n if (!guard.ok) {\n return jsonResult(\n {\n question,\n accepted: false,\n rejectedCypher: cypher,\n reason: guard.reason,\n },\n { isError: false },\n );\n }\n return cachedJsonResult(\n \"nl_query\",\n { question, limit, cypher: guard.normalized },\n deps,\n async () => {\n try {\n const rows = await deps.graph.query(guard.normalized ?? cypher, { limit });\n return {\n question,\n accepted: true,\n cypher: guard.normalized ?? cypher,\n rowCount: rows.length,\n rows,\n };\n } catch (err) {\n return {\n question,\n accepted: true,\n cypher: guard.normalized ?? cypher,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n },\n );\n },\n};\n\nfunction stripCodeFence(text: string): string {\n const fenced = text.match(/```(?:cypher)?\\n([\\s\\S]*?)```/i);\n if (fenced?.[1]) return fenced[1];\n return text;\n}\n","/**\n * Allowlist-style validator for Cypher generated by `nl_query`.\n *\n * The rules are intentionally strict and conservative:\n * - Exactly one statement (no semicolons except optionally one trailing).\n * - The first non-whitespace clause must be a read clause (MATCH, OPTIONAL MATCH, WITH,\n * UNWIND, RETURN).\n * - Mutating keywords (CREATE, MERGE, DELETE, DETACH DELETE, SET, REMOVE, DROP, FOREACH)\n * are rejected.\n * - `CALL { ... }` subqueries are rejected because they can hide writes.\n * - Procedure calls (`CALL db.foo()`) are rejected because they can mutate or be slow.\n *\n * String literals and comments are stripped before checking so that keywords inside quoted\n * strings (e.g. a node `name` literal containing the word `DELETE`) don't trip the guard.\n */\n\nexport interface CypherGuardResult {\n ok: boolean;\n /** When `ok === false`, a one-line reason suitable for surfacing back to the LLM. */\n reason?: string;\n /** The normalized statement that was validated (comments and strings stripped). */\n normalized?: string;\n}\n\nconst ALLOWED_LEADING_CLAUSES = [\"MATCH\", \"OPTIONAL MATCH\", \"WITH\", \"UNWIND\", \"RETURN\"] as const;\n\nconst FORBIDDEN_KEYWORDS = [\n \"CREATE\",\n \"MERGE\",\n \"DELETE\",\n \"DETACH DELETE\",\n \"SET\",\n \"REMOVE\",\n \"DROP\",\n \"FOREACH\",\n \"LOAD CSV\",\n] as const;\n\n/** Strip `//` and `/* ... *\\/` style comments. */\nfunction stripComments(src: string): string {\n return src.replace(/\\/\\*[\\s\\S]*?\\*\\//g, \" \").replace(/\\/\\/[^\\n]*/g, \" \");\n}\n\n/** Replace string literal contents with empty quotes so keywords inside strings are ignored. */\nfunction stripStringLiterals(src: string): string {\n return src\n .replace(/'(?:\\\\.|[^'\\\\])*'/g, \"''\")\n .replace(/\"(?:\\\\.|[^\"\\\\])*\"/g, '\"\"')\n .replace(/`(?:\\\\.|[^`\\\\])*`/g, \"``\");\n}\n\nfunction startsWithAllowedClause(upper: string): boolean {\n for (const clause of ALLOWED_LEADING_CLAUSES) {\n if (upper.startsWith(`${clause} `) || upper === clause) {\n return true;\n }\n }\n return false;\n}\n\nfunction findForbiddenKeyword(upper: string): string | null {\n for (const kw of FORBIDDEN_KEYWORDS) {\n const pattern = new RegExp(`\\\\b${kw.replace(/\\s+/g, \"\\\\s+\")}\\\\b`);\n if (pattern.test(upper)) {\n return kw;\n }\n }\n return null;\n}\n\nexport function validateReadOnlyCypher(input: string): CypherGuardResult {\n if (typeof input !== \"string\" || input.trim().length === 0) {\n return { ok: false, reason: \"Empty Cypher statement.\" };\n }\n\n const withoutComments = stripComments(input);\n const sanitized = stripStringLiterals(withoutComments).trim();\n\n const withoutTrailingSemicolon = sanitized.replace(/;\\s*$/, \"\");\n if (withoutTrailingSemicolon.includes(\";\")) {\n return {\n ok: false,\n reason: \"Multiple statements are not allowed (found `;`).\",\n normalized: sanitized,\n };\n }\n\n const normalized = withoutTrailingSemicolon.trim();\n const upper = normalized.toUpperCase().replace(/\\s+/g, \" \").trim();\n\n if (!startsWithAllowedClause(upper)) {\n return {\n ok: false,\n reason: `Statement must start with one of: ${ALLOWED_LEADING_CLAUSES.join(\", \")}.`,\n normalized,\n };\n }\n\n const forbidden = findForbiddenKeyword(upper);\n if (forbidden) {\n return {\n ok: false,\n reason: `Mutating keyword '${forbidden}' is not allowed in nl_query results.`,\n normalized,\n };\n }\n\n if (/\\bCALL\\s*\\{/.test(upper)) {\n return {\n ok: false,\n reason: \"CALL { ... } subqueries are not allowed (they may hide writes).\",\n normalized,\n };\n }\n\n if (/\\bCALL\\s+[A-Z0-9_.]+\\s*\\(/.test(upper)) {\n return {\n ok: false,\n reason: \"Procedure calls (CALL ns.proc(...)) are not allowed.\",\n normalized,\n };\n }\n\n return { ok: true, normalized };\n}\n","import { z } from \"zod\";\nimport type { ToolDefinition } from \"./types.js\";\nimport { cachedJsonResult, jsonResult } from \"./util.js\";\n\nconst inputSchema = {\n description: z\n .string()\n .min(1)\n .describe(\"Natural-language description of the symbol you are looking for.\"),\n k: z.number().int().positive().max(50).default(10).describe(\"Number of nearest neighbours.\"),\n};\n\nexport const searchSemanticTool: ToolDefinition<typeof inputSchema> = {\n name: \"search_semantic\",\n config: {\n title: \"Semantic Symbol Search\",\n description:\n \"Embed the supplied description via the configured LLM router, then run a vector KNN over indexed symbol embeddings.\",\n inputSchema,\n annotations: { readOnlyHint: true, idempotentHint: true },\n },\n handler: async ({ description, k }, deps) => {\n const [embedding] = await deps.llm.embed([description]);\n if (!embedding) {\n return jsonResult(\n { error: \"LLM router returned no embedding for the query.\" },\n { isError: true },\n );\n }\n const namespace = `${deps.llm.embeddingNamespace.provider}:${deps.llm.embeddingNamespace.model}:${deps.llm.embeddingNamespace.dimension}`;\n return cachedJsonResult(\"search_semantic\", { description, k, namespace }, deps, async () => {\n // Kuzu vector extension: CALL QUERY_VECTOR_INDEX('table', 'index_name', $vec, $k)\n // returns each candidate as `node` plus a `distance` column. We filter to the active\n // embedding namespace so cross-provider drift can't poison results.\n const rows = await deps.graph.query(\n `CALL QUERY_VECTOR_INDEX('Symbol', 'embedding_idx', $vec, $k)\n WITH node, distance\n WHERE node.embeddingNamespace = $ns\n RETURN node.id AS id, node.name AS name, node.kind AS kind, node.path AS path,\n node.lineStart AS line, node.signature AS signature, distance AS score\n ORDER BY distance ASC`,\n { vec: embedding, k, ns: namespace },\n );\n return { description, k, namespace, count: rows.length, matches: rows };\n });\n },\n};\n","import { z } from \"zod\";\nimport type { ToolDefinition } from \"./types.js\";\nimport { cachedJsonResult } from \"./util.js\";\n\nconst inputSchema = {\n query: z.string().min(1).describe(\"Substring to match against symbol names (case-insensitive).\"),\n kind: z\n .enum([\"File\", \"Function\", \"Class\", \"Interface\", \"Component\", \"Route\", \"Variable\"])\n .optional()\n .describe(\"Optional filter by node kind.\"),\n limit: z.number().int().positive().max(200).default(25),\n};\n\nexport const searchSymbolTool: ToolDefinition<typeof inputSchema> = {\n name: \"search_symbol\",\n config: {\n title: \"Search Symbol\",\n description:\n \"Find functions, classes, components, routes, or variables by case-insensitive substring match on the symbol name.\",\n inputSchema,\n annotations: { readOnlyHint: true, idempotentHint: true },\n },\n handler: async ({ query, kind, limit }, deps) =>\n cachedJsonResult(\"search_symbol\", { query, kind, limit }, deps, async () => {\n // Kuzu stores all symbols under a single `:Symbol` table with a `kind` discriminator\n // column, so the kind filter is a `WHERE s.kind = $kind` rather than a label.\n const cypher = kind\n ? `MATCH (s:Symbol)\n WHERE s.kind = $kind AND lower(s.name) CONTAINS lower($q)\n RETURN s.id AS id, s.name AS name, s.kind AS kind, s.path AS path,\n s.lineStart AS line, s.signature AS signature\n ORDER BY s.name LIMIT $limit`\n : `MATCH (s:Symbol)\n WHERE s.name IS NOT NULL AND lower(s.name) CONTAINS lower($q)\n RETURN s.id AS id, s.name AS name, s.kind AS kind, s.path AS path,\n s.lineStart AS line, s.signature AS signature\n ORDER BY s.name LIMIT $limit`;\n const rows = await deps.graph.query(cypher, { q: query, limit, kind: kind ?? null });\n return { query, kind: kind ?? null, count: rows.length, matches: rows };\n }),\n};\n","import type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { ToolDeps } from \"../types.js\";\nimport { affectedByTool } from \"./affected-by.js\";\nimport { blastRadiusTool } from \"./blast-radius.js\";\nimport { findCallersTool } from \"./find-callers.js\";\nimport { findFileTool } from \"./find-file.js\";\nimport { getComponentTreeTool } from \"./get-component-tree.js\";\nimport { getDependenciesTool } from \"./get-dependencies.js\";\nimport { getFileContextTool } from \"./get-file-context.js\";\nimport { nlQueryTool } from \"./nl-query.js\";\nimport { searchSemanticTool } from \"./search-semantic.js\";\nimport { searchSymbolTool } from \"./search-symbol.js\";\nimport type { ToolDefinition, ToolInputShape } from \"./types.js\";\nimport { jsonResult } from \"./util.js\";\n\nexport const ALL_TOOLS: ReadonlyArray<ToolDefinition<ToolInputShape>> = [\n searchSymbolTool,\n findFileTool,\n searchSemanticTool,\n getFileContextTool,\n findCallersTool,\n getComponentTreeTool,\n affectedByTool,\n getDependenciesTool,\n blastRadiusTool,\n nlQueryTool,\n] as unknown as ReadonlyArray<ToolDefinition<ToolInputShape>>;\n\n/** Register every Phase-2 tool with the provided MCP server, wired to the given deps. */\nexport function registerAllTools(server: McpServer, deps: ToolDeps): void {\n for (const tool of ALL_TOOLS) {\n server.registerTool(tool.name, tool.config, async (args) => {\n try {\n return await tool.handler(args as never, deps);\n } catch (err) {\n deps.logger?.error(\"tool handler threw\", {\n tool: tool.name,\n error: err instanceof Error ? err.message : String(err),\n });\n return jsonResult(\n {\n tool: tool.name,\n error: err instanceof Error ? err.message : String(err),\n },\n { isError: true },\n );\n }\n });\n }\n}\n\nexport {\n affectedByTool,\n blastRadiusTool,\n findCallersTool,\n findFileTool,\n getComponentTreeTool,\n getDependenciesTool,\n getFileContextTool,\n nlQueryTool,\n searchSemanticTool,\n searchSymbolTool,\n};\nexport type { ToolDefinition, ToolInputShape } from \"./types.js\";\n","import type { Logger } from \"./types.js\";\n\n/** Minimal stderr JSON logger. Stdout is reserved for MCP-over-stdio future use. */\nexport function createConsoleLogger(level: \"info\" | \"warn\" | \"error\" = \"info\"): Logger {\n const levels = { info: 10, warn: 20, error: 30 };\n const min = levels[level];\n const emit = (lvl: \"info\" | \"warn\" | \"error\", msg: string, meta?: Record<string, unknown>) => {\n if (levels[lvl] < min) return;\n const line = JSON.stringify({ ts: new Date().toISOString(), level: lvl, msg, ...meta });\n process.stderr.write(`${line}\\n`);\n };\n return {\n info: (msg, meta) => emit(\"info\", msg, meta),\n warn: (msg, meta) => emit(\"warn\", msg, meta),\n error: (msg, meta) => emit(\"error\", msg, meta),\n };\n}\n","import { startMcpServer } from \"@codegraph/mcp-server\";\nimport { makeSpinner, renderServeBanner } from \"../ui.js\";\n\nexport interface ServeCommandOptions {\n port?: number;\n host?: string;\n dbPath?: string;\n}\n\n/**\n * Boots the local MCP server in-process. The bootstrap reads `~/.codegraph/config.json`\n * (generating a bearer token on first run), connects to the embedded Kuzu graph, and\n * starts the SSE listener.\n *\n * SIGINT / SIGTERM trigger a graceful shutdown. The shutdown closes active SSE\n * transports, releases the HTTP server, and disposes the graph + cache.\n */\nexport async function runServeCommand(opts: ServeCommandOptions = {}): Promise<void> {\n const spinner = makeSpinner(\"Booting MCP server\").start();\n let started: Awaited<ReturnType<typeof startMcpServer>>;\n try {\n started = await startMcpServer({\n ...(opts.port !== undefined ? { port: opts.port } : {}),\n ...(opts.host !== undefined ? { host: opts.host } : {}),\n ...(opts.dbPath !== undefined ? { dbPath: opts.dbPath } : {}),\n });\n spinner.stop();\n } catch (err) {\n spinner.fail(\"Server failed to start\");\n throw err;\n }\n\n const url = `http://${started.address.host}:${started.address.port}/mcp`;\n const tokenHint =\n \"bearer token at ~/.codegraph/config.json (codegraph config show to view)\";\n process.stdout.write(`${renderServeBanner(url, tokenHint)}\\n`);\n\n const shutdown = async (signal: NodeJS.Signals): Promise<never> => {\n process.stderr.write(`\\nshutting down (${signal})...\\n`);\n try {\n await started.close();\n } catch (err) {\n process.stderr.write(\n `shutdown failed: ${err instanceof Error ? err.message : String(err)}\\n`,\n );\n }\n process.exit(0);\n };\n process.once(\"SIGINT\", shutdown);\n process.once(\"SIGTERM\", shutdown);\n\n // Hold the event loop open so the SSE listener keeps accepting connections. The signal\n // handlers above terminate the process when triggered.\n await new Promise<void>(() => {});\n}\n"],"mappings":"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","names":["kleur","kleur","mkdir","kleur","kleur","path","mkdir","path","readFile","dirname","require","id","ident","path","targetId","_unused","rest","path","readFile","stat","join","createHash","ignore","readFile","path","join","readFile","embedded","kleur","createHash","path","path","kleur","createHash","mkdir","readFile","writeFile","dirname","z","path","inputSchema","resolve","configPath","GraphDb","createLlmRouter"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../graph-db/src/client.ts","../../graph-db/src/schema.ts"],"sourcesContent":["import { mkdir } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { dirname, resolve } from \"node:path\";\nimport { EDGE_KINDS, NODE_KINDS, type EdgeKind } from \"@codegraph/shared\";\nimport * as kuzu from \"kuzu\";\nimport {\n DEFAULT_EMBEDDING_DIMENSION,\n SYMBOL_COLUMNS,\n buildSchemaStatements,\n buildVectorIndexStatements,\n defaultFor,\n} from \"./schema.js\";\nimport type { QueryResult, UpsertEdgeInput, UpsertNodeInput } from \"./types.js\";\n\nexport interface GraphDbOptions {\n /** Directory where Kuzu stores its on-disk database files. Defaults to `~/.codegraph/graph`. */\n dbPath?: string;\n /**\n * Legacy `url` option kept for back-compat with Phase-1 callers. Ignored at runtime -\n * Kuzu is embedded - but accepted so existing call sites compile while the rest of the\n * codebase migrates to `dbPath`.\n */\n url?: string;\n /** Vector dimension for the `Symbol.embedding` column. Baked into the schema at create time. */\n embeddingDimension?: number;\n}\n\n/** Default on-disk location for the embedded graph. */\nexport function defaultDbPath(): string {\n return resolve(homedir(), \".codegraph\", \"graph\");\n}\n\n/**\n * Thin, typed wrapper around the embedded Kuzu database.\n *\n * Public surface (intentionally identical to the Phase-1 FalkorDB client so callers don't\n * change): connect / close / migrate / query / upsertNodes / upsertEdges / deleteByRepo /\n * stats. Internals are pure Kuzu.\n */\nexport class GraphDb {\n private readonly dbPath: string;\n private readonly embeddingDimension: number;\n private db: kuzu.Database | null = null;\n private conn: kuzu.Connection | null = null;\n private vectorIndexReady = false;\n /**\n * Cache of `conn.prepare()` results keyed by Cypher source. Kuzu's Node SDK requires a\n * prepared statement for any parameterized query - reusing the prepared object keeps\n * UNWIND-batched upserts fast.\n */\n private preparedCache = new Map<string, kuzu.PreparedStatement>();\n\n constructor(opts: GraphDbOptions = {}) {\n this.dbPath = opts.dbPath ?? defaultDbPath();\n this.embeddingDimension = opts.embeddingDimension ?? DEFAULT_EMBEDDING_DIMENSION;\n }\n\n async connect(): Promise<void> {\n if (this.conn) return;\n await mkdir(dirname(this.dbPath), { recursive: true });\n this.db = new kuzu.Database(this.dbPath);\n this.conn = new kuzu.Connection(this.db);\n }\n\n async close(): Promise<void> {\n // We deliberately do NOT call `conn.close()` / `db.close()` on Kuzu's Node bindings.\n // In 0.11.x those native handles are also disposed by the binding's process-exit hook,\n // and double-disposing can SIGSEGV the worker on cleanup. Dropping references is\n // enough for the GC to release the underlying memory before the process exits.\n this.preparedCache.clear();\n this.conn = null;\n this.db = null;\n this.vectorIndexReady = false;\n }\n\n private requireConn(): kuzu.Connection {\n if (!this.conn) {\n throw new Error(\"GraphDb not connected. Call connect() first.\");\n }\n return this.conn;\n }\n\n /**\n * Idempotent migration. Runs all DDL through `IF NOT EXISTS` guards and tolerates the\n * vector-index \"already exists\" error from re-runs.\n */\n async migrate(): Promise<void> {\n await this.connect();\n const schemaStmts = buildSchemaStatements({ embeddingDimension: this.embeddingDimension });\n for (const stmt of schemaStmts) {\n await this.exec(stmt);\n }\n for (const stmt of buildVectorIndexStatements()) {\n try {\n await this.exec(stmt);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n if (isAlreadyExistsError(message)) continue;\n // Vector extension not available is a soft failure - we still get all the other\n // functionality, just no semantic search. Warn and continue.\n if (/extension/i.test(message) && /(not found|missing|unsupported|disabled)/i.test(message)) {\n // eslint-disable-next-line no-console\n console.warn(\n `[codegraph] vector extension unavailable; semantic search disabled. Underlying: ${message}`,\n );\n return;\n }\n throw new Error(`migrate failed on \\`${stmt}\\`: ${message}`);\n }\n }\n this.vectorIndexReady = true;\n }\n\n /**\n * Typed Cypher escape hatch.\n *\n * Kuzu returns BIGINT columns as native BigInt; we coerce to plain `number` when safe so\n * downstream JSON serialization (MCP responses, snapshot tests) does not need bespoke\n * handling.\n */\n async query<T = Record<string, unknown>>(\n cypher: string,\n params: Record<string, unknown> = {},\n ): Promise<QueryResult<T>> {\n const result = await this.runQuery(cypher, params);\n const raw = await collectAll(result);\n const data = raw.map((row) => normalizeRow(row)) as T[];\n const headers = raw.length > 0 ? Object.keys(raw[0] ?? {}) : [];\n return { data, headers, metadata: [] };\n }\n\n /** Fire-and-forget DDL/exec. */\n private async exec(cypher: string, params: Record<string, unknown> = {}): Promise<void> {\n await this.runQuery(cypher, params);\n }\n\n /**\n * Bridge to Kuzu's two execution paths:\n * - `conn.query(stmt)` for unparameterized statements (the second positional arg is a\n * `progressCallback`, NOT params - mistaking that is the #1 way to confuse the API).\n * - `conn.prepare(stmt) + conn.execute(prepared, params)` for anything with `$name`\n * placeholders. We cache the prepared statement so UNWIND batches reuse it.\n */\n private async runQuery(cypher: string, params: Record<string, unknown>): Promise<unknown> {\n const conn = this.requireConn();\n if (Object.keys(params).length === 0) {\n return conn.query(cypher);\n }\n let prepared = this.preparedCache.get(cypher);\n if (!prepared) {\n prepared = await conn.prepare(cypher);\n if (!prepared.isSuccess()) {\n throw new Error(prepared.getErrorMessage());\n }\n this.preparedCache.set(cypher, prepared);\n }\n // Cast through `unknown`: Kuzu's bindings advertise a strict `KuzuValue` union, but\n // we can pass through any JSON-serializable value the embedded engine accepts (nested\n // structs and lists are converted at the native layer).\n return conn.execute(prepared, params as unknown as Parameters<kuzu.Connection[\"execute\"]>[1]);\n }\n\n /**\n * Upserts nodes via batched UNWIND + MERGE. Kuzu requires every column we SET to exist\n * in the schema, so each row is normalized to include every `SYMBOL_COLUMNS` field (NULL\n * for fields not present).\n */\n async upsertNodes(nodes: UpsertNodeInput[]): Promise<void> {\n if (nodes.length === 0) return;\n await this.connect();\n const BATCH = 200;\n const setClause = SYMBOL_COLUMNS.filter((c) => c !== \"id\")\n .map((c) => `n.${c} = r.${c}`)\n .join(\", \");\n const cypher = `UNWIND $batch AS r MERGE (n:Symbol {id: r.id}) SET ${setClause}`;\n for (let i = 0; i < nodes.length; i += BATCH) {\n const slice = nodes.slice(i, i + BATCH);\n const payload = slice.map(buildSymbolRow);\n await this.exec(cypher, { batch: payload });\n }\n }\n\n /**\n * Upserts edges. Both endpoints must already exist as `Symbol` nodes; rows where the\n * MATCH fails are silently dropped, matching Cypher semantics.\n *\n * Uses CREATE because the orchestrator wipes the repo's slice before writing, so\n * duplicates can't pre-exist within a single index pass.\n */\n async upsertEdges(edges: UpsertEdgeInput[]): Promise<void> {\n if (edges.length === 0) return;\n await this.connect();\n const byKind = new Map<EdgeKind, UpsertEdgeInput[]>();\n for (const e of edges) {\n const bucket = byKind.get(e.kind);\n if (bucket) bucket.push(e);\n else byKind.set(e.kind, [e]);\n }\n const BATCH = 500;\n for (const [kind, batch] of byKind) {\n const cypher = `UNWIND $batch AS r MATCH (a:Symbol {id: r.fromId}) MATCH (b:Symbol {id: r.toId}) CREATE (a)-[e:${kind} {line: r.line}]->(b)`;\n for (let i = 0; i < batch.length; i += BATCH) {\n const slice = batch.slice(i, i + BATCH);\n // Use 0 (not null) for missing line numbers so Kuzu can infer the struct field\n // as INT64 even when an entire batch happens to have no `line` set.\n const payload = slice.map((e) => ({\n fromId: e.fromId,\n toId: e.toId,\n line: typeof e.line === \"number\" ? e.line : 0,\n }));\n await this.exec(cypher, { batch: payload });\n }\n }\n }\n\n /**\n * Deletes all nodes (and incident edges via DETACH DELETE) for a repo. If `paths` is\n * provided, restricts the delete to nodes whose `path` is in the list - used by\n * incremental re-indexing.\n */\n async deleteByRepo(repoId: string, paths?: string[]): Promise<void> {\n await this.connect();\n if (paths && paths.length > 0) {\n await this.exec(\n \"MATCH (n:Symbol) WHERE n.repoId = $repoId AND n.path IN $paths DETACH DELETE n\",\n { repoId, paths },\n );\n return;\n }\n await this.exec(\"MATCH (n:Symbol) WHERE n.repoId = $repoId DETACH DELETE n\", { repoId });\n }\n\n /**\n * Returns counts of nodes (per kind) and edges (per kind) for a repo, plus the share of\n * non-File nodes that carry an embedding.\n */\n async stats(repoId: string): Promise<{\n nodes: Record<string, number>;\n edges: Record<string, number>;\n embeddingCoverage: number;\n }> {\n await this.connect();\n const nodes: Record<string, number> = {};\n for (const kind of NODE_KINDS) {\n const r = await this.query<{ count: number }>(\n \"MATCH (n:Symbol) WHERE n.repoId = $repoId AND n.kind = $kind RETURN count(n) AS count\",\n { repoId, kind },\n );\n nodes[kind] = Number(r.data[0]?.count ?? 0);\n }\n const edges: Record<string, number> = {};\n for (const kind of EDGE_KINDS) {\n const r = await this.query<{ count: number }>(\n `MATCH (a:Symbol)-[r:${kind}]->(b:Symbol)\n WHERE a.repoId = $repoId AND b.repoId = $repoId\n RETURN count(r) AS count`,\n { repoId },\n );\n edges[kind] = Number(r.data[0]?.count ?? 0);\n }\n const cov = await this.query<{ total: number | bigint; embedded: number | bigint }>(\n `MATCH (n:Symbol)\n WHERE n.repoId = $repoId AND n.kind <> 'File'\n RETURN count(n) AS total,\n count(n.embedding) AS embedded`,\n { repoId },\n );\n const row = cov.data[0];\n const total = Number(row?.total ?? 0);\n const embedded = Number(row?.embedded ?? 0);\n const coverage = total === 0 ? 0 : embedded / total;\n return { nodes, edges, embeddingCoverage: coverage };\n }\n\n /** True once `migrate()` confirmed the vector extension is loaded. */\n hasVectorIndex(): boolean {\n return this.vectorIndexReady;\n }\n}\n\n/**\n * Build a fully-populated row for a Kuzu UNWIND batch. Every column in `SYMBOL_COLUMNS`\n * is present (NULL when missing) so Kuzu can infer a homogeneous struct schema for the\n * batch parameter.\n */\nfunction buildSymbolRow(node: UpsertNodeInput): Record<string, unknown> {\n const src = node as unknown as Record<string, unknown>;\n const row: Record<string, unknown> = {};\n for (const col of SYMBOL_COLUMNS) {\n const value = src[col];\n // Use typed defaults instead of null so Kuzu's struct-param type inference can\n // resolve each column to its declared type even when an entire batch happens to be\n // missing a given optional field.\n row[col] = value === undefined || value === null ? defaultFor(col) : value;\n }\n row.id = node.id;\n row.kind = node.kind;\n return row;\n}\n\n/** Convert Kuzu's row representation (Map or plain object) into a plain JSON object. */\nfunction normalizeRow(row: unknown): Record<string, unknown> {\n if (row instanceof Map) {\n const out: Record<string, unknown> = {};\n for (const [k, v] of row) {\n out[String(k)] = coerceValue(v);\n }\n return out;\n }\n if (row && typeof row === \"object\") {\n const src = row as Record<string, unknown>;\n const out: Record<string, unknown> = {};\n for (const k of Object.keys(src)) {\n out[k] = coerceValue(src[k]);\n }\n return out;\n }\n return { value: coerceValue(row) };\n}\n\n/**\n * Kuzu returns BIGINT columns as JS BigInt. Coerce to `number` when within Number.MAX_SAFE\n * for JSON-friendly downstream consumption.\n */\nfunction coerceValue(value: unknown): unknown {\n if (typeof value === \"bigint\") {\n if (value <= BigInt(Number.MAX_SAFE_INTEGER) && value >= BigInt(Number.MIN_SAFE_INTEGER)) {\n return Number(value);\n }\n return value.toString();\n }\n if (Array.isArray(value)) return value.map(coerceValue);\n return value;\n}\n\n/** Drain a Kuzu QueryResult (or array of them) into an array of row objects. */\nasync function collectAll(result: unknown): Promise<unknown[]> {\n // Multi-statement queries return an array; we keep only the last one (matches how the\n // final statement is the one that carries a `RETURN`).\n const target = Array.isArray(result) ? result[result.length - 1] : result;\n if (!target) return [];\n const getAll = (target as { getAll?: () => Promise<unknown[]> }).getAll;\n if (typeof getAll !== \"function\") return [];\n return getAll.call(target);\n}\n\nfunction isAlreadyExistsError(message: string): boolean {\n return (\n /already exists/i.test(message) ||\n /already loaded/i.test(message) ||\n /already installed/i.test(message) ||\n /duplicate (table|index)/i.test(message)\n );\n}\n","import { EDGE_KINDS } from \"@codegraph/shared\";\n\n/**\n * Kuzu is schema-first. Unlike FalkorDB which is schema-less, every column we ever want to\n * SET on a node must exist up-front. We use ONE `Symbol` node table with a `kind` column\n * (Kuzu does not support multi-labels), and one REL table per `EdgeKind`.\n *\n * Columns are the union of every field across the `GraphNode` discriminated union in\n * `@codegraph/shared` plus the two embedding-namespace fields. Fields that are not\n * relevant to a given kind stay NULL.\n */\n\n/**\n * Per-column metadata so the upserter can build batches with explicit typed defaults.\n *\n * Kuzu's struct parameter type inference fails when a column is null on every row in a\n * batch (it defaults to STRING and rejects assignment to a BOOL/INT64 column). Concrete\n * defaults keep inference deterministic and let us skip clunky CAST() clauses.\n *\n * Convention: optional booleans default to `false`, optional ints to `0`, optional strings\n * to `\"\"`. We never check `WHERE n.foo IS NULL` in queries, so the lost null-distinction\n * is acceptable for v0.1.0.\n */\nexport const SYMBOL_COLUMN_SPEC = {\n id: \"STRING\",\n kind: \"STRING\",\n repoId: \"STRING\",\n name: \"STRING\",\n path: \"STRING\",\n lineStart: \"INT64\",\n lineEnd: \"INT64\",\n signature: \"STRING\",\n leadingComment: \"STRING\",\n isExported: \"BOOLEAN\",\n // File-specific\n language: \"STRING\",\n sizeBytes: \"INT64\",\n contentHash: \"STRING\",\n // Function-specific\n isAsync: \"BOOLEAN\",\n isArrow: \"BOOLEAN\",\n // Route-specific\n method: \"STRING\",\n routePath: \"STRING\",\n framework: \"STRING\",\n // Embedding namespace tag\n embeddingNamespace: \"STRING\",\n} as const;\n\nexport type SymbolColumn = keyof typeof SYMBOL_COLUMN_SPEC;\n\nexport const SYMBOL_COLUMNS = Object.keys(SYMBOL_COLUMN_SPEC) as SymbolColumn[];\n\n/** Return the typed default for an unset optional column. */\nexport function defaultFor(column: SymbolColumn): unknown {\n const t = SYMBOL_COLUMN_SPEC[column];\n if (t === \"BOOLEAN\") return false;\n if (t === \"INT64\") return 0;\n return \"\";\n}\n\n/** Optional per-edge metadata. Currently only `line`. */\nexport const EDGE_COLUMNS = [\"line\"] as const;\n\nexport type EdgeColumn = (typeof EDGE_COLUMNS)[number];\n\n/**\n * DDL statements that bring an empty Kuzu database to the codegraph schema.\n * `IF NOT EXISTS` makes `migrate()` idempotent so it can run on every connect.\n *\n * `embedding` is a fixed-dimension column - dimension is configured at migrate time and\n * baked into the schema. If a user later switches to an embedding provider with a\n * different dimension they must delete the on-disk graph directory to recreate it. The\n * embedding-namespace tag ensures we never silently mix dimensions.\n */\nexport function buildSchemaStatements(opts: { embeddingDimension: number }): string[] {\n const columnDefs = [\n \"id STRING\",\n \"kind STRING\",\n \"repoId STRING\",\n \"name STRING\",\n \"path STRING\",\n \"lineStart INT64\",\n \"lineEnd INT64\",\n \"signature STRING\",\n \"leadingComment STRING\",\n \"isExported BOOLEAN\",\n \"language STRING\",\n \"sizeBytes INT64\",\n \"contentHash STRING\",\n \"isAsync BOOLEAN\",\n \"isArrow BOOLEAN\",\n \"method STRING\",\n \"routePath STRING\",\n \"framework STRING\",\n \"embeddingNamespace STRING\",\n `embedding FLOAT[${opts.embeddingDimension}]`,\n \"PRIMARY KEY (id)\",\n ];\n const statements: string[] = [\n `CREATE NODE TABLE IF NOT EXISTS Symbol(${columnDefs.join(\", \")})`,\n ];\n for (const kind of EDGE_KINDS) {\n statements.push(\n `CREATE REL TABLE IF NOT EXISTS ${kind}(FROM Symbol TO Symbol, line INT64)`,\n );\n }\n return statements;\n}\n\n/**\n * The vector extension is bundled but not auto-loaded. We install + load on every connect\n * (both no-op if already done) and create the HNSW index if it does not already exist.\n *\n * Kuzu's `CALL CREATE_VECTOR_INDEX` errors out with a stable \"already exists\" message\n * when re-run, so the client's `migrate()` swallows that specific error.\n */\nexport function buildVectorIndexStatements(): string[] {\n return [\n \"INSTALL VECTOR\",\n \"LOAD EXTENSION VECTOR\",\n \"CALL CREATE_VECTOR_INDEX('Symbol', 'embedding_idx', 'embedding', metric := 'cosine')\",\n ];\n}\n\n/** Default embedding dimension when none is supplied. Matches `text-embedding-3-small`. */\nexport const DEFAULT_EMBEDDING_DIMENSION = 1536;\n"],"mappings":"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","names":[]}
|
|
File without changes
|