@wwyxin/pi-ask

Multi-select capable `ask` tool for the Pi coding agent: tappable option lists in pi-web (works on a phone) and keyboard dialogs in the TUI.

Packages

Package details

extension

Install @wwyxin/pi-ask from npm and Pi will load the resources declared by the package manifest.

$ pi install npm:@wwyxin/pi-ask
Package
@wwyxin/pi-ask
Version
0.1.4
Published
Sep 23, 2026
Downloads
492/mo · 492/wk
Author
wwyxin
License
MIT
Types
extension
Size
34.1 KB
Dependencies
0 dependencies · 3 peers
Pi manifest JSON
{
  "extensions": [
    "./index.ts"
  ]
}

Security note

Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.

README

pi-ask

A multi-select capable ask tool for the Pi coding agent — tappable option lists in pi-web (usable on a phone) and normal keyboard dialogs in the terminal TUI.

中文速览

Why this package exists

Pi ships no interactive question tool of its own, and the obvious approaches do not work on a phone:

  • The RPC / pi-web dialog protocol has no multi-select field. ctx.ui.select() is rendered by pi-web as a list of native, tappable option buttons, but it returns a single string (options: string[]).
  • ctx.ui.custom() panels are keyboard-only. Pi forwards a TUI component to pi-web as an ANSI text panel plus a hidden textarea that only receives raw keystrokes. A phone soft keyboard cannot send ArrowUp, Space or Tab, so checkbox UIs built that way are unusable on mobile.

pi-ask therefore emulates multi-select by looping ctx.ui.select(): every pass is a fresh tappable list, tapping an option toggles it, and tapping ✅ 完成选择 finishes the question. No keyboard required.

Install

pi install npm:@wwyxin/pi-ask

The extension auto-loads in every session (pi, pi-web, RPC). Restart pi-web or run /reload in an existing session to pick it up.

Usage

The model calls the tool; you answer by tapping.

{
  "questions": [
    {
      "id": "scope",
      "prompt": "Which parts should I process?",
      "multiSelect": true,
      "options": [
        { "value": "api",   "label": "API layer" },
        { "value": "db",    "label": "Database migrations" },
        { "value": "docs",  "label": "Documentation" }
      ]
    },
    {
      "id": "mode",
      "prompt": "How should I proceed?",
      "allowOther": false,   // opt out of the free-text row; it is on by default
      "options": [
        { "value": "plan", "label": "Show me a plan first" },
        { "value": "do",   "label": "Just do it" }
      ]
    }
  ]
}
Field Type Notes
questions array One or more questions, asked in order in a single tool call
questions[].id string Stable id used in the answer summary
questions[].prompt string Question text (shown as the dialog title)
questions[].options array { value, label, description? }; value is what the model gets back
questions[].multiSelect boolean true = checkbox question, several options may be picked
questions[].allowOther boolean Free-text row (✎ 输入其他 / 补充说明) so the user can always add a note. Defaults to true; set false only when free text would be meaningless

What the user sees

Multi-select question (multiSelect: true) — in pi-web every row is a tappable button, and the three kinds of row look different on purpose:

Which parts should I process?  [已选:API layer、Documentation、放最后再做]

☑ API layer                      ← option: real checkbox (GFM task list)
☐ Database migrations
☑ (其他) 放最后再做                ← typed note: also a checkbox row; tap again to remove
✎ 输入其他 / 补充说明             ← free text: monospace chip, kept above the actions
✅ 完成选择(已选 3 项)           ← commit: bold
🗑 清空选择                       ← destructive: struck through
✕ 取消                           ← escape: italic

pi-web renders option text as GFM Markdown (remark-gfm + rehype-sanitize), and the RPC protocol carries no style information — the option string is the only lever, because pi-web draws the same button chrome around every row. So in RPC mode each kind of row gets its own markdown treatment (checkbox / inline code / bold / strikethrough / italic), which keeps the options, the free-text entry and each of the three action rows visually distinct. The terminal TUI does not render Markdown and keeps the plain glyph form (☐/☑, plain labels).

Known limitation: the bordered button around every row comes from pi-web itself (ExtensionDialog in components/ChatWindow.tsx); the RPC protocol has no per-row style field and rehype-sanitize strips style/class, so an extension cannot remove that frame. Typography above is the strongest differentiation available without patching pi-web.

  • Every row is a button: tap to toggle ☐/☑.
  • The title echoes the running selection, so the list can be long without losing track.
  • ✅ 完成选择 ends the question (zero selections is a valid answer).
  • 🗑 清空选择 appears only when something is selected, and drops typed notes as well as ticks.
  • ✕ 取消 reports a cancellation to the model.

Every question offers a free-text row by default (allowOther defaults to true), so the user is never boxed into the offered options. Typed text shows up as a removable checked row — tap it again to delete it, or tap ✎ 输入其他 / 补充说明 to add another note (duplicates are ignored).

Single-select questions (multiSelect omitted) are a plain list where one tap finishes immediately.

The tool result the model receives is a compact, machine-readable summary:

User answered:
- scope [多选]: API layer、Documentation
- mode: Just do it

Compatibility

  • Works in the terminal TUI and in pi-web / RPC mode (pi-web renders the same dialogs natively).
  • Verified against @earendil-works/pi-coding-agent 0.87.x and @agegr/pi-web 0.9.x.
  • No runtime dependencies: @earendil-works/pi-* are resolved and aliased by the pi extension loader.

Development

npm install   # dev dependency: @earendil-works/pi-coding-agent (for the extension loader)
npm test      # loads index.ts through the real loader and drives it with a fake UI

npm test covers option toggling, the confirm/clear/cancel rows, single-select, the free-text row (including allowOther: false and removing a typed note), several questions per call and the no-UI failure path. It makes no model calls and no network requests.

License

MIT

中文速览

给 Pi coding agent 加的 ask 工具,重点是手机上能用真·多选复选框。

  • 安装:pi install npm:@wwyxin/pi-ask,然后重启 pi-web 或在会话里 /reload。
  • 多选题目里,每个选项都是可点按的按钮,点一下切换勾选;标题实时显示「已选:…」,点「✅ 完成选择」结束。
  • 每类行长得不一样(pi-web 把选项文本按 GFM Markdown 渲染,而 RPC 协议没有样式通道,只能靠文本本身): 选项行 = 真复选框(GFM 任务列表);✎ 输入其他 / 补充说明 = 等宽码片,且放在操作行上面; ✅ 完成选择 = 加粗;🗑 清空选择 = 删除线(破坏性操作);✕ 取消 = 斜体。 终端 TUI 不渲染 Markdown,保持 ☐/☑ 原样。
  • 每行外面那圈带边框的卡片是 pi-web 自己画的(ExtensionDialog 给每行都套同一个按钮壳),RPC 协议没有 逐行样式字段、rehype-sanitize 又会去掉 style/class,所以扩展改不掉那圈框——上面这套排版是“不改 pi-web 的前提下能做到的最强区分”。
  • 每题默认都有一行「✎ 输入其他 / 补充说明」,选项都不合适或想补几句话就点它;输入过的文字会变成 一行可点掉的 ☑ (其他) …,再点一次就删掉。「🗑 清空选择」会连输入的补充一起清掉。
  • 单选题目点一下即结束。
  • 为什么不用 TUI 自绘组件:那些组件在 pi-web 里只会变成一块收原始按键的文本面板,手机软键盘按不出 ↑↓/空格/Tab,等于不可用。本包改成循环调用 ctx.ui.select(),所以纯点按即可。