Skip to content

feat(tui): restore @ file mentions - #493

Merged
emal-avala merged 1 commit into
mainfrom
feat/tui-mentions-and-search
Jul 25, 2026
Merged

feat(tui): restore @ file mentions#493
emal-avala merged 1 commit into
mainfrom
feat/tui-mentions-and-search

Conversation

@emal-avala

Copy link
Copy Markdown
Member

Summary

@path file mentions regressed out when the classic REPL was removed. The parser survived (it still backs /files reporting), but nothing completes a mention or expands one — so @src/main.rs reaches the model as literal text. Both peer terminal agents have this; it's table stakes.

What works now

  • Tab completion on @ tokens → files and directories under the session cwd, gitignore-aware, .git never offered, directories gain a trailing / so you can drill in. Completion targets the token under the cursor, so several mentions in one prompt each complete independently. Non-@ input still completes slash commands exactly as before.
  • Expansion on submit — each mention's contents are inlined for the model, while the transcript keeps the line exactly as you typed it. Skipped or truncated mentions surface as a note instead of failing the turn. Queued and interjected prompts route through the same seam, so they expand too.
  • Directories expand to a one-level gitignore-filtered listing rather than being silently ignored.

Limits

Limit Value Rationale
Per file 64 KiB A large source file lands whole; one stray @app.log can't dominate the context window
Per prompt 256 KiB Worst case ~4 full-size files; the remainder are skipped with a note naming the limit
Completion scan 4 000 entries, depth 1 Bounded per keypress so the UI thread can't stall in a huge repo
Directory listing 100 entries … +N more beyond that

Files are read through a limited reader, so an oversized file is never held in memory whole. Binaries are skipped via a NUL sniff plus a UTF-8 decode (a read cut mid-character is trimmed, not misreported as binary).

Security note — worth reviewing closely

The obvious reuse for path confinement, Permissions::read_scope_allows_path, is unsafe here: it returns true unconditionally when no AMR read scope is configured, which is exactly the interactive TUI case. Using it would have provided zero confinement and made @../../etc/passwd readable.

Instead the check canonicalises both sides before prefix-comparing — mirroring the approach of the private read_scope_allows — so a symlink cannot defeat a lexical check. There are explicit tests for a ../ escape and for a symlink escape, plus a .git/ component reject.

Verification

30 new tests, all pure functions over (cwd, text) so they need no terminal:

  • token-under-cursor incl. multi-mention, email rejection (a@b.com is never a token), multibyte input
  • completion: directory contents, trailing slash, case-insensitive leaf prefix, gitignore + .git exclusion, ../ and /etc/ refusal, unknown prefix
  • expansion: single/multiple/deduped, missing file noted, workspace escape rejected, symlink escape rejected, oversized file truncated with marker, total cap across 8 files (asserts exactly 4 blocks + a note), binary skipped, directory listing, email ignored, trailing punctuation tolerated
  • app-level: Tab completion end to end, gitignored path leaves input unchanged, submit inlines contents while the transcript keeps the typed line, no-mention submit byte-identical to before

cargo test, clippy --all-targets -- -D warnings, fmt --check, and a whole-workspace cargo check --all-targets are all clean.

Note

One parser quirk documented in passing: mentions require a / or . in the token (that's what keeps @alice and emails safe), so completing an extensionless top-level file emits ./Makefile to round-trip through the existing parser.

Referencing a file with `@path` stopped working when the classic REPL was
removed: the parser survived (it still backs `/files` reporting) but nothing
completed a mention or expanded one, so `@src/main.rs` reached the model as
literal text.

- Tab completes `@` tokens to files and directories under the session cwd,
  gitignore-aware, directories gaining a trailing slash so you can drill in.
  Completion targets the token under the cursor, so multiple mentions in one
  prompt each complete independently; non-`@` input still completes slash
  commands exactly as before.
- On submit, each mention's contents are inlined for the model while the
  transcript keeps the line as typed. Skipped or truncated mentions surface
  as a note rather than failing the turn.
- Paths are confined to the workspace by canonicalizing both sides before
  comparing, so a symlink cannot escape it; `.git/` and binary files are
  skipped. Content is capped at 64 KiB per file and 256 KiB per prompt, read
  through a limited reader so an oversized file is never held whole.
- Directories expand to a one-level listing instead of being ignored.

The existing mention parser is reused rather than duplicated, and the
slash completer's longest-common-prefix helper is now shared by both.
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@mintlify

mintlify Bot commented Jul 25, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
agentcode 🟡 Building Jul 25, 2026, 6:31 AM

💡 Tip: Enable Workflows to automatically generate PRs for you.

@emal-avala
emal-avala merged commit e93d6ee into main Jul 25, 2026
14 of 15 checks passed
@emal-avala
emal-avala deleted the feat/tui-mentions-and-search branch July 25, 2026 08:14
@emal-avala emal-avala mentioned this pull request Jul 25, 2026
8 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant