feat(host): directory-picker capability seam with dialog and browse backends

The web GUI's folder picking was hardwired to one interaction: a native
OS chooser compiled into the gateway, unusable for remote deployments
and swappable only by editing apiproxy source.

Directory picking becomes a three-package capability seam in
packages/host: ctx.directoryPicker returns a discriminated capability —
dialog (the extracted native chooser; host-display only) or browse
(new: one-level listing + child creation over Node stdlib, hidden flags
host-stamped, symlinks followed, ancestry crumbs; remote-capable). The
gateway injects the seam, advertises the kind via
host.describe.directoryPicker, serves host.listDirectory /
host.createDirectory under browse, and answers
directory-picker-unavailable across kinds. cordis.yml is the swap
point; apps/cli keeps dialog mounted, so behavior is unchanged until
the in-app browser PR flips the default. The connection fixture serves
a deterministic browse tree; WorkspacesService gains the browse calls
the browser UI will drive. Decision record:
.agents/notes/implemented/architecture/2026-07-28-directory-picker-capability-seam.md
This commit is contained in:
creatixchu
2026-07-28 15:44:53 +08:00
parent d1ce22e7ad
commit 7fd2abd828
73 changed files with 1536 additions and 49 deletions

View File

@@ -0,0 +1,19 @@
# @deepseek-ai/dsh-host-directory-picker
English | [中文](README.zh.md)
The **workspace-directory picking seam** for the web-GUI host: an abstract `DirectoryPicker` service (`ctx.directoryPicker`) whose single contract method `capability()` returns a discriminated capability describing how an operator selects a directory. Backends differ in interaction shape, not just mechanism, so the seam models the shapes explicitly instead of one method set: `{ kind: 'dialog', pick(signal) }` opens one native OS chooser on the host display ([`-dialog`](../directory-picker-dialog/README.md)); `{ kind: 'browse', list(path?), createDirectory(path, name) }` serves listing/creation primitives an in-app browser drives, which works for remote clients no OS dialog can reach ([`-browse`](../directory-picker-browse/README.md)). Consumers switch on `capability().kind`; the union is merge-extensible and the documented default for an unknown kind is to hide the picking affordance rather than fail. The capability object must be stable for the service lifetime.
Browse primitives fail with the typed `DirectoryPickerError` (`directory-unreadable` / `directory-exists` / `directory-create-failed`, each carrying the subject `path`), which the consuming gateway maps 1:1 onto wire error codes. `DirectoryEntry` rows carry a host-owned `hidden` flag (POSIX dot convention) so display policy stays client-side; `DirectoryListing.crumbs` is the ancestor chain from the filesystem root, every crumb a jump target. Design rationale, the `ctx.fs` separation, and the policy decisions live in [the directory-picker capability seam Agent Note](../../../.agents/notes/implemented/architecture/2026-07-28-directory-picker-capability-seam.md).
## Model Experience
None, as the seam 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
- **No multi-root vocabulary** — the browse contract exposes one ancestry chain per listing; per-deployment root scoping (and Windows drive-root enumeration above a drive) waits for a consumer that needs it, per the seam Agent Note.