Skip to content

fix(opencode): show opencode run status when it starts in a hidden tab - #24238

Closed
brennanb2025 wants to merge 5 commits into
mainfrom
brennanb2025/opencode-run-host-status
Closed

brennanb2025 wants to merge 5 commits into
mainfrom
brennanb2025/opencode-run-host-status

Conversation

@brennanb2025

@brennanb2025 brennanb2025 commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor
Files Added Deleted Net
Test 4 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​72 $\color{#cf222e}{\Huge{\mathbf{−}}}$​5 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​67
Prod 7 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​22 $\color{#cf222e}{\Huge{\mathbf{−}}}$​11 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​11

ELI5

When you run opencode run "<prompt>" in an Orca terminal, the pane should show Working while it runs. When it exits back to the shell, the row clears. #23722 added that, but Working only appeared if the tab was visible at the moment the command started. If the tab was hidden at that moment, the pane showed nothing for the whole run. That happens when a script or another agent sends the command to a background tab, or when you type ahead and switch tabs before it starts. Now those runs show Working while they run, and the row clears when they exit.

What it fixes and scope

  • Fixes: no Working for an OpenCode 2 opencode run that starts while its tab is hidden. This is a follow-up to fix(opencode): report OpenCode 2 status from each pane's own TUI #23722, which added opencode run status and labelled the hidden-tab case temporary.
  • Surface: local terminal panes (macOS, Linux, Windows) whose shell has Orca's shell integration (zsh, bash, PowerShell).
  • Not affected:
    • Full OpenCode windows, which report through their own plugin since fix(opencode): report OpenCode 2 status from each pane's own TUI #23722.
    • Other agents.
    • SSH and WSL panes, where opencode run detection is not enabled yet; this PR doesn't change that.
    • Visible tabs, which already worked.
    • A run already in flight when Orca restarts, which behaves as on main today (see TEMPORARY below).

What Changed

Before (user): send opencode run "…" to a tab you're not looking at, or type it ahead and switch tabs before it starts. That pane's sidebar row never shows Working.

After (user): the pane shows Working while the command runs, whether or not its tab is visible. When the command exits back to the shell, the row clears, the same as for a visible tab.

What happens on exit today. On main, the run detector also posts Done when opencode run exits. That isn't the intended behaviour: when a command exits back to the shell, the pane should show nothing. A separate PR stops the detector from posting Done on exit. This PR adds no Done of its own; it only lets the existing detector see a hidden-tab start.

Mechanism, before:

  • Orca's main process detects opencode run. When the shell reports "a command started" (a standard terminal marker, OSC 133;C), main checks the pane's foreground process. If it is opencode run, main marks the pane Working. The shell's "command finished" marker (OSC 133;D) ends it.
  • While a tab is hidden, main hands scanning of that pane's output to the terminal daemon, the background process that owns the terminals, so the daemon can drop the hidden pane's backlog without losing events.
  • The daemon forwarded "command finished" back to main, but not "command started". So a command that started while hidden never armed the detector.

Mechanism, after:

  • The daemon's hidden-tab scanner also forwards "command started" (daemon-background-transient-facts.ts). It uses the same shared scanner main uses, and main stops its own copy at the same handoff point, so each marker is still acted on exactly once.
  • Main sends the new fact to the existing detector (orca-runtime-emit-daemon-pty-transient-fact.ts). The detector itself is unchanged.
  • The daemon protocol version goes from 38 to 39. A daemon left running from before an update keeps serving new terminals at its own version, so without the bump new terminals would stay on code that drops the new fact.

Why

  • The fix belongs where the missing signal is. The detector already lives in the main process, which owns agent status, and it already works for visible tabs. The only gap was one fact the daemon didn't forward.
  • Rejected: move the detector into the daemon. The daemon has no status store or settings, and it survives Orca updates, so any logic in it would stay frozen at old versions.
  • Rejected: keep main scanning hidden tabs too. Under backlog pressure the daemon drops exactly the output that holds the marker.
  • Rejected: poll every pane's process table. That adds a loop over every pane, and Orca has had process-spawning storms from polling like that.
  • Rejected: check when the tab is revealed. Working would only show once you looked at the tab.
  • Rejected: stop hiding older-daemon terminals. Making old daemons keep their terminals visible to main would close the gap below for terminals opened before the update. But those terminals would lose their hidden-backlog protection for the rest of their life.

How this compares with the reference mechanisms

  • Same: process and terminal observation stays on the host, never on the client, and doesn't depend on whether anyone is looking.
  • INTENDED: command lifetime comes from shell-integration markers the daemon and main already scan, not from polling the process table. The markers are already parsed for every pane, and polling would add a per-pane loop. The cost is that shells without these markers (for example cmd.exe and sh) get no opencode run status, as before.
  • TEMPORARY: terminals opened before this update stay on the old daemon, which doesn't forward "command started", until they are closed. A new terminal gets the fix.
  • TEMPORARY: a run already in flight when Orca restarts gets no Working. Re-checking surviving terminals after a restart is a separate follow-up.
  • TEMPORARY (existed before this PR): SSH and WSL panes get no opencode run status.

Known gaps (exist on main today; not caused by this PR)

  • Done on exit: the run detector posts Done when opencode run exits, instead of the row clearing. A separate PR removes that.
  • opencode run inside a nested shell can stay Working.
    • What you see: you start a nested shell such as /bin/sh and type opencode run within a few seconds. The pane can show Working until you leave that nested shell, even after the run has ended.
    • Cause: right after a command starts, the detector re-checks the foreground for a few seconds while a shell is still in front. The nested shell never reports its own commands finishing.
    • Measured live on origin/main with matched timing.
  • A run that ends while Orca is closed keeps an "Idle - OpenCode" row.

Linked Issue

Follow-up to Linear STA-8629 (OpenCode2 shows done while still working) and #23722.

Visual Proof

Screenshots (remote Mac, real OpenCode 2.0.21; the sidebar's agent rows are expanded. The "Done - OpenCode" row in some shots belongs to an earlier, visible run in Terminal 1. Posting Done on exit is today's behaviour, which a separate PR removes.)

Before, origin/main: opencode run sent to hidden Terminal 2 while it runs. There is no row for Terminal 2.
main hidden tab, no status

After, this PR: the same send to hidden Terminal 2 shows Working while it runs.
PR hidden tab Working

A new terminal after the update, hidden while its run starts: Working.
new-daemon terminal Working

A terminal opened before the update stays on the old daemon and stays silent for a hidden start, as described.
old-daemon terminal silent

Nested /bin/sh, 2 minutes after the run ended: still Working on origin/main and on this PR alike. This exists on main today.
nested sh main
nested sh PR

Testing

  • Manually tested on a remote macOS machine with real OpenCode 2, against origin/main (see Visual Proof)

  • Automated tests added/updated, or explained why not below

  • New tests:

    • The daemon's hidden-tab scanner emits "command started": in byte order with "command finished", split across chunks, and split across the hidden handoff.
    • The hidden-tab path end to end in the runtime: the detector arms from the relayed start, and main's own scan does not arm it a second time while the daemon holds the scan.
    • The protocol-version tests were updated.
  • Ablations: reverting the daemon relay, main's handling of the fact, or main's hidden-scan guard each makes its tests fail (3, 3 and 1 tests).

  • 25 related daemon, IPC and runtime test files pass (1707 tests, 1 skipped), including the orca-runtime.test.ts harness and all daemon-pty-adapter suites. pnpm tc:node passes.

Review

Agent skill upstream boundary

  • Not applicable, or this change follows docs/reference/agent-skill-sharing-upstream-boundary.md and copies or mechanically translates no upstream skill-installer source, tests, fixtures, registry entries, path tables, comments, or documentation.

Notes

  • Security: no new inputs.
  • Backwards compatibility:
    • A new daemon protocol version. Old terminals keep working on their old daemon (see TEMPORARY above).
    • What paired clients and remote hosts exchange is unchanged.
    • Merge note: other open PRs also touch the daemon protocol version. Before merging, check that origin/main is still at 38. If another PR has claimed 39, move this to the next free version.
  • Performance: one extra control event per command start in a hidden tab. No per-chunk cost is added.

Checklist

  • This PR is small and focused
  • I explained what changed and why (ELI5, the user-facing before/after, the mechanism, and why over the alternatives)
  • Before/after screenshots or videos attached for UI changes, or N/A with reason
  • Self-reviewed for correctness, security, and performance
  • Cross-platform, SSH/remote, and path/shortcut impact considered (or N/A)
  • pnpm lint, pnpm typecheck, pnpm test, and pnpm build pass (or CI will cover; local preferred)

…tab or survives a restart

An OpenCode 2 `opencode run` typed into a pane showed no status at all when
the command started while the pane's tab was hidden (sent by the CLI or an
agent to a background tab, or typed ahead before a tab switch). While a tab is
hidden the terminal daemon owns the OSC 133 scan and relayed only the command
finish, so main's run producer never saw the start. A run already in flight
when Orca restarted had the same gap: its start was printed before main was
listening, so it never showed Working and its Done never came.

- The daemon's background scanner now relays `command-started`, and main
  routes it to the existing run producer. Daemon protocol goes to v39 so new
  panes get a daemon that relays it; panes on a daemon preserved across the
  update keep the old behaviour until they close.
- On a reattach or adoption commit, the producer checks the pane's foreground
  once (no retry ladder) unless it already tracks the pane's current command.
…mand is running

The reattach check armed Working from the foreground command line alone. In a pane
whose shell prints no OSC 133 markers (cmd.exe, sh, dash, ksh, `exec sh`) nothing ever
ends that Working, and the check ran on every remount, not just after a restart. It
also never ran when a phone or paired client was the first to attach a restored
terminal.

The daemon already scans every session's OSC 133 markers. Its reply to an attach of an
existing session now carries that session's state (running / at-prompt / unmarked),
read atomically with the attach, on protocol v39. Main checks the foreground only when
the daemon says a command is running; older daemons omit the field and get no check.
Both paths that attach a surviving session (a pane mount's spawn commit and a remote
viewer's provider attach) report through one runtime method.
This PR now fixes only a run that starts while its tab is hidden: the daemon relays
the command-start fact, protocol v39. Re-deriving a run in flight when Orca reattaches
a surviving pane needs a liveness check behind its arm, so it moves to its own PR
(branch brennanb2025/opencode-run-reattach-liveness). Restores the reattach files to
their main versions and drops the reattach tests; the relay, its tests and the comment
fixes stay.
@brennanb2025

brennanb2025 commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor Author

Review status: ready (hidden-tab start fix only)

The problem. Since #23722, opencode run in an Orca terminal shows Working while it runs, but only if the tab was visible when the command started. Hidden tabs showed nothing for the whole run. That covers a command sent to a background tab by a script or agent, and typing ahead and then switching tabs. The cause: while a tab is hidden, the terminal daemon scans that pane's output. It forwarded "command finished" to the main process, but not "command started", so the detector never armed.

What changes for you. A run that starts in a hidden tab now shows Working while it runs, on the right pane. When it exits back to the shell, the row clears, the same as for a visible tab. Visible tabs are unchanged. A run in flight across an Orca restart behaves as on main today.

Done on exit. On main today, the run detector also posts Done when opencode run exits. That isn't intended: the pane should show nothing once the command is back at the shell. A separate PR stops the detector from posting Done on exit. This PR adds no Done of its own; it only lets the existing detector see a hidden-tab start.

What changed in review:

  • The builder's first version also tried to recover status for a run that was already going when Orca restarted. Review showed it could leave a Working that never clears:
    • in shells that never report command start and end (cmd.exe, sh);
    • after exec <shell> or inside a nested shell;
    • and it did nothing on the restart that installs the update.
  • Each fix added another guard, and the real fix is a different mechanism: keep checking the pane's foreground until the run ends. So that part was split out. This PR is now the hidden-tab start fix only (11 files). The restart work is kept on a separate branch for a follow-up.

Problems found that this PR does not cause (both exist on main today):

  • A nested shell keeps Working. opencode run typed within a few seconds of starting a nested /bin/sh shows Working until you leave that shell. Measured on both main and this PR.
  • A run that ends while Orca is closed leaves a stale "Idle - OpenCode" row.

Deferred (not fixed here):

  • Three wording and test nits, and one daemon-version constant used only by a test (matching how earlier protocol bumps did it).
  • Terminals opened before this update stay on the old daemon and keep today's behaviour until they are closed.

Merge note. This bumps the daemon protocol to 39. Other open PRs touch the protocol version too. Check origin/main is still at 38 right before merging; if 39 is taken, move this to the next free number.

Verified:

  • Live on a remote Mac with real OpenCode 2.0.21, origin/main against this head (5252676). In each hidden case a main-process log proved the pane really was handed to the daemon.
    • Visible run: unchanged.
    • Hidden-tab start: Working while it runs, on that pane only.
    • Type-ahead then switch tabs: Working while it runs.
    • Terminal on the old daemon: silent, as described.
    • New terminal: Working.
    • Restart mid-run: same as main, no stuck Working.
  • Tests: 25 daemon, IPC and runtime test files pass. Reverting each part of the fix makes its tests fail.
  • Typecheck passes, and CI is green.

Not verified: Windows, Linux, SSH and WSL panes (SSH and WSL have no opencode run status yet either way), and a paired phone.

Screenshots (remote Mac, real OpenCode 2.0.21; the sidebar's agent rows are expanded. The "Done - OpenCode" row in some shots belongs to an earlier, visible run in Terminal 1. Posting Done on exit is today's behaviour, which a separate PR removes.)

Before, origin/main: opencode run sent to hidden Terminal 2 while it runs. There is no row for Terminal 2.
main hidden tab, no status

After, this PR: the same send to hidden Terminal 2 shows Working while it runs.
PR hidden tab Working

A new terminal after the update, hidden while its run starts: Working.
new-daemon terminal Working

A terminal opened before the update stays on the old daemon and stays silent for a hidden start, as described.
old-daemon terminal silent

Nested /bin/sh, 2 minutes after the run ended: still Working on origin/main and on this PR alike. This exists on main today.
nested sh main
nested sh PR

@brennanb2025
brennanb2025 marked this pull request as ready for review October 1, 2026 05:20
@greptile-apps

greptile-apps Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 5/5

[Critical risk] Bumps daemon protocol version and changes inter-process communication contract.

The PR appears safe to merge based on the changes since the previous review.

Summary

The PR relays command-start markers from hidden terminals to the existing OpenCode run-status detector and updates the daemon protocol version. Since the previous review, it removes test assertions that expected the currently unintended Done status on exit. No new actionable issue was identified.

Reviews (2) · Last reviewed commit: "test(opencode): assert only the hidden-s..."

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ℹ️ Minor suggestions only — the implementation is correct; two documentation nits below.

Reviewed changes

  • Relay emits the command-start fact — daemon-background-transient-facts.ts wires onCommandStarted into the existing shared OSC-133 scanner and emits { kind: 'command-started' } in byte order. No new scanner, no per-chunk cost.
  • Fact union widened — command-started added to DaemonTransientFact (daemon-stream-events.ts) and PtyTransientFact (pty-provider-events.ts); the adapter passes it through unchanged.
  • Main handles it — orca-runtime-emit-daemon-pty-transient-fact.ts routes command-started to openCodeRunLifetime.onCommandStarted, mirroring the visible-byte path in orca-runtime-get-unpersisted-tracked-title-for-pty.ts:146 (no side-effect fact, same as visible behavior).
  • Protocol bump 38 → 39 — daemon-protocol-version.ts, daemon-protocol-version.test.ts, daemon-foreground-confirmation-protocol.test.ts, and the local-build compatibility contract (.ts + .json) all updated consistently.
  • Tests — relay unit tests (byte order, split chunks, handoff split, non-backgrounded session) and runtime tests (hidden-tab Working→Done, no double-arm while delegated, Done from main's scanner after un-hide). I ran the four touched/related suites (43 tests) and pnpm tc:node; both pass.

ℹ️ PR title claims a restart fix that was moved out of this PR

The head commit 5252676 reverts the reattach re-derivation ("survives a restart") into a separate branch, and the body correctly states that a run in flight across a restart behaves as on main and is a follow-up. The title still advertises "or survives a restart", which no longer matches the shipped scope.

Technical details
# Title overstates scope

## Affected sites
- PR title (#24238) — "show opencode run status when it starts in a hidden tab or survives a restart"
- Author description § Known gaps / TEMPORARY — restart gives no status, deferred to a follow-up PR

## Required outcome
- Title reflects only the hidden-tab fix, or the restart re-derivation is restored.

## Suggested approach (optional)
- Edit the title to drop "or survives a restart".

ℹ️ Transient-fact contract doc omits the new command-started fact

pty-provider-contract.ts:175 enumerates the transient facts a thinning transport may interleave (bell/command-finished/pr-link/2031). This PR adds a fifth (command-started), so the roster is now incomplete.

Technical details
# Stale fact roster in provider contract doc

## Affected sites
- `src/main/providers/pty-provider-contract.ts:175` — "(bell/command-finished/pr-link/2031)" omits `command-started`

## Required outcome
- Doc comment lists every `PtyTransientFact` kind the transport may emit.

## Suggested approach (optional)
- Add `command-started` to the parenthesised roster.

Pullfrog  | Fix it ➔ | View workflow run | Using DeepSeek Flash (free via Pullfrog for OSS) | 𝕏

@coderabbitai

coderabbitai Bot commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Advanced

Run ID: abdb9f51-b025-4249-ac7d-ef1709f100bd

📥 Commits

Reviewing files that changed from the base of the PR and between 5252676 and b2d1eeb.

📒 Files selected for processing (1)
  • src/main/runtime/opencode-run-lifetime-runtime.test.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 2 remain after this review.


📝 Walkthrough

Walkthrough

The daemon now emits a command-started transient fact when a command starts during background scanning. The runtime forwards the fact to OpenCode run-lifetime tracking. Tests cover background handoffs, split markers, delegated scanning, and main-process scanning. The daemon protocol and local-build compatibility contract advance from version 38 to 39.

Priority: ⬇️ Low

Merge Risk: ⚪ Minimal · up to b2d1e

Hidden-tab OpenCode runs can show Working when the v39 daemon relays a command-start marker. The supplied context identifies no new material failure, so the change is ready for normal merge checks.

Architecture Summary

Architecture risk: 🔵 Low · up to b2d1e

The change affects 1 system.

Changed systems: src

Architecture concerns
No architecture-level concerns identified.

Review details

Systems and components

  • observed — src (service) was modified; 11 changed files map to changed impact.

Before / after behavior

  • observed — Modified behavior in src/main/daemon/daemon-background-transient-facts.test.ts: Adds a test expecting a backgrounded session’s OSC 133;C marker to emit command-started before a following OSC 133;D fact with exit code 130.
  • observed — Modified behavior in src/main/daemon/daemon-background-transient-facts.test.ts: Adds a test expecting one command-started fact when OSC 133;C is split across data chunks.
  • observed — Modified behavior in src/main/daemon/daemon-background-transient-facts.test.ts: Adds a test expecting one command-started fact when the marker prefix is seeded before data scanning continues after background handoff.
  • observed — Modified behavior in src/main/daemon/daemon-background-transient-facts.test.ts: Adds a test expecting no command-started fact when the session is not backgrounded and main remains responsible for scanning.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 2 functions across 10 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly and concisely describes the primary change: showing OpenCode run status when a run starts in a hidden tab.
Description check ✅ Passed The description is detailed and covers the user impact, mechanism, rationale, scope, limitations, visual proof, testing, compatibility, and checklist. The linked issue section names related issues, al…
  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
  • 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.

@brennanb2025 brennanb2025 changed the title fix(opencode): show opencode run status when it starts in a hidden tab or survives a restart fix(opencode): show opencode run status when it starts in a hidden tab Oct 1, 2026
@brennanb2025
brennanb2025 marked this pull request as draft October 1, 2026 23:09
@brennanb2025

Copy link
Copy Markdown
Contributor Author

On hold, back to draft: Orca should not special-case one agent's one-shot command. Status should come only from the agent's own hooks, plus the normal rule that clears a row when the process exits. The opencode run detector this PR refines is being removed instead, in a PR that will be linked here. This PR will then be closed as superseded.

@brennanb2025

Copy link
Copy Markdown
Contributor Author

Closing: Orca should not special-case one agent's one-shot command, so the opencode run detector this PR refines is being removed instead (follow-up PR from branch brennanb2025/opencode-run-remove-detector). After that, opencode run shows no status, the same as other commands that fire no agent hooks.

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