@leeoohoo/ui-apps-devkit 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/README.md +70 -0
  2. package/bin/chatos-uiapp.js +5 -0
  3. package/package.json +22 -0
  4. package/src/cli.js +53 -0
  5. package/src/commands/dev.js +14 -0
  6. package/src/commands/init.js +141 -0
  7. package/src/commands/install.js +55 -0
  8. package/src/commands/pack.js +72 -0
  9. package/src/commands/validate.js +103 -0
  10. package/src/lib/args.js +49 -0
  11. package/src/lib/config.js +29 -0
  12. package/src/lib/fs.js +78 -0
  13. package/src/lib/path-boundary.js +16 -0
  14. package/src/lib/plugin.js +45 -0
  15. package/src/lib/template.js +168 -0
  16. package/src/sandbox/server.js +861 -0
  17. package/templates/basic/README.md +58 -0
  18. package/templates/basic/chatos.config.json +5 -0
  19. package/templates/basic/docs/CHATOS_UI_APPS_AI_CONTRIBUTIONS.md +181 -0
  20. package/templates/basic/docs/CHATOS_UI_APPS_BACKEND_PROTOCOL.md +74 -0
  21. package/templates/basic/docs/CHATOS_UI_APPS_HOST_API.md +123 -0
  22. package/templates/basic/docs/CHATOS_UI_APPS_OVERVIEW.md +110 -0
  23. package/templates/basic/docs/CHATOS_UI_APPS_PLUGIN_MANIFEST.md +227 -0
  24. package/templates/basic/docs/CHATOS_UI_PROMPTS_PROTOCOL.md +392 -0
  25. package/templates/basic/plugin/apps/app/index.mjs +263 -0
  26. package/templates/basic/plugin/apps/app/mcp-prompt.en.md +7 -0
  27. package/templates/basic/plugin/apps/app/mcp-prompt.zh.md +7 -0
  28. package/templates/basic/plugin/apps/app/mcp-server.mjs +15 -0
  29. package/templates/basic/plugin/backend/index.mjs +37 -0
  30. package/templates/basic/template.json +7 -0
  31. package/templates/notepad/README.md +36 -0
  32. package/templates/notepad/chatos.config.json +4 -0
  33. package/templates/notepad/docs/CHATOS_UI_APPS_AI_CONTRIBUTIONS.md +181 -0
  34. package/templates/notepad/docs/CHATOS_UI_APPS_BACKEND_PROTOCOL.md +74 -0
  35. package/templates/notepad/docs/CHATOS_UI_APPS_HOST_API.md +123 -0
  36. package/templates/notepad/docs/CHATOS_UI_APPS_OVERVIEW.md +110 -0
  37. package/templates/notepad/docs/CHATOS_UI_APPS_PLUGIN_MANIFEST.md +227 -0
  38. package/templates/notepad/docs/CHATOS_UI_PROMPTS_PROTOCOL.md +392 -0
  39. package/templates/notepad/plugin/apps/app/api.mjs +30 -0
  40. package/templates/notepad/plugin/apps/app/dom.mjs +14 -0
  41. package/templates/notepad/plugin/apps/app/ds-tree.mjs +35 -0
  42. package/templates/notepad/plugin/apps/app/index.mjs +1056 -0
  43. package/templates/notepad/plugin/apps/app/layers.mjs +338 -0
  44. package/templates/notepad/plugin/apps/app/markdown.mjs +120 -0
  45. package/templates/notepad/plugin/apps/app/mcp-prompt.en.md +22 -0
  46. package/templates/notepad/plugin/apps/app/mcp-prompt.zh.md +22 -0
  47. package/templates/notepad/plugin/apps/app/mcp-server.mjs +200 -0
  48. package/templates/notepad/plugin/apps/app/styles.mjs +355 -0
  49. package/templates/notepad/plugin/apps/app/tags.mjs +21 -0
  50. package/templates/notepad/plugin/apps/app/ui.mjs +280 -0
  51. package/templates/notepad/plugin/backend/index.mjs +99 -0
  52. package/templates/notepad/plugin/plugin.json +23 -0
  53. package/templates/notepad/plugin/shared/notepad-paths.mjs +62 -0
  54. package/templates/notepad/plugin/shared/notepad-store.mjs +765 -0
  55. package/templates/notepad/template.json +8 -0
@@ -0,0 +1,227 @@
1
+ # ChatOS UI Apps:`plugin.json` 清单规范(协议)
2
+
3
+ 本文件定义 UI Apps 插件清单 `plugin.json` 的字段与约束,目标是让第三方/内置应用都能按统一契约被 ChatOS 扫描、加载与运行。
4
+
5
+ 实现对照(以代码为准):
6
+
7
+ - schema:`deepseek_cli/electron/ui-apps/schemas.js`
8
+ - 扫描/校验:`deepseek_cli/electron/ui-apps/index.js`
9
+ - 导入/安装:`deepseek_cli/electron/ui-apps/plugin-installer.js`
10
+
11
+ 另见:
12
+
13
+ - [`CHATOS_UI_APPS_HOST_API.md`](./CHATOS_UI_APPS_HOST_API.md)(`module` 应用与宿主交互)
14
+ - [`CHATOS_UI_APPS_BACKEND_PROTOCOL.md`](./CHATOS_UI_APPS_BACKEND_PROTOCOL.md)(插件后端)
15
+ - [`CHATOS_UI_APPS_AI_CONTRIBUTIONS.md`](./CHATOS_UI_APPS_AI_CONTRIBUTIONS.md)(MCP/Prompt 暴露)
16
+
17
+ ## 1. 文件与安装位置
18
+
19
+ - 每个插件一个目录,目录根部必须包含 `plugin.json`。
20
+ - 插件目录可放在:
21
+ - `deepseek_cli/ui_apps/plugins`(内置/开发)
22
+ - `~/.deepseek_cli/chatos/ui_apps/plugins`(用户插件目录)
23
+ - 也可通过桌面端 UI:`应用` → `导入应用包`(目录或 `.zip`)安装到用户插件目录。
24
+
25
+ ## 2. 顶层 schema(`uiAppsPluginSchema`)
26
+
27
+ `plugin.json`(Top-level)字段:
28
+
29
+ | 字段 | 类型 | 必填 | 默认 | 说明 |
30
+ |---|---:|---:|---|---|
31
+ | `manifestVersion` | `number` | 否 | `1` | 目前仅支持 `1` |
32
+ | `id` | `string` | 是 | - | 插件 ID(使用反向域名;稳定且全局唯一) |
33
+ | `name` | `string` | 是 | - | 插件显示名称 |
34
+ | `version` | `string` | 否 | `"0.0.0"` | 版本号(展示用途) |
35
+ | `description` | `string` | 否 | `""` | 插件描述 |
36
+ | `backend` | `object` | 否 | - | 插件后端(Electron main 进程) |
37
+ | `apps` | `array` | 否 | `[]` | 插件内的应用列表 |
38
+
39
+ `backend`:
40
+
41
+ | 字段 | 类型 | 必填 | 说明 |
42
+ |---|---:|---:|---|
43
+ | `backend.entry` | `string` | 是 | 后端入口模块路径(相对插件目录;必须在插件目录内且是文件) |
44
+
45
+ ## 3. apps schema(`uiAppSchema`)
46
+
47
+ `apps[i]` 字段:
48
+
49
+ | 字段 | 类型 | 必填 | 默认 | 说明 |
50
+ |---|---:|---:|---|---|
51
+ | `id` | `string` | 是 | - | 应用 ID(同一插件内唯一) |
52
+ | `name` | `string` | 是 | - | 应用显示名称 |
53
+ | `description` | `string` | 否 | `""` | 描述 |
54
+ | `icon` | `string` | 否 | `""` | 图标(当前实现以字符串透传为主) |
55
+ | `entry` | `object` | 是 | - | 入口(仅支持 `module`) |
56
+ | `ai` | `object|string` | 否 | - | AI 声明(MCP/Prompt/暴露列表等;详见下文) |
57
+
58
+ ### 3.1 `apps[i].entry`(仅支持 `module`)
59
+
60
+ ```json
61
+ { "type": "module", "path": "my-app/index.mjs" }
62
+ ```
63
+
64
+ 硬约束:
65
+
66
+ - `entry.type` 必须为 `"module"`(ChatOS 不支持 `iframe/url`)。
67
+ - `entry.path` 必须在插件目录内(宿主做路径边界校验),且必须是文件。
68
+
69
+ ## 4. `apps[i].ai` schema(`uiAppAiSchema`)
70
+
71
+ `ai` 可以写成两种形式:
72
+
73
+ 1) **对象**(inline):
74
+
75
+ ```json
76
+ {
77
+ "ai": {
78
+ "mcpServers": true,
79
+ "prompts": true
80
+ }
81
+ }
82
+ ```
83
+
84
+ 2) **字符串路径**(等价于 `{ "config": "<path>" }`):
85
+
86
+ ```json
87
+ { "ai": "my-app/ai.yaml" }
88
+ ```
89
+
90
+ 对象形式还支持额外带一个 `config` 字段,用于从文件读取并与 inline 合并:
91
+
92
+ ```json
93
+ {
94
+ "ai": {
95
+ "config": "my-app/ai.yaml",
96
+ "mcpServers": true,
97
+ "prompts": true
98
+ }
99
+ }
100
+ ```
101
+
102
+ 所有 `ai` 的 path(`ai.config`、`ai.mcp.entry`、`ai.mcpPrompt.*.path`)都必须在插件目录内,且文件大小受限(默认最大 `128 KiB`)。
103
+
104
+ ### 4.1 `ai` 字段一览(`uiAppAiConfigSchema`)
105
+
106
+ | 字段 | 类型 | 说明 |
107
+ |---|---:|---|
108
+ | `ai.mcp` | `object` | 声明并同步一个 MCP Server(`serverName` 固定派生为 `${pluginId}.${appId}`) |
109
+ | `ai.mcpPrompt` | `string|object` | 声明并同步一个 system prompt(名称固定派生) |
110
+ | `ai.mcpServers` | `true|false|string[]` | 暴露给 Agent 的 MCP servers 范围(聚合“已有的”资源) |
111
+ | `ai.prompts` | `true|false|string[]` | 暴露给 Agent 的 prompts 范围(聚合“已有的”资源) |
112
+ | `ai.agent` | `object` | 可选:应用提供的 Agent 模板(当前实现主要做透传/保留字段) |
113
+
114
+ ## 5. `ai.mcp`:MCP Server 声明
115
+
116
+ `ai.mcp` 字段(当前 schema):
117
+
118
+ | 字段 | 类型 | 必填 | 默认 | 说明 |
119
+ |---|---:|---:|---|---|
120
+ | `url` | `string` | 二选一 | - | 远程 MCP Server 地址(`http(s)://` / `ws(s)://` 等) |
121
+ | `entry` | `string` | 二选一 | - | 本地脚本入口(相对插件目录);宿主会转换为 `cmd://...` |
122
+ | `command` | `string` | 否 | `"node"` | 拉起本地 `entry` 时使用的命令 |
123
+ | `args` | `string[]` | 否 | `[]` | 拉起时追加参数 |
124
+ | `description` | `string` | 否 | `""` | 描述 |
125
+ | `tags` | `string[]` | 否 | `[]` | 标签(宿主还会自动附加 `uiapp*` 标签) |
126
+ | `enabled` | `boolean` | 否 | - | 是否启用(未填则宿主同步时默认 `true`) |
127
+ | `allowMain` | `boolean` | 否 | - | 是否允许主流程使用(未填则宿主同步时默认 `true`) |
128
+ | `allowSub` | `boolean` | 否 | - | 是否允许子代理使用(未填则宿主同步时默认 `true`) |
129
+ | `auth` | `object` | 否 | - | 认证信息(token/basic/headers) |
130
+
131
+ 强约束:
132
+
133
+ - 必须提供 `url` 或 `entry` 其中之一(只写 `command` 不算有效配置)。
134
+
135
+ `auth` 结构(均为可选,且支持 partial):
136
+
137
+ ```json
138
+ {
139
+ "auth": {
140
+ "token": "…",
141
+ "basic": { "username": "u", "password": "p" },
142
+ "headers": { "X-Foo": "bar" }
143
+ }
144
+ }
145
+ ```
146
+
147
+ 当使用 `entry` 时,宿主会把它转换为可运行的 `cmd://`:
148
+
149
+ - `command` 默认为 `node`
150
+ - `args` 会追加到命令行末尾
151
+ - 宿主会把空格/引号等做安全引用,以避免路径包含空格时解析失败
152
+
153
+ ## 6. `ai.mcpPrompt`:应用默认 Prompt 声明
154
+
155
+ `ai.mcpPrompt` 支持两种写法:
156
+
157
+ 1) **字符串**:等价于中文 prompt 从该路径读取:
158
+
159
+ ```json
160
+ { "mcpPrompt": "my-app/mcp-prompt.zh.md" }
161
+ ```
162
+
163
+ 2) **对象**:可分别提供 `zh`/`en`,并支持 path 或 inline content:
164
+
165
+ ```json
166
+ {
167
+ "mcpPrompt": {
168
+ "title": "My App · MCP Prompt",
169
+ "zh": "my-app/mcp-prompt.zh.md",
170
+ "en": { "path": "my-app/mcp-prompt.en.md" }
171
+ }
172
+ }
173
+ ```
174
+
175
+ `zh/en` 的“source”结构为:
176
+
177
+ ```json
178
+ { "path": "relative.md", "content": "inline markdown…" }
179
+ ```
180
+
181
+ 约束:
182
+
183
+ - `mcpPrompt` 必须至少提供 `zh` 或 `en` 其一;
184
+ - 若提供 `path`,必须在插件目录内且是文件;
185
+ - 内容大小受限(默认最大 `128 KiB`)。
186
+
187
+ ## 7. `ai.mcpServers` / `ai.prompts`:聚合暴露范围
188
+
189
+ - `true`:开启暴露(“具体暴露哪些”由 `ai.config` / 内置默认清单决定;否则表示全部)
190
+ - `false`:禁用暴露
191
+ - `string[]`:精确列出允许暴露的 `serverName` / `prompt name`
192
+
193
+ 注意:这里定义的是“在 Agent UI 中可选/可见的范围”,最终是否启用、启用哪些仍由 Agent 编辑页勾选决定。
194
+
195
+ ## 8. 最小示例
196
+
197
+ ### 8.1 最小可运行插件(仅 module)
198
+
199
+ ```json
200
+ {
201
+ "manifestVersion": 1,
202
+ "id": "com.example.tools",
203
+ "name": "Example Tools",
204
+ "version": "0.1.0",
205
+ "apps": [
206
+ {
207
+ "id": "hello",
208
+ "name": "Hello App(Module)",
209
+ "entry": { "type": "module", "path": "hello/index.mjs" }
210
+ }
211
+ ]
212
+ }
213
+ ```
214
+
215
+ ### 8.2 带后端 + MCP/Prompt 的应用(节选)
216
+
217
+ ```json
218
+ {
219
+ "id": "db-client",
220
+ "name": "数据库客户端",
221
+ "entry": { "type": "module", "path": "db-client/index.mjs" },
222
+ "ai": {
223
+ "mcp": { "entry": "db-client/mcp-server.mjs", "command": "node", "allowMain": true, "allowSub": true },
224
+ "mcpPrompt": { "zh": "db-client/mcp-prompt.zh.md", "en": "db-client/mcp-prompt.en.md" }
225
+ }
226
+ }
227
+ ```
@@ -0,0 +1,392 @@
1
+ # ChatOS UI Prompts(笑脸交互待办)协议
2
+
3
+ UI Prompts 是 ChatOS 的全局交互队列:任意组件(AI / MCP / UI Apps)都通过向队列写入 `request` 记录来发起一次“需要用户输入/确认”的交互;用户在 UI(右下角笑脸面板)完成填写后,系统写入对应的 `response` 记录来结束该交互。
4
+
5
+ 本协议定义:
6
+
7
+ - 存储格式:`ui-prompts.jsonl`(JSON Lines 追加日志)
8
+ - 交互生命周期:`request` → `response`
9
+ - UI 渲染支持的 `prompt.kind` 与字段(`kv` / `choice` / `task_confirm` / `file_change_confirm`)
10
+ - UI Apps 的 Host API 调用方式(`host.uiPrompts.*`)
11
+
12
+ 实现对照(以代码为准):
13
+
14
+ - UI 渲染:`deepseek_cli/apps/ui/src/features/session/floating-island/FloatingIslandPrompt.jsx`
15
+ - 笑脸面板:`deepseek_cli/apps/ui/src/components/UiPromptsSmileHub.jsx`
16
+ - Host IPC:`deepseek_cli/electron/main.js`(`uiPrompts:*`)
17
+ - 写入/读取日志:`aide/electron/session-api.js`(`requestUiPrompt` / `respondUiPrompt` / `readUiPromptsPayload`)
18
+ - MCP `ui_prompter`:`aide/mcp_servers/ui-prompt-server.js`
19
+
20
+ ---
21
+
22
+ ## 1. 存储:`ui-prompts.jsonl`
23
+
24
+ ### 1.1 文件位置
25
+
26
+ UI Prompts 以 JSONL 形式追加写入到:
27
+
28
+ - `stateDir/ui-prompts.jsonl`
29
+
30
+ 其中 `stateDir` 为 ChatOS 的状态目录(宿主按 `hostApp` 做隔离;ChatOS 的 `hostApp=chatos`)。
31
+
32
+ ### 1.2 JSONL 记录类型
33
+
34
+ 每一行是一个 JSON 对象(以下简称 entry)。当前 UI Prompts 只消费:
35
+
36
+ - `entry.type === "ui_prompt"`
37
+
38
+ 并按 `entry.action` 区分:
39
+
40
+ - `entry.action === "request"`:发起交互
41
+ - `entry.action === "response"`:结束交互
42
+
43
+ ### 1.3 Pending 判定(队列语义)
44
+
45
+ UI 端的“待处理”集合由日志推导:
46
+
47
+ - 对同一个 `requestId`,存在 `request` 但不存在 `response` 时,该交互处于 pending 状态;
48
+ - 当出现 `response` 后,该交互从 pending 中移除;
49
+ - 日志是追加写入,系统不删除旧行。
50
+
51
+ ---
52
+
53
+ ## 2. Host API(UI Apps 对接入口)
54
+
55
+ UI Apps 的 `module` 应用通过 Host API 与 UI Prompts 交互:
56
+
57
+ - `host.uiPrompts.read(): Promise<{ path: string, entries: any[] }>`
58
+ - `host.uiPrompts.onUpdate((payload) => void): () => void`
59
+ - `host.uiPrompts.request(payload): Promise<{ ok: true, requestId: string }>`
60
+ - `host.uiPrompts.respond(payload): Promise<{ ok: true }>`
61
+ - `host.uiPrompts.open()/close()/toggle()`
62
+
63
+ `host.uiPrompts.request()` 在 `prompt.source` 为空时,会自动写入 `${pluginId}:${appId}`。
64
+
65
+ ### 2.1 `host.uiPrompts.request(payload)`
66
+
67
+ `payload` 字段:
68
+
69
+ | 字段 | 类型 | 必填 | 说明 |
70
+ |---|---:|---:|---|
71
+ | `requestId` | `string` | 否 | 为空时宿主生成 |
72
+ | `runId` | `string` | 否 | 透传到 entry,用于 UI 标识来源 run |
73
+ | `prompt` | `object` | 是 | 交互定义(见第 4-8 节) |
74
+
75
+ 返回:
76
+
77
+ - `{ ok: true, requestId }`(`requestId` 为最终使用的 ID)
78
+
79
+ ### 2.2 `host.uiPrompts.respond(payload)`
80
+
81
+ `payload` 字段:
82
+
83
+ | 字段 | 类型 | 必填 | 说明 |
84
+ |---|---:|---:|---|
85
+ | `requestId` | `string` | 是 | 对应 `request` 的 `requestId` |
86
+ | `runId` | `string` | 否 | 透传到 entry |
87
+ | `response` | `object` | 是 | 必须包含 `response.status` |
88
+
89
+ 返回:
90
+
91
+ - `{ ok: true }`
92
+
93
+ ---
94
+
95
+ ## 3. Entry 协议(写入 `ui-prompts.jsonl` 的数据结构)
96
+
97
+ ### 3.1 Request Entry
98
+
99
+ ```json
100
+ {
101
+ "ts": "2026-01-11T00:00:00.000Z",
102
+ "type": "ui_prompt",
103
+ "action": "request",
104
+ "requestId": "uuid-or-app-generated-id",
105
+ "runId": "optional-run-id",
106
+ "prompt": { "...": "see below" }
107
+ }
108
+ ```
109
+
110
+ 字段:
111
+
112
+ - `ts`:ISO 时间字符串
113
+ - `type`:固定为 `"ui_prompt"`
114
+ - `action`:固定为 `"request"`
115
+ - `requestId`:字符串;同一次交互的唯一 ID
116
+ - `runId`:可选字符串;用于在 UI 中标识来源 run(显示为 Tag)
117
+ - `prompt`:对象;由 `prompt.kind` 决定结构(见第 4 节)
118
+
119
+ ### 3.2 Response Entry
120
+
121
+ ```json
122
+ {
123
+ "ts": "2026-01-11T00:00:10.000Z",
124
+ "type": "ui_prompt",
125
+ "action": "response",
126
+ "requestId": "uuid-or-app-generated-id",
127
+ "runId": "optional-run-id",
128
+ "response": { "...": "see below" }
129
+ }
130
+ ```
131
+
132
+ 字段:
133
+
134
+ - `ts`:ISO 时间字符串
135
+ - `type`:固定为 `"ui_prompt"`
136
+ - `action`:固定为 `"response"`
137
+ - `requestId`:必须与对应 `request` 一致
138
+ - `runId`:可选;用于标识来源 run
139
+ - `response`:对象;必须包含 `response.status`
140
+
141
+ ---
142
+
143
+ ## 4. Prompt 协议(`prompt.kind`)
144
+
145
+ ### 4.1 通用字段(所有 kind 均可出现)
146
+
147
+ | 字段 | 类型 | 必填 | 说明 |
148
+ |---|---:|---:|---|
149
+ | `kind` | `string` | 是 | 取值:`kv` / `choice` / `task_confirm` / `file_change_confirm` |
150
+ | `title` | `string` | 否 | UI 标题 |
151
+ | `message` | `string` | 否 | UI 描述/说明 |
152
+ | `source` | `string` | 否 | 来源标识(UI 显示 Tag) |
153
+ | `allowCancel` | `boolean` | 否 | `false` 时 UI 不提供取消入口;其余情况允许取消 |
154
+
155
+ ---
156
+
157
+ ## 5. `kind="kv"`:键值表单(多字段输入)
158
+
159
+ ### 5.1 请求结构
160
+
161
+ ```json
162
+ {
163
+ "kind": "kv",
164
+ "title": "需要你补充信息",
165
+ "message": "请填写表单后继续。",
166
+ "source": "com.example.plugin:my-app",
167
+ "allowCancel": true,
168
+ "fields": [
169
+ {
170
+ "key": "name",
171
+ "label": "姓名",
172
+ "description": "用于报告署名",
173
+ "placeholder": "请输入",
174
+ "default": "",
175
+ "required": true,
176
+ "multiline": false,
177
+ "secret": false
178
+ }
179
+ ]
180
+ }
181
+ ```
182
+
183
+ 字段约束:
184
+
185
+ - `fields`:数组,长度 `1..50`
186
+ - `fields[].key`:字符串,非空且在 `fields` 内唯一
187
+ - `fields[].label/description/placeholder/default`:可选字符串
188
+ - `fields[].required/multiline/secret`:可选布尔
189
+
190
+ UI 渲染规则:
191
+
192
+ - `multiline=true` → 多行输入框(TextArea)
193
+ - `secret=true` → 密码输入框(Password)
194
+ - 否则 → 单行输入框(Input)
195
+
196
+ ### 5.2 响应结构
197
+
198
+ ```json
199
+ { "status": "ok", "values": { "name": "Alice" } }
200
+ ```
201
+
202
+ - `status="ok"` 时,`values` 必须为对象,value 类型为 `string`
203
+ - `status!="ok"` 时,`values` 字段不参与消费
204
+
205
+ ---
206
+
207
+ ## 6. `kind="choice"`:单选 / 多选
208
+
209
+ ### 6.1 请求结构(单选)
210
+
211
+ ```json
212
+ {
213
+ "kind": "choice",
214
+ "title": "需要你做出选择",
215
+ "message": "请选择一项。",
216
+ "source": "com.example.plugin:my-app",
217
+ "allowCancel": true,
218
+ "multiple": false,
219
+ "options": [
220
+ { "value": "alpha", "label": "Alpha", "description": "选项说明" },
221
+ { "value": "beta", "label": "Beta", "description": "" }
222
+ ],
223
+ "default": "alpha",
224
+ "minSelections": 0,
225
+ "maxSelections": 2
226
+ }
227
+ ```
228
+
229
+ ### 6.2 请求结构(多选)
230
+
231
+ ```json
232
+ {
233
+ "kind": "choice",
234
+ "title": "需要你做出选择(多选)",
235
+ "message": "请选择 1-2 项。",
236
+ "allowCancel": true,
237
+ "multiple": true,
238
+ "options": [
239
+ { "value": "a", "label": "A" },
240
+ { "value": "b", "label": "B" },
241
+ { "value": "c", "label": "C" }
242
+ ],
243
+ "default": ["a"],
244
+ "minSelections": 1,
245
+ "maxSelections": 2
246
+ }
247
+ ```
248
+
249
+ 字段约束:
250
+
251
+ - `options`:数组,长度 `1..60`
252
+ - `options[].value`:字符串,非空且在 `options` 内唯一
253
+ - `options[].label/description`:可选字符串
254
+ - `multiple`:布尔,缺省为 `false`
255
+ - `default`:
256
+ - `multiple=false` → `string`
257
+ - `multiple=true` → `string[]`
258
+ - 默认值必须来自 `options[].value`
259
+ - `minSelections/maxSelections`:
260
+ - `multiple=true` 时生效
261
+ - `minSelections`:整数,范围 `0..options.length`
262
+ - `maxSelections`:整数,范围 `1..options.length`
263
+ - `minSelections <= maxSelections`
264
+
265
+ ### 6.3 响应结构
266
+
267
+ 单选:
268
+
269
+ ```json
270
+ { "status": "ok", "selection": "alpha" }
271
+ ```
272
+
273
+ 多选:
274
+
275
+ ```json
276
+ { "status": "ok", "selection": ["a", "b"] }
277
+ ```
278
+
279
+ `status!="ok"` 时,`selection` 字段不参与消费。
280
+
281
+ ---
282
+
283
+ ## 7. `kind="task_confirm"`:任务创建确认(复杂表单)
284
+
285
+ 该类型用于“任务列表的创建/编辑/排序确认”。UI 会渲染一组可编辑任务卡片,并在提交时返回任务数组。
286
+
287
+ ### 7.1 请求结构
288
+
289
+ ```json
290
+ {
291
+ "kind": "task_confirm",
292
+ "title": "任务创建确认",
293
+ "message": "请确认任务列表。",
294
+ "allowCancel": true,
295
+ "source": "main",
296
+ "tasks": [
297
+ {
298
+ "draftId": "uuid",
299
+ "title": "写文档",
300
+ "details": "补齐 UI Prompts 协议",
301
+ "priority": "high",
302
+ "status": "todo",
303
+ "tags": ["docs", "ui-prompts"]
304
+ }
305
+ ],
306
+ "defaultRemark": ""
307
+ }
308
+ ```
309
+
310
+ 字段:
311
+
312
+ - `tasks`:可选数组(缺省为 `[]`)
313
+ - `tasks[].draftId`:字符串;为空时系统会生成
314
+ - `tasks[].title/details`:字符串
315
+ - `tasks[].priority`:`high | medium | low`(缺省为 `medium`)
316
+ - `tasks[].status`:`todo | doing | blocked | done`(缺省为 `todo`)
317
+ - `tasks[].tags`:`string[]`
318
+ - `defaultRemark`:可选字符串;用于初始化备注输入框
319
+
320
+ ### 7.2 响应结构
321
+
322
+ ```json
323
+ {
324
+ "status": "ok",
325
+ "tasks": [
326
+ {
327
+ "draftId": "uuid",
328
+ "title": "写文档",
329
+ "details": "补齐 UI Prompts 协议",
330
+ "priority": "high",
331
+ "status": "todo",
332
+ "tags": ["docs", "ui-prompts"]
333
+ }
334
+ ],
335
+ "remark": "按这个列表创建即可"
336
+ }
337
+ ```
338
+
339
+ `status="ok"` 时,`tasks` 为数组;`remark` 为可选字符串。
340
+ `status!="ok"` 时,`tasks` 字段不参与消费;`remark` 可出现。
341
+
342
+ ---
343
+
344
+ ## 8. `kind="file_change_confirm"`:文件变更确认(复杂表单)
345
+
346
+ 该类型用于“文件变更/命令执行前确认”。UI 会渲染 diff/命令与路径信息,并在提交时返回 `remark`。
347
+
348
+ ### 8.1 请求结构
349
+
350
+ ```json
351
+ {
352
+ "kind": "file_change_confirm",
353
+ "title": "文件变更确认",
354
+ "message": "即将写入文件。",
355
+ "allowCancel": true,
356
+ "source": "filesystem/write_file",
357
+ "path": "src/app.js",
358
+ "command": "node scripts/generate.js",
359
+ "cwd": "C:\\\\project\\\\aide",
360
+ "diff": "--- a/src/app.js\\n+++ b/src/app.js\\n@@ ...",
361
+ "defaultRemark": ""
362
+ }
363
+ ```
364
+
365
+ 字段:
366
+
367
+ - `path/command/cwd/diff/defaultRemark`:可选字符串
368
+
369
+ ### 8.2 响应结构
370
+
371
+ ```json
372
+ { "status": "ok", "remark": "继续执行" }
373
+ ```
374
+
375
+ `remark` 为可选字符串;`status="ok"` 表示确认继续,其它 `status` 表示取消/中止。
376
+
377
+ ---
378
+
379
+ ## 9. 复杂交互的构建方式
380
+
381
+ UI Prompts 的基本单位是一条 `request` 记录。复杂交互由多条 `request/response` 串联构成:
382
+
383
+ 1) 应用写入第 1 条 `request`(得到 `requestId`)
384
+ 2) 应用监听 `host.uiPrompts.onUpdate`,在 entries 中定位同 `requestId` 的 `response`
385
+ 3) 应用基于该 `response` 决定下一步,再写入下一条 `request`
386
+
387
+ 在该模型下:
388
+
389
+ - “多字段表单”使用 `kind="kv"` 的 `fields[]` 承载
390
+ - “多选/单选”使用 `kind="choice"` 的 `multiple/options` 承载
391
+ - “任务列表确认”使用 `kind="task_confirm"` 承载
392
+ - “diff/命令确认”使用 `kind="file_change_confirm"` 承载