lite-questionnaire
轻量级交互式问卷工具 — 单选、多选、文本、确认、评分,带条件子问题和声明式校验
Package details
Install lite-questionnaire from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:lite-questionnaire- Package
lite-questionnaire- Version
1.1.4- Published
- May 26, 2026
- Downloads
- not available
- Author
- yunwuhai
- License
- MIT
- Types
- extension, skill
- Size
- 924.9 KB
- Dependencies
- 0 dependencies · 3 peers
Pi manifest JSON
{
"extensions": [
"./index.ts"
],
"skills": [
"./skills"
],
"image": "https://raw.githubusercontent.com/yunwuhai/lite-questionnaire/main/image/logo.png"
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
lite-questionnaire
通用交互式问卷工具,支持单选、多选、文本输入、确认、评分五种问题类型,提供条件子问题、约束校验、会话持久化等高级特性。
目录
问题类型
| 类型 | 标识 | 说明 | Enter 行为 |
|---|---|---|---|
select |
单选 | Space 标定一项,Enter 提交 | 提交并前进 |
multiSelect |
多选 | Space 切换勾选多项,Enter 批量提交 | 提交并前进 |
text |
文本 | 按 Tab 进入内联编辑,无选项列表 | 提交并前进 |
confirm |
确认 | Y/N 双按钮,← → 切换 | 提交默认值"是"并前进 |
rating |
评分 | 滑块条 + 表情量表 + 文字注释 | 提交默认值 3 并前进 |
注意:所有问题均为必答。
confirm和rating具有默认值(是 / 3),无需进入编辑态即可直接 Enter 提交。text类型留空按 Enter 会显示错误提示,不可跳过。←/→ 切换问题时自动提交当前草稿(有值则保存,无值则标红)。
视觉演示
单选
多选
文本输入
确认
评分
参数与字段说明
顶层参数:
| 参数 | 类型 | 说明 |
|---|---|---|
questions |
Question[] |
问题列表(至少 1 个) |
基础字段(所有类型共用)
| 字段 | 类型 | 必填 | 默认 | 说明 |
|---|---|---|---|---|
id |
string | ✅ | - | 唯一标识,作为结果映射的键名 |
label |
string | ✅ | - | Tab 栏短标签 |
prompt |
string | ✅ | - | 完整问题文本 |
type |
enum | ✅ | - | select / multiSelect / text / confirm / rating |
constraints |
Constraint[] | ❌ | [] | 声明式约束校验(详见约束条件) |
children |
Question[] | ❌ | [] | 条件子问题(详见条件子问题) |
showIf |
{ value } | ❌ | - | 子问题条件,仅 children 中的子问题使用 |
select / multiSelect 特有字段
| 字段 | 类型 | 说明 |
|---|---|---|
options |
Option[] | 选项列表 { value, label, description? } |
maxSelect |
number | 单选 = 1,多选 >= 2(最大可选数量) |
末尾自动追加"自定义"选项,Space 勾选 + Tab 编辑自定义值。
text 特有字段
| 字段 | 类型 | 默认 | 说明 |
|---|---|---|---|
placeholder |
string | - | 输入框占位符 |
multiline |
boolean | false | 是否启用多行文本编辑 |
confirm 特有字段
| 字段 | 类型 | 默认 | 说明 |
|---|---|---|---|
yesLabel |
string | "是" | 确认按钮文本 |
noLabel |
string | "否" | 否认按钮文本 |
默认选中"是"。编辑态 ←/→ 切换按钮,Enter 提交。
rating 特有字段
| 字段 | 类型 | 默认 | 说明 |
|---|---|---|---|
range |
{ min: 1, max: 5 } | - | 固定 1-5 评分范围 |
showEmoji |
boolean | false | 显示表情量表(😡😟😐😊😍) |
annotations |
Record<string, string> | - | 数值到文字注释的映射 |
默认值为 3。编辑态 ←/→ 或数字键调整,Enter 提交。
约束条件
{
"constraints": [
{ "type": "minSelect", "value": 1, "message": "至少选择一项" },
{ "type": "minLength", "value": 10, "message": "至少 10 个字符" }
]
}
| type | 适用问题 | value | 说明 |
|---|---|---|---|
required |
全部 | - | 必填校验 |
minSelect |
multiSelect | number | 最少选择项数 |
maxSelect |
multiSelect | number | 最多选择项数 |
minLength |
text | number | 最小文本长度 |
maxLength |
text | number | 最大文本长度 |
pattern |
text | string | 正则匹配 |
条件子问题
{
"id": "lang",
"type": "select",
"maxSelect": 1,
"label": "语言",
"prompt": "用哪种编程语言?",
"options": [
{ "value": "ts", "label": "TypeScript" },
{ "value": "py", "label": "Python" }
],
"children": [
{
"id": "framework",
"type": "select",
"maxSelect": 1,
"label": "框架",
"prompt": "用哪个框架?",
"showIf": { "value": "ts" },
"options": [
{ "value": "react", "label": "React" },
{ "value": "vue", "label": "Vue" }
]
}
]
}
当用户选择 "TypeScript" 时,子问题"框架"自动插入 Tab 序列中(紧跟在父问题之后)。子问题也可以嵌套自己的 children。
交互方式与按键表
| 按键 | 单选 | 多选 | 文本 | 确认 | 评分 |
|---|---|---|---|---|---|
| ↑ ↓ | 导航选项 | 导航选项 | — | — | — |
| ← → | 切换问题 | 切换问题 | 切换问题 | 切换按钮(编辑态) | 调整滑块(编辑态) |
| Space | 标定选项 | 切换勾选 | — | — | — |
| Enter | 提交+前进 | 提交+前进 | 提交+前进 | 提交+前进 | 提交+前进 |
| Tab | 编辑自定义 | 编辑自定义 | 进入编辑 | 进入编辑 | 进入编辑 |
| 1-9 | 跳转选项 | 跳转选项 | — | — | 1-5 跳到对应值 |
| Esc | 取消问卷 | 取消问卷 | 取消问卷 | 取消问卷 | 取消问卷 |
| ← → 非编辑态 | 切换 Tab,有草稿/默认值时自动保存(进度点变绿),无值时标红 | | ← → 编辑态 | 仅操作当前控件(confirm 切换按钮,rating 调整数值),不切换问题 |
- 进度点(三态状态机):⚪ 未访问 → 🔴 已访问但无值 → 🟢 已完成
- 默认值:
confirm默认"是"、rating默认中间值,无需编辑即可直接 Enter 提交 - ←/→ 切题:自动执行非强制提交。有有效值时保存变绿;空值离开标红;违反约束则阻止切换
- ← 回退:随时回到上一题修改,草稿保留。修改后 Enter 覆盖原答案
- 提交页:汇总所有答案,未完成项禁止提交,必须 ← 回去补答
- 自定义选项:单选/多选选项列表末尾始终有"自定义",Space 勾选 + Tab 编辑独立操作
- 单题问卷:完成后直接返回结果(跳过提交页)
返回结果
提交后返回 QuestionnaireResult,answers 为键值对,键为问题 id,值为对应答案结构。
不取消时(正常提交)
{
"answers": {
"<问题id>": { ... },
"<问题id>": { ... }
},
"submittedAt": "2026-05-26T12:00:00.000Z"
}
取消时(按 Esc)
{
"cancelled": true,
"message": "User cancelled the questionnaire"
}
答案类型
SelectAnswer — 单选
{ "value": "ts", "label": "TypeScript", "wasCustom": false }
| 字段 | 类型 | 说明 |
|---|---|---|
value |
string | 用户选择的选项值;自定义内容时为用户输入 |
label |
string | 用户选择的选项显示文本 |
wasCustom |
boolean? | 是否来自"自定义"选项(仅自定义时为 true) |
MultiSelectAnswer — 多选
{ "values": ["auth","api"], "labels": ["用户认证","REST API"], "wasCustom": false }
| 字段 | 类型 | 说明 |
|---|---|---|
values |
string[] | 用户选择的所有选项值 |
labels |
string[] | 用户选择的所有选项显示文本 |
wasCustom |
boolean? | 是否包含"自定义"选项(仅含自定义时为 true) |
TextAnswer — 文本
{ "text": "一个高性能 API 服务" }
| 字段 | 类型 | 说明 |
|---|---|---|
text |
string | 用户输入的文本内容 |
ConfirmAnswer — 确认
{ "confirmed": true, "label": "创建" }
| 字段 | 类型 | 说明 |
|---|---|---|
confirmed |
boolean | 用户的选择:true = 是,false = 否 |
label |
string | 用户选中的按钮文本(yesLabel 或 noLabel) |
RatingAnswer — 评分
{ "value": 5, "annotation": "非常好" }
| 字段 | 类型 | 说明 |
|---|---|---|
value |
number | 用户选择的评分值(整数) |
annotation |
string | 对应数值的文字注释;未配置注解时为空字符串 |
会话持久化
问卷状态自动跨 TUI 会话保存与恢复。如果 AI 多次调用 questionnaire 工具传相同的 questions 列表:
- 首次调用:初始化为空白问卷
- 后续调用:恢复上一次的答案和进度,用户可继续编辑或提交
- 按 Esc 取消后:下次调用仍恢复之前的草稿(取消不会丢失数据)
- 提交后:下一次相同
questions的调用将重新开始(清空状态)
对 AI 而言无需特殊处理,正常调用 questionnaire 即可享受无缝续填体验。
完整示例
{
"questions": [
{
"id": "lang",
"type": "select",
"maxSelect": 1,
"label": "语言",
"prompt": "用哪种编程语言?",
"options": [
{ "value": "ts", "label": "TypeScript" },
{ "value": "py", "label": "Python" },
{ "value": "rs", "label": "Rust" }
],
"children": [
{
"id": "framework",
"type": "select",
"maxSelect": 1,
"label": "框架",
"prompt": "用哪个框架?",
"showIf": { "value": "ts" },
"options": [
{ "value": "react", "label": "React" },
{ "value": "vue", "label": "Vue" }
]
}
]
},
{
"id": "features",
"type": "multiSelect",
"maxSelect": 3,
"label": "功能",
"prompt": "需要哪些功能?",
"options": [
{ "value": "auth", "label": "用户认证" },
{ "value": "api", "label": "REST API" },
{ "value": "ws", "label": "WebSocket" }
],
"constraints": [
{ "type": "minSelect", "value": 1, "message": "至少选择一项" }
]
},
{
"id": "description",
"type": "text",
"label": "描述",
"prompt": "项目描述",
"multiline": true
},
{
"id": "confirm",
"type": "confirm",
"label": "确认",
"prompt": "确定要创建项目?",
"yesLabel": "创建",
"noLabel": "取消"
},
{
"id": "satisfaction",
"type": "rating",
"label": "满意度",
"prompt": "对代码质量的满意度?",
"range": { "min": 1, "max": 5 },
"showEmoji": true,
"annotations": { "1": "非常差", "5": "非常好" }
}
]
}
OpenAPI 规范
完整的 OpenAPI 3.0 类型定义见 design/questionnaire-openapi.yaml。包含所有 schema 定义、答案类型、约束类型和完整请求示例。
代码架构
lite-questionnaire/
├── index.ts # 入口,注册工具 + TypeBox Schema + 渲染回调
├── core.ts # 状态管理、子问题展开、状态机进度判定、约束校验
├── types.ts # TypeScript 类型定义
├── render.ts # 通用渲染(面板框架、Tab 栏、提交页、提示栏)
├── input.ts # 全局按键分发(← → Space Enter Esc Tab 1-9)
├── state.ts # 会话持久化(pi.appendEntry)
├── modules/
│ ├── shared.ts # 模块间共享类型
│ ├── select.ts # 单选渲染 + 输入处理
│ ├── multiSelect.ts # 多选渲染 + 输入处理
│ ├── text.ts # 文本编辑渲染 + 草稿保存
│ ├── confirm.ts # 确认双按钮渲染
│ └── rating.ts # 评分滑块 + 表情渲染
├── design/
│ └── questionnaire-openapi.yaml
├── image/
├── skills/
│ └── lite-questionnaire/
│ └── SKILL.md
├── .gitignore
├── LICENSE
├── package.json
└── README.md
