Skip to content

mac: restore Codex session actions - #204

Open
khoi wants to merge 20 commits into
mainfrom
fix/codex-session-ownership
Open

mac: restore Codex session actions#204
khoi wants to merge 20 commits into
mainfrom
fix/codex-session-ownership

Conversation

@khoi

@khoi khoi commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

Why

Codex 0.151 can emit SessionStart from a shared host with no Supaterm pane context. Its PID may also sit outside the pane process tree. When process working-directory inspection fails, Supaterm could not find the pane even though the terminal knew its current directory. The panel never received the session ID, so Fork and Copy session ID stayed hidden.

Even after routing a hook, Supaterm could bind the session to the short-lived hook emitter. Process cleanup then removed the session when that process exited.

The prior E2E pinned Codex 0.150.1, checked screen states, and never asserted first-prompt session binding. The new binding assertion first exposed lost process evidence. Once that was fixed, CI exposed a second fault: the installed command resolved the bridge through the hook process's $HOME, which need not match the home used during installation.

Installer tests used the same ambient home and did not execute the exact command written to settings under a different HOME. Local runs inherited the expected value. The real E2E caught the launch fault only after the earlier routing fault stopped hiding it.

What changed

The hook uses Codex's session_id, requires only a non-empty transcript_path, and never opens or parses the transcript.

Contextless routing now uses, in order:

  • Exact session-title ownership
  • Pane process ownership
  • One exact workspace after every app instance replies and the retry window expires

Detection resolves the effective Codex workspace while it reads the process invocation, then retains only that path with the exact process identity. Later unreadable scans cannot erase it; a changed agent or process start drops it. Hook routing uses this evidence before trying a fresh process query. It never stores the command line.

Process-derived workspace stays authoritative, including -C and --cd. Absolute declared paths do not depend on process working-directory access; relative paths still do. If process-derived routing evidence is unavailable, Supaterm uses the pane terminal's reported directory. Ambiguous, mismatched, and unknown owners still reject the hook.

The selected pane anchors the session to its detected Codex process, then its foreground process. Supaterm uses the hook emitter only when it proves related and no stable pane process exists.

New panes clear inherited CODEX_THREAD_ID. Nested sessions still require the inherited ID to match the hook payload.

The installer writes the absolute, shell-escaped bridge path into every hook command. The bridge keeps the hook process lineage used for pane routing, drains input and succeeds when unavailable, uses an absolute bundled CLI fallback, and never depends on pane or hook-host environment. One home-scoped command policy now owns generation, health, upgrade, rollback, and removal.

Verification

  • make mac-check
  • Full make mac-test-xcodebuild
  • Real Codex 0.151 E2E: 6 tests passed, including first-prompt binding and every root state through interrupt
  • Fresh debug build with plain codex: Copy session ID showed Copied; Fork session right opened a pane that confirmed the source thread
  • Installer regression executes the exact installed command with a different HOME, special characters in the install path, and sh, bash, zsh, and fish
  • Missing and unreadable bridges drain input and exit successfully
  • Table coverage for every -C and --cd form, missing process working directories, relative paths, process priority, terminal fallback, mismatch, and unknown workspace states
  • Socket routing coverage for exact, ambiguous, incomplete, and shared-host cases
  • Both thermo reviews: no findings
  • Pre-commit and pre-push checks

Note

Codex emits a usable SessionStart after the first prompt. Session actions appear then, not on the untouched welcome screen.

Reject transcriptless and nested Codex session starts before they can replace a pane's root session. Clear inherited Codex thread context at pane boundaries and remove the working-directory heuristic.

Cover ownership rules, panel actions, socket transport, pane environments, and two-pane behavior.
@tuist

tuist Bot commented Aug 29, 2026

Copy link
Copy Markdown

🛠️ Tuist Run Report 🛠️

Tests 🧪

Scheme Status Cache hit rate Tests Skipped Ran Commit
supatermUITests 0 % 71 0 71 74986de7d

Builds 🔨

Scheme Status Duration Commit
supatermUITests 2m 6s 74986de7d

khoi added 5 commits August 29, 2026 19:50
Keep the nested-session test's distinct working directory while relying on
the decoder tests for empty transcript normalization.
Manual hook payloads without persistence metadata succeed at the CLI but
do not bind a panel session. Document the required signal and inherited
thread guard in both the internal design and shipped agent guide.
…ership

% Conflicts:
%	integrations/supaterm-skills
The shared hook host no longer inherits pane identity or the bundled CLI
path, so valid starts could not bind to a terminal. Shell parsing also
blocked the old command before it reached the CLI.

Install a shell-safe bridge and route contextless starts to the one live
process whose working directory matches. Keep ambiguous sessions unbound
so one app cannot claim another app's session.
The --cd option changes the hook workspace without changing the process
working directory. Resolve absolute, relative, long, and short forms
against the launch directory before routing contextless session starts.
@khoi khoi changed the title mac: preserve root Codex session identity mac: restore Codex session actions Aug 29, 2026
khoi added 14 commits August 30, 2026 00:33
…ership

% Conflicts:
%	apps/mac/SupatermCLIShared/SupatermAgentHook.swift
Codex now runs session hooks from a shared app-server process that has no
pane context and may inherit another thread ID. Process and workspace
matching alone can therefore miss the pane that owns the session.

Use the hook payload as the session source and the exact terminal title as
routing evidence. Keep process and workspace fallbacks for older clients,
and preserve the inherited-session guard when a nested process owns the
pane.
The managed hook command relied on the hook process inheriting the home
used during installation. Shared hook hosts and CI can run with another
home, so the shell never reached the installed bridge.

Bind the command and ownership policy to the install home. Keep the hook
optional when the bridge is unavailable and preserve its process lineage
for pane routing.
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