From 6b0bb19e914a3bbaeca198ac1627d698c3a13a76 Mon Sep 17 00:00:00 2001
From: Adam Malczewski <github@tradam.dev>
Date: Thu, 25 Jun 2026 17:09:57 +0900
Subject: feat(computer): SSH computer selection + status + workspace default
 (handoff #2)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Mirrors the cwd/workspace UI for the SSH-computer feature:

- New feature library src/features/computer/:
  - logic/view-model.ts (pure): viewComputer/viewComputerStatus/viewTestResult/
    summarizeComputers/formatHost/knownHostLabel + state->badge for the 4
    ComputerStatusResponse states + SaveComputer/LoadComputerStatus/
    TestComputer/LoadComputers ports. 20 view-model tests.
  - ui/ComputerField.svelte: per-conversation selector (dropdown +
    connection-status badge + Test-connection, polling the selected alias).
  - ui/ComputerSelect.svelte: reusable Local/computers dropdown, shared with
    the workspace default-computer control.
- AppStore: computerId state + refreshComputer (at every focus site, parallel
  to refreshCwd) + setComputer (PUT /conversations/:id/computer, null=clear) +
  global computers catalog (GET /computers on boot, like models) +
  computerStatus(alias) + testComputer(alias). chat.send UNCHANGED (resolved
  server-side like cwd).
- App.svelte: ComputerField in the Model sidebar view next to CwdField; adapted
  ports wrap the store.
- workspaces: setDefaultComputer on WorkspaceHttp+WorkspaceStore
  (PUT /workspaces/:id/default-computer); default-computer selector in
  WorkspaceCard (reuses ComputerSelect); router passes store.computers through.
- Re-mirrored .dispatch/transport-contract.reference.md (Computers section +
  ChatRequest.computerId); updated .dispatch/wire.reference.md (Computer/
  ComputerEntry/defaultComputerId + the provider-retry divergence note from
  handoff #1); GLOSSARY + backend-handoff.md (handoff #2, §2e).

Transparency invariant: the computer is USER-facing only (a tool-execution
target, never part of the model prompt); the agent never sees it.

Verify: 795/795 tests green; biome clean; vite build succeeds; 0 typecheck
errors from the computer feature. (11 pre-existing svelte-check errors remain
from the open §2d provider-retry divergence — backend feature/ssh-support
still lacks TurnProviderRetryEvent; not from this feature.)
---
 src/features/workspaces/ui/WorkspacesHome.svelte | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

(limited to 'src/features/workspaces/ui/WorkspacesHome.svelte')

diff --git a/src/features/workspaces/ui/WorkspacesHome.svelte b/src/features/workspaces/ui/WorkspacesHome.svelte
index 5894f0a..bdfd023 100644
--- a/src/features/workspaces/ui/WorkspacesHome.svelte
+++ b/src/features/workspaces/ui/WorkspacesHome.svelte
@@ -1,10 +1,16 @@
 <script lang="ts">
 	import { onMount } from "svelte";
+	import type { ComputerEntry } from "@dispatch/wire";
 	import type { WorkspaceStore } from "../store.svelte";
 	import { isValidSlug, workspacePath } from "../logic/route";
 	import WorkspaceCard from "./WorkspaceCard.svelte";
 
-	let { store, onNavigate }: { store: WorkspaceStore; onNavigate: (path: string) => void } = $props();
+	let {
+		store,
+		onNavigate,
+		computers,
+	}: { store: WorkspaceStore; onNavigate: (path: string) => void; computers: readonly ComputerEntry[] } =
+		$props();
 
 	onMount(() => {
 		void store.refresh();
@@ -78,7 +84,7 @@
 		{:else}
 			<ul class="flex flex-col gap-2">
 				{#each store.list as ws (ws.id)}
-					<WorkspaceCard {ws} {store} {onNavigate} />
+					<WorkspaceCard {ws} {store} {onNavigate} {computers} />
 				{/each}
 			</ul>
 		{/if}
-- 
cgit v1.2.3

