Four codecontext sidecar wrappers — get_file_analysis (required file_path), get_symbol_info, get_dependencies, and get_semantic_neighborhoods (optional) — forwarded file_path to the HTTP sidecar unchanged. The sidecar's internal file index is keyed on absolute paths, so any relative path from the model returned "File not found in graph". Three back-to-back failures observed in one chat on 2026-05-22 17:56 UTC, ~48 s of wasted tool budget. ## Resolver Add resolveProjectPath(projectRoot, rawPath) in codecontext_client.ts: trim check → absolute/relative branch (both go through resolve() so dot-segments normalise) → realpath with ENOENT fallthrough → escape check using the realpathed value. Error shape mirrors the existing target_dir escape error byte-for-byte; only the field name differs. Wired into callCodecontext at the args-spread site, guarded on file_path presence + non-empty. All four wrappers benefit from one call site; wrappers without file_path (overview, framework, watch, search) are unaffected. ## Schema trim .trim() added to all four file_path Zod schemas: get_file_analysis: z.string().trim().min(1) get_symbol_info: z.string().trim().optional() get_dependencies: z.string().trim().optional() get_semantic_neighborhoods: z.string().trim().optional() Absorbs trailing newlines / whitespace from model output before the resolver sees the value. ## Adversarial review fixes Adversarial pass surfaced two P2 findings: 1. Absolute path with `..` resolving outside the project root (e.g. `<projectRoot>/../etc/passwd`) that ENOENTs at realpath would slip through the literal prefix-check: the raw string starts with `<projectRoot>/`. Fix: resolve() the absolute branch's candidate too, so dot-segments normalise before the prefix check. 2. No symlink-escape test coverage. Realpath's stated purpose (catching in-project symlinks pointing outside the project) was never tested. Added: create a tmpdir outside projectRoot, symlink projectRoot/evil-link → outside file, assert rejection. ## Tests codecontext_client.test.ts: 19 tests (10 baseline + 9 new file_path resolution cases). Cases cover: relative→absolute, absolute-inside, relative-escape, absolute-outside, ENOENT-fallthrough, empty-string, wrapper-without-file_path, absolute-with-`..`-ENOENT, symlink-leaving-root. codecontext_tools.test.ts: one assertion updated to expect the resolved-absolute file_path on the wire (previously asserted the raw relative path passed through, which is exactly the bug being fixed). Full suite: 301 passed, 7 skipped. ## Affected / unaffected - get_codebase_overview, get_framework_analysis, watch_changes, search_symbols: no file_path arg → resolver guard skips them. No behavior change. - get_semantic_neighborhoods IS in SYNTHESIS_TOOLS — previously-failing relative-path calls will now successfully synthesize. Desirable, not a regression. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2.2 KiB
v1.13.18 — codecontext file_path resolver
Fixes a silent failure that caused all four file_path-taking codecontext wrappers to return "file not found" whenever the model passed a relative path.
Why
BooCode's codecontext sidecar (codecontext_client.ts) already realpath-resolves target_dir before forwarding it to the HTTP shim. It did not do the same for file_path. The sidecar's internal file index is keyed on absolute paths, so any relative path from the model produced a JSON error response:
{"error":"file not found: apps/server/src/services/inference/turn.ts","result":null}
This was observed repeatedly in the 2026-05-22 docker logs (17:56 UTC window) — the model passed relative paths on every get_file_analysis tool call and received no useful output, burning tool budget on dead calls.
Scope
Four wrappers take a file_path argument:
tools/codecontext/get_file_analysis.ts—file_pathrequiredtools/codecontext/get_symbol_info.ts—file_pathoptionaltools/codecontext/get_dependencies.ts—file_pathoptionaltools/codecontext/get_semantic_neighborhoods.ts—file_pathoptional
Fix lands in one place: callCodecontext in codecontext_client.ts. A new resolveProjectPath helper is inserted at the args-spread site and invoked whenever file_path is present and non-empty. All four wrappers benefit automatically; no per-wrapper edits required.
Zod .trim() is added to all four file_path schema entries so that whitespace-padded paths from the model are cleaned before they reach the resolver.
Decision: single resolver over per-wrapper edits
Four wrappers, one shared code path. Per-wrapper edits would require four edits and make it easy to miss one. The callCodecontext shim already owns target_dir validation; file_path validation belongs there too for symmetry.
Non-goals
- No changes to the
target_dirresolver — it already works correctly. - No extension to wrappers that do not take
file_path(get_codebase_overview,get_framework_analysis,search_symbols,watch_changes). - No fix for the unrelated RPC errors and Go map-race warnings visible in the codecontext sidecar logs — those are upstream bugs.