diff options
| author | Adam Malczewski <[email protected]> | 2026-06-25 22:45:51 +0900 |
|---|---|---|
| committer | Adam Malczewski <[email protected]> | 2026-06-25 22:45:51 +0900 |
| commit | 1285564f12238b22f6b39b9f3fbcecaca8456911 (patch) | |
| tree | 9d8ca532969a5a11ee61b5c42135ac6f54159183 /.dispatch | |
| parent | c5ea2232f117adda740c7e3b8366e9f10f14d3cb (diff) | |
| parent | cdce5197abcf0f5b0576e847a701d3a317384a65 (diff) | |
| download | dispatch-web-1285564f12238b22f6b39b9f3fbcecaca8456911.tar.gz dispatch-web-1285564f12238b22f6b39b9f3fbcecaca8456911.zip | |
Merge branch 'feature/ssh-support' into dev
# Conflicts:
# src/features/workspaces/ui/WorkspaceCard.svelte
# src/features/workspaces/ui/WorkspaceCard.test.ts
# src/features/workspaces/ui/WorkspacesHome.svelte
Diffstat (limited to '.dispatch')
| -rw-r--r-- | .dispatch/transport-contract.reference.md | 100 | ||||
| -rw-r--r-- | .dispatch/wire.reference.md | 70 |
2 files changed, 167 insertions, 3 deletions
diff --git a/.dispatch/transport-contract.reference.md b/.dispatch/transport-contract.reference.md index 8c6023a..48ba45d 100644 --- a/.dispatch/transport-contract.reference.md +++ b/.dispatch/transport-contract.reference.md @@ -5,9 +5,20 @@ > permission prompt). Your CODE still imports `@dispatch/transport-contract` normally — this file is for > READING only. > -> **Orchestrator:** SNAPSHOT of `[email protected]` (MCP status). Regenerate whenever +> **Orchestrator:** SNAPSHOT of `[email protected]` (MCP status + computers). Regenerate whenever > it changes. > +> **2026-06-25 delta (SSH handoff #2 — ADDITIVE to `[email protected]`, NO version bump):** adds the +> computer HTTP API types: `ComputerListResponse` (`GET /computers`), `ComputerResponse` (`GET /computers/:alias`), +> `ComputerStatusResponse` (`GET /computers/:alias/status`), `TestComputerResponse` (`POST /computers/:alias/test`), +> `SetConversationComputerRequest` + `ConversationComputerResponse` +> (`GET`/`PUT`/`DELETE /conversations/:id/computer`), `SetWorkspaceDefaultComputerRequest` +> (`PUT /workspaces/:id/default-computer`). Also `computerId?: string` on `ChatRequest`/`ChatSendMessage`/ +> `QueueRequest` (per-turn override; resolved server-side from the persisted per-conversation value in the MVP, so +> `chat.send` need not send it). `Computer`/`ComputerEntry` themselves are `@dispatch/wire` types. See +> `backend-handoff.md` §2e. (The `ssh` extension that provides the ComputerService is the last backend wave — +> until it lands, `GET /computers` returns `[]` and statuses return `disconnected`.) +> > **2026-06-24 delta (MCP status handoff — package bumped `0.18.0` → `0.22.0`, ADDITIVE):** adds > `McpServerState`, `McpServerInfo`, and `McpStatusResponse`; endpoint > `GET /conversations/:id/mcp`. Mirrors the existing `GET /conversations/:id/lsp` shape (returns @@ -117,6 +128,16 @@ export interface ChatRequest { * defaultCwd = null). */ readonly workspaceId?: string; + + /** + * The computer to run this turn's tools on — an SSH config `Host` alias + * (one of the `alias` values returned by `GET /computers`). Omit to inherit + * the resolved chain: per-conversation `computerId` → the workspace's + * `defaultComputerId` → `null`/local (today's behavior). Like `cwd`, this is + * a per-turn tool-execution target forwarded to tools and never part of the + * model prompt (so it does not affect prompt caching). Mirrors `cwd`. + */ + readonly computerId?: string; } /** @@ -843,5 +864,82 @@ export interface DeleteWorkspaceResponse { /** Conversations that were closed (status → "closed") by this delete. */ readonly closedCount: number; } + +// ─── Computers (SSH handoff #2) ───────────────────────────────────────────── + +/** + * Response of `GET /computers` — every remote computer discovered from the + * system's `~/.ssh/config`, sorted by `alias`. Parallel to + * `WorkspaceListResponse`: each entry is a `ComputerEntry` (a `Computer` plus a + * usage count). There is no Computer CRUD — to add one, the user adds a `Host` + * block to `~/.ssh/config` and Dispatch discovers it on the next read. + */ +export interface ComputerListResponse { + readonly computers: readonly ComputerEntry[]; +} + +/** + * Response of `GET /computers/:alias` — a single computer. Parallel to + * `WorkspaceResponse` (the entity itself). `alias` is the `computerId` users + * select; the remaining fields are resolved from the SSH config. + */ +export interface ComputerResponse extends Computer {} + +/** + * Response of `GET /computers/:alias/status` — the live connection state of a + * computer (whether Dispatch currently holds an open SSH session to it). Drives + * the frontend connection indicator. `error` is present only when + * `state === "error"`; `knownHost` mirrors the read-only `Computer` field. + */ +export interface ComputerStatusResponse { + readonly alias: string; + readonly state: "disconnected" | "connecting" | "connected" | "error"; + readonly error?: string; + readonly knownHost: boolean; +} + +/** + * Body of `PUT /conversations/:id/computer` — set or clear the conversation's + * persisted computer selection (the computer analog of `SetCwdRequest`). Pass + * `null` to clear → the conversation inherits the workspace's + * `defaultComputerId`, then `null`/local. An unknown alias is not validated here + * (the connection resolves at turn time; an unreachable host → turn error, not + * a 400). Mirrors the cwd/model PUT clear semantics. + */ +export interface SetConversationComputerRequest { + readonly computerId: string | null; +} + +/** + * Response of `GET /conversations/:id/computer`. `computerId` is the persisted + * SSH `Host` alias, or `null` when never set (the conversation then inherits + * the workspace default → local). Parallel to `CwdResponse`. + */ +export interface ConversationComputerResponse { + readonly conversationId: string; + readonly computerId: string | null; +} + +/** + * Body of `PUT /workspaces/:id/default-computer` — set or clear the workspace's + * default computer (the computer analog of `SetWorkspaceDefaultCwdRequest`). + * `null` means local (no SSH). Conversations in the workspace with no + * `computerId` of their own inherit this. + */ +export interface SetWorkspaceDefaultComputerRequest { + readonly computerId: string | null; +} + +/** + * Response of `POST /computers/:alias/test` — the result of a one-shot + * connectivity probe (Dispatch opens an SSH connection to the alias, runs a + * trivial command, then closes). `ok` is true on success; `error` carries the + * failure reason (e.g. auth refused, host unreachable) when `ok` is false. + */ +export interface TestComputerResponse { + readonly alias: string; + readonly ok: boolean; + readonly error?: string; +} ``` diff --git a/.dispatch/wire.reference.md b/.dispatch/wire.reference.md index b7003ec..05ed40b 100644 --- a/.dispatch/wire.reference.md +++ b/.dispatch/wire.reference.md @@ -4,13 +4,30 @@ > types WITHOUT following the `file:` dep symlink out of this repo (which hangs on a permission > prompt). Your CODE still imports `@dispatch/wire` normally — this file is for READING only. > -> **Orchestrator:** SNAPSHOT of `[email protected]` (workspaces). Regenerate whenever `@dispatch/wire` changes. +> **Orchestrator:** SNAPSHOT of `[email protected]` (workspaces + computers). Regenerate whenever `@dispatch/wire` changes. > > **2026-06-23 delta (workspaces handoff — package bumped `0.11.0` → `0.12.0`, ADDITIVE):** adds > `Workspace` + `WorkspaceEntry` (a list entry with a conversation count) and a required > `workspaceId: string` on `ConversationMeta` (`"default"` for legacy/unspecified conversations). A > workspace is a URL-driven grouping of conversations that owns a default cwd; conversations that > haven't set their own cwd inherit `workspace.defaultCwd`. See `backend-handoff-workspaces-reply.md`. +> +> **2026-06-25 delta (SSH handoff #1 — ADDITIVE to `[email protected]`, NO version bump):** adds a REQUIRED +> `defaultComputerId: string | null` on `Workspace` (null = local / no SSH; the computer analog of +> `defaultCwd`) and two new read-only view types: `Computer` (a discovered `~/.ssh/config` `Host` alias) +> and `ComputerEntry extends Computer` (a list entry with a `usageCount`). `alias` IS the `computerId` +> users select (persisted per-conversation/per-workspace like cwd). The full HTTP API surface +> (`GET /computers`, `PUT /conversations/:id/computer`, `PUT /workspaces/:id/default-computer`, +> `GET /computers/:alias/status`, `chat.send computerId`) comes in a LATER handoff — NOT consumed yet. +> +> **⚠️ CROSS-REPO DIVERGENCE (2026-06-25, BLOCKING FE typecheck):** the backend `feature/ssh-support` +> branch (where the SSH types landed) was cut from `8a74335` and is MISSING the `TurnProviderRetryEvent` / +> `provider-retry` `AgentEvent` addition that is on `dev` (and which the FE already consumes — see §2c of +> `backend-handoff.md`). The mirror below KEEPS `TurnProviderRetryEvent` (it is the FE's expected contract +> and matches `dev`); it is marked where it appears. Until the backend merges `dev` into +> `feature/ssh-support`, the FE pinned to the `feature/ssh-support` wire will NOT typecheck (11 errors, +> all the missing `provider-retry` seam). The SSH `Computer`/`defaultComputerId` types ARE present on +> `feature/ssh-support` and are consumed below. ```ts /** @@ -288,7 +305,7 @@ export type AgentEvent = | TurnUsageEvent | TurnStepCompleteEvent | TurnErrorEvent - | TurnProviderRetryEvent + | TurnProviderRetryEvent // ⚠️ divergent: present on `dev`, MISSING on the pinned `feature/ssh-support` wire (see header + backend-handoff.md §2c) | TurnDoneEvent | TurnSealedEvent | TurnSteeringEvent; @@ -611,6 +628,14 @@ export interface Workspace { readonly title: string; /** The workspace's default cwd, or `null` (fall through to server default). */ readonly defaultCwd: string | null; + /** + * The workspace's default computer — an SSH config `Host` alias that + * conversations in this workspace inherit when they set no `computerId` of + * their own. `null` means local (no SSH; today's behavior). The computer + * analog of `defaultCwd`. Resolved per-conversation by `getEffectiveComputer` + * (per-conv `computerId` → this → `null`/local). + */ + readonly defaultComputerId: string | null; /** Epoch-ms when the workspace was first created. */ readonly createdAt: number; /** Epoch-ms of the most recent conversation activity in this workspace. */ @@ -625,4 +650,45 @@ export interface WorkspaceEntry extends Workspace { /** Number of conversations assigned to this workspace. */ readonly conversationCount: number; } + +// ─── Computers ─────────────────────────────────────────────────────────────── + +/** + * A read-only view of a remote computer discovered from the system's + * `~/.ssh/config` — a "computer" is a `Host` alias, NOT an editable entity + * (there is no Computer CRUD store). To add a computer, the user adds a `Host` + * block to `~/.ssh/config`; Dispatch discovers it on the next `listComputers()` + * read. Every field below is resolved from the config (first-match-wins for + * `HostName`/`User`/`Port`/`IdentityFile`). + * + * `alias` is the `computerId` users select — the string persisted per + * conversation and per workspace (the computer analog of `cwd`). `knownHost` + * drives the frontend "known/new" indicator and is read-only. + */ +export interface Computer { + /** The SSH config `Host` alias — also the `computerId` users select. */ + readonly alias: string; + /** Resolved `HostName`/IP from the config (falls back to the alias itself). */ + readonly hostName: string; + /** Resolved port (config `Port`, default 22). */ + readonly port: number; + /** Resolved user (config `User`, default the current user). */ + readonly user: string; + /** Resolved `IdentityFile` path (from the config, or `null` = default `~/.ssh/id_*`). */ + readonly identityFile: string | null; + /** + * Whether the host's key is already in `~/.ssh/known_hosts` (i.e. previously + * connected). Drives the frontend "known/new" indicator. Read-only. + */ + readonly knownHost: boolean; +} + +/** + * A computer entry in the list response (`GET /computers`) — a `Computer` plus + * a usage count. Parallel to `WorkspaceEntry`. + */ +export interface ComputerEntry extends Computer { + /** Number of conversations/workspaces whose `computerId` resolves to this alias. */ + readonly usageCount: number; +} ``` |
