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

Inherits:
Pikuri::Workspace::Confirmer show all
Defined in:
lib/pikuri/workspace/confirmer.rb

Overview

Stdin/stdout implementation. Renders the request as up to several lines (a leading puts guarantees separation from any streamed output the Terminal listener may have produced just above):

  1. a bold-yellow warning block — one line per Sanitizer::Warning — shown only when the sanitizer flagged something suspicious in the question or detail

  2. the question, bold

  3. the detail, dim — omitted when nil

  4. the (y/n)? cue

Both question and detail pass through Sanitizer, which neutralizes control bytes — without it, a model could craft a command or description containing “rrm -rf ~/” that visually overwrites the echoed line after the user has already read it —and reports why it was unsafe so the user reads the warning before answering. Colors come from Rainbow (already in the dependency closure via pikuri-core), which self-disables on non-TTY output; the bold-yellow warning rendering is this terminal chrome’s call, not the sanitizer’s (the Warning carries plain text only).

Then reads one line from $stdin and parses it strictly:

  • “y” / “yes” (case-insensitive, stripped) → true

  • “n” / “no”false

  • EOF / Ctrl+D (gets returns nil) → false, deliberate abort

  • anything else (blank, typo, “maybe”) → re-prompt with a short “Please answer y or n: ” line and loop

No retry cap; EOF eventually breaks adversarial input.

Constant Summary

Constants inherited from Pikuri::Workspace::Confirmer

AUTO_APPROVE, TERMINAL

Instance Method Summary collapse

Instance Method Details

#confirm?(request:) ⇒ Boolean

Parameters:

Returns:

  • (Boolean)


109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/pikuri/workspace/confirmer.rb', line 109

def confirm?(request:)
  question = Pikuri::Sanitizer.sanitize(request.question)
  detail   = request.detail ? Pikuri::Sanitizer.sanitize(request.detail) : nil
  warnings = question.warnings + (detail ? detail.warnings : [])

  puts
  unless warnings.empty?
    puts Rainbow('⚠ Suspicious content detected — read carefully before approving:').yellow.bold
    warnings.each { |w| puts Rainbow("  ! #{w.explanation}").yellow }
  end
  puts Rainbow(question.text).bold
  puts Rainbow(detail.text).dimgray if detail
  puts '(y/n)?'
  $stdout.flush
  loop do
    line = $stdin.gets
    return false if line.nil?

    answer = line.strip.downcase
    return true  if answer == 'y' || answer == 'yes'
    return false if answer == 'n' || answer == 'no'

    print 'Please answer y or n: '
    $stdout.flush
  end
end