feat(agent-setup): report agent launch from the wrapper so terminals bind at boot

Merged
KI
2mo ago
+273-4

Problem

A freshly launched agent pane can sit with no terminalAgentBindings row — and therefore none of the binding-gated pane controls — until its first Stop or an attach. Worst right after a session handoff: the new pane is exactly the one a user wants to chain from.

Root cause (proven empirically, not delivery): Codex 0.150.1 creates its session rollout lazily, so the native SessionStart hook registered in ~/.codex/hooks.json fires only with the first turn. An idle Codex TUI booted for 10s with --enable hooks --dangerously-bypass-hook-trust fires nothing; codex resume fires nothing at launch either. Vibe has no session hooks at all (its hooks.toml supports only before_tool/post_agent_turn). Every hook POST that did fire got a 200 — the gap is upstream of the wire.

Fix

  • Wrapper launch report (buildWrapperScript, all 12 agent wrappers, marker v3→v4): a backgrounded subshell waits 2s, checks the agent process is still alive (kill -0 on the pid that survives exec), then fires {"hook_event_name":"SessionStart"} through notify.sh. Skips --help/-h/--version/-V/-v (before --) and runs only inside Superset terminals, so version probes and fast exits never bind a pane. Server-side, SessionStart→Attached already creates the binding; harnesses with working native SessionStart still fire it and attach the real session id via upsert.
  • Store guard: an Attached for the same agent session no longer downgrades an active Start/PermissionRequest — the delayed report must not flip a working agent to idle.

Per-harness: all 12 wrapper harnesses (claude, amp, codex, gemini, mastracode, opencode, copilot, vibe, kimi, grok, cursor-agent, droid) now report at launch via the wrapper; omp/pi have no wrappers but their extensions already fire session_start at session boot. Known limits: long-running non-session subcommands (claude mcp add, codex login) bind until they exit; direct-binary launches that bypass the wrapper rely on native hooks only.

Verification

  • Both new tests proven failing before the fix. packages/agent-setup: 268/268 + tsc clean. packages/host-service: 1407/1407 + typecheck clean.
  • Real app over CDP: launching codex in a dev-app terminal produced a codex | Attached binding 2.5s after Enter, while Codex was still at its trust prompt (no session, no native hook possible); the pane tab swapped to the Codex icon (the binding-gated UI on main); /quit ended the binding as detached.

https://claude.ai/code/session_01HR6rXRzQM6p8epeyer3XqG


Summary by cubic

Agent terminals now get their agent binding at boot instead of waiting for the harness's first native hook, which Codex defers until the first turn and vibe never fires at launch.

  • All 12 agent wrappers emit a synthetic SessionStart through notify.sh 2s after launch, gated on the agent process still being alive and running inside a Superset terminal, so --help/--version probes and fast exits never bind a pane.
  • Harnesses with working native hooks still fire their real SessionStart; the host upsert keeps the duplicate harmless and attaches the real session id.
  • A delayed Attached event no longer rewrites any same-session lifecycle state — Start, PermissionRequest, Stop, or Failed — and only refreshes lastEventAt, so a late launch report can't hide a failure or erase a resume candidate.
  • Known limits: long-running non-session subcommands (claude mcp add, codex login) bind until they exit, and direct-binary launches that bypass the wrapper rely on native hooks only.
  • Verified in the dev app: launching codex produced an Attached binding 2.5s after Enter while Codex was still at its trust prompt.

Summary by CodeRabbit

  • New Features

    • Added launch reporting for eligible long-running agent sessions, improving host visibility into session starts.
    • Reports are automatically skipped for help, version, short-lived commands, and unsupported environments.
  • Bug Fixes

    • Preserved all existing session lifecycle states when an attachment event occurs, including permission requests, stops, and failures.
    • Correctly refreshed session activity during reattachment without overwriting the current lifecycle status.