Selecting a preset from the hero pushed the session into the conversation view: the /permission switch logs its command/run + command/done pair, the pair folds into flow nodes, and the composerPhase predicate counted ANY node as conversation — so the hero (composerPhase === 'blank') collapsed. The host-side blank bit was already correct (sessionBlank = no turn/start; knob events open no turn), but the client derives its phase from window content, and command rows are log-only records, not conversation. derivePhase's hasContent now excludes command nodes — the client mirror of the host predicate. The knob events themselves never fold (not surface-eligible), so the pair was the only leak. Covers /plan on the hero identically (same lifecycle pair, same predicate). Specs: the host blank spec pins the three knob events as standalone events; a session spec drives the /permission pair through the live path and asserts phase stays 'blank' while the command node renders.
host/ — web-GUI host half
English | 中文
The host side of the dsh web GUI: the API gateway every client shape shares, and the plain HTTP server it rides on. The browser side lives in client/; the composed application is apps/cli serving apps/web. All product packages.
| Package | Role | ctx key |
|---|---|---|
apiproxy/ |
The shared API gateway: the zero-Node TS wire contract (src/api/), the fetch carrier pair (toFetchHandler host-side, AbstractApiClient client-side), and the host implementation over ctx.agents/ctx.workspace |
ctx.apiProxy |
webserver/ |
Plain HTTP route-registration carrier: node:http server listening on activation; routes register as named exact/prefix handlers |
ctx.httpServer |
directory-picker/ |
Workspace-directory picking seam: discriminated native/browse capability the gateway's picker RPCs delegate to |
ctx.directoryPicker |
directory-picker-native/ |
Dual-face native interaction: OS-chooser backend (osascript / PowerShell / Zenity+KDialog, host-display only) + the browser half filling ui-workspace's directory-flow slots | (registers ctx.directoryPicker) |
directory-picker-browse/ |
Dual-face browse interaction: listing/creation primitives over Node stdlib (remote-capable) + the browser half rendering the in-app Select Workspace Directory dialog | (registers ctx.directoryPicker) |
apiproxy is transport-agnostic by design — it registers no routes; carriers wrap ctx.apiProxy themselves. The HTTP carrier route (with its /api browser-trust fence) is mounted by client/connection's node half, which is why that package lives in the client group: it owns both ends of the wire.