docs: organize product design by feature

Define repository and feature-scoped documentation rules for PRDs, User Stories, logic, UI, technical design, and progress evidence.

Move feature-owned documents under docs/features, add one entry point per feature, remove the redundant docs index, and update all affected cross-references. Expand the local tool environment design with explicit product, story, logic, UI, technical, and progress documents.
This commit is contained in:
mesalogo
2026-09-01 14:52:22 +08:00
parent dba3380a06
commit 2f1881a414
56 changed files with 1763 additions and 765 deletions
+13
View File
@@ -0,0 +1,13 @@
# 助手工作栏
助手工作栏统一承载本机与远程执行空间、Task、成果、文件、浏览器和终端等持续工作界面。
## 文档导航
| 文档 | 权威职责 |
| --- | --- |
| [通用助手工作栏与执行空间 PRD](./prd.md) | 工作栏整体产品范围、执行空间和各工作面板归属 |
| [多终端页签 PRD](./terminal-tabs-prd.md) | 多终端 Tab、目标选择、关闭确认和终端生命周期 |
当前尚未拆出独立 User Stories、功能逻辑、UI 设计、技术设计和进度文档;相关内容仍保留在
两份现有 PRD 中,后续实际维护该功能时按职责拆分。
+988
View File
@@ -0,0 +1,988 @@
# 通用助手工作栏与执行空间 PRD
## 文档信息
| 项目 | 内容 |
| --- | --- |
| 状态 | 设计中 |
| 版本 | 0.6 |
| 日期 | 2026-08-31 |
| 适用产品 | GoodBuddy 桌面端 |
| 相关设计 | [统一界面设计系统](../../../UI-DESIGN.md)、[SSH 远程主机与 GoodBuddy Agent 实现说明](../remote-host/technical-design.md) |
| 相关能力 | [会话监督](../conversation-supervision/prd.md)、[自动化平台](../../architecture/automation-platform-architecture.md)、[长期助手路线图](../../roadmap/long-term-assistant-roadmap.md) |
## 1. 背景
GoodBuddy 已经在聊天右侧提供任务中心、工作区、浏览器和成果面板,也已经具备
Runtime 事件、Git 变更、文件预览、成果存储、受控浏览器和专家执行等基础能力。后续还
计划增加:
- Conversation、Task 和实验的独立监督。
- OpenCode、Continue 和 DeepSeek Harness 的 Runtime 生命周期监督。
- 用户可直接使用的终端和受管进程。
- HTML 等成果的即时安全预览。
- 本机与 SSH 远程主机上的工作区和 Agent Runtime。
这些能力不能被收束为只面向编程的工作台。监督、Runtime、终端、进程、浏览器和成果
都可以服务于普通问答、内容分析、自动化、数据处理、远程运维、知识整理和软件开发。
同时,能力目录也不能根据当前页面、项目类型或 Runtime 能力无提示地变化,否则用户无法在
需要时主动打开面板并选择目标、主机或运行环境。
本设计把右侧区域定义为应用级的“助手工作栏”,并把本机或远程的目录、终端、进程和
Runtime 统一抽象为“执行空间”。
## 2. 产品定义
### 2.1 助手工作栏
助手工作栏是 GoodBuddy 中始终可访问的应用级工具容器。它提供稳定能力目录,用户从中
查看任务中心,并按需打开一个或多个监督、Runtime、终端、进程、工作区、浏览器和成果
面板实例。稳定的是能力的可发现性,不是八个同时占据界面的固定面板。
工作栏不是:
- 只在编程项目中出现的 IDE 面板。
- 当前聊天消息的附属详情框。
- 根据能力探测结果自动增删入口的动态菜单。
- 绕过 Main、Preload、Ask/Execute 或审批边界的控制台。
- 全系统进程管理器、任意文件浏览器或无边界远程管理工具。
### 2.2 执行空间
执行空间描述工作区、终端、受管进程和 Agent Runtime 实际运行的位置:
```ts
type ExecutionSpaceSelection =
| {
kind: 'local'
rootPath?: string
}
| {
kind: 'ssh'
hostId: string
remoteRootPath?: string
}
```
执行空间可以来自当前项目,也可以由用户在工作栏中临时选择。临时选择不会静默修改项目
设置,也不直接授予文件、终端或 Runtime 能力。Main 必须先把选择草稿验证为绑定窗口、
controller、Host/Workspace identity、信任 revision、能力和 lease 的 opaque 临时 Grant;
后续 IPC 只引用 Grant ID。只有用户显式保存并重新通过 Project 候选验证时才成为项目默认值。
## 3. 核心产品原则
### 3.1 能力目录稳定,面板实例由用户控制
工作栏能力目录提供以下标准能力:
```text
任务中心
监督
Runtime
终端
进程
工作区
浏览器
成果
```
- 应用不得根据当前项目、会话、Runtime、主机或探测结果无提示地增删能力目录项。
- 用户主动打开、关闭、排序和停靠面板实例;应用不默认同时挂载全部能力。
- Task Center 是 Task 的单例应用级索引。每个 Task 只关联一条 Conversation,一条
Conversation 可以关联多个 Task;Task Center 不复制会话内容,也不显示普通 Conversation、
Job、Run 或心跳事项。
- 当前能力、连接、数据和空状态可以动态变化。
- 能力不可用时,目录项或已打开面板显示原因、影响和可执行的配置或切换入口,不能只通过隐藏表示。
- 用户可以在设置中调整目录顺序;恢复默认布局恢复标准目录与默认打开面板,不强制打开全部能力。
- 同一能力需要并排比较不同目标时可以创建多个实例,每个实例拥有独立身份和范围绑定。
### 3.2 当前上下文只提供默认值
任务中心作为全局索引不跟随当前会话,也不支持为同一列表打开多个目标实例。其他可绑定
目标的能力使用当前会话、项目、Runtime 和主机帮助新面板实例初始定位,但这些上下文不是
使用门槛:
- 监督默认选择当前会话,用户可以改选其他 Conversation、Task 或实验对象。
- Runtime 默认跟随当前会话或 Task;执行事件可以查看,但 Job/Run 不作为独立选择对象。
- 终端创建时固定到当前项目执行空间,由项目配置自动决定本机或托管 SSH;没有当前项目时
使用本机 Home。
- 工作区默认显示当前项目目录,用户可以打开其他本机目录或远程目录。
- 成果默认使用当前范围,用户可以切换到项目、全局或其他允许范围。
- 下一次请求的附件和知识库由当前 Composer 展示与管理,不作为工作栏能力。历史执行上下文
随关联 Task 查看;记忆功能实现后也归入任务中心,而不是新增独立上下文面板。
每个可切换目标的面板实例都提供一致的范围模式:
```text
跟随当前上下文
固定到指定对象
```
固定目标失效时,面板显示“目标不可用”和修复入口,不静默回到其他目标。
### 3.3 用户控制打开、切换和介入
- 后台事件可以更新目录徽标、面板状态和通知,但不得无条件抢占当前面板。
- 只有用户刚刚发起且明确需要面板完成的交互,才可以打开对应面板。
- 浏览器画面、审批、监督警告、Runtime 失败和终端退出默认通过徽标或通知提示。
- 高风险状态必须持续可见,但不以自动切页代替用户选择。
- 用户切换页面、会话或项目时,已固定的面板目标保持不变;跟随模式才更新目标。
### 3.4 入口稳定不等于虚假能力
稳定能力目录和已打开面板必须准确呈现能力差异:
- 当前 Runtime 不支持后台 Job 时,Runtime 能力仍可发现;打开后说明当前可监督的内容。
- 当前执行空间没有 Git 仓库时,工作区文件功能仍可使用,Git 区域显示不可用原因。
- 没有活动进程时,进程面板提供创建终端或启动 Runtime 的入口。
- 没有项目时,终端使用当前用户本机 Home;工作区等允许选择路径的能力仍必须先取得有界
临时 Execution Space Grant,不能把可选路径直接传给文件、Git、Process 或 Runtime。
- 监督未启用时,监督面板提供目标、模式和“开始监督”,而不是隐藏能力。
不得渲染成排没有解释的禁用按钮,也不得把“进程连通”描述为已经支持完整原生监督。
### 3.5 通用能力与领域能力分层
- 监督判断目标、证据、矛盾、遗漏、质量和风险,不假设目标一定是编程。
- Runtime 监督展示运行生命周期,不假设 Runtime 一定是 OpenCode。
- 终端和进程是通用执行能力,不只服务代码构建。
- 工作区可以是文档、数据、知识或代码目录;Git 是可选区域。
- HTML 预览属于通用成果能力,不只用于网页开发。
- SSH 主机可以承载 Agent、自动化、数据处理和工作区,不只代表远程代码仓库。
## 4. 目标
### 4.1 用户目标
- 从任意主要页面随时发现同一组稳定能力,并按需打开所需面板。
- 自主选择每个可绑定目标的面板实例跟随当前上下文还是固定到指定目标。
- 在不中断主任务的情况下观察监督意见、Runtime、进程和成果。
- 随时创建本机或远程终端,并理解其执行位置和权限。
- 查看 GoodBuddy 管理的进程及其来源、输出和停止状态。
- 对生成的 HTML、Markdown、JSON、图片等成果进行即时安全预览。
- 管理 SSH 主机,并在远程执行空间中运行受控 Agent Runtime。
### 4.2 产品目标
- 建立不依赖具体页面和 Runtime 的应用级工作栏、能力目录和面板实例壳层。
- 建立统一范围、执行空间、生命周期、成果和控制契约。
- 复用现有 Project、Conversation、Task、Artifact、Activity 和 Approval 数据。
- 保持 Renderer 无任意文件、进程、PTY、SSH 或 Electron API 能力。
- 保持 Ask 只读、Execute 审批、取消、超时、输出边界和活动审计。
- 为本机与远程能力提供一致 UI,同时准确表达能力差异。
## 5. 非目标
- 不把 GoodBuddy 改造成完整 IDE。
- 不提供全系统进程枚举和任意 PID 终止。
- 不默认扫描用户全部目录、远程主机或 SSH 配置。
- 不允许 Agent 未经现有 Runtime 边界直接向用户终端注入输入。
- 不自动执行 HTML 中的脚本或访问网络。
- 不让监督器自动替用户发言、批准工具、扩大范围或修改安全策略。
- 不提供以 SSH 连接为生命周期的临时远程 Agent;远程执行必须由用户级常驻 Daemon 承载。
- 不支持任意 ProxyCommand、任意端口转发或 SSH Agent Forwarding。
- 不要求所有 Runtime 提供相同的 Subagent、Job、Hook 或会话能力。
## 6. 信息架构
### 6.1 应用级位置
助手工作栏位于主窗口右侧,但不归属于聊天页面。聊天、知识、魔法笔记、自动化、活动记录
等主要页面都可以打开它。各页面可以提供默认范围,不能维护互不相容的右栏副本。
```text
┌──────────────┬──────────────────────────────┬────────────────────────┐
│ 主导航 │ 当前主任务 │ 助手工作栏 │
│ │ │ │
│ 会话 / 知识 │ 聊天、文档、自动化或数据视图 │ 稳定能力目录 │
│ 自动化 / 活动│ │ 用户打开的面板实例 │
│ 设置 │ │ 各实例范围与执行空间 │
└──────────────┴──────────────────────────────┴────────────────────────┘
```
### 6.2 能力目录与面板实例
能力目录不等于同时打开八个面板。当前产品采用“已打开实例 Tab + 持久新增按钮”的工作栏
模型:Tab 行只显示已打开实例,行末“+”始终可见;点击后在工作栏内容区打开稳定能力目录,
用户再创建或激活应用实例。详细交互以
[助手工作栏多终端页签 PRD](./terminal-tabs-prd.md) 为准。
- 每项始终显示稳定图标,并提供可见标签或可持续查看的工具提示。
- 已打开实例使用 `tablist`、`tab`、`tabpanel`;“+”是位于 `tablist` 外的普通命令按钮。
- 应用注册表声明 `single` 或 `multiple`。重复选择单实例应用时聚焦已有实例;选择多实例
应用时每次创建新实例。
- 支持方向键、Home、End、Enter、Space、关闭面板和正确焦点恢复。
- 徽标显示未解决数量、等待审批或失败状态,并同时提供文字或可访问名称。
- 用户调整目录顺序、打开实例、停靠位置和尺寸后持久化;关闭实例后能力仍可从目录重新打开。
- 默认布局只恢复经过产品确认的少量常用面板,不自动打开全部标准能力。
- 每个实例显示稳定实例 ID、能力名称、跟随或固定状态与当前目标;同能力多实例不能只靠位置区分。
从当前聊天右栏迁移时,Task Center、工作区、浏览器和成果作为默认打开的单实例应用保留;
终端不默认打开,由用户通过“+”创建,并从首期开始支持多实例。Tab 必须单行横向滚动,
不能自动隐藏或缩写到不可辨认,“+”不能随滚动消失。Task Center 继续作为 Task 的现有
入口;审批定位到所属 Task 或 Runtime。智能心跳不作为工作栏页签,其报告、建议、历史和
完整配置统一归属“智能心跳”菜单入口。当前阶段不新增独立自动化中心。
### 6.3 工作栏尺寸
- 所有窗口宽度下工作栏都停靠右侧并参与水平布局回流;展开时主工作区同步收缩,不能覆盖
或遮罩其内容。
- 分栏计算排除最左侧主导航,主工作区与工作栏使用相同的 `300px` 最小宽度。拖动记录两侧
在可用分栏宽度中的比例;任一侧达到最小值后停止,窗口缩放后按原比例重新计算并再次
应用同一最小值约束。
- 最左侧主导航保持全高连续表面;窗口标题栏只覆盖右侧内容框架,不能横跨主导航并把品牌、
项目切换器和导航整体向下推移。
- 对话内容与输入区始终保留对称的左右安全边距,工作栏边界不得覆盖或裁切输入框、发送
按钮及主工作区右侧边距。
- 唯一展开与收起开关固定在窗口关闭按钮正下方。工作栏内部不重复关闭入口。开关图标中的
箭头方向随当前动作切换,按钮不以持续高亮表达展开状态;当前会话没有 Task 时不渲染空
Task 上下文栏。
- “新建任务”入口位于工作栏“任务索引”标题后方,不在会话 Task 上下文栏重复出现;索引
状态筛选占满可用宽度并等分各筛选项。
- 终端、宽日志和大型成果允许用户切换到底部停靠或独立窗口。
- 应用只建议适合的布局,不因面板内容自动改变用户已经选择的停靠位置。
## 7. 能力与面板定义
### 7.1 Task Center
Task Center 保留为工作栏中的稳定入口,并在现有基础上适度完善:
- 只索引 Task;每个 Task 只关联一条 Conversation,一条 Conversation 可以关联多个 Task。
- 显示名称、关联 Conversation、Global 或 Project 范围、Ask/Execute、状态、最近进展、
真实活动时间和需要关注信息。
- 点击 Task 打开其关联 Conversation 并定位 Task。
- 完整消息留在 Conversation;工具、Subagent、审批、错误和成果按 Task 关联到 Runtime、
活动记录和成果查看器中,不在窄栏复制,也不呈现 Job/Run 树。
- 智能心跳的报告、建议、历史和配置不进入任务中心。
任务中心是单例索引,不使用其他能力的“跟随 / 固定目标”多实例模型。后台状态可以更新
徽标和排序,但不能自动打开面板或抢占用户当前工作。
主侧栏最近会话为关联 Task 提供轻量入口:父会话行只显示行首展开按钮,Task 子项使用
任务图标和本地化摘要,展开层级只到 Task;点击 Task 子项打开同一 Conversation 并定位。
新建定制任务使用 Modal 选择当前或新
Conversation,默认 Execute,并持续显示 Runtime、Project、工作目录、工具和审批摘要。
详细产品边界以 [Task Center PRD](../task-and-job/task-center-prd.md) 和
[Task 与 Job 统一领域模型](../task-and-job/task-and-job-model.md) 为准。
### 7.2 监督
监督是通用观察与评论入口,详细行为以
[会话监督 PRD](../conversation-supervision/prd.md) 为准。
监督能力在目录中稳定可发现;用户打开面板实例后可以选择:
- 普通会话。
- Task。
- 实验或实验结果。
- 后续支持的文档分析和其他可监督对象。
监督面板包含:
- 当前目标与范围。
- 开启状态、监督模式、触发方式和预算。
- 评论、警告、人工复核请求和证据。
- 未解决、已查看、已解决、忽略和误报状态。
- “带入输入框”“查看证据”“追问”“停止当前回复”等用户介入操作。
“采纳”只生成可编辑草稿或显式会话操作,不自动发送、执行、切换 Execute 或批准工具。
### 7.3 Runtime
Runtime 能力统一监督直连模型、OpenCode、Continue、DeepSeek Harness 和后续 Runtime。
能力在目录中稳定可发现,打开的面板实例依据所选 Runtime 的真实能力显示状态。
远程实现先只交付 OpenCode 官方 ACP 闭环;Continue 与 DeepSeek Harness 后续复用同一
面板和通道契约。产品不为并行建设多套后端而增加用户可见模式或临时入口。
共同区域:
- Runtime、模型连接、Conversation 或 Task 身份。
- 活动请求、状态、耗时、用量和取消。
- 工具、审批、问题、上下文压缩和错误。
- 跳转完整活动记录和持久设置。
可选区域:
- Task 级委派状态和取消。
- Task 级后台执行进度、结果和终止。
- Todo、Workflow 和 Hook 运行。
- 原生会话、暂停、恢复、压缩或释放。
可选区域不可用时,用一段有操作路径的状态说明替代空卡片。用户可以在面板中切换 Runtime
或 Conversation / Task 目标,不要求先回到聊天 Composer。内部 Job/Run 事件按 Task
聚合,不提供 Job/Run 选择器、树、页面或独立操作菜单。
### 7.4 终端
终端面板允许用户通过工作栏“+”主动创建和管理多个本机或 SSH 终端。详细产品行为、首期
直接 SSH PTY 技术选择、生命周期和验收以
[助手工作栏多终端页签 PRD](./terminal-tabs-prd.md) 为准。
- 新建、重命名、切换、关闭和重新连接终端。
- 创建时自动绑定当前项目执行空间、权威工作目录和平台默认 Shell,不显示重复目标选择。
- 显示本机或远程主机、目录、Shell 和连接状态。
- 支持复制、粘贴、搜索、清屏、滚动和调整终端尺寸。
- 支持将终端切换到右侧、底部或独立窗口。
终端属于用户交互表面。Agent 工具调用可以产生独立受管进程和日志,但不能伪装成用户终端,
也不能在没有明确授权的情况下向现有终端发送按键或命令。
### 7.5 进程
进程面板只展示 GoodBuddy 创建、托管或明确接管的进程:
- 用户终端 Shell。
- Runtime Host、Server、Utility 和远程 GoodBuddy Agent。
- Runtime 后台 Job。
- 用户通过工作栏显式启动的长运行命令。
- 浏览器或自动化中属于 GoodBuddy 的受管子进程摘要。
每项显示:
- 名称和有界命令摘要。
- 来源、执行空间、项目或会话归属。
- 启动时间、状态、退出码和资源摘要。
- 有界 stdout/stderr 或结构化日志。
- 正常终止、必要时强制终止和打开关联对象。
Renderer 不接收任意系统 PID 控制能力。控制动作引用 Main 签发的受管进程 ID,并由 Main
重新验证所有权、当前状态和允许操作。
### 7.6 工作区
工作区面板允许用户选择:
- 当前项目目录。
- 其他本机目录。
- 已配置 SSH 主机上的远程目录。
面板提供:
- 有界目录树和文本文件预览。
- 当前选择、规范化路径和执行空间。
- 可选 Git 状态、Diff 和仓库信息。
- 显式打开、下载副本或在终端中打开。
- HTML 文件的源码与安全预览。
本机和远程访问都必须由 Main 或远程 GoodBuddy Agent 在对应文件系统上执行路径规范化、相对路径和
符号链接边界检查。Renderer 只能提交受约束的相对路径和已授权范围 ID。
### 7.7 浏览器
浏览器能力在目录中稳定可发现,打开面板后允许用户:
- 创建新的 GoodBuddy 隔离浏览器会话。
- 选择当前会话或其他受控浏览器会话。
- 查看状态、当前 URL、有界画面和错误。
- 通过顶部浏览器工具栏返回、刷新或停止加载、编辑地址并前往。
- 进入明确的交互模式或关闭浏览器。
顶部工具栏按“返回、刷新/停止加载、地址输入、前往、交互、关闭浏览器”组织。“刷新”在
页面加载期间原位切换为“停止加载”;“关闭浏览器”是清楚独立于导航的会话生命周期操作,
必须与“停止加载”在文案和视觉上明确区分。现有“停止浏览器”语义统一改名为“关闭浏览器”。
浏览器面板和 Agent 操作同一条按 Conversation 归属的浏览器会话,不创建用户预览专用的
第二个页面。用户执行前往、返回或刷新会有意改变 Agent 下一步读取和操作的页面。所有
前往、返回和刷新请求都进入 `BrowserService`,并与 Agent 发起的浏览器操作串行执行;不在
Renderer 建立第二套导航队列、抢占规则或恢复状态机。
浏览器工具栏读取的权威状态至少包含:
```ts
type BrowserToolbarState = {
committedUrl: string
loading: boolean
canGoBack: boolean
sessionActivity: 'inactive' | 'creating' | 'ready' | 'agent_action' | 'full_interaction'
}
```
`committedUrl` 是浏览器已经提交的权威 URL。地址输入在未编辑时与它同步;获得编辑意图后,
输入文字保持为 Renderer 本地草稿,画面、加载状态和 URL 更新不得覆盖草稿,直到用户“前往”
或放弃编辑。用户提交未带 `http://` 或 `https://` 的裸域名时,Renderer 自动补上
`http://`,再通过既有浏览器 URL 策略提交。地址草稿不属于浏览器会话持久状态,也不需要
恢复或版本化机制。
创建会话、Agent 操作和完整交互窗口期间,返回、刷新、地址提交、前往、交互和关闭浏览器
控件禁用,避免与同一会话并发操作。例外是活动导航处于加载中时,“停止加载”保持可用,
可中断当前页面加载;
它只取消页面加载,不销毁浏览器会话、不执行“关闭浏览器”,也不释放当前 Runtime 上下文。
“关闭浏览器”沿用现有停止会话的生命周期语义。
没有浏览器会话时仍显示工具栏。活动 Conversation 可以直接在地址栏输入非空 URL 并“前往”,
由 `BrowserService` 通过 Agent 浏览器相同的能力检查和 URL 策略创建会话并导航;不得为这一
空状态增加旁路 WebView 或宽松 URL 入口。没有活动 Conversation 时说明需要先选择或创建会话。
模型或后台浏览器活动可以更新徽标,但不得无条件打开面板或切换用户当前面板。
浏览器面板只管理 GoodBuddy 受控浏览器,不表示可以控制用户已安装的浏览器。
### 7.8 成果
成果面板统一显示全局、项目、Conversation、Task 执行和监督显式产生的独立成果:
- Markdown、纯文本和 JSON。
- 图片和图表。
- HTML 安全预览。
- 后续的 PDF、Office、表格和其他受支持格式。
普通聊天回复只保留在会话消息流中,不自动复制为成果。只有 Runtime 或受管工具显式声明的
Artifact、自动化和监督生成的独立输出,以及用户手动导入或明确保存的内容进入成果面板。
升级前已经自动保存的普通对话 Markdown 可以从成果列表中隐藏,但不应通过升级迁移物理
删除用户数据库内容。
用户可以切换范围、搜索、预览、查看来源、导出或打开关联对象。成果必须保留项目、
Conversation、Task、内部 Run、创建者、MIME、大小、校验值和时间等可用归属;界面按
Task 呈现来源,不把 Run 作为导航对象。
#### HTML 即时预览
- Runtime 或受管工具通过显式 Artifact 事件声明成果,不能让 Renderer 猜测任意路径。
- Main 验证成果属于当前授权执行空间,限制大小、类型和读取范围后再持久化。
- HTML 使用 `iframe sandbox=""` 和严格 CSP 进行脚本关闭、网络关闭的静态预览。
- 清理脚本、事件属性、嵌套 frame、object、embed、base、link、meta refresh、表单和活动 URL。
- 提供“预览 / 源码”切换,并持续标注“静态安全预览,脚本和网络已禁用”。
- 不使用 `dangerouslySetInnerHTML`,不启用 Electron `webviewTag`。
- 外部打开是明确的用户操作,并说明外部浏览器可能执行脚本或联网。
### 7.9 Composer 与任务上下文
工作栏不提供独立“上下文”能力。用户准备下一次模型请求时:
- 附件、图片、文档提取结果以及知识库范围在 Composer 中展示与管理。
- Composer 提供与发送行为直接关联的预览、移除和清空操作,不在工作栏重复入口或状态。
- 浏览器、工作区文件、授权目录以及 Runtime 或自动化绑定内容由各自能力展示。
- Task 的历史执行上下文作为不可变快照随 Task 查看。
- 记忆功能实现前不展示占位内容;实现后在任务中心按关联 Task 展示和管理。
## 8. 范围和选择模型
### 8.1 通用目标引用
各面板实例使用不包含敏感内容的目标引用:
```ts
type WorkbarCapabilityId =
| 'supervision'
| 'runtime'
| 'terminal'
| 'processes'
| 'workspace'
| 'browser'
| 'results'
type WorkbarTargetRef =
| { type: 'conversation'; id: string }
| { type: 'task'; id: string }
| { type: 'experiment'; id: string }
| { type: 'project'; id: string }
| { type: 'workspace'; id: string }
| { type: 'runtime-session'; id: string }
| { type: 'terminal'; id: string }
| { type: 'managed-process'; id: string }
| { type: 'browser-session'; id: string }
| { type: 'artifact'; id: string }
```
Renderer 选择目标后,Main 必须重新验证对象存在、归属范围和当前用户可见性。不能把目标 ID
直接转换为文件、进程或远程控制权限。
### 8.2 跟随与固定
```ts
type WorkbarScopeBinding =
| { mode: 'follow'; source: 'active-context' }
| { mode: 'pinned'; target: WorkbarTargetRef }
type WorkbarPanelInstance = {
id: string
capability: WorkbarCapabilityId
binding: WorkbarScopeBinding
dock: 'right' | 'bottom' | 'window'
}
```
- 每个面板实例独立保存绑定方式;同一能力的多个实例不能共享可变选择状态。
- 绑定只包含公开 ID,不包含路径、凭据、Token 或日志。
- 删除固定目标后保留失效状态,直到用户选择新目标或恢复跟随。
- 工作栏重新打开、页面切换和窗口重建后恢复用户打开的实例与选择。
## 9. 主机管理与远程执行空间
本节定义产品入口和用户行为。Host Key、凭据、远程 Agent 协议、模型请求代理、签名更新、
断线和 Runtime 适配的技术边界以
[SSH 远程主机与 GoodBuddy Agent 稳定终态设计](../remote-host/technical-design.md)
为准。
### 9.1 设置入口
设置中心“平台功能”提供独立“远程项目(技术预览)”页签及开关,默认关闭。关闭时不显示
“主机与远程执行”分类、托管 SSH 项目创建选项和已保存远程项目,Main IPC 同时拒绝新的
SSH/远程项目操作;已有 Host、项目和凭据保持不变。若当前项目已经是远程项目,则切回
项目列表中的第一个普通
本地项目。重新启用后恢复完整入口和既有数据。
启用后,设置中心显示“主机与远程执行”分类,管理:
- 主机名称、地址、端口和用户名。
- 认证方式和凭据配置状态。
- Host Key 算法与 SHA-256 指纹。
- 引导式身份/认证验证、远程系统和架构。
- GoodBuddy Agent、Runtime 和能力状态。
- 删除、重新验证或更新 Host Key。
主机配置是全局资源。项目或工作栏只引用主机 ID,不能复制凭据。
删除 Host 前列出所有引用它的本地项目记录,包括归档项目;确认后仅删除本机 Host、凭据、
项目和关联数据,不建立 SSH 连接,也不删除远端目录或内容。若当前项目被删除,界面切回
普通本地项目。
当前实施状态:设置中心已经实现主机 CRUD 和模态验证向导。新增或目标/认证编辑依次完成
连接信息、认证前 Host Key 核对、密码/系统 SSH Agent 认证和平台/架构/Shell/Home 有界
探针,全部成功后才原子保存主机、加密凭据和完整 Host Key。认证失败可在弹窗内修改凭据
重试;取消或失败不保留新主机。Key 变化显示旧/新指纹并要求显式高风险确认。项目创建和
设置现可选择托管 SSH、已保存 Host、远端工作目录、OpenCode 和 Ask/Execute,不要求
额外 trust tier 或 consent checklist。候选完成签名 Agent/Runtime、Workspace、ACP、模型桥
和文本模型 profile 验证后原子提交。私钥导入仍未开放。旧流程已保存但
没有成功探针记录的主机继续读取,但在完成新向导前显示为“需要重新验证”。
当前源码已把 Agent/Runtime 生命周期归入 Host 管理。新增或重新验证 Host
在身份、认证和系统探针成功后先保存 Host,再只读探测实际组件状态和瞬时下载能力,然后
结束新增向导。产品不提供自动安装开关,也不在保存后传输包。Host 卡片只有一个按版本
事实显示“安装远程环境”“更新远程环境”或“重新安装”的主按钮;次级 SegmentedControl
选择“自动”“Host 下载”或“GoodBuddy 传输”,默认“自动”且不持久化。版本匹配 badge
不代表环境健康。环境准备失败或取消保留 Host 并显示可重试状态;重新安装失败时显示
本次操作未完成,并以随后重新检查的版本卡片表达当前事实,不对不确定提交宣称旧版本
未被替换。详细技术契约见
[SSH Host 远程环境准备与直连下载设计](../remote-host/environment-provisioning-technical-design.md)。
进入或切回“主机与远程执行”页面只读取本地 Host 列表,不逐台建立 SSH 连接。版本和瞬时
下载能力仅在用户点击某台 Host 的“刷新版本”时探测,成功结果在当前 Renderer 进程内按
Host 持久化缓存,切换页面或重启应用后返回直接显示;Host 编辑、删除或开始更新远程环境后
不复用旧结果。该动作不是项目连接前置条件;用户
切换已有远程项目只更新 Renderer 的本地项目选择,不建立 Host/Agent 连接。
新建远程项目弹窗同样只读取本地 Host 验证记录,不扫描所有 Host;浏览目录或保存时才连接
所选 Host。版本号相同时仍允许用户显式重新安装,以修复 registry、签名或 identity 异常,
且不删除 Host、凭据或项目。由远程主机安装只使用 SSH 和远端系统工具,不依赖已有 Agent;
“自动”仅在操作开始时探测:直连明确可用才选 Host 下载,否则选 GoodBuddy 传输;用户
显式选择不被改写,prepare、commit 或 adoption 失败后不在同次操作中切换 acquisition。
项目选择器中每个项目的管理按钮默认隐藏,在悬停、键盘焦点或触屏环境显示。该入口直接
打开目标项目设置而不先切换项目,因此 Host 不可达或远端目录已不存在时仍可删除本地项目
记录;删除操作从不删除远端项目内容。
应用重启后固定进入项目列表中的第一个普通本地项目。用户主动打开已有托管 SSH 项目时只
切换本地项目配置;首次实际使用 Workspace 或 Runtime 时,Main 才通过 Agent/Runtime
安装管理器解析 Host current identity,执行固定 `attach-or-bootstrap`,并使用同一 Agent
连接。
项目数据库不保存 Agent installation、Host revision、Workspace identity 或 Runtime
digest。当前 registry、连接或 capability 无效时项目保持未切换,并提示到 Host 管理显式
修复。当前进程缓存每个 Host 已确认的 Agent/Runtime identity,并复用 Agent 连接;Host
编辑或环境更新会定向清空。Agent 的 attach/按需启动只读取 Host 管理已提交的 registry 与
匹配 manifest 元数据,不重新验签或哈希完整 Agent payload。项目切换器立即提交本地选择,
不展示远程激活进度;完整进度和取消只属于新建或显式保存项目。
项目只持久化 Host ID、规范远端路径、Runtime 选择和默认工作模式。新建和保存验证当前
Workspace/Runtime,但不写入组件 identity;普通切换不做远程验证。未就绪或版本过旧时,
实际 Workspace/Runtime 操作显示错误。桌面更新造成组件版本变化时,用户先在 Host 管理中
准备环境;项目切换本身不连接、不下载、不扫描、不安装,也不改写项目。
已保存 Host 的地址、用户或固定 Host Key 变化后,Main 关闭旧连接并定向退役该 Host 的
Runtime 缓存。引用项目下次选择时使用 Host 管理的当前 revision、Host Key 和用户执行固定
attach 并读取 current registry,不存在项目中的旧 Host revision 或组件 identity;
当前环境无效时才要求显式修复。
新建托管 SSH 项目时,远端工作目录既可手工输入,也可通过文件夹按钮打开 Main 管理的
只读、有界 SFTP 目录选择器。选择器从 SSH 账号 Home 或当前有效绝对路径开始,只返回目录,
支持上级、刷新、取消和选择当前目录;Host 变化、连接错误或取消都保留草稿,选择结果不会
绕过正常项目验证与保存事务。
### 9.2 凭据和主机验证
- 优先支持系统 SSH Agent 或 OpenSSH 证书。
- 导入私钥或密码时使用 Electron `safeStorage` 加密。
- 凭据绑定主机 ID、地址、端口、用户名和认证类型。
- Renderer 只接收 `credentialConfigured`、来源和错误状态。
- Host Key 检查使用 Main 内五分钟有效、目标绑定的临时候选,检查阶段不接收认证凭据;
认证和系统探针成功前不持久化新增主机,取消或失败不留下主机或密码。
- 首次连接必须在发送密码、私钥签名或 SSH Agent 签名前取得并展示 Host Key 算法和
SHA-256 指纹,由用户显式接受;持久化完整 Host Key 或可信 Host CA,不能只保存展示指纹。
- Host Key 变化硬失败,并通过独立高风险流程替换。
- 禁止 `StrictHostKeyChecking=no` 和默认 SSH Agent Forwarding。
- 命令参数、URL、日志、SQLite 明文和 IPC 响应中不得出现私钥或密码;用户在受信任表单
输入的密码只通过严格校验的单用途 IPC 请求交给 Main,Renderer 不得读取已保存密码。
### 9.3 远程 GoodBuddy Agent
远程能力通过版本化 GoodBuddy Agent 提供:
- 安装到远程当前用户的 GoodBuddy-owned 目录,不要求 root。首次连接先 attach,Agent
不存在或未运行时幂等 bootstrap 为 detached process,再重新 attach;不注册开机服务,
不依赖 systemd、D-Bus 或 `Linger=yes`。
- SSH 负责 Host Key、认证、固定 bootstrap、可选 SFTP 安装和 `goodbuddy-agent attach`
中继;attach 只连接用户私有 Unix socket。SSH relay 断开不终止 Agent 或活动 Runtime。
- Host 环境准备可让远端按签名目录固定的 GitHub/北京镜像 URL、大小和 SHA-256 下载完整
`.gbagent`,也可由 GoodBuddy 下载、完整验证后通过有界流式 SFTP 传输一个 compound
archive 和归档中已验证的 bootstrap Node;完整包不一次读入 Main `Buffer`,Host 仍再次
校验。两种 acquisition 交付到固定 operation staging 后共用
`prepare → commit → Agent activate/health → Runtime activate → finalize → cleanup`。
- 直连首次 bootstrap 不依赖已安装 Agent daemon。GoodBuddy 桌面控制面通过固定 SSH
prepare channel 发送有界 one-shot installer;Host 先验证目录绑定的归档大小和 SHA-256,
再由 format v1 归档内固定 Node 解码并运行 installer。归档无需包含
`agent/lib/package-installer.cjs`,目录不提供或检查额外的 bootstrap 能力元数据。
- Agent 与 Runtime 各自维护版本,签名摘要标识精确工件。Host 在解包到准备目录的同一遍
处理中完成完整 payload 校验,commit 只复核签名 metadata 并原子替换 side-by-side
目录,不重新读取归档、扫描旧目录或使用跨安装硬链接。
- Main 只保存清理 operation staging 所需的 operation ID。控制通道中断或 adoption 失败
后,下次更新尽力清理旧暂存并重新 prepare,不保存或恢复 Agent/Runtime metadata 副本。
新 Agent/Runtime 各自最多完整验证一次;注册后的
health、capabilities 和 prompt 启动只检查 registry、签名 manifest 与入口 metadata。
确认 adoption 后显式 cleanup,cleanup 失败不回滚健康环境,也不阻塞下一次 fresh prepare。
- 握手报告 installation、Daemon boot identity、协议、系统、架构、用户监督器和能力。
- 在远程执行路径规范化、Git、文件、PTY、进程组和 Runtime 管理。
- 持久化有界 Agent 到 Main 输出;SSH 断开后 Agent 继续运行,同一 Agent 重连时只恢复
可确认的输出。Main 到 Runtime 的输入、工具、模型和 blob 请求不自动重放。
- 对有副作用的请求使用稳定 operation ID 和 payload digest 去重;结果无法证明时进入
`outcome-unknown`,禁止自动重放。
- 对事件、日志、journal、文件、帧、超时、并发、缓存和总传输量设置硬上限。
- Daemon、Runtime、受管进程和用户终端分别具有明确 lease、取消、drain 和回收语义。
- Agent 不可用或身份不匹配时远程执行失败,不退化为 SSH stdio Runtime。
Host Key、远端用户或目标变化会关闭旧连接,并使绑定旧 Host identity 的 Workspace 和
Runtime 会话失效。产品不维护 T1/T2/T3 等附加信任层级。
### 9.4 远程 Runtime
- Runtime 在远程执行空间内运行,不能让本机 Runtime 对远程路径进行伪本地操作。
- Main 保持可信控制面,远程 GoodBuddy Agent 只接受有范围、有期限的请求。
- GoodBuddy 控制协议负责 Agent、Workspace、Git、Process、Blob 和 Runtime supervision;
Runtime Session、stream、tool、permission、usage 和取消优先复用 ACP。
- Ask 的只读限制在远程 GoodBuddy Agent 和 Runtime 适配层共同强制。
- Execute 是用户对所选 SSH 账号完整权限的授权,直接以该账号可用的文件、进程、网络和
工具能力运行,不要求逐工具审批或第二个“受控执行”模式。取消、超时、输出上限和活动
记录继续保留。
- GoodBuddy 模型凭据和 Provider URL 必须留在 Main。远程 Runtime 只获得不含凭据的模型
policy、私有 Unix socket、隔离 loopback endpoint 和 Prompt-bound blob channel;
Main 按 durable round、profile digest、调用次数、最坏输出 token 预留和最终 delivery ACK
代发,不得把原始 API Key 或认证头发送到远端。
- 不向远程 Runtime 暴露通用本机 MCP、浏览器、文件系统或其他未分配能力。
## 10. Runtime 与进程统一生命周期
需要新增统一、受限的生命周期模型:
```ts
type ManagedLifecycleState =
| 'starting'
| 'running'
| 'waiting_approval'
| 'paused'
| 'reconciling'
| 'stopping'
| 'completed'
| 'failed'
| 'cancelled'
| 'interrupted'
| 'outcome_unknown'
```
每个 Runtime 会话、Task 级执行、终端或受管进程公开:
- GoodBuddy 受管 ID。
- 类型、来源和父子关系。
- 执行空间和范围。
- 状态、开始与结束时间。
- 支持的控制动作。
- 有界进度、用量和日志游标。
控制动作按能力声明:
```ts
type ManagedControl =
| 'cancel'
| 'terminate'
| 'force-terminate'
| 'pause'
| 'resume'
| 'reconnect'
| 'release'
```
界面不能因为状态枚举中存在某个动作就假设所有 Runtime 都支持。Main 根据当前受管对象和
能力重新验证动作。内部 Job/Run 快照可以支持聚合与审计,但不能成为
`WorkbarTargetRef` 或独立 UI 对象。
## 11. 数据与契约建议
### 11.1 共享 Zod 契约
建议新增:
- `workbar-contracts.ts`
- `managed-process-contracts.ts`
- `terminal-contracts.ts`
- `remote-host-contracts.ts`
- 通用 Artifact Event 和 Preview 契约
- Runtime Inspector Snapshot 和 Control 契约
所有输入严格限制字符串、数组、日志、帧、路径、端口和事件数量。公开快照不得包含:
- 凭据和认证头。
- 完整环境变量。
- 任意本机或远程绝对路径,除非该路径本身是用户当前可见对象。
- 未经限制的 stdout/stderr、文件或 Runtime 响应。
- 可直接传给系统 kill、spawn、Shell 或 SSH 的自由参数。
### 11.2 持久化
建议增加:
```text
workbar_preferences
remote_hosts
terminal_sessions
managed_processes
runtime_sessions
runtime_jobs
remote_agent_installations
remote_operations
```
其中:
- 工作栏偏好只保存能力目录顺序、面板实例、停靠布局、尺寸和目标引用。
- 主机表只保存非敏感元数据和加密凭据引用。
- 应用重启后先通过远程 Daemon 的 journal、lease、boot identity 和 event cursor 核对活动
终端、进程与 Runtime;无法确认时标记 `interrupted` 或 `outcome_unknown`。
- 日志使用有界环形缓冲或分页持久化,不能无限写入 SQLite。
- Artifact 继续作为成果的权威实体,不把完整成果复制进工作栏状态。
- 当前 Renderer `localStorage` 活动记录不能作为 Runtime、监督或进程的权威来源。
### 11.3 IPC 与 Preload
Renderer 只通过显式方法访问:
- 工作栏偏好和目标绑定。
- 主机 CRUD、临时 Host Key 检查、验证并原子保存。
- 终端创建、输入、调整大小、关闭和有界输出订阅。
- 受管进程列表、日志和允许的控制动作。
- Runtime Inspector 快照、事件和允许的控制动作。
- 工作区、成果、浏览器和监督的既有或扩展服务。
每个 Main Handler 都必须验证可信发送者、Zod 输入、对象归属和当前状态。不得暴露 raw
Electron、ChildProcess、PTY、SSH Client、Socket 或文件句柄。
## 12. 安全边界
1. 工作栏能力目录项和面板实例不授予任何能力;权限只由 Main 中的范围和控制契约产生。
2. Ask 在本机和远程 Runtime 边界保持只读。
3. Execute 继续经过现有 Runtime 和审批控制,工作栏不能直接放宽。
4. 用户终端和 Agent 工具执行使用不同身份和事件来源。
5. 进程面板只控制 GoodBuddy 受管对象,不接受任意 PID。
6. 本机和远程路径分别在对应文件系统上 canonicalize 并验证符号链接边界。
7. HTML 默认静态、无脚本、无网络、无 Electron API。
8. Supervisor 不接收授权回调,不能批准工具或替用户发送消息。
9. SSH Host Key 必须固定,凭据保留在 Main 加密存储。
10. 远程端只获得请求级、可撤销、最小范围能力。
11. 关闭面板或切换目标、主机或 Runtime 时,旧订阅必须取消;其他固定实例的订阅明确保留。
12. 通知、徽标和日志不得包含密钥、私人正文或未脱敏提供商响应。
## 13. 状态、错误和恢复
每个面板实例区分:
- 尚未选择目标。
- 目标为空。
- 正在连接或加载。
- 正常可用。
- 部分可用。
- 当前能力不支持。
- 连接失败。
- 权限不足或只读。
- 目标已失效。
- 操作已取消或中断。
错误必须保留用户选择、终端缓冲、输入草稿、范围和可重试上下文。短期成功和非局部错误使用
应用通知;预览失败、终端断线、Host Key 变化、监督证据失效等需要本地恢复的错误留在面板
内。同一事件不得同时重复显示为面板警告和应用通知。
## 14. 性能与资源边界
- 工作栏关闭或面板实例关闭时停止对应非必要画面和高频日志推送,但保留 Main 中的受管运行。
- 每个打开的面板实例只订阅其跟随或固定目标,不进行全局无界监听。
- 终端和日志使用增量序号、环形缓冲和背压。
- HTML、文件、目录、浏览器画面和远程传输沿用或收紧现有大小限制。
- Runtime Snapshot 与事件流分离,重新打开时先取权威快照,再接增量事件。
- 监督使用独立低优先级并发池和预算,不延迟前台回答。
- 应用退出时停止新操作并让用户选择取消、等待或 detach;关闭 SSH attach 不卸载或终止
用户级 GoodBuddy Agent Daemon。依赖 Main 模型网关、审批或本机工具的 Run 不能被描述为
可以无人值守继续。
## 15. 无障碍与响应式
- 能力目录、所有面板实例、目标选择器、终端控制和进程操作可用键盘完成。
- 能力目录与面板标题具有稳定可访问名称,徽标不是唯一状态信号。
- 终端需要独立可访问说明,并允许关闭动画和声音提示。
- 进程和 Runtime 高频日志不逐行进入实时区域,只播报重要状态变化。
- 监督证据定位后将焦点移动到对应对象,并提供返回监督记录的方式。
- HTML iframe 有明确标题、静态安全说明和源码替代视图。
- 窄窗口下能力目录仍完整可达,不因空间不足隐藏能力。
- 文字缩放到 200% 时,当前目标、执行空间、风险状态和停止操作不能被裁切。
## 16. 分阶段实施
本节只表示内部依赖顺序,不表示可以发布临时架构。SSH 远程执行只使用用户级 Daemon,
不发布连接期 stdio Agent。OpenCode Ask、OpenCode Execute 和后续 Runtime 分别通过自身的
安装、权限、取消和重连门槛后开放,未完成的能力继续显示不可用。
### 阶段 0:应用级工作栏壳层
- 将当前聊天专属右栏提升为应用级壳层。
- 建立稳定能力目录和用户打开、关闭、排序、停靠的面板实例模型。
- 建立实例级跟随、固定和失效目标语义。
- 保留现有任务中心、工作区、浏览器和成果行为;附件与知识库继续由 Composer 管理。
- 将 Task Center 明确为 Task 的单例索引,并补齐范围、状态、最近进展、需要关注和直接打开 Conversation。
- 审批在所属任务或 Runtime 中持续可见,不新增独立审批面板。
- 智能心跳菜单入口承接完整配置和范围后,再从任务中心移除重复表单;不得移除任务中心本身。
### 阶段 1:成果与 Runtime 可观测性
- 通用 Artifact Event。
- HTML 工作区和成果的静态即时预览。
- Runtime Inspector Snapshot 与事件。
- OpenCode 会话、子会话、Todo、工具、用量和取消;本地与托管 SSH 的原生 Task 调用在
Conversation 中统一显示为可追踪的 Subagent 状态,而不是普通工具参数卡。
- 直连模型、OpenCode 原生 Subagent 及现有 GoodBuddy Subagent 的统一展示。
### 阶段 2:监督、终端与受管进程
- 普通会话手动监督和右栏评论流。
- 工作栏持久“+”、应用注册表和单/多实例 Tab。
- 本机 PTY 与直接 SSH PTY 多终端。
- 受管进程注册、日志和终止。
- 自动回复后监督、节流和独立预算。
- 用户选择终端停靠位置。
### 阶段 3:Runtime 原生长期能力
- Continue 会话级 Host。
- Continue Background Job、Subagent 和 Hook 的有界适配。
- DeepSeek Harness 后续服务的能力握手。
- Runtime Job、Workflow 和会话恢复契约。
### 阶段 4:SSH 主机与远程执行空间
- [x] 引导式主机管理、先验证后保存、密码安全存储、系统 SSH Agent、Host Key 固定和
有界系统探针。
- [ ] 私钥与受限 OpenSSH config 导入。
- 签名、side-by-side GoodBuddy Agent 安装和按需 detached Daemon。
- SSH connection pool、固定 attach relay、Agent 控制协议、Agent 本地 ACP 日志和断线重连同步。
- 远程工作区、Git、终端和受管进程。
- 先完成签名 OpenCode bundle、Ask bubblewrap、Execute 直接进程、官方 ACP channel、
Main 模型网关、取消、超时和活动记录。
- OpenCode 闭环稳定后,Continue 与 DeepSeek Harness 复用相同面板和通道契约逐个接入。
- 新增或重新验证 Host 时只保存并探测 Agent/Runtime,不自动安装。用户在 Host 卡片用
单一主按钮启动,并用次级控件选择自动、Host 下载或 GoodBuddy 传输;Host 保存与环境
准备是两个可独立重试的事务。
- 控制面直连源码直接使用既有 package format v1 包;不等待发布携带 installer 的新
Agent 包,也不通过额外目录元数据判断 bootstrap 能力。GitHub/北京镜像、
Linux x64/arm64、取消和离线 GoodBuddy 传输仍须真实 Host 验收,不能据此声称已发布或已完成
真实 Host 测试。
- 一次远程项目保存请求完成 Host/Agent/Workspace/Runtime 当前环境验证和 SQLite 原子
提交,但只持久化 Host、路径、Runtime 选择和模式,也不获取或安装组件。
- 桌面更新后,用户先在 Host 管理中更新当前签名 Agent/Runtime;远程项目下一次实际使用
Workspace/Runtime 时直接使用新的 current 环境,无需刷新项目绑定。应用启动和项目切换
本身都不连接 Host,也不下载或安装组件。
- SSH、Main、Daemon、Runtime 和远端重启后的核对、恢复与 `outcome_unknown`。
- 支持平台的安装、Ask、Execute、取消和重连冒烟测试通过后开放对应 OpenCode 能力。
### 阶段 5:开放后的扩展
- 更多远程系统和架构。
- PDF、Office 和数据成果预览。
- Conversation、Task 和实验的完整监督。
- 用户可导入导出工作栏布局和主机非敏感配置。
## 17. 验收标准
### 17.1 稳定能力目录与用户控制
- [ ] 八个标准能力在所有主要页面的目录中始终可发现,但不会默认同时打开。
- [ ] Task Center 继续作为 Task 的单例索引,不删除入口、不复制会话,也不混入 Job、Run 或心跳事项。
- [ ] 项目、会话、Runtime 或主机变化不会无提示地增删能力目录项。
- [ ] 用户可以按需打开、关闭、排序和停靠面板实例。
- [ ] 用户可以独立设置每个可绑定目标的面板实例跟随或固定目标,并为同一能力打开多个目标实例。
- [ ] 固定目标失效后显示修复状态,不静默切换。
- [ ] 后台事件不会无条件打开面板或抢占用户当前实例。
- [ ] 用户可一键恢复标准能力目录和默认的少量打开面板。
### 17.2 通用使用
- [ ] 没有项目时仍可创建终端、选择工作区、打开浏览器和查看成果。
- [ ] 监督可以作用于普通 Conversation、Task 和后续实验对象,不假设编程语境。
- [ ] 工作区不是 Git 仓库时仍可浏览文件。
- [ ] Runtime 不支持某项原生能力时仍可从目录打开面板并获得准确说明。
### 17.3 安全与控制
- [ ] Renderer 没有任意文件、Shell、进程、PTY、SSH 或 Electron API。
- [ ] Agent 不能未经授权向用户终端注入命令。
- [ ] 进程面板不能枚举或终止任意系统进程。
- [ ] Ask 在本机和远程执行空间均无法调用写入或外部副作用工具。
- [ ] HTML 预览无法执行脚本、联网、打开窗口、提交表单或访问 Electron API。
- [ ] Supervisor 不能自动发送消息、批准工具、切换工作模式或扩大范围。
- [ ] SSH 首次连接和 Host Key 变化均经过明确验证流程。
- [ ] 凭据不进入 Renderer、日志、SQLite 明文或命令参数。
- [ ] Host 地址、用户或 Host Key 变化会关闭旧连接,并使旧 Workspace 和 Runtime 会话失效。
### 17.4 生命周期与恢复
- [ ] Runtime、终端、Task 级执行和进程具有权威 Main 快照和有序增量事件。
- [ ] 取消、终止、失败、断线和应用退出都有确定终态。
- [ ] 远程执行只通过按需 detached Daemon 提供,SSH attach 断开不销毁 Daemon 状态。
- [ ] 重连先恢复 event cursor 并查询 operation;有副作用操作不会自动重放,无法确认的
结果显示为 `outcome_unknown`。
- [ ] Agent side-by-side 更新支持所需签名版本的健康切换,失败时保留旧项目绑定。
- [x] 新增 Host 只探测远端下载能力,不提供自动安装开关,也不传输完整包;Host 卡片用
一个按版本事实命名的主按钮与不持久化的 acquisition SegmentedControl 启动准备。
- [x] 创建、保存、打开和切换托管 SSH 项目都从 Host current registry 与当前 Agent
连接验证环境;项目只保存稳定配置,且这些流程不下载 `.gbagent`、上传 payload 或发布
安装。
- [ ] 切换跟随目标后不显示上一对象的过期状态。
- [ ] 固定目标的订阅在页面切换后保持,关闭时正确释放。
- [ ] 日志、终端、文件、成果和远程传输均有明确上限和背压。
### 17.5 可用性
- [ ] 宽、中、窄窗口均可访问完整能力目录和用户打开的面板实例。
- [ ] 工作栏在宽、中、窄窗口展开时都推动主工作区回流,不覆盖、遮罩或隔离主内容;唯一
开关始终固定在窗口关闭按钮正下方。
- [ ] 仅使用键盘可以选择能力、面板实例、目标、执行空间和控制动作。
- [ ] 状态不只依赖颜色,徽标具有文字或可访问名称。
- [ ] 终端、HTML、监督证据和高频日志具有可访问替代或降噪行为。
- [ ] 浏览器 Tab 顶部工具栏始终清楚区分“停止加载”和“关闭浏览器”;地址编辑草稿不会被
权威状态刷新覆盖,用户与 Agent 的导航通过同一 `BrowserService` 会话串行执行。
- [ ] 创建中、Agent 操作中和完整交互期间禁用浏览器其余工具栏控件;活动加载仍可单独停止,
且停止加载不会关闭会话或释放 Runtime 上下文。
- [ ] 活动 Conversation 没有浏览器会话时,可从同一地址栏按 Agent 相同 URL 策略启动会话。
## 18. 相关文档的职责
- 本文是助手工作栏稳定能力目录、用户面板实例、范围控制和执行空间的产品总契约。
- [助手工作栏多终端页签 PRD](./terminal-tabs-prd.md) 定义持久“+”、应用实例策略、
动态 Tab 以及本机与直接 SSH 多终端。
- [Task 与 Job 统一领域模型](../task-and-job/task-and-job-model.md) 定义 Task、Conversation、
Job、Subjob、Run 与 Subagent。
- [Task Center PRD](../task-and-job/task-center-prd.md) 定义应用级 Task 索引。
- [智能心跳 PRD](../smart-heartbeat/prd.md) 定义心跳入口、范围和长期边界。
- [会话监督 PRD](../conversation-supervision/prd.md) 定义监督判断、证据、预算和介入边界。
- [自动化平台总体设计](../../architecture/automation-platform-architecture.md) 定义 Plan、Job、Run、监督、预算和记忆。
- [长期助手路线图](../../roadmap/long-term-assistant-roadmap.md) 记录整体长期能力与实施背景。
- [DeepSeek Harness Runtime 设计](../deepseek-harness/technical-design.md) 定义该 Runtime 的具体适配边界。
- [SSH Host 远程环境准备与直连下载设计](../remote-host/environment-provisioning-technical-design.md)
定义 Host 级组件获取、首次准备、更新、回退和项目只验证边界。
- [统一界面设计系统](../../../UI-DESIGN.md) 定义视觉、语义、响应式和无障碍规则。
若其他文档把工作栏描述为八个同时固定显示的栏目、根据项目或 Runtime 自动裁剪的动态入口,
或仅属于当前聊天的附属区域,以本文“能力目录稳定、面板实例由用户打开、当前上下文只提供
默认值”的产品决策为准。
@@ -0,0 +1,582 @@
# 助手工作栏多终端页签 PRD
## 文档信息
| 项目 | 内容 |
| --- | --- |
| 状态 | 已实施,跨平台验证中 |
| 版本 | 1.1 |
| 日期 | 2026-08-31 |
| 适用产品 | GoodBuddy 桌面端 |
| 界面归属 | [通用助手工作栏与执行空间](./prd.md) |
| 相关设计 | [统一界面设计系统](../../../UI-DESIGN.md) |
| 远程架构 | [SSH 远程主机与 GoodBuddy Agent 实现说明](../remote-host/technical-design.md)、[SSH Host 远程环境准备与控制面直连设计](../remote-host/environment-provisioning-technical-design.md) |
## 1. 文档职责
本文细化助手工作栏中的以下行为:
- 已打开应用以同级 Tab 呈现。
- Tab 行始终提供“+”入口,用户按需打开应用。
- 应用通过统一注册表声明单实例或多实例策略。
- “终端”作为首个多实例应用,自动使用当前项目的本机或托管 SSH 执行空间。
- 本机与远程交互式终端的生命周期、状态、性能和验收要求。
[通用助手工作栏与执行空间 PRD](./prd.md)
继续负责工作栏的应用级位置、稳定能力目录、执行空间、范围绑定和总体产品边界。本文不重新
定义 Host Key、凭据、Agent 安装、Ask/Execute Runtime 或项目持久化契约。
## 2. 背景与当前问题
当前工作栏在聊天页面右侧固定显示“任务中心、工作区、浏览器、成果”四个 Tab。用户不能:
- 通过统一入口按需打开新的工作栏应用。
- 关闭并重新打开一个工作栏应用。
- 为支持多实例的应用创建第二个独立实例。
- 在 GoodBuddy 内使用本机或远程 Host 的交互式 Shell。
当前代码已经具备工作栏右侧回流、宽度调整、Tab 键盘导航、SSH Host Key 固定、加密凭据和
SSH 连接池,但尚不存在工作栏应用实例模型、终端 IPC、终端 Session Manager 或终端模拟器。
`node-pty` 当前只作为其他 Runtime 的间接依赖被打包,不能视为已经存在用户终端能力。
## 3. 产品定义
### 3.1 工作栏应用
工作栏应用是可以在助手工作栏中打开的一个能力,例如任务中心、工作区、浏览器、成果或
终端。每项应用通过统一注册表声明:
- 稳定应用 ID。
- 用户可见名称、图标和说明。
- `single` 或 `multiple` 实例策略。
- 创建实例时可用的默认上下文。
- 当前不可用时的原因和修复入口。
目录中的应用可发现性与实例是否已经打开相互独立。应用不可用时保留入口并说明原因,不以
隐藏代替状态。
### 3.2 工作栏 Tab 实例
工作栏 Tab 是应用的一次打开实例。每个实例具有独立 ID、标题、应用类型和状态。Tab 行只
显示已经打开的实例,不把全部能力同时渲染为 Tab。
### 3.3 终端实例
每个终端 Tab 对应一个独立交互式 Shell Session:
- 本机终端由桌面 Main 进程管理本机 PTY。
- 远程终端通过现有、已验证的 SSH Host 打开直接 SSH PTY。
- 不同终端拥有独立 Shell、工作目录、输入、输出、尺寸和结束状态。
- 创建后固定到当时选择的执行位置,切换项目不会迁移已经运行的终端。
直接 SSH PTY 是用户操作的远程终端,不是连接期临时 GoodBuddy Agent,也不作为 Runtime
stdio fallback。首期远程终端随 SSH Channel 结束,不提供跨 SSH 或桌面重启的进程恢复。
## 4. 已确认的产品决策
1. 工作栏 Tab 行末尾始终显示“+”按钮。
2. “+”是普通命令按钮,不是一个 `tab`。
3. 点击“+”在工作栏内容区显示“新建工作栏应用”选择页;取消后返回原活动 Tab。
4. 选择应用后创建或激活实例,并关闭临时选择页。
5. 单实例应用已经打开时,再次选择只聚焦已有实例,不创建重复 Tab。
6. 多实例应用每次选择都创建新实例。
7. 终端从首期开始就是多实例应用。
8. 任务中心、工作区、浏览器和成果首期保持单实例;后续只需修改应用注册表策略即可开放
多实例,不重写 Tab 壳层。
9. 现有四个应用在升级后仍按当前默认布局打开,避免用户入口突然消失。
10. 用户关闭、切换或重排应用 Tab 后,“+”仍保持可见。
11. 选择“终端”后不再显示第二层目标选择器。存在当前项目时直接绑定该项目,由 Main
根据项目执行空间自动打开本机或托管 SSH Shell;没有当前项目时打开本机 Home Shell。
12. 远程首期使用直接 SSH PTY。SSH 断线后终端进入“已中断”,重新连接会创建一个新的
Shell,不伪装为恢复旧进程。
13. 工作栏收起、切换主页面或切换 Tab 不终止终端;显式关闭终端 Tab 才终止对应 Shell。
14. 应用重启不自动启动 Shell。恢复的终端 Tab 显示“会话已结束”,由用户显式重新连接。
15. 终端是用户交互表面。Ask/Execute 继续约束 Agent Runtime,不把用户键盘操作误判为
Agent 工具调用;Agent、自动化和模型不得未经明确用户操作向终端注入输入。
16. 工作栏继续按上位 PRD 提升为应用级容器;切换聊天、知识、魔法笔记或活动记录等主页面
不销毁 Tab 实例或终端 Session。
## 5. 目标
### 5.1 用户目标
- 在工作栏中随时通过“+”发现并打开应用。
- 同时打开多个本机或远程终端,并通过 Tab 快速切换。
- 清楚知道每个终端运行在本机还是哪个远程 Host、当前目录和连接状态。
- 在终端断线、退出或目标失效后获得准确状态和明确恢复操作。
- 使用键盘完成打开应用、切换 Tab、操作终端和关闭实例。
### 5.2 产品目标
- 用一个可扩展的应用注册表统一单实例与多实例行为。
- 把现有固定四 Tab 迁移为用户实例,而不回归现有任务中心、工作区、浏览器和成果能力。
- 建立真实的 Main/Preload/Renderer 终端生产链路,而不是用普通文本框模拟终端。
- 复用现有 SSH Host Key、凭据和连接池,不建立第二套 Host 管理。
- 保持终端输入输出有序、响应流畅、内存有界,并可靠清理本机和远程资源。
## 6. 非目标
- 不把 GoodBuddy 改造成完整 IDE。
- 不唤起 Windows Terminal、Terminal.app 等外部终端窗口代替内嵌终端。
- 不扫描或导入用户全部 SSH config、目录、Shell profile 或命令历史。
- 不支持任意 `ProxyCommand`、端口转发或 SSH Agent Forwarding。
- 不在打开远程终端时安装、更新或修复 GoodBuddy Agent。
- 不把 Agent 工具调用、Runtime 日志或自动化输出伪装成用户终端。
- 不允许 Renderer 直接访问 PTY、ChildProcess、SSH Client、凭据或 Node API。
- 首期不提供终端协作、录制、云同步、Shell Session 复用、tmux 管理或跨设备恢复。
- 首期不实现底部停靠和独立窗口;本文保留兼容模型,后续按工作栏总 PRD 扩展。
- 首期不通过 GoodBuddy Agent 恢复远程终端,也不为终端复制 Runtime transcript、
`outcome_unknown` 或模型调用恢复协议。
## 7. 信息架构与“+”交互
### 7.1 Tab 行
```text
┌──────────────────────────────────────────────┐
│ 任务中心 │ 工作区 │ 终端 1 │ 终端 2 │ + │
├──────────────────────────────────────────────┤
│ 当前活动实例内容 │
└──────────────────────────────────────────────┘
```
- 已打开实例位于一个语义化 `tablist` 中。
- 每个实例使用独立 `tab` 和 `tabpanel`。
- “+”固定在 Tab 行末尾,但位于 `tablist` 之外。
- Tab 过多时实例区域单行横向滚动,“+”保持可见;不换行、不自动隐藏实例。
- 终端 Tab 默认使用递增标题,例如“终端 1”“终端 2”;状态栏持续显示项目、Host、
工作目录和 Shell。用户可以重命名终端。
- 当前 Tab 同时使用连续内容表面、选中边框、顶部强调线、图标和较高字重,不能只靠文字颜色。
- Tab 关闭按钮默认不争夺视觉注意力,仅在鼠标悬停或键盘焦点进入对应 Tab 时出现;
粗指针或无悬停设备始终显示,出现与隐藏不得引发布局位移。
### 7.2 新建应用选择页
点击“+”后:
1. 保留当前实例及其运行状态。
2. 在工作栏内容区显示“新建工作栏应用”。
3. 列出稳定应用目录,每项显示名称、说明、单/多实例提示和当前可用状态。
4. 初始焦点进入第一个可用应用;Escape 或“取消”返回原活动实例和“+”按钮。
5. 选择单实例应用时,若实例已存在,直接聚焦该 Tab。
6. 选择终端时直接解析当前项目执行空间,创建新 Tab 并聚焦终端输入,不再要求用户
重复选择本机或远程目标。
选择页是“+”触发的临时界面,不进入实例顺序,不持久化,也不占用一个普通 Tab。
### 7.3 首期应用注册表
| 应用 | 实例策略 | 升级后默认状态 | 再次从“+”选择 |
| --- | --- | --- | --- |
| 任务中心 | `single` | 打开 | 聚焦已有 Tab |
| 工作区 | `single` | 打开 | 聚焦已有 Tab |
| 浏览器 | `single` | 打开 | 聚焦已有 Tab |
| 成果 | `single` | 打开 | 聚焦已有 Tab |
| 终端 | `multiple` | 不打开 | 每次创建新 Tab |
实例策略是应用注册数据,不能分散硬编码在多个点击处理器中。
### 7.4 Tab 操作
- 点击或使用方向键切换实例不会暂停或终止后台实例。
- 支持左右方向键、Home、End 和 roving `tabindex`。
- 关闭非活动 Tab 后焦点保持在当前活动 Tab。
- 关闭活动 Tab 后激活右侧相邻实例;没有右侧实例时激活左侧实例。
- 关闭最后一个实例后显示明确空状态和“打开应用”,Tab 行仍保留“+”。
- 关闭正在运行的终端需要确认“关闭终端将结束 Shell 及其子进程”;取消是初始焦点。
- 已退出或已中断的终端可以直接关闭,不重复确认。
## 8. 终端创建流程
### 8.1 自动目标解析
- 当前项目是本地项目时,创建目标为公开 Project ID,Main 从权威项目记录解析本机根目录。
- 当前项目是托管 SSH 项目时,创建目标仍为公开 Project ID,Main 再解析项目 Host、
固定 Host Key、凭据和远端根目录。
- 没有当前项目时使用本机目标和当前用户 Home。
- Host 未验证、凭据不可用或不支持交互式 Shell 时,终端 Tab 就地显示失败原因和恢复入口,
不静默切换到本机或其他 Host。
### 8.2 本机终端
- 当前项目是本地项目时,默认工作目录为项目根目录。
- 没有本地项目目标时,默认工作目录为当前用户 Home。
- Windows 优先使用可用的 PowerShell 7,其次 Windows PowerShell,最后使用系统
`COMSPEC`。
- macOS 和 Linux 优先使用当前用户有效的 `$SHELL`,不可用时使用平台常规 Shell fallback。
- 首期自动选择默认 Shell,不提供任意可执行文件路径输入。
- Main 只向 Shell 传递正常交互所需的筛选环境,不注入模型 API Key、GoodBuddy 内部
Token 或其他产品凭据。
### 8.3 远程终端
- 当前项目是托管 SSH 项目时,自动使用项目 Host 和远端项目根目录。
- Main 复用现有 Host store、完整 Host Key 固定、认证方式和 SSH connection pool。
- 远端通过 SSH PTY 打开账号的登录 Shell,并支持输入、ANSI 输出和窗口尺寸同步。
- 活动终端持有专用 Channel lease,不得被连接池空闲回收。
- 不把密码、私钥、认证头或 GoodBuddy 模型凭据发送给 Renderer 或写入终端环境。
- Host 地址、用户、凭据或 Host Key generation 变化时,旧 Session 进入“已中断”,新建
Session 必须使用 Host store 中的当前身份。
### 8.4 创建结果
创建成功后:
- 新 Tab 插入当前活动 Tab 右侧并立即激活。
- 焦点进入终端输入区域。
- 状态栏显示“本机”或 Host 名称、工作目录、Shell 和连接状态。
- 终端尺寸使用内容区计算出的首个有效 `cols/rows`,不是固定默认值覆盖实际布局。
创建失败时在终端 Tab 保留错误上下文并提供重试;不得留下不可回收 Session 或显示为已经连接。
## 9. 终端交互与状态
### 9.1 基础交互
首期支持:
- 真实 TTY 输入与 ANSI 输出。
- 中文输入法、组合字符和常规键盘快捷键。
- 复制、粘贴、全选、搜索、清屏和滚动。
- 工作栏宽度或窗口尺寸变化后的 PTY resize。
- 终端重命名。
- 显式关闭、退出后重新打开和远程中断后重新连接。
浏览器原生页面快捷键与终端按键冲突时,终端聚焦期间优先交给终端;应用级保留快捷键必须
有明确规则和可访问说明。
### 9.2 状态模型
```ts
type TerminalSessionState =
| 'starting'
| 'running'
| 'exited'
| 'interrupted'
| 'closing'
| 'failed'
```
- `starting`:正在创建本机 PTY 或 SSH Channel。
- `running`:允许输入和 resize。
- `exited`:Shell 正常或带退出码结束,显示退出码或信号。
- `interrupted`:远程连接、Host identity 或桌面生命周期导致会话失效。
- `closing`:已拒绝新输入,正在回收进程或 Channel。
- `failed`:Session 未成功开始或发生不可恢复错误。
高频输出不逐行进入 live region。只播报连接成功、连接失败、已中断和 Shell 已退出等重要
状态变化。
### 9.3 重新连接
- 本机或远程 Session 结束后,“重新打开”在同一 Tab 中创建全新的 Shell Session。
- 远程断线后的按钮文案为“重新连接并新建 Shell”,不能暗示恢复旧进程。
- 新 Session 使用 Host store 和项目中的当前有效配置,不复用旧 Host identity。
- 重新连接前清空旧终端画面,并保留可见说明“这是新的 Shell 会话”。
## 10. 实例、Session 与持久化
工作栏实例与运行 Session 分离:
```ts
type WorkbarAppDefinition = {
id: 'tasks' | 'workspace' | 'browser' | 'results' | 'terminal'
instancePolicy: 'single' | 'multiple'
}
type WorkbarTabInstance = {
id: string
appId: WorkbarAppDefinition['id']
title: string
targetRef?: {
type: 'project' | 'local'
id?: string
}
}
```
- 持久化工作栏打开状态、Tab 顺序、活动实例、应用 ID、自定义标题、公开目标引用和宽度比例。
- 不持久化终端正文、未执行输入、凭据、环境变量、PTY PID、SSH Channel 或派生 Host
identity。
- Main 创建终端后返回新的不透明 Session ID;Renderer 不能选择 PID 或 Channel。
- 应用重启恢复终端 Tab 描述,但状态为“会话已结束”,不自动建立 SSH 连接或启动本机
Shell。
- 运行期间切换项目不会改变已经创建的终端目标。用户需要新目标时通过“+”创建新终端。
## 11. 生命周期与关闭语义
| 用户或系统动作 | Tab | Shell Session |
| --- | --- | --- |
| 切换 Tab | 保留 | 继续运行 |
| 收起工作栏 | 保留 | 继续运行,停止非必要高频 UI 工作 |
| 切换主页面 | 保留 | 继续运行 |
| 切换项目 | 保留并显示原目标 | 继续在原目标运行 |
| 关闭运行中的终端 Tab 并确认 | 删除 | 结束 Shell 和子进程 |
| Shell 自行退出 | 保留 | 标记 `exited` |
| SSH 断线 | 保留 | 标记 `interrupted` |
| 删除或修改目标 Host | 保留 | 关闭旧 Channel 并标记 `interrupted` |
| Renderer 销毁或应用退出 | 下次恢复描述 | 在总关闭截止时间内回收 |
关闭操作必须安全处理竞态。Main 停止接受新输入,关闭 stdin/Channel,先正常结束,再在既有
应用关闭截止时间内升级清理;一个卡死终端不能无限阻塞应用退出。关闭后的迟到 ACK 视为已
完成,input、resize 或重复 close 返回 Session 不存在,不操作其他 Session。
## 12. 技术生产路径
### 12.1 Shared
新增独立终端契约,至少覆盖:
- `create`:目标引用、初始 `cols/rows`。
- `write`:Session ID 和有界输入。
- `resize`:Session ID、`cols/rows`。
- `close`:Session ID。
- `snapshot`:目标、状态、Shell、目录和终态。
- `event`:带 Session ID 和单调序号的输出、状态、退出与错误事件。
所有 Schema 使用 Zod 严格校验,并限制 ID、标题、输入、尺寸、事件块、会话数和缓冲字节。
### 12.2 Main
新增统一 `TerminalSessionManager`:
- Session 按所属 `webContents` 和不透明 ID 隔离。
- 将现有间接 `node-pty` 提升为 GoodBuddy 直接生产依赖,并用于启动平台 Shell。
- 远程使用现有 `SshConnectionPool` 打开交互式 PTY Channel。
- 统一处理 write、resize、close、exit、连接中断和应用退出。
- 终端输出只发送给所属窗口。
- 复用现有子进程树终止思路,但针对 PTY 验证 Windows 与 POSIX 的实际回收行为。
### 12.3 Preload 与 IPC
- `DesktopApi` 只暴露显式 `terminal.create/write/resize/close/getSnapshot/onEvent`。
- Main Handler 对每个调用执行可信 sender 检查和共享 Schema parse。
- Preload 管理事件订阅释放,不暴露 `ipcRenderer`、PTY、SSH Client 或 Node API。
### 12.4 Renderer
- 使用 `@xterm/xterm` 6 和官方 fit/search addon 处理 ANSI、光标、选择、IME、搜索、
滚动和可访问输入,不自行实现终端转义状态机。
- 终端首次打开时按需加载;支持 WebGL2 时使用官方 WebGL renderer,初始化失败或 Context
丢失时释放 WebGL addon 并回退到 xterm 默认 renderer。
- xterm 使用解析后的跨平台系统等宽字体栈,不能把未解析的 CSS `var(...)` 交给 Canvas。
- Tab 壳层只管理实例与焦点,不持有 PTY 或 SSH 对象。
- `ResizeObserver` 只在有效非零布局后发送去重后的 `cols/rows`。
- 组件卸载时退订画面事件;只有显式关闭终端才调用 Session close。
- 终端样式复用全局语义颜色、边框、焦点和字体令牌,不创建另一套工作台设计系统。
### 12.5 输出顺序与背压
- 输出按 Session 分区并携带单调序号。
- Main 合并小块输出,限制单事件大小、待发送条目和总字节。
- Renderer 确认已经消费的序号;慢消费者达到上限时暂停 PTY/SSH stream,消费后恢复。
- 不通过丢弃中间输出维持界面响应,因为丢失字节会破坏终端状态。
- Renderer 只保留有界滚动历史;清屏不改变 Main Session 生命周期。
## 13. 权限与边界
- 用户终端以当前本机账号或所选 SSH 账号的正常权限运行,不增加额外虚构的 trust tier。
- Ask/Execute 是 Agent Runtime 模式,不自动改变用户直接操作终端的 OS 权限。
- UI 必须持续将其标注为“用户终端”,避免被理解为 Ask Runtime 的只读输出。
- Agent、模型、监督器和自动化不能调用终端 write,也不能把指令注入已有 Session。
- 终端输出不会自动进入对话上下文、模型 Prompt、成果或活动记录。
- Renderer 只能引用项目和 Session 的公开 ID;Main 从权威 store 解析目录、Host、凭据和
当前 Host identity。
- 不接受 Renderer 提交任意 Shell 可执行路径、SSH 命令、PID、环境变量集合或原始凭据。
- 保持 Electron `contextIsolation`、sandbox 和禁用 Renderer Node integration。
## 14. 错误与反馈
- 创建失败、断线、Shell 退出和目标失效保留在终端面板,提供就地重试。
- 不与全局通知重复显示同一终端错误。
- 非局部错误,例如无法保存工作栏布局,可以进入应用通知。
- 错误文案说明发生了什么、当前 Shell 是否仍在运行、用户可以做什么。
- Host Key 变化沿用现有 Host 管理流程;终端只显示“主机身份已变化,请重新验证”,不在
终端内复制凭据或 Host Key 修改流程。
- 目标不可用时保留 Tab 名称和目标,不静默切换到本机或其他 Host。
## 15. 性能与资源要求
- 工作栏切换和终端输入在正常负载下保持即时反馈,持续输出不能阻塞主界面导航。
- 同一窗口的活动终端数量必须有明确上限;达到上限时阻止新建并说明先关闭不用的终端。
- 每个 Session 的输出队列、Renderer 滚动历史和 IPC 单事件均有硬上限。
- 工作栏不可见时可以降低渲染刷新频率,但不能丢失终端协议字节或暂停 Shell 本身。
- 应用退出复用现有总清理截止时间,不因终端新增无界等待。
- 生产构建必须实际加载本机 PTY 原生模块;不能只验证文件存在。
- 远程终端不能使 SSH connection pool 的空闲项、Channel 或监听器泄漏。
具体数值在共享契约和性能测试中确定,以现有 IPC、窗口和关闭预算为上限,不在多个进程中
维护不同常量。
## 16. 无障碍与响应式
- Tab 使用 `tablist/tab/tabpanel`;“+”使用带可访问名称“打开工作栏应用”的普通按钮。
- 应用选择页使用可键盘操作的列表或菜单语义,不使用 `SegmentedControl`;终端没有重复的
目标选择页。
- 每个终端 Tab 的可访问名称包含自定义名称或位置,多个终端不能都只读作“终端”。
- Tab 关闭后焦点移动到确定的相邻 Tab;取消创建后焦点返回“+”。
- 工作栏收起后焦点返回唯一工作栏开关,不增加焦点陷阱或遮罩。
- 终端高频输出不逐行播报;只播报连接、退出、失败和中断。
- 200% 文字缩放时,目标、Shell、目录、状态和关闭操作仍可访问。
- Tab 单行横向滚动,终端内容随工作栏尺寸变化并同步 PTY,不把 Tab 换成下拉框。
- 深色和浅色主题都使用设计系统语义令牌,并保持终端文本、选择和光标可辨。
## 17. 实施顺序与多代理工作包
功能必须以完整的本机和远程用户流程交付。以下是可并行的开发工作包,不表示可以发布只有
Schema、假数据终端或不可用入口的中间产品。
### 17.1 依赖顺序
```text
契约冻结
├─ 工作栏实例壳层
├─ 本机 PTY 后端
├─ SSH PTY 后端
└─ 终端 Renderer
↓
单一集成负责人完成 Main/Preload/App 接线
↓
完整验证、真实 Host 验收与文档同步
```
### 17.2 文件所有权
| 工作包 | 主要职责 | 建议文件所有权 | 不应修改 |
| --- | --- | --- | --- |
| 契约与注册表 | Workbar/Terminal Schema、状态、测试 | 新建 `src/shared/workbar-contracts.ts`、`terminal-contracts.ts` 及测试 | `App.tsx`、`ipc.ts`、Preload |
| 工作栏壳层 | 动态实例 Tab、“+”、选择页、单/多实例和焦点 | 新建工作栏组件及其测试 | PTY、SSH、Main IPC |
| 本机终端后端 | 本机 PTY、输入、resize、退出和进程树清理 | 新建 `src/main/terminal/` 本机文件及测试 | Renderer、远程 Agent |
| SSH 终端后端 | SSH PTY、lease、resize、断线和 Channel 清理 | 新建 `src/main/terminal/` 远程文件及聚焦测试 | 工作栏 UI、Agent 协议 |
| 终端 Renderer | 模拟器、IME、搜索、复制粘贴、状态栏和 resize | 新建终端组件、样式和测试 | Main、SSH、中心 IPC |
| 集成 | 依赖、IPC channel、DesktopApi、Preload、Main 注册、`App` 接线与关闭顺序 | `package.json`、lock、`ipc-channels.ts`、`contracts.ts`、`preload/index.ts`、`main/ipc.ts`、`App.tsx` | 不重写各包已验收内部逻辑 |
| 验收与文档 | E2E、跨平台构建检查、真实 Host、最终文档 | 测试与相关文档 | 不用假实现替换生产路径 |
中心文件只能由集成负责人修改,避免多个代理同时编辑 `App.tsx`、`main/ipc.ts`、
`shared/contracts.ts`、`preload/index.ts`、`package.json` 和 lockfile。
### 17.3 并行开发门槛
契约负责人先冻结:
- 应用注册和实例策略。
- Terminal request、snapshot、event 和 error code。
- Session 所有权和关闭语义。
- 输出序号、ACK 与容量常量。
其他代理基于冻结契约工作。接口偏差由集成负责人统一修正,不由多个代理分别修改共享中心
文件。
## 18. 验收标准
### 18.1 工作栏应用与实例
- [ ] Tab 行末始终显示“+”,包括没有任何打开实例时。
- [ ] 点击“+”显示稳定应用目录,取消后返回原实例并恢复焦点。
- [ ] 选择已打开单实例应用只聚焦已有 Tab。
- [x] 连续选择终端会创建多个互相独立的终端 Tab。
- [ ] 关闭、切换和重排实例后,“+”仍保持可用。
- [ ] Tab 溢出时单行横向滚动,不隐藏“+”或把 Tab 换成下拉框。
- [x] 关闭活动 Tab 后激活正确的相邻 Tab 并恢复焦点。
- [x] 当前 Tab 的背景、边框、顶部指示和字重清晰可辨;关闭按钮仅在悬停、焦点或无悬停
设备上出现,且不引发布局位移。
- [ ] 升级后现有任务中心、工作区、浏览器和成果仍按默认布局打开且行为不回归。
- [ ] 在所有主要页面都能打开工作栏;切换主要页面不会销毁 Tab 实例或终端 Session。
### 18.2 本机终端
- [x] 从“+ → 终端”直接打开当前本机项目的真实交互式 Shell,工作目录为项目根。
- [ ] 没有项目时从用户 Home 打开本机 Shell。
- [ ] `pwd` / `Get-Location`、交互输入、ANSI 颜色、中文 IME、复制和粘贴工作正常。
- [ ] 调整工作栏和窗口尺寸会更新 PTY `cols/rows`,全屏 TTY 程序正确重绘。
- [ ] 多个本机终端的输入、输出、目录和退出状态互不串线。
- [ ] Shell 有活动子进程时关闭 Tab,确认后回收完整进程树;取消后 Session 继续运行。
- [ ] 退出后的 Tab 显示退出码,并可在同一 Tab 显式创建新 Shell。
### 18.3 远程终端
- [ ] 从“+ → 终端”直接为当前托管 SSH 项目打开真实 SSH PTY。
- [ ] 终端持续显示 Host、远端目录、Shell 和连接状态。
- [ ] 使用现有固定 Host Key 和已存凭据,Renderer、日志和命令参数不出现凭据。
- [ ] 输入、ANSI、中文、复制粘贴和 resize 在真实 Host 上工作正常。
- [ ] 活动远程终端不会被 SSH connection pool 空闲回收。
- [ ] SSH 断线立即标记“已中断”并拒绝继续输入,不显示为仍在运行。
- [ ] “重新连接并新建 Shell”明确创建新 Session,不宣称恢复旧远端进程。
- [ ] Host 删除、地址/用户/凭据或 Host Key generation 变化会中断旧 Session;新 Session
使用当前 Host identity。
### 18.4 生命周期、性能和边界
- [ ] 收起工作栏、切换主页面、切换 Tab 或切换项目不会终止已有终端。
- [ ] 终端不会随项目切换静默迁移执行位置。
- [ ] 应用重启只恢复终端 Tab 描述,不自动连接或启动 Shell。
- [ ] 输出顺序在持续大输出下保持正确,Main 和 Renderer 内存保持有界,主界面仍可操作。
- [ ] 慢 Renderer 触发暂停和恢复,不丢弃中间终端字节。
- [ ] Renderer 不获得 raw PTY、ChildProcess、SSH Client、PID、环境变量或凭据。
- [ ] Agent、模型和自动化不能向已有用户终端注入输入。
- [ ] 窗口销毁和应用退出在既有关闭截止时间内回收本机进程、SSH Channel 和监听器。
- [ ] 重复 close、迟到 input/resize 和退出竞态不会操作其他 Session 或导致进程泄漏。
### 18.5 设计、无障碍和跨平台
- [ ] 仅使用键盘可以打开应用、创建终端、切换和关闭 Tab、复制、粘贴及重新连接。
- [ ] Tab、“+”、选择页和关闭确认使用正确语义并有可见焦点。
- [ ] 终端输出不逐行进入 live region,关键状态变化可被辅助技术感知。
- [ ] 浅色、深色、200% 文字缩放和窄窗口下可以完成核心流程。
- [ ] Windows、macOS、Linux x64 和 Linux arm64 的正式构建实际启动本机 PTY。
- [ ] 远程链路在共享 Linux x64 真实 Host 上完成创建、输入、resize、断线、重连、关闭和
应用退出验证;若 Host 不可达,远程终端不得标记为完成。
## 19. 验证计划
### 19.1 自动验证
- 共享 Zod Schema 和边界值测试。
- 单/多实例注册策略、Tab 顺序、关闭焦点和“+”选择页组件测试。
- 本机 PTY Session Manager 的输入、resize、退出、幂等关闭和进程树测试。
- SSH PTY 的 Host identity、lease、断线、resize 和关闭测试。
- Main trusted sender、Session 所有权、IPC 输入边界和事件路由测试。
- Terminal Renderer 的 IME、键盘、ResizeObserver、订阅释放和状态测试。
- `npm test`
- `npm run typecheck`
- `npm run lint`
- `npm run build`
### 19.2 真实路径验证
- 在当前开发平台通过产品 UI 完成本机终端全流程。
- 在共享 Linux x64 Host 通过现有 Host 配置完成远程终端全流程。
- 真实运行需要 TTY 的程序,验证 ANSI、光标和 resize,不只运行非交互命令。
- 持续输出并主动减慢 Renderer 消费,验证背压和内存上限。
- 分别在本机和远程启动带子进程的命令,关闭 Tab 和应用后核对无 GoodBuddy 所属遗留资源。
- 生产构建在各受支持平台实际加载 PTY 原生模块,不以单元测试或包内文件存在代替。
### 19.3 当前开发验证记录
2026-09-01 已通过生产 `SshConnectionPool` 和 `createSshTerminalSession` 在共享 Linux x64
Host 完成直接 SSH PTY 验证:使用已有固定 Host Key 和测试凭据,以远端项目目录启动登录
Shell,验证交互输入、ANSI、UTF-8 中文、`80×24` 到 `101×37` resize、连接销毁后进入
`interrupted`、重新连接创建新 Shell,以及 Session close 和 connection pool dispose
回收远端 Shell。验证只创建一个
`$HOME/.goodbuddy/terminal-smoke-<UUID>` 临时目录,结束后已删除并确认无遗留 Shell 进程。
同日使用最新生产构建完成工作栏视觉检查:活动 Tab 使用连续内容表面、顶部强调线和应用
图标;关闭按钮默认不可见,悬停后以 overlay 显示且 Tab 宽度不变;横向滚动继续可用但不
显示滚动条,“+”保持独立可见。
本记录不替代尚未勾选的完整产品 UI、剪贴板、macOS、Linux arm64 和各平台本机 PTY 验收。
本 PRD 不改变 Agent 协议,因此首期远程终端无需 Agent package 更新。若实现期间改为
Agent-owned PTY,必须先修订本文的远程生命周期和恢复语义,并按 Agent 开发规则在共享
Linux x64 Host 验证当前源码或候选包。
## 20. 相关文档职责
- [通用助手工作栏与执行空间 PRD](./prd.md):
工作栏应用级位置、稳定能力目录、执行空间和总体范围。
- 本文:持久“+”、应用实例策略、工作栏动态 Tab、自动项目目标、本机与直接 SSH 多终端。
- [统一界面设计系统](../../../UI-DESIGN.md):Tab、菜单、布局、主题、焦点和无障碍规则。
- [SSH 远程主机与 GoodBuddy Agent 实现说明](../remote-host/technical-design.md):
Host Key、凭据、连接池、Agent 和远程项目现状。
- [SSH Host 远程环境准备与控制面直连设计](../remote-host/environment-provisioning-technical-design.md):
Host 保存、环境准备和项目使用之间的职责。