Files
deepseek-harness/packages/host/directory-picker-browse
creatixchu 6cd63f741c fix(host): address review — Escape scoping, relist gating, crumb overflow, aria golden
- Escape (and the mask) now reaches only the topmost dialog: while the
  nested New-folder dialog is up the browser ignores its own Modal close,
  and the nested dialog's in-flight fence keeps both open during creation.
- New folder disables while any listing loads, so a slow post-create
  relist/select sequence cannot host a second create against a target the
  pending listing is about to change.
- Deep ancestry scrolls inside a dedicated crumb trail whose tail is pinned
  into view; the path-edit zone keeps its reserved width instead of being
  clipped by the card, preserving cross-drive path entry.
- The workspace-management e2e records a directory-browser aria golden at a
  staged tree (host HOME pointed at the scaffold cwd collapses ancestry into
  the Home crumb, keeping the artifact machine-independent), and the keyless
  snapshot's row targeting goes through visible label text — listitem
  accessible-name computation differs across dom-accessibility-api
  environments (the CI-only miss).
2026-07-28 23:21:27 +08:00
..

@deepseek-ai/dsh-host-directory-picker-browse

English | 中文

The in-app browsing backend of the directory-picker seam: BrowseDirectoryPicker registers ctx.directoryPicker with the browse capability — one-level directory listing and child-directory creation over Node's stdlib, which already carries the per-OS adaptation. Nothing renders on the host display, so this backend serves remote clients the native backend cannot.

Behavior facts: listings return directories only, name-sorted, with symlinks-to-directories followed (broken/cyclic links skipped — the probe stat failing means "not enterable") and a host-owned hidden flag (POSIX dot convention) left for the client to act on; crumbs is the root-to-target ancestor chain, the root crumb labeled by its full path (/, C:\); an absent list path means the host account's home directory. createDirectory is non-recursive (a missing parent is a real failure, not a level to invent) and validates the name as a single non-blank segment even when called directly, mirroring the wire schema's fence. Both primitives reject an explicit path that is not fully qualified — relative forms, and on Windows the rooted drive-less forms (\foo, /foo) and incomplete UNC prefixes (\\, \\server) that isAbsolute accepts — with directory-unreadable/directory-create-failed, instead of letting resolve rebase it under the host process cwd or current drive. Failures throw the seam's typed DirectoryPickerError. Policy rationale: the directory-picker capability seam Agent Note.

Dual-face package: the browser half (./client) fills ui-workspace's two directory-flow holes with the in-app Select Workspace Directory dialog (figma Harness 813-23126 family — Miller two-column view, breadcrumb with a click-to-edit path zone, nested New-folder dialog), driving host.listDirectory/host.createDirectory and registering its own locale namespace (directory-browser, zh default / en). One cordis.yml row therefore composes both sides of the browse interaction; the client carries no capability-kind branching, and mounting a second flow package fails at load (the holes are single kind).

Model Experience

None, as the backend serves the GUI host's directory selection; nothing here reaches a model request.

KV Cache effect

None; this package neither assembles nor sends a provider request.

Known Limitations and Deferred Work

  • Windows hidden attribute is not read — Node dirents do not expose FILE_ATTRIBUTE_HIDDEN, so hidden means dot-prefixed on every platform until a native probe is worth its cost.
  • No drive-root enumeration — on Windows the ancestry stops at the drive root; crossing drives waits for the browser UI's path-entry affordance rather than an enumeration primitive here.
  • Whole-filesystem scope — no per-deployment browse-root restriction; workspace.create accepts arbitrary paths today, so a root here would be UX scoping, not a boundary — deferred until a deployment needs it.