@tt-a1i/openpi 0.3.1 → 0.4.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 (60) hide show
  1. package/README.md +87 -24
  2. package/SETUP.md +3 -3
  3. package/extensions/ask-user/index.ts +30 -14
  4. package/extensions/background-terminals/src/prompt.ts +1 -1
  5. package/extensions/background-terminals/src/ui/ps.ts +132 -129
  6. package/extensions/capabilities/index.ts +30 -42
  7. package/extensions/capabilities/src/ui.ts +93 -0
  8. package/extensions/file-mutation-display/index.ts +34 -76
  9. package/extensions/file-mutation-display/render.ts +387 -88
  10. package/extensions/file-search/index.ts +8 -7
  11. package/extensions/file-search/src/binaries.ts +18 -18
  12. package/extensions/git-info/src/changed-files-view.ts +47 -14
  13. package/extensions/git-read/index.ts +330 -0
  14. package/extensions/git-read/src/args.ts +171 -0
  15. package/extensions/git-read/src/process.ts +81 -0
  16. package/extensions/git-read/src/prompt.ts +56 -0
  17. package/extensions/sessions/index.ts +70 -55
  18. package/extensions/setup/index.ts +6 -6
  19. package/extensions/shared/activity-status.ts +6 -5
  20. package/extensions/shared/below-editor-navigation.ts +26 -0
  21. package/extensions/shared/capability-intent.ts +53 -0
  22. package/extensions/shared/child-session.ts +7 -1
  23. package/extensions/shared/result-budget.ts +134 -0
  24. package/extensions/shared/screen-chrome.ts +133 -0
  25. package/extensions/shared/setup-config.ts +24 -5
  26. package/extensions/shared/spinner.ts +28 -0
  27. package/extensions/shared/text-projection.ts +56 -0
  28. package/extensions/shared/tool-surface.ts +13 -6
  29. package/extensions/subagents/index.ts +204 -140
  30. package/extensions/subagents/navigation.ts +52 -23
  31. package/extensions/subagents/src/agent-types.ts +37 -15
  32. package/extensions/subagents/src/backends/stub.ts +7 -0
  33. package/extensions/subagents/src/id-sequence.ts +84 -0
  34. package/extensions/subagents/src/manager.ts +620 -537
  35. package/extensions/subagents/src/prompt.ts +153 -38
  36. package/extensions/subagents/src/result-artifact.ts +142 -0
  37. package/extensions/subagents/src/runtime.ts +8 -5
  38. package/extensions/subagents/src/ui/takeover.ts +84 -109
  39. package/extensions/subagents/src/ui/transcript.ts +76 -42
  40. package/extensions/subagents/src/ui/wait-result.ts +1 -1
  41. package/extensions/tasks/ui.ts +79 -62
  42. package/extensions/ui-customization/footer.ts +7 -4
  43. package/extensions/user-input-fold/index.ts +185 -0
  44. package/extensions/workflows/artifacts.ts +35 -0
  45. package/extensions/workflows/controller.ts +14 -2
  46. package/extensions/workflows/coordinator.ts +64 -0
  47. package/extensions/workflows/dashboard.ts +353 -173
  48. package/extensions/workflows/handoff.ts +62 -20
  49. package/extensions/workflows/index.ts +647 -387
  50. package/extensions/workflows/model.ts +57 -15
  51. package/extensions/workflows/navigation.ts +33 -14
  52. package/extensions/workflows/prompt.ts +104 -8
  53. package/extensions/workflows/replay-safety.ts +16 -6
  54. package/extensions/workflows/result-delivery.ts +189 -0
  55. package/extensions/workflows/sandbox-child.cjs +11 -0
  56. package/package.json +1 -1
  57. package/skills/subagents/SKILL.md +2 -2
  58. package/skills/workflows/REFERENCE.md +7 -4
  59. package/skills/workflows/SKILL.md +53 -10
  60. package/extensions/subagents/src/format.ts +0 -48
package/README.md CHANGED
@@ -69,12 +69,18 @@ pi install npm:@tt-a1i/openpi
69
69
  重启 Pi,或在当前 Session 运行 `/reload`。然后直接描述真实任务:
70
70
 
71
71
  ```text
72
- 启动前端 dev server;并行检查 API 主链路和测试覆盖;
72
+ 在后台启动前端 dev server;用子代理并行检查 API 主链路和测试覆盖;
73
73
  结果回来后汇总风险,主会话不要原地等待。
74
74
  ```
75
75
 
76
76
  OpenPI 会把长期进程放到后台,把独立任务交给隔离 Context 的 Pi Subagent,把多阶段依赖组织成 Workflow。状态会持续显示;完整运行可从 `/ps`、`/subagents` 和 `/workflows` 检查或终止。
77
77
 
78
+ > [!TIP]
79
+ > Capability discovery 默认 `explicit`:明确说出能力意图才会加载对应组。英文 `subagent` 与 `workflow` 是保留授权词,单独输入也会加载对应能力。
80
+ > 例如 `subagent, workflow` → 同时加载两组;「在后台运行 dev server」→ 后台终端;「用/使用子代理检查」→ Subagent;「用工作流编排」→ Workflow;「用 fd/rg 搜索」或「用 git diff 比较分支」→ 搜索与只读 Git 工具。
81
+ > 关键是把意图说清楚(说「用子代理」「后台运行」这类带动作的短语),不需要记住任何工具名。
82
+ > 在交互输入框中,保留词 `Subagent` / `Workflow`,以及已被识别的中文能力请求,会使用 Claude Code 风格的薰衣草紫显示;浅色终端自动使用更深的紫色以维持可读性。变色表示提交后会加载对应能力。因为英文名称本身就是授权词,讨论中写出它们也会开闸;条件句和否定句仍保持普通显示,Suggestion 幽灵文字也要在用户接受进输入框后才参与识别。
83
+
78
84
  > [!IMPORTANT]
79
85
  > 默认安装是安静的:不改主题、不绑定 Provider 或模型、不开启下一步预测,也不执行 post-edit 命令。Capability discovery 默认 `explicit`;只有用户通过 `/openpi-setup` 选择 `adaptive` 后,模型才会常驻看到一个小型发现网关并可自主加载额外能力。
80
86
 
@@ -112,7 +118,7 @@ OpenPI 把成熟 Coding Agent 的工作习惯做成 Pi-native 能力,但不复
112
118
  | 连续性 | Tasks、Goal、Plan Mode、Context Pivot、Session Browser、Session-scoped Cron |
113
119
  | 自定义 Agent | `explorer` / `implementer` / `reviewer` / `advisor`,支持全局与项目角色文件、独立模型与 effort |
114
120
  | 终端工作台 | 自定义 Footer 与任务栏、运行状态、紧凑 Tool Result、Next-action Suggestion、Git / PR 信号 |
115
- | 快捷工作流 | `/btw` 旁路提问(TUI)、`/lg` 浏览 Diff(TUI)、`/pr` 查 PR、`/copy-all`、`fd`、`rg` |
121
+ | 快捷工作流 | `/btw` 旁路提问(TUI)、`/lg` 浏览 Diff(TUI)、`/pr` 查 PR、`/copy-all`、`fd`、`rg`、只读 Git 工具 |
116
122
  | 人类决策 | `ask_user` 草稿与最终复核、parent-only `human_handoff`、Plan Ready 实施门禁 |
117
123
  | 跨 Session | 可选 parent-only `pi-intercom`;父子通信仍走 Subagent / Workflow 原生通道 |
118
124
  | 统一配置 | `/openpi-setup` 管理 OpenPI 自有模型、并发、Footer、输出密度与 Post-edit 偏好 |
@@ -180,7 +186,7 @@ subagent_spawn({
180
186
 
181
187
  每个 Subagent 都是新的进程内 Pi SDK Session:
182
188
 
183
- - 默认继承父会话的 Provider、模型与 Thinking Level
189
+ - 默认继承父会话的 Provider 与模型;用户可明确指定 Thinking Level,否则模型根据角色建议、任务难度与目标模型实际支持的档位选择;
184
190
  - 继承普通 child-safe 工具、Skills、项目说明与 Trust 决策;
185
191
  - 最多 4 个模型发起的 Subagent 并发运行,结束后自动回传;
186
192
  - 可 `check`、`wait`、`cancel`,也可用 `subagent_send` 继续同一子会话;
@@ -188,12 +194,14 @@ subagent_spawn({
188
194
 
189
195
  内置角色由 Harness 强制工具边界,不靠 Prompt 自律:
190
196
 
191
- | `agent_type` | 适合 | 默认 effort | 强制能力 |
192
- | ------------- | ---------------- | ----------- | ----------------------------- |
193
- | `explorer` | 代码追踪与探索 | high | 只读发现工具 |
194
- | `implementer` | 聚焦实现 | high | read / bash / edit / write 等 |
195
- | `reviewer` | 正确性与回归审查 | medium | 只读发现工具 |
196
- | `advisor` | 深度技术建议 | xhigh | 只读发现工具 |
197
+ | `agent_type` | 适合 | 相对 effort 建议 | 强制能力 |
198
+ | ------------- | ---------------- | ------------------- | ----------------------------- |
199
+ | `explorer` | 代码追踪与探索 | 中等,难题可提高 | 只读发现工具 |
200
+ | `implementer` | 聚焦实现 | 中高,按范围与风险调整 | read / bash / edit / write 等 |
201
+ | `reviewer` | 正确性与回归审查 | 较高 | 只读发现工具 |
202
+ | `advisor` | 深度技术建议 | 较高 | 只读发现工具 |
203
+
204
+ 上述只是模型的相对选择提示,不会为内置角色写死具体档位。用户明确指定的 `reasoning_effort` 始终优先;否则模型结合任务难度,从目标模型实际支持的档位中选择。
197
205
 
198
206
  角色可由全局 `~/.pi/agent/agents/*.md` 或受信任项目 `.pi/agents/*.md` 覆盖。模型优先级是:显式调用 > Agent Type 文件 > `/openpi-setup` 角色模型 > 父模型继承。更高优先级定义损坏时会阻断 fallback,而不是悄悄退回更宽松的能力。
199
207
 
@@ -253,7 +261,7 @@ return agent("Synthesize the verified findings", {
253
261
  | ------------ | -------------------------------------------------------------------------- |
254
262
  | `phase()` | 标记当前阶段 |
255
263
  | `log()` | 向实时界面与最终报告追加一行进度 |
256
- | `usage()` | 读取累计 Token、缓存与成本的单调 lower bound;不是预算器 |
264
+ | `usage()` | 读取累计 Token、缓存、成本及本轮并发/调用余量;Token lower bound,不是预算器 |
257
265
  | `agent()` | 启动 Pi Agent;支持 role、schema、acceptance、inputs、operator 与 worktree |
258
266
  | `pipeline()` | 每个 item 完成上阶段后立即进入下一阶段;多阶段 fan-out 的默认选择 |
259
267
  | `parallel()` | 并发 barrier;只在下一阶段确实需要全部结果时使用 |
@@ -323,20 +331,22 @@ Next-action Suggestion 是可选的:完整主 Agent Run 结束后,在空编
323
331
 
324
332
  ## 终端体验
325
333
 
326
- 默认 Powerline Footer 把真实运行状态压进一行:
334
+ 默认 Footer 把真实运行状态压进一行,指标自带小图标(无需 Nerd Font):
327
335
 
328
336
  ```text
329
- cwd model thinking context cache cost throughput git PR
337
+ model contextgit PR  cwd
330
338
  ```
331
339
 
332
- - 支持 `powerline`、`powerline-mono`、`compact`,也支持自定义多行布局;
340
+ Footer 使用一套 Codicon 线性图标:`` 模型、`` context、`` 目录;`⎇` 表示分支。`thinking`、`cache`、`cost`、`throughput` 也是可选指标,可通过 `/openpi-setup` 加入自定义布局。未安装包含 Codicons 的 Nerd Font 时,图标可能显示为空框,但后面的文字指标仍然完整可读。
341
+
342
+ - 默认把高频的模型与 context 放在最左侧,把项目定位信息归到右侧,并以当前目录作为最右锚点;支持 `powerline`、`powerline-mono`、`compact`,也支持自定义多行布局;
333
343
  - 终端变窄时按优先级隐藏次要指标,不机械截断尾部;
334
344
  - Subagent 与 Workflow 活动时自动出现,空闲时不占空间;
335
- - Bash、Write/Edit 与 Subagent 结果可独立选择 `full` 或 `compact`;Subagent compact 模式只显示状态摘要,不暴露原始子 Agent 正文;
336
- - 折叠内容用 Pi 的 `app.tools.expand` 快捷键临时展开,默认 `Ctrl+O`;
345
+ - Bash、Write/Edit 与 Subagent 结果可独立选择 `full` 或 `compact`;普通 `read`、`grep`、`find`、`ls` 以及 compact Bash/Write/Edit 默认显示一行语义活动摘要,包含目标、状态与关键规模;Nerd Font 可为读取、终端、编辑、搜索和目录动作显示 Codex 风格线框图标,未安装时动词与全部信息仍保持可读;
346
+ - 折叠内容用 Pi 的 `app.tools.expand` 快捷键临时展开(默认 `Ctrl+O`),展开后直接恢复 Pi 原生参数、输出、错误、diff、耗时与 full-output 证据;
337
347
  - Git 状态本地刷新;只有显式运行 `/pr` 才查询 GitHub PR。
338
348
 
339
- `fd` 与 `rg` 是结构化模型工具,不拼接 Shell。它们默认遵守 `.gitignore`,支持 Glob、类型、Smart Case、固定字符串与上下文;输出限制为 50 KiB / 2000 行,完整截断内容最多私有保存 10 MiB,并在 Session Shutdown 时清理。
349
+ `fd` 与 `rg` 是结构化模型工具,不拼接 Shell。它们默认遵守 `.gitignore`,支持 Glob、类型、Smart Case、固定字符串与上下文。`git_show`、`git_diff`、`git_log` 以结构化参数提供只读提交、差异和历史检查,并禁用仓库配置的 external diff/textconv。两类工具的输出均限制为 50 KiB / 2000 行,完整截断内容最多私有保存 10 MiB,并在 Session Shutdown 时清理。
340
350
 
341
351
  macOS/Linux arm64 与 x64 缺少二进制时,OpenPI 会从官方 Release 下载固定版本、校验 SHA-256 后原子安装。其他平台需自行提供 `fd` 与 `rg`。
342
352
 
@@ -413,16 +423,68 @@ macOS/Linux arm64 与 x64 缺少二进制时,OpenPI 会从官方 Release 下
413
423
  - npm 安装:`pi install npm:@tt-a1i/openpi`;
414
424
  - GitHub 安装:`pi install git:github.com/tt-a1i/openpi`。
415
425
 
416
- 开发当前源码:
426
+ #### 开发运行时:区分 npm 与当前源码
427
+
428
+ npm 制品、GitHub 安装和本地 checkout 是三个不同的运行资产。源码目录更新、测试通过或版本号相同,都不能证明当前 Pi 已经加载这份代码。所有本地开发、Provider 兼容排查、手工 smoke 和 UI 验收都使用下面这一条证据链。
429
+
430
+ **1. 先固定源码和加载来源**
431
+
432
+ ```bash
433
+ git status --short --branch
434
+ git rev-parse --short HEAD
435
+ pi list
436
+ ```
437
+
438
+ 完成标准:知道正在修改哪个 checkout、分支和提交;`pi list` 中只有一个 OpenPI 来源,并能明确它是 npm、GitHub 还是某个本地绝对路径。其他 Pi package(例如 `pi-intercom`)不属于重复 OpenPI 来源。
439
+
440
+ **2. 开发时让 Pi 直接加载当前 checkout**
417
441
 
418
442
  ```bash
419
443
  git clone https://github.com/tt-a1i/openpi.git ~/work/openpi
420
444
  cd ~/work/openpi
421
445
  bun install --frozen-lockfile
422
- pi install ~/work/openpi
446
+
447
+ # 若 pi list 显示了旧 OpenPI,把变量设为它显示的 package spec 或绝对路径。
448
+ OLD_OPENPI_SOURCE=/absolute/path/to/old/openpi
449
+ pi remove "$OLD_OPENPI_SOURCE"
450
+ pi install "$PWD"
451
+ pi list
423
452
  ```
424
453
 
425
- 安装或更新后重启 Pi,或运行 `/reload`。Host SDK 与 TypeBox 按 Pi Package 契约声明为 Peer Dependencies;仓库开发依赖不随包重复提供。
454
+ 已经安装当前 checkout 时,不需要反复 remove/install。切换分支或修改源码后,运行 `/reload` 或重启 Pi 才会重载扩展。`/reload` 之前的界面和工具集合只证明旧内存状态。
455
+
456
+ 完成标准:`pi list` 唯一的 OpenPI 路径就是当前 checkout,且该路径的 HEAD 与预期提交一致。不要修改 `~/.pi/agent/npm/node_modules/@tt-a1i/openpi` 来冒充源码修复。
457
+
458
+ **3. 分层验证改动**
459
+
460
+ ```bash
461
+ # 开发环:先运行与改动最接近的测试,并沿用 package.json 的 runner。
462
+ node --test --experimental-strip-types path/to/relevant.test.ts
463
+ bunx vitest run path/to/relevant.spec.ts
464
+
465
+ # 仓库门禁:提交或交付前两项都要通过。
466
+ bun run check
467
+ bun run test
468
+ ```
469
+
470
+ 自动化通过只证明代码、类型和测试合同。涉及运行时或界面时,还要在已 `/reload` 的真实 Pi 中完成对应 smoke:
471
+
472
+ - 工具或生命周期改动:在普通工具模式实际触发成功、失败和结束路径;
473
+ - Provider 兼容改动:保留正常工具 Schema,不用 `--no-tools` 绕过问题;
474
+ - UI 改动:在真实 TUI 触发目标状态并肉眼检查,必要时保存截图;
475
+ - 配置改动:通过 `/openpi-setup` 写入,再核对无参数状态输出和实际行为。
476
+
477
+ 完成标准:分别记录 checkout HEAD、`pi list` 来源、专项测试、`bun run check`、完整测试和手工 smoke。没有执行的层级写成“未验证”,不能用另一层的绿色结果代替。
478
+
479
+ **4. 保持工作区可恢复**
480
+
481
+ - 开始前检查 dirty worktree;保存用户的未提交、未跟踪和 ignored 文件;
482
+ - 本地 Benchmark、日志和原始结果可以通过 `.git/info/exclude` 隐藏,但 ignore 不是备份;
483
+ - 使用 `git clean -nd` 只能预览普通未跟踪文件;不要运行会删除 ignored 资产的 `git clean -fdx`;
484
+ - 稳定运行副本和开发 checkout 只有在确有隔离需求时才并存,并始终用 `pi list` 说明 Pi 加载哪一个;
485
+ - 提交前复查 diff,确保本地配置、密钥、模型结果和评测原始数据没有进入版本控制。
486
+
487
+ Host SDK 与 TypeBox 按 Pi Package 契约声明为 Peer Dependencies;仓库开发依赖不随包重复提供。
426
488
 
427
489
  ### 可选:顶层 Pi Session 通信
428
490
 
@@ -453,7 +515,7 @@ pi install npm:pi-intercom
453
515
  <details>
454
516
  <summary><strong>模型工具速查</strong></summary>
455
517
 
456
- Capability discovery 默认是 `explicit`:普通父 Session 不常驻任何 OpenPI 模型工具,首轮保持 Pi 原生 `read`、`bash`、`edit`、`write`。用户明确要求结构化搜索、Subagent、Workflow、后台进程或 Session Goal/Tasks 时,OpenPI 在 `before_agent_start` 直接加载对应能力组;明确询问 OpenPI capabilities/tools/features 时显示 `openpi_load_tools`。可通过 `/openpi-setup` 显式选择 `adaptive`:此时只让小型 `openpi_load_tools` 网关常驻,模型可在判断任务确实受益时自主加载一个能力组。该选择也授权模型启动该组内的昂贵工作,因此不作为默认值。条件句(例如 “If you delegate…”)不会被当成显式委派意图。能力组在当前 Session 内单调保持,避免反复增删工具破坏缓存。组内管理工具仍只在资源成功创建或状态确实存在后出现。Mode / Setup / Context 工具独立跟随实时状态显示和隐藏。Background、Subagent 与 Workflow 的 Skill 文件仍随包发布,但只在对应能力触发后提示读取,不常驻普通系统 Prompt。
518
+ Capability discovery 默认是 `explicit`:普通父 Session 不常驻任何 OpenPI 模型工具,首轮保持 Pi 原生 `read`、`bash`、`edit`、`write`。用户明确要求结构化搜索、Subagent、Workflow、后台进程或 Session Goal/Tasks 时,OpenPI 在 `before_agent_start` 直接加载对应能力组;明确询问 OpenPI capabilities/tools/features 时显示 `openpi_load_tools`。可通过 `/openpi-setup` 显式选择 `adaptive`:此时只让小型 `openpi_load_tools` 网关常驻,模型可在判断任务确实受益时自主加载一个能力组。该选择也授权模型启动该组内的昂贵工作,因此不作为默认值。条件句(例如 “If you delegate…”)不会被当成显式委派意图。能力组在当前 Session 内单调保持,避免反复增删工具破坏缓存。Delegate 一经加载便一次性开放完整、稳定的 Subagent 工具族;资源不存在时由工具执行层明确返回空状态或 fail-closed,而不再按实例生命周期改变模型接口。其他组内管理工具仍只在资源成功创建或状态确实存在后出现。Mode / Setup / Context 工具独立跟随实时状态显示和隐藏。Background、Subagent 与 Workflow 的 Skill 文件仍随包发布,但只在对应能力触发后提示读取,不常驻普通系统 Prompt。
457
519
 
458
520
  普通产品默认采用 Pi-native execution:保留 Pi 原生完整历史、工具输出上限、Session compaction、显式 Bash timeout 与 provider loop,不再额外做固定事务投影、成功 Bash 二次裁剪、测试 timeout 改写、重复失败硬拦或恢复/轨迹提示。OpenPI 只保留独立的工作区安全边界:阻止未授权删除 pre-existing 路径,并从实际文件状态识别本轮通过原生写入、文字重定向或 literal `mkdir -p` 创建的 scratch,避免误拦其清理。旧执行策略仅保留为受 benchmark root 门控的实验 profile,不会进入普通 Session。
459
521
 
@@ -461,14 +523,14 @@ Capability discovery 默认是 `explicit`:普通父 Session 不常驻任何 Op
461
523
  | -------------------------------------------------------------------------------------------------------- | ------------------------------ | -------------------------------- |
462
524
  | `openpi_load_tools` | 列出或加载可选工具组 | 明确询问;或启用 `adaptive` |
463
525
  | `bg_start`, `bg_status`, `bg_list`, `bg_watch`, `bg_kill` | 后台进程生命周期 | 明确意图或 adaptive;启动后展开 |
464
- | `subagent_spawn`, `subagent_check`, `subagent_list`, `subagent_wait`, `subagent_send`, `subagent_cancel` | 独立子 Agent | 明确意图或 adaptive;创建后展开 |
465
- | `workflow`, `workflow_status`, `workflow_stop` | 动态多阶段编排与运行管理 | 明确意图或 adaptive;运行后展开 |
526
+ | `subagent_spawn`, `subagent_check`, `subagent_list`, `subagent_wait`, `subagent_send`, `subagent_cancel` | 独立子 Agent | 明确意图或 adaptive;整组稳定加载 |
527
+ | `workflow`, `workflow_status`, `workflow_stop` | 动态多阶段编排与运行管理 | 明确意图或 adaptive;能力组一次稳定展开 |
466
528
  | `tasks_add`, `tasks_update`, `tasks_list` | Session 工作项 | 明确意图或 adaptive;存在后展开 |
467
529
  | `get_goal`, `create_goal`, `update_goal` | Session Goal | 明确意图或 adaptive;存在后展开 |
468
530
  | `context_pivot` | Context 阶段切换 | Context 达到阈值时 |
469
531
  | `ask_user`, `human_handoff` | 经复核的用户决策与用户专属操作 | Plan 或 Setup 进行中 |
470
532
  | `plan_ready` | 显式完成计划,不自动开始实施 | Plan 调研阶段 |
471
- | `fd`, `rg` | 文件发现与内容搜索 | 明确意图或 adaptive 加载 search |
533
+ | `fd`, `rg`, `git_show`, `git_diff`, `git_log` | 文件、内容与只读 Git 检查 | 明确意图或 adaptive 加载 search |
472
534
  | `configure_my_pi_setup` | 受限配置写入 | `/openpi-setup` 进行中 |
473
535
 
474
536
  </details>
@@ -539,6 +601,7 @@ extensions/
539
601
  ├── plan-mode/ + cron/ # 批准门禁与 Session 定时 Prompt
540
602
  ├── ask-user/ # Reviewed input 与 Human Handoff
541
603
  ├── file-search/ # fd / rg 与安全二进制获取
604
+ ├── git-read/ # 只读 git show / diff / log
542
605
  ├── sessions/ # Session 搜索与切换
543
606
  ├── suggestions/ # Ephemeral next-action suggestion
544
607
  ├── ui-customization/ # Header、Footer、Terminal title
@@ -568,4 +631,4 @@ npm 仍用于发布包的 `pack` / clean-install 验证,因为用户通过 npm
568
631
 
569
632
  `extensions/sessions/` 改编自 [jayshah5696/pi-agent-extensions](https://github.com/jayshah5696/pi-agent-extensions)。可选的顶层 Session 通信由 [pi-intercom](https://github.com/nicobailon/pi-intercom) 提供。完整第三方说明见 [`THIRD_PARTY_NOTICES.md`](THIRD_PARTY_NOTICES.md)。
570
633
 
571
- 本仓库目前没有项目级开源许可证;`THIRD_PARTY_NOTICES.md` 只记录第三方来源与各自许可,不等同于授予本项目使用许可。
634
+ 本项目以 MIT 许可证发布(见 [`LICENSE`](LICENSE));`THIRD_PARTY_NOTICES.md` 记录第三方来源与各自许可。
package/SETUP.md CHANGED
@@ -14,9 +14,9 @@ pi install git:github.com/tt-a1i/openpi
14
14
 
15
15
  Pi installs the package dependencies automatically. Restart Pi or run `/reload` after installation.
16
16
 
17
- ## fd and rg tools
17
+ ## fd, rg, and read-only git tools
18
18
 
19
- The `file-search` extension registers `fd` and `rg` as model tools. They stay outside an ordinary parent turn until the user explicitly asks to use `fd`/`rg` or structured file search, or the model loads the `search` group through `openpi_load_tools`. The gateway is shown after an explicit OpenPI-capability request, or remains visible when the user opts into adaptive discovery; child sessions may still receive `fd` and `rg` through the reviewed child-safe allowlist. No setup is normally needed: at startup it silently uses a system-installed `fd` (or `fdfind` on Debian/Ubuntu) and `rg` when available, or an existing fallback in this package's private `bin/` directory. Only when neither exists does it download an official release binary (macOS/Linux, arm64/x64, over HTTPS) into that package-local directory and show a one-time notification. If your platform is unsupported, install `fd` and `rg` with your package manager and restart Pi.
19
+ The `file-search` extension registers `fd` and `rg` as model tools, and `git-read` registers `git_show`, `git_diff`, and `git_log` (read-only git inspection). They stay outside an ordinary parent turn until the user explicitly asks to use `fd`/`rg`/git history, or structured file search, or the model loads the `search` group through `openpi_load_tools`. The gateway is shown after an explicit OpenPI-capability request, or remains visible when the user opts into adaptive discovery; child sessions may still receive these tools through the reviewed child-safe allowlist (the read-only git tools let reviewer/advisor subagents inspect diffs, which a bash-free tool boundary otherwise excludes). No setup is normally needed: at startup `fd`/`rg` silently use a system-installed binary (`fd`/`fdfind` and `rg`) when available, or an existing binary in the agent's private managed bin directory (`~/.pi/agent/bin`). Only when neither exists does it download an official release binary (macOS/Linux, arm64/x64, over HTTPS) into that directory — a persistent cache that survives package updates and show a one-time notification. If your platform is unsupported, install `fd` and `rg` with your package manager and restart Pi. The git tools require a system `git`.
20
20
 
21
21
  ## Theme
22
22
 
@@ -54,7 +54,7 @@ Use the single canonical package-owned command. `/my-pi-setup` remains a compati
54
54
  /openpi-setup 清除 explorer 的模型,让它继承父模型
55
55
  ```
56
56
 
57
- Capability discovery defaults to `explicit`, preserving the zero-resident OpenPI tool surface until the user asks for a capability. `adaptive` is an explicit opt-in that keeps only `openpi_load_tools` visible and allows the model to load a useful group on its own; because this can start Subagents, Workflows, or background processes, normal permission and configured concurrency/call limits still apply. Changing the setting updates the current Session immediately, while already loaded groups remain stable for that Session. Next-action suggestions default to off. Run `/openpi-setup` to explicitly choose an available model and reasoning level. After a fully settled main-agent run, one suggestion may appear as dim inline text on the first row of an empty editor; reserved cells at the row end keep CJK IME preedit from overwriting it. `Right` accepts it into the editor without submitting, while any other editor input dismisses it. Suggestions are ephemeral and never enter session history or model context. Workflows default to 8 concurrent agents and 128 total agent calls per run; configurable hard maxima are 64 and 1024. The large decorative header defaults off and the custom dashboard footer defaults on with a one-line Powerline layout (`cwd model thinking context cache cost throughput |flex| git pr`). Footer presets are `powerline`, `powerline-mono`, and `compact`; style can also be set independently to `plain`, `powerline`, or `powerline-mono`. Custom layouts use a 2D `footerLines` array with at most one `flex` per row for left/right alignment. Nerd Font only affects powerline separator glyphs (``); metric text stays readable without it. Footer changes apply immediately in the active TUI session. Subagent results default to the existing full display; compact mode shows only bounded status rows and keeps raw child reports behind `app.tools.expand` (`Ctrl+O` by default). Bash defaults to a folded one-line command with bounded output and a hidden-line count. Write/Edit defaults to an extra-short folded preview capped at three rendered lines including the operation header; its hidden-line hint remains inside the operation's status background. Select full independently for any category to keep it expanded. Compact views temporarily expand with `app.tools.expand`. An optional post-edit command is off by default: set one (for example `npm run format`, maximum 500 characters) and it runs once in the background after each interactive-TUI turn with successful Write/Edit operations, with failures reported as a notification. It deliberately does not guess whether arbitrary Bash commands changed files. Built-in Agent roles `explorer`, `implementer`, `reviewer`, and `advisor` are shared by `subagent_spawn.agent_type` and Workflow `agent(..., { agent_type })`; all inherit the parent model by default. `/openpi-setup` may assign a currently available Registry model to any subset; clearing one returns it to inheritance and omitted roles stay unchanged. Model precedence is explicit call > selected role-file model > setup assignment > parent inheritance; effort is explicit call > selected role > parent. A trusted project `.pi/agents/<role>.md` overrides global `~/.pi/agent/agents/<role>.md`, which overrides the complete built-in role definition; overrides are diagnosed. Role-model changes apply to the next spawn or Workflow agent call without reload. Configuration is stored privately at `~/.pi/agent/my-pi-setup.json`.
57
+ Capability discovery defaults to `explicit`, preserving the zero-resident OpenPI tool surface until the user asks for a capability. The case-insensitive English words `subagent` and `workflow` are reserved authorization words: entering either word is sufficient to load its capability group, and the interactive editor shows it in Claude Code-style lavender before submission, with a darker purple fallback for light themes. This makes discussion that contains either English word an intentional opt-in tradeoff; conditional and negated clauses remain inert, while Chinese capability names still require a recognized action request. `adaptive` is an explicit opt-in that keeps only `openpi_load_tools` visible and allows the model to load a useful group on its own; because this can start Subagents, Workflows, or background processes, normal permission and configured concurrency/call limits still apply. Changing the setting updates the current Session immediately, while already loaded groups remain stable for that Session. Accepted Suggestion text is classified only after it becomes real editor input. The visual feedback and runtime activation share one fail-closed intent classifier. Next-action suggestions default to off. Run `/openpi-setup` to explicitly choose an available model and reasoning level. After a fully settled main-agent run, one suggestion may appear as dim inline text on the first row of an empty editor; reserved cells at the row end keep CJK IME preedit from overwriting it. `Right` accepts it into the editor without submitting, while any other editor input dismisses it. Suggestions are ephemeral and never enter session history or model context. Workflows default to 8 concurrent agents and 128 total agent calls per run; configurable hard maxima are 64 and 1024. The large decorative header defaults off and the custom dashboard footer defaults on with a one-line plain layout (`model context |flex| git pr cwd`; `thinking`, `cache`, `cost`, and `throughput` remain opt-in metrics). Footer presets are `powerline`, `powerline-mono`, and `compact`; style can also be set independently to `plain`, `powerline`, or `powerline-mono`. Custom layouts use a 2D `footerLines` array with at most one `flex` per row for left/right alignment. Nerd Font affects powerline separator glyphs (``) and adds Codex-style outline icons to compact read, terminal, edit, search, and directory activity rows; all accompanying text remains readable without it. Footer metrics use one Codicon outline family (`` model, `` context, and `` directory) plus `⎇` for the branch. A Nerd Font containing Codicons renders them as designed; without one, the text labels remain readable even if an icon falls back to an empty box. Footer changes apply immediately in the active TUI session. Subagent results default to the existing full display; compact mode shows only bounded status rows and keeps raw child reports behind `app.tools.expand` (`Ctrl+O` by default). Ordinary `read`, `grep`, `find`, and `ls` operations render as one-line semantic activity summaries. Bash and Write/Edit default to the same activity-row projection, showing the target, running/success/failure state, and useful line or diff counts without replaying stdout or previews. Select full independently for Bash or Write/Edit to keep Pi's native rendering expanded. `app.tools.expand` temporarily restores the native arguments, output, errors, diff, timing, images, truncation notices, and full-output metadata; it never changes Session history or model context. An optional post-edit command is off by default: set one (for example `npm run format`, maximum 500 characters) and it runs once in the background after each interactive-TUI turn with successful Write/Edit operations, with failures reported as a notification. It deliberately does not guess whether arbitrary Bash commands changed files. Built-in Agent roles `explorer`, `implementer`, `reviewer`, and `advisor` are shared by `subagent_spawn.agent_type` and Workflow `agent(..., { agent_type })`; all inherit the parent model by default. `/openpi-setup` may assign a currently available Registry model to any subset; clearing one returns it to inheritance and omitted roles stay unchanged. Model precedence is explicit call > selected role-file model > setup assignment > parent inheritance; effort is explicit call > selected role > parent. A trusted project `.pi/agents/<role>.md` overrides global `~/.pi/agent/agents/<role>.md`, which overrides the complete built-in role definition; overrides are diagnosed. Role-model changes apply to the next spawn or Workflow agent call without reload. Configuration is stored privately at `~/.pi/agent/my-pi-setup.json`.
58
58
 
59
59
  ## Session Goal and Tasks
60
60
 
@@ -15,36 +15,37 @@ import type {
15
15
  import {
16
16
  Editor,
17
17
  type EditorTheme,
18
+ type Focusable,
18
19
  Key,
19
20
  matchesKey,
20
21
  Text,
21
22
  truncateToWidth,
22
- type Focusable,
23
23
  wrapTextWithAnsi,
24
24
  } from "@earendil-works/pi-tui";
25
25
  import { Cause, Effect, Exit } from "effect";
26
- import { Type, type Static } from "typebox";
27
- import { sanitizeTerminalText } from "../shared/terminal-text.ts";
26
+ import { type Static, Type } from "typebox";
28
27
  import {
29
28
  PLAN_MODE_CHANNEL,
30
29
  type PlanModeState,
31
30
  } from "../shared/plan-mode-state.ts";
31
+ import { hintLine } from "../shared/screen-chrome.ts";
32
32
  import {
33
33
  OPENPI_SETUP_EPISODE_CHANNEL,
34
34
  type OpenPiSetupEpisodeState,
35
35
  } from "../shared/setup-episode-state.ts";
36
+ import { sanitizeTerminalText } from "../shared/terminal-text.ts";
36
37
  import {
37
38
  OPENPI_TOOL_SURFACE,
38
39
  patchOwnedTools,
39
40
  } from "../shared/tool-surface.ts";
40
41
  import { createHumanHandoffToolDefinition } from "./handoff.ts";
41
42
  import {
42
- BRACKETED_PASTE_END,
43
- BRACKETED_PASTE_START,
44
- MAX_ANSWER_DRAFT_UTF8_BYTES,
45
43
  answerDraftByteLength,
46
44
  answerDraftFits,
45
+ BRACKETED_PASTE_END,
46
+ BRACKETED_PASTE_START,
47
47
  longerThanAnswerDraftLimit,
48
+ MAX_ANSWER_DRAFT_UTF8_BYTES,
48
49
  prospectiveAnswerDraftFits,
49
50
  sanitizeAnswerDraftEditorInput,
50
51
  } from "./limits.ts";
@@ -63,7 +64,7 @@ const MAX_OPTIONS = 5;
63
64
  /** Preview lines rendered before the tail is summarized. */
64
65
  const PREVIEW_MAX_LINES = 20;
65
66
 
66
- export { MAX_ANSWER_DRAFT_UTF8_BYTES, answerDraftFits } from "./limits.ts";
67
+ export { answerDraftFits, MAX_ANSWER_DRAFT_UTF8_BYTES } from "./limits.ts";
67
68
 
68
69
  const OptionSchema = Type.Object({
69
70
  label: Type.String({
@@ -949,9 +950,15 @@ export default function askUser(pi: ExtensionAPI) {
949
950
  );
950
951
  lines.push("");
951
952
  add(
952
- theme.fg(
953
- "dim",
954
- ` ↑↓ choose • 1-${params.questions.length} edit answer • Enter open/submit • Esc dismiss`,
953
+ hintLine(
954
+ theme,
955
+ [
956
+ ["↑↓", "choose"],
957
+ [`1-${params.questions.length}`, "edit answer"],
958
+ ["enter", "open/submit"],
959
+ ["esc", "dismiss"],
960
+ ],
961
+ width,
955
962
  ),
956
963
  );
957
964
  add(theme.fg("accent", "─".repeat(width)));
@@ -1043,11 +1050,20 @@ export default function askUser(pi: ExtensionAPI) {
1043
1050
 
1044
1051
  lines.push("");
1045
1052
  add(
1046
- theme.fg(
1047
- "dim",
1053
+ hintLine(
1054
+ theme,
1048
1055
  editMode
1049
- ? " Enter save answer • Esc keep draft and return"
1050
- : ` ↑↓ or 1-${currentOptions.length} select • Tab add notes • Enter save draft answer • Esc dismiss`,
1056
+ ? [
1057
+ ["enter", "save answer"],
1058
+ ["esc", "keep draft and return"],
1059
+ ]
1060
+ : [
1061
+ [`↑↓ or 1-${currentOptions.length}`, "select"],
1062
+ ["tab", "add notes"],
1063
+ ["enter", "save draft answer"],
1064
+ ["esc", "dismiss"],
1065
+ ],
1066
+ width,
1051
1067
  ),
1052
1068
  );
1053
1069
  add(theme.fg("accent", "─".repeat(width)));
@@ -178,7 +178,7 @@ export function buildTerminalResultMessage(snap: TerminalSnapshot) {
178
178
  if (snap.stderr.totalBytes > 0) {
179
179
  text += `\n\n${outputSection("stderr", snap.stderr, RESULT_STDERR_MAX, RESULT_STDERR_MAX_LINES)}`;
180
180
  }
181
- return text;
181
+ return `${text}\n\n(This result is already shown to the user. Act on it and relay only the decisions or next steps — do not repeat it verbatim.)`;
182
182
  }
183
183
 
184
184
  /** Preserve every retained terminal identity while globally bounding batch logs. */