Skip to content

Offer one-click fixes for build, test and merge failures in terminal output - #1625

Merged
currentbits merged 3 commits into
mainfrom
coder/proactive-fix-suggestions-from-the-termi-afcba7
Oct 13, 2026
Merged

currentbits merged 3 commits into
mainfrom
coder/proactive-fix-suggestions-from-the-termi-afcba7

Conversation

@currentbits

Copy link
Copy Markdown
Owner

Closes #253.

When a thread's terminal or dev server prints a build error, a failing test or a merge conflict, a small card now appears where the failure happened. The card turns the failure into a ready-made prompt, so the user doesn't have to copy the output into the composer by hand.

What changed

Detection (src/fixSuggest.ts)

  • plainText() strips ANSI escapes and applies \r overwrites, so the matching runs on what a reader actually sees.

  • detectFailure() checks the output against a fixed list of line regexes for common toolchains:

    • Conflicts: git conflicts, Automatic merge failed and could not apply
    • Build errors: error TS…, rustc error[E…], C-style file:line:col: error:, esbuild ✘ [ERROR], vite internal errors, Failed to compile and Module not found
    • Test failures: Jest/Vitest FAIL and Tests: N failed, node:test fail N, mocha N failing, Go --- FAIL:, cargo test result: FAILED and pytest FAILED

    The first matching rule wins, so a conflict beats the build error it causes, and a build error beats the tests it breaks.

  • failureKey() removes digits from the matched line. A rerun that reports different line numbers or timings counts as the same failure, so a dismissed card doesn't come back.

  • fixPrompt() builds a self-contained prompt: a block of up to 40 lines / 3000 chars taken around the last occurrence of the failing line, followed by an instruction for that kind of failure. It has to be self-contained because a forked thread only gets a digest of the parent thread.

UI (src/components/FixSuggestion.tsx + CSS)

  • The card shows the failure label, the line that matched, and four buttons:
    • Fix it sends the prompt to this thread's agent.
    • Edit prompt puts the prompt in the composer.
    • Fork sends the prompt to a new worktree thread.
    • × dismisses the card.
  • The prompt is built when a button is clicked, so it includes output that arrived after the failing line.

Where the card appears

  • TerminalPane: only live output is scanned; replayed scrollback is ignored. The pane keeps the last 16k characters of plain output. Each new chunk is checked together with a 300-character overlap, so a failing line split across two chunks is still caught. A failure that was dismissed or acted on stays hidden for as long as that terminal view is mounted.
  • DevServerCard (AgentsPanel): scans the polled lastLines tail. The card shows while the failure is in that tail, until the user dismisses or acts on it.

Wiring

  • useSuggestionHandlers gets a new handleFixSuggestion. "Draft" goes through the existing restore-draft path. "Fork" calls forkThread (worktree, not selected) and then startRun. "Run" calls startRun on the current thread.
  • restoreDraft gets an append flag. Normally a restored draft only lands in an empty composer. With append, the fix prompt is added after the in-progress draft, separated by a blank line, instead of being dropped.
  • onFixSuggestion is passed down through App → ThreadView → TerminalPane and through App → AgentsPanel → GitTab → DevServerCard. If the prop is absent, no cards are shown.

Tests

  • test/fixSuggest.test.ts: escape stripping, detection and rule order, key normalization, and the prompt excerpt.
  • test/terminalPane.test.tsx and test/devServer.test.tsx: the card appears for failures and the actions/dismiss behave correctly.
  • test/composer.test.tsx: append adds the prompt after an existing draft.

🤖 Generated with Claude Code

Solenta-Message-Id: 7114291a-ea93-4ab8-b38e-a9570ad6b765
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 13, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-13T14:13:32.980435Z d3cbc60 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d3cbc60fc0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +92 to +94
if (action === "fork") {
const t = await forkThread(threadId, { worktree: true, select: false });
if (!t) return;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve the failing checkout when forking fixes

When the detected failure depends on committed or uncommitted changes in the source thread's worktree, this creates a fresh pending worktree without carrying the source branch or a snapshot. forkThread only records handoffFrom, while worktree materialization starts the new thread from its normal base, so merge conflicts disappear and build/test failures caused by the source changes cannot be reproduced or fixed. The fork action needs to start from the failing checkout's snapshot rather than a clean base.

Useful? React with 👍 / 👎.

Comment on lines +570 to +573
const [handledFixes, setHandledFixes] = useState<string[]>([]);
const devOutput = onFix ? plainText((state.lastLines ?? []).join("\n")) : "";
const found = onFix ? detectFailure(devOutput) : null;
const fixFailure = found && !handledFixes.includes(failureKey(found)) ? found : null;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Clear dev-server fix state when changing threads

When the inspector switches directly between two non-null threads, the load effect leaves state.lastLines from the old thread in place until both async requests for the new thread resolve. During that interval this computes a card from the old output but renders it with the new threadId, so clicking Fix, Edit, or Fork applies thread A's failure prompt to thread B. Reset the output synchronously on a thread change or associate the state with the thread that produced it.

Useful? React with 👍 / 👎.

Comment on lines 3791 to +3794
threadId={detail?.thread.id ?? null}
api={terminalApi}
reveal={terminalReveal}
onFix={onFixSuggestion}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Disable fix actions on archived threads

When an archived thread is opened, its composer is deliberately hard-disabled, but the terminal still receives the unrestricted fix handler here; the dev-server card is wired the same way. A detected failure therefore exposes Fix/Edit/Fork, and Fix calls startRun directly—even though the backend rejects deleted threads but does not reject archived ones—allowing a new agent run to start in an archived thread. Gate the actions by isArchived or enforce the archive check in the handler.

Useful? React with 👍 / 👎.

Willem added 2 commits October 13, 2026 16:44
@currentbits
currentbits enabled auto-merge (squash) October 13, 2026 15:27
@currentbits
currentbits merged commit f0a49c0 into main Oct 13, 2026
6 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.

Proactive fix suggestions from the terminal/dev-server error stream

1 participant