pi-herdr-sudo-task

内容来源:README.md(说明文档) · 原始地址 · 查看安装指南

原始内容

pi-herdr-sudo-task

License: MIT

Pi extension providing one blocking sudo_task tool for reviewed privileged work in a dedicated Herdr pane. The tool registers only when Pi boots inside Herdr with HERDR_ENV=1, HERDR_SOCKET_PATH, and HERDR_PANE_ID set. Its Pi prompt guidance tells the agent to proactively request required privileged work through sudo_task instead of waiting for user encouragement or suggesting manual sudo.

sudo_task keeps password input out of captured output. Opening a pane does not authorize execution: user must consent once in Pi, inspect exact immutable task in new pane, then explicitly press y there before any sudo command runs. Pane output is incrementally saved to a private local transcript whose path may be read by the AI without another confirmation.

Safety model

  • Refuses calls outside live Herdr environment or without Pi approval UI.
  • Validates title, existing absolute working directory, 1–10 steps, reasons, failure policies, and control-character boundaries.
  • Uses two separate consent gates. Neither gate has execution as default.
  • Stores validated task in mode-0600 temporary payload; commands are not interpolated into pane transport text.
  • Runs sudo -v, then each approved command sequentially as sudo sh -c <exact command>.
  • Stops at first nonzero exit unless that step sets continueOnError: true.
  • Runner opens transcript before any sudo, then uses async Node spawn with inherited stdin and piped stdout/stderr. Each output chunk goes directly to pane and append-only transcript; parent never reconstructs transcript from pane snapshots.
  • Standard sudo reads passwords from /dev/tty; prompt and echo-disabled password keystrokes bypass piped stdout/stderr and transcript. Approved commands can intentionally echo input as command output, which is captured.
  • Stores ANSI-stripped transcript plus bounded JSON metadata under /tmp/pi-herdr-sudo-task-<uid>/<unpredictable-runner-id>/ (0700 directories, 0600 active files, 0400 finalized files).
  • Returns transcript and metadata paths plus a sensitive-output warning for every launched runner; never embeds transcript content in tool result.
  • Returns on terminal marker. Pane then asks: Enter closes owned pane, Escape restores normal terminal and returns to shell, other keys reprompt.
  • Preserves partial transcript and returns conservative unknown if pane disappears before terminal marker. Never retries unknown outcome automatically.

This extension reduces accidental or hidden privileged execution. It is not a sandbox: approved shell commands have root privileges and may perform destructive actions.

Prerequisites

  • Pi 0.80.7 or newer
  • Node.js 22.19.0 or newer
  • Herdr 0.7.3 or newer
  • Pi running inside Herdr with HERDR_ENV=1, valid HERDR_SOCKET_PATH, and current HERDR_PANE_ID
  • Working sudo configuration and permission for requested commands
  • Interactive Pi approval UI (print/JSON mode is refused)

Install

Pi packages execute with full system access. Review this package's source before installation.

Install from npm:

pi install npm:pi-herdr-sudo-task

Restart Pi after installation. To try the extension for one session without adding it to settings:

pi -e npm:pi-herdr-sudo-task

Update or remove it with:

pi update npm:pi-herdr-sudo-task
pi remove npm:pi-herdr-sudo-task

To install directly from GitHub instead:

pi install git:github.com/tigorlazuardi/pi-herdr-sudo-task

Tool schema

type SudoTaskInput = {
  title: string; // non-empty
  cwd: string;   // existing absolute directory
  steps: Array<{
    command: string;           // exact shell program passed to sudo sh -c
    reason: string;            // non-empty human-readable justification
    continueOnError?: boolean; // default false
  }>; // 1-10 entries
};

Single-step example:

{
  "title": "Refresh package index",
  "cwd": "/home/user/project",
  "steps": [
    {
      "command": "apt-get update",
      "reason": "Refresh package metadata",
      "continueOnError": false
    }
  ]
}

Multi-step example with explicit failure policy:

{
  "title": "Refresh packages and restart service",
  "cwd": "/home/user/project",
  "steps": [
    {
      "command": "apt-get update",
      "reason": "Refresh package metadata",
      "continueOnError": true
    },
    {
      "command": "apt-get install --only-upgrade -y nginx",
      "reason": "Install available nginx security updates",
      "continueOnError": false
    },
    {
      "command": "systemctl restart nginx",
      "reason": "Load upgraded nginx binaries",
      "continueOnError": false
    }
  ]
}

Here, failed metadata refresh is reported but does not block step 2. Failure in step 2 stops task, so step 3 does not run.

Exact UX flow

  1. Model calls sudo_task with title, working directory, and ordered steps.
  2. Extension validates full input and Herdr environment. Invalid/unavailable requests return invalid or refused; nothing runs.
  3. Pi shows first gate with title, primary reason, and guarantee that opening pane runs no command:
    • Review commands — creates fresh focused pane for detailed review.
    • Reject with Reason — requires non-empty reason, returns it to model, and invites revised request through new call.
    • Cancel — returns cancelled status.
  4. New Herdr pane displays exact title, resolved working directory, every command, every reason, and each failure policy.
  5. Pane asks Proceed with these exact commands? [y/n]: with no default. Only y or Y proceeds. n, N, Ctrl-C, EOF, input failure, or terminal raw-mode failure executes no sudo.
  6. After y, runner invokes sudo -v, then approved steps in order. Runner tees stdout/stderr chunks to pane and private transcript while keeping stdin and controlling TTY inherited.
  7. Runner flushes, fsyncs, and closes transcript before emitting terminal marker. Parent waits through Herdr wait output; marker proves transcript writer is closed. Parent then finalizes metadata and modes to 0400 without reading pane text.
  8. Pi tool call returns as soon as known terminal marker is received; it does not wait for final pane choice.
  9. Completed/failed pane asks for one key: Enter closes only invocation-owned pane; Escape exits runner into usable shell; any other key reprompts.

Cancellation and unknown outcomes

Cancellation before runner launch executes nothing and closes only pane created by current call when needed. Once runner launch is attempted, cancellation or monitoring failure cannot prove commands stopped. Extension closes its owned pane best-effort and returns status: "unknown", observed step count, durable transcriptPath/metadataPath, and cleanup status.

Treat unknown as potentially executed. Inspect transcript and system effects before retrying. Blind retry can repeat privileged changes. Transcript may contain sensitive command output and may be read by the AI.

Security notes

  • Review commands and reasons in Herdr pane, not only model summary.
  • Commands execute through shell under sudo; shell operators, substitutions, redirections, and referenced scripts retain normal shell semantics.
  • Extension does not inspect semantic safety of approved commands.
  • Temporary payload and runner are deleted best-effort after tool returns; OS temp cleanup is fallback.
  • Private transcript artifacts intentionally remain until reboot or ordinary /tmp cleanup. Stale 0600 files become 0400 only after owner PID and Linux process start-time identity are confirmed dead.
  • Commands and reasons are not duplicated into metadata. Password input is never captured. Raw transcript content is not embedded in tool result.
  • Report vulnerabilities privately to repository owner before public disclosure when practical.

License

MIT © 2026 Tigorlazuardi