feat: shared PaneHeaderActions + chat-resolve WorkspaceState fix (v2.7.7)
In-flight workspace UX work. - Extract a shared PaneHeaderActions cluster (+/Split/Reopen/History/Close) used by ChatTabBar + the Workspace coder/terminal pane headers, replacing the divergent per-header copies; SessionLandingPage history + useWorkspacePanes tweaks. - Fix coder-side correctness bug: resolveChatId read sessions.workspace_panes as a bare WorkspacePane[] but v2.6.5 widened it to a WorkspaceState envelope, so it mis-read panes and clobbered tabNumbers/nextTabNumber/closedPaneStack on every pane-chat write. New normalizeWorkspaceState handles either shape and preserves the envelope (+ regression test). - CLAUDE.md doc-sync (coder vitest suite, deploy-by-surface, dual-remote push, in-flight-web-WIP staging, release-branch naming). Web tsc + coder build + coder tests green. Builds on v2.7.6. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -640,13 +640,23 @@ export function useWorkspacePanes(sessionId: string): UseWorkspacePanesResult {
|
||||
const showLandingPage = useCallback((paneIdx: number) => {
|
||||
setPanes((prev) => {
|
||||
const pane = prev[paneIdx];
|
||||
// Coder/terminal panes are not chat hosts — history button is chat-only.
|
||||
if (!pane || pane.kind === 'coder' || pane.kind === 'terminal') return prev;
|
||||
if (!pane) return prev;
|
||||
const next = [...prev];
|
||||
next[paneIdx] = { ...pane, kind: 'empty', chatId: undefined };
|
||||
if (pane.kind === 'coder' || pane.kind === 'terminal') {
|
||||
// Scoped panes don't host chat tabs. Leaving one for the session
|
||||
// history closes it: drop the pane→chat binding, and for terminals
|
||||
// kill the tmux session (terminals are ephemeral — closing = killing,
|
||||
// mirroring removePane).
|
||||
if (pane.kind === 'terminal') {
|
||||
api.terminals.kill(sessionId, pane.id).catch(() => { /* non-fatal */ });
|
||||
}
|
||||
next[paneIdx] = { ...pane, kind: 'empty', chatId: undefined, chatIds: [], activeChatIdx: -1 };
|
||||
} else {
|
||||
next[paneIdx] = { ...pane, kind: 'empty', chatId: undefined };
|
||||
}
|
||||
return next;
|
||||
});
|
||||
}, []);
|
||||
}, [sessionId]);
|
||||
|
||||
const addSplitPane = useCallback((kind: 'chat' | 'terminal' | 'coder'): string | null => {
|
||||
// Generate the id outside the updater so we can return it deterministically.
|
||||
|
||||
Reference in New Issue
Block a user