{"id":"twofado","repo":"xpufx/paseo","url":"https://github.com/xpufx/paseo/tree/main/plugins/twofado","package":"@xpufx/paseo-twofado","npm":{"package":"@xpufx/paseo-twofado","version":"0.1.4","integrity":"sha512-oJGVgxhL9HZp+krZHkl8lIM0PSae2Y5/MJ0dfnZnjPnnAySwETI2IjjdgwffIaIrRnbEiyKyuzEyGJZ8ojIptw==","publishedAt":"2026-09-25T14:17:51.902Z","downloadsLast30Days":452},"name":"twofado","description":"Approval-gate UI and notifications for the **2fado** privileged-command daemon, for [Paseo](https://github.com/getpaseo/paseo).","categories":["automation","monitoring"],"platforms":["linux","macos"],"caveats":["Runs companion 2fado daemon within the paseo node context. Possible to run your own version instead. (https://github.com/xpufx/2fado)"],"images":[],"themes":[],"health":{"manifestValid":true,"hasReadme":true,"hasLicense":true,"hasTests":true,"hasTypecheckScript":true,"updatedRecently":true},"scannedAt":"2026-09-25T14:40:48.504Z","addedAt":"2026-09-25T14:37:49Z","npmSecurity":{"status":"passed","blockingFindings":0,"advisoryFindings":0,"scannedAt":"2026-09-25T14:40:23.147Z","version":"0.1.4","integrity":"sha512-oJGVgxhL9HZp+krZHkl8lIM0PSae2Y5/MJ0dfnZnjPnnAySwETI2IjjdgwffIaIrRnbEiyKyuzEyGJZ8ojIptw=="},"path":"plugins/twofado","version":"0.1.4","security":{"status":"passed","blockingFindings":0,"advisoryFindings":0,"scannedAt":"2026-09-25T14:40:23.147Z","commit":"9a2c551e748a635c693731dbc5a7b50016eca866"},"license":"MIT","paseoVersionRequirement":">=0.8.0","descriptionNodes":[{"type":"text","text":"Approval-gate UI and notifications for the "},{"type":"text","text":"2fado","strong":true},{"type":"text","text":" privileged-command daemon, for "},{"type":"link","href":"https://github.com/getpaseo/paseo","children":[{"type":"text","text":"Paseo"}]},{"type":"text","text":"."}],"caveatNodes":[[{"type":"text","text":"Runs companion 2fado daemon within the paseo node context. Possible to run your own version instead. ("},{"type":"link","href":"https://github.com/xpufx/2fado","children":[{"type":"text","text":"https://github.com/xpufx/2fado"}]},{"type":"text","text":")"}]],"manifest":{"id":"twofado","requirements":{"paseo":">=0.8.0"},"build":[["node","scripts/install-companion.mjs","--optional"]]},"repoMeta":{"stars":2,"defaultBranch":"main","pushedAt":"2026-09-25T14:28:02Z"},"owner":{"login":"xpufx","avatarUrl":"https://avatars.githubusercontent.com/u/25581961?v=4"},"installNotesHtml":"<p>Install from npm:</p>\n<pre><code class=\"language-sh\">paseo plugin add npm:@xpufx/paseo-twofado\n</code></pre>\n<p>Or install directly from the Git repository:</p>\n<pre><code class=\"language-sh\">paseo plugin add xpufx/paseo --path plugins/twofado\n</code></pre>","readmeText":"# twofado\n\n\n\nApproval-gate UI and notifications for the **2fado** privileged-command daemon, for\n[Paseo](https://github.com/getpaseo/paseo).\n\nSurfaces pending risky command requests from `2fadod` and lets a human\napprove, deny, or acknowledge them without leaving Paseo. The plugin also\nregisters a sidebar item, a workspace header button, and a command-center\nentry so the queue is one tap away.\n\n> **⚠️ WIP — use at your own risk.** Not release-ready; APIs and behavior may change without notice.\n\nBuilt on [paseo-plugin-helper](https://github.com/xpufx/paseo/tree/main/packages/paseo-plugin-helper), the shared Paseo plugin runtime.\n\n> [!NOTE]\n> **Prerequisites & Platform Support**:\n> - Requires a `2fadod`; the daemon is reached over a unix socket. The plugin\n>   acquires the platform binary during install and can supervise the daemon\n>   directly when no external one is running. The socket path is configurable\n>   and otherwise falls back to `$TWOFADO_SOCKET`, `$FADO_SOCKET`, then\n>   `/tmp/2fado.sock`.\n> - Developed and tested primarily on **Linux**.\n\n## What it does\n\n- **Pending queue.** Each request shows the argv, caller, host, working\n  directory, expiry, and (when provided) a code preview with resolved binary,\n  risk level, affected path count, and sample paths.\n- **Approve / deny.** A decision is submitted for the request id; two-step\n  confirmations are distinguished, and notify-only petitions expose an\n  **Ack** action instead of a binding verdict.\n- **Interactive questions.** `kind: \"ask\"` petitions render the question,\n  recommended option, and single- or multi-select option buttons plus an\n  optional write-in answer; submitting calls `approval.select`, which forwards\n  the daemon's `select` op. First-selection-wins: a resolved petition (from\n  Telegram or another client) locks the card to its chosen answer.\n- **Policy shortcuts.** From a pending item, save an always-approve or\n  always-deny rule scoped to the exact argv, the resolved binary's base, or a\n  custom matcher.\n- **History.** Recently decided requests are listed with decision, decided-by,\n  exit code, and a truncated output preview.\n- **Health.** The header reports daemon reachability and a down state when\n  the socket cannot be probed.\n- **Companion daemon lifecycle.** When no external daemon serves the configured\n  socket, the plugin acquires the platform `2fado` binary during install\n  (`scripts/install-companion.mjs`) and supervises the daemon process in Node\n  (`scripts/daemon-supervisor.mjs`). The settings tab exposes process state,\n  PID/uptime, start/stop/restart, on-demand binary install, and the supervised\n  log ring buffer. An external daemon (systemd or standalone) is adopted, never\n  killed by the plugin.\n- **Notification target.** Choose whether notifications go to Telegram, the\n  Paseo client, or both; Telegram bot token, chat id, and approver list are\n  configurable in settings.\n\n## RPC contracts (`shared/approval.ts`)\n\n- `approval.list` / `approval.recent`: pending and recently decided requests,\n  including `ask` question/options/selection fields.\n- `approval.verdict` / `approval.ack` / `approval.select`: record an\n  approve/deny decision, acknowledge a notify-only petition, or answer an\n  interactive `ask` question.\n- `approval.status` / `approval.health`: per-request status and daemon probe.\n  `approval.health` also reports the daemon's advertised ops so the surface can\n  tell an `ask` card it cannot submit yet when the daemon lacks the `select` op.\n- `approval.telegram_info` / `approval.telegram_set_config`: read and sync the\n  daemon-side notification configuration.\n- `approval.policy_add_rule`: persist a policy rule derived from a request.\n- `daemon.status` / `daemon.start` / `daemon.stop` / `daemon.restart` /\n  `daemon.logs` / `daemon.install`: supervised daemon lifecycle, log ring\n  buffer, and on-demand companion binary acquisition.\n- `twofado.settings`: socket path, notification target, Telegram config, and\n  companion auto-start.\n\n## Install\n\nInstall from npm:\n\n```sh\npaseo plugin add npm:@xpufx/paseo-twofado\n```\n\nOr install directly from the Git repository:\n\n```sh\npaseo plugin add xpufx/paseo --path plugins/twofado\n```\n\n## Development\n\n```sh\nnpm run typecheck --workspace=plugins/twofado\nnpm test --workspace=plugins/twofado\n```\n\n> [!NOTE]\n> Ask-card submission requires a 2fadod that advertises the `select` socket op.\n> Reference daemon builds today expose ask options on `list`/`status` but wire\n> selection only through the Telegram callback; when `select` is absent the card\n> renders read-only with an explicit \"cannot submit\" notice rather than\n> pretending the answer landed.\n"}