Skip to content

Create and refresh local WSL tmux sessions - #91

Merged
wesm merged 17 commits into
rust-portfrom
rust-port-auto-refresh
Aug 9, 2026
Merged

Create and refresh local WSL tmux sessions#91
wesm merged 17 commits into
rust-portfrom
rust-port-auto-refresh

Conversation

@wesm

@wesm wesm commented Aug 9, 2026

Copy link
Copy Markdown
Member
  • Keeps local WSL tmux sessions current when the Ghosthub window regains focus, so sessions created elsewhere appear without a manual refresh.
  • Lets users create the first or an additional local tmux session from the compact + action beside a ready WSL host.
  • Uses one atomic new-session -A ordinary client, then captures the exact WSL runtime, tmux server, session ID, and creation time before publishing the terminal.
  • Preserves the current terminal during refresh and creation, restores it when a new client cannot be established, and never reruns or kills a session after an ambiguous launch.
  • Keeps SSH and remote lifecycle work out of scope.
  • Exercises empty-namespace creation and same-name creation races against isolated real WSL tmux servers; the full Rust workspace, Clippy, architecture contracts, strict docs, and license closure pass.

wesm and others added 2 commits August 9, 2026 06:46
Sessions created outside Ghosthub should appear promptly without turning host discovery into a polling loop. Matching the Swift application's activation-driven behavior keeps discovery responsive while preserving explicit Retry and Connect authority for failed or disconnected hosts.

Reusing the already-admitted host avoids repeating tmux verification each time the window regains focus, and retaining cached rows keeps active navigation usable during the refresh.

Validation: the live WSL workspace suite passed all seven lifecycle cases.

Generated with Codex
Co-authored-by: Codex <noreply@openai.com>
An attach-only client forced users out to another terminal just to bootstrap a local workspace. Let a ready WSL host create or atomically attach to one named tmux session while keeping tmux in charge of process lifetime and preserving the existing terminal presentation during failure.

Creation authority is consumed exactly once and is demoted to ordinary attach identity after live discovery. Races attach to the existing exact-name session, while ambiguous failures never rerun creation or gain cleanup authority.

Validation: isolated live WSL tests created the first session in an empty namespace and proved an external same-name creation race retained the exact existing identity.

Generated with Codex
Co-authored-by: Codex <noreply@openai.com>
@roborev-ci

roborev-ci Bot commented Aug 9, 2026

Copy link
Copy Markdown

roborev: Combined Review (d6ab4a1)

Medium-severity issues remain in WSL session creation and attachment.

Medium

  • rust/workspace/src/lib.rs:2872 — Creation always uses TERM=xterm-256color, while WSL admission guarantees only baseline xterm. If that terminfo entry is unavailable, the client can exit before creating the session, and the attach fallback never runs because discovery has not published the worker. Use xterm for the one-shot command and propagate it into attachment state/notices, or preflight xterm-256color availability before consuming CreateOnce.

  • rust/host/src/wsl.rs:494 — In a creation race, new-session -A attaches to an already-created session without -E, potentially applying tmux’s update-environment policy and mutating that session’s environment. Use new-session -A -E -s <name> and add an observable environment-preservation test for the raced-existing-session path.


Reviewers: 2 done | Synthesis: codex, 12s | Total: 7m58s

wesm and others added 3 commits August 9, 2026 08:07
The creation dialog treated its untouched state as an error, offered no visible focus feedback, and briefly revoked creation whenever an activation refresh marked an admitted host as connecting. That made a routine local action feel broken even while the underlying host remained usable.

Keep the selected endpoint pinned while permitting the existing admitted capability through background refresh. Disconnected, unavailable, and changed endpoints remain blocked so better interaction feedback does not weaken host identity boundaries.

Validation: isolated live WSL tests created a first session and preserved the exact existing identity across a same-name creation race.

Generated with Codex
Co-authored-by: Codex <noreply@openai.com>
The sidebar should prioritize workspace navigation, while distro and endpoint configuration belongs in settings and endpoint-specific safety surfaces. Repeating the configured distro under the logical WSL host made the primary navigation taller and visually heavier than the Swift application.

Keep endpoint identity in the window title, creation flow, diagnostics, and retained-session qualification, but render the persistent host entry as one compact logical-host row.

Generated with Codex
Co-authored-by: Codex <noreply@openai.com>
The Rust dialog mixed endpoint configuration, validation, and lifecycle policy into one prominent line, making the WSL substrate look like the product identity and obscuring the actual creation decision. The shipped Swift sheet already defines a clearer hierarchy for this workflow.

Use the same generic title, logical-host validation language, terminal-marked input, and subdued ownership footer so the two native applications communicate the same model without exposing implementation detail as chrome.

Generated with Codex
Co-authored-by: Codex <noreply@openai.com>
@roborev-ci

roborev-ci Bot commented Aug 9, 2026

Copy link
Copy Markdown

roborev: Combined Review (e916422)

Medium-severity issues remain in session creation and refresh handling.

Medium

  • rust/workspace/src/lib.rs:1561 — Creation publishes Attaching before reserving attachment state. Switching sessions during fresh discovery increments the navigation generation but finds no active attachment; creation then exits without restoring state, leaving the workspace stuck on Attaching.

    • Fix: Register pending creation and its fallback synchronously before publishing Attaching, then atomically cancel and restore the prior state when superseded.
  • rust/workspace/src/lib.rs:2800 — Creation during an activation refresh retains the older inventory generation, causing publish_attach_inventory to reject the post-creation snapshot. If the concurrent refresh listed sessions before creation, the new session disappears after detaching until another refresh.

    • Fix: Fence or supersede the concurrent refresh before publishing the post-creation snapshot so an older refresh cannot overwrite it.
  • rust/host/src/wsl.rs:494 — The create-or-attach command omits -E. If a same-name race makes new-session -A attach to an existing session, tmux applies update-environment, unexpectedly mutating that session’s environment.

    • Fix: Use new-session -A -E -s <name> and add coverage verifying that a raced existing session retains its environment.

Reviewers: 2 done | Synthesis: codex, 14s | Total: 11m44s

Routine creation should ask for the required name and expose the decision, not teach endpoint routing or session ownership. Explanatory policy copy made a small modal taller and noisier while competing with the only feedback users need there: actionable validation errors.

Keep lifecycle and host configuration semantics in documentation and settings-oriented surfaces. The creation modal now remains silent for empty and valid input and speaks only when the user must correct something.

Generated with Codex
Co-authored-by: Codex <noreply@openai.com>
@roborev-ci

roborev-ci Bot commented Aug 9, 2026

Copy link
Copy Markdown

roborev: Combined Review (21919dd)

Medium-severity issues remain in session creation, inventory refresh, and WSL environment handling.

Medium

  • rust/workspace/src/lib.rs:2919 — Creation associates the client with whichever session currently has the requested name. An after-new-session hook that renames the session can cause a false failure, while a kill/recreate race can grant attach authority to a replacement session the client never opened. Capture the creating client’s exact server/session identity and reconcile inventory by identity, using the discovered name only for display.

  • rust/workspace/src/lib.rs:2833 — A creation started during activation refresh retains the previous inventory generation, causing publish_attach_inventory to reject its fresh snapshot. If the refresh finishes before creation, detaching leaves the new session absent until another refresh. Merge the post-create snapshot into the current generation after verifying the pinned endpoint/runtime, and test the refresh-completes-before-create race.

  • rust/host/src/wsl.rs:494new-session -A omits -E. If a race causes it to attach to an existing session, tmux applies update-environment, potentially changing values such as SSH_AUTH_SOCK, unlike Ghosthub’s other attach/create paths. Use new-session -A -E -s <name> and verify that raced attachment preserves the session environment.


Reviewers: 2 done | Synthesis: codex, 14s | Total: 12m2s

wesm added 2 commits August 9, 2026 09:07
The session-row close affordance must not masquerade as detach when the shipped product treats it as the only destructive session action. Require a fresh live identity before presenting confirmation, then let tmux compare the server PID, session ID, and creation time atomically so a same-named replacement can never be killed from cached inventory.

Cancellation and every lookup, runtime, identity, or command failure leave the presentation open. A successful kill removes only the matching presentation and refreshes WSL inventory; ordinary navigation and application shutdown remain detach-only.\n\nValidation: the isolated live WSL lifecycle suite proved cancel preserves the session, a same-named replacement survives stale confirmation, and a second fresh confirmation kills only that replacement.\n\nGenerated with Codex\nCo-authored-by: Codex <noreply@openai.com>
A requested session name is only intent, not proof of what an atomic new-session -A client actually entered. Hooks may rename a new session, and a same-name replacement may appear before discovery, so granting presentation authority from the name could reject the real client or attach state to the wrong server object.\n\nHave the ordinary client report its stable tmux identity, preserve existing session environments on the raced attach path, and publish the resulting inventory against the latest compatible WSL runtime generation. This keeps creation one-shot while making rename, replacement, and concurrent-refresh races explicit.\n\nValidation: isolated WSL tests proved a real after-new-session rename follows the creating client, an existing-session race preserves exact identity, and new-session -A -E retains the session environment.\n\nGenerated with Codex\nCo-authored-by: Codex <noreply@openai.com>
@roborev-ci

roborev-ci Bot commented Aug 9, 2026

Copy link
Copy Markdown

roborev: Combined Review (f9703cb)

Verdict: Changes requested due to one command-injection vulnerability and four medium-severity lifecycle issues.

High

  • Command injection through tmux session namesrust/session/src/lib.rs:39 (sink: rust/host/src/wsl.rs:541)
    SessionName::parse permits #, allowing a crafted name such as #(touch /tmp/ghosthub-owned) to reach tmux new-session -s. Tmux evaluates #(...) as a format job through the shell, so separate argv handling does not prevent execution. Reject # in user-created names or escape it as ##, and add an isolated real-tmux regression test proving embedded commands cannot execute.

Medium

  • Race can detach an unrelated active presentationrust/workspace/src/lib.rs:2082
    Kill completion checks the active identity and calls detach() separately. If the user switches sessions between those operations, the newly active presentation can be detached. Hold the navigation lock while rechecking identity and detaching, making cleanup atomic.

  • Detach and Kill Session actions are conflatedrust/ui/src/lib.rs:2333
    The active row’s detach control has been replaced by Kill Session, while inactive rows expose only Open. This removes per-presentation detach and requires attaching before killing a discovered session. Restore detach for the active presentation and expose Kill Session separately for every known running session.

  • Destructive confirmation omits the exact endpointrust/ui/src/lib.rs:1800
    The dialog shows only the session name and generic “WSL” text. A retained session may target a different endpoint from the current host, preventing users from verifying where processes will be terminated. Include the exact endpoint or host from confirmation.selection().

  • Cached rows bypass disconnected host staterust/ui/src/lib.rs:2600
    Cached session rows remain clickable when a host is disconnected or unavailable, allowing an unopened row to trigger discovery and attachment despite the explicit Connect/Retry state. Keep cached rows visible, but disable fresh Open actions while disconnected or unavailable; retained presentations may remain restorable.


Reviewers: 2 done | Synthesis: codex, 15s | Total: 14m45s

User-created names cross a tmux format-aware boundary, so separate argv handling alone is not sufficient to rule out format jobs. The session tree also needs to distinguish closing Ghosthub's client from destroying server-owned work, particularly while cached inventory remains visible during host failure.

Reject format syntax before creation authority exists, keep retained presentations restorable without enabling stale fresh attaches, and serialize successful kill cleanup with navigation so a concurrent switch cannot close an unrelated client.

Validation: an isolated real-WSL tmux test verified a format-job-shaped name cannot create its sentinel file.

Generated with Codex
Co-authored-by: Codex <noreply@openai.com>
@roborev-ci

roborev-ci Bot commented Aug 9, 2026

Copy link
Copy Markdown

roborev: Combined Review (76011d6)

The PR has one medium-severity correctness issue in WSL admission caching.

Medium

  • rust/workspace/src/lib.rs:495 — Refreshes reuse WslHost, but its admission cache is keyed only by WslRuntimeIdentity, not WslEndpoint. Because WSL distributions share a kernel boot ID and may have colliding PID 1 start ticks, changing the default distribution can reuse another distribution’s tmux admission and publish an unverified host as ready.
    • Fix: Store the resolved endpoint in VerifiedAdmission and require both endpoint and runtime identity to match before reusing the cached capability.

Reviewers: 2 done | Synthesis: codex, 11s | Total: 14m1s

WSL distributions can share kernel identity and can occasionally report colliding init start values. Runtime identity alone therefore cannot prove that cached tmux capability evidence belongs to the distro currently selected by default resolution.

Require both the resolved endpoint and runtime to match before reusing admission, so a distro change always re-establishes the tmux capability boundary.

Generated with Codex
Co-authored-by: Codex <noreply@openai.com>
@roborev-ci

roborev-ci Bot commented Aug 9, 2026

Copy link
Copy Markdown

roborev: Combined Review (2c42287)

Medium-severity issue found in tmux session creation; trust boundaries and destructive-operation safeguards otherwise look sound.

Medium

  • rust/workspace/src/lib.rs:3234 — Session creation always consumes its one-shot CreateOnce authority using TERM=xterm-256color. On hosts without that terminfo entry, tmux can reject the creation client before it emits the identity marker, so the existing xterm attachment fallback cannot run. Determine terminal support before consuming CreateOnce (for example, during admission), then create once with the supported type; alternatively, conservatively use xterm and show the reduced-color notice.

Reviewers: 2 done | Synthesis: codex, 11s | Total: 15m22s

CreateOnce cannot be retried safely after a terminal startup failure, so assuming xterm-256color could consume creation authority before the client reports its identity. Admission now proves the same atomic client shape and binds the supported TERM to the admitted WSL endpoint and runtime before creation begins.\n\nThis preserves full color on normal distributions while minimal installations use the proven xterm baseline and existing reduced-color notice without rerunning creation.\n\nValidation: an isolated real WSL lifecycle test reached the client identity marker, detached, and preserved the exact session.

Generated with Codex\nCo-authored-by: Codex <noreply@openai.com>
@roborev-ci

roborev-ci Bot commented Aug 9, 2026

Copy link
Copy Markdown

roborev: Combined Review (aeef3c4)

One medium-severity race remains in session creation; no concrete security vulnerabilities were found.

Medium

  • rust/workspace/src/lib.rs:1617 — Creation publishes Attaching but does not reserve an attachment until creation and discovery complete. If the user switches sessions or starts another creation, navigation invalidates the task, but supersede_inflight_attachment cannot cancel it because no attachment exists. The task then exits without restoring inventory, leaving the workspace stuck in Attaching.

    Fix: Represent pending creation in attachment/navigation state before publishing Attaching, or explicitly cancel and restore pending creation when superseded. Add coverage for switching sessions during creation.


Reviewers: 2 done | Synthesis: codex, 11s | Total: 13m59s

The attaching view previously appeared before tmux creation had any reserved lifecycle state. A session switch could invalidate the background task without finding anything to cancel, leaving navigation stranded in Attaching.\n\nTreat pending creation as an explicit cancellable reservation whose fallback ownership promotes atomically into the ordinary attachment state. Superseding navigation restores inventory immediately, while any late background completion remains generation-stale and cannot publish.

Generated with Codex\nCo-authored-by: Codex <noreply@openai.com>
@roborev-ci

roborev-ci Bot commented Aug 9, 2026

Copy link
Copy Markdown

roborev: Combined Review (37d505a)

Two medium-severity concurrency and cancellation issues should be addressed before merging.

Medium

  • rust/workspace/src/lib.rs:1987 — Kill-generation validation occurs before acquiring pending_kill. Cancellation, navigation, or a newer kill request can invalidate the generation between validation and publication, allowing a stale confirmation to reappear and block the current UI. Acquire pending_kill before the final generation check, publish only while holding that lock, and defensively filter confirmations against the current generation.

  • rust/workspace/src/lib.rs:2236 — Detaching an Attaching creation row invalidates navigation but neither removes nor cancels pending_creation. The WSL operation may continue after detachment, while its stale reservation remains until another creation replaces it. Have detach_locked take and cancel any pending creation while holding the navigation lock, and add coverage for calling detach() during creation.


Reviewers: 2 done | Synthesis: codex, 10s | Total: 16m35s

Kill confirmation is meaningful only while its live-identity request remains the current destructive operation. Checking generation outside the confirmation lock allowed cancellation, navigation, or a newer request to race stale UI authority back into view.\n\nUse the pending-kill lock as the linearization boundary for generation changes and publication, while retaining a defensive generation filter at read time. Detach now also consumes and cancels pending creation so closing an attaching presentation cannot leave WSL work or stale workspace authority behind.

Generated with Codex\nCo-authored-by: Codex <noreply@openai.com>
@roborev-ci

roborev-ci Bot commented Aug 9, 2026

Copy link
Copy Markdown

roborev: Combined Review (476fd79)

High-severity issues remain in tmux target handling, plus a medium-severity race in kill-request generation.

High

  • rust/host/src/wsl.rs:648 — A directly discovered session name is interpolated into a tmux target without validation. Tmux format sequences such as #(...) may be evaluated in target arguments, potentially executing a format job or capturing another session’s identity before destructive confirmation.
    • Fix: Query all live sessions using the existing length-prefixed inventory format, match the decoded name in Rust, and construct authority from that identity without passing the name into another tmux target expression.

Medium

  • rust/workspace/src/lib.rs:1965 — The current kill generation is invalidated only after the new selection is captured. If an earlier identity query is still running and a newer kill request fails validation, the earlier result can unexpectedly publish confirmation for the old session.
    • Fix: Reserve or invalidate the generation before any fallible capture work so every newer request supersedes prior queries, including when validation or thread creation fails.

Reviewers: 2 done | Synthesis: codex, 14s | Total: 14m20s

Discovered tmux names are untrusted display data, and passing one back through a target expression lets tmux interpret format syntax before destructive confirmation. Fresh authority must therefore come from identity-bearing inventory rather than a second name-targeted command.\n\nMatch the length-framed all-session result in Rust and carry only the captured stable identity into the conditional kill. Reserve destructive-request generation before validation as well, so every newer user intent supersedes older identity queries even when the new request is rejected.\n\nValidation: an isolated real WSL lifecycle test confirmed that a replaced session survives stale confirmation and only a newly captured identity is killed.

Generated with Codex\nCo-authored-by: Codex <noreply@openai.com>
@roborev-ci

roborev-ci Bot commented Aug 9, 2026

Copy link
Copy Markdown

roborev: Combined Review (952aff2)

Medium-severity test coverage gap; no High or Critical findings.

Medium

  • rust/workspace/tests/wsl_live.rs:210 — The new end-to-end creation and guarded-kill tests are ignored, while rust-test and Windows CI run ordinary cargo test. As a result, the WSL/tmux boundaries introduced here are not exercised by any quality gate.
    • Fix: Add the documented WSL live-test Make target and run the ignored tests on a WSL-capable acceptance runner.

Reviewers: 2 done | Synthesis: codex, 8s | Total: 23m35s

WSL attachment, creation, guarded kill, and client-lifetime behavior cross a real Windows/ConPTY/WSL2 boundary that ordinary cargo test intentionally skips. Those contracts need repeatable acceptance evidence without making fast pull-request CI depend on a hosted runner configuration that does not guarantee a usable WSL2 distro.

Keep the live suites isolated behind one documented Make target and a dedicated labeled acceptance workflow, with early runtime and tmux checks so an unsuitable runner cannot produce misleading results.

Validation: all 16 ignored terminal and workspace tests passed against the local WSL2 Ubuntu/tmux environment.

Generated with Codex
Co-authored-by: Codex <noreply@openai.com>
@roborev-ci

roborev-ci Bot commented Aug 9, 2026

Copy link
Copy Markdown

roborev: Combined Review (92267a9)

Verdict: High-risk workflow configuration allows untrusted branch code to execute on a persistent self-hosted WSL runner.

High

  • Untrusted code execution on self-hosted runner.github/workflows/rust-wsl-live.yml:4,24

    The workflow is callable without repository/ref restrictions and can also be manually dispatched from any selectable branch. Its checkout resolves to the triggering caller/ref, allowing malicious Rust tests, build scripts, or procedural macros to execute with access to the runner’s filesystem, WSL environment, network identity, caches, and persistence opportunities.

    Fix: Make the workflow manual-only and restrict it to the canonical repository and a trusted immutable ref, explicitly checking out that ref. If feature-branch testing is required, use a protected environment with trusted approval and an ephemeral, reset-after-job runner. Constrain the runner group to this exact trusted workflow.


Reviewers: 2 done | Synthesis: codex, 10s | Total: 16m27s

A persistent WSL2 runner is a privileged execution boundary, so branch-selectable dispatch and reusable workflow callers must not be able to place arbitrary Rust build logic on it.

Limit dispatch to the canonical rust-port branch, pin checkout to that dispatch's immutable SHA, and route the job through a dedicated runner group whose external policy is scoped to this workflow. Feature branches continue proving the live boundary on isolated developer machines before merge.

Validation: actionlint 1.7.10 accepted the hardened workflow.

Generated with Codex
Co-authored-by: Codex <noreply@openai.com>
@roborev-ci

roborev-ci Bot commented Aug 9, 2026

Copy link
Copy Markdown

roborev: Combined Review (c39d920)

Verdict: One medium-severity issue must be fixed; otherwise the WSL/tmux changes look sound.

Medium

  • rust/host/src/wsl.rs:683 — After a confirmed session is replaced, its captured session ID no longer exists. Consequently, if-shell -t =$old_id: fails during target resolution and never runs the mismatch branch. The error is classified as “no longer running,” causing the new WSL acceptance test to time out while waiting for “replaced after confirmation.”
    • Fix: When the stable-ID target is missing, perform a fresh length-framed inventory query and report replacement if the original name now has a different identity. Continue avoiding the session name as a tmux target.

Reviewers: 2 done | Synthesis: codex, 10s | Total: 14m29s

A stable tmux session ID that disappears before confirmed deletion prevents if-shell from evaluating its identity mismatch branch. Reporting that as an ordinary missing session hides the important fact that the original name now belongs to different processes.

Use the existing length-framed all-session query only for classification after a missing stable target. The destructive command remains identity-targeted, while a same-named different identity receives the replacement diagnostic and survives untouched.

Validation: the isolated WSL2 guarded-kill test replaced the confirmed session, observed the replacement diagnostic, preserved it, and then killed it only after fresh confirmation.

Generated with Codex
Co-authored-by: Codex <noreply@openai.com>
@roborev-ci

roborev-ci Bot commented Aug 9, 2026

Copy link
Copy Markdown

roborev: Combined Review (44b2bf2)

No Medium, High, or Critical issues found.


Reviewers: 2 done | Synthesis: codex, 5s | Total: 18m1s

@wesm
wesm merged commit 3f0efd1 into rust-port Aug 9, 2026
5 checks passed
@wesm
wesm deleted the rust-port-auto-refresh branch August 9, 2026 23:24
wesm added a commit that referenced this pull request Aug 9, 2026
- Keeps local WSL tmux sessions current when the Ghosthub window regains focus, so sessions created elsewhere appear without a manual refresh.
- Lets users create the first or an additional local tmux session from the compact `+` action beside a ready WSL host.
- Uses one atomic `new-session -A` ordinary client, then captures the exact WSL runtime, tmux server, session ID, and creation time before publishing the terminal.
- Preserves the current terminal during refresh and creation, restores it when a new client cannot be established, and never reruns or kills a session after an ambiguous launch.
- Keeps SSH and remote lifecycle work out of scope.
- Exercises empty-namespace creation and same-name creation races against isolated real WSL tmux servers; the full Rust workspace, Clippy, architecture contracts, strict docs, and license closure pass.

Co-authored-by: Wes McKinney <wesm@users.noreply.github.com>
wesm added a commit that referenced this pull request Aug 10, 2026
- Keeps local WSL tmux sessions current when the Ghosthub window regains focus, so sessions created elsewhere appear without a manual refresh.
- Lets users create the first or an additional local tmux session from the compact `+` action beside a ready WSL host.
- Uses one atomic `new-session -A` ordinary client, then captures the exact WSL runtime, tmux server, session ID, and creation time before publishing the terminal.
- Preserves the current terminal during refresh and creation, restores it when a new client cannot be established, and never reruns or kills a session after an ambiguous launch.
- Keeps SSH and remote lifecycle work out of scope.
- Exercises empty-namespace creation and same-name creation races against isolated real WSL tmux servers; the full Rust workspace, Clippy, architecture contracts, strict docs, and license closure pass.

Co-authored-by: Wes McKinney <wesm@users.noreply.github.com>
wesm added a commit that referenced this pull request Aug 11, 2026
- Keeps local WSL tmux sessions current when the Ghosthub window regains focus, so sessions created elsewhere appear without a manual refresh.
- Lets users create the first or an additional local tmux session from the compact `+` action beside a ready WSL host.
- Uses one atomic `new-session -A` ordinary client, then captures the exact WSL runtime, tmux server, session ID, and creation time before publishing the terminal.
- Preserves the current terminal during refresh and creation, restores it when a new client cannot be established, and never reruns or kills a session after an ambiguous launch.
- Keeps SSH and remote lifecycle work out of scope.
- Exercises empty-namespace creation and same-name creation races against isolated real WSL tmux servers; the full Rust workspace, Clippy, architecture contracts, strict docs, and license closure pass.

Co-authored-by: Wes McKinney <wesm@users.noreply.github.com>
wesm added a commit that referenced this pull request Aug 13, 2026
- Keeps local WSL tmux sessions current when the Ghosthub window regains focus, so sessions created elsewhere appear without a manual refresh.
- Lets users create the first or an additional local tmux session from the compact `+` action beside a ready WSL host.
- Uses one atomic `new-session -A` ordinary client, then captures the exact WSL runtime, tmux server, session ID, and creation time before publishing the terminal.
- Preserves the current terminal during refresh and creation, restores it when a new client cannot be established, and never reruns or kills a session after an ambiguous launch.
- Keeps SSH and remote lifecycle work out of scope.
- Exercises empty-namespace creation and same-name creation races against isolated real WSL tmux servers; the full Rust workspace, Clippy, architecture contracts, strict docs, and license closure pass.

Co-authored-by: Wes McKinney <wesm@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

Development

Successfully merging this pull request may close these issues.

1 participant