Skip to content

Fix ptmux previews and app session restoration - #1

Draft
JackiMa wants to merge 34 commits into
gema/latest-ptmuxfrom
gema/ptmux-preview-links
Draft

JackiMa wants to merge 34 commits into
gema/latest-ptmuxfrom
gema/ptmux-preview-links

Conversation

@JackiMa

@JackiMa JackiMa commented Sep 27, 2026 •

Copy link
Copy Markdown
Owner

Remote tmux links could not create a browser or file preview beside the mirrored terminal, and the app excluded connected tmux workspaces from its saved session. This change opens previews in a shared local pane and reconnects saved remote workspaces to their existing tmux panes when the app reopens.

Changes

  • On tmux 3.2a, use window-size latest and explicit focus/input handoff. Background geometry, reconnect replay and terminal protocol replies remain passive. Returning to cmux reclaims its current size even when dimensions are unchanged; native input or reported focus can reclaim a wider grid. Projected session panes and standalone window panes share the control mutation path. The running server enables focus-events; the global window-size default and tmux.conf remain unchanged. Selecting a cmux tab also changes the shared remote session's selected window.
  • Let file reads reuse the terminal SSH master and fall back to a non-interactive connection when its session channels are full or its socket is unavailable. Preserve destination, identity, configured proxy and host-key policy; clear configured port forwards on file-read connections. Browser forwarding keeps its existing master-only behavior.
  • Resolve absolute remote file paths independently of the terminal directory. For relative paths, query the clicked tmux pane’s current directory at click time, including when its cached directory is missing or stale. Report the resolved missing path without searching other directories. The download no longer needs remote Python.
  • Keep remote tmux windows in their terminal strip while browser and downloaded-file previews share a local pane. Preserve focus, local preview ordering, and the separation between preview and remote terminal ownership. File errors include the resolved remote path.
  • Save the SSH destination, identity-file path, tmux session, selected window, and original remote localhost browser URLs. Restore terminal displays without replaying saved commands locally; reconnect after the workspace graph is installed, subject to managed connection policy. Reuse the saved workspace and allocate fresh browser forwarding ports. An unavailable host retains its saved attachment target for retry.
  • Restore a valid bound agent directly on Workspace and Dock restore paths, without requiring process restore admission (c7ac3bcd). Historical shell records still require explicit continuation. This follows the user's rule that a valid window binding should restore; the newer sizing work preserves the old running app and its agents.
  • Strip Grok new-session/fork selectors from resume commands and retain explicit empty Claude variadic values (for example --tools '') through capture and replay.
  • Classify unavailable process censuses as retryable admission failures, using the CLI's existing bounded retry. Actual corrupt hook stores remain nonretryable, and no launch is admitted before complete ownership evidence is available.
  • Refresh Codex hook and restore identity only for a confirmed newer process when an old process left prompt depth behind. Same-process and unverifiable starts still cannot erase an active turn; idle resumed sessions remain eligible for the next reopen without a new prompt.
  • Package the SwiftPM localization bundle beside the embedded CLI so help and config validation work on cold and cached builds.
  • Document the project map, initialization, link path resolution, SSH forwarding, and session recovery in docs/ptmux-preview.md.

Current sizing verification

  • Current source: 4fe03a81d7. The legacy sizing regression was committed before the implementation (fac4378d3b → 0911998ef6); it failed with six assertions against a real, isolated tmux 3.2a server before passing. An actual app projection then exposed a missing session-owner control path. Its test-only commit dd0ae277fd failed four checks; cc9a5fcd4c routes session focus/text/key actions through the window owner.
  • The final focused run passed 26 tests across three suites, with zero failures and zero skips, against tmux 3.2a. A separate repeat of the real-server legacy test passed. Two earlier fixed runs failed an additional peer command after the intentional window-close step; this fixture's fake peer transport has no production respawn. The final fixture ends that scenario at the batch-owning client's reply fence. Focus/text/key, native-width, background replay, reconnect and the earlier replacement-client detach check remain; command/error diagnostics are retained. Final test result: /tmp/cmux-latest-sizing-session-final.xcresult; repeat: /tmp/cmux-latest-sizing-session-final-repeat.xcresult.
  • A real native PTY client on tmux 3.2a passed: cmux claim 139 columns → native key 188 → background replay stays 188 → unchanged cmux reclaim 120 → native focus-in 188. The committed probe uses an isolated -L server and cleans only its own server. An earlier forced-legacy run also passed with tmux 3.7c; the final session-owner follow-up was verified on the reported 3.2a server.
  • The final tagged app passed real AppKit frame and projected surface.focus checks on two remote windows: native 188 columns survives background resize; cmux focus reclaims 90; grow/shrink reaches 110 → 68; second-window focus and return both converge to 68. Every selected window's server grid equals its pushed viewport and every pane's rendered grid equals its assigned grid. A real native PTY focus-in then reclaims 188, and another projected cmux focus immediately reclaims unchanged 68. This uses API focus and actual AppKit frames, not a physical mouse drag. Records: /tmp/cmux-latest-sizing-runtime-results.json and /tmp/cmux-latest-sizing-runtime-native-focus.json. The disposable remote session and native peer were removed; only the owned test-mode app was stopped.
  • Localization: eight catalogs, nine supported macOS locales, zero parity errors; no new user-facing strings. Test wiring check passed for 1,050 direct files. git diff --check passed.
  • Standalone tagged rebuild succeeded on pushed 4fe03a81d7, tag ptmux-latest-sizing. The matching CLI reports cmux 0.64.25 (106) [4fe03a81d]; existing global CLI links were preserved. Build logs: /tmp/cmux-latest-sizing-final-tagged-build.log and /tmp/cmux-reload-ptmux-latest-sizing.log. This is local build/test evidence, not a claim that GitHub required CI or physical GUI dogfood passed.
  • Normal tagged launch is blocked by the project's development-account credential check on this machine. App protocol/geometry checks use the project's isolated UI-test mode, with saved-session restore disabled. The test-only SSH override skips ptmux restore/names discovery and resolves /usr/bin/tmux to expose its uniquely named disposable fixture; SSH transport, server, control protocol, AppKit geometry and Ghostty surfaces are real. No SSH keys/configuration or persistent ptmux registration is changed. Desktop automation reported Sky Computer Use native pipe startup failed; physical mouse dragging and screenshot/pixel review were not verified this turn. The existing old-tag app remains running; no user agent was deliberately terminated or migrated. This is a draft, not merged, and awaits user dogfood.

Earlier verification (prior revisions)

  • The SSH-channel follow-up passed 21 tests across five suites. A read-only live probe first reproduced Session open refused by peer on the already saturated terminal master, then the fixed fetcher downloaded the real PNG by absolute and relative paths with matching SHA-256. The production link-coordinator test also downloaded the PNG, placed the previews, and received HTTP 200 from the real web service. Both live checks executed. The new regression commit failed with the original error before the fix.
  • Regression tests were committed before the preview routing, CLI resource, agent recovery, remote workspace snapshot, Grok selector, Claude empty-argument, transient admission, and Codex process-generation fixes. Each failed before its implementation change.
  • The focused recovery and remote workspace run passed 49 tests across six suites: RemoteTmuxSessionSnapshotTests, RemoteTmuxPreviewRoutingTests, RemoteTmuxMirrorLifecycleTests, TerminalRecoveryTests, DeferredAgentResumeIndexFallbackTests, and AgentRestoreLiveOwnerAdmissionTests.
  • The launch-argument run passed 44 tests across three suites. The admission/recovery run passed 31 tests across three suites, and the correctly targeted RestoreAdmissionRetryPolicyTests run passed four tests. The new transient-census test failed with the old nonretryable result before the fix; corrupt-store and live-owner behavior remain covered.
  • The packaged CLI hook suite passed 15 tests, including completed, idle-with-depth, and interrupted prior-process records. The two stale-depth cases failed with the original code; same-process stale callback coverage remains passing.
  • The follow-up file-path run passed 19 tests across four suites, with the live SSH test executed. It verifies the real PNG via an absolute path paired with a nonexistent cwd and via relative paths with stale or missing cached cwd, plus pane placement, SHA-256 equality, and the existing web preview. The new absolute-path test failed before the implementation fix.
  • A separate live SSH run passed eight tests across two suites, including the opt-in RemoteTmuxPreviewIntegrationTests (executed, not skipped). The production terminal-link coordinator fetched the requested PNG with a matching SHA-256, forwarded the real localhost service with HTTP 200 and the expected TensorBoard content, and placed both previews in one local pane. Its uniquely named test tmux session was removed afterward.
  • An actual app quit/reopen restored the saved remote workspace without an explicit connection command. The workspace UUID, remote session/window/pane IDs, shell PID, and Node PID remained unchanged.
  • tests/test_build_app_bundled_resources.sh passed five cases. Earlier tagged app CLI help and config validation passed without a resource-path override.
  • Earlier GUI checks displayed TensorBoard run data and the PNG in the tagged app. The new live integration test exercises the production link coordinator; it does not synthesize a physical Cmd-click gesture.
  • During the earlier recovery checks, the old-tag app and its two Codex processes and one Grok process were kept running. No active old-tag agent was migrated or restarted by this work. Recovery snapshots and explicit continuation instructions were saved privately.
  • Test wiring includes 1,049 direct test files. Project normalization and catalog validation pass: eight catalogs, nine required locales, no new or changed localization keys. The latest SSH-channel diff audit passed with no new or changed keys. An earlier localization diff tool run flagged two pre-existing parser limitations in CLI/cmux.swift; manual diff review confirmed this fix changes only a predicate and comments, with no localization expressions changed. Focused Swift tests use English to accommodate two pre-existing bracket-shape assertions.

The earlier standalone build and session-reopen checks below ran on 1f100fd690. The file-path build ran on 1821c92f62. The SSH-channel follow-up was built on 10f0189718; the earlier smallest width follow-up was on 558f281da4, superseded by the latest-interaction implementation below. That earlier app was reopened. After a final app quit/reopen, the three isolated real Codex, Claude, and Grok CLI fixtures resumed automatically with their original session IDs and new process IDs. Codex displayed its original reply, Claude and Grok retained their original prompt histories, and the next saved snapshot classified all three as running agents. No new prompt was sent to make Codex restorable. The remote workspace also reattached to its original tmux pane without a connection command. These fixtures do not migrate the old-tag user's live sessions.

The separately approved machine-specific SSH change allows only the designated preview destination and restricts reverse listeners; a different destination port remains denied. Private identity material, host coordinates, and session backups are not included in this PR. No v2 socket method or remote relay allowlist was added.

Browser separation follows the approach in manaflow-ai#9861; Chanh Nguyen is credited as a coauthor. This draft targets the customized fork branch.

Earlier preview and restore work: MochiSpindle (reservation pending at that handoff).

— OtterGauge · pending
Run: run_cmux_latest_size_0f15b5921db54edc8c6befde7157cd49
Session: 01a0e881-cd17-7892-927d-fcf86e1ad491
Intention: make legacy remote tmux sizing follow explicit focus/input while preserving live sessions.

JackiMa and others added 2 commits September 27, 2026 12:37
Keep remote window tabs in their own pane, allow scoped browser and file preview splits, and report the resolved remote file path on failure.

Co-authored-by: Chanh Nguyen <channguyen@nvidia.com>
@JackiMa JackiMa changed the title Fix remote tmux browser and file previews Fix ptmux previews and confirmed agent recovery Sep 27, 2026
@JackiMa JackiMa changed the title Fix ptmux previews and confirmed agent recovery Fix ptmux previews and app session restoration Sep 27, 2026
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.

1 participant