feat(ci): implement auto-trigger agent on CI failure#1500
feat(ci): implement auto-trigger agent on CI failure#1500singhvibhanshu wants to merge 1 commit intogeneralaction:mainfrom
Conversation
|
@singhvibhanshu is attempting to deploy a commit to the General Action Team on Vercel. A member of the Team first needs to authorize it. |
Greptile SummaryThis PR adds an auto-trigger agent on CI failure feature that polls GitHub Actions for failed workflows on active task branches, fetches and truncates error logs, and spawns an AI agent to attempt a fix. It includes a settings UI card, per-branch retry state tracking, worktree locking, and local/remote HEAD drift guards.
Confidence Score: 2/5
|
| Filename | Overview |
|---|---|
| src/main/services/ci/types.ts | Clean type definitions for CI auto-fix config, retry state, failure candidates, and parsed logs. No issues. |
| src/main/services/ci/config.ts | Well-structured config resolution with proper normalization, bounds checking, and project-level override support. No issues. |
| src/main/services/ci/logParser.ts | Log parsing with ANSI stripping and tail-based truncation. Step-scoped filtering relies on tab-delimited gh log format which is reasonable. |
| src/main/services/ci/stateTracker.ts | Retry state tracking with manual-commit reset detection and async persistence queue. Solid design for preventing infinite retry loops. |
| src/main/services/ci/monitor.ts | Polling-based CI failure monitor. Issue: polls database and GitHub API unconditionally even when feature is globally disabled, wasting resources. |
| src/main/services/ci/orchestrator.ts | Core orchestrator with lock management, race condition guards, and agent spawning. Issues: auto-mode prompt contradicts actual commit/push behavior; remote-drift safety check silently bypassed when initial remote HEAD is null. |
| src/main/main.ts | Clean integration: starts orchestrator on app ready, stops on before-quit. Follows existing service lifecycle patterns. |
| src/main/settings.ts | Adds ciAutoFix to AppSettings with proper normalization. Duplicates validation logic from config.ts but follows existing settings patterns. |
| src/renderer/components/CiAutoFixSettingsCard.tsx | Settings UI card with toggle, dropdowns, and numeric inputs. Follows existing component patterns. Sub-controls not disabled when feature toggle is off (minor UX). |
| src/renderer/components/SettingsPage.tsx | Minimal change adding CI auto-fix card to the repository settings tab. No issues. |
| src/test/main/ci/logParser.test.ts | Single test for sanitize+truncate. Coverage is minimal — no tests for fetchAndParseFailedLog, extractLinesForFailedSteps, or collectFailedStepNames. |
| src/test/main/ci/orchestrator.test.ts | Tests the head-mismatch abort path. Good but only covers one scenario; no tests for auto-mode commit/push flow, review mode, or lock contention. |
| src/test/main/ci/stateTracker.test.ts | Good coverage of retry counting, halting, and manual-commit reset. Well-structured tests with temp directory cleanup. |
Sequence Diagram
sequenceDiagram
participant Main as main.ts
participant Orch as Orchestrator
participant Mon as Monitor
participant DB as DatabaseService
participant GH as gh CLI
participant Agent as AI Agent
participant Git as git
Main->>Orch: start()
Orch->>Mon: start(onFailure)
loop Every pollIntervalMs
Mon->>DB: getTasks() + getProjects()
Mon->>GH: gh run list --branch <branch>
alt Failed run found & passes filters
Mon->>Orch: onFailure(candidate, config)
Orch->>Git: rev-parse HEAD (local)
Orch->>Git: ls-remote origin (remote)
alt Heads match & lock acquired
Orch->>GH: gh run view <runId> --log-failed
Orch->>Agent: spawn(cli, prompt)
Agent-->>Orch: exit(0)
alt auto mode & files changed
Orch->>Git: add -A + commit + push
else review mode
Orch-->>Main: notify user
end
end
end
end
Main->>Orch: stop()
Orch->>Mon: stop()
Last reviewed commit: cd914b6
| const loop = async () => { | ||
| if (this.isPolling) { | ||
| return; | ||
| } | ||
| this.isPolling = true; | ||
|
|
||
| try { | ||
| const tasks = await databaseService.getTasks(); |
There was a problem hiding this comment.
Monitor polls even when feature is disabled
The CiFailureMonitorService.start() is called unconditionally from main.ts, and the polling loop fires every pollIntervalMs regardless of the global enabled flag. The enabled check only happens inside processTask after the loop has already fetched all tasks and projects from the database, and then calls gh run list for every active task before checking the per-project config.
Consider adding an early-exit at the top of the loop function:
| const loop = async () => { | |
| if (this.isPolling) { | |
| return; | |
| } | |
| this.isPolling = true; | |
| try { | |
| const tasks = await databaseService.getTasks(); | |
| const loop = async () => { | |
| if (this.isPolling) { | |
| return; | |
| } | |
| this.isPolling = true; | |
| try { | |
| const globalConfig = getGlobalCiAutoFixConfig(); | |
| if (!globalConfig.enabled) { | |
| return; | |
| } | |
| const tasks = await databaseService.getTasks(); |
This avoids unnecessary database and GitHub API calls when the user has not enabled the feature.
| const modeInstruction = | ||
| mode === 'auto' | ||
| ? 'Do not commit or push by yourself. Only modify files and explain what you changed.' | ||
| : 'Do not commit or push. Only modify files in the working tree so a human can review.'; |
There was a problem hiding this comment.
Auto-mode prompt contradicts actual behavior
In auto mode the prompt tells the agent "Do not commit or push by yourself. Only modify files and explain what you changed." — but finalizeAutoMode (line 308) then commits with git add -A and git push origin HEAD:... on behalf of the agent. Meanwhile in review mode the instruction is nearly identical: "Do not commit or push. Only modify files..."
The auto mode instruction should make it clearer that the orchestrator will handle committing and pushing, not the agent. Right now both modes give virtually the same instruction, making auto mode indistinguishable to the agent.
| return; | ||
| } | ||
|
|
||
| await this.finalizeAutoMode(candidate, branchKey, localHeadSha, remoteHeadAtStart); |
There was a problem hiding this comment.
Remote-drift safety check silently skipped when remoteHeadAtStart is null
If getRemoteHeadSha returns null at the start (e.g. network error, new branch not yet pushed), remoteHeadAtStart is null. Then in finalizeAutoMode (line 315), the condition if (remoteHeadAtStart && remoteHeadBeforePush && ...) short-circuits and the remote-drift check is entirely bypassed. This means the push proceeds without any verification that the remote hasn't changed.
Consider logging a warning or treating a null remote head at start as an unknown state that should block auto-push, rather than silently skipping the safety check.
|
will apply the suggested changes and logic gaps soon! |
Summary
This PR introduces the Auto-trigger agent on CI failure feature. It automatically monitors active task branches for GitHub Actions workflow failures. When a failure occurs, Emdash fetches and smartly truncates the error logs, spins up an agent in the task's worktree, and allows the AI to attempt a fix—closing the feedback loop without manual context switching.
Key Implementation Details:
CiAutoFixSettingsCardto the existing Settings UI so users can easily toggle modes (autovs.review), set retry limits, and define trigger filters (e.g., test/lint only) without manually editing.emdash.json.Fixes
Fixes #1375
Type of change
Mandatory Tasks
Checklist
pnpm run format)pnpm run lint)