v2.0.0: BooCoder frontend — chat pane + diff pane + session picker

Integrates BooCoder as a 'coder' workspace pane within the existing
BooChat SPA at code.indifferentketchup.com. Renamed the placeholder
'agent' pane kind to 'coder' across all types, menus, hooks, and
mobile switcher (Icon: Code instead of Bot).

CoderPane.tsx: split layout with chat area (messages via WS to
boocoder:9502, input bar posting to /api/coder/sessions/:id/messages)
and diff panel (pending changes with Approve/Reject per change plus
Approve All/Reject All). Reuses MarkdownRenderer for message content.

Proxy: Vite dev config adds /api/coder → boocoder:9502 (ordered above
/api per CLAUDE.md proxy-ordering rule). Production: Fastify route in
apps/server/src/index.ts proxies /api/coder/* to http://boocoder:3000
via fetch() pass-through. WS connects directly to :9502 (same
Tailscale network, no proxy needed for WebSocket upgrade).

WorkspacePaneKind mirror updated in both apps/web and apps/server
types. useWorkspacePanes gains coderPane() factory (replaces the old
agent toast stub). Workspace.tsx switch renders CoderPane for
pane.kind === 'coder'.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-25 03:24:49 +00:00
parent 78455b7efc
commit 457c59fb06
11 changed files with 512 additions and 30 deletions

View File

@@ -1,6 +1,6 @@
import { useRef, useState } from 'react';
import {
Bot,
Code,
ChevronDown,
Edit2,
MessageSquare,
@@ -43,7 +43,7 @@ const SWIPE_VISUAL_CAP = 120;
function paneIcon(kind: WorkspacePane['kind']) {
if (kind === 'terminal') return <Terminal size={14} />;
if (kind === 'agent') return <Bot size={14} />;
if (kind === 'coder') return <Code size={14} />;
if (kind === 'settings') return <SettingsIcon size={14} />;
return <MessageSquare size={14} />;
}
@@ -64,7 +64,7 @@ function paneLabel(pane: WorkspacePane, chats: Chat[]): string {
}
if (pane.kind === 'chat') return 'Chat';
if (pane.kind === 'terminal') return 'Terminal';
if (pane.kind === 'agent') return 'Agent';
if (pane.kind === 'coder') return 'Coder';
if (pane.kind === 'settings') return 'Settings';
return 'Empty';
}