# Plan Roadmap for the next phases of the codespace web IDE. ## Now: shadcn/ui dialog and dropdown migration The frontend still uses `window.prompt`, `window.confirm`, and an absolute-positioned `
` for the file-tree context menu. Replace these with shadcn/ui components backed by Radix UI primitives. This gives us: - Consistent visual style for all popups - Better keyboard navigation and accessibility - The right-click context menu in the file tree becomes a real `DropdownMenu` instead of an in-place div ### Concrete steps 1. Add Radix UI primitives: `@radix-ui/react-dialog`, `@radix-ui/react-alert-dialog`, `@radix-ui/react-dropdown-menu`. 2. Add shadcn-style wrappers under `web/src/components/ui/`: - `dialog.tsx` (Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter) - `alert-dialog.tsx` (AlertDialog, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogDescription, AlertDialogAction, AlertDialogCancel) - `dropdown-menu.tsx` (DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator) - `input.tsx` (used inside Dialogs for prompts) 3. Migrate the existing callers: - `WorkspaceSelector.tsx`: replace `window.prompt` for new-workspace with a `Dialog` containing an `Input`. Replace `window.confirm` for delete with an `AlertDialog`. - `FileExplorerPanel.tsx`: replace all `window.prompt` (new file, new folder, rename) with a generic `Dialog` + `Input` component parameterized by title and callback. Replace `window.confirm` (delete) with an `AlertDialog`. Replace the absolute-positioned context menu with `DropdownMenu`. 4. Do not change backend behavior. ## Next: opencode ACP panel and integration `opencode acp` exposes the editor as an **Agent Client Protocol** server. The current `opencode` process is started in the background but the user has no way to interact with it. The next phase adds a first-class ACP client panel in the web IDE. **Status: ✅ Completed** (commits: ACP backend `feat(backend): add opencode ACP ...`, ACP frontend `feat(web): add ACP chat panel ...`, bug fix `fix(acp): parse session/update content as ContentBlock, not string`). ### Why The terminal currently runs `bash` (the shell subsystem). The `opencode` process is started via the toolbar and is meant to be controlled by an ACP client — the same protocol that editors like Zed use to talk to coding agents. Without an ACP panel, the opencode process is invisible: it has a PID and a status indicator, but no way to send it prompts or read responses. ### Scope 1. **Backend: switch the opencode process to ACP mode** - Default `opencodeCommand` stays `opencode`; new `process.args` field defaults to `["acp"]` so the launched command is `opencode acp`. Configurable via `configs/config.yaml` and the `CODESPACE_OPENCODE_ARGS` env var. - The `internal/process` package still captures stdout/stderr and exposes stdin via the WebSocket. ACP over stdio sits on top in the new `internal/acp` package — no transport changes to the existing process WS route. 2. **Backend: ACP-aware HTTP API** - Implemented as four HTTP routes per ACP method. The frontend does not need to know JSON-RPC. - Routes: - `GET /api/workspaces/:id/acp/status` — observational: `{workspaceId, ready, sessionId, running, pid, error}`. Does NOT start the process. - `GET /api/workspaces/:id/acp/history` — accumulated `{sessionId, messages: [{role, text, time}]}`, oldest first. In-memory only. - `POST /api/workspaces/:id/acp/prompt` — body `{content: string}`. Returns `{sessionId, stopReason, text}`. Starts the process + session on demand (synchronous, 5-min default timeout). - `POST /api/workspaces/:id/acp/cancel` — best-effort interrupt. 3. **Frontend: ACP panel** - Implemented as `web/src/components/acp/AcpPanel.tsx` with subcomponents `MessageBubble`, `MarkdownView`, `ThinkingIndicator`. Renders markdown with code-block highlighting (react-markdown + react-syntax-highlighter Prism oneDark), with auto-scroll, error toast fade, and a "thinking…" indicator while in flight. - Hooks: `useAcpStatus` (3s poll), `useAcpHistory` (5s poll), `useAcpPrompt` (mutation), `useAcpCancel` (mutation). 4. **Frontend: integration with the workspace shell** - Bottom panel converted to a tabbed area: `Terminal` / `Agent` (decided on **Tabs + Sibling tab**, not replace, not split). Tab state lives in `workspaceUiStore.bottomTab`. - `StatusBar` shows `agent: ready` / `initializing…` / `` pill when the ACP session is initialized; hides when not. - The existing `process/*` routes and raw process WebSocket remain untouched (the new acp routes are additive). ### Concrete tasks — all done 1. ✅ Switched opencode default to `opencode acp` via `process.args`. 2. ✅ Added `internal/acp` package: NDJSON transport + JSON-RPC 2.0 client (NDJSON framing with split-line buffering, request/response correlation, notification dispatch, per-workspace `Client` + `Service`). 3. ✅ Added `internal/api/acp_handler.go` with the four routes. 4. ✅ Added `web/src/lib/api/acp.ts` with the four hooks. 5. ✅ Added `web/src/components/acp/AcpPanel.tsx` + subcomponents. 6. ✅ Added `react-markdown` + `react-syntax-highlighter` + `remark-gfm` to `web/package.json`. 7. ✅ Wired the ACP panel into `WorkspaceShell.tsx` as a tabbed bottom panel. 8. ✅ Documented the ACP routes in `README.md` (section + env var + example curl). ### Tests - `internal/acp/client_test.go` covers NDJSON split-lines, request/response correlation, notification dispatch, and agent-initiated request handling for `fs/*` (real dispatch) and `terminal/*` (MethodNotFound). - E2E smoke test against the live `opencode acp` binary: created a workspace, sent a prompt, received `text: "Hi there!"` non-empty, history has 4 messages (1 user + 3 agent chunks), 0 `invalid session/update` log entries. ### Out of scope (deferred to v2) - Streaming responses over WebSocket (v1 is single round-trip per prompt). - Tool-call approval UI. - Multiple agents / agent switching. - Authentication. - Cross-workspace agent memory. - ACP session persistence across opencode restarts (history is in-memory and cleared on process restart — acceptable for v1). - `terminal/*` agent tool calls (return `MethodNotFound -32601`; the agent will fail those tool calls gracefully).