Module: Pikuri::Workspace::WriteGate
- Defined in:
- lib/pikuri/workspace/write_gate.rb
Overview
The shared pre-write gate for the confirm-all-writes posture (the OS-helper wiring; book/os-assistant.md). Before a Write/Edit mutates a file it runs WriteGate.check, which:
- Short-circuits an unwritable target. If the user can't write the
path, the write would fail anyway and confirming a doomed write is
noise — so return a "permission denied — ask the user to sudo"
observation without prompting. Exact, not a guess: the file tools run
in-process as the real user (only bash is sandboxed), so
File.writable?is real. Subsumes/etc//boot— no path list. - Confirms with a diff. Else ask the human via a Confirmer::Change payload (the chrome renders the diff), surfacing the decline reason on no.
Stateless module (composition, not a base class); both tools call WriteGate.check
and return on a non-nil result. Write always routes an overwrite through
it (its confirmer is mandatory; confirm_all_writes only decides whether
new-file writes go through too); Edit stays promptless unless a confirmer
is passed, then every edit routes through it.
Class Method Summary collapse
-
.check(confirmer:, path:, resolved:, question:, change:) ⇒ String?
An
"Error: ..."observation to return immediately (unwritable, or declined), ornilto proceed. - .declined(path, reason) ⇒ String
- .permission_denied(path) ⇒ String
-
.writable_target?(resolved) ⇒ Boolean
Whether the user can write the target — the file if it exists, else the nearest existing ancestor dir (where Write would
mkdir_p).
Class Method Details
.check(confirmer:, path:, resolved:, question:, change:) ⇒ String?
Returns an "Error: ..." observation to return
immediately (unwritable, or declined), or nil to proceed.
34 35 36 37 38 39 40 41 |
# File 'lib/pikuri/workspace/write_gate.rb', line 34 def check(confirmer:, path:, resolved:, question:, change:) return (path) unless writable_target?(resolved) case confirmer.ask(request: Confirmer::Request.new(question: question, change: change)) in Confirmer::Rejected(reason:) then declined(path, reason) else nil end end |
.declined(path, reason) ⇒ String
66 67 68 69 |
# File 'lib/pikuri/workspace/write_gate.rb', line 66 def declined(path, reason) reason ? "Error: user declined the write to #{path}: #{reason}" \ : "Error: user declined the write to #{path}." end |
.permission_denied(path) ⇒ String
58 59 60 61 |
# File 'lib/pikuri/workspace/write_gate.rb', line 58 def (path) "Error: permission denied — cannot write #{path} as this user; " \ 'ask the user to make the change themselves (e.g. with sudo).' end |
.writable_target?(resolved) ⇒ Boolean
Whether the user can write the target — the file if it exists, else the
nearest existing ancestor dir (where Pikuri::Workspace::Write would mkdir_p).
48 49 50 51 52 53 54 |
# File 'lib/pikuri/workspace/write_gate.rb', line 48 def writable_target?(resolved) return File.writable?(resolved) if resolved.exist? dir = resolved.dirname dir = dir.parent until dir.exist? || dir.root? File.writable?(dir) end |