Skip to content

feat(cli): answer a run's human gate from the terminal - #94

Merged
EdmondDantes merged 2 commits into
mainfrom
feat/cli-run-answer-gate
Jul 27, 2026
Merged

feat(cli): answer a run's human gate from the terminal#94
EdmondDantes merged 2 commits into
mainfrom
feat/cli-run-answer-gate

Conversation

@EdmondDantes

Copy link
Copy Markdown
Contributor

What

The fourth slice of TODO item 2 (3b), completing the run experience over the server. #93 brought the trace back to the terminal read-only; this makes it interactive — when a tailed run parks at a question, the CLI asks the person and sends their reply, and the run carries on.

  • ServerClient::answer()POST /api/projects/{key}/issues/{id}/answer with {"text": …}, mapping 202→ok, 409→"the run is not waiting" exception, else error.
  • WorkflowMode::tailRun() — a question trace row opens the gate (its prompt is the question), an answer row closes it; on a tty the CLI prompts on STDIN and posts the reply, on a pipe it keeps the read-only hint so it never blocks on input.

Behaviour

⏸ Which sort should the module use — merge or quick?
› merge sort
  • Answer accepted → the run wakes (the server sends it down the gate channel) and the trace keeps flowing.
  • Piped / non-interactive claw run never blocks: it prints the dashboard hint once and keeps following.
  • Ctrl-D / closed input detaches cleanly (the run continues on the server; answer it in the dashboard).
  • A rejected answer (409 "not waiting" — the gate was answered elsewhere or the run moved on) is dropped, not re-prompted in a loop.

Honesty

answer()'s status mapping is unit-tested. The interactive path is not live-verified — a real gate fires only when the model decides to ask, which is non-deterministic and costs a full run to reach. The read-only tail it builds on was verified live in #93. Reviewed for control-flow (no spin/double-prompt/missed-gate).

Design note

Answering by issue, not by question id: the server matches the reply to the issue's one open gate (POST …/answer takes only text), and has a dead-gate fallback that journals the answer if the run that asked is gone — so a reply is never lost to a restart.

Not in this PR

  • /start returning the run id (would remove the awaitRun discovery poll).
  • Folding claw -i / -c writers behind the server.

Checks

composer qa green — cs, PHPStan level 8, Testo (459 tests). New tests cover the answer status mapping (accepted carries the text; 409 is surfaced).

When a tailed run parks at a question, the CLI prompts on the terminal and POSTs the reply to …/answer; the run wakes and carries on. A non-tty (piped) run keeps the read-only hint instead of blocking on input, and a closed stream detaches. Turns the read-only tail interactive. answer() status mapping is unit-tested; the interactive path is not live-verified (a real gate fires non-deterministically).
From Fable's review: re-prompt on a bare Enter rather than spending the gate on an empty answer; suppress the doubled hint after an EOF detach; reject an answer that will not JSON-encode instead of sending an empty body. The stale-answer-to-a-second-question window (a dashboard answer racing the terminal user's typing) is left for a server-side fix — /answer should take a question id and 409 on mismatch.
@EdmondDantes
EdmondDantes merged commit 0f73de2 into main Jul 27, 2026
2 checks passed
@EdmondDantes
EdmondDantes deleted the feat/cli-run-answer-gate branch July 27, 2026 18:57
EdmondDantes added a commit that referenced this pull request Jul 27, 2026
Closes the terminal-vs-dashboard race from #94's review: while the CLI blocks on input, the same gate can be answered in the dashboard and the run can open a new question — the terminal reply then landed on the wrong question with a 202. /answer now accepts the question id the caller is reading from the trace and returns 409 when it is no longer the open one; the CLI re-prompts for the current question. A missing id keeps the old behaviour.
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