Skip to content

feat(harness): keep input live during a turn; Escape cancels, typing steers#28

Merged
mike-diff merged 1 commit into
mainfrom
live-input
Jun 16, 2026
Merged

feat(harness): keep input live during a turn; Escape cancels, typing steers#28
mike-diff merged 1 commit into
mainfrom
live-input

Conversation

@mike-diff

Copy link
Copy Markdown
Owner

Fixes #25 and #26.

Root cause (one bug behind both issues)

During a turn the main goroutine was inside runTurn/drive, so nothing read stdin: the input bar froze until the turn finished. Ctrl+C only ever worked because it rode a separate path (SIGINT), which is exactly why it was flaky and undebuggable.

Fix

A single pump goroutine owns stdin and feeds a select-able channel, so the editor stays live while the turn runs in a worker goroutine. While the agent works you can:

  • Type a message + Enter to queue a steer. It's injected as a user turn at the next iteration boundary (the format-safe point, since the provider requires alternating roles), so it steers the next step without corrupting an in-flight reply.
  • Press Escape to cancel the turn (resolves [feature] Make Escape the interrupt key #26; reliable now because it's a keystroke, not a signal).

Ctrl+C is reserved for quitting (twice within two seconds), as requested in #26.

How it works

pump() is the only reader of the terminal; every other consumer (readLineMode, readCSI, readPaste, Select, ReadKey, escIsBare) reads decoded runes from the channel. readLineMode gains a turn-attend mode that selects on a keystroke or the turn's done channel, so it stops attending the instant the turn ends without swallowing a keystroke meant for the next prompt. The worker streams the response above the footer while the editor's input row stays live below it; both render under the existing footer mutex.

Scope (called out for review)

  • Live input covers the default free-running posture. With -ask, the gate reads approvals mid-turn from the same keyboard, so that posture stays synchronous (Ctrl+C quits). A gate mod (executable) does not read stdin, so it keeps live input.
  • Queued steers land at iteration boundaries, not mid-tool-chain (a user message can't be injected between tool rounds without breaking the alternating-role format).
  • I could not interactively TTY-test in the dev sandbox (no controlling terminal), so the logic is unit-tested and the terminal plumbing wants a smoke test (type while it works; Enter to steer; Escape to cancel; Ctrl+C twice to quit).

Tests

  • TestAttendTurnQueuesAndCancels — drives the live editor: Enter queues, bare Escape cancels.
  • TestDriveInjectsQueuedSteer — a queued message is injected as a user turn and acted on in place of the judge.
  • TestInterruptsQueue — drain returns and clears (a steer is consumed once).
  • Existing e2e drivers keep passing (the pump initializes lazily for test-built consoles).

gofmt/vet clean, full suite + -race on harness/ and agent/ green.

…steers

Fixes #25 and #26. The bug behind both: during a turn the main goroutine was
inside the run loop, so nothing read stdin and the input bar froze until the
turn finished. Ctrl-C only ever worked because it rode SIGINT, which is exactly
why it was flaky.

Now a single pump goroutine owns stdin and feeds a selectable channel, so the
editor stays live while the turn runs in a worker goroutine. While it works:
type a message and Enter to queue a steer (injected as a user turn at the next
iteration boundary, the format-safe point), or press Escape to cancel. Ctrl-C
is now reserved for quitting (twice).

Scope: live input covers the default free-running posture; with -ask the gate
reads approvals mid-turn from the same keyboard, so that posture stays
synchronous. Injection lands at iteration boundaries, not mid-tool-chain.
@mike-diff mike-diff merged commit 82cad5e into main Jun 16, 2026
2 checks passed
@mike-diff mike-diff deleted the live-input branch June 16, 2026 04:19
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.

[feature] Make Escape the interrupt key [bug] Ctrl+C does not interrupt an in-progress turn; message bar freezes until completion

1 participant