npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@d3ara1n/pi-ask-user

v2.2.2

Published

Ask-user tool for pi — renders in the bottom editor slot (not a screen overlay), so the transcript stays visible and scrollable above the panel while you decide

Readme

@d3ara1n/pi-ask-user

A collapsible ask-user tool for pi.

Why

Most ask-user tools render the panel as a screen overlay that covers the transcript, so you can't read the analysis that should inform your choice — you choose blind.

This tool uses overlay: false instead. The panel renders into pi's bottom editorContainer slot (the same path ctx.ui.select() / ctx.ui.input() take), so the transcript stays visible above the panel while you decide.

Scrolling, and the pi-powerline-footer caveat

Native pi writes every chat line to the terminal's normal scrollback (mouse wheel / Shift+PgUp / Cmd+↑), so the transcript above the panel is always scrollable.

pi-powerline-footer changes that — once it's loaded the native scrollback stops working, so an overlay-type ask-user panel is a dead end: it covers a transcript you then can't scroll back through. This tool's overlay: false keeps the transcript in the content area, so it stays visible and usable even alongside pi-powerline-footer — exactly the case where overlay tools break.

  • Collapse (Ctrl+\) shrinks the panel to a single status row, leaving even more of the transcript on screen while you decide.

Tool: ask_user

{
  "questions": [
    {
      "header": "Which layout?",
      "tab": "layout",
      "prompt": "Pick the layout for the new settings page.",
      "options": [
        { "label": "Sidebar", "description": "Nav on the left…" },
        { "label": "Tabs", "description": "Top tabs…" }
      ]
    }
  ]
}

Fields

Question

| Field | Type | Required | Description | |-------|------|----------|-------------| | header | string | yes | Short title shown in the panel header | | tab | string | yes | Short keyword identifying this question. Shown on the tab bar when there are multiple questions, and returned in the result as the answer's prefix. Write it in the user's language, not as a programmatic identifier. It should be unique across all questions in one call; if duplicates are supplied, results preserve question order as tab, tab-2, tab-3, … | | options | array | yes | 2–4 options | | prompt | string | no | Longer body text under the header | | multiSelect | boolean | no | Check multiple options. Default false | | allowSkip | boolean | no | If false, the user MUST answer before proceeding. Default true |

Option

| Field | Type | Required | Description | |-------|------|----------|-------------| | label | string | yes | Display label | | description | string | no | Short explanation under the label (wraps). Add one when the label alone isn't self-explanatory | | preview | string | no | Use when description (a short one-liner) isn't enough and the user genuinely benefits from more detail in a side column — ASCII layout demo, code skeleton, Pro/Cons breakdown, or the reasoning behind the option and what choosing it entails. Rendered verbatim. Don't treat it as extra text capacity — every line competes for the user's attention. If a short description already conveys the option, leave empty. Most options need only description |

Icons

All selection icons live in the U+25A0–25FF Geometric Shapes block, so any font that renders one renders all of them consistently:

  • Single-select: (white circle) → (fisheye) when committed
  • Multi-select: (white square) → (square with fill) when checked
  • Cursor: marks the current position, independent of selection

Moving / only moves the cursor; selection is committed separately.

Single-select vs multi-select

  • Single-select: Space selects (fills the circle) without advancing; Enter selects and advances to the next question.
  • Multi-select (multiSelect: true): Space toggles a checkbox; Enter commits all checked options and advances.

Custom input ("Type something.")

Every question always shows a "Type something." row (this cannot be turned off), so the user is never locked into the provided options. Press Space on it to open a text editor:

  • After submitting, the row displays the committed text with a filled glyph (◉ ✎ your text).
  • Press Space again to re-edit it — the editor prefills the committed text so you can tweak it.
  • Esc discards the edit (the original answer is kept); Enter confirms the change (the answer is updated).

Multi-select + custom input. In multiSelect mode the custom text is an extra entry kept alongside the checked options — it never overwrites them. You can check several options, then open "Type something.", type a value, and submit: both the checks and the custom text are preserved and returned together. The same holds in reverse — edit the question later from the review screen to add or remove checks and the committed custom text stays intact (and vice versa). Submitting an empty custom value clears only the custom entry; any remaining checks are kept.

Required questions

Set allowSkip: false to force an answer. The user cannot advance forward (Tab/) until they answer; the built-in "Type something." row always lets them supply a custom answer, so they're never trapped by options they dislike. Backward navigation (Shift+Tab/) is always allowed so they can review/edit earlier questions.

Rich previews

description is the default way to explain an option; reserve preview for the rare case where a description can't fully convey it. If any option of a question carries a preview field, that question renders in two columns: option list on the left, the focused option's preview on the right. Moving the cursor updates the right pane. Ideal for comparing ASCII layouts / code samples:

{
  "header": "Which layout?",
  "tab": "layout",
  "options": [
    {
      "label": "Sidebar",
      "description": "Left-side navigation with the main content to its right.",
      "preview": "┌──┬────────┐\n│NA│  body  │\n│V │        │\n└──┴────────┘\nleft sidebar nav"
    },
    {
      "label": "Top bar",
      "description": "Top horizontal nav with the main content below.",
      "preview": "┌──────────────┐\n│    nav bar   │\n├──────────────┤\n│     body     │\n└──────────────┘\ntop horizontal nav"
    }
  ]
}

Plain description text (no newline) wraps normally. A description that contains a newline renders verbatim as a fixed-width block.

Review screen

After the last question is answered, a review screen lists every question and its answer (multi-select answers are comma-joined and truncated with when too long; skipped questions show (skipped)). Each question entry spans two rows (header + answer), followed by a trailing note entry:

 ▸ 1. Which layout?
      Sidebar
   2. Which database?
      Postgres

   ✎  Note to assistant
      (optional — Space to add a note)

Each title carries a fixed-width marker (1./2.… for questions, for the note) so every title aligns; the body is indented one level deeper to keep header vs content visually distinct. An empty line sets the note apart from the Q&A list above it.

  • / — move the cursor between entries (questions + the note)
  • PgUp/PgDn — scroll by page (when there are more entries than rows)
  • Space — edit the focused entry: a question (jumps to its tab; returns to review afterwards) or the note (opens a free-form editor)
  • Tab/ — advance to the next tab (cycles back to the first question after the review); Shift+Tab/ go back
  • Enter — confirm and submit all answers. Enter is always "submit" on the review screen, never "edit" — this deliberately differs from the question screens (where Space edits and Enter confirms/advances) so you can never submit by double-tapping Enter while trying to edit something. Use Space to edit.
  • Esc — cancel

Note to assistant

The review screen ends with a note entry — a free-form message the user can attach for the assistant, about anything beyond the specific questions (overall direction, pacing, priorities, a correction to the premise, …).

  • Move the cursor to the note row and press Space to open the editor.
  • Enter saves the note (empty = no note); Esc returns to the review without saving (the in-progress draft is kept).
  • The note is out-of-band: it is not part of questions/options and the assistant cannot request or pre-fill it. It surfaces only in the tool result as message, and only when non-empty.

Because the note can reframe or override the answers, the assistant is told to treat it as high-priority context.

Result

The tool result returned to the model is JSON, shaped symmetrically with the questions schema so the model can correlate each answer back to its own question by the tab key:

{
  "cancelled": false,
  "answers": [
    { "tab": "layout", "answer": "Sidebar" },
    { "tab": "extras", "answers": ["dark-mode"], "custom": "also add export-to-pdf" },
    { "tab": "db", "skipped": true }
  ],
  "message": "leaning towards the minimal option"
}

Only the relevant fields appear per answer (no noise). For duplicate input tabs, the result keeps every question in order by suffixing later occurrences as tab-2, tab-3, and so on; the original first occurrence remains tab.

| Situation | Fields | |-----------|--------| | single-select, option picked | answer | | single-select, custom typed | custom | | multi-select, options picked | answers: [...] | | multi-select, options + custom | answers + custom | | multi-select, custom only | custom | | multi-select, empty commit (skippable, submitted with nothing) | answers: [] | | any question, Tab-skipped | skipped: true |

custom is always a sibling of answer/answers, never mixed in — it signals the user typed something outside the offered options. The top-level message (the user's review-screen note) appears only when non-empty. cancelled: true means the user pressed Esc; answers still lists whatever was answered before cancellation. This JSON shape replaces the old "tab: answer" text format, which could break when a custom answer contained a colon or newline.

Keys

| Key | Action | |-----|--------| | / PgUp PgDn | Move cursor / scroll options | | Space | The "interact" key: select (single) / toggle (multi) / edit (open custom input, edit the focused review entry, or open the note) | | Enter | Confirm & advance (single) / commit checked (multi). Never enters edit mode — that's Space | | Tab / Shift+Tab | Next / previous question, cycling (last → first). Option list only — not hijacked inside the editor | | / | Next / previous question, but stop at the boundary (no cycle) — safer than Tab when there are many questions | | Esc | Cancel (or exit custom-input editor without saving) | | Ctrl+\ | Collapse / expand the panel |

Dependencies

None.

Installation

pi install npm:@d3ara1n/pi-ask-user

Or add to ~/.pi/agent/settings.json:

{
  "extensions": [
    "/absolute/path/to/pi-extensions/packages/pi-ask-user"
  ]
}