feat: chat workspace mode integrated with the-controller-daemon#541
Merged
Conversation
Design for a new 'chat' workspace mode in the Tauri app that renders the-controller-daemon sessions as structured messages, alongside the existing development and agents modes. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Step-by-step TDD plan (21 tasks) for adding a 'chat' workspace mode to the Tauri app that integrates with the-controller-daemon. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
jsdom@27.4.0 and later pull in CJS packages (html-encoding-sniffer@6, whatwg-url@16, cssstyle@5) that internally require() ESM-only dependencies (@exodus/bytes, @csstools/css-calc@3), which crashes vitest fork workers with ERR_REQUIRE_ESM and prevents any test from running. jsdom@26.x predates that dependency refactor and still uses CJS-compatible html-encoding-sniffer@4 and cssstyle@4, restoring a working test suite. Revisit this pin when the upstream packages are republished with proper conditional exports (or dual CJS/ESM builds) that don't mix CJS require() with ESM-only modules. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Task 12 of the chat mode implementation plan. Adds a modal for creating daemon-backed chat sessions from a project row. Includes agent dropdown, optional initial prompt, 422 inline error handling, and a shared `newChatTarget` field on the daemon store so Sidebar and ChatWorkspace can coordinate. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add ChatView (header + transcript area) that hydrates from readEvents on mount and opens a WS stream; Transcript renders finalized agent/user text plus in-progress delta blocks. ChatWorkspace now mounts ChatView when a session is active and shows an empty-state prompt otherwise. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds ToolApprovalBlock which renders Approve / Deny / Deny-with-reason
controls beneath a pending tool_call. Transcript now detects pending
approvals via statusState === 'waiting_for_tool_approval' and a missing
tool_result for the tool_call, and forwards sessionId to the block.
Clicks send { kind: 'tool_approval', call_id, approved, reason? } via
DaemonClient.sendMessage. Buttons disable while the request is in flight.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Task 17 of the chat mode plan. Adds a textarea input mounted below the transcript in ChatView. Cmd/Ctrl+Enter sends user_text via DaemonClient; Esc sends interrupt only when statusState is working, starting, or waiting_for_tool_approval. Textarea disables itself when the session is ended or failed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add classifyError helper that maps DaemonHttpError status codes and network/unknown errors into a stable ErrorKind union. Wire into ChatView.onMount (clean up session + toast on 404) and ChatInput.sendText (banner on 409 session_ended, toast otherwise). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Extend HotkeyManager so j/k walks through projects and their daemon chat sessions in chat mode, and Enter on a focused chat session sets daemonStore.activeSessionId (instead of the PTY focus-terminal path). - getVisibleItems gains a chat branch that lists daemon sessions whose cwd matches each project's repo_path. The "+ New chat" row is intentionally not keyboard-walkable for v1. - navigateItem and the Enter (expand-collapse) handler route to daemonStore.activeSessionId when currentMode === "chat", leaving development and agents behavior unchanged. - Adds a "chat mode navigation" describe block in HotkeyManager.test.ts covering j/k across project + chat session boundaries, PTY sessions being ignored in chat mode, Enter setting daemonStore.activeSessionId, project Enter still toggling expand, and collapsed projects skipping their chats. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Extract mode label to a $derived so chat mode renders as "Chat" instead of falling through to "Development".
Adds chat-mode.spec.ts with:
- An always-runs test asserting Space -> c switches to chat mode and the
DaemonEmptyState ("Daemon not running") is rendered when the daemon is
unreachable; Retry keeps the empty state when still unreachable.
- A skippable suite scaffolded to spawn the real daemon against the
fake_agent binary (from the-controller-daemon project), with beforeAll /
afterAll lifecycle + isolated TCD_STATE_DIR. The test inside is marked
fixme with a clear note: it cannot pass under the browser-based e2e
harness because the Axum test server does not expose
/api/read_daemon_token. Full end-to-end validation is left as a
follow-up once the harness can either run under Tauri or proxy the
daemon-token command.
Adds scripts/chat-integration-daemon.sh: helper with build/run/status
subcommands so contributors can easily produce the daemon + fake_agent
binaries at the paths the spec probes for.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- client.test.ts: cast fetchMock.mock.calls[0] via unknown for type safety - commands/daemon.rs: apply rustfmt's default line wrapping Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
CI's stable clippy now flags sort_by with a full comparator as unnecessary_sort_by; apply the suggested sort_by_key + Reverse form. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
chatworkspace mode (hotkeySpace c) alongsidedevelopment,agents, andkanbanthe-controller-daemon(the HTTP+WebSocket daemon at~/projects/the-controller-daemon/) for structured, typed chat sessions against Claude Code and CodexDesign and plan
docs/plans/2026-04-22-chat-mode-design.mddocs/plans/2026-04-22-chat-mode-plan.mdWhat's inside
Daemon client library (
src/lib/daemon/):model.rsDaemonClient— HTTP wrapper with bearer auth, typed endpointsreduceTranscript(delta accumulation, dedupe, status tracking)SvelteMapfor reactive Map updatesclassifyErrorhelper mapping HTTP status codes to UX kinds (401/404/409/422/503/network/unknown)Rust:
read_daemon_token(reads~/.the-controller/daemon.token, honors$TCD_STATE_DIR)Chat UI (
src/lib/chat/):ChatWorkspace,DaemonEmptyStateChatSessionList(grouped byproject.repo_path),NewChatDialogChatView,Transcript(tool_call/tool_result join by call_id)MessageBlock,UserMessage,AgentMessage(markdown via existingmarkdown.ts; plain text for streaming deltas)ToolCallBlock(collapsed/expand),ToolApprovalBlock(Approve/Deny/Deny-with-reason)ChatInput(Cmd/Ctrl+Enter send, Esc interrupt, disabled when ended)Integration:
WorkspaceModetype, picker entry, hotkey handler,App.sveltebranch,Sidebar.sveltebranch,HotkeyManagernavigation,HotkeyHelplabeltest.fixmepending/api/read_daemon_tokenexposure on the Axum test serverDependencies / infrastructure
jsdomto^26.1.0to fix a pre-existingERR_REQUIRE_ESM(html-encoding-sniffer / @exodus/bytes) that blocked vitest workersFollow-ups
Tracked in #540 — includes: exposing
read_daemon_tokenon the Axum test server (to un-fixme the full e2e), 401 retry-once, "+ New chat" keyboard nav, dedicated Chat help section, quality polish (toast on tool-approval failure, trim whitespace, orphan transcript GC, virtualization).Test plan
pnpm test— 300/300 passcd src-tauri && cargo test— all passpnpm exec svelte-check— no new errors (3 pre-existing on main)🤖 Generated with Claude Code