feat(desktop): the file tree's search covers the whole repository, read in one recursive listing the first time it is used
Part 2 of 4 of Dean's file viewer polish; part 1 (#2125, the tree's icons, flattening, search field, and filter) is merged. The orchestrator asked for it: searching only the folders opened so far would feel broken.
Summary
The tree's search covers the whole repository.
- The first time the search field is used, the pane reads the repository whole in one GitHub call: git trees with
recursive=1. - The search then narrows a tree of every path, drawn in its own frame, standing in the browsing tree's place while a query stands. So searching opens no folders in the browsing tree, and clearing the query leaves it exactly as it was.
- The listing is read lazily (most trees are browsed and never searched), kept for the File view's life across File tabs, and read again on the next search if it did not land.
- When GitHub cuts the listing short (past 100,000 entries or 7 MB), or it holds more than the new 50,000-entry bound, the search falls back to the folders listed so far. The empty field says so quietly: its placeholder reads Search opened folders instead of Search files.
Wire: the existing tree read (planning.tree act → gateway → HostedPlanClient.readTree → GET /api/plans/{id}/tree) gains an optional recursive flag, sent as ?recursive=1. No new route or method. Asked recursively:
- The service lists everything under the folder, each entry named by its path, under the same rules as one folder's listing (
plan-tree.ts). - Anything inside a folder named as a secret file is left out, though the folder itself is named, as a per-folder listing would show it.
- The answer is cut at
PLAN_TREE_BOUNDS.MAX_RECURSIVE_ENTRIES(50,000) and says so withtruncated. A single folder's listing keeps its 5,000 bound. - Any value of
recursiveother than1is an invalid request.
Goldens (re-recorded with LUKE_UPDATE_FIXTURES=1). These are desktop↔service wire schemas, not shown to any model:
plan-wire-planTreeRequestSchema.json: gains the optionalrecursive: boolean.plan-wire-planTreeFolderSchema.jsonandplan-wire-planTreeAnswerSchema.json:entries.maxItemsgoes from 5000 to 50000, the recursive bound.
Bundle
The file-tree.js change is a few lines (a third view, swapped in as the other two are). No budget move.
Screenshots (headless Chrome, fixture data)
plan finds packages/core/src/plans.ts and packages/ui/src/plan-card.tsx in folders the tree never opened:
| Light | Dark |
|---|---|
![]() | ![]() |
Verification
./scripts/check.shexits 0.- New tests, each failing without the change:
apps/web/tests/plans-app.test.ts: a recursive read lists everything by path, leaves out what is inside a secret-named folder, says when GitHub cut it, and refusesrecursive=yes.packages/hosted/src/plan-client.test.ts: a recursive read asks?recursive=1.host-operator.test.ts:recursivereaches the host, and a plain read carries none.file-tree/index.test.ts: given the whole listing, a search finds a file in a folder never opened, opens it on a press, and clearing the search shows the folders as they were.planning/file-view.test.ts: the first search reads the whole repository once and hands the tree its entries; a cut-short listing hands nothing and the empty field says Search opened folders.
- CI could not verify this. It is a desktop UI change and
./scripts/verify.shwas not run: this was written on a Linux VM. A Mac break that lands is caught at the release rehearsal on a tag (LUKE-159).
🤖 Generated with Claude Code

