Skip to content

feat(code): workbench Diff/Files/Terminal tabs per session#3719

Merged
BunsDev merged 1 commit into
mainfrom
feat/code-workbench-tabs
Jul 23, 2026
Merged

feat(code): workbench Diff/Files/Terminal tabs per session#3719
BunsDev merged 1 commit into
mainfrom
feat/code-workbench-tabs

Conversation

@BunsDev

@BunsDev BunsDev commented Jul 23, 2026

Copy link
Copy Markdown
Member

Phase 2 of the dedicated Code surface (cave-k0ua, follows #3716; flag NEXT_PUBLIC_CAVE_CODE_SURFACE).

Replaces the read-only session overview with a per-session workbench:

Tab What Reuse
Diff changed files, unified diffs, commit box, create-PR, checkpoints, per-file revert SessionChangesInner mounted whole, keyed by work root
Files file explorer + preview/editing with Cmd/Ctrl+S save new code-workbench-files.tsx: ProjectTree + RailFilePreview
Terminal session-root pty (same thread as chat rail: cave.rail.<id>) RailTerminalPanel, lazy + keepalive

Header: familiar + project, branch/PR/diffstat chips (attribution-safe per cave-9q24 — workBranch → worktree branch → PR branch, never bare shared-checkout branch), Open in Chat jump.

Scoping: every tab uses codeSessionWorkRoot (worktree root when the session has one, else project root) — now in the pure model with behavioral tests.

Chunking: Files (CodeMirror) and Terminal (xterm) are locally dynamic(); Diff renders immediately.

Chat's code rail untouched (follow-up phase per plan).

Verification

  • pnpm test:app — 891 files ✓ (workbench pins added to code-surface-mode.test.ts)
  • pnpm test:api — 239 files ✓
  • pnpm typecheck

Phase 2 of the Code surface (cave-k0ua, follows #3716). Replaces the
read-only session overview pane with a real per-session workbench:

- code-workbench.tsx — header (familiar, branch/PR/diffstat chips, Open
  in Chat) + Diff | Files | Terminal tab strip. All tabs scope to
  codeSessionWorkRoot (worktree over shared checkout, cave-9q24).
- Diff tab: SessionChangesInner keyed by work root — diffs, commit,
  create-PR, checkpoints, revert (proven panel, reused whole).
- Files tab: new code-workbench-files.tsx composition — ProjectTree +
  RailFilePreview (CodeMirror editing + Cmd/Ctrl+S save included);
  dynamic() so CodeMirror stays out of the surface chunk.
- Terminal tab: RailTerminalPanel, lazy + keepalive once opened; same
  pty thread as chat's rail terminal by design (cave.rail.<sessionId>).
- code-surface.ts: codeSessionWorkRoot moved into the pure model with
  behavioral tests; workbench wiring pinned in code-surface-mode.test.ts.

Deep link ?wtab= now lands on real tabs ('pr' still coerces to diff
until the PR panel tab ships). Chat rail untouched.

Verified: pnpm test:app (891), test:api (239), typecheck all green.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 23, 2026 18:42

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements Phase 2 of the flag-gated Code surface by replacing the per-session read-only overview pane with a per-session workbench that provides Diff/Files/Terminal tabs, each scoped to the session’s correct work root (worktree when present).

Changes:

  • Added codeSessionWorkRoot() and corresponding tests to ensure all workbench tabs scope to the session’s actual work root.
  • Introduced CodeWorkbench (Diff/Files/Terminal tabs) and CodeWorkbenchFiles (ProjectTree + editable RailFilePreview), with Files/Terminal lazy-loaded via dynamic().
  • Updated CodeView to render the workbench for the selected session and forward deep-linked wtab into the workbench.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/lib/code-surface.ts Adds codeSessionWorkRoot() helper to unify workbench scoping to the session’s work root.
src/lib/code-surface.test.ts Adds behavioral coverage for work-root selection and fallback behavior.
src/components/code-workbench.tsx New per-session workbench pane (header + Diff/Files/Terminal tabs, dynamic loading, terminal keepalive).
src/components/code-workbench-files.tsx New Files tab layout wiring ProjectTree to RailFilePreview editing/saving.
src/components/code-view.tsx Swaps session overview for the new workbench and forwards deep-linked workbench tab selection.
src/components/code-surface-mode.test.ts Adds source-contract assertions to pin workbench scoping + dynamic chunking + terminal keepalive behaviors.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +117 to +135
<div role="tablist" aria-label="Session workbench" className="mt-2 flex items-center gap-1">
{TAB_LABELS.map((t) => (
<button
key={t.id}
type="button"
role="tab"
aria-selected={tab === t.id}
onClick={() => setTab(t.id)}
className={`focus-ring inline-flex items-center gap-1.5 rounded px-2 py-1 text-[length:var(--text-xs)] ${
tab === t.id
? "bg-[var(--bg-hover)] text-[var(--text-primary)]"
: "text-[var(--text-secondary)] hover:text-[var(--text-primary)]"
}`}
>
<Icon name={t.icon} width={12} height={12} />
{t.label}
</button>
))}
</div>
@BunsDev
BunsDev merged commit 57ec707 into main Jul 23, 2026
16 checks passed
@BunsDev
BunsDev deleted the feat/code-workbench-tabs branch July 23, 2026 18:51
BunsDev added a commit that referenced this pull request Jul 23, 2026
…3722)

Phase 3 of the Code surface (cave-k0ua, follows #3716/#3719). The
workbench's reserved 'pr' tab becomes real:

- code-session-pr-panel.tsx — stage strip (bead → PR → checks → review
  → merged) via the SAME resolveStageForBranch the work queue and chat
  stage header use, anchored to codeSessionBranch (attributed branch,
  cave-9q24 — never the checkout's current branch).
- Live check runs (/api/github/checks, 30s re-poll while pending) with
  pass/fail counts and details links.
- Review threads (/api/github/comments?isPull=1) with resolve/unresolve
  (POST /api/github/resolve-thread), authed-gated.
- Actions: comment / approve (POST /api/github/review) and squash-only
  merge (POST /api/github/merge) behind a two-click confirm.
- No-PR state points at the Diff tab's Create PR flow.
- Workbench: 'pr' deep-link coercion removed — ?wtab=pr now lands here;
  tab strip gains PR; panel dynamic() + keyed by session id.

Pins: PR-panel wiring added to code-surface-mode.test.ts (stage-model
reuse, attributed branch, API surface, squash-only, confirm-gated merge).

Verified: pnpm test:app (892), test:api (239), typecheck, eslint green.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
BunsDev added a commit that referenced this pull request Jul 23, 2026
Phase 4 of the Code surface (cave-k0ua, follows #3716/#3719/#3722):
the surface goes from read-only to generative.

- code-composer.tsx — Codex-style 'Ask for follow-up changes' box under
  every workbench tab except Terminal. Sends through the sanctioned
  client LLM path (streamFamiliarText → /api/chat/send) RESUMING the
  selected session (sessionId rides), rooted at codeSessionWorkRoot
  (cave-9q24). Streams a compact reply tail with 'Full thread in Chat';
  Stop cancels via /api/chat/stop with the send's runId.
- code-new-session.tsx — '+ New session' modal: project + familiar
  pickers (/api/projects, /api/familiars), optional FRESH worktree
  (existing /api/changes action=create-worktree → .worktrees/<branch>),
  kickoff prompt. The send carries no sessionId (fresh thread, saved
  like any chat); onSession hands the id to the rail immediately while
  the stream keeps flowing server-side.
- code-session-rail.tsx — + New session entry (also in empty state).
- code-view.tsx — pendingNewIdRef guard: a just-created session's
  selection survives until /api/sessions/list catches up (the newest-
  session auto-pick must not clobber it).

Pins added for all of the above in code-surface-mode.test.ts.

Verified: pnpm test:app (892), test:api (239), typecheck, eslint green.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants