Skip to content

Make the surface layer kind-agnostic #641

Description

@jeremybower

What problem does this solve?

This is the foundation track of #500 (in-app browser), split out per the discussion there. It supersedes #536, whose three commits (content-agnostic split-tree leaf, focus lifecycle and pane drag-and-drop lifted above the leaf) solved the view seam and carry over as the base of this work.

As established in the #500 thread, #536 alone leaves a second surface kind as a drop-in replacement for GhosttySurfaceView rather than a first-class citizen: the tab/split/lifecycle layer still speaks a terminal-shaped vocabulary. Terminal-only commands and events (blocking scripts, binding actions, scrollback search, agent hooks) live in the shared client enums beside neutral lifecycle verbs; per-worktree state interleaves generic tree/tab/focus management with terminal specifics (Ghostty view map, zmx sessions, script tracking); and the persisted layout leaf is terminal-only. A browser pane would only "work" by quietly no-oping terminal concepts, and every additional kind would thread more kind-checks through the shared switches.

@sbertix asked for this refactor before any browser work proceeds: "refactoring existing reducer with agnostic actions, improving state management (especially efficiency-wise) [...] so that whatever we build next (browser, file viewer, etc) can truly stand its ground and not just serve as a drop-in replacement of <GhosttySurfaceView>."

Proposed solution

Make the tab/split/lifecycle layer speak surface-neutral verbs, with terminal-only concepts behind a per-kind seam -- across commands/events, per-worktree state, layout persistence, and the reducer -- and rename the load-bearing types to match what they now are. Ships no user-visible change: terminal behavior stays identical, and the PR is reviewable purely as "terminal behavior unchanged + is this the right seam."

Acceptance bar, as agreed in #500:

  1. Agnostic actions -- the shared layer never enumerates kinds; kind-specific behavior sits behind one arm per kind ("at least far enough so leaf != terminal (U browser)").
  2. No state multiplication -- the per-kind layer must not regress performance or grow what's held per worktree for kinds that aren't present.
  3. Third surface is virtually free -- a new kind touches only its own module plus a registration case at each dispatch point, minus the surface-specific logic and UI. Zero edits inside existing arms.

The real acceptance test for the seam is the follow-on browser POC, which must add its kind by touching only its own module plus the registration cases.

Alternatives considered

Supacode version

current main

Are you planning to build this yourself?

  • I intend to open a pull request once this is approved and marked ready.

Before submitting

  • I searched existing issues and this is not a duplicate.
  • I understand feature pull requests are closed until the issue is marked ready.
  • I agree to follow this project's Code of Conduct.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestreadyApproved for a pull request. Added by a maintainer once an issue is triaged.

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions