Skip to content

Add semantic status updates for Codex and OpenCode#1340

Merged
rabanspiegel merged 5 commits intomainfrom
emdash/codex-opencode-status
Mar 6, 2026
Merged

Add semantic status updates for Codex and OpenCode#1340
rabanspiegel merged 5 commits intomainfrom
emdash/codex-opencode-status

Conversation

@rabanspiegel
Copy link
Contributor

@rabanspiegel rabanspiegel commented Mar 6, 2026

Summary

  • add Codex semantic status updates to the shared agent status infrastructure
  • add OpenCode semantic status updates and drive working state from real submitted input instead of PTY output parsing
  • keep the existing unread/update behavior and shared sidebar/tab indicators for these providers

Testing

  • pnpm run type-check
  • pnpm exec vitest run src/test/renderer/agentStatusStore.test.ts src/test/main/AgentEventService.test.ts

Note

Medium Risk
Changes how agent status transitions to working by driving it from captured submitted input (and extends event mapping) for multiple providers, which can affect sidebar/unread indicators and perceived agent activity. Risk is limited to renderer status/terminal input handling with added unit coverage.

Overview
Adds semantic agent status support for Codex and OpenCode, extending provider adapters so their agent events can drive waiting/complete/error and user submits can set working.

Refactors AgentStatusStore to mark working immediately on submit (removing PTY-output-based confirmation), and updates terminal/injection paths to only call markUserInputSubmitted when a real non-empty submit is detected via new submitCapture tracking. Extracts ANSI stripping into shared stripAnsi and adds unit tests for the new status mappings and submit-capture logic.

Written by Cursor Bugbot for commit d673462. This will update automatically on new commits. Configure here.

@vercel
Copy link

vercel bot commented Mar 6, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
docs Ready Ready Preview, Comment Mar 6, 2026 9:45pm

Request Review

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Mar 6, 2026

Greptile Summary

This PR adds semantic status tracking for Codex and OpenCode providers by wiring them into the shared agentStatusStore infrastructure, and replaces the previous PTY-output-parsing approach to determining "working" state with direct tracking of submitted user input across all three supported providers (Claude, Codex, OpenCode).

Key changes:

  • providerStatusAdapters.ts — extends the provider allow-lists so that codex and opencode agent events (stop, error, notification) are mapped to the correct AgentStatusKind, and markUserInputSubmitted now returns 'working' for all three providers.
  • agentStatusStore.ts — removes the pendingSubmitPtyIds set and the handlePtyData method; markUserInputSubmitted now immediately transitions status to working without waiting for a confirming PTY-output signal.
  • TerminalSessionManager.ts — introduces consumeSubmittedInput, a character-level input tracker that determines whether an Enter-press carries actual content, replacing the old PTY-data event hook. The agentStatusStore.handlePtyData call is removed from the PTY data listener. Contains a logic bug in the pending-injection path (see inline comment).
  • usePendingInjection.ts — guards markUserInputSubmitted behind text.trim() to avoid false working transitions on empty/whitespace submits.
  • useInitialPromptInjection.ts — calls markUserInputSubmitted optimistically just before the PTY input write, correctly covering the initial-prompt path for all supported providers.
  • Tests updated to cover the new immediate-working behavior and new provider mappings.

Confidence Score: 3/5

  • Safe to merge after fixing the short-circuit logic bug in the pending-injection path of TerminalSessionManager.
  • The architectural simplification is clean and well-tested. One concrete logic bug was found in TerminalSessionManager.ts at line 612: the (submittedText || pendingText).trim() expression can silently suppress a markUserInputSubmitted call when submittedText is whitespace-only but pendingText has real content. An additional inherent design limitation exists — terminal history recall (Up Arrow) bypasses currentSubmittedInput tracking because the recalled text arrives as PTY output, not as typed characters — but this is a known trade-off of the input-side approach and not a regression from the previous behavior for Codex/OpenCode (which had no tracking at all before this PR).
  • src/renderer/terminal/TerminalSessionManager.ts — specifically the pending-injection condition at line 612.

Important Files Changed

Filename Overview
src/renderer/lib/agentStatusStore.ts Removes the pendingSubmitPtyIds set and the handlePtyData method entirely; markUserInputSubmitted now immediately sets status to working rather than waiting for PTY-output confirmation. Clean simplification with no issues.
src/renderer/lib/providerStatusAdapters.ts Extends provider allow-lists to include codex and opencode in both mapAgentEventToStatus and mapUserInputToStatus. Straightforward, correct change.
src/renderer/terminal/TerminalSessionManager.ts Introduces consumeSubmittedInput to track typed characters and determine whether an Enter-press carries real content, replacing the prior PTY-output-based confirmation. Contains a logic bug at line 612 where whitespace-only submittedText suppresses a valid pendingText-based markUserInputSubmitted call. Additionally, history-recall via arrow keys is not reflected in currentSubmittedInput (a known design limitation of input-side tracking).
src/renderer/hooks/useInitialPromptInjection.ts Adds agentStatusStore.markUserInputSubmitted call immediately before the PTY input write; status is optimistically set to working before confirmation. The ordering is safe because a failed ptyInput call leaves sent=false, allowing retry, and PTY exit will eventually reset status to idle.
src/renderer/hooks/usePendingInjection.ts Adds a text.trim() guard around markUserInputSubmitted so that submitting empty/whitespace text does not incorrectly transition the agent to working. Correct defensive fix.
src/test/renderer/agentStatusStore.test.ts Updates and extends test coverage for the new immediate working-on-submit behavior for Claude, Codex, and OpenCode; adds notification-mapping tests for all three providers. Removed tests that relied on the now-deleted PTY-data confirmation path. Good coverage.

Sequence Diagram

sequenceDiagram
    participant User
    participant TerminalSessionManager
    participant usePendingInjection
    participant useInitialPromptInjection
    participant agentStatusStore
    participant AgentEventService

    Note over User,AgentEventService: Path A — Direct keyboard input (new consumeSubmittedInput logic)
    User->>TerminalSessionManager: keypress (chars + Enter)
    TerminalSessionManager->>TerminalSessionManager: consumeSubmittedInput() → submittedText
    alt submittedText is non-empty
        TerminalSessionManager->>agentStatusStore: markUserInputSubmitted({ ptyId })
        agentStatusStore-->>agentStatusStore: status → working
    end
    TerminalSessionManager->>ElectronAPI: ptyInput(data)

    Note over User,AgentEventService: Path B — Pending injection (usePendingInjection.sendNow)
    User->>usePendingInjection: sendNow(ptyId, text)
    alt text.trim() non-empty
        usePendingInjection->>agentStatusStore: markUserInputSubmitted({ ptyId })
        agentStatusStore-->>agentStatusStore: status → working
    end
    usePendingInjection->>ElectronAPI: ptyInput(text + "\r")

    Note over User,AgentEventService: Path C — Initial prompt injection
    useInitialPromptInjection->>agentStatusStore: markUserInputSubmitted({ ptyId })
    agentStatusStore-->>agentStatusStore: status → working
    useInitialPromptInjection->>ElectronAPI: ptyInput(prompt + "\n")

    Note over User,AgentEventService: Semantic event updates (Codex / OpenCode / Claude)
    AgentEventService->>agentStatusStore: handleAgentEvent({ type: "notification", notificationType: "idle_prompt" | "permission_prompt" })
    agentStatusStore-->>agentStatusStore: status → waiting (+ unread flag)
    AgentEventService->>agentStatusStore: handleAgentEvent({ type: "stop" })
    agentStatusStore-->>agentStatusStore: status → complete (+ unread flag)
    AgentEventService->>agentStatusStore: handleAgentEvent({ type: "error" })
    agentStatusStore-->>agentStatusStore: status → error (+ unread flag)
Loading

Last reviewed commit: 673118a

Comment on lines +612 to +614
if ((submittedText || pendingText).trim()) {
agentStatusStore.markUserInputSubmitted({ ptyId: this.id });
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Incorrect short-circuit || may suppress markUserInputSubmitted call

(submittedText || pendingText).trim() uses JavaScript's short-circuit ||, which returns submittedText when it is truthy — even if it is whitespace-only (e.g. " "). In that case .trim() yields "" (falsy) and markUserInputSubmitted is never called, even though pendingText is guaranteed truthy and non-empty at this point in the code (the outer if (pendingText && ...) already confirmed it).

Concrete scenario: user presses the spacebar once before an Enter key, triggering the pending-injection path. submittedText would be " " (truthy but whitespace), so " ".trim() is "", the condition is false, and the agent status stays at unknown / its prior state instead of flipping to working.

Suggested change
if ((submittedText || pendingText).trim()) {
agentStatusStore.markUserInputSubmitted({ ptyId: this.id });
}
if (submittedText?.trim() || pendingText.trim()) {

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

@rabanspiegel rabanspiegel merged commit 9472a2e into main Mar 6, 2026
5 checks passed
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