Skip to content

File browser hides files deeper than 3 levels: /api/files depth default is 3 and the dashboard never overrides it #1726

Description

@baogiadoan

Summary

The dashboard file browser silently hides files nested deeper than 3 directory levels. The
GET /api/files endpoint defaults to depth=3 and the dashboard never sends a depth
parameter, so the tree is always truncated at 3.

The symptom is easy to misread. In a repo where the conventional directories are shallow
(codev/specs/*.md is depth 2) but working files are deeper, it looks like "markdown preview
only works under codev/". It isn't a preview restriction — the preview gate is correct and
path-agnostic (tower-routes.js, const isMarkdown = ext === 'md'). It is a depth cap on the
tree, so the deeper files never appear to be clicked in the first place.

Observed on @cluesmith/codev@3.3.4: a reports/weekly/draft/ directory came back with 0
children (8 .md files hidden) while codev/specs returned all 41 entries.

Root cause

dist/agent-farm/servers/tower-routes.js, handleWorkspaceFiles:

const maxDepth = parseInt(url.searchParams.get('depth') || '3', 10);

readTree returns [] once depth <= 0, so a truncated directory is indistinguishable from an
empty one in the response — the client cannot tell that anything was withheld. The depth is also
not exposed in .codev/config.json, so there is no way to raise it short of editing dist/.

Measurements

Against a live Tower, one moderately large repo, timings include JSON transfer:

depth entries .md found wall time
3 (current default) 2,027 156 31 ms
4 4,594 227 76 ms
5 2,212 ms

Depth 4 is close to free and recovers the files that actually matter. Depth 5 is already
seconds, which is not acceptable for an endpoint the dashboard polls.

Why "just extend the ignore set" is not sufficient

The natural reading of the table is that deep walks are slow because they descend into
dependency directories, and that a bigger ignore set would let the default rise. On the repo
measured, that turns out not to be the case. Breaking down the .md files reachable at depth 8:

8431  data/output      <- the project's own experiment artifact directory
  64  codev/protocols
  50  reports/real_end_to_end_production_smoke
  41  codev/specs

The overwhelming majority are in data/output — a project-specific artifact directory, not
vendor content. node_modules, dist, __pycache__ and friends are already ignored. No ignore
set shipped in the package can anticipate that a given project dumps tens of thousands of
generated markdown files under data/output, so extending the shipped list does not make a
deeper default safe in general.

This matters because it rules out the cheapest-looking fix.

Suggested fixes

Preferred — lazy-load children on expand. Have the browser request a directory's children
when the user expands it, rather than serving a fixed-depth tree up front. This removes the
depth ceiling entirely and makes cost proportional to what the user actually opens, which is
the only approach that is robust to arbitrary project layouts.

Interim — expose the depth. Two small changes that are useful even alongside the above:

  1. Make the depth configurable in .codev/config.json so a project can tune it to its own
    layout, and/or have the dashboard send an explicit depth.
  2. Mark truncation in the response, e.g. { type: 'directory', truncated: true, children: [] },
    so a capped directory is distinguishable from an empty one. This alone would have made the
    original symptom self-explanatory instead of looking like a preview bug.

Raising the shipped default from 3 to 4 is a reasonable stopgap — it is ~45 ms on the repo
measured — but per the breakdown above it should not go past 4 without the lazy-loading change.

Workaround for anyone hitting this

afx open <path>.md renders preview for any markdown file regardless of depth or location,
because the preview gate keys on the file extension only. Only the tree is affected.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions