v0.9.14: Add AST-resolved symbol-targeted edits (edit_symbol) so anchoring stops failing on text matching
- Dominant language
- Rust
- Stars
- 41k
- Forks
- 3.6k
- Avg merge
- 13h 59m
- Merged PRs (30d)
- 299
Description
## Why this matters
The dominant edit-tool failure mode is anchoring, not syntax: `edit_file`'s
`old_string` is not found, is not unique, or matches stale whitespace after a
format change. Each failure costs a turn and a re-read. Letting the model
address code by *name* — "replace `impl Foo::bar`" — removes the failure class
entirely instead of detecting it after the fact.
## Current behavior
- `edit_file` does exact-string replacement with fidelity checks
(`crates/tui/src/tools/file.rs:1607`); `apply_patch` applies unified-diff
hunks textually (`crates/tui/src/tools/apply_patch.rs:232`).
- Symbol knowledge exists only through the opt-in LSP tool
(`crates/tui/src/tools/lsp.rs`), which requires a spawned server and cannot
return edit-ready spans offline.
- No structural resolver exists for offline, deterministic span lookup.
## Desired behavior
1. New tool (e.g. `edit_symbol`) taking `{ path, symbol, replacement }` where
`symbol` names a Rust/TS item: `fn name`, `impl Type::method`,
`struct Name`, `const NAME`, etc.
2. Resolve the item's full byte span — including doc comments and attributes —
via `ast-grep-core` (same dependency as #6202), then splice the replacement
and run the post-edit syntax gate before reporting success.
3. Ambiguous matches return a typed error listing candidate items (name +
kind + line), never a silent first-match.
4. Unsupported languages return a clear error pointing at
`edit_file`/`apply_patch` as the fallback.
5. All writes flow through the existing approval/sandbox/write policy
unchanged; a diff preview is returned in the tool result.
## Evidence
- Exact-match edit path: `crates/tui/src/tools/file.rs:1607-2270`.
- Unified-diff path: `crates/tui/src/tools/apply_patch.rs:232`.
- LSP symbols exist but are server-bound: `crates/tui/src/tools/lsp.rs`,
`crates/tui/src/lsp/registry.rs:100`.
## Acceptance criteria
- [ ] `edit_symbol` replaces a named `fn`/`impl` block on a Rust fixture,
including its doc comments, verified by a unit test.
- [ ] Two same-named functions produce an ambiguity error listing both
candidates, not a blind first match.
- [ ] Post-edit output passes the syntax gate from #6202; a syntactically
broken replacement is rejected before write.
- [ ] Unsupported file types fail with explicit fallback guidance.
- [ ] `cargo test -p codewhale-tui` edit-tool tests stay green.
## Related
- #6202 — the ast-grep-core dependency and post-edit syntax gate this builds on.
- #3980 — broader structural search/preview scope, closed not planned; this is
the narrower edit-only slice.
Contributor guide
Research direction
Start by reading crates/tui/src/tools/file.rs, crates/tui/src/tools/apply_patch.rs, crates/tui/src/tools/lsp.rs, and the ast-grep-core and syntax-gate work in #6202. Run the existing edit-tool tests with cargo test -p codewhale-tui, then use Rust fixtures to verify named replacement, ambiguity errors, syntax rejection, unsupported-language guidance, and unchanged approval/write policy.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust, typescript
- Domain
- cli, testing-qa, tooling
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100