Skip to content

Track per-terminal subprocess activity in thread state#105

Merged
juliusmarminge merged 1 commit intomainfrom
codething/2860c0a0
Feb 27, 2026
Merged

Track per-terminal subprocess activity in thread state#105
juliusmarminge merged 1 commit intomainfrom
codething/2860c0a0

Conversation

@juliusmarminge
Copy link
Copy Markdown
Member

@juliusmarminge juliusmarminge commented Feb 27, 2026

Summary

  • wire terminal event subscription in the root route to track per-terminal subprocess activity in client state
  • add SET_THREAD_TERMINAL_ACTIVITY reducer action to maintain runningTerminalIds per thread
  • ignore activity updates for unknown terminal IDs and normalize terminal state updates
  • add terminalRunningSubprocessFromEvent helper to map terminal events to running/idle/no-op activity signals
  • add focused Vitest coverage for reducer behavior and terminal event mapping

Testing

  • apps/web/src/store.test.ts: verifies add/remove/ignore behavior for runningTerminalIds
  • apps/web/src/terminalActivity.test.ts: verifies activity parsing for activity, started/restarted/exited, and ignored event types
  • Lint: Not run
  • Full test suite: Not run

Note

Medium Risk
Adds a new terminal event subscription and reducer path that continuously mutates per-thread runningTerminalIds, which can affect UI behavior that depends on terminal busy/idle state. Risk is moderate due to new event-driven state updates, but it’s scoped to client-side state and covered by focused tests.

Overview
Tracks per-terminal subprocess activity in client state. The root EventRouter now subscribes to api.terminal.onEvent, maps terminal events to a running/idle signal, and dispatches a new SET_THREAD_TERMINAL_ACTIVITY action.

The store reducer adds setThreadTerminalActivity to maintain each thread’s runningTerminalIds (ignoring unknown terminal IDs and normalizing terminal state). Adds terminalRunningSubprocessFromEvent plus Vitest coverage for both the event mapping and reducer add/remove/ignore behavior.

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

Note

Track per-thread terminal subprocess activity and dispatch SET_THREAD_TERMINAL_ACTIVITY from EventRouter in __root.tsx

Add terminal event subscription that derives subprocess activity via terminalActivity.terminalRunningSubprocessFromEvent and updates thread state through the reducer, with tests covering event mapping and store updates.

📍Where to Start

Start with EventRouter in apps/web/src/routes/__root.tsx, then review terminalActivity.terminalRunningSubprocessFromEvent in apps/web/src/terminalActivity.ts and the SET_THREAD_TERMINAL_ACTIVITY case in apps/web/src/store.ts.

Macroscope summarized c901709.

Summary by CodeRabbit

  • New Features

    • Enhanced terminal subprocess activity monitoring to accurately track when subprocesses are running across terminals, providing real-time visibility into terminal operations.
  • Tests

    • Added comprehensive test coverage for terminal activity state management, including subprocess start, stop, and activity scenarios.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Feb 27, 2026

Walkthrough

This PR introduces terminal activity tracking by adding a new Redux action to manage subprocess status per terminal, a utility function to derive subprocess state from terminal events, and integrating event listeners into the root component to dispatch state updates.

Changes

Cohort / File(s) Summary
Store Terminal Activity Management
apps/web/src/store.ts, apps/web/src/store.test.ts
Added SET_THREAD_TERMINAL_ACTIVITY action type with threadId, terminalId, and hasRunningSubprocess fields; implemented helper function setThreadTerminalActivity to toggle terminal running state and reducer case to update the target thread's running subprocess set.
Terminal Subprocess Derivation
apps/web/src/terminalActivity.ts, apps/web/src/terminalActivity.test.ts
Introduced terminalRunningSubprocessFromEvent utility function that extracts subprocess running state from TerminalEvent objects, returning the hasRunningSubprocess flag for activity events and false for lifecycle events (started, restarted, exited).
Event Integration
apps/web/src/routes/__root.tsx
Wired terminal event listener to dispatch SET_THREAD_TERMINAL_ACTIVITY actions when subprocesses are detected; added proper cleanup via unsubscription during component teardown alongside existing event handlers.

Sequence Diagram

sequenceDiagram
    participant TerminalAPI as Terminal API
    participant Root as Root Component
    participant Utility as terminalRunningSubprocessFromEvent
    participant Store as Redux Store
    participant State as Thread State

    TerminalAPI->>Root: onEvent (TerminalEvent)
    Root->>Utility: terminalRunningSubprocessFromEvent(event)
    Utility-->>Root: boolean | null
    Root->>Store: dispatch SET_THREAD_TERMINAL_ACTIVITY
    Store->>Store: reducer: setThreadTerminalActivity()
    Store->>State: update thread.runningTerminalIds
    State-->>Root: state updated
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Track per-terminal subprocess activity in thread state' accurately and specifically summarizes the main change: implementing per-terminal subprocess activity tracking integrated into the thread state management system.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch codething/2860c0a0

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
apps/web/src/store.ts (1)

379-398: Avoid no-op state churn on repeated terminal activity events.

Lines 379-398 and Lines 566-572 currently rebuild thread/state even when hasRunningSubprocess doesn’t change. On high-frequency terminal events, this can trigger unnecessary rerenders.

♻️ Proposed refactor (short-circuit unchanged updates)
 function setThreadTerminalActivity(
   thread: Thread,
   terminalId: string,
   hasRunningSubprocess: boolean,
 ): Thread {
-  const normalizedThread = normalizeThreadTerminals(thread);
-  if (!normalizedThread.terminalIds.includes(terminalId)) {
-    return normalizedThread;
+  if (!thread.terminalIds.includes(terminalId)) {
+    return thread;
   }
-  const runningTerminalIds = new Set(normalizedThread.runningTerminalIds);
-  if (hasRunningSubprocess) {
-    runningTerminalIds.add(terminalId);
-  } else {
-    runningTerminalIds.delete(terminalId);
+  const isRunning = thread.runningTerminalIds.includes(terminalId);
+  if (isRunning === hasRunningSubprocess) {
+    return thread;
   }
+
+  const normalizedThread = normalizeThreadTerminals(thread);
+  const runningTerminalIds = hasRunningSubprocess
+    ? [...new Set([...normalizedThread.runningTerminalIds, terminalId])]
+    : normalizedThread.runningTerminalIds.filter((id) => id !== terminalId);
+
   return normalizeThreadTerminals({
     ...normalizedThread,
-    runningTerminalIds: [...runningTerminalIds],
+    runningTerminalIds,
   });
 }
@@
-    case "SET_THREAD_TERMINAL_ACTIVITY":
-      return {
-        ...state,
-        threads: updateThread(state.threads, action.threadId, (thread) =>
-          setThreadTerminalActivity(thread, action.terminalId, action.hasRunningSubprocess),
-        ),
-      };
+    case "SET_THREAD_TERMINAL_ACTIVITY": {
+      let changed = false;
+      const threads = state.threads.map((thread) => {
+        if (thread.id !== action.threadId) return thread;
+        const nextThread = setThreadTerminalActivity(
+          thread,
+          action.terminalId,
+          action.hasRunningSubprocess,
+        );
+        changed ||= nextThread !== thread;
+        return nextThread;
+      });
+      return changed ? { ...state, threads } : state;
+    }

Also applies to: 566-572

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/src/store.ts` around lines 379 - 398, setThreadTerminalActivity is
rebuilding the Thread object on every terminal event even when the
runningTerminalIds set doesn’t change; fix by short-circuiting: compute
currentHasRunning = normalizedThread.runningTerminalIds.includes(terminalId) and
if currentHasRunning === hasRunningSubprocess return normalizedThread
immediately (no spread/normalize) otherwise proceed to add/delete and return the
updated normalized thread; apply the same short-circuit pattern to the analogous
terminal-activity updater that also manipulates runningTerminalIds (the other
function handling terminal activity in this file) and reuse
normalizeThreadTerminals consistently.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@apps/web/src/store.ts`:
- Around line 379-398: setThreadTerminalActivity is rebuilding the Thread object
on every terminal event even when the runningTerminalIds set doesn’t change; fix
by short-circuiting: compute currentHasRunning =
normalizedThread.runningTerminalIds.includes(terminalId) and if
currentHasRunning === hasRunningSubprocess return normalizedThread immediately
(no spread/normalize) otherwise proceed to add/delete and return the updated
normalized thread; apply the same short-circuit pattern to the analogous
terminal-activity updater that also manipulates runningTerminalIds (the other
function handling terminal activity in this file) and reuse
normalizeThreadTerminals consistently.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0d67424 and 051f352.

📒 Files selected for processing (5)
  • apps/web/src/routes/__root.tsx
  • apps/web/src/store.test.ts
  • apps/web/src/store.ts
  • apps/web/src/terminalActivity.test.ts
  • apps/web/src/terminalActivity.ts

- subscribe to terminal events in root route and dispatch terminal activity updates
- add reducer support to maintain `runningTerminalIds` per thread/terminal
- add unit tests for terminal event mapping and store activity state transitions
@juliusmarminge juliusmarminge merged commit 68585d4 into main Feb 27, 2026
4 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