mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-11-14 18:39:33 +01:00
fix(files): mark folders the scan limit stopped short of
The fair rounds give a directory its node before reading it, so every folder still queued when the 5,000-node budget ends sat in the tree with empty or partial children and read as an empty folder. Keep the node on the tree cursor and set an additive incomplete: true on every cursor left in the queue, then draw one dim, inert row under such a folder while it is expanded. The envelope check ignores keys it does not know, so old and new clients stay compatible. Stop each round at the top once the budget is spent, before the shift: the rest stay queued unread, and flagged, rather than read and sorted for nothing. Say what the walk is: a per-directory round-robin (breadth-first), fair per directory and not per subtree, with search results now shallow-first. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
bb42f8105e
commit
a908be05ac
12 files changed
+370
-15
No files matched your search
@@ -1014,6 +1014,14 @@ while a `q` containing `/` is matched against paths relative to the folder walke
|
||||
also carries `worktree`, the same `{ name, path }`, whenever the session has a `liveWorktree`,
|
||||
whichever folder was walked and with or without `root=live`.
|
||||
|
||||
The walk reads at most 5,000 files and folders and sets `truncated` when it stops early. It is
|
||||
a per-directory round-robin (breadth-first): each folder found so far gets an equal share of what
|
||||
is left before any of them gets more, so one huge folder cannot hide its later siblings, and the
|
||||
`matches` of a `q` search come back shallow-first. A folder made of thousands of small subfolders
|
||||
can still use most of the limit one level down. In the tree, a directory node the limit stopped
|
||||
short of also carries `incomplete: true`: its `children` hold what was read before the limit,
|
||||
which can be nothing. The key is absent on every other node.
|
||||
|
||||
## Session model (`displayModel`)
|
||||
|
||||
Session state (`GET /api/v1/sessions`, the `session:updated` event) carries the model a
|
||||
|
||||
@@ -734,6 +734,8 @@ Frontend `readmymind-ui.js`: header 🧠 marker-hidden (`btn-readmymind--hidden`
|
||||
|
||||
⚠️ **A query turns that endpoint into a FLAT match list rather than a nested tree**, and the walk deliberately recurses past non-matching directories, since the whole point of searching is to reach a file whose ancestors do not match. An empty or whitespace-only query compiles to `null`, which is what keeps the default tree response byte-identical when no search is requested.
|
||||
|
||||
⚠️ **Both walks are a per-directory round-robin (breadth-first) over ONE 5,000-node budget.** They used to recurse depth-first through name-sorted folders, so an early folder could spend the whole budget: 4 of 57 top-level folders were shown in one real workspace. Each round divides what is left equally among the directories queued so far. That is fair per directory, not per subtree: a folder of thousands of one-file subfolders still crowds out its neighbours one level down (`a/b/c/d/needle.ts` beside such a `z/` is found depth-first and missed here), and that trade is accepted, since a file browser wants the shallow levels first. Search results therefore arrive shallow-first. ⚠️ A directory gets its node, with `children: []`, when it is counted and is read in a later round, so every cursor still queued after the loop is a folder that is unread or half read: it must carry `incomplete: true` or it reads as an empty folder, the failure that went from 0 to 635 such folders before the flag existed. `renderFileBrowserTree` draws one dim, inert row under it while it is expanded, and the row is not a `.file-tree-item`, so the click wiring leaves it alone. The budget check at the top of each round runs BEFORE the `shift()`, so a directory the round skips stays queued and keeps its flag. The walk's root has no node, so `truncated` is its only signal, and a folder dropped at the depth cap is not flagged, since the row says "file limit" and it looks the same as it always has.
|
||||
|
||||
⚠️ **Globs are never compiled into a RegExp**: `*a*a*a…` translated to `^.*a.*a.*a…$` is a classic backtracking blowup evaluated synchronously against every walked path, so one pathological query would freeze the event loop for the whole server (the same reason `search-service.ts` is regex-free). `globMatch()` is a two-pointer wildcard walk instead, O(text · pattern) with both operands short by construction, and an overlong query (`MAX_QUERY_LENGTH`, 256) also compiles to `null` rather than running.
|
||||
|
||||
Matching semantics: a query containing `/` matches the path relative to the folder being walked (`workingDir`, or the worktree of a `root=live` listing; the returned `path`s stay relative to `workingDir` either way), otherwise the bare entry name; globs match anchored and case-insensitively (`*` spans any run, slashes included, `?` exactly one character), everything else is a plain case-insensitive substring.
|
||||
|
||||
@@ -10,6 +10,11 @@ A panel that browses the active session's working directory, or the git worktree
|
||||
moved into ([Git Worktrees](Git-Worktrees#when-an-agent-moves-into-a-worktree)). Its header
|
||||
button is on by default; if it is missing, re-enable it in **App Settings → Header & Panels**.
|
||||
|
||||
The panel and its search scan up to 5,000 files and folders per load, shallow levels first and
|
||||
taking turns between folders, so one huge folder cannot hide the ones after it. When a workspace
|
||||
is bigger than that the status line says `(truncated)`, and an expanded folder the scan did not
|
||||
finish shows **Not fully scanned (file limit reached)** rather than looking empty.
|
||||
|
||||
It renders what it can:
|
||||
|
||||
| Kind | Behaviour |
|
||||
|
||||
Reference in new issue
Block a user