Skip to content

feat: direct acpmux React agent pane - #16203

Draft
teamleaderleo wants to merge 40 commits into
feat/acpmux-ts-pane-basefrom
feat/acpmux-ts-pane-direct
Draft

teamleaderleo wants to merge 40 commits into
feat/acpmux-ts-pane-basefrom
feat/acpmux-ts-pane-direct

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Sep 30, 2026 •

Copy link
Copy Markdown
Collaborator

This PR carries the React TypeScript agent pane over a direct authenticated acpmux WebSocket client. Swift hosts WKWebView and provides the endpoint, token, and initial session. React attaches, folds the versioned event stream, pages history, handles permissions and queue state, and sends ACP actions directly. Native remains the default renderer.

The renderer uses Pretext-style measurement, memoized row versions, typed-array geometry, binary-search virtualization, scroll anchoring, registry-based React row components, and hot-reloaded theme, layout, and user renderers. The standalone preview includes Claude and Codex recordings, real-speed streaming replay, seeded 5,000-row transcripts, permission and queue fixtures, theme controls, width controls, and fling timing.

Base and recovery

This PR uses the owned base branch feat/acpmux-ts-pane-base, which contains the pre-React acpmux pane snapshot. It does not use or update Lawrence's branches.

The earlier PR #16042 was opened against the wrong stacked base and auto-merged into that parent. This replacement PR is the direct-to-acpmux implementation on an owned base so it can be reviewed and merged independently.

The projections RFC is https://github.com/manaflow-ai/cmuxterm-hq#1051: acpmux owns sessions and event history, Swift hosts, and React and native are both clients.

Preview

cd webviews
bun run preview:dev
bun run preview:build

Static output: webviews/dist/acpmux-agent-session-preview/.

Validation

  • bun test src/agent-session/acpmux/model.test.ts src/agent-session/acpmux/direct.test.ts (8 passed)
  • bun x tsgo --noEmit
  • ./scripts/build-agent-session-web.sh
  • ./scripts/build-webviews-app.sh --check
  • Swift package tests require macOS CI because this Linux host cannot import the package's existing Darwin dependency.
  • Lawrence's native seeded-row fling reference is p50 and p95 8.33 ms at 120 Hz. Comparable TypeScript numbers still require macOS or fleet measurement.

Changelog

Added: React TypeScript agent pane over a direct authenticated acpmux event stream, with a standalone preview harness.


Summary by cubic

Adds a React TypeScript agent session pane that renders a direct authenticated acpmux WebSocket stream. Swift stays the WKWebView host and passes the authenticated loopback endpoint, per-launch token, and selected session through a new versioned bridge; React pages the event stream, merges in-flight events with paged history, creates sessions, merges daemon model, mode, and config catalogs, handles prompt acknowledgements and permission and queue state, sends ACP actions, and routes native-only actions (copy, open URL, open file, focus) back through the host bridge.

Lifecycle hardening ignores stale attach replies, session selections, and history pages, persists new sessions before prompting, settles optimistic sends, preserves tool update metadata, computes turn durations, pairs turn summaries without duplicate rows across daemon versions, preserves turn boundaries and duplicate queued prompts with their session defaults, retains implicit turn rows during history replay, keeps fallback transcript events visible during reconnects, and keeps non-edit tool activity visible alongside edited-file details. Every session change reopens the transcript at its latest turn, and the composer stays ready across live snapshots. The transcript uses Pretext measurement aligned with the rendered markdown blocks, coalesces streaming thoughts, binary-search virtualization, memoized rows, cached prepared markdown blocks, code copying, and LCS-based edited-file diff counts. Native rendering remains the default.

Renderer selection

  • New app.agentSession.renderer config selects native (default) or TypeScript for new agent session panes; the catalog key placement mirrors the schema nesting so validation stays consistent.
  • The session picker refreshes whenever the daemon session list changes, even if the selected session is unchanged, and new agent panes created from command-line tokens now resolve to the configured renderer instead of hardcoding React.

Preview

  • Standalone preview at webviews/src/agent-session/acpmux-preview replays recorded Claude and Codex streams with seeded 5,000-row transcripts, permission and queue fixtures, and theme and width controls.

Written for commit 00937c1. Summary will update on new commits.

Review in cubic

teamleaderleo and others added 13 commits September 30, 2026 13:22
Add the versioned Swift bridge, React transcript renderer, Pretext layout model, customization registry, and standalone preview harness. Keep native rendering as the default.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Move transcript projection and ACP actions into the React client. Keep Swift as the WKWebView host and pass an authenticated loopback endpoint through the versioned handshake.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Handle permission envelopes, settle optimistic prompts, and reset streaming rows between turns. Install the webview lockfile before bundling Pretext resources in CI.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Merge in-flight events with attach pages, reconcile legacy prompt echoes, and mark rejected sends failed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Sep 30, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Autopilot is currently an internal CodeRabbit preview.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@blacksmith-sh

This comment has been minimized.

@github-actions

github-actions Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

CI failure attribution

CI failed on 00937c1a6e (run 36794029609 attempt 1): 1 code.

Job Verdict Why
guards / workflow-guard-tests / preflight code a Python test failed
Matched log lines
guards / workflow-guard-tests / preflight: FAIL: test_every_advertised_path_is_supported (__main__.ConfigurationReviewPathsTests.test_every_advertised_path_is_supported)

Not re-run automatically: guards / workflow-guard-tests / preflight is not a machine failure.

Written by scripts/ci/classify_failures.py (ci-failure-attribution.yml); signatures are its SIGNATURES table. A machine verdict is the runner's fault, not this PR's.

@socket-security

socket-security Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addednpm/​marked@​17.0.51001001009880
Addednpm/​@​chenglou/​pretext@​0.0.91001009990100

View full report

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review at 74231d5: PASS. The fresh review covered direct.ts, App/model, Swift host bridge and session persistence, generated resources, preview fixtures, and purge, selection, reconnect, and attach races. The owned base has no Lawrence ancestry.
Fixed: the replacement preserves the direct acpmux client, generated bundle parity, preview harness, and lifecycle repairs from the merged implementation.
Left: Swift package tests and comparable macOS fling numbers require CI or fleet validation.

teamleaderleo and others added 2 commits September 30, 2026 13:41
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

Dogfood tours of 00937c1a

sidebar-and-chrome-tour at 00937c1a: not run

skipped: CI left no app build for this head (its compile failed or was cancelled)

Tours are picked by the paths globs in dogfood/scenarios/*.json; a Dogfood-tours: a, b line in the description picks them instead (none turns this off). Look at every frame before merging: a green tour only means no step failed.

teamleaderleo and others added 3 commits September 30, 2026 14:15
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@blacksmith-sh

This comment has been minimized.

teamleaderleo and others added 5 commits September 30, 2026 14:46
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Emit snapshots for session-list changes even when the selected session is unchanged, so the picker stays current for sessions created or purged elsewhere.\n\nCo-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Handle prompt acknowledgements, preserve tool update metadata, compute turn durations, and reset session-local reducer state. Restore the compiled Tailwind asset pipeline and align markdown measurement with the rendered blocks.\n\nCo-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Pair turn_end and turn_result summaries without duplicate rows, preserve duration and state across session resets, and account for code block padding in precomputed geometry. Keep fallback transcript events visible during reconnects.\n\nCo-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Merge daemon model catalogs, expose new-session creation, and show edited-file diff counts. Add code copying and keep the generated web assets aligned with the React renderer.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
teamleaderleo and others added 5 commits September 30, 2026 15:20
Ignore stale history responses after session changes and keep non-edit tool activity visible alongside edited-file details.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Use an LCS line diff for ACP edit blocks so replacement changes report both additions and deletions accurately.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Reuse a pending turn-end summary when a later turn result supplies the turn id, avoiding duplicate transcript cards across daemon versions.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Keep the shell, scroller, spacer, thread, row, composer, and markdown geometry rules in the source and generated WebKit assets.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Reset virtual transcript anchors when the selected session changes so each session opens at its newest content.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@blacksmith-sh

This comment has been minimized.

teamleaderleo and others added 7 commits September 30, 2026 15:56
Use the app section prefix required by the settings catalog so CmuxSettings validation and generated config schema stay consistent.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Move agentSession.renderer under app in the public and embedded cmux.json schemas so the catalog key and schema validation agree.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@blacksmith-sh

This comment has been minimized.

teamleaderleo and others added 3 commits September 30, 2026 16:42
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@blacksmith-sh

This comment has been minimized.

teamleaderleo and others added 2 commits September 30, 2026 16:56
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
teamleaderleo added a commit that referenced this pull request Oct 1, 2026
…ry in sync with the daemon (#16426)

* Agent pane: failing tests for picker refresh, history paging, socket readiness, lag recovery and select reset

Seven client tests drive AcpmuxDirectClient over a scripted socket. All
fail on this commit: an unselected purge leaves the picker stale, history
reattaches instead of paging _acpmux/events, a request on a closed socket
resolves silently, _acpmux/lagged is ignored, and select keeps the old
session's queue, summary and permission.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RYQHfug1ZVQDp4eWgwVUtD

* Agent pane: refresh the session picker on every session-list change

sessionChanged emitted only when the selected session changed, so a
session created, updated or purged elsewhere left the picker stale until
some other event. It now emits after every list mutation, including the
unselected purge branch. Ported from #16203 (0b8b161).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RYQHfug1ZVQDp4eWgwVUtD

* Agent pane: select resets all of the previous session's client state

select cleared only rows, sequence, turn, streaming and permission, so the
old session's queue, summary, optimistic prompt rows, superseded IDs,
message mapping and assistant message ID lingered until the new attach
replaced some of them. One resetSessionState helper now does the full
reset for select, the open missing-session path and the selected purge
path.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RYQHfug1ZVQDp4eWgwVUtD

* Agent pane: reject requests on a closed socket and recover from lag

request sent through socket?.send and waited forever when the socket was
absent or not open. It now rejects at once. The client also handles
_acpmux/lagged: it fetches _acpmux/events after the last seen sequence,
drops the reply if the session or selection generation changed, and
merges the missed events into the transcript instead of clearing it.
rebuild keeps optimistic rows for prompts still in flight, so a lag
replay no longer blanks a prompt the user just sent; the lag test now
covers that.

Ported from #16203 (a974f73, 8fc1387). The reconnect test's fake
socket gains readyState so the guard sees an open socket.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RYQHfug1ZVQDp4eWgwVUtD

* Agent pane: page history through _acpmux/events instead of reattaching

loadOlder reattached with beforeSeq, which replaced the live summary and
queue with the attach reply and rebuilt away the pending permission. It
now asks _acpmux/events for the page before the first loaded sequence,
captures the session and selection generation first and drops the reply
if either changed, merges the older events, and restores the live
summary, queue and permission after the rebuild. History stops when the
daemon reports no more, returns an empty page, or reaches sequence 1.
attach loses its now-unused beforeSeq parameter.

Ported from #16203 (8fc1387, guard from 4d91ad2).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RYQHfug1ZVQDp4eWgwVUtD

* Agent pane: rebuild the bundled page after the session-state follow-ups

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RYQHfug1ZVQDp4eWgwVUtD

* Agent pane: failing tests for the daemon's real lagged and history shapes

The acpmux daemon sends _acpmux/lagged as {sessionIds, watch, dropped}
(agent-gui) or {dropped} (older daemons), never {sessionId}, and ends
_acpmux/events pages with `more`, not `hasMore`. With the real shapes the
client ignores every lag notice, stops lag recovery after one page,
leaves the picker stale after a watch lag, and keeps offering older
history after `more: false`. Six tests fail here.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RYQHfug1ZVQDp4eWgwVUtD

* Agent pane: follow the daemon's real lagged and history shapes

Lag recovery read a sessionId the daemon never sends, so it never ran.
It now resyncs the selected session when the notice lists it, or when
the notice has no sessionIds (older daemons send only dropped), pages
_acpmux/events until `more` is false, and rereads the session list when
the watch stream lagged. History paging reads `more` instead of
`hasMore`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RYQHfug1ZVQDp4eWgwVUtD

* Agent pane: failing tests for lag paging past live events and lag before attach

Lag recovery pages from this.lastSeq, which live events advance between
pages, so a live event that lands mid-resync makes the next page skip the
rest of the gap. A lag notice that arrives while a newly selected
session's attach is in flight resyncs from seq 0. Both tests fail here.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RYQHfug1ZVQDp4eWgwVUtD

* Agent pane: page lag recovery from its own cursor and wait for attach

The resync loop now advances a local cursor to the newest seq of each
page instead of reading lastSeq, which live events move ahead mid-resync.
A lag notice is ignored until the selected session's attach reply has
landed, since that reply already carries the latest events and there is
no cursor before it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RYQHfug1ZVQDp4eWgwVUtD

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
@azooz2003-bit azooz2003-bit reopened this Oct 6, 2026
@azooz2003-bit azooz2003-bit reopened this Oct 6, 2026
@blacksmith-sh

blacksmith-sh Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

Found 2 test failures on Blacksmith runners:

Failures

Test View Logs
test_every_advertised_path_is_supported (main.ConfigurationReviewPathsTests.test_ev
ery_advertised_path_is_supported)/
test_every_advertised_path_is_supported (main.ConfigurationReviewPathsTests.test_ev
ery_advertised_path_is_supported)
View Logs
test_list_supported_matches_schema_settings_paths (main.SupportedPathsTests.test_li
st_supported_matches_schema_settings_paths)/
test_list_supported_matches_schema_settings_paths (main.SupportedPathsTests.test_li
st_supported_matches_schema_settings_paths)
View Logs

Fix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.

This branch has not been deployed

No deployments
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