- delete the singleQuote shell-quoting helper and its bash-spawning tests
(no in-repo consumers; no shell layer exists anymore)
- drop spill from both collect streams: the tool never reads a raw spill
path, and a lossy stdout read is a pure SEARCH_RAW_OUTPUT_OVERFLOW error
- prepend --no-config so a host RIPGREP_CONFIG_PATH cannot inject a --pre
preprocessor into the unconfined spawn
- promote graceMs and stderrMaxBytes to validated Config fields (defaults
SEARCH_GRACE_MS / SEARCH_STDERR_MAX_BYTES) instead of inheriting
bash-local's config
- correct the grep tool's JSDoc seam reference (bash -> subprocess)
- drop the dead exit-127/command-not-found classification branch
glob/grep now run the @vscode/ripgrep binary via ctx.subprocess with a plain
argv vector: no system rg install, no shell layer, unconditional registration.
The load-time command -v rg probe and the bash-seam coupling are removed;
timeouts ride the cooperative exec.signal plus the seam's terminate
escalation. The fs-glob-sampling ACP snapshot executes the real packaged
binary against an mtime-pinned fixture. Adds the packaged-ripgrep-search
Agent Note, updates the roster-note facts and both shipped-composition e2es,
and regenerates the doc catalogs and third-party notices (surfacing
pre-existing manifest drift plus the new @vscode/ripgrep row; the notices
generator also learns pnpm 11's truncated virtual-store names).
Asked what a workspace contained, an agent described one subfolder as the
whole project. `glob {"pattern": "*"}` matched 10030 paths across 22
top-level entries and the inline page was the first 100 of them, all under a
single unpacked archive.
Three properties compose into that page: a pattern with no `/` matches
basenames at any depth, so `*` means the whole tree rather than its top
level; `--sort=modified` orders oldest first, and unpacking an archive
restores timestamps that predate everything the user wrote; and the page was
the head of that order. Each is defensible alone, and together they make the
most ordinary request an agent receives produce a confident wrong answer.
A result within `globMaxResults` is unchanged — shown whole, in
modification-time order. Beyond it the page is filled round-robin across the
complete result's top-level entries, so one subtree cannot own every slot,
and the footer states that the page was sampled rather than taken in
modification-time order. Measured on a 24-entry, 716-file reproduction, the
head of 100 reaches 7 top-level names and the sampled page reaches 21. The
spill artifact still holds the complete sorted list.
The guidance and schema stop steering away from `ls`, state the any-depth
pattern rule, say results are files and never directories, and point at
`list` for a directory's contents.
Implements docs/rfc/implemented/feature/2026-07-09-bash-backed-grep-glob-
discovery.md: model-facing glob/grep in a new @deepseek-ai/dsh-tool-fs-search
package, executing fixed ripgrep templates through ctx.bash.resolve/run —
not ctx.fs provider methods — so filesystem backends stay free of a search
contract and sandboxed/remote executors substitute cleanly. The tools never
call ctx.bash.start(); the tool layer owns quoting (one singleQuote safety
boundary), rg --json parsing, ItemRetainer/TextRetainer retention, and the
first tool-owned ctx.spillFiles.saveText() handoff (item-level retention the
generic post-execute spill policy cannot recover).
RFC amendments on the way to implemented/: a shared src/search-core.ts (the
SEARCH_* vocabulary + bash-run/raw-spill/spill plumbing was byte-identical
across both tools — the missed-extraction smell), and a snapshot-gap note:
wiring the acp-agent tree changes the assembled prompt, so goldens need a
keyed re-record; the spill notice text is pinned by unit tests instead and
only the coding-agent example ships the tools for now.