fix(node): accept a line-numbered file reference in file-view (#1831) - #1836
Open
maxmilian wants to merge 1 commit into
Open
fix(node): accept a line-numbered file reference in file-view (#1831)#1836maxmilian wants to merge 1 commit into
maxmilian wants to merge 1 commit into
Conversation
…chenry#1831) `codegraph node "src/app.ts:42-80"` answered `No indexed file matches` for a file that IS indexed, worded byte-for-byte like a genuine miss, so there was no way to tell "wrong path" from "right path, wrong spelling". The file-view normalizer treated the `:42-80` as part of the filename. explore has stripped exactly these shapes all along (src/search/query-paths.ts) — file-view now does too, and the range it strips becomes the read window. - The literal spelling is resolved FIRST; only when that finds nothing is the suffix stripped, so a file genuinely named `foo:12` still wins. - Supports `:<a>`, `:<a>-<b>`, `#L<n>`, `#L<a>-L<b>` (and `#L<a>-<b>`). - A stripped range maps to `offset=a, limit=b-a+1`; a bare `:<a>` is a start-here pointer (Read given only an offset). An explicit offset/limit from the caller always wins over the suffix. - `#L<n>` was not mentioned in the issue but was broken the same way. Tests: 8 new cases across __tests__/node-file-view.test.ts and __tests__/cli-node-command.test.ts, including a vacuity guard (the same path without the suffix resolves) and a genuine-miss case. Red-armed: with the fix reverted, 6 of them fail with the exact `No indexed file matches` string. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XDR1wm73oH8J8cRWnKyv9m
maxmilian
marked this pull request as ready for review
September 11, 2026 00:35
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #1831.
The problem
codegraph node "src/app.ts:42-80"— the way an agent or a human pastes a file reference — answers:for a file that is indexed. The reply is byte-for-byte identical to the one a genuinely missing path gets (
codegraph node "scripts/nope.ts"), so the caller cannot tell "wrong path" from "right path, wrong spelling" and has no way to discover that dropping the:42-80would have worked.The cause is in
handleFileView: its normalizer only touches separators and leading/trailing slashes, so the:42-80stays part of the filename and never matches an indexed path.Why this shape belongs here
Codegraph already handles it elsewhere.
explorestrips exactly these suffixes from agent-written paths —src/search/query-paths.ts:135:So this is not a new convention — it is file-view catching up with the one the codebase already committed to. This PR reuses that exact pattern (with capture groups added, so the range is kept rather than discarded).
#L<n>is fixed too. The issue only reports:<a>-<b>, butsrc/app.ts#L42andsrc/app.ts#L42-L80— the GitHub-permalink spelling, and the other half of the precedent regex — failed identically. Fixing one and not the other would have left the same confusing message behind.The fix
About eight lines in
handleFileView, plus lifting the existing resolution cascade into aresolveOne()helper so it can be called twice:foo:12still resolves to itself. The suffix path is reached only when the literal spelling matches nothing — zero regression by construction, not by assumption.:<a>-<b>maps tooffset=a, limit=b-a+1. A bare:<a>/#L<a>is a start-here pointer —offset=awith the default limit, exactly whatRead(file, offset=N)does.offset/limit(or--offset/--limit) overrides the suffix, so nothing is silently rewritten under a caller that asked for a specific window.No new gate counters, so
docs/design/telemetry.mdis untouched.Verification
8 new cases in
__tests__/node-file-view.test.tsand__tests__/cli-node-command.test.tscovering:a,:a-b,#Ln,#La-Lb,#La-b, a full repo-relative path with a suffix, caller-offset precedence, and a genuine miss.Two of them are guards rather than assertions of the fix:
does-not-exist.ts:10-20must still report a miss.Red-armed. With the fix reverted and the tests kept, 6 fail with the exact
No indexed file matches "…"string; the vacuity guard and the genuine-miss case pass in that state, which is what makes the other six meaningful. With the fix applied:23 passed (23)across both files.Full suite:
4428 passed, with 14 pre-existing failures across 8 files (installer-targets,mcp-callers-truncation,nextjs,object-literal-methods,react-native-bridge,ui-steps-api,ui-steps-api-servers,ui-steps-cross-tier) — identical count and identical files on the unmodified base commit, verified by stashing the change and re-running those files.npm run buildis clean.End-to-end on a real indexed project:
One thing I could not cover with a fixture
I wanted a regression fixture for a file whose name literally ends in
:N, to pin the literal-first ordering. It turns out such a file can never reach this code path: the indexer resolves language by extension, and.ts:12matches none, sogetFiles()never contains such a path. The ordering is still guaranteed structurally —resolveOne(fileArg)runs before any stripping — just not by a fixture. Flagging it rather than leaving it look like an oversight.🤖 Generated with Claude Code
https://claude.ai/code/session_01XDR1wm73oH8J8cRWnKyv9m