Class: Pikuri::Workspace::Confirmer::Terminal

Inherits:
Confirmer
  • Object
show all
Defined in:
lib/pikuri/workspace/confirmer/terminal.rb

Overview

Stdin/stdout implementation, written for pikuri's own single-threaded bin/ scripts — not a component to build a host on. A real host (TUI, web) owns its screen and its event loop, so it cannot have a library class calling puts and gets behind its back; it writes its own Pikuri::Workspace::Confirmer and this is the worked example to read while doing it. The one piece to carry over is not the chrome but the warning-gated retype below — everything else is a terminal's answer to a problem your UI will answer differently.

Renders the request as up to several lines (a leading puts separates it from any streamed output above):

  1. a bold-yellow warning block (one line per Sanitizer::Warning) when the sanitizer flagged the question or detail
  2. the question, bold
  3. the detail, dim — omitted when nil
  4. the answer cue

Question and detail pass through Sanitizer, which neutralizes control bytes (else a model could craft "\rrm -rf ~/" that overwrites the echoed line after the user read it) and reports why it was unsafe. Colors are Rainbow (self-disables on non-TTY).

The human chrome — the one confirmer that renders a dialog and reads an answer. In its own file so the base seam carries no rendering deps (Rainbow / Reline / tmpdir ride only here).

The two flows

A non-editable request (bash, write) gets (y/n)?: yApproved, nRejected (after an optional reason), EOF → Rejected, else re-prompt.

An editable request (the agent task) also offers e to edit, and the warning set gates the pre-fill: the payload sent onward is RAW bytes but the terminal must display sanitized bytes, so pre-filling an editable buffer with raw bytes would reintroduce the control-byte attack. So a clean task offers [y] approve [e] edit [n] reject (+e+ opens the raw task editable), a flagged task drops bare-approve and forces a retype: [e] edit [n] reject. Honest limit: a terminal can't structurally forbid a rubber-stamp y on a clean task — the pure no-rubber-stamp author seat is a richer-UI invariant; the warning-gated retype is the terminal's partial answer.

Sharing

P_one_agent, and no lock is coming: this is the demo chrome, and one script is one agent. Two agents prompting at once would interleave their blocks on one terminal, and whichever gets runs first reads the answer — so agent A could consume the y meant for agent B and approve a command nobody read. There is no state to corrupt; the contended resource is the terminal and the human at it.

That queue belongs to whoever owns the screen, and it needs more than a mutex — it has to say which agent is asking. Which is the same sentence as the paragraph at the top: a multi-agent host writes its own confirmer.

Constant Summary collapse

LOGGER =
Pikuri.logger_for('Workspace::Confirmer')
DIFF_MAX_LINES =

Maximum diff lines rendered before truncation — keeps a whole-file rewrite from scrolling the terminal off-screen.

300

Instance Method Summary collapse

Instance Method Details

#ask(request:) ⇒ Approved, Rejected

Parameters:

Returns:



76
77
78
79
80
81
82
83
# File 'lib/pikuri/workspace/confirmer/terminal.rb', line 76

def ask(request:)
  warnings = render(request)
  if request.editable && !request.detail.nil?
    ask_editable(request, clean: warnings.empty?)
  else
    ask_plain(request)
  end
end