@autopilot-agent/cli 0.1.0 → 0.2.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.
- package/README.md +27 -155
- package/dist/activity-animation.d.ts +2 -0
- package/dist/activity-animation.js +8 -5
- package/dist/composition-root.js +13 -1
- package/dist/context-report.d.ts +1 -1
- package/dist/context-report.js +2 -3
- package/dist/controller.js +60 -0
- package/dist/design-tokens.d.ts +4 -0
- package/dist/design-tokens.js +4 -0
- package/dist/event-projector.js +4 -2
- package/dist/parser.js +13 -4
- package/dist/renderer.js +16 -2
- package/dist/termination-format.js +1 -0
- package/dist/tui/app.js +11 -8
- package/dist/tui/approval.d.ts +1 -1
- package/dist/tui/approval.js +8 -4
- package/dist/tui/constants.d.ts +1 -1
- package/dist/tui/constants.js +1 -1
- package/dist/tui/format.js +4 -2
- package/dist/tui/store.js +84 -48
- package/dist/tui/timeline/live.js +7 -5
- package/dist/tui/timeline/presentation-timeline.d.ts +2 -1
- package/dist/tui/timeline/presentation-timeline.js +34 -15
- package/dist/tui/timeline/static-timeline.js +16 -6
- package/dist/tui/timeline/turn-items.d.ts +12 -0
- package/dist/tui/timeline/turn-items.js +28 -0
- package/dist/tui/timeline/turn.js +6 -6
- package/dist/tui/transcript.d.ts +1 -1
- package/dist/tui/transcript.js +2 -2
- package/dist/tui/types.d.ts +15 -1
- package/dist/tui/viewport/sources.d.ts +2 -2
- package/dist/tui/viewport/sources.js +72 -65
- package/dist/tui/viewport/viewport.js +5 -1
- package/dist/types.d.ts +13 -0
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -1,181 +1,53 @@
|
|
|
1
|
-
<!-- 本文件用于 npm CLI 用户了解安装、配置和使用方式。 -->
|
|
2
1
|
# @autopilot-agent/cli
|
|
3
2
|
|
|
4
|
-
Autopilot
|
|
5
|
-
|
|
6
|
-
安装后使用 `ap` 或 `autopilot` 启动,两者功能相同。
|
|
7
|
-
|
|
8
|
-
## 可以做什么
|
|
9
|
-
|
|
10
|
-
- **理解项目**:阅读文件、按文件名或内容搜索代码,梳理项目结构、解释实现、定位问题。输入 `@src/index.ts` 这样的相对路径,可以把指定文件带入当前对话。
|
|
11
|
-
- **编写和修改代码**:根据需求创建文件、修改已有代码,帮助修复 Bug、补充测试和整理文档;交互界面会展示文件修改信息。
|
|
12
|
-
- **执行开发命令**:运行测试、构建和其他命令,根据输出继续排查;耗时命令可以作为后台任务运行,随时查看输出或请求停止。
|
|
13
|
-
- **跟踪任务进度**:将复杂需求拆成待办事项,在执行过程中更新完成状态;任务运行时也可以排队提交下一条需求。
|
|
14
|
-
- **继续已有对话**:保存并管理项目会话,在已有会话中继续提问;中断后可恢复的任务可以通过 `ap resume` 继续。
|
|
15
|
-
- **管理上下文**:查看当前上下文用量,手动压缩对话;具备有效上下文预算时,也会按阈值自动压缩,帮助继续较长的任务。
|
|
16
|
-
- **控制操作权限**:确认项目是否可信,选择权限模式,并审批需要确认的操作;通过 `/undo` 预览并撤销当前会话最近一轮可撤销的文件修改。
|
|
17
|
-
- **扩展工具和工作流程**:加载已安装的 Skills,通过 `/skill` 选择使用;配置并授权 MCP 服务后,可以调用其提供的工具。
|
|
18
|
-
- **查资料和分析图片**:配置搜索服务后可以联网搜索、读取网页;配置可用的视觉模型后,可以分析项目中的图片,例如界面截图。
|
|
19
|
-
|
|
20
|
-
你可以直接用自然语言提出需求,例如:
|
|
21
|
-
|
|
22
|
-
```text
|
|
23
|
-
分析这个项目的入口和主要模块,先不要修改文件。
|
|
24
|
-
查找登录失败的原因,修复后运行相关测试。
|
|
25
|
-
根据这张UI设计图片,还原设计稿。
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
## 常用交互命令
|
|
29
|
-
|
|
30
|
-
启动 `ap` 后,输入 `/` 可以查看命令建议。
|
|
31
|
-
|
|
32
|
-
| 命令 | 用途 |
|
|
33
|
-
|---|---|
|
|
34
|
-
| `/model`、`/effort` | 选择后续任务使用的模型和思考强度 |
|
|
35
|
-
| `/skill` | 查看并选择已安装的 Skills |
|
|
36
|
-
| `/permissions` | 查看或切换当前会话的权限模式 |
|
|
37
|
-
| `/context`、`/context all` | 查看上下文用量,或展开详细信息 |
|
|
38
|
-
| `/compact` | 手动压缩当前上下文 |
|
|
39
|
-
| `/jobs` | 查看后台任务,也可查看输出或请求停止 |
|
|
40
|
-
| `/queue <需求>` | 将下一条需求加入队列 |
|
|
41
|
-
| `/undo` | 预览最近一轮可撤销的文件修改,再确认是否撤销 |
|
|
42
|
-
| `/cancel`、`/exit` | 取消当前任务,或退出 CLI |
|
|
43
|
-
|
|
44
|
-
## 安装
|
|
45
|
-
|
|
46
|
-
请先安装 **Node.js >=20.11.0 且 <22** 和 npm,再运行以下命令。安装时需要联网。
|
|
3
|
+
Autopilot 的终端宿主包。普通用户安装主包 `autopilot-agent@0.2.0`,无需分别安装各个 scoped 包:
|
|
47
4
|
|
|
48
5
|
```bash
|
|
49
|
-
npm install -g autopilot-agent
|
|
6
|
+
npm install -g autopilot-agent@0.2.0
|
|
50
7
|
ap --help
|
|
51
8
|
```
|
|
52
9
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
## 配置 settings.json
|
|
10
|
+
完整安装、Anthropic / Chat Completions 配置、使用和限制见 [主包手册](https://github.com/C-Clay-W/autopilot/blob/main/packages/autopilot-agent/README.md),完整 argv / slash 语法见 [CLI 参考](https://github.com/C-Clay-W/autopilot/blob/main/agent/doc/CLI-Reference.md)。开发参考随源码更新,可能先于已发布版本的行为。
|
|
56
11
|
|
|
57
|
-
|
|
12
|
+
## 结构与职责
|
|
58
13
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
14
|
+
- parser.ts 解析 argv 与交互命令,main.ts 编排入口、输出及退出。
|
|
15
|
+
- composition-root.ts 注入共享 Core Runtime 与 Node Adapters,controller.ts 管理任务、审批与恢复。
|
|
16
|
+
- tui/ 使用 React / Ink;renderer.ts 与 event-projector.ts 支持纯文本和 JSONL。
|
|
17
|
+
- 内部依赖为 Core、Adapters、Presentation,0.2.0 使用匹配的精确版本。
|
|
63
18
|
|
|
64
|
-
|
|
19
|
+
本包的 bin 提供 ap/autopilot,主入口包再转发至本包的 dist/main.js,不复制 Runtime。TTY 使用交互界面;显式 --output text/jsonl 用于脚本,JSONL 不输出 ANSI 或交互提示。
|
|
65
20
|
|
|
66
|
-
|
|
21
|
+
## 编程入口
|
|
67
22
|
|
|
68
|
-
|
|
23
|
+
包根导出 parseArgv、parseSlashAction、renderHelp、createCliCompositionRoot、createCliController、main、事件投影和 TUI 相关类型。优先把它作为终端应用使用;自行嵌入时需要处理输入输出、Trust、审批和退出清理,不在模块导入时自动启动任务。
|
|
69
24
|
|
|
70
|
-
```
|
|
71
|
-
{
|
|
72
|
-
"env": {
|
|
73
|
-
"ANTHROPIC_BASE_URL": "https://api.anthropic.com",
|
|
74
|
-
"ANTHROPIC_API_KEY": "YOUR_API_KEY"
|
|
75
|
-
},
|
|
76
|
-
"model": "YOUR_MODEL_ID"
|
|
77
|
-
}
|
|
78
|
-
```
|
|
25
|
+
```typescript
|
|
26
|
+
import { parseArgv, renderHelp } from "@autopilot-agent/cli";
|
|
79
27
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
如果服务支持 OpenAI Chat Completions 协议,使用下面的配置。替换密钥、`baseUrl` 和两处 `YOUR_MODEL_ID`;其余字段可以保留示例写法。
|
|
85
|
-
|
|
86
|
-
```json
|
|
87
|
-
{
|
|
88
|
-
"env": { "USER_SETTINGS_CUSTOM_API_KEY": "YOUR_API_KEY" },
|
|
89
|
-
"providerRoutes": {
|
|
90
|
-
"custom": {
|
|
91
|
-
"id": "custom",
|
|
92
|
-
"apiProtocol": "openai-chat-completions",
|
|
93
|
-
"baseUrl": "https://api.example.com/v1",
|
|
94
|
-
"credentialRef": { "provider": "custom", "key": "USER_SETTINGS_CUSTOM_API_KEY" },
|
|
95
|
-
"models": [{ "id": "YOUR_MODEL_ID" }]
|
|
96
|
-
}
|
|
97
|
-
},
|
|
98
|
-
"model": "custom/YOUR_MODEL_ID"
|
|
99
|
-
}
|
|
28
|
+
const parsed = parseArgv(["chat", "解释项目结构", "--output", "text"]);
|
|
29
|
+
console.log(parsed);
|
|
30
|
+
console.log(renderHelp());
|
|
100
31
|
```
|
|
101
32
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
需要配置多个服务时,可以在 `providerRoutes` 中增加其他条目。每个条目的名称、`id` 和 `credentialRef.provider` 应一致;`credentialRef.key` 对应 `env` 中的密钥名称。`model` 使用 `服务名称/模型名称` 的形式,模型必须列在对应服务的 `models` 中。协议只支持 `anthropic-messages` 和 `openai-chat-completions`。
|
|
105
|
-
|
|
106
|
-
### 常用可选参数
|
|
33
|
+
## 源码开发
|
|
107
34
|
|
|
108
|
-
|
|
109
|
-
|---|---|
|
|
110
|
-
| `model` | 使用的模型名称,或上面示例中的 `服务名称/模型名称`;建议填写服务商提供的完整模型名称 |
|
|
111
|
-
| `availableModels` | 默认连接允许使用的模型列表,例如 `["MODEL_A", "MODEL_B"]`;不能为空、不能重复,当前模型也需要在列表中 |
|
|
112
|
-
| `effortLevel` | 思考强度,可选 `"low"`、`"medium"`、`"high"`,具体效果取决于模型支持情况 |
|
|
113
|
-
| `alwaysThinkingEnabled` | 是否启用思考,填写 `true` 或 `false`,不要加引号;需要模型支持 |
|
|
114
|
-
| `maxOutputTokens` | 单次输出的 token 上限,填写 1–1,000,000 的整数;不是上下文大小 |
|
|
115
|
-
| `env.API_TIMEOUT_MS` | 默认模型连接的请求超时,单位毫秒,填写 1,000–600,000 的整数字符串,例如 `"60000"` |
|
|
116
|
-
| `visionModel` | 图片分析使用的模型,填写已配置的 Chat Completions 服务中的 `服务名称/模型名称`;`false` 关闭,省略时使用主模型 |
|
|
117
|
-
| `webSearch` | `false` 关闭模型联网搜索;启用时需另行配置搜索服务 |
|
|
118
|
-
|
|
119
|
-
`env` 中的值都需要写成字符串。填写模型名称和密钥时,避免带入首尾空格或换行。建议通过顶层 `model` 和 `effortLevel` 设置模型与思考强度;`env.ANTHROPIC_MODEL` 和 `env.CLAUDE_CODE_EFFORT_LEVEL` 会覆盖对应设置。
|
|
120
|
-
|
|
121
|
-
服务地址、密钥、模型列表等连接设置请放在上面的个人配置文件中,不要把密钥提交到项目或版本控制。项目也可以提供 `.autopilot/settings.json` 和 `.autopilot/settings.local.json`,在你信任该项目后应用允许的设置;项目设置不能替换个人配置中的连接信息。
|
|
122
|
-
|
|
123
|
-
### 修改配置
|
|
124
|
-
|
|
125
|
-
直接编辑个人 `settings.json` 可以修改完整配置。简单配置也可以通过以下命令修改模型、思考强度和可用模型列表:
|
|
35
|
+
从 monorepo 根安装依赖,依次构建 Core、Adapters、Presentation,再执行:
|
|
126
36
|
|
|
127
37
|
```bash
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
38
|
+
npm run build -w apps/cli
|
|
39
|
+
node apps/cli/dist/main.js --help
|
|
40
|
+
npm run test -w apps/cli -- test/parser.test.ts
|
|
131
41
|
```
|
|
132
42
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
## 开始使用
|
|
43
|
+
build 使用 TypeScript,输出 dist/*.js 与声明,不在 npm 包中发布源码映射和测试。当前 Node 声明为 >=20.11.0 <22;建议整仓构建使用 Node 20.20.2。
|
|
136
44
|
|
|
137
|
-
|
|
45
|
+
CLI 使用用户级 settings.json,默认工作区为当前目录,可显式指定 --workspace-root。CLI 不读取开发仓库 Web env,也不因配置中含 RAG 字段而自动启用私有知识库工具。重要项目保留版本控制,OS 沙箱、MCP 和平台限制见主包手册。
|
|
138
46
|
|
|
139
|
-
|
|
140
|
-
ap
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
首次打开项目时,按提示确认是否信任该项目。确认后,可以检查配置和模型连接:
|
|
144
|
-
|
|
145
|
-
```bash
|
|
146
|
-
ap doctor
|
|
147
|
-
ap doctor --connectivity
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
`ap doctor` 检查本地配置,`--connectivity` 还会联网检查模型服务。未信任项目时,部分检查会跳过。
|
|
151
|
-
|
|
152
|
-
`ap` 会进入交互模式,你可以直接输入需求。也可以提交一次任务:
|
|
153
|
-
|
|
154
|
-
```bash
|
|
155
|
-
ap chat "分析当前项目结构,不修改文件"
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
常用管理命令:
|
|
159
|
-
|
|
160
|
-
```bash
|
|
161
|
-
ap session list
|
|
162
|
-
ap trust status
|
|
163
|
-
ap sandbox status
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
查看各命令的具体参数与限制:`ap --help`。更新和卸载:
|
|
167
|
-
|
|
168
|
-
```bash
|
|
169
|
-
npm install -g autopilot-agent@latest
|
|
170
|
-
npm uninstall -g autopilot-agent
|
|
171
|
-
```
|
|
47
|
+
## 0.2.0 版本
|
|
172
48
|
|
|
173
|
-
|
|
49
|
+
本包随 npm 0.2.0 发布,内部依赖使用匹配的精确版本。Windows 命令、后台 Job 与 host MCP 逐次审批后以当前用户权限直接执行,审批不提供 OS 隔离;macOS 继续使用 Seatbelt。实机与进程树生命周期仍需按实际验证确认。
|
|
174
50
|
|
|
175
|
-
##
|
|
51
|
+
## 许可证
|
|
176
52
|
|
|
177
|
-
-
|
|
178
|
-
- 沙箱功能需要额外的平台支持,可通过 `ap doctor` 和 `ap sandbox status` 查看状态。MCP 工具默认在本机运行,不提供操作系统级隔离。
|
|
179
|
-
- Windows 后台任务的子进程可能无法全部停止;沙箱中的 MCP 工具也可能遇到输入无法转发的问题。需要可靠停止的长任务,建议先在测试项目中验证。
|
|
180
|
-
- macOS 尚未完成完整功能验证,Linux 暂未验证。模型服务的可用性、限额和费用以服务商为准。
|
|
181
|
-
- 当前为早期版本,处理重要项目时,请保留版本控制或备份。
|
|
53
|
+
公开源码采用 [MIT 许可证](https://github.com/C-Clay-W/autopilot/blob/main/LICENSE)。第三方依赖保留各自许可证。
|
|
@@ -8,6 +8,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
8
8
|
*/
|
|
9
9
|
import { useEffect, useState } from "react";
|
|
10
10
|
import { Box, Text } from "ink";
|
|
11
|
+
import { formatTuiDuration } from "./tui/format.js";
|
|
11
12
|
export const CLI_ACTIVITY_STALLED_AFTER_MS = 20_000;
|
|
12
13
|
export const CLI_ACTIVITY_TRANSITION_MS = 2_000;
|
|
13
14
|
/** CC v2.1.88 的默认 spinner glyph;首尾重复保证 ping-pong 转向自然。 */
|
|
@@ -124,22 +125,24 @@ export function TuiActivityLine(props) {
|
|
|
124
125
|
const [clockTime, setClockTime] = useState(props.clock.now());
|
|
125
126
|
const view = resolveCliActivityView({ activity: props.activity, status: props.status, now: clockTime, waitingForApproval: props.waitingForApproval });
|
|
126
127
|
const shouldAnimate = props.animationActive && !props.screenReader && !props.reducedMotion && view !== undefined && view.phase !== "terminal";
|
|
128
|
+
const shouldTick = shouldAnimate || (props.startedAt !== undefined && (props.status === "running" || props.status === "waiting_approval"));
|
|
127
129
|
useEffect(function subscribeActivityClock() {
|
|
128
|
-
props.clock.setActive(
|
|
129
|
-
if (!
|
|
130
|
+
props.clock.setActive(shouldTick);
|
|
131
|
+
if (!shouldTick) {
|
|
130
132
|
setClockTime(props.clock.now());
|
|
131
133
|
return;
|
|
132
134
|
}
|
|
133
135
|
setClockTime(props.clock.now());
|
|
134
136
|
return props.clock.subscribe(function updateActivityClock(time) {
|
|
135
|
-
|
|
137
|
+
// 禁动画仍按秒刷新累计时间,复用同一枚时钟。
|
|
138
|
+
setClockTime(function next(previous) { return shouldAnimate || Math.floor(previous / 1000) !== Math.floor(time / 1000) ? time : previous; });
|
|
136
139
|
});
|
|
137
|
-
}, [props.clock, shouldAnimate]);
|
|
140
|
+
}, [props.clock, shouldAnimate, shouldTick]);
|
|
138
141
|
if (!view)
|
|
139
142
|
return null;
|
|
140
143
|
if (view.phase === "terminal")
|
|
141
144
|
return null;
|
|
142
145
|
const frame = shouldAnimate ? view.frame : "·";
|
|
143
146
|
const isStalled = view.phase === "stalled";
|
|
144
|
-
return (_jsxs(Box, { flexDirection: "row", children: [_jsx(Box, { width: 3, flexShrink: 0, children: _jsx(Text, { bold: isStalled, color: props.useColor ? "ansi256(208)" : undefined, children: frame }) }),
|
|
147
|
+
return (_jsxs(Box, { flexDirection: "row", children: [_jsx(Box, { width: 3, flexShrink: 0, children: _jsx(Text, { bold: isStalled, color: props.useColor ? "ansi256(208)" : undefined, children: frame }) }), _jsxs(Text, { bold: isStalled, dimColor: props.useColor && !isStalled, children: [props.activeForm ?? view.label, props.startedAt !== undefined ? ` · ${formatTuiDuration(Math.max(0, clockTime - props.startedAt))}` : ""] })] }));
|
|
145
148
|
}
|
package/dist/composition-root.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { WEB_SEARCH_DATA_FLOW_NOTICE } from "@autopilot-agent/presentation";
|
|
8
8
|
import { createDefaultModelSamplerFactory, createRuntimeBootstrapService, createSafeBootstrapConfig, WorkspaceTrustError, getMcpServerGrantConstraint, } from "@autopilot-agent/core";
|
|
9
|
-
import { createNodeCredentialStore, createNodeCapabilityLoader, createNodeSandboxPort, createNodeSettingsLoader, createNodeSettingsWriter, ensureUserConfigDirectory, createNodeRuntimePorts, createNodeTrustPolicy, createNodeWorkspaceRegistry, createNodeWorkspaceAdapter, createNodeWorkspaceId, getNodeStateCorruptionDiagnostics, getNodeStatePaths, getNodeStateSchemaDiagnostic, initializeNodeStateRoot, resolveNodeSettingsPaths, resolveNodeStateRoot, assertNodeStateSchema, } from "@autopilot-agent/adapters";
|
|
9
|
+
import { createNodeCredentialStore, createNodeCapabilityLoader, createNodeHostExecutionSandboxPort, createNodeSandboxPort, createNodeSettingsLoader, createNodeSettingsWriter, ensureUserConfigDirectory, createNodeRuntimePorts, createNodeTrustPolicy, createNodeWorkspaceRegistry, createNodeWorkspaceAdapter, createNodeWorkspaceId, getNodeStateCorruptionDiagnostics, getNodeStatePaths, getNodeStateSchemaDiagnostic, initializeNodeStateRoot, resolveNodeSettingsPaths, resolveNodeStateRoot, assertNodeStateSchema, } from "@autopilot-agent/adapters";
|
|
10
10
|
import fs from "node:fs";
|
|
11
11
|
import path from "node:path";
|
|
12
12
|
/** CLI 专用模型行为补充:无结构化 answerer 时以普通正文完成最少必要澄清。 */
|
|
@@ -222,9 +222,19 @@ export function createCliCompositionRoot(options = {}) {
|
|
|
222
222
|
let sandboxPort;
|
|
223
223
|
let sandboxPortRoot;
|
|
224
224
|
function getSandboxPort(workspaceRoot) {
|
|
225
|
+
// Talk-Plan1022 S1:Windows 宿主执行模式——status/setup/doctor 只报告停用事实,
|
|
226
|
+
// 不加载 SRT、不触发 UAC provision;macOS 装配保持不变。
|
|
227
|
+
if (process.platform === "win32") {
|
|
228
|
+
if (!sandboxPort || sandboxPortRoot !== workspaceRoot) {
|
|
229
|
+
sandboxPort = createNodeHostExecutionSandboxPort();
|
|
230
|
+
sandboxPortRoot = workspaceRoot;
|
|
231
|
+
}
|
|
232
|
+
return sandboxPort;
|
|
233
|
+
}
|
|
225
234
|
if (!sandboxPort || sandboxPortRoot !== workspaceRoot) {
|
|
226
235
|
sandboxPort = createNodeSandboxPort({
|
|
227
236
|
workspaceRoot,
|
|
237
|
+
stateRoot,
|
|
228
238
|
tempRoot: path.join(workspaceRoot, ".autopilot", "tmp"),
|
|
229
239
|
});
|
|
230
240
|
sandboxPortRoot = workspaceRoot;
|
|
@@ -338,6 +348,7 @@ export function createCliCompositionRoot(options = {}) {
|
|
|
338
348
|
initializeNodeStateRoot(stateRoot);
|
|
339
349
|
return createNodeRuntimePorts({
|
|
340
350
|
stateRoot,
|
|
351
|
+
trustRoot: options.trustRoot,
|
|
341
352
|
workspaceRoot,
|
|
342
353
|
env,
|
|
343
354
|
userSettingsPath: resolveNodeSettingsPaths(workspaceRoot).user,
|
|
@@ -355,6 +366,7 @@ export function createCliCompositionRoot(options = {}) {
|
|
|
355
366
|
const visionRef = resolvedSettings.visionModelRef === false ? undefined : resolvedSettings.visionModelRef ?? resolvedSettings.modelRef;
|
|
356
367
|
const visionRoute = visionRef && resolvedSettings.providerRoutes[visionRef.provider];
|
|
357
368
|
return {
|
|
369
|
+
...(resolvedSettings.maxTurns !== undefined ? { maxSteps: resolvedSettings.maxTurns } : {}),
|
|
358
370
|
...(resolvedSettings.modelRef ? { modelRef: resolvedSettings.modelRef } : {}),
|
|
359
371
|
...(resolvedSettings.reasoningProfile ? { reasoningProfile: resolvedSettings.reasoningProfile } : {}),
|
|
360
372
|
...(selectedProvider?.credentialRef ? { credentialRef: selectedProvider.credentialRef } : {}),
|
package/dist/context-report.d.ts
CHANGED
|
@@ -16,5 +16,5 @@ export declare function formatContextReportLines(usage: ContextUsageView | null,
|
|
|
16
16
|
}): string[];
|
|
17
17
|
/** Plain/非 TTY 的稳定文本报告;始终跳过装饰网格。 */
|
|
18
18
|
export declare function formatPlainContextReport(usage: ContextUsageView | null, expanded: boolean): string[];
|
|
19
|
-
/**
|
|
19
|
+
/** 状态栏只显示整个窗口的整数剩余百分比;计量来源留在 /context all。 */
|
|
20
20
|
export declare function formatTuiContextStatus(usage: ContextUsageView | null): string;
|
package/dist/context-report.js
CHANGED
|
@@ -165,10 +165,9 @@ export function formatContextReportLines(usage, expanded, options) {
|
|
|
165
165
|
export function formatPlainContextReport(usage, expanded) {
|
|
166
166
|
return formatContextReportLines(usage, expanded, { grid: false, columns: Number.MAX_SAFE_INTEGER });
|
|
167
167
|
}
|
|
168
|
-
/**
|
|
168
|
+
/** 状态栏只显示整个窗口的整数剩余百分比;计量来源留在 /context all。 */
|
|
169
169
|
export function formatTuiContextStatus(usage) {
|
|
170
170
|
if (!usage)
|
|
171
171
|
return "unknown";
|
|
172
|
-
|
|
173
|
-
return `${usage.measurement === "measured" ? "" : "≈"}${percent} · ${usage.measurement}`;
|
|
172
|
+
return `${Math.round(Math.max(0, 1 - usage.usageRatio) * 100)}%`;
|
|
174
173
|
}
|
package/dist/controller.js
CHANGED
|
@@ -126,6 +126,62 @@ export function createCliController(options) {
|
|
|
126
126
|
];
|
|
127
127
|
return result("ok", 0, lines, { permissionOptions, statusView });
|
|
128
128
|
}
|
|
129
|
+
/** 合并 Session 级与 Workspace 级持久授权为当前会话可见列表;按 scope+身份去重。 */
|
|
130
|
+
async function listVisiblePermissionGrants() {
|
|
131
|
+
if (!options.runtime)
|
|
132
|
+
return [];
|
|
133
|
+
const grants = new Map();
|
|
134
|
+
const collect = function collectGrant(grant) {
|
|
135
|
+
grants.set(`${grant.scope}|${grant.toolName}|${grant.constraint}|${grant.workspaceRoot ?? ""}|${grant.sessionId ?? ""}`, grant);
|
|
136
|
+
};
|
|
137
|
+
if (sessionId)
|
|
138
|
+
for (const grant of await options.runtime.approvals.listPersistentGrants({ sessionId }))
|
|
139
|
+
collect(grant);
|
|
140
|
+
if (options.workspaceRoot)
|
|
141
|
+
for (const grant of await options.runtime.approvals.listPersistentGrants({ workspaceRoot: options.workspaceRoot }))
|
|
142
|
+
collect(grant);
|
|
143
|
+
return [...grants.values()];
|
|
144
|
+
}
|
|
145
|
+
/** 列出当前 Session/工作区可见的持久授权;只展示 Core 冻结的脱敏事实。 */
|
|
146
|
+
async function listPermissionGrants() {
|
|
147
|
+
if (!options.runtime)
|
|
148
|
+
return result("error", 1, [], "CLI_RUNTIME_NOT_ATTACHED");
|
|
149
|
+
const grants = await listVisiblePermissionGrants();
|
|
150
|
+
if (grants.length === 0)
|
|
151
|
+
return result("ok", 0, ["当前 Session/工作区没有可见的持久授权。"]);
|
|
152
|
+
const lines = grants.map(function formatGrantLine(grant, index) {
|
|
153
|
+
const scope = grant.scope === "allow_workspace" ? "工作区" : "会话";
|
|
154
|
+
const projection = grant.projection === "pending" ? " · 记住未同步(待重新批准)" : "";
|
|
155
|
+
return `${index + 1}. [${scope}] ${grant.toolName} · ${grant.constraint}${projection}`;
|
|
156
|
+
});
|
|
157
|
+
lines.push("撤销:/permissions revoke <constraint>(constraint 请按列表原样复制)");
|
|
158
|
+
return result("ok", 0, lines);
|
|
159
|
+
}
|
|
160
|
+
/** 按 toolName+constraint 精确撤销当前可见授权;Core 先删 grant 权威再删 local 投影规则。 */
|
|
161
|
+
async function revokePermissionGrant(constraint) {
|
|
162
|
+
if (!options.runtime)
|
|
163
|
+
return result("error", 1, [], "CLI_RUNTIME_NOT_ATTACHED");
|
|
164
|
+
if (!sessionId || !options.workspaceRoot)
|
|
165
|
+
return result("error", 2, [], "CLI_APPROVAL_NOT_AVAILABLE");
|
|
166
|
+
const grants = await listVisiblePermissionGrants();
|
|
167
|
+
const targets = grants.filter(function matchConstraint(grant) { return grant.constraint === constraint; });
|
|
168
|
+
if (targets.length === 0)
|
|
169
|
+
return result("error", 2, [], "CLI_PERMISSION_GRANT_NOT_FOUND");
|
|
170
|
+
const lines = [];
|
|
171
|
+
for (const grant of targets) {
|
|
172
|
+
const outcome = await options.runtime.approvals.revokePersistentGrant({
|
|
173
|
+
workspaceRoot: options.workspaceRoot,
|
|
174
|
+
sessionId,
|
|
175
|
+
toolName: grant.toolName,
|
|
176
|
+
constraint,
|
|
177
|
+
});
|
|
178
|
+
if (!outcome.deleted)
|
|
179
|
+
return result("error", 1, [], "CLI_PERMISSION_GRANT_REVOKE_FAILED");
|
|
180
|
+
lines.push(`已撤销 [${grant.scope === "allow_workspace" ? "工作区" : "会话"}] ${grant.toolName} · ${grant.constraint}${outcome.ruleRemoved ? ",并已删除工作区记住规则" : ""}`);
|
|
181
|
+
}
|
|
182
|
+
lines.push("后续同范围操作将重新请求授权。");
|
|
183
|
+
return result("ok", 0, lines);
|
|
184
|
+
}
|
|
129
185
|
/** 读-合并-写入 Session 默认权限,只改变 permissionMode 并保留其他配置字段。 */
|
|
130
186
|
async function setPermissionMode(mode) {
|
|
131
187
|
if (!sessionId)
|
|
@@ -631,6 +687,10 @@ export function createCliController(options) {
|
|
|
631
687
|
return openPermissions();
|
|
632
688
|
if (action.type === "set_permission_mode")
|
|
633
689
|
return setPermissionMode(action.mode);
|
|
690
|
+
if (action.type === "list_permission_grants")
|
|
691
|
+
return listPermissionGrants();
|
|
692
|
+
if (action.type === "revoke_permission_grant")
|
|
693
|
+
return revokePermissionGrant(action.constraint);
|
|
634
694
|
if (action.type === "open_model_picker")
|
|
635
695
|
return openModelPicker();
|
|
636
696
|
if (action.type === "set_model")
|
package/dist/design-tokens.d.ts
CHANGED
|
@@ -20,6 +20,10 @@ export declare const TUI_CHIP_TEXT_COLOR = "ansi256(16)";
|
|
|
20
20
|
export declare const TUI_TOOL_SUCCESS_COLOR = "ansi256(46)";
|
|
21
21
|
/** 工具失败文字的辅助红;状态永远带文字标签,不靠颜色传达。 */
|
|
22
22
|
export declare const TUI_TOOL_ERROR_COLOR = "ansi256(196)";
|
|
23
|
+
/** 失败徽标的红色背景;与错误文字共用语义红,NO_COLOR 时仍显示状态文字。 */
|
|
24
|
+
export declare const TUI_TOOL_ERROR_BG_COLOR = "ansi256(196)";
|
|
25
|
+
/** 红底失败徽标使用深色粗体文字,便于和错误背景形成明确边界。 */
|
|
26
|
+
export declare const TUI_TOOL_ERROR_TEXT_COLOR = "ansi256(16)";
|
|
23
27
|
/** Skill 已启用开关的语义色。 */
|
|
24
28
|
export declare const TUI_SKILL_ON_COLOR = "ansi256(46)";
|
|
25
29
|
/** Skill 未启用开关的语义色。 */
|
package/dist/design-tokens.js
CHANGED
|
@@ -20,6 +20,10 @@ export const TUI_CHIP_TEXT_COLOR = "ansi256(16)";
|
|
|
20
20
|
export const TUI_TOOL_SUCCESS_COLOR = "ansi256(46)";
|
|
21
21
|
/** 工具失败文字的辅助红;状态永远带文字标签,不靠颜色传达。 */
|
|
22
22
|
export const TUI_TOOL_ERROR_COLOR = "ansi256(196)";
|
|
23
|
+
/** 失败徽标的红色背景;与错误文字共用语义红,NO_COLOR 时仍显示状态文字。 */
|
|
24
|
+
export const TUI_TOOL_ERROR_BG_COLOR = TUI_TOOL_ERROR_COLOR;
|
|
25
|
+
/** 红底失败徽标使用深色粗体文字,便于和错误背景形成明确边界。 */
|
|
26
|
+
export const TUI_TOOL_ERROR_TEXT_COLOR = TUI_CHIP_TEXT_COLOR;
|
|
23
27
|
/** Skill 已启用开关的语义色。 */
|
|
24
28
|
export const TUI_SKILL_ON_COLOR = "ansi256(46)";
|
|
25
29
|
/** Skill 未启用开关的语义色。 */
|
package/dist/event-projector.js
CHANGED
|
@@ -90,7 +90,7 @@ function cloneProjection(previous, envelope) {
|
|
|
90
90
|
...previous,
|
|
91
91
|
turnId: envelope.turnId,
|
|
92
92
|
lastSeq: Math.max(previous.lastSeq ?? 0, envelope.seq),
|
|
93
|
-
activeSkills: previous.activeSkills
|
|
93
|
+
activeSkills: previous.activeSkills,
|
|
94
94
|
events: [...previous.events],
|
|
95
95
|
seenKeys,
|
|
96
96
|
};
|
|
@@ -113,7 +113,7 @@ function applyCheckpoint(projection, checkpoint, seq, turnId) {
|
|
|
113
113
|
if (sameSkills(projection.activeSkills, activeSkills))
|
|
114
114
|
return;
|
|
115
115
|
projection.activeSkills = activeSkills;
|
|
116
|
-
projection
|
|
116
|
+
appendEvent(projection, { type: "active_skills", seq, turnId, skills: activeSkills });
|
|
117
117
|
}
|
|
118
118
|
/** 将安全事件追加到投影事件列表。 */
|
|
119
119
|
function appendEvent(projection, event) {
|
|
@@ -187,6 +187,7 @@ function projectEvent(envelope, projection) {
|
|
|
187
187
|
toolName: sanitizeText(event.toolName, 160),
|
|
188
188
|
reason,
|
|
189
189
|
risk: display?.risk,
|
|
190
|
+
constraint: event.result.approval.constraint,
|
|
190
191
|
allowedDecisions,
|
|
191
192
|
display,
|
|
192
193
|
};
|
|
@@ -198,6 +199,7 @@ function projectEvent(envelope, projection) {
|
|
|
198
199
|
toolName: sanitizeText(event.toolName, 160),
|
|
199
200
|
reason,
|
|
200
201
|
risk: display?.risk,
|
|
202
|
+
constraint: event.result.approval.constraint,
|
|
201
203
|
allowedDecisions,
|
|
202
204
|
display,
|
|
203
205
|
};
|
package/dist/parser.js
CHANGED
|
@@ -15,7 +15,7 @@ export const CLI_SLASH_COMMANDS = [
|
|
|
15
15
|
{ name: "/model", usage: "/model", description: "查看或设置下一个 Turn 的模型" },
|
|
16
16
|
{ name: "/effort", usage: "/effort", description: "查看或设置下一个 Turn 的推理强度" },
|
|
17
17
|
{ name: "/skill", usage: "/skill [name]", description: "打开 Skill picker 或选择 Skill" },
|
|
18
|
-
{ name: "/permissions", usage: "/permissions [mode]", description: "
|
|
18
|
+
{ name: "/permissions", usage: "/permissions [mode | grants | revoke <constraint>]", description: "查看/设置权限模式,或查看与撤销持久授权" },
|
|
19
19
|
{ name: "/approve", usage: "/approve <decision>", description: "提交当前工具审批决定" },
|
|
20
20
|
{ name: "/undo", usage: "/undo [confirm]", description: "预览并确认撤销当前会话最近一轮文件修改" },
|
|
21
21
|
];
|
|
@@ -54,7 +54,7 @@ export function renderHelp() {
|
|
|
54
54
|
" -h, --help show this help",
|
|
55
55
|
"",
|
|
56
56
|
"Permissions: ask requires confirmation; auto_approve only auto-runs safe writes and workspace commands after Trust; full_access still enforces path, schema, and destructive-command guards.",
|
|
57
|
-
"Limits: AGENT_MAX_STEPS
|
|
57
|
+
"Limits: settings.json maxTurns, AGENT_MAX_STEPS and AGENT_MAX_DURATION_MS are optional (unset means no step/time cap); maxTurns maps to per-run steps without a fixed platform cap; AGENT_MAX_TOOL_RETRIES defaults to 5 and is capped at 10.",
|
|
58
58
|
"Exit codes: 0 success/normal exit, 1 runtime error, 2 usage error, 130 SIGINT, 143 SIGTERM.",
|
|
59
59
|
"Interactive uses Ink on a TTY and Plain fallback otherwise; --output jsonl never emits ANSI or prompts.",
|
|
60
60
|
].join("\n");
|
|
@@ -359,12 +359,21 @@ function isApprovalDecision(value) {
|
|
|
359
359
|
function invalidSlashArguments(name) {
|
|
360
360
|
return { kind: "error", message: `/${name} 不接受额外参数` };
|
|
361
361
|
}
|
|
362
|
-
/**
|
|
362
|
+
/** 解析权限模式查询、Session 默认权限更新与持久授权查看/撤销(Talk-Plan1013 Stage 4)。 */
|
|
363
363
|
function parsePermissionsAction(parts) {
|
|
364
364
|
if (parts.length === 1)
|
|
365
365
|
return { kind: "action", action: { type: "open_permissions" } };
|
|
366
|
+
if (parts.length === 2 && parts[1] === "grants")
|
|
367
|
+
return { kind: "action", action: { type: "list_permission_grants" } };
|
|
368
|
+
if (parts[1] === "revoke") {
|
|
369
|
+
if (parts.length === 2)
|
|
370
|
+
return { kind: "error", message: "/permissions revoke 需要从 /permissions grants 列表中复制的完整 constraint" };
|
|
371
|
+
// constraint 由 ext-file:/path:/program: 前缀与路径组成,路径可含空格,按原样拼接且不再拆分。
|
|
372
|
+
const constraint = parts.slice(2).join(" ").trim();
|
|
373
|
+
return { kind: "action", action: { type: "revoke_permission_grant", constraint } };
|
|
374
|
+
}
|
|
366
375
|
if (parts.length !== 2 || !isPermissionMode(parts[1])) {
|
|
367
|
-
return { kind: "error", message: "/permissions 需要 ask|auto_approve|full_access" };
|
|
376
|
+
return { kind: "error", message: "/permissions 需要 ask|auto_approve|full_access 或 grants | revoke <constraint>" };
|
|
368
377
|
}
|
|
369
378
|
return { kind: "action", action: { type: "set_permission_mode", mode: parts[1] } };
|
|
370
379
|
}
|
package/dist/renderer.js
CHANGED
|
@@ -5,6 +5,10 @@
|
|
|
5
5
|
* Store、checkpoint 或 Web SSE DTO;因此 text 与 JSONL 的语义来源一致。
|
|
6
6
|
*/
|
|
7
7
|
import { formatAgentTermination } from "./termination-format.js";
|
|
8
|
+
/** 判断审批约束是否为无沙箱直接执行;与 Web 审批卡同一字符串判定,休眠底座不签发,历史记录仍可能携带。 */
|
|
9
|
+
function isNoSandboxApproval(constraint) {
|
|
10
|
+
return constraint === "no-sandbox-exec:v1";
|
|
11
|
+
}
|
|
8
12
|
/** 将安全事件渲染为不带 ANSI 的 Plain 文本行。 */
|
|
9
13
|
function renderTextEvent(event) {
|
|
10
14
|
switch (event.type) {
|
|
@@ -15,8 +19,18 @@ function renderTextEvent(event) {
|
|
|
15
19
|
case "answer_reset": return "answer reset";
|
|
16
20
|
case "tool_started": return `tool ${event.toolName}: ${event.summary}`;
|
|
17
21
|
case "tool_progress": return `tool ${event.toolName}: ${event.tail}`;
|
|
18
|
-
case "tool_result":
|
|
19
|
-
|
|
22
|
+
case "tool_result": {
|
|
23
|
+
const isolation = event.display?.executionMode === "unisolated" ? " · 未隔离:宿主直接执行" : "";
|
|
24
|
+
const diagnostics = event.display?.diagnostics?.length ? ` · 诊断:${event.display.diagnostics.join(";")}` : "";
|
|
25
|
+
return `tool ${event.toolName} [${event.status}]: ${event.summary}${event.errorCode ? ` (${event.errorCode})` : ""}${diagnostics}${isolation}${event.diff ? `\n${event.diff}` : ""}`;
|
|
26
|
+
}
|
|
27
|
+
case "approval_required": {
|
|
28
|
+
const cwd = event.display?.cwd ? ` · 工作目录:${event.display.cwd}` : "";
|
|
29
|
+
const noSandbox = isNoSandboxApproval(event.constraint) ? " · 无沙箱直接执行,仅本次有效" : "";
|
|
30
|
+
// Talk-Plan1022 S3:宿主执行审批卡按"将采用"措辞说明无隔离事实,待审批不显示成已执行。
|
|
31
|
+
const hostExecution = event.display?.executionMode === "unisolated" ? " · 将在当前用户权限下运行(未启用沙箱隔离)" : "";
|
|
32
|
+
return `approval ${event.approvalId}: ${event.toolName} ${event.reason}${cwd}${noSandbox}${hostExecution}`;
|
|
33
|
+
}
|
|
20
34
|
case "input_queued": return `input queued: ${event.inputId} (${event.delivery})`;
|
|
21
35
|
case "todo_updated": {
|
|
22
36
|
const total = event.todos.length;
|
package/dist/tui/app.js
CHANGED
|
@@ -19,6 +19,7 @@ import { TuiInputArea } from "./input-area.js";
|
|
|
19
19
|
import { TuiInfoLines, TuiStatusLine } from "./status-line.js";
|
|
20
20
|
import { TuiJobs } from "./jobs.js";
|
|
21
21
|
import { TuiLiveTurn } from "./timeline/turn.js";
|
|
22
|
+
import { getTuiTurnTodo } from "./timeline/turn-items.js";
|
|
22
23
|
import { MemoizedTuiTranscriptItem, TuiPendingInputItem, TuiPromptLine } from "./transcript.js";
|
|
23
24
|
import { getTuiSelectedText } from "./viewport/selection.js";
|
|
24
25
|
import { createTuiViewportSourceCache } from "./viewport/sources.js";
|
|
@@ -81,10 +82,11 @@ export function CliTuiApp(props) {
|
|
|
81
82
|
.slice(-4)
|
|
82
83
|
.map(function getNoticeMessage(item) { return item.message; });
|
|
83
84
|
const approvalHeight = isViewportMode && snapshot.pendingApproval ? createTuiApprovalOptions(snapshot.pendingApproval).length + 6 : 0;
|
|
84
|
-
const fixedHeight = inputLayout.promptHeight + inputLayout.pickerHeight + approvalHeight + infoMessages.length + 1 + (statusView ? 5 : 2);
|
|
85
|
-
const viewportHeight = Math.max(1, rows - fixedHeight);
|
|
86
85
|
// Todo 展开态最多占 10 行;矮终端为输入框、状态栏和活动文案至少保留 6 行。
|
|
87
86
|
const todoRowLimit = Math.max(2, Math.min(10, rows - 6));
|
|
87
|
+
const activeTodoForm = getTuiTurnTodo(snapshot.liveEvents, snapshot.liveTurnId ?? "")?.todos.find(function active(todo) { return todo.status === "in_progress"; })?.activeForm;
|
|
88
|
+
const fixedHeight = inputLayout.promptHeight + inputLayout.pickerHeight + approvalHeight + infoMessages.length + 1 + (statusView ? 5 : 2);
|
|
89
|
+
const viewportHeight = Math.max(1, rows - fixedHeight);
|
|
88
90
|
const viewportSourceCacheRef = useRef(undefined);
|
|
89
91
|
if (!viewportSourceCacheRef.current)
|
|
90
92
|
viewportSourceCacheRef.current = createTuiViewportSourceCache();
|
|
@@ -94,9 +96,9 @@ export function CliTuiApp(props) {
|
|
|
94
96
|
const viewportContentWidth = Math.max(1, columns - 1);
|
|
95
97
|
const viewportSources = useMemo(function getCachedViewportSources() {
|
|
96
98
|
return isViewportMode
|
|
97
|
-
? viewportSourceCacheRef.current.getSources(snapshot, statusView, pickers.approvalPickerIndex, viewportContentWidth, todoExpanded, props.useColor)
|
|
99
|
+
? viewportSourceCacheRef.current.getSources(snapshot, statusView, pickers.approvalPickerIndex, viewportContentWidth, todoExpanded, props.useColor, todoRowLimit)
|
|
98
100
|
: EMPTY_VIEWPORT_SOURCES;
|
|
99
|
-
}, [isViewportMode, pickers.approvalPickerIndex, snapshot, statusView, viewportContentWidth, todoExpanded, props.useColor]);
|
|
101
|
+
}, [isViewportMode, pickers.approvalPickerIndex, snapshot, statusView, viewportContentWidth, todoExpanded, props.useColor, todoRowLimit]);
|
|
100
102
|
const viewportLines = useMemo(function getCachedViewportLines() {
|
|
101
103
|
return isViewportMode
|
|
102
104
|
? viewportLineCacheRef.current.getLines(viewportSources, viewportContentWidth)
|
|
@@ -120,6 +122,7 @@ export function CliTuiApp(props) {
|
|
|
120
122
|
return;
|
|
121
123
|
const isJobAction = action.type === "list_jobs" || action.type === "show_job" || action.type === "read_job_output" || action.type === "stop_job";
|
|
122
124
|
const jobGeneration = isJobAction ? ++jobRequestGeneration.current : undefined;
|
|
125
|
+
const inputPosition = prompt && allowWhileRunning ? props.store.captureInputPosition() : undefined;
|
|
123
126
|
if (prompt) {
|
|
124
127
|
lastSubmittedPromptRef.current = prompt.trim();
|
|
125
128
|
props.store.recordPrompt(prompt, !allowWhileRunning);
|
|
@@ -177,9 +180,9 @@ export function CliTuiApp(props) {
|
|
|
177
180
|
}
|
|
178
181
|
if (result.contextView)
|
|
179
182
|
setContextView(result.contextView);
|
|
180
|
-
await refreshStatusView();
|
|
181
183
|
if (prompt && result.submittedInput)
|
|
182
|
-
props.store.addPendingPrompt(prompt, result.submittedInput);
|
|
184
|
+
props.store.addPendingPrompt(prompt, result.submittedInput, inputPosition);
|
|
185
|
+
await refreshStatusView();
|
|
183
186
|
if (result.skillOptions) {
|
|
184
187
|
pickers.setSkillPickerSkills(result.skillOptions);
|
|
185
188
|
if (!preserveSkillPickerQuery)
|
|
@@ -405,6 +408,6 @@ export function CliTuiApp(props) {
|
|
|
405
408
|
}
|
|
406
409
|
return _jsx(TuiBrandHeader, { statusView: statusView, columns: columns, useColor: props.useColor, screenReader: props.screenReader, reducedMotion: props.reducedMotion ?? false, animationActive: false }, item.key);
|
|
407
410
|
}), activePrompt ? _jsx(TuiPromptLine, { content: activePrompt.content, columns: columns, useColor: props.useColor, keyValue: activePrompt.key }) : null, _jsx(TuiLiveTurn, { turnId: isLiveTurnTerminal ? undefined : snapshot.liveTurnId, events: snapshot.liveEvents, presentation: snapshot.livePresentation, pendingApproval: snapshot.pendingApproval, approvalSelectedIndex: pickers.approvalPickerIndex, status: snapshot.status, metrics: snapshot.liveMetrics, useColor: props.useColor, screenReader: props.screenReader, todoExpanded: todoExpanded, todoRowLimit: todoRowLimit, maximumWidth: Math.max(1, columns - 2) }), snapshot.pendingInputs.map(function renderPendingInput(item) {
|
|
408
|
-
return _jsx(TuiPendingInputItem, { item: item, useColor: props.useColor }, item.key);
|
|
409
|
-
})] }), _jsx(TuiActivityLine, { activity: snapshot.activity, status: snapshot.status, waitingForApproval: snapshot.pendingApproval !== undefined, useColor: props.useColor, screenReader: props.screenReader, reducedMotion: props.reducedMotion ?? false, animationActive: animationActive, clock: animationClock }), _jsx(TuiInfoLines, { messages: infoMessages, useColor: props.useColor }), _jsx(TuiInputArea, { store: props.store, columns: columns, busy: busy, keepOpenAfterCancel: keepOpenAfterCancel, lastSubmittedPromptRef: lastSubmittedPromptRef, rawInputSequenceRef: rawInputSequenceRef, dispatchAction: dispatchAction, onEof: props.onEof, onRequestInterrupt: props.onRequestInterrupt, onRequestCancel: props.onRequestCancel, isRawModeSupported: isRawModeSupported, isInputActive: jobView === undefined && contextView === undefined, showInput: jobView === undefined && contextView === undefined, useColor: props.useColor, screenReader: props.screenReader, pickers: pickers, derivedRef: derivedRef, fileMentionIndex: fileMentionIndex, onLayoutChange: handleInputLayoutChange }), _jsx(TuiStatusLine, { snapshot: snapshot, statusView: statusView, useColor: props.useColor, screenReader: props.screenReader, selectionCharacters: selectedText.length })] }));
|
|
411
|
+
return item.delivery === "queue" ? _jsx(TuiPendingInputItem, { item: item, useColor: props.useColor }, item.key) : null;
|
|
412
|
+
})] }), _jsx(TuiActivityLine, { activity: snapshot.activity, status: snapshot.status, waitingForApproval: snapshot.pendingApproval !== undefined, useColor: props.useColor, screenReader: props.screenReader, reducedMotion: props.reducedMotion ?? false, animationActive: animationActive, clock: animationClock, startedAt: snapshot.liveMetrics?.startedAt, activeForm: activeTodoForm }), _jsx(TuiInfoLines, { messages: infoMessages, useColor: props.useColor }), _jsx(TuiInputArea, { store: props.store, columns: columns, busy: busy, keepOpenAfterCancel: keepOpenAfterCancel, lastSubmittedPromptRef: lastSubmittedPromptRef, rawInputSequenceRef: rawInputSequenceRef, dispatchAction: dispatchAction, onEof: props.onEof, onRequestInterrupt: props.onRequestInterrupt, onRequestCancel: props.onRequestCancel, isRawModeSupported: isRawModeSupported, isInputActive: jobView === undefined && contextView === undefined, showInput: jobView === undefined && contextView === undefined, useColor: props.useColor, screenReader: props.screenReader, pickers: pickers, derivedRef: derivedRef, fileMentionIndex: fileMentionIndex, onLayoutChange: handleInputLayoutChange }), _jsx(TuiStatusLine, { snapshot: snapshot, statusView: statusView, useColor: props.useColor, screenReader: props.screenReader, selectionCharacters: selectedText.length })] }));
|
|
410
413
|
}
|
package/dist/tui/approval.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ export interface CliTuiApprovalOption {
|
|
|
8
8
|
}>["decision"];
|
|
9
9
|
label: string;
|
|
10
10
|
}
|
|
11
|
-
/**
|
|
11
|
+
/** 根据待审批工具收窄菜单;旧记录缺少冻结范围时保持最保守的单次/拒绝。 */
|
|
12
12
|
export declare function createTuiApprovalOptions(pendingApproval: NonNullable<CliProjection["pendingApproval"]>): CliTuiApprovalOption[];
|
|
13
13
|
/** 以 CC 风格上下选择、回车确认渲染当前审批菜单。 */
|
|
14
14
|
export declare function TuiApprovalPrompt(props: {
|