@orion-agents/orion-code 0.2.2 → 0.3.1

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 (217) hide show
  1. package/CHANGELOG.md +82 -0
  2. package/README.md +89 -14
  3. package/README.zh-CN.md +77 -14
  4. package/bin/orion +15 -4
  5. package/dist/cli.js +51 -172
  6. package/dist/cli.js.map +1 -1
  7. package/dist/commands/model-command-handlers.d.ts +2 -2
  8. package/dist/commands/model-command-handlers.d.ts.map +1 -1
  9. package/dist/commands/model-command-handlers.js +113 -32
  10. package/dist/commands/model-command-handlers.js.map +1 -1
  11. package/dist/commands/session-command-handlers.d.ts.map +1 -1
  12. package/dist/commands/session-command-handlers.js +106 -15
  13. package/dist/commands/session-command-handlers.js.map +1 -1
  14. package/dist/commands/types.d.ts +13 -3
  15. package/dist/commands/types.d.ts.map +1 -1
  16. package/dist/commands/types.js +1 -1
  17. package/dist/commands/types.js.map +1 -1
  18. package/dist/core/tool-artifacts.d.ts +2 -0
  19. package/dist/core/tool-artifacts.d.ts.map +1 -1
  20. package/dist/core/tool-artifacts.js +27 -1
  21. package/dist/core/tool-artifacts.js.map +1 -1
  22. package/dist/index.d.ts +1 -1
  23. package/dist/index.js +1 -1
  24. package/dist/runtime/agent-loop.d.ts.map +1 -1
  25. package/dist/runtime/agent-loop.js +3 -3
  26. package/dist/runtime/agent-loop.js.map +1 -1
  27. package/dist/runtime/agent-runtime-controller.d.ts +32 -1
  28. package/dist/runtime/agent-runtime-controller.d.ts.map +1 -1
  29. package/dist/runtime/agent-runtime-controller.js +241 -27
  30. package/dist/runtime/agent-runtime-controller.js.map +1 -1
  31. package/dist/runtime/agent-runtime-protocol.d.ts +4 -0
  32. package/dist/runtime/agent-runtime-protocol.d.ts.map +1 -1
  33. package/dist/runtime/agent-runtime-protocol.js.map +1 -1
  34. package/dist/runtime/agent-runtime-runner.d.ts +2 -1
  35. package/dist/runtime/agent-runtime-runner.d.ts.map +1 -1
  36. package/dist/runtime/durable-tool-receipt-reader.d.ts +32 -0
  37. package/dist/runtime/durable-tool-receipt-reader.d.ts.map +1 -0
  38. package/dist/runtime/durable-tool-receipt-reader.js +130 -0
  39. package/dist/runtime/durable-tool-receipt-reader.js.map +1 -0
  40. package/dist/runtime/legacy-thread-materializer.d.ts +31 -0
  41. package/dist/runtime/legacy-thread-materializer.d.ts.map +1 -1
  42. package/dist/runtime/legacy-thread-materializer.js +71 -17
  43. package/dist/runtime/legacy-thread-materializer.js.map +1 -1
  44. package/dist/runtime/orion-runtime-v1.d.ts +2 -0
  45. package/dist/runtime/orion-runtime-v1.d.ts.map +1 -1
  46. package/dist/runtime/orion-runtime-v1.js +7 -1
  47. package/dist/runtime/orion-runtime-v1.js.map +1 -1
  48. package/dist/runtime/orion-session-runner.d.ts +7 -2
  49. package/dist/runtime/orion-session-runner.d.ts.map +1 -1
  50. package/dist/runtime/orion-session-runner.js +16 -6
  51. package/dist/runtime/orion-session-runner.js.map +1 -1
  52. package/dist/runtime/product-bootstrap.d.ts +22 -0
  53. package/dist/runtime/product-bootstrap.d.ts.map +1 -0
  54. package/dist/runtime/product-bootstrap.js +374 -0
  55. package/dist/runtime/product-bootstrap.js.map +1 -0
  56. package/dist/runtime/product-orion-runtime.d.ts +2 -1
  57. package/dist/runtime/product-orion-runtime.d.ts.map +1 -1
  58. package/dist/runtime/product-orion-runtime.js +83 -13
  59. package/dist/runtime/product-orion-runtime.js.map +1 -1
  60. package/dist/runtime/protocol/runtime-protocol-v1.d.ts +1 -1
  61. package/dist/runtime/protocol/runtime-protocol-v1.js +1 -1
  62. package/dist/runtime/protocol/runtime-protocol-v1.js.map +1 -1
  63. package/dist/runtime/release-receipts.d.ts +66 -3
  64. package/dist/runtime/release-receipts.d.ts.map +1 -1
  65. package/dist/runtime/release-receipts.js +340 -7
  66. package/dist/runtime/release-receipts.js.map +1 -1
  67. package/dist/runtime/step-snapshot.d.ts.map +1 -1
  68. package/dist/runtime/step-snapshot.js +22 -2
  69. package/dist/runtime/step-snapshot.js.map +1 -1
  70. package/dist/runtime/subagents/runtime-integration.d.ts +1 -1
  71. package/dist/runtime/subagents/runtime-integration.d.ts.map +1 -1
  72. package/dist/runtime/subagents/runtime-integration.js +5 -2
  73. package/dist/runtime/subagents/runtime-integration.js.map +1 -1
  74. package/dist/runtime/thread-event-store.d.ts +80 -0
  75. package/dist/runtime/thread-event-store.d.ts.map +1 -1
  76. package/dist/runtime/thread-event-store.js +456 -22
  77. package/dist/runtime/thread-event-store.js.map +1 -1
  78. package/dist/runtime/thread-projection.d.ts +10 -0
  79. package/dist/runtime/thread-projection.d.ts.map +1 -1
  80. package/dist/runtime/thread-projection.js +40 -0
  81. package/dist/runtime/thread-projection.js.map +1 -1
  82. package/dist/runtime/thread-runtime.d.ts +3 -1
  83. package/dist/runtime/thread-runtime.d.ts.map +1 -1
  84. package/dist/runtime/thread-runtime.js +6 -0
  85. package/dist/runtime/thread-runtime.js.map +1 -1
  86. package/dist/runtime/thread-session-index.d.ts +84 -0
  87. package/dist/runtime/thread-session-index.d.ts.map +1 -0
  88. package/dist/runtime/thread-session-index.js +503 -0
  89. package/dist/runtime/thread-session-index.js.map +1 -0
  90. package/dist/runtime/thread-session-view.d.ts +70 -9
  91. package/dist/runtime/thread-session-view.d.ts.map +1 -1
  92. package/dist/runtime/thread-session-view.js +200 -82
  93. package/dist/runtime/thread-session-view.js.map +1 -1
  94. package/dist/runtime/thread-ui-adapter.d.ts +2 -0
  95. package/dist/runtime/thread-ui-adapter.d.ts.map +1 -1
  96. package/dist/runtime/thread-ui-adapter.js +86 -4
  97. package/dist/runtime/thread-ui-adapter.js.map +1 -1
  98. package/dist/runtime/tool-detail-repository.d.ts.map +1 -1
  99. package/dist/runtime/tool-detail-repository.js +23 -19
  100. package/dist/runtime/tool-detail-repository.js.map +1 -1
  101. package/dist/runtime/tool-receipt-validator.d.ts +21 -0
  102. package/dist/runtime/tool-receipt-validator.d.ts.map +1 -0
  103. package/dist/runtime/tool-receipt-validator.js +157 -0
  104. package/dist/runtime/tool-receipt-validator.js.map +1 -0
  105. package/dist/runtime/ui-events.d.ts +35 -0
  106. package/dist/runtime/ui-events.d.ts.map +1 -1
  107. package/dist/runtime/ui-events.js +1 -0
  108. package/dist/runtime/ui-events.js.map +1 -1
  109. package/dist/runtime/ui-view-model.d.ts +2 -0
  110. package/dist/runtime/ui-view-model.d.ts.map +1 -1
  111. package/dist/runtime/ui-view-model.js +7 -3
  112. package/dist/runtime/ui-view-model.js.map +1 -1
  113. package/dist/services/global-config.d.ts +25 -0
  114. package/dist/services/global-config.d.ts.map +1 -1
  115. package/dist/services/global-config.js +373 -5
  116. package/dist/services/global-config.js.map +1 -1
  117. package/dist/services/redaction.d.ts +4 -0
  118. package/dist/services/redaction.d.ts.map +1 -1
  119. package/dist/services/redaction.js +63 -0
  120. package/dist/services/redaction.js.map +1 -1
  121. package/dist/services/session-index.d.ts +16 -0
  122. package/dist/services/session-index.d.ts.map +1 -1
  123. package/dist/services/session-index.js +45 -36
  124. package/dist/services/session-index.js.map +1 -1
  125. package/dist/services/session-storage.d.ts +59 -0
  126. package/dist/services/session-storage.d.ts.map +1 -1
  127. package/dist/services/session-storage.js +306 -107
  128. package/dist/services/session-storage.js.map +1 -1
  129. package/dist/services/settings-coordinator.d.ts +174 -0
  130. package/dist/services/settings-coordinator.d.ts.map +1 -0
  131. package/dist/services/settings-coordinator.js +605 -0
  132. package/dist/services/settings-coordinator.js.map +1 -0
  133. package/dist/services/settings-document-repository.d.ts +138 -0
  134. package/dist/services/settings-document-repository.d.ts.map +1 -0
  135. package/dist/services/settings-document-repository.js +551 -0
  136. package/dist/services/settings-document-repository.js.map +1 -0
  137. package/dist/services/workspace-registry.d.ts +42 -0
  138. package/dist/services/workspace-registry.d.ts.map +1 -0
  139. package/dist/services/workspace-registry.js +222 -0
  140. package/dist/services/workspace-registry.js.map +1 -0
  141. package/dist/terminal-ui/launch.d.ts.map +1 -1
  142. package/dist/terminal-ui/launch.js +5 -0
  143. package/dist/terminal-ui/launch.js.map +1 -1
  144. package/dist/tui-ui/state.d.ts.map +1 -1
  145. package/dist/tui-ui/state.js +5 -0
  146. package/dist/tui-ui/state.js.map +1 -1
  147. package/dist/web/errors.d.ts +6 -0
  148. package/dist/web/errors.d.ts.map +1 -0
  149. package/dist/web/errors.js +13 -0
  150. package/dist/web/errors.js.map +1 -0
  151. package/dist/web/event-hub.d.ts +43 -0
  152. package/dist/web/event-hub.d.ts.map +1 -0
  153. package/dist/web/event-hub.js +323 -0
  154. package/dist/web/event-hub.js.map +1 -0
  155. package/dist/web/file-read-service.d.ts +55 -0
  156. package/dist/web/file-read-service.d.ts.map +1 -0
  157. package/dist/web/file-read-service.js +399 -0
  158. package/dist/web/file-read-service.js.map +1 -0
  159. package/dist/web/git-read-model-service.d.ts +77 -0
  160. package/dist/web/git-read-model-service.d.ts.map +1 -0
  161. package/dist/web/git-read-model-service.js +631 -0
  162. package/dist/web/git-read-model-service.js.map +1 -0
  163. package/dist/web/index.d.ts +6 -0
  164. package/dist/web/index.d.ts.map +1 -0
  165. package/dist/web/index.js +28 -0
  166. package/dist/web/index.js.map +1 -0
  167. package/dist/web/launch.d.ts +9 -0
  168. package/dist/web/launch.d.ts.map +1 -0
  169. package/dist/web/launch.js +64 -0
  170. package/dist/web/launch.js.map +1 -0
  171. package/dist/web/protocol.d.ts +408 -0
  172. package/dist/web/protocol.d.ts.map +1 -0
  173. package/dist/web/protocol.js +369 -0
  174. package/dist/web/protocol.js.map +1 -0
  175. package/dist/web/review-service.d.ts +38 -0
  176. package/dist/web/review-service.d.ts.map +1 -0
  177. package/dist/web/review-service.js +74 -0
  178. package/dist/web/review-service.js.map +1 -0
  179. package/dist/web/server.d.ts +20 -0
  180. package/dist/web/server.d.ts.map +1 -0
  181. package/dist/web/server.js +744 -0
  182. package/dist/web/server.js.map +1 -0
  183. package/dist/web/terminal-manager.d.ts +155 -0
  184. package/dist/web/terminal-manager.d.ts.map +1 -0
  185. package/dist/web/terminal-manager.js +728 -0
  186. package/dist/web/terminal-manager.js.map +1 -0
  187. package/dist/web/terminal-server.d.ts +8 -0
  188. package/dist/web/terminal-server.d.ts.map +1 -0
  189. package/dist/web/terminal-server.js +275 -0
  190. package/dist/web/terminal-server.js.map +1 -0
  191. package/dist/web/workbench-controller.d.ts +99 -0
  192. package/dist/web/workbench-controller.d.ts.map +1 -0
  193. package/dist/web/workbench-controller.js +1267 -0
  194. package/dist/web/workbench-controller.js.map +1 -0
  195. package/dist/web-client/assets/DiffViewer-DpKoD07C.js +5 -0
  196. package/dist/web-client/assets/FilesPanel-BkoLmgjR.js +2 -0
  197. package/dist/web-client/assets/GitPanel-D20StcdG.js +1 -0
  198. package/dist/web-client/assets/ReviewPanel-3MVWbMQV.js +1 -0
  199. package/dist/web-client/assets/TerminalPanel-BLQ592Fb.js +21 -0
  200. package/dist/web-client/assets/TerminalPanel-DLuoa74B.css +1 -0
  201. package/dist/web-client/assets/index-BkIDl_xk.js +16 -0
  202. package/dist/web-client/assets/index-DXMpnWE8.css +1 -0
  203. package/dist/web-client/index.html +16 -0
  204. package/docs/architecture/v0.3.0-web-api.yaml +1340 -0
  205. package/docs/architecture/v0.3.1-web-api.yaml +2290 -0
  206. package/docs/migration/v0.2.2-to-v0.3.0-settings.md +114 -0
  207. package/docs/migration/v0.2.2-to-v0.3.0.md +55 -0
  208. package/docs/migration/v0.3.0-to-v0.3.1.md +88 -0
  209. package/docs/orion.example.json +9 -2
  210. package/docs/plan/v0.3.0-node-runtime-compatibility-plan.md +57 -0
  211. package/docs/plan/v0.3.0-settings-integration-plan.md +740 -0
  212. package/docs/plan/v0.3.0-web-workbench-plan.md +376 -0
  213. package/docs/plan/v0.3.1-web-workbench-professional-shell-plan.md +848 -0
  214. package/docs/readme.md +22 -1
  215. package/docs/test/v0.3.1-web-workbench-e2e-plan.md +140 -0
  216. package/npm-shrinkwrap.json +1229 -45
  217. package/package.json +47 -11
@@ -0,0 +1,848 @@
1
+ # v0.3.1 Web Workbench 专业工作台优化计划
2
+
3
+ - 版本:v0.3.1
4
+ - 状态:待实施
5
+ - 日期:2026-08-29
6
+ - 范围:Web Workbench 左侧项目导航、右侧工作面板、布局系统、专业化 UI
7
+ - 参考:Codex 的工作台信息架构与交互密度;不复制其品牌、视觉资产或私有实现
8
+
9
+ ## 0. 决策摘要
10
+
11
+ v0.3.1 将当前的“三栏页面”升级为可长期承载工程能力的专业工作台:
12
+
13
+ 1. 左侧由“当前工作区 + 当前工作区会话”升级为**多项目导航器**,可同时看到和展开多个已知项目;
14
+ 2. 中间继续是唯一的会话、流式消息、审批和 Composer 主工作区;
15
+ 3. 右侧由固定宽度的“工作详情”升级为**可变宽工作面板**,一级入口为:
16
+ **Agent、审阅、终端、文件、Git**;
17
+ 4. 当前 Goal、活动、能力、诊断不被删除,而是收进 Agent 面板的二级导航;
18
+ 5. 文件和 Git 在 v0.3.1 以安全、可分页的只读能力为主;审阅支持差异阅读和将反馈送回对话;
19
+ 终端必须是真实 PTY,而不是工具输出的伪终端;
20
+ 6. Host 仍只有一个 active workspace/runtime。多项目是导航与只读概览能力,不虚构多个 Agent
21
+ Runtime 同时运行;跨项目会话激活必须是一次原子 Context transition;
22
+ 7. 所有新能力遵循当前 loopback Host、nonce、Origin/Host 校验、幂等 mutation、工作区 containment、
23
+ 安全分页和恢复语义。
24
+
25
+ 本计划的完成定义不是“画出新布局”,而是:四项用户需求全部由真实 Host 数据驱动,并通过
26
+ source-clean exact-tarball、真实 Chrome、Node 22.12/24/26 和无障碍门禁。
27
+
28
+ ## 1. 背景与当前基线
29
+
30
+ ### 1.1 当前实现
31
+
32
+ 源码基线以 v0.3.1 当前工作树为准:
33
+
34
+ - `web/src/App.tsx` 使用固定三栏 Grid;右侧在 `1180px` 以下切换为 modal drawer;
35
+ - `web/src/styles.css` 将左栏固定为 `264px`,右栏固定为 `336px`,折叠态为 `48px`;
36
+ - `web/src/components/Inspector.tsx` 只有 Goal、活动、能力、诊断四个标签;
37
+ - `web/src/components/WorkspaceRail.tsx` 只渲染当前工作区卡片及其 Session 列表;
38
+ - `src/web/protocol.ts::WebWorkspaceSummaryV1` 仅包含 path、label、active、sessionCount;
39
+ - `src/web/workbench-controller.ts::listWorkspaces()` 从当前目录和历史 Session 推导工作区,尚无独立、
40
+ 持久的项目注册表;
41
+ - Web API 已有工作区/Session、快照、Skills、MCP、tool details、settings 和 SSE,但没有文件树、
42
+ 文件预览、Git 状态/历史/差异或 PTY 合同;
43
+ - `src/services/workspace-state.ts` 和 `src/services/workspace-diff.ts` 已有可复用的 Git 只读基础,
44
+ `src/tools/git.ts` 也已有受控 Git 工具,但不能直接当成浏览器 API;
45
+ - 当前依赖中没有 Web terminal emulator 或 Node PTY backend。
46
+
47
+ ### 1.2 当前问题
48
+
49
+ - 右侧 336px 固定宽度无法同时适配 Goal 卡片、长 Diff、文件内容和终端;
50
+ - 将更多能力继续塞进当前四标签会造成一级导航过载;
51
+ - 工作区切换藏在 modal 中,无法形成“多个项目并列、每个项目下有会话”的稳定心智模型;
52
+ - 现有 UI 的正文、元数据和状态字号跨度过大,部分 8.5–10px 文本不利于长期阅读;
53
+ - 当前卡片较多而信息层级不够统一,工程状态、空态、加载态和错误态没有一套跨面板规范;
54
+ - 文件、Git 和终端尚未形成独立的安全 read model,不能只靠解析 Tool 输出拼装 UI。
55
+
56
+ ## 2. 目标、成功指标与非目标
57
+
58
+ ### 2.1 产品目标
59
+
60
+ | ID | 目标 | v0.3.1 结果 |
61
+ | --- | ------------------------ | ------------------------------------------------------------------ |
62
+ | G1 | 右侧具备工程工作面板能力 | Agent、审阅、终端、文件、Git 均有真实数据和完整状态 |
63
+ | G2 | 右侧宽度可调整 | 通过 IDE 式分隔条用鼠标或触控板拖动;刷新后恢复;窄屏自动切 drawer |
64
+ | G3 | 左侧支持多工作区/项目 | 多项目可见、可展开、可搜索、可切换,每个项目显示会话和 Git 摘要 |
65
+ | G4 | UI 更专业 | 统一 tokens、组件、状态、密度、响应式、键盘与 WCAG 2.2 AA |
66
+
67
+ ### 2.2 可量化成功指标
68
+
69
+ - 首屏已有项目列表在本地 warm Host 下 p95 ≤ 250ms;
70
+ - 展开一个项目的首个 Session page p95 ≤ 250ms,不预取所有项目的全部 Session;
71
+ - 右侧面板切换视觉响应 ≤ 100ms;拖动调整宽度在目标设备上保持 55–60fps;
72
+ - 本地终端按键到回显 p95 ≤ 80ms,持续输出不阻塞对话滚动;
73
+ - Git status p95 ≤ 500ms,单文件 Diff 首屏 p95 ≤ 400ms;
74
+ - 文件树首次 page p95 ≤ 250ms,目录规模超过 500 项时仍不一次性渲染全部节点;
75
+ - 320px、390px、760px、1180px、1440px 五档无页面级横向滚动;
76
+ - 关键文本对比度 ≥ 4.5:1,控件边界/状态 ≥ 3:1,目标触控区域 ≥ 44×44 CSS px;
77
+ - axe blocking violations = 0;键盘可以完成项目切换、面板切换、Diff 导航和终端退出;精细调宽是
78
+ 指针交互,键盘用户仍可使用展开/折叠操作;
79
+ - 真实 E2E 中 console error、page error、HTTP 5xx、secret finding、dropped event 均为 0。
80
+
81
+ ### 2.3 非目标
82
+
83
+ v0.3.1 不包含:
84
+
85
+ - 同时运行多个 Agent Runtime;
86
+ - 完整 IDE、LSP 编辑器或 Monaco 替换会话主区;
87
+ - GitHub/GitLab PR 网络审阅、远端 Issue 或 CI 管理;
88
+ - 浏览器直接访问文件系统、直接执行 shell、直接读取 `.git` 内部文件;
89
+ - Git checkout、merge、rebase、push、reset、discard file 等破坏性 Git 操作;
90
+ - 文件面板内直接编辑任意文件;
91
+ - 把 Tool 输出解析为 Git、文件或终端的权威状态;
92
+ - 复制 Codex 的商标、文案、图标、色板或未公开内部协议。
93
+
94
+ ## 3. 用户与核心场景
95
+
96
+ ### 3.1 主要用户
97
+
98
+ - 同时维护多个本地仓库的独立开发者;
99
+ - 在对话、代码变更、命令输出和仓库状态之间频繁切换的 Agent 用户;
100
+ - 需要键盘、高对比度、缩放或窄屏使用的开发者;
101
+ - 需要确认 Agent 实际修改内容、验证结果和当前 Git 状态的审阅者。
102
+
103
+ ### 3.2 核心任务流
104
+
105
+ 1. 用户从左侧展开两个或以上项目,查看各自 Session、分支和脏状态;
106
+ 2. 用户点击非活动项目的 Session,Host 原子切换 workspace + session,主会话和右侧上下文同步;
107
+ 3. Agent 修改文件后,审阅面板显示变更集合、验证摘要和逐文件 Diff;
108
+ 4. 用户选中 Diff 片段并“发送到对话”,要求 Orion 修正,而不是浏览器直接重写文件;
109
+ 5. 用户在文件面板中浏览安全的项目树和只读文件内容;
110
+ 6. 用户在 Git 面板查看 branch、HEAD、ahead/behind、staged/unstaged/untracked/conflict 和提交历史;
111
+ 7. 用户明确点击“启动终端”,进入真实 PTY;刷新后可在 Host 仍存活时重新连接;
112
+ 8. 用户像在 Codex 或 IDE 中一样拖动左右分隔条改变右侧宽度,刷新页面后宽度和当前面板保持;
113
+ 9. 在窄屏下,左/右面板变成互斥 drawer,主会话没有水平压缩或焦点丢失。
114
+
115
+ ## 4. 信息架构
116
+
117
+ ### 4.1 桌面布局
118
+
119
+ ```text
120
+ ┌──────────────────────┬─────────────────────────────────────┬─┬──────────────────────────┐
121
+ │ Projects │ Conversation │↔│ Work panel │
122
+ │ │ │ │ │
123
+ │ Search projects │ Session header │ │ Agent Review Terminal │
124
+ │ │ Transcript │ │ Files Git │
125
+ │ ▾ orion-code main • │ │ │ │
126
+ │ ● Session A │ │ │ Active panel content │
127
+ │ Session B │ │ │ │
128
+ │ ▸ orion-studio │ │ │ │
129
+ │ ▾ agents-www feat/x │ │ │ │
130
+ │ Session C │ Approval / queue / composer │ │ status / actions │
131
+ └──────────────────────┴─────────────────────────────────────┴─┴──────────────────────────┘
132
+ ```
133
+
134
+ 默认尺寸:
135
+
136
+ - 左侧:280px,v0.3.1 不提供拖动,避免同时引入两个 resize 轴;
137
+ - 中间:`minmax(560px, 1fr)`,始终拥有优先空间;
138
+ - 右侧:默认 420px,可调整 320–720px;实际可用上限同时受 viewport 的 55% 和中间列 560px
139
+ 最小宽度约束,足够宽的桌面(当前三栏参数下为 1560px 及以上)才能达到完整 720px;
140
+ - 右侧折叠轨:48px;
141
+ - 分隔手柄:视觉 1px、命中区域 9px。
142
+
143
+ ### 4.2 右侧一级导航
144
+
145
+ | 一级面板 | 目的 | 权威数据源 | v0.3.1 范围 |
146
+ | -------- | ---------------------------- | ------------------------------------------- | ---------------------------------------------- |
147
+ | Agent | Goal、Plan、活动、能力、诊断 | Runtime snapshot/SSE/TurnCommit | 保留现有能力,改为二级导航 |
148
+ | 审阅 | 当前工作区变更和验证结果 | Git read model + Tool/verification receipts | 文件列表、Diff、反馈回对话、刷新 |
149
+ | 终端 | 用户控制的真实本地 PTY | Host PTY owner + dedicated stream | 多 tab、输入/输出/resize/reconnect/close |
150
+ | 文件 | 项目树和文件内容 | workspace-contained file service | 懒加载树、搜索、只读分页预览 |
151
+ | Git | 仓库事实和历史 | bounded Git service | status、branch、HEAD、upstream、log、Diff 入口 |
152
+
153
+ Agent 面板内部二级导航保持 Goal、活动、能力、诊断,避免丢失 v0.3.0 功能,也避免把九个入口平铺到同一行。
154
+
155
+ ### 4.3 窄屏布局
156
+
157
+ ```text
158
+ ┌──────────────────────────────────┐
159
+ │ [Projects] Session [Panel] │
160
+ ├──────────────────────────────────┤
161
+ │ │
162
+ │ Conversation │
163
+ │ │
164
+ ├──────────────────────────────────┤
165
+ │ Composer │
166
+ └──────────────────────────────────┘
167
+
168
+ Projects 或 Work panel 打开时:
169
+ ┌──────────────────────────────────┐
170
+ │ modal drawer [Close]│
171
+ │ 完整面板内容 │
172
+ └──────────────────────────────────┘
173
+ ```
174
+
175
+ - `> 1180px`:三栏 Dock,右侧可调整宽度;
176
+ - `761–1180px`:左栏 Dock,右侧 modal drawer;
177
+ - `≤ 760px`:左右均为互斥 modal drawer;
178
+ - drawer 状态不覆盖桌面宽度偏好,返回桌面时恢复;
179
+ - 打开 drawer 后主区 `inert`,焦点进入面板;Escape、关闭按钮和 scrim 均关闭并把焦点还给触发器。
180
+
181
+ ## 5. 右侧工作面板详细设计
182
+
183
+ ### 5.1 共用 Panel shell
184
+
185
+ 所有面板共用:
186
+
187
+ - 标题、当前项目/Session 上下文、刷新和折叠操作;
188
+ - 一级 icon rail + 文字标签;宽度不足 380px 时只显示 icon + accessible tooltip;
189
+ - loading skeleton、empty state、stale state、offline state、permission state、error state;
190
+ - 独立滚动容器,不能推动页面或 Composer;
191
+ - 面板内容缓存按 `{workspaceId, sessionId?, resourceRevision}` 分区;
192
+ - workspace/session 改变后旧请求通过 generation/AbortController 取消,旧响应不得覆盖新上下文;
193
+ - 每个数据面板显示“更新于”和明确刷新,不用静默无限轮询。
194
+
195
+ ### 5.2 Agent 面板
196
+
197
+ 迁移当前 `Inspector` 内容:
198
+
199
+ - Goal:Goal 状态、预算、criteria、evidence、Plan receipt;
200
+ - 活动:工具、子任务、研究、验证和安全的 tool detail;
201
+ - 能力:Skills、MCP 和模型可用性;
202
+ - 诊断:连接、cursor、Runtime、上下文和脱敏诊断。
203
+
204
+ 迁移要求:
205
+
206
+ - 数据合同不因重排而改变权威来源;
207
+ - Goal/Plan 仍来自最新有效 TurnCommit,不创造虚构步骤或审核状态;
208
+ - tool detail 仍读取预先生成的安全 derivative;
209
+ - 现有 collapsed shortcut badge 迁移到新的一级 icon rail。
210
+
211
+ ### 5.3 审阅面板
212
+
213
+ 审阅面板由三层组成:
214
+
215
+ 1. **Overview**:分支、HEAD、变更文件数、staged/unstaged/untracked/conflict、最近验证结论;
216
+ 2. **Changed files**:按状态分组、按路径过滤、显示增删行数;
217
+ 3. **Diff viewer**:统一 Diff、hunk 导航、行号、空白字符开关、复制、选区送入对话。
218
+
219
+ P0 操作:
220
+
221
+ - 刷新变更;
222
+ - 在文件之间导航;
223
+ - 折叠/展开 hunk;
224
+ - 选择一个文件或 hunk,生成结构化 `review_context` 并附加到 Composer;
225
+ - “请 Orion 修复此处”只产生用户可见草稿,用户确认发送后才成为 Agent 输入;
226
+ - 查看与当前 workspace revision 绑定的验证 receipt。
227
+
228
+ P0 明确不做浏览器端 accept/reject/revert/stage。若未来增加,必须作为幂等 mutation,经 ToolGateway、
229
+ 明确 expected revision 和审批,不得用直接文件写入实现。
230
+
231
+ ### 5.4 终端面板
232
+
233
+ 终端必须满足真实 terminal 语义:PTY、ANSI、resize、交互程序和进程生命周期,不以 `exec_command`
234
+ 工具卡代替。
235
+
236
+ #### 前端
237
+
238
+ - 使用维护中的 Web terminal emulator;优先评估 `@xterm/xterm` 及 fit/accessibility addon;
239
+ - 支持 1–4 个 terminal tab,显示 shell、cwd、running/exited 状态;
240
+ - 支持复制、清屏、重连、关闭;粘贴多行命令时二次确认;
241
+ - `Ctrl/Cmd+K` 等快捷键仅在 terminal 获得焦点时生效,不劫持全局;
242
+ - 屏幕阅读器模式、光标对比度和 reduced motion 纳入门禁。
243
+
244
+ #### Host
245
+
246
+ - 新建 `TerminalManagerV1`,每个 terminal 强绑定 workspaceId 和 canonical cwd;
247
+ - 使用真正的 PTY backend。优先评估 `node-pty`,但只有在 Node 22.12/24/26 的 source-clean
248
+ exact-tarball 安装、ABI 和运行门禁通过后才能纳入生产依赖;
249
+ - 默认启动不读取登录 profile 的安全交互 shell,继承环境使用 allowlist,并删除 token/key/secret/auth
250
+ 等变量;用户 profile 模式不属于 v0.3.1;
251
+ - terminal 是用户显式启动的特权表面,模型、Skill、MCP 和页面自动化不得创建 terminal 或写入输入;
252
+ - 输出不进入 Workbench SSE、日志、release receipt 或 transcript;保留最多 2MiB 内存滚动窗口;
253
+ - Host 重启后 terminal 明确变为 `lost`,不伪造进程恢复;
254
+ - workspace 切换时旧 terminal 可保持 detached,但受全局 4 个 PTY/每项目 2 个 PTY 限额;
255
+ - Host shutdown、workspace 移除和显式 close 必须终止 child process tree。
256
+
257
+ #### 传输
258
+
259
+ Workbench 原有事件继续使用 SSE;PTY 使用独立同源 WebSocket,避免每个按键一个 HTTP mutation:
260
+
261
+ 1. `POST /terminals` 通过 nonce 创建 terminal,并返回短期、单次使用的 stream ticket;
262
+ 2. WebSocket URL 只带 opaque terminalId,不把 ticket 放入 URL;
263
+ 3. 升级时先校验 loopback Host 和 exact Origin;连接后第一帧必须在 5 秒内提交 ticket;
264
+ 4. ticket 使用后立即失效;input/resize/output 有 monotonic sequence;
265
+ 5. gap、buffer overflow 或 ticket 失效都进入明确 reconnect/lost 状态,禁止静默丢字符。
266
+
267
+ 真实终端可能显示用户主动访问的敏感信息,因此 UI 必须有一次性风险说明;它不能借“脱敏”之名破坏
268
+ terminal 字节语义,也不能把原始输出复制到普通 Web 诊断或证据文件。
269
+
270
+ ### 5.5 文件面板
271
+
272
+ P0 能力:
273
+
274
+ - 以项目根为唯一 root 的懒加载树;
275
+ - 目录展开、文件名搜索、Git 状态 decoration;
276
+ - 只读文本预览、行号、换行、复制、跳到指定行;
277
+ - 大文件按行/字节分页,二进制文件只显示元数据;
278
+ - 默认忽略 `.git`、`node_modules`、构建缓存和 Orion 自身私有存储;
279
+ - `.env`、credential、keychain、SSH key 等敏感模式不返回内容;
280
+ - symlink 显示为 symlink,只有 realpath 仍位于 workspace 内才可继续读取。
281
+
282
+ 服务端返回 opaque nodeId/fileId。浏览器不得把任意路径拼到 URL,也不得使用 nodeId 绕过 active
283
+ workspace。文件内容响应包含 content revision;翻页时 revision 不一致返回 409,前端重新载入第一页。
284
+
285
+ 文件搜索 P0 只搜索文件名和已加载路径,不承诺全仓内容索引。全仓内容搜索和文件编辑列入 P1。
286
+
287
+ ### 5.6 Git 面板
288
+
289
+ P0 展示:
290
+
291
+ - 是否为 Git repository、repo root 的安全显示名;
292
+ - branch/detached HEAD、short SHA、最近 commit;
293
+ - upstream、ahead/behind;
294
+ - staged、unstaged、untracked、conflicted 分组;
295
+ - 最近 commit log 的 cursor page;
296
+ - 选择文件进入审阅 Diff;
297
+ - refresh 和 stale revision 提示。
298
+
299
+ 实现复用 `workspace-state.ts`/`workspace-diff.ts` 的解析思想,但抽出 `GitReadModelServiceV1`,统一:
300
+
301
+ - 仅用 `execFile` + argv,不经 shell;
302
+ - `-c core.quotepath=false`、固定 timeout、maxBuffer 和条目上限;
303
+ - canonical repo root 必须位于 active workspace 内或等于 active workspace;
304
+ - 不返回包含凭证的 remote URL;只返回 remote 名称和 sanitized host(可选);
305
+ - branch/status/diff/log 共用 `repositoryRevision`,不能跨 revision 拼接;
306
+ - 非 Git 目录是正常 empty state,不作为 Host 错误。
307
+
308
+ stage、unstage、commit、push、checkout 等 mutation 延后至 P1,并需要单独安全方案。
309
+
310
+ ## 6. 右侧宽度调整
311
+
312
+ ### 6.1 状态模型
313
+
314
+ ```ts
315
+ interface WorkPanelLayoutPreferenceV1 {
316
+ expanded: boolean;
317
+ widthPx: number; // clamp 320..min(720, viewport * 0.55)
318
+ activePanel: 'agent' | 'review' | 'terminal' | 'files' | 'git';
319
+ agentTab: 'goal' | 'activity' | 'integrations' | 'diagnostics';
320
+ }
321
+ ```
322
+
323
+ - 宽度和一级面板属于设备 UI preference,保存在 localStorage;
324
+ - Agent 二级 tab 可同样本地保存;
325
+ - 项目/Session 数据不写入 localStorage;
326
+ - localStorage 不可用时回退默认值,不阻断启动;
327
+ - preference schema 有版本,非法/超界值被丢弃;
328
+ - mobile drawer 使用 viewport 安全宽度,但不覆盖桌面 `widthPx`。
329
+
330
+ ### 6.2 IDE 式指针拖动
331
+
332
+ Resize handle:
333
+
334
+ - 分隔线本身保持轻量,不做成可聚焦按钮;hover/drag 时显示 `col-resize` 光标和高亮线;
335
+ - 鼠标或触控板按下后使用 pointer capture,左右拖动即时改变宽度并禁止误选文字;
336
+ - 双击分隔线恢复 420px 默认宽度;
337
+ - 精细调宽不提供键盘操作;键盘用户继续通过既有“展开/折叠工作面板”按钮控制面板显隐;
338
+ - 拖动期间只更新 CSS custom property,pointerup 后再持久化,避免每帧 React 全树重渲染;
339
+ - reduced-motion 下关闭 grid transition;
340
+ - 中间列将小于 560px 时自动进入 overlay 模式,不能继续挤压对话。
341
+
342
+ ## 7. 左侧多项目导航
343
+
344
+ ### 7.1 项目模型
345
+
346
+ 当前从 Session 历史推导工作区会丢失“已打开但还没有 Session”的项目。v0.3.1 新增持久
347
+ `WorkspaceRegistryV1`:
348
+
349
+ ```ts
350
+ interface WorkspaceRegistryEntryV1 {
351
+ id: string; // opaque stable id
352
+ canonicalPath: string; // Host only authority
353
+ label: string;
354
+ lastActivatedAt: string;
355
+ pinnedOrder?: number;
356
+ }
357
+ ```
358
+
359
+ - 注册表位于 Orion config root,原子写入并使用锁/CAS;
360
+ - 只记录用户显式打开过的目录,不扫描 HOME 或磁盘;
361
+ - path 不作为 mutation identity;API 使用 opaque workspaceId;
362
+ - 已删除、不可读和安全边界失败的目录显示 unavailable,可从列表移除;
363
+ - 从现有 Session catalog 一次性迁移已知项目,迁移幂等;
364
+ - 当前 workspace 即使无 Session 也必须保留。
365
+
366
+ ### 7.2 左栏结构
367
+
368
+ ```text
369
+ ORION CODE
370
+
371
+ [Search projects and sessions]
372
+
373
+ PINNED
374
+ ▾ orion-code main M12
375
+ ● Optimize Web shell running
376
+ Session 3840b3fe 90 msgs
377
+
378
+ RECENT
379
+ ▸ orion-studio main clean
380
+ ▾ orion-agents-www feat M2
381
+ Website release idle
382
+
383
+ [Open project] [Settings]
384
+ Runtime connected · v0.3.1
385
+ ```
386
+
387
+ 行为:
388
+
389
+ - 项目可独立展开/折叠;展开时懒加载该项目的第一个 Session page;
390
+ - 当前 active 项目和 active Session 有唯一、清晰的 `aria-current`;
391
+ - 项目摘要显示 branch、dirty count、Session count、running/approval 标记;
392
+ - 搜索同时匹配已加载项目和 Session;结果区域明确提示是否仍有未加载页;
393
+ - “打开项目”复用受控本地目录输入/选择流程;
394
+ - 置顶和最近分组属于 P0;拖动重排属于 P1,P0 用菜单“置顶/取消置顶”;
395
+ - 多项目树使用虚拟列表或 windowing;DOM 不随历史项目数线性无限增长;
396
+ - 项目切换期间旧项目仍可见,但主区显示明确 transition,Composer 禁用。
397
+
398
+ ### 7.3 原子 Context transition
399
+
400
+ 为避免先切 workspace、再切 Session 的中间态,新建统一 mutation:
401
+
402
+ ```text
403
+ POST /context/activate
404
+ {
405
+ requestId,
406
+ expectedContextRevision,
407
+ workspaceId,
408
+ sessionId: string | null
409
+ }
410
+ ```
411
+
412
+ Host 在同一 transition owner 中:
413
+
414
+ 1. 校验 workspaceId 和可访问性;
415
+ 2. 校验 Session 属于目标 workspace;
416
+ 3. drain 当前 Runtime;
417
+ 4. 安装目标 workspace Runtime;
418
+ 5. 可选恢复 Session;
419
+ 6. 返回新的 bootstrap snapshot 与 `contextRevision`;
420
+ 7. 发出一个 authoritative `workbench_state` edge。
421
+
422
+ 失败时恢复旧 context;无法恢复则进入明确 fatal recovery state。客户端不得自动重放可能有副作用的命令。
423
+
424
+ ## 8. 专业 UI 设计系统
425
+
426
+ ### 8.1 设计原则
427
+
428
+ - **工程信息优先**:路径、分支、状态和结果比装饰性卡片更重要;
429
+ - **安静的层级**:减少大面积渐变和重复边框,靠间距、字体、分组和轻量 surface 建立层次;
430
+ - **高密度但可读**:body 不低于 12px,关键 meta 不低于 11px;
431
+ - **状态可辨识**:颜色不是唯一信号,配合 icon、文案和形状;
432
+ - **同构状态**:所有列表和面板使用同一 loading/empty/error/stale/offline 模式;
433
+ - **本地优先**:不加载外部字体、图标或遥测资源。
434
+
435
+ ### 8.2 Tokens
436
+
437
+ 扩展当前 CSS variables 为语义 tokens:
438
+
439
+ - surfaces:canvas、rail、panel、raised、hover、selected、terminal;
440
+ - text:primary、secondary、muted、disabled、inverse;
441
+ - borders:subtle、default、strong、focus、danger;
442
+ - status:success、warning、danger、info、running、conflict、untracked;
443
+ - spacing:4/8/12/16/24/32;
444
+ - radius:6/8/12,减少无差别大圆角;
445
+ - typography:title、section、body、meta、code、badge;
446
+ - motion:120ms micro、180ms panel,reduced motion = 0ms。
447
+
448
+ Light/Dark/System 共用语义 token,不在组件里写散落色值。所有组合在自动 contrast test 中验证。
449
+
450
+ ### 8.3 组件边界
451
+
452
+ 建议拆分:
453
+
454
+ ```text
455
+ WorkbenchShell
456
+ ├── ProjectNavigator
457
+ │ ├── ProjectSearch
458
+ │ ├── ProjectTree
459
+ │ └── SessionTree
460
+ ├── ConversationWorkspace
461
+ └── WorkPanelDock
462
+ ├── WorkPanelRail
463
+ ├── WorkPanelResizeHandle
464
+ ├── AgentPanel
465
+ ├── ReviewPanel
466
+ ├── TerminalPanel
467
+ ├── FileExplorerPanel
468
+ └── GitPanel
469
+ ```
470
+
471
+ 共享基础组件:`PanelHeader`、`ResourceList`、`VirtualTree`、`StatusBadge`、`EmptyState`、
472
+ `LoadingSkeleton`、`ErrorState`、`RevisionBanner`、`SplitView`、`CodeViewport`、`IconButton`。
473
+
474
+ `Inspector.tsx` 不继续膨胀。每个业务面板拥有独立 reducer/query hook;Shell 只管理布局、选择和焦点。
475
+
476
+ ### 8.4 视觉与交互状态矩阵
477
+
478
+ 每个面板必须实现并截图:
479
+
480
+ - normal with data;
481
+ - empty;
482
+ - initial loading;
483
+ - incremental loading;
484
+ - stale revision;
485
+ - recoverable error;
486
+ - offline/Host closed;
487
+ - permission/capability unavailable;
488
+ - light/dark;
489
+ - 320/390/760/1180/1440;
490
+ - 100% 和 200% zoom。
491
+
492
+ ## 9. API 与数据合同
493
+
494
+ ### 9.1 新增/调整的只读资源
495
+
496
+ 最终路径在实现前写入 `docs/architecture/v0.3.1-web-api.yaml`,至少覆盖:
497
+
498
+ | 资源 | 建议路由 | 关键合同 |
499
+ | --------------- | ---------------------------------------- | ----------------------------------------------------- |
500
+ | 项目 | `GET /workspaces` | registry page、Git 摘要、revision-bound cursor |
501
+ | 项目 Session | `GET /workspaces/{workspaceId}/sessions` | inactive project 可读、分页、无 Runtime side effect |
502
+ | Context | `POST /context/activate` | requestId + expectedContextRevision + 原子切换 |
503
+ | 文件树 | `GET /files?parentId&cursor` | opaque id、懒加载、root containment |
504
+ | 文件内容 | `GET /files/{fileId}/content?cursor` | content revision、文本分页、binary metadata |
505
+ | Git status | `GET /git/status` | repositoryRevision、bounded groups |
506
+ | Git log | `GET /git/log?cursor` | keyset page、sanitized author metadata |
507
+ | Git diff | `GET /git/diff/{fileId}?cursor` | revision-bound hunks、输出预算 |
508
+ | 审阅摘要 | `GET /review` | change set + verification receipt refs |
509
+ | Terminal list | `GET /terminals` | active workspace terminal metadata only |
510
+ | Terminal create | `POST /terminals` | requestId、expectedContextRevision、single-use ticket |
511
+ | Terminal close | `DELETE /terminals/{id}` | requestId、幂等、process-tree termination |
512
+
513
+ ### 9.2 统一合同规则
514
+
515
+ - 所有 mutation 都有 UUID requestId、body digest 冲突检测和 admission cap;
516
+ - 所有 session-bound command 保留 expectedSessionId;workspace-bound mutation 增加 expectedContextRevision;
517
+ - 所有 collection cursor 绑定 route、workspace、revision、排序键和页边界;
518
+ - 所有文件/Git/审阅响应都有资源 revision;跨 revision continuation 返回 409;
519
+ - 所有响应限制 items、bytes、lines、depth 和执行时间;
520
+ - 任何 path 只作为 display metadata 返回,操作使用 opaque ID;
521
+ - SSE 新增 `workspace_resource_invalidated`,只表示需重取,不携带完整 Diff/文件内容;
522
+ - terminal output 永远不进入 SSE;
523
+ - capability flags 增加 review/files/git/terminal,缺少 backend 时 UI 显示 unavailable,不伪装为空数据。
524
+
525
+ ### 9.3 刷新策略
526
+
527
+ - 正确性依赖 revisioned GET,不依赖 watcher;
528
+ - ToolGateway write/edit receipt、terminal command completion、context activation 触发 resource invalidation;
529
+ - 面板获得焦点时若数据超过 2 秒可刷新;
530
+ - 外部编辑可用 bounded watcher 提示刷新,但 watcher 丢事件不能破坏正确性;
531
+ - Git 和文件请求每 workspace 最多一个并发 refresh,新请求取消旧请求;
532
+ - 不在后台对所有已知项目轮询 Git status。
533
+
534
+ ## 10. 安全、隐私与权限边界
535
+
536
+ ### 10.1 文件与 Git
537
+
538
+ - 每次读取都以 canonical active workspace 重新做 realpath containment;
539
+ - symlink、rename、删除并发按 fail-closed 处理;
540
+ - 拒绝绝对路径、`..`、NUL、Git pathspec magic 和超长路径;
541
+ - 文件树不跟随 workspace 外 symlink;
542
+ - 敏感文件名 blocklist 与文本 redaction 共用 `src/services/redaction.ts`,避免多套规则漂移;
543
+ - Git 使用 argv,不执行用户提供的 shell string;
544
+ - diff/log/status 输出在 Host 截断、解析和脱敏后才进入浏览器;
545
+ - remote credential、环境变量、authorization、terminal ticket 不进入页面诊断或日志。
546
+
547
+ ### 10.2 终端
548
+
549
+ - terminal 只接受真实用户手势创建;Agent API 没有 terminal input 能力;
550
+ - 同源 WebSocket 校验 Host、Origin、单次 ticket、连接超时和 terminal ownership;
551
+ - inherited env 采用 allowlist;Host 不把 provider secrets 注入 PTY;
552
+ - terminal 输出不持久化;复制由用户明确触发;
553
+ - 资源上限:4 PTY、2MiB scrollback/PTY、输出速率和 frame size 上限、idle timeout 可配置;
554
+ - 关闭和 Host shutdown 杀死完整 process tree,测试无 orphan;
555
+ - PTY backend 的 native binary、安装脚本和 Node ABI 纳入供应链与 exact-tarball 门禁。
556
+
557
+ ### 10.3 浏览器边界
558
+
559
+ - 继续只监听 loopback;
560
+ - CSP 保持 `script-src 'self'`,不引入 CDN;
561
+ - 新 WebSocket 不放宽普通 HTTP 的 nonce、Origin、Host 和 content-type 校验;
562
+ - 所有用户可见错误只返回稳定 code + 安全文案,本地详细错误留在 Host diagnostics;
563
+ - E2E 对 HTML、SSE、WS、截图、manifest 和 Host stdout/stderr 执行 opaque secret sentinel 扫描。
564
+
565
+ ## 11. 性能与可恢复性
566
+
567
+ - 项目、Session、文件、Git log、Diff hunks 均分页,禁止客户端自动 drain 全部页;
568
+ - 左侧项目树和长文件列表使用 windowing;
569
+ - Diff viewer 只渲染 viewport 附近 hunk;单响应默认 ≤ 256KiB;
570
+ - 文件预览单响应默认 ≤ 128KiB,完整读取由显式分页完成;
571
+ - Git status 默认 ≤ 2,000 entries,超出时返回 truncated + nextCursor;
572
+ - Terminal output 使用独立流和 backpressure,不与 transcript/SSE retention 竞争;
573
+ - 面板切换不销毁仍在运行的 terminal,但普通只读面板可释放大对象;
574
+ - 页面刷新从 bootstrap + active context snapshot 重建;无 active Session 时文件/Git 仍可基于 active workspace 工作;
575
+ - `replay_reset` 继续是普通 Workbench SSE 的硬屏障;terminal stream 使用独立 sequence/gap 恢复;
576
+ - Host restart 后只恢复 durable workspace registry 和 UI 可重取状态,不宣称恢复 PTY 进程。
577
+
578
+ ## 12. 无障碍与键盘
579
+
580
+ ### 12.1 必须支持
581
+
582
+ - `Cmd/Ctrl+B`:切换项目导航;
583
+ - `Cmd/Ctrl+Shift+B`:切换右侧工作面板;
584
+ - `Cmd/Ctrl+Shift+1..5`:Agent/审阅/终端/文件/Git;
585
+ - 工作面板展开/折叠按钮保持完整键盘能力;精细宽度调整只由鼠标/触控板分隔条拖动完成;
586
+ - Project tree 使用标准 tree/treeitem 或语义等价的 disclosure + list,方向键行为一致;
587
+ - 面板 tab 使用 roving tabindex;
588
+ - Diff hunk、文件行和 terminal toolbar 均有可感知名称;
589
+ - drawer focus trap、Escape、scrim、焦点恢复;
590
+ - loading/status 用 `aria-live`,持续 terminal output 不逐字播报;
591
+ - 200% zoom 后控件不重叠,主要功能不丢失;
592
+ - reduced motion、forced colors/high contrast 有专门测试。
593
+
594
+ ### 12.2 可读性门槛
595
+
596
+ - 正文最小 12px/1.5;辅助文字最小 11px/1.4;
597
+ - 代码和 terminal 默认 12–13px,可在设置中调整到 11–18px;
598
+ - 不用只靠红/绿区分 staged、unstaged、conflict;
599
+ - icon-only control 必须有 accessible name 和 tooltip;
600
+ - selected、focus、running、warning 均有不同视觉轮廓。
601
+
602
+ ## 13. 实施切片
603
+
604
+ ### Phase 0:合同与风险验证(P0)
605
+
606
+ 交付:
607
+
608
+ - 冻结本计划和 `docs/architecture/v0.3.1-web-api.yaml`;
609
+ - 记录当前 320/390/760/1180/1440 截图和性能基线;
610
+ - 完成 PTY dependency spike,验证 Node 22.12/24/26 exact-tarball install/run;
611
+ - 定义 WorkspaceRegistry、ContextRevision、RepositoryRevision、FileRevision、Terminal protocol;
612
+ - threat model:path traversal、symlink escape、Git argv、terminal ticket、secret output、orphan process。
613
+
614
+ 退出条件:协议引用全部解析;PTY backend 在三条 Node 线均有真实 proof;否则 v0.3.1 terminal 不能标记完成。
615
+
616
+ ### Phase 1:Shell 与可变宽右栏(P0)
617
+
618
+ 交付:
619
+
620
+ - `WorkbenchShell`、`WorkPanelDock`、一级 icon rail、Agent 二级导航;
621
+ - 320–720px IDE 式指针 resize、local preference、断点切 drawer;
622
+ - 从 `Inspector.tsx` 拆出 Agent 子面板;
623
+ - 统一 panel states 和焦点管理;
624
+ - 视觉 regression:expanded/collapsed/min/default/max/overlay。
625
+
626
+ 退出条件:现有 Goal/活动/能力/诊断不回归;桌面/移动所有交互键盘可达。
627
+
628
+ ### Phase 2:多项目左栏与原子 Context(P0)
629
+
630
+ 交付:
631
+
632
+ - WorkspaceRegistryV1 与迁移;
633
+ - 多项目 ProjectTree、lazy Session pages、search、pin/recent;
634
+ - inactive workspace Session read endpoint;
635
+ - 原子 `/context/activate` 与恢复;
636
+ - virtualized list 和 active/running/approval/Git summary badges。
637
+
638
+ 退出条件:至少三个真实项目可同时展示;跨项目 Session 激活无中间错误归属或命令误投。
639
+
640
+ ### Phase 3:文件、Git 与审阅(P0)
641
+
642
+ 交付:
643
+
644
+ - FileReadService、GitReadModelService、ReviewService;
645
+ - 文件树/预览、Git status/log、Review overview/diff;
646
+ - revision-bound paging、stale recovery、output budgets;
647
+ - “发送审阅反馈到 Composer”;
648
+ - Git/file invalidation 与手动 refresh。
649
+
650
+ 退出条件:真实仓库的 staged/unstaged/untracked/conflict、large diff、binary、symlink 和非 Git 项目均验证。
651
+
652
+ ### Phase 4:真实 PTY 终端(P0)
653
+
654
+ 交付:
655
+
656
+ - TerminalManagerV1、PTY backend、同源 WebSocket ticket handshake;
657
+ - terminal tabs、fit/resize、copy/paste guard、reconnect/lost/close;
658
+ - env scrub、process tree cleanup、buffer/backpressure/resource limits;
659
+ - terminal accessibility 与 light/dark tokens。
660
+
661
+ 退出条件:交互 shell、ANSI、resize、长输出、刷新重连、Host shutdown、workspace switch、无 orphan 全部通过。
662
+
663
+ ### Phase 5:专业 UI 收口与发布证据(P0)
664
+
665
+ 交付:
666
+
667
+ - semantic tokens、字号/间距/密度、全状态矩阵;
668
+ - light/dark/forced colors/reduced motion;-真实 installed-tarball Chrome E2E 和截图;
669
+ - Node 22.12/24/26 同一 tgz receipt;
670
+ - README、CHANGELOG、迁移和操作说明。
671
+
672
+ 退出条件:第 15 节所有 release gate 为 GO。
673
+
674
+ ### P1(v0.3.1 后续,不阻塞本计划 P0)
675
+
676
+ - 左侧拖动排序、自定义分组;
677
+ - 文件全文搜索和只读 symbol outline;
678
+ - Git stage/unstage/commit 的独立受控 mutation 方案;
679
+ - Diff inline comment 持久化;
680
+ - terminal command history preference;
681
+ - 左栏宽度调整;
682
+ - 项目级面板布局 profile。
683
+
684
+ ### P2
685
+
686
+ - 远端 PR/Issue/CI 集成;
687
+ - 多 Runtime 并发项目;
688
+ - 内置代码编辑器和 LSP;
689
+ - 可自由停靠的多面板布局;
690
+ - terminal session durable checkpoint。
691
+
692
+ ## 14. 测试方案
693
+
694
+ ### 14.1 单元与合同测试
695
+
696
+ 建议新增:
697
+
698
+ - `tests/web-workspace-registry.test.ts`:迁移、CAS、删除目录、并发写;
699
+ - `tests/web-context-transition.test.ts`:workspace + session 原子切换、rollback、TOCTOU;
700
+ - `tests/web-file-service.test.ts`:containment、symlink、sensitive file、binary、paging、stale cursor;
701
+ - `tests/web-git-read-model.test.ts`:unicode/rename/conflict/detached/upstream/large status;
702
+ - `tests/web-review-service.test.ts`:Diff budget、revision、verification receipts;
703
+ - `tests/web-terminal-manager.test.ts`:ticket、ownership、env scrub、buffer、close、orphan;
704
+ - `tests/web-layout-preferences.test.ts`:schema、clamp、invalid local value;
705
+ - `tests/web-protocol.test.ts`:全部新增 discriminated schema 和拒绝路径。
706
+
707
+ ### 14.2 组件与可访问性测试
708
+
709
+ - ProjectTree 键盘、展开/折叠、virtualization、active identity;
710
+ - Resize gutter 的鼠标/触控板 drag、双击复位和边界 clamp;
711
+ - Work panel tab/focus/persistence;
712
+ - Diff viewer hunk navigation;
713
+ - terminal toolbar 和 screen-reader mode;
714
+ - 主题、200% zoom、reduced motion、forced colors。
715
+
716
+ ### 14.3 真实 E2E
717
+
718
+ 建议新建:
719
+
720
+ | 场景 ID | 真实旅程 |
721
+ | ----------- | --------------------------------------------------------------------------------------- |
722
+ | WEB31-P0-01 | packaged bootstrap + 三项目可见 + lazy Session page |
723
+ | WEB31-P0-02 | 跨项目 Session 原子切换 + 命令只落目标 Session |
724
+ | WEB31-P0-03 | 鼠标/触控板分隔条 min/default/max 拖动 + 双击复位 + refresh persistence;无键盘调宽入口 |
725
+ | WEB31-P0-04 | Agent 旧能力迁移无回归 |
726
+ | WEB31-P0-05 | 文件树、文本分页、binary、敏感文件和 symlink escape |
727
+ | WEB31-P0-06 | Git clean/dirty/staged/untracked/conflict/log/detached |
728
+ | WEB31-P0-07 | Review Diff + selected hunk 送入 Composer |
729
+ | WEB31-P0-08 | 真实 PTY input/output/ANSI/resize/tab/close |
730
+ | WEB31-P0-09 | terminal refresh reconnect、gap、Host restart lost、无 orphan |
731
+ | WEB31-P0-10 | SSE/WS 并存、对话流不被 terminal 长输出挤掉 |
732
+ | WEB31-P0-11 | 1180/760/390/320 drawer、焦点、200% zoom |
733
+ | WEB31-P0-12 | light/dark/reduced-motion/axe/secret sentinel |
734
+
735
+ E2E 必须从同一个 source-clean tgz 安装,使用真实 Chrome、真实 Git fixture、真实 PTY 和真实 Host;
736
+ 不能用 DOM 注入伪造 Git/文件/terminal 状态。截图裁剪到产品窗口,不记录绝对路径、terminal 原始输出或 secret。
737
+
738
+ ### 14.4 性能测试
739
+
740
+ - 100 项目 × 每项目 200 Session 的列表与搜索;
741
+ - 100k 文件的合成树,验证 lazy page 和 DOM 上限;
742
+ - 2,000 changed files、50MiB raw diff,验证首屏预算和 pagination;
743
+ - 10MiB terminal burst,验证 backpressure、UI 帧率和 transcript 独立性;
744
+ - cold Host / warm Host 分别记录 workspaces、sessions、Git、files、diff;
745
+ - 计数器包括 Git process count、bytes read、items parsed、DOM nodes、WS buffered bytes。
746
+
747
+ ## 15. 验收标准与 Release Gate
748
+
749
+ ### 15.1 Given / When / Then
750
+
751
+ #### AC-01 右侧工程能力
752
+
753
+ Given 一个有 Git 变更、文件、验证结果和可用 shell 的真实项目,When 用户依次打开右侧 Agent、审阅、
754
+ 终端、文件和 Git,Then 每个入口展示对应 Host 权威数据,终端可真实交互,且没有通过解析 transcript
755
+ 或 Tool 文本伪造状态。
756
+
757
+ #### AC-02 可变宽右栏
758
+
759
+ Given 桌面布局,When 用户用鼠标或触控板拖动分隔条,Then 右栏在
760
+ `320..min(720, viewport - 280 - 560)` 的合法范围内变化;1440px 下上限为 600px,1560px 及以上可达
761
+ 720px,中间列始终不小于 560px;刷新后恢复偏好,切到窄屏变 drawer,返回桌面仍恢复该偏好宽度。
762
+
763
+ #### AC-03 多工作区左栏
764
+
765
+ Given 至少三个已注册项目,其中一个无 Session、一个非 active、一个含运行 Session,When 页面启动,
766
+ Then 三个项目都可见;展开项目只加载该项目 Session;点击非 active 项目 Session 后 workspace + session
767
+ 原子切换,Composer 在完成前禁用,任何命令都不会落到错误 Session。
768
+
769
+ #### AC-04 专业 UI
770
+
771
+ Given dark/light、320–1440px、100%/200% zoom 和键盘/屏幕阅读器,When 用户完成项目切换、面板切换、
772
+ Diff 导航、terminal 创建/关闭和发送消息,Then 无横向溢出、焦点丢失、不可达操作、低对比度阻断或
773
+ 只有颜色的状态表达。
774
+
775
+ #### AC-05 安全边界
776
+
777
+ Given workspace 外 symlink、sensitive filename、恶意 Git path、过期 terminal ticket 和 secret sentinel,
778
+ When 请求文件/Git/terminal API,Then Host fail-closed,浏览器、SSE、WS 普通诊断、截图和证据中 sentinel
779
+ 出现 0 次,且无 workspace 外读取或 orphan process。
780
+
781
+ #### AC-06 性能
782
+
783
+ Given 第 14.4 节的规模 fixture,When 打开项目、Git、文件、Diff 和终端,Then 满足第 2.2 节 p95、DOM、
784
+ bytes 和帧率门槛,不预取全部集合,不把 terminal output 放入 Workbench SSE。
785
+
786
+ ### 15.2 发布必须同时满足
787
+
788
+ - `npm run lint`、`npm run build`、完整 Jest、Web/E2E TypeScript、Prettier、`git diff --check`;
789
+ - OpenAPI parse/ref/operationId/security/requestId/cursor/revision 自动检查;
790
+ - WEB31-P0-01..12 全部真实 Chrome GO,无 skip/expected-fail;
791
+ - Node 22.12、24.0、26.0 使用**同一个** source-clean tgz,runtime + critical Web/PTY journey 全 GO;
792
+ - terminal native dependency 在三线都能 clean install,不依赖开发机已有 binary;
793
+ - axe blocking 0,console/page/HTTP5xx/secret/dropped event/orphan process 计数 0;
794
+ - package version、README、CHANGELOG、migration、截图、receipt digest 一致;
795
+ - 当前 live v0.3.0 不作为 v0.3.1 发布证明。
796
+
797
+ ## 16. 风险与缓解
798
+
799
+ | 风险 | 影响 | 缓解 |
800
+ | ------------------------------------ | -------------------------------- | --------------------------------------------------------------------------- |
801
+ | PTY native dependency 不支持 Node 26 | v0.3.1 无法正式支持真实 terminal | Phase 0 先做 exact-tarball spike;失败即 release NO_GO,不降级成伪终端 |
802
+ | 多项目 UI 被误解为多 Runtime | 命令落错项目或资源竞争 | 单 active context、原子 activate、contextRevision、清晰 running 状态 |
803
+ | 文件/Git API 扩大本地数据暴露 | workspace 外读取或 secret 泄漏 | opaque ID、realpath containment、敏感文件策略、统一 redaction、sentinel E2E |
804
+ | 大仓库使 Git/文件树阻塞 Host | 对话和 Composer 卡顿 | worker/service 隔离、timeout、分页、取消、并发 1、性能 counters |
805
+ | 右侧功能过多 | 导航复杂、窄宽不可用 | 一级 5 入口,现有四项收进 Agent;窄宽 icon rail;统一面板 shell |
806
+ | resize 导致布局抖动 | 输入体验下降 | CSS variable + pointer capture;pointerup 才持久化;最小中栏门槛 |
807
+ | terminal 输出含敏感信息 | 浏览器/证据泄漏 | 明示特权表面、env scrub、非持久、禁入日志/receipt、截图不捕获原始输出 |
808
+ | watcher 丢事件 | stale Git/文件状态 | revisioned GET 为权威;watcher 只 invalidation;focus/explicit refresh 收敛 |
809
+
810
+ ## 17. 文件级实施建议
811
+
812
+ 预计新增或重构:
813
+
814
+ - `web/src/layout/WorkbenchShell.tsx`
815
+ - `web/src/layout/WorkPanelDock.tsx`
816
+ - `web/src/layout/WorkPanelResizeHandle.tsx`
817
+ - `web/src/components/projects/ProjectNavigator.tsx`
818
+ - `web/src/components/agent/AgentPanel.tsx`
819
+ - `web/src/components/review/ReviewPanel.tsx`
820
+ - `web/src/components/terminal/TerminalPanel.tsx`
821
+ - `web/src/components/files/FileExplorerPanel.tsx`
822
+ - `web/src/components/git/GitPanel.tsx`
823
+ - `web/src/components/shared/*`
824
+ - `web/src/state/layout-preferences.ts`
825
+ - `src/services/workspace-registry.ts`
826
+ - `src/web/workspace-file-service.ts`
827
+ - `src/web/git-read-model-service.ts`
828
+ - `src/web/review-service.ts`
829
+ - `src/web/terminal-manager.ts`
830
+ - `src/web/terminal-server.ts`
831
+ - `docs/architecture/v0.3.1-web-api.yaml`
832
+ - `docs/test/v0.3.1-web-workbench-e2e-plan.md`
833
+ - `docs/migration/v0.3.0-to-v0.3.1.md`
834
+
835
+ 现有 `WorkspaceRail.tsx` 和 `Inspector.tsx` 应迁移为薄入口或删除,不能保留两套同时维护的 Shell。
836
+ `App.tsx` 只做 composition、global dialog 和 recovery boundary,不继续承载面板业务状态。
837
+
838
+ ## 18. 需求追踪矩阵
839
+
840
+ | 用户要求 | 方案位置 | 验收证据 |
841
+ | ----------------------------------------- | ------------- | ------------------------------------------- |
842
+ | 右侧参考 Codex,支持审阅、终端、文件、Git | 第 4、5、9 节 | WEB31-P0-04..10、AC-01、AC-05 |
843
+ | 右侧边栏可变宽 | 第 6 节 | WEB31-P0-03、AC-02 |
844
+ | 左侧参考 Codex,支持多工作区/项目展示 | 第 7 节 | WEB31-P0-01..02、AC-03 |
845
+ | UI 更专业 | 第 8、12 节 | WEB31-P0-11..12、AC-04、视觉状态矩阵 |
846
+ | 方案写入 docs | 本文件 | 文件存在、Markdown/链接/whitespace 检查通过 |
847
+
848
+ 只有当以上五行都有当前 source、真实运行和 release receipt 证据时,v0.3.1 Web Workbench 优化才算完成。