diff --git a/THIRD_PARTY.md b/THIRD_PARTY.md index b35e4ae2f..593cb740a 100644 --- a/THIRD_PARTY.md +++ b/THIRD_PARTY.md @@ -15,7 +15,7 @@ The tree-sitter C runtime is vendored in `internal/cbm/vendored/ts_runtime/`. Pre-generated parser sources are vendored in `internal/cbm/vendored/grammars//`. Each grammar is the work of its upstream authors; we vendor only the generated -`parser.c` (and `scanner.c` where applicable) for CGo compilation. +`parser.c` (and `scanner.c` where applicable) for static compilation. | Grammar | Upstream Repository | License | Copyright | |---------|-------------------|---------|-----------| @@ -84,16 +84,18 @@ Each grammar is the work of its upstream authors; we vendor only the generated | yaml | [tree-sitter/tree-sitter-yaml](https://github.com/tree-sitter/tree-sitter-yaml) | MIT | (c) Max Brunsfeld | | zig | [tree-sitter/tree-sitter-zig](https://github.com/tree-sitter/tree-sitter-zig) | MIT | (c) Max Brunsfeld | -## Go Module Dependencies +## Vendored C Libraries -| Module | License | Project | -|--------|---------|---------| -| github.com/mattn/go-sqlite3 | MIT | [mattn/go-sqlite3](https://github.com/mattn/go-sqlite3) | -| github.com/modelcontextprotocol/go-sdk | MIT | [modelcontextprotocol/go-sdk](https://github.com/modelcontextprotocol/go-sdk) | -| github.com/zeebo/xxh3 | BSD-2-Clause | [zeebo/xxh3](https://github.com/zeebo/xxh3) | -| golang.org/x/sync | BSD-3-Clause | [golang.org/x/sync](https://pkg.go.dev/golang.org/x/sync) | -| golang.org/x/sys | BSD-3-Clause | [golang.org/x/sys](https://pkg.go.dev/golang.org/x/sys) | -| gopkg.in/yaml.v3 | MIT + Apache-2.0 | [go-yaml/yaml](https://github.com/go-yaml/yaml) | +All C dependencies are vendored in `vendored/` — zero system library dependencies required. + +| Library | License | Project | +|---------|---------|---------| +| SQLite 3 | Public Domain | [sqlite.org](https://www.sqlite.org/) | +| mimalloc | MIT | [microsoft/mimalloc](https://github.com/microsoft/mimalloc) | +| Mongoose | Dual GPLv2 / Commercial | [cesanta/mongoose](https://github.com/cesanta/mongoose) | +| yyjson | MIT | [ibireme/yyjson](https://github.com/ibireme/yyjson) | +| xxHash | BSD-2-Clause | [Cyan4973/xxHash](https://github.com/Cyan4973/xxHash) | +| TRE | BSD-2-Clause | [laurikari/tre](https://github.com/laurikari/tre) | ## Notes diff --git a/cmd/codebase-memory-mcp/assets/codex-instructions.md b/cmd/codebase-memory-mcp/assets/codex-instructions.md deleted file mode 100644 index 1cc83bee8..000000000 --- a/cmd/codebase-memory-mcp/assets/codex-instructions.md +++ /dev/null @@ -1,34 +0,0 @@ -# Codebase Knowledge Graph - -This project has a code knowledge graph available via MCP tools. Use it for -structural questions instead of grep — one graph query returns what would take -dozens of file-by-file searches. - -## Finding Code - -- "Who calls X?" → use `trace_call_path` with `direction=inbound` -- "What does X call?" → use `trace_call_path` with `direction=outbound` -- "Find functions matching pattern" → use `search_graph` with `name_pattern` -- "Find all routes" → use `search_graph` with `label=Route` -- "Show codebase structure" → use `get_graph_schema` for overview - -## Tracing Dependencies - -- Always discover exact names first: `search_graph(name_pattern=".*Partial.*")` -- Then trace: `trace_call_path(function_name="ExactName", direction="both")` -- Cross-service HTTP calls: `query_graph("MATCH (a)-[r:HTTP_CALLS]->(b) RETURN a.name, b.name, r.url_path")` -- Read source: `get_code_snippet(qualified_name="project.path.FunctionName")` - -## Quality Analysis - -- Dead code: `search_graph` with `max_degree=0`, `exclude_entry_points=true`, `relationship=CALLS`, `direction=inbound` -- High fan-out: `search_graph` with `min_degree=10`, `relationship=CALLS`, `direction=outbound` -- Change coupling: `query_graph("MATCH (a)-[r:FILE_CHANGES_WITH]->(b) WHERE r.coupling_score >= 0.5 RETURN ...")` - -## Important - -- Always check `list_projects` first — run `index_repository` if the project is missing -- Use `search_graph` to discover exact names before `trace_call_path` (it requires exact match) -- The graph doesn't index text content — use grep for string literals, error messages, config values -- Results default to 10 per page — check `has_more` and use `offset` to paginate -- Use `project` parameter when multiple repos are indexed diff --git a/cmd/codebase-memory-mcp/assets/skills/codebase-memory-exploring/SKILL.md b/cmd/codebase-memory-mcp/assets/skills/codebase-memory-exploring/SKILL.md deleted file mode 100644 index cc45a8be0..000000000 --- a/cmd/codebase-memory-mcp/assets/skills/codebase-memory-exploring/SKILL.md +++ /dev/null @@ -1,90 +0,0 @@ ---- -name: codebase-memory-exploring -description: > - This skill should be used when the user asks to "explore the codebase", - "understand the architecture", "what functions exist", "show me the structure", - "how is the code organized", "find functions matching", "search for classes", - "list all routes", "show API endpoints", or needs codebase orientation. ---- - -# Codebase Exploration via Knowledge Graph - -Use graph tools for structural code questions. They return precise results in ~500 tokens vs ~80K for grep-based exploration. - -## Workflow - -### Step 1: Check if project is indexed - -``` -list_projects -``` - -If the project is missing from the list: - -``` -index_repository(repo_path="/path/to/project") -``` - -If already indexed, skip — auto-sync keeps the graph fresh. - -### Step 2: Get a structural overview - -``` -get_graph_schema -``` - -This returns node label counts (functions, classes, routes, etc.), edge type counts, and relationship patterns. Use it to understand what's in the graph before querying. - -### Step 3: Find specific code elements - -Find functions by name pattern: -``` -search_graph(label="Function", name_pattern=".*Handler.*") -``` - -Find classes: -``` -search_graph(label="Class", name_pattern=".*Service.*") -``` - -Find all REST routes: -``` -search_graph(label="Route") -``` - -Find modules/packages: -``` -search_graph(label="Module") -``` - -Scope to a specific directory: -``` -search_graph(label="Function", qn_pattern=".*services\\.order\\..*") -``` - -### Step 4: Read source code - -After finding a function via search, read its source: -``` -get_code_snippet(qualified_name="project.path.to.FunctionName") -``` - -### Step 5: Understand structure - -For file/directory exploration within the indexed project: -``` -list_directory(path="src/services") -``` - -## When to Use Grep Instead - -- Searching for **string literals** or error messages → `search_code` or Grep -- Finding a file by exact name → Glob -- The graph doesn't index text content, only structural elements - -## Key Tips - -- Results default to 10 per page. Check `has_more` and use `offset` to paginate. -- Use `project` parameter when multiple repos are indexed. -- Route nodes have a `properties.handler` field with the actual handler function name. -- `exclude_labels` removes noise (e.g., `exclude_labels=["Route"]` when searching by name pattern). diff --git a/cmd/codebase-memory-mcp/assets/skills/codebase-memory-quality/SKILL.md b/cmd/codebase-memory-mcp/assets/skills/codebase-memory-quality/SKILL.md deleted file mode 100644 index 1542eee26..000000000 --- a/cmd/codebase-memory-mcp/assets/skills/codebase-memory-quality/SKILL.md +++ /dev/null @@ -1,101 +0,0 @@ ---- -name: codebase-memory-quality -description: > - This skill should be used when the user asks about "dead code", - "find dead code", "detect dead code", "show dead code", "dead code analysis", - "unused functions", "find unused functions", "unreachable code", - "identify high fan-out functions", "find complex functions", - "code quality audit", "find functions nobody calls", - "reduce codebase size", "refactor candidates", "cleanup candidates", - or needs code quality analysis. ---- - -# Code Quality Analysis via Knowledge Graph - -Use graph degree filtering to find dead code, high-complexity functions, and refactor candidates — all in single tool calls. - -## Workflow - -### Dead Code Detection - -Find functions with zero inbound CALLS edges, excluding entry points: - -``` -search_graph( - label="Function", - relationship="CALLS", - direction="inbound", - max_degree=0, - exclude_entry_points=true -) -``` - -`exclude_entry_points=true` removes route handlers, `main()`, and framework-registered functions that have zero callers by design. - -### Verify Dead Code Candidates - -Before deleting, verify each candidate truly has no callers: - -``` -trace_call_path(function_name="SuspectFunction", direction="inbound", depth=1) -``` - -Also check for read references (callbacks, stored in variables): - -``` -query_graph(query="MATCH (a)-[r:USAGE]->(b) WHERE b.name = 'SuspectFunction' RETURN a.name, a.file_path LIMIT 10") -``` - -### High Fan-Out Functions (calling 10+ others) - -These are often doing too much and are refactor candidates: - -``` -search_graph( - label="Function", - relationship="CALLS", - direction="outbound", - min_degree=10 -) -``` - -### High Fan-In Functions (called by 10+ others) - -These are critical functions — changes have wide impact: - -``` -search_graph( - label="Function", - relationship="CALLS", - direction="inbound", - min_degree=10 -) -``` - -### Files That Change Together (Hidden Coupling) - -Find files with high git change coupling: - -``` -query_graph(query="MATCH (a)-[r:FILE_CHANGES_WITH]->(b) WHERE r.coupling_score >= 0.5 RETURN a.name, b.name, r.coupling_score, r.co_change_count ORDER BY r.coupling_score DESC LIMIT 20") -``` - -High coupling between unrelated files suggests hidden dependencies. - -### Unused Imports - -``` -search_graph( - relationship="IMPORTS", - direction="outbound", - max_degree=0, - label="Module" -) -``` - -## Key Tips - -- `search_graph` with degree filters has no row cap (unlike `query_graph` which caps at 200). -- Use `file_pattern` to scope analysis to specific directories: `file_pattern="**/services/**"`. -- Dead code detection works best after a full index — run `index_repository` if the project was recently set up. -- Paginate results with `limit` and `offset` — check `has_more` in the response. diff --git a/cmd/codebase-memory-mcp/assets/skills/codebase-memory-reference/SKILL.md b/cmd/codebase-memory-mcp/assets/skills/codebase-memory-reference/SKILL.md deleted file mode 100644 index 97dbfd621..000000000 --- a/cmd/codebase-memory-mcp/assets/skills/codebase-memory-reference/SKILL.md +++ /dev/null @@ -1,154 +0,0 @@ ---- -name: codebase-memory-reference -description: > - This skill should be used when the user asks about "codebase-memory-mcp tools", - "graph query syntax", "Cypher query examples", "edge types", - "how to use search_graph", "query_graph examples", or needs reference - documentation for the codebase knowledge graph tools. ---- - -# Codebase Memory MCP — Tool Reference - -## Tools (14 total) - -| Tool | Purpose | -|------|---------| -| `index_repository` | Parse and ingest repo into graph (only once — auto-sync keeps it fresh) | -| `index_status` | Check indexing status (ready/indexing/not found) | -| `list_projects` | List all indexed projects with timestamps and counts | -| `delete_project` | Remove a project from the graph | -| `search_graph` | Structured search with filters (name, label, degree, file pattern) | -| `search_code` | Grep-like text search within indexed project files | -| `trace_call_path` | BFS call chain traversal (exact name match required). Supports `risk_labels=true` for impact classification. | -| `detect_changes` | Map git diff to affected symbols + blast radius with risk scoring | -| `query_graph` | Cypher-like graph queries (200-row cap) | -| `get_graph_schema` | Node/edge counts, relationship patterns | -| `get_code_snippet` | Read source code by qualified name | -| `read_file` | Read any file from indexed project | -| `list_directory` | List files/directories with glob filter | -| `ingest_traces` | Ingest OpenTelemetry traces to validate HTTP_CALLS edges | - -## Edge Types - -| Type | Meaning | -|------|---------| -| `CALLS` | Direct function call within same service | -| `HTTP_CALLS` | Synchronous cross-service HTTP request | -| `ASYNC_CALLS` | Async dispatch (Cloud Tasks, Pub/Sub, SQS, Kafka) | -| `IMPORTS` | Module/package import | -| `DEFINES` / `DEFINES_METHOD` | Module/class defines a function/method | -| `HANDLES` | Route node handled by a function | -| `IMPLEMENTS` | Type implements an interface | -| `OVERRIDE` | Struct method overrides an interface method | -| `USAGE` | Read reference (callback, variable assignment) | -| `FILE_CHANGES_WITH` | Git history change coupling | -| `CONTAINS_FILE` / `CONTAINS_FOLDER` / `CONTAINS_PACKAGE` | Structural containment | - -## Node Labels - -`Project`, `Package`, `Folder`, `File`, `Module`, `Class`, `Function`, `Method`, `Interface`, `Enum`, `Type`, `Route` - -## Qualified Name Format - -`..` — file path with `/` replaced by `.`, extension removed. - -Examples: -- `myproject.cmd.server.main.HandleRequest` (Go) -- `myproject.services.orders.ProcessOrder` (Python) -- `myproject.src.components.App.App` (TypeScript) - -Use `search_graph` to discover qualified names, then pass them to `get_code_snippet`. - -## Cypher Subset (for query_graph) - -**Supported:** -- `MATCH` with node labels and relationship types -- Variable-length paths: `-[:CALLS*1..3]->` -- `WHERE` with `=`, `<>`, `>`, `<`, `>=`, `<=`, `=~` (regex), `CONTAINS`, `STARTS WITH` -- `WHERE` with `AND`, `OR`, `NOT` -- `RETURN` with property access, `COUNT(x)`, `DISTINCT` -- `ORDER BY` with `ASC`/`DESC` -- `LIMIT` -- Edge property access: `r.confidence`, `r.url_path`, `r.coupling_score` - -**Not supported:** `WITH`, `COLLECT`, `SUM`, `CREATE/DELETE/SET`, `OPTIONAL MATCH`, `UNION` - -## Common Cypher Patterns - -``` -# Cross-service HTTP calls with confidence -MATCH (a)-[r:HTTP_CALLS]->(b) RETURN a.name, b.name, r.url_path, r.confidence LIMIT 20 - -# Filter by URL path -MATCH (a)-[r:HTTP_CALLS]->(b) WHERE r.url_path CONTAINS '/orders' RETURN a.name, b.name - -# Interface implementations -MATCH (s)-[r:OVERRIDE]->(i) RETURN s.name, i.name LIMIT 20 - -# Change coupling -MATCH (a)-[r:FILE_CHANGES_WITH]->(b) WHERE r.coupling_score >= 0.5 RETURN a.name, b.name, r.coupling_score - -# Functions calling a specific function -MATCH (f:Function)-[:CALLS]->(g:Function) WHERE g.name = 'ProcessOrder' RETURN f.name LIMIT 20 -``` - -## Regex-Powered Search (No Full-Text Index Needed) - -`search_graph` and `search_code` support full Go regex, making full-text search indexes unnecessary. Regex patterns provide precise, composable queries that cover all common discovery scenarios: - -### search_graph — name_pattern / qn_pattern - -| Pattern | Matches | Use case | -|---------|---------|----------| -| `.*Handler$` | names ending in Handler | Find all handlers | -| `(?i)auth` | case-insensitive "auth" | Find auth-related symbols | -| `get\|fetch\|load` | any of three words | Find data-loading functions | -| `^on[A-Z]` | names starting with on + uppercase | Find event handlers | -| `.*Service.*Impl` | Service...Impl pattern | Find service implementations | -| `^(Get\|Set\|Delete)` | CRUD prefixes | Find CRUD operations | -| `.*_test$` | names ending in _test | Find test functions | -| `.*\\.controllers\\..*` | qn_pattern for directory scoping | Scope to controllers dir | - -### search_code — regex=true - -| Pattern | Matches | Use case | -|---------|---------|----------| -| `TODO\|FIXME\|HACK` | multi-pattern scan | Find tech debt markers | -| `(?i)password\|secret\|token` | case-insensitive secrets | Security scan | -| `func\\s+Test` | Go test functions | Find test entry points | -| `api[._/]v[0-9]` | API version references | Find versioned API usage | -| `import.*from ['"]@` | scoped npm imports | Find package imports | - -### Combining Filters for Surgical Queries - -``` -# Find unused auth handlers -search_graph(name_pattern="(?i).*auth.*handler.*", max_degree=0, exclude_entry_points=true) - -# Find high fan-out functions in the services directory -search_graph(qn_pattern=".*\\.services\\..*", min_degree=10, relationship="CALLS", direction="outbound") - -# Find all route handlers matching a URL pattern -search_code(pattern="(?i)(POST|PUT).*\\/api\\/v[0-9]\\/orders", regex=true) -``` - -## Critical Pitfalls - -1. **`search_graph(relationship="HTTP_CALLS")` does NOT return edges** — it filters nodes by degree. Use `query_graph` with Cypher to see actual edges. -2. **`query_graph` has a 200-row cap** before aggregation — COUNT queries silently undercount on large codebases. Use `search_graph` with `min_degree`/`max_degree` for counting. -3. **`trace_call_path` needs exact names** — use `search_graph(name_pattern=".*Partial.*")` first to discover names. -4. **`direction="outbound"` misses cross-service callers** — use `direction="both"` for full context. - -## Decision Matrix - -| Question | Use | -|----------|-----| -| Who calls X? | `trace_call_path(direction="inbound")` | -| What does X call? | `trace_call_path(direction="outbound")` | -| Full call context | `trace_call_path(direction="both")` | -| Find by name pattern | `search_graph(name_pattern="...")` | -| Dead code | `search_graph(max_degree=0, exclude_entry_points=true)` | -| Cross-service edges | `query_graph` with Cypher | -| Impact of local changes | `detect_changes()` | -| Risk-classified trace | `trace_call_path(risk_labels=true)` | -| Text search | `search_code` or Grep | diff --git a/cmd/codebase-memory-mcp/assets/skills/codebase-memory-tracing/SKILL.md b/cmd/codebase-memory-mcp/assets/skills/codebase-memory-tracing/SKILL.md deleted file mode 100644 index bc14abe72..000000000 --- a/cmd/codebase-memory-mcp/assets/skills/codebase-memory-tracing/SKILL.md +++ /dev/null @@ -1,125 +0,0 @@ ---- -name: codebase-memory-tracing -description: > - This skill should be used when the user asks "who calls this function", - "what does X call", "trace the call chain", "find callers of", - "show dependencies", "what depends on", "trace call path", - "find all references to", "impact analysis", or needs to understand - function call relationships and dependency chains. ---- - -# Call Chain Tracing via Knowledge Graph - -Use graph tools to trace function call relationships. One `trace_call_path` call replaces dozens of grep searches across files. - -## Workflow - -### Step 1: Discover the exact function name - -`trace_call_path` requires an **exact** name match. If you don't know the exact name, discover it first with regex: - -``` -search_graph(name_pattern=".*Order.*", label="Function") -``` - -Use full regex for precise discovery — no full-text search needed: -- `(?i)order` — case-insensitive -- `^(Get|Set|Delete)Order` — CRUD variants -- `.*Order.*Handler$` — handlers only -- `qn_pattern=".*services\\.order\\..*"` — scope to order service directory - -This returns matching functions with their qualified names and file locations. - -### Step 2: Trace callers (who calls this function?) - -``` -trace_call_path(function_name="ProcessOrder", direction="inbound", depth=3) -``` - -Returns a hop-by-hop list of all functions that call `ProcessOrder`, up to 3 levels deep. - -### Step 3: Trace callees (what does this function call?) - -``` -trace_call_path(function_name="ProcessOrder", direction="outbound", depth=3) -``` - -### Step 4: Full context (both callers and callees) - -``` -trace_call_path(function_name="ProcessOrder", direction="both", depth=3) -``` - -**Always use `direction="both"` for complete context.** Cross-service HTTP_CALLS edges from other services appear as inbound edges — `direction="outbound"` alone misses them. - -### Step 5: Read suspicious code - -After finding interesting callers/callees, read their source: - -``` -get_code_snippet(qualified_name="project.path.module.FunctionName") -``` - -## Cross-Service HTTP Calls - -To see all HTTP links between services with URLs and confidence scores: - -``` -query_graph(query="MATCH (a)-[r:HTTP_CALLS]->(b) RETURN a.name, b.name, r.url_path, r.confidence ORDER BY r.confidence DESC LIMIT 20") -``` - -Filter by URL path: -``` -query_graph(query="MATCH (a)-[r:HTTP_CALLS]->(b) WHERE r.url_path CONTAINS '/orders' RETURN a.name, b.name, r.url_path") -``` - -## Async Dispatch (Cloud Tasks, Pub/Sub, etc.) - -Find dispatch functions by name pattern, then trace: -``` -search_graph(name_pattern=".*CreateTask.*|.*send_to_pubsub.*") -trace_call_path(function_name="CreateMultidataTask", direction="both") -``` - -## Interface Implementations - -Find which structs implement an interface method: -``` -query_graph(query="MATCH (s)-[r:OVERRIDE]->(i) WHERE i.name = 'Read' RETURN s.name, i.name LIMIT 20") -``` - -## Read References (callbacks, variable assignments) - -``` -query_graph(query="MATCH (a)-[r:USAGE]->(b) WHERE b.name = 'ProcessOrder' RETURN a.name, a.file_path LIMIT 20") -``` - -## Risk-Classified Impact Analysis - -Add `risk_labels=true` to get risk classification on each node: - -``` -trace_call_path(function_name="ProcessOrder", direction="inbound", depth=3, risk_labels=true) -``` - -Returns nodes with `risk` (CRITICAL/HIGH/MEDIUM/LOW) based on hop depth, plus an `impact_summary` with counts. Risk mapping: hop 1=CRITICAL, 2=HIGH, 3=MEDIUM, 4+=LOW. - -## Detect Changes (Git Diff Impact) - -Map uncommitted changes to affected symbols and their blast radius: - -``` -detect_changes() -detect_changes(scope="staged") -detect_changes(scope="branch", base_branch="main") -``` - -Returns changed files, changed symbols, and impacted callers with risk classification. Scopes: `unstaged`, `staged`, `all` (default), `branch`. - -## Key Tips - -- Start with `depth=1` for quick answers, increase only if needed (max 5). -- Edge types in trace results: `CALLS` (direct), `HTTP_CALLS` (cross-service), `ASYNC_CALLS` (async dispatch), `USAGE` (read reference), `OVERRIDE` (interface implementation). -- `search_graph(relationship="HTTP_CALLS")` filters nodes by degree — it does NOT return edges. Use `query_graph` with Cypher to see actual edges with properties. -- Results are capped at 200 nodes per trace. -- `detect_changes` requires git in PATH. diff --git a/BENCHMARK.md b/docs/BENCHMARK.md similarity index 100% rename from BENCHMARK.md rename to docs/BENCHMARK.md diff --git a/scripts/setup-windows.ps1 b/scripts/setup-windows.ps1 index b8daaf0cf..592a9cd49 100644 --- a/scripts/setup-windows.ps1 +++ b/scripts/setup-windows.ps1 @@ -213,7 +213,7 @@ if ($FromSource) { Write-Host "" Write-Host "Building binary (this may take a minute)..." -ForegroundColor White $wslBinaryPath = "/home/$wslUser/.local/bin/$BinaryName" - Invoke-WSL "mkdir -p /home/$wslUser/.local/bin && cd $sourceDir && CGO_ENABLED=1 go build -buildvcs=false -o $wslBinaryPath ./cmd/codebase-memory-mcp/" + Invoke-WSL "mkdir -p /home/$wslUser/.local/bin && cd $sourceDir && scripts/build.sh && cp build/c/codebase-memory-mcp $wslBinaryPath" Write-Ok "Built to $wslBinaryPath (inside WSL)" # Verify diff --git a/scripts/setup.sh b/scripts/setup.sh index 0e98f66cf..2c1873f7f 100755 --- a/scripts/setup.sh +++ b/scripts/setup.sh @@ -199,13 +199,7 @@ build_from_source() { echo "${BOLD}Building binary (this may take a minute)...${RESET}" mkdir -p "$INSTALL_DIR" - local build_flags="" - # Use -buildvcs=false in WSL (git metadata fails across filesystem boundaries) - if grep -qi microsoft /proc/version 2>/dev/null; then - build_flags="-buildvcs=false" - fi - - (cd "$SOURCE_DIR" && CGO_ENABLED=1 go build $build_flags -o "${INSTALL_DIR}/${BINARY_NAME}" ./cmd/codebase-memory-mcp/) + (cd "$SOURCE_DIR" && scripts/build.sh && cp build/c/codebase-memory-mcp "${INSTALL_DIR}/${BINARY_NAME}") ok "Built and installed to ${INSTALL_DIR}/${BINARY_NAME}" }