ui-workspace's two trigger surfaces each declare a single-kind directory-flow hole (conversation.hero.workspace.directoryFlow / sidebar.workspaces.directoryFlow, same owner contract) and keep only the trigger and the adoption: the Open-local- folder entry renders while the surface's hole is occupied, and the occupant reports one picked path per open through the hole's owner conversation (open/busy/onPicked/onCancel/onError). directory-picker-native becomes dual-face: its browser half fills both holes with a renderless occupant driving host.pickDirectory, so the cordis.yml row that mounts the backend also composes the client interaction — a mismatch is impossible and a second flow package fails at client load. With composition wiring both sides, the host.describe.directoryPicker advertisement and the client's kind branching lose their last consumer: the field, WorkspacesService.directoryPickerKind(), the DirectoryPickerKind wire type, and the picker's per-open describe read are deleted. The connection fixture now serves a deterministic pickDirectory path so the keyless snapshot drives the full pick-then-adopt flow. ui-workspace's hand-rolled declaration deferral is replaced by the deferRegistration helper it duplicated.
90 lines
3.3 KiB
TypeScript
90 lines
3.3 KiB
TypeScript
/**
|
|
* host domain contract. No protocol version: client and host ship
|
|
* together; introduce protocolVersion only when an independently released client appears.
|
|
*/
|
|
|
|
import type { RpcRequest, RpcResponse } from './rpc.ts'
|
|
|
|
/** One directory row of a listing: a child entry or a breadcrumb ancestor. */
|
|
export interface DirectoryEntry {
|
|
/** Base name shown in a browser row (a root crumb carries its full path). */
|
|
name: string
|
|
/** Absolute host path — the client never joins path segments itself. */
|
|
path: string
|
|
/** Hidden by the host platform's convention (dot-prefixed on POSIX); the client owns whether to show it. */
|
|
hidden: boolean
|
|
}
|
|
|
|
/** host.listDirectory response value: one directory level plus its ancestry. */
|
|
export interface DirectoryListing {
|
|
/** Absolute path of the listed directory. */
|
|
path: string
|
|
/** The host account's home directory (breadcrumb "Home" rooting). */
|
|
home: string
|
|
/**
|
|
* Ancestor chain from the filesystem root to the listed directory
|
|
* inclusive; every crumb is a jump target (crumb `hidden` is always false).
|
|
*/
|
|
crumbs: DirectoryEntry[]
|
|
/** Direct child directories, name-sorted; symlinks to directories included. */
|
|
entries: DirectoryEntry[]
|
|
}
|
|
|
|
/** Host-level unary methods. */
|
|
export interface HostApi {
|
|
/**
|
|
* One-shot host snapshot. Empty payload uses the literal `{}` (extend in place when fields arrive).
|
|
* version = the host app's (apps/cli) package.json version; cwd = the host process working
|
|
* directory (root for session persistence and tool execution); provider/model = the defaults
|
|
* applied when a new agent doesn't specify them explicitly, absent when the host configures
|
|
* no explicit default (the adapter falls back internally);
|
|
* attachedSessions = count of currently attached sessions (those with a live agent);
|
|
*/
|
|
describe(request: RpcRequest<{}>): Promise<RpcResponse<{
|
|
version: string
|
|
cwd: string
|
|
provider?: string
|
|
model?: string
|
|
attachedSessions: number
|
|
}>>
|
|
|
|
/**
|
|
* Open the operating system's single-directory picker; cancellation returns
|
|
* null. Only served under the `native` capability.
|
|
*/
|
|
pickDirectory(
|
|
request: RpcRequest<{}>,
|
|
signal: AbortSignal,
|
|
): Promise<RpcResponse<{ path: string | null }>>
|
|
|
|
/**
|
|
* List one directory level for the in-app browser; an absent path lists the
|
|
* host account's home directory. Only served under the `browse` capability;
|
|
* unreadable or missing targets fail with `directory-unreadable`.
|
|
*/
|
|
listDirectory(
|
|
request: RpcRequest<{ path?: string }>,
|
|
): Promise<RpcResponse<DirectoryListing>>
|
|
|
|
/**
|
|
* Create one child directory under an existing parent (the browser's
|
|
* "New folder"). Only served under the `browse` capability; an existing
|
|
* child fails with `directory-exists`, every other filesystem failure with
|
|
* `directory-create-failed`.
|
|
*/
|
|
createDirectory(
|
|
request: RpcRequest<{ path: string; name: string }>,
|
|
): Promise<RpcResponse<{ path: string }>>
|
|
|
|
/**
|
|
* Open a filesystem path with the operating system's default application
|
|
* (Finder / Explorer / xdg-open hand-off). The browser carrier's
|
|
* prefix-wide trust fence covers this privileged method like every other
|
|
* `/api` request.
|
|
*/
|
|
openPath(
|
|
request: RpcRequest<{ path: string }>,
|
|
signal: AbortSignal,
|
|
): Promise<RpcResponse<{ opened: true }>>
|
|
}
|