Skip to content

refactor(cue): decompose executor into SRP modules and fix run manager race conditions - #790

Merged
reachrazamair merged 5 commits into
rcfrom
cue-polish
Apr 11, 2026
Merged

refactor(cue): decompose executor into SRP modules and fix run manager race conditions#790
reachrazamair merged 5 commits into
rcfrom
cue-polish

Conversation

@reachrazamair

@reachrazamair reachrazamair commented Apr 11, 2026

Copy link
Copy Markdown
Contributor

Summary

CueExecutor Decomposition (521 → 170 lines, −67%)

The cue-executor.ts module mixed four concerns: template variable population, agent spawn preparation, process lifecycle management, and history recording. This PR decomposes it into three focused modules with the executor as a thin orchestrator.

cue-template-context-builder.ts (105 lines) — Builds templateContext.cue from event payloads using an enricher registry pattern (Map<CueEventType | '*', EnricherFn>). The '*' enricher produces 15 common fields (eventType, triggerName, runId, file/source fields). Dedicated enrichers handle task.pending (6 task fields), github.pull_request, and github.issue (13 GitHub fields via shared helper). Adding a new event type requires one enricher entry — no changes to executor or engine.

cue-spawn-builder.ts (155 lines) — Pure async transformation: CueExecutionConfig + substituted prompt → SpawnSpec. Handles agent definition lookup, buildAgentArgs, applyAgentConfigOverrides, SSH wrapping via wrapSpawnWithSsh, and prompt appending (supporting -- separator, promptArgs, and noPromptSeparator modes). Returns a discriminated union ({ ok: true, spec } | { ok: false, message }) for type-safe error handling.

cue-process-lifecycle.ts (237 lines) — Spawns child processes, manages stdio capture, enforces timeouts with SIGTERM → SIGKILL escalation (5s grace period), and tracks active processes for the Process Monitor. Owns the module-level activeProcesses Map, the settled guard pattern (prevents duplicate close/error resolution), and output parser integration.

Refactored cue-executor.ts (170 lines) — Thin orchestrator: validate prompt → build template context → substitute variables → build spawn spec → run process → assemble CueRunResult. Re-exports CueProcessInfo and SpawnSpec for backwards compatibility. All delegation wrappers (stopCueRun, getActiveProcesses, getCueProcessList) preserved — zero changes to src/main/index.ts or any other consumer.

Run Manager State Machine Fix

Problem: stopRun() and the finally block of doExecuteCueRun both independently managed the "run is done" transition via a manuallyStoppedRuns Set. This caused two bugs:

  1. Spurious chain propagation after engine shutdownreset() (called by engine.stop()) cleared activeRuns and manuallyStoppedRuns, but the finally block of still-running promises would execute afterward, calling onRunCompleted and triggering downstream agent.completed chains even though the engine was shut down.

  2. No double-stop protection — Calling stopRun() twice on the same run would add it to manuallyStoppedRuns again and attempt to signal/delete/decrement a second time.

Fix: Replaced manuallyStoppedRuns Set with an explicit RunPhase type ('running' | 'stopping' | 'finished') on ActiveRun, with a transitionRun(runId, toPhase) helper that validates transitions and returns the previous phase (or null for invalid transitions).

  • stopRun() calls transitionRun(runId, 'stopping') — returns false if the run doesn't exist or is already stopping/finished. It is now fully self-contained: transition → signal kill → set result → delete from activeRuns → release sleep → free concurrency slot → drain queue → DB update → notify → log.
  • The finally block uses activeRuns.has(runId) as its guard: if the run was already removed (by stopRun or reset), it skips all cleanup entirely. Only natural completions flow through the finally path.
  • stopRun now also records updateCueEventStatus(runId, 'stopped') directly, rather than deferring to the finally block. This makes DB status consistent regardless of when the promise resolves.

Test plan

  • cue-template-context-builder.test.ts (15 tests) — enricher registry for all event types (file.changed, task.pending, github.pull_request, github.issue, time.heartbeat, time.scheduled, agent.completed), empty payload defaults, numeric/boolean coercion, unknown event type graceful handling
  • cue-spawn-builder.test.ts (13 tests) — unknown agent error, correct command/cwd, custom path, prompt appending modes (-- separator, promptArgs, noPromptSeparator), yoloMode flag, config overrides passthrough, process.env inclusion, SSH execution (wrapSpawnWithSsh call, no double-append, sshStdinScript, stdinPrompt passthrough)
  • cue-process-lifecycle.test.ts (24 tests) — spawn with correct args, stdout/stderr capture, completed/failed status, spawn errors, activeProcesses tracking, stdin close, SSH stdin modes, timeout SIGTERM/SIGKILL escalation with logging, no timeout when 0, output parsing (raw and parsed via parser registry), stopProcess (unknown/known/SIGKILL escalation), getProcessList (empty/active/completed), settled guard (duplicate close, error after close)
  • cue-run-manager.test.ts (37 tests) — phase state machine (running→stopping, running→finished, double-stop rejection), run lifecycle (onRunCompleted on success/failure/exception, onRunStopped on manual stop, chainDepth passthrough, endedAt/durationMs on stop), sleep prevention (onPreventSleep on start, onAllowSleep on completion and stop), concurrency (slot release on natural completion and stop, no double-decrement when stop followed by finally), DB recording (status update on completion and stop), race conditions (reset during active run, stopAll+reset, stop during output prompt phase), output prompt (execution on success, skip on failure), stopAll/reset (stops all runs, clears queue, releases sleep blocks), logging (runStarted/runFinished/runStopped structured events), process signaling (onStopCueRun call, AbortController abort), getActiveRunCount accuracy
  • All 729 pre-existing cue backend tests pass unchanged (766 total)
  • All 471 renderer cue tests pass unchanged
  • npm run lint — 0 type errors across all 3 tsconfig files
  • npm run lint:eslint — 0 errors on all changed files
  • Manual: open Cue Modal → trigger subscription → verify activity log entry
  • Manual: start a run → click Stop → verify it stops cleanly and queued events dispatch
  • Manual: toggle Cue off while runs are active → verify no errors in system log and no spurious chain triggers
  • Manual: trigger an agent.completed chain → verify downstream subscription fires correctly

Summary by CodeRabbit

  • Tests

    • Added broad end-to-end and unit tests covering process lifecycle, run manager, spawn spec logic, and template-context generation.
  • Refactor

    • Split execution into modular components and centralized process lifecycle with clearer run-phase state handling.
  • New Features

    • Improved timeout escalation (TERM→KILL), richer process metadata for monitoring, enhanced SSH/stdin/prompt behavior, and more robust template-context enrichment for events.

…s, −67%)

Extract three single-responsibility modules from the monolithic executor:
- cue-template-context-builder: enricher registry for event→template mapping
- cue-spawn-builder: agent definition lookup, arg building, SSH wrapping
- cue-process-lifecycle: process spawning, stdio capture, timeout enforcement

Executor becomes a thin orchestrator composing the three modules. All existing
47 executor tests pass unchanged. 52 new tests across the three modules.
…chine

Add explicit RunPhase ('running' | 'stopping' | 'finished') to ActiveRun
with a validated transitionRun() helper. stopRun() is now fully self-contained
and the finally block only handles natural completions via activeRuns.has()
guard. Fixes spurious onRunCompleted after engine reset and prevents double-stop.

New test file: cue-run-manager.test.ts (37 tests) covering phase transitions,
race conditions, concurrency slot management, and output prompt lifecycle.
@coderabbitai

coderabbitai Bot commented Apr 11, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 0cb2234d-9b63-4661-bb35-abafef1cedfe

📥 Commits

Reviewing files that changed from the base of the PR and between 9099b36 and 92d7a38.

📒 Files selected for processing (1)
  • src/main/cue/cue-executor.ts

📝 Walkthrough

Walkthrough

Extracts Cue process lifecycle, spawn-spec construction, and template-context enrichment into dedicated modules; refactors executor and run-manager to delegate to those modules; and adds comprehensive Vitest suites covering lifecycle, spawn building, run-manager state, and template-context behavior.

Changes

Cohort / File(s) Summary
Process lifecycle
src/main/cue/cue-process-lifecycle.ts
New module: runProcess, stopProcess, active-process map, stdout/stderr capture, NDJSON/JSON output parsing via getOutputParser, timeout handling (SIGTERM→SIGKILL), and getProcessList/process metadata exports.
Spawn spec builder
src/main/cue/cue-spawn-builder.ts
New buildSpawnSpec that resolves agent defs, constructs args (YOLO), applies session overrides/env, places prompt correctly, and optionally wraps command for SSH (sshStdinScript/stdinPrompt/sshRemoteUsed). Exports SpawnSpec and result types.
Template context builder
src/main/cue/cue-template-context-builder.ts
New registry-driven buildCueTemplateContext with base and event-specific enrichers (task, GitHub PR/issue), coercing payload primitives to strings and exporting CueTemplateContext.
Executor refactor
src/main/cue/cue-executor.ts
Executor simplified to validate prompt, build template context, substitute variables, call buildSpawnSpec, and delegate execution to runProcess; re-exports CueProcessInfo/SpawnSpec; removed in-file spawn/timeout/parse logic.
Run manager updates
src/main/cue/cue-run-manager.ts
Introduces RunPhase, stores phase and optional processRunId on ActiveRun, adds transitionRun, phase-aware cleanup, stops parent + output-prompt processes, and adjusts stop/completion/DB error handling.
Tests added
src/__tests__/main/cue/...
cue-process-lifecycle.test.ts, cue-run-manager.test.ts, cue-spawn-builder.test.ts, cue-template-context-builder.test.ts
Extensive Vitest suites covering lifecycle (spawn, stdin/SSH, timeouts/escalation, parsing), spawn-spec behaviors (local/SSH, prompt rules, env overrides), run-manager phase/queue/concurrency semantics, and template-context enrichment cases.

Sequence Diagram(s)

mermaid
sequenceDiagram
participant Executor as Executor
participant Builder as SpawnSpecBuilder
participant Lifecycle as ProcessLifecycle
participant Child as ChildProcess
participant Parser as OutputParser
participant Logger as onLog
Executor->>Builder: buildSpawnSpec(substitutedPrompt, config)
Builder-->>Executor: SpawnSpec (or error)
Executor->>Lifecycle: runProcess(runId, SpawnSpec, options)
Lifecycle->>Child: spawn(command,args,cwd,env)
Child-->>Lifecycle: stdout/stderr chunks
Lifecycle->>Parser: getOutputParser(toolType) → parse stdout
Child-->>Lifecycle: close / exit code
Lifecycle->>Logger: log timeout/kill/events
Lifecycle-->>Executor: ProcessRunResult (status, stdout, parsedResult)

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

Poem

🐰
I scoped the prompt and built the spawn,
I tracked the pids from dusk till dawn,
I nudged SIGTERM, then SIGKILL too,
Tests hopped in and proved what’s true,
A tidy burrow of runs brand-new.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 64.00% 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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly summarizes the main changes: refactoring the monolithic cue-executor into SRP modules and fixing run manager race conditions with phase-based state tracking.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cue-polish

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 and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Nitpick comments (1)
src/main/cue/cue-executor.ts (1)

162-164: Consider stronger typing for the return value.

The return type Map<string, any> is loose. If getActiveProcessMap() has a more specific type in cue-process-lifecycle, propagating it here would improve type safety for callers.

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

In `@src/main/cue/cue-executor.ts` around lines 162 - 164, The exported function
getActiveProcesses currently returns Map<string, any>; change its signature to a
stronger type by using the actual type from cue-process-lifecycle (either import
the concrete Map type or use ReturnType<typeof getActiveProcessMap>) so callers
get correct typings; update the return type of getActiveProcesses to that
specific type and ensure any imports (e.g., the type alias or
getActiveProcessMap) are added so the function remains a thin wrapper around
getActiveProcessMap().
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/main/cue/cue-executor.ts`:
- Around line 93-102: The code validates trimmedPrompt but then calls
substituteTemplateVariables with the original promptPath, so whitespace can
sneak back in; change the call to substituteTemplateVariables to use
trimmedPrompt (after setting templateContext.cue via buildCueTemplateContext)
and ensure any downstream logic uses trimmedPrompt instead of promptPath (refer
to trimmedPrompt, promptPath, substituteTemplateVariables,
buildCueTemplateContext, and substitutedPrompt) so substitutions operate on the
trimmed value.

In `@src/main/cue/cue-process-lifecycle.ts`:
- Around line 11-16: The code currently swallows child-process startup failures
into stderr; update the spawn logic in cue-process-lifecycle.ts to report both
synchronous spawn exceptions and ChildProcess 'error' events to Sentry (use the
same captureException call pattern as in ChildProcessSpawner.ts) and ensure such
errors convert the CueRunStatus result to a failed state. Specifically, wrap the
call to spawn(...) in a try/catch and call captureException(err) then
return/emit a failed CueRunStatus when spawn throws synchronously, and attach an
'error' listener on the returned ChildProcess that calls captureException(error)
and transitions the run to failed (same error-to-failed handling as for non-zero
exit). Ensure these changes touch the areas around the spawn invocation and the
existing listeners for the ChildProcess so both synchronous and async spawn
failures are reported and produce a failed result.

In `@src/main/cue/cue-run-manager.ts`:
- Line 181: The handler is stopping the parent runId instead of the actual
executing phase run (outputRunId), so update the stop logic to target the
phase-specific id: when you start a subprocess under a new outputRunId, store
its abortController and phase in activeRuns using outputRunId (see
activeRuns.set(...)), and call onStopCueRun(outputRunId) (not
onStopCueRun(runId)) when cancelling that subprocess; make the same change for
the other occurrence in the 374-382 region so all stop signals reference the
exact run id that owns the abortController/phase.
- Around line 399-404: The catch currently swallowing failures from
updateCueEventStatus(runId, 'stopped') must report the error to Sentry and
include runId context; update the try/catch around updateCueEventStatus to
import and call the Sentry helper (captureException or captureMessage) with the
caught error and an extra/context payload containing runId and the attempted
status ('stopped'), and also optionally log a short message via the existing
logger; do not silently ignore the exception so it surfaces for monitoring.

In `@src/main/cue/cue-spawn-builder.ts`:
- Around line 116-151: The code currently skips appending the prompt whenever
sshRemoteConfig?.enabled is true, even if wrapSpawnWithSsh didn't run because
sshStore was missing; change the logic to append the prompt unless the SSH
wrapper was actually used. Concretely, ensure the sshRemoteUsed flag (set from
sshResult.sshRemoteUsed after wrapSpawnWithSsh) is initialized false and
updated, then replace the local-only condition if (!sshRemoteConfig?.enabled)
with if (!sshRemoteUsed) so the prompt (via agentDef.promptArgs,
agentDef.noPromptSeparator, substitutedPrompt) is appended whenever the process
was not actually wrapped by wrapSpawnWithSsh.

---

Nitpick comments:
In `@src/main/cue/cue-executor.ts`:
- Around line 162-164: The exported function getActiveProcesses currently
returns Map<string, any>; change its signature to a stronger type by using the
actual type from cue-process-lifecycle (either import the concrete Map type or
use ReturnType<typeof getActiveProcessMap>) so callers get correct typings;
update the return type of getActiveProcesses to that specific type and ensure
any imports (e.g., the type alias or getActiveProcessMap) are added so the
function remains a thin wrapper around getActiveProcessMap().
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 61d893b6-84b5-46b0-b710-3b95c1ed7063

📥 Commits

Reviewing files that changed from the base of the PR and between d129114 and e00fb22.

📒 Files selected for processing (9)
  • src/__tests__/main/cue/cue-process-lifecycle.test.ts
  • src/__tests__/main/cue/cue-run-manager.test.ts
  • src/__tests__/main/cue/cue-spawn-builder.test.ts
  • src/__tests__/main/cue/cue-template-context-builder.test.ts
  • src/main/cue/cue-executor.ts
  • src/main/cue/cue-process-lifecycle.ts
  • src/main/cue/cue-run-manager.ts
  • src/main/cue/cue-spawn-builder.ts
  • src/main/cue/cue-template-context-builder.ts

Comment thread src/main/cue/cue-executor.ts Outdated
Comment thread src/main/cue/cue-process-lifecycle.ts
Comment thread src/main/cue/cue-run-manager.ts
Comment thread src/main/cue/cue-run-manager.ts
Comment thread src/main/cue/cue-spawn-builder.ts
@greptile-apps

greptile-apps Bot commented Apr 11, 2026

Copy link
Copy Markdown

Greptile Summary

This PR decomposes a 521-line cue-executor.ts into three focused modules (template context builder, spawn builder, process lifecycle) and replaces the manuallyStoppedRuns Set in the run manager with a RunPhase state machine to eliminate two documented race conditions. The architectural separation is clean, test coverage is thorough (89 new tests), and backwards compatibility is preserved through re-exports. All remaining findings are P2.

Confidence Score: 5/5

Safe to merge — no P0/P1 issues; all findings are P2 style suggestions that do not affect correctness on the changed path.

The RunPhase state machine correctly eliminates both documented race conditions. The module decomposition is clean, backwards compatibility is preserved via re-exports, and the 89-test suite covers phase transitions, race conditions, concurrency, DB recording, and SSH paths. All three inline comments are non-blocking improvements.

src/main/cue/cue-run-manager.ts — three P2 concerns: this.stopRun binding in stopAll(), reset() not signaling processes, and output-prompt process not cancellable via stopRun.

Important Files Changed

Filename Overview
src/main/cue/cue-run-manager.ts Core race-condition fix: replaces manuallyStoppedRuns Set with RunPhase state machine. Logic is sound; minor concerns around reset() not signaling processes and this-binding in stopAll().
src/main/cue/cue-process-lifecycle.ts Extracted process spawning, stdio capture, timeout/SIGTERM/SIGKILL escalation, and active-process tracking into a dedicated module. The settled guard correctly prevents duplicate resolution.
src/main/cue/cue-spawn-builder.ts Pure transformation from CueExecutionConfig to SpawnSpec; discriminated union return type for type-safe error handling. SSH wrapping and prompt appending logic mirrors the existing process:spawn IPC path.
src/main/cue/cue-template-context-builder.ts Enricher registry pattern cleanly separates per-event-type context building. Shared GitHub enricher avoids duplication between pull_request and issue handlers.
src/main/cue/cue-executor.ts Reduced to a thin orchestrator (170 lines). Re-exports CueProcessInfo and SpawnSpec for backwards compatibility. Delegation wrappers preserved with no IPC handler changes required.
src/tests/main/cue/cue-run-manager.test.ts 37 tests covering phase state machine, lifecycle, concurrency, DB recording, race conditions (reset-during-run, stopAll+reset, stop-during-output-prompt), and process signaling.
src/tests/main/cue/cue-process-lifecycle.test.ts 24 tests covering spawn, stdio capture, timeout escalation, stopProcess, getProcessList, settled guard, SSH stdin modes, and output parser integration.
src/tests/main/cue/cue-spawn-builder.test.ts 13 tests covering agent lookup, prompt appending modes, yoloMode, config overrides, process.env inclusion, and SSH wrapping.
src/tests/main/cue/cue-template-context-builder.test.ts 15 tests covering all event types, empty payload defaults, numeric/boolean coercion, and unknown event type graceful handling.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[CueEngine triggers event] --> B[CueRunManager.execute]
    B --> C{Concurrency slot available?}
    C -- No --> D[Queue event]
    C -- Yes --> E[doExecuteCueRun phase: running]
    E --> F[CueTemplateContextBuilder]
    F --> G[substituteTemplateVariables]
    G --> H[CueSpawnBuilder buildSpawnSpec]
    H --> I{SSH enabled?}
    I -- Yes --> J[wrapSpawnWithSsh]
    I -- No --> K[Append prompt to args]
    J --> L[CueProcessLifecycle runProcess]
    K --> L
    L --> M[spawn child process]
    M --> N{Outcome}
    N -- Natural exit --> O[finally block activeRuns.has check]
    N -- Timeout SIGTERM/SIGKILL --> O
    O -- run still tracked --> P[transitionRun finished / onRunCompleted]
    O -- removed by stopRun/reset --> Q[Skip no spurious callbacks]
    R[stopRun called] --> S[transitionRun stopping]
    S --> T[delete from activeRuns / release slot]
    T --> U[onStopCueRun SIGTERM process]
    T --> V[onRunStopped DB update]
    W[reset called] --> X[onAllowSleep each run / clear maps]
    X --> Q
Loading

Comments Outside Diff (3)

  1. src/main/cue/cue-run-manager.ts, line 415-420 (link)

    P2 this.stopRun binding depends on call context

    stopAll calls this.stopRun(runId), which works when invoked as manager.stopAll() but silently breaks if the method is ever destructured (const { stopAll } = manager; stopAll()). Since stopRun is accessible within the closure, a safer approach is to call it directly without this:

    …where stopRunImpl is extracted as a named closure inside createCueRunManager containing the current stopRun body. This avoids the implicit this dependency entirely.

  2. src/main/cue/cue-run-manager.ts, line 459-466 (link)

    P2 reset() releases sleep but does not signal processes

    reset() calls onAllowSleep and clears all maps, but it does not call deps.onStopCueRun or run.abortController?.abort() for each active run. After reset(), the underlying child processes continue running until natural completion — the doExecuteCueRun finally-block guard correctly prevents spurious onRunCompleted callbacks, but the processes themselves are orphaned. By contrast, stopAll() correctly signals each run. If the engine only calls reset() (without a prior stopAll()), processes are left running after engine shutdown. Consider signaling each run inside reset():

  3. src/main/cue/cue-run-manager.ts, line 228-281 (link)

    P2 Output-prompt process not stoppable via stopRun

    When stopRun(runId) is called during the output-prompt phase, deps.onStopCueRun(runId) is invoked with the main run ID. By that point the main process has already exited and been removed from activeProcesses, so stopProcess(runId) returns false — a no-op. The output-prompt process (tracked under outputRunId) continues running until natural completion. The run-manager result correctly shows 'stopped' and the doExecuteCueRun finally-block correctly skips onRunCompleted, so there is no spurious chain propagation. But the child process consuming time/resources is not terminated.

    To stop the output-prompt process as well, outputRunId would need to be stored (e.g. on ActiveRun) so stopRun can signal it. This may be acceptable as a known limitation — worth a comment or a follow-up issue.

Reviews (1): Last reviewed commit: "refactor(cue): replace manuallyStoppedRu..." | Re-trigger Greptile

…anager, and spawn builder

- Use trimmedPrompt in substituteTemplateVariables instead of raw promptPath
- Add Sentry reporting for both sync and async spawn failures in process lifecycle
- Stop output prompt subprocess with correct runId via new processRunId field
- Report DB update failures to Sentry with context instead of silently swallowing
- Use sshRemoteUsed flag for prompt append guard so missing sshStore falls back correctly
- Tighten getActiveProcesses return type from Map<string, any> to actual type

7 new tests covering Sentry reporting, output prompt stop targeting, DB error
handling, and SSH fallback prompt appending.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/__tests__/main/cue/cue-spawn-builder.test.ts`:
- Around line 220-227: The test currently asserts process.env.PATH which is
platform-fragile; modify the test that calls buildSpawnSpec(createConfig(),
'prompt') to instead seed a unique temporary environment variable on process.env
(e.g., TEMP_TEST_ENV = 'some-value') before invoking buildSpawnSpec, then assert
that result.ok is true and that result.spec.env[TEMP_TEST_ENV] equals the seeded
value; finally, remove or restore the temporary env var after the assertion. Use
the existing symbols buildSpawnSpec, createConfig and result.spec.env to locate
where to inject the setup/teardown and assertion.

In `@src/main/cue/cue-executor.ts`:
- Around line 124-130: The runProcess call is passing sshRemoteEnabled based on
sshRemoteConfig?.enabled which can differ from the actual decision made by
buildSpawnSpec(); update the runProcess invocation to use spec.sshRemoteUsed
(and only pass sshStdinScript/stdinPrompt when spec.sshRemoteUsed is true) so
runProcess sees whether SSH wrapping is actually used and won't duplicate stdin
delivery. Locate the runProcess call and replace sshRemoteEnabled:
sshRemoteConfig?.enabled with sshRemoteEnabled: spec.sshRemoteUsed, and
conditionally include sshStdinScript/stdinPrompt based on spec.sshRemoteUsed to
avoid sending the prompt for local fallbacks.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 7faee5a2-54a7-416f-b240-728a413bd2a9

📥 Commits

Reviewing files that changed from the base of the PR and between e00fb22 and af475a6.

📒 Files selected for processing (7)
  • src/__tests__/main/cue/cue-process-lifecycle.test.ts
  • src/__tests__/main/cue/cue-run-manager.test.ts
  • src/__tests__/main/cue/cue-spawn-builder.test.ts
  • src/main/cue/cue-executor.ts
  • src/main/cue/cue-process-lifecycle.ts
  • src/main/cue/cue-run-manager.ts
  • src/main/cue/cue-spawn-builder.ts
✅ Files skipped from review due to trivial changes (2)
  • src/main/cue/cue-process-lifecycle.ts
  • src/tests/main/cue/cue-process-lifecycle.test.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/main/cue/cue-run-manager.ts
  • src/main/cue/cue-spawn-builder.ts

Comment thread src/__tests__/main/cue/cue-spawn-builder.test.ts
Comment thread src/main/cue/cue-executor.ts
…tform-fragile env test

- cue-executor: derive sshActuallyUsed from spec.sshRemoteUsed (the resolved
  SSH config) rather than sshRemoteConfig?.enabled (the requested config).
  This prevents stdin misdelivery when SSH is configured but sshStore is
  missing and the wrapper was never called. Also gates sshStdinScript and
  stdinPrompt on sshActuallyUsed so they are not passed through in local mode.

- cue-spawn-builder.test: replace PATH assertion (undefined on some CI
  environments) with a seeded __CUE_SPAWN_TEST__ env var in a try/finally
  block so the test is deterministic on all platforms.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/main/cue/cue-executor.ts (1)

36-50: Consider moving inline import types to the import section.

The inline import types for CueEvent and SshRemoteSettingsStore work correctly but deviate from the standard pattern of top-level imports used elsewhere in the file. Moving them to the import section would improve consistency.

♻️ Suggested refactor
 import type { CueRunResult, CueSubscription } from './cue-types';
+import type { CueEvent } from './cue-types';
 import type { HistoryEntry, SessionInfo } from '../../shared/types';
 import { substituteTemplateVariables, type TemplateContext } from '../../shared/templateVariables';
 import { buildCueTemplateContext } from './cue-template-context-builder';
 import { buildSpawnSpec } from './cue-spawn-builder';
+import type { SshRemoteSettingsStore } from '../utils/ssh-remote-resolver';
 ...
 export interface CueExecutionConfig {
 	...
-	event: import('./cue-types').CueEvent;
+	event: CueEvent;
 	...
-	sshStore?: import('../utils/ssh-remote-resolver').SshRemoteSettingsStore;
+	sshStore?: SshRemoteSettingsStore;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/cue/cue-executor.ts` around lines 36 - 50, Move the inline type
imports to the top import section: add "import type { CueEvent } from
'./cue-types';" and "import type { SshRemoteSettingsStore } from
'../utils/ssh-remote-resolver';" (use "import type" to avoid runtime imports),
then replace the inline type annotations in the parameter/interface (the event
property and sshStore?: ...) so they reference CueEvent and
SshRemoteSettingsStore directly (e.g., event: CueEvent; sshStore?:
SshRemoteSettingsStore;). Ensure any references to the previous inline import
syntax are removed.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/main/cue/cue-executor.ts`:
- Around line 36-50: Move the inline type imports to the top import section: add
"import type { CueEvent } from './cue-types';" and "import type {
SshRemoteSettingsStore } from '../utils/ssh-remote-resolver';" (use "import
type" to avoid runtime imports), then replace the inline type annotations in the
parameter/interface (the event property and sshStore?: ...) so they reference
CueEvent and SshRemoteSettingsStore directly (e.g., event: CueEvent; sshStore?:
SshRemoteSettingsStore;). Ensure any references to the previous inline import
syntax are removed.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 871bb869-e52b-45dd-ab41-e83f04b6ec45

📥 Commits

Reviewing files that changed from the base of the PR and between af475a6 and 9099b36.

📒 Files selected for processing (2)
  • src/__tests__/main/cue/cue-spawn-builder.test.ts
  • src/main/cue/cue-executor.ts
✅ Files skipped from review due to trivial changes (1)
  • src/tests/main/cue/cue-spawn-builder.test.ts

…ports

Replace import('./cue-types').CueEvent and
import('../utils/ssh-remote-resolver').SshRemoteSettingsStore inline
annotations in CueExecutionConfig with proper top-level import type
declarations, keeping runtime-free type-only imports.
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