oh-my-agent-web 0.3.0 → 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 (250) hide show
  1. package/README.md +86 -455
  2. package/dist/server/approval/read-only.js +107 -0
  3. package/dist/server/approval/rules.js +85 -0
  4. package/dist/server/approval/scope.js +150 -0
  5. package/dist/server/brand.js +2 -0
  6. package/dist/server/cli-config.js +52 -0
  7. package/dist/server/cli-info.js +101 -0
  8. package/dist/server/cli.js +304 -0
  9. package/dist/server/engine/builtin.js +61 -0
  10. package/dist/server/engine/catalog.js +8 -0
  11. package/dist/server/engine/codex-approvals.js +45 -0
  12. package/dist/server/engine/codex-map.js +298 -0
  13. package/dist/server/engine/codex-sessions.js +159 -0
  14. package/dist/server/engine/codex-transport.js +49 -0
  15. package/dist/server/engine/codex.js +314 -0
  16. package/dist/server/engine/dsh-history.js +195 -0
  17. package/dist/server/engine/dsh-log.js +245 -0
  18. package/dist/server/engine/dsh-map.js +221 -0
  19. package/dist/server/engine/dsh-sessions.js +207 -0
  20. package/dist/server/engine/dsh-transport.js +37 -0
  21. package/dist/server/engine/dsh.js +284 -0
  22. package/dist/server/engine/fake.js +231 -0
  23. package/dist/server/engine/jsonrpc-stdio.js +241 -0
  24. package/dist/server/engine/model-registry-reload.js +115 -0
  25. package/dist/server/engine/pi-events.js +148 -0
  26. package/dist/server/engine/pi-rename.js +14 -0
  27. package/dist/server/engine/pi-sdk.js +343 -0
  28. package/dist/server/engine/pi-session-model.js +23 -0
  29. package/dist/server/engine/pi-thinking.js +34 -0
  30. package/dist/server/engine/pi-transcript.js +225 -0
  31. package/dist/server/engine/pi-version.js +11 -0
  32. package/dist/server/engine/port.js +1 -0
  33. package/dist/server/engine/registry.js +47 -0
  34. package/dist/server/engine/scratch.js +13 -0
  35. package/dist/server/engine/suggestion-guidance.js +9 -0
  36. package/dist/server/engine/switchable.js +22 -0
  37. package/dist/server/engine/wiring.js +107 -0
  38. package/dist/server/files/dir-routes.js +40 -0
  39. package/dist/server/files/file-search.js +63 -0
  40. package/dist/server/files/file-service.js +232 -0
  41. package/dist/server/files/files-routes.js +182 -0
  42. package/dist/server/files/git-info.js +186 -0
  43. package/dist/server/http/auth-routes.js +99 -0
  44. package/dist/server/http/auth.js +191 -0
  45. package/dist/server/http/aux-routes.js +24 -0
  46. package/dist/server/http/compress.js +75 -0
  47. package/dist/server/http/health-and-static.js +33 -0
  48. package/dist/server/http/live-routes.js +113 -0
  49. package/dist/server/http/login-page.js +200 -0
  50. package/dist/server/index.js +342 -520
  51. package/dist/server/markers/actions.js +262 -0
  52. package/dist/server/protocol-parse.js +201 -0
  53. package/dist/server/protocol-settings.js +1 -0
  54. package/dist/server/protocol.js +6 -0
  55. package/dist/server/providers/catalog-store.js +85 -0
  56. package/dist/server/providers/catalog-writes.js +197 -0
  57. package/dist/server/providers/catalog.js +77 -0
  58. package/dist/server/providers/enabled-models.js +118 -0
  59. package/dist/server/providers/import-models.js +69 -0
  60. package/dist/server/providers/import-routes.js +136 -0
  61. package/dist/server/providers/model-test.js +52 -0
  62. package/dist/server/providers/probe.js +64 -0
  63. package/dist/server/providers/provider-handlers.js +203 -0
  64. package/dist/server/providers/provider-store.js +327 -0
  65. package/dist/server/providers/request-headers.js +7 -0
  66. package/dist/server/providers/validate.js +241 -0
  67. package/dist/server/push/push-routes.js +114 -0
  68. package/dist/server/push/push.js +120 -0
  69. package/dist/server/session/approval-bridge.js +103 -0
  70. package/dist/server/session/attachment-resolve.js +21 -0
  71. package/dist/server/session/client-view.js +82 -0
  72. package/dist/server/session/conversation-create.js +65 -0
  73. package/dist/server/session/delete-session.js +84 -0
  74. package/dist/server/session/engine-switch.js +108 -0
  75. package/dist/server/session/lock.js +82 -0
  76. package/dist/server/session/model-controller.js +111 -0
  77. package/dist/server/session/notices.js +31 -0
  78. package/dist/server/session/pi-opener.js +123 -0
  79. package/dist/server/session/pi-refresh.js +51 -0
  80. package/dist/server/session/pi-sessions-provider.js +46 -0
  81. package/dist/server/session/pi-sessions.js +272 -0
  82. package/dist/server/session/refresh-actions.js +42 -0
  83. package/dist/server/session/rename-session.js +23 -0
  84. package/dist/server/session/runtime-services.js +28 -0
  85. package/dist/server/session/runtime-types.js +1 -0
  86. package/dist/server/session/runtime.js +358 -0
  87. package/dist/server/session/session-stats.js +88 -0
  88. package/dist/server/session/settings.js +367 -0
  89. package/dist/server/session/snapshot-for.js +7 -0
  90. package/dist/server/session/stats-refresher.js +50 -0
  91. package/dist/server/session/switch-conversation.js +86 -0
  92. package/dist/server/session/throttle.js +14 -0
  93. package/dist/server/session/turn-events.js +126 -0
  94. package/dist/server/session/turn-finish.js +79 -0
  95. package/dist/server/session/turn-markers.js +26 -0
  96. package/dist/server/session/turn-queue.js +111 -0
  97. package/dist/server/session/turn-send.js +88 -0
  98. package/dist/server/session/turn-watchdog.js +77 -0
  99. package/dist/server/sessions/session-routes.js +17 -0
  100. package/dist/server/skills/skill-routes.js +28 -0
  101. package/dist/server/skills/skill-store.js +134 -0
  102. package/dist/server/snapshot/fan-out.js +10 -0
  103. package/dist/server/snapshot/messages.js +75 -0
  104. package/dist/server/snapshot/sender.js +62 -0
  105. package/dist/server/snapshot/state.js +193 -0
  106. package/dist/server/terminal/terminal-routes.js +176 -0
  107. package/dist/server/terminal/terminal-session.js +140 -0
  108. package/dist/server/uploads/upload-routes.js +64 -0
  109. package/dist/server/uploads/upload-store.js +115 -0
  110. package/dist/server/util/data-dir.js +36 -0
  111. package/dist/server/util/env.js +140 -0
  112. package/dist/server/util/ids.js +28 -0
  113. package/dist/server/util/log-file.js +67 -0
  114. package/dist/server/util/log.js +52 -0
  115. package/dist/server/util/origin.js +75 -0
  116. package/dist/server/util/paths.js +60 -0
  117. package/dist/server/util/pricing-index.js +121 -0
  118. package/dist/server/util/pricing.js +214 -0
  119. package/dist/server/util/startup.js +34 -0
  120. package/dist/server/util/upstream-version.js +140 -0
  121. package/dist/server/util/usage.js +19 -0
  122. package/dist/server/util/version.js +50 -0
  123. package/dist/server/ws/handle-message.js +95 -0
  124. package/package.json +49 -63
  125. package/web/dist/apple-touch-icon-precomposed.png +0 -0
  126. package/web/dist/apple-touch-icon.png +0 -0
  127. package/web/dist/assets/abnfDiagram-WEYOIA3C-NLp09iEC.js +1 -0
  128. package/web/dist/assets/arc-DviL9o3c.js +1 -0
  129. package/web/dist/assets/architecture-WOLXFQ4H-fjsM_Sy3.js +1 -0
  130. package/web/dist/assets/architectureDiagram-ZHVYKT53-Cn3B4TE8.js +36 -0
  131. package/web/dist/assets/array-BifhSqXX.js +1 -0
  132. package/web/dist/assets/blockDiagram-RJAE7QA3-CIuvxWvi.js +140 -0
  133. package/web/dist/assets/c4Diagram-XDPPPE54-DvdKmEpF.js +38 -0
  134. package/web/dist/assets/channel-C3AQ6nAs.js +1 -0
  135. package/web/dist/assets/chunk-2E7WHVMD-HNNASGCS.js +88 -0
  136. package/web/dist/assets/chunk-2Q5K7J3B-C1jixKkw.js +1 -0
  137. package/web/dist/assets/chunk-4EMNKR2T-Cg-eRwBE.js +1 -0
  138. package/web/dist/assets/chunk-55XCU76K-BweiisZL.js +1 -0
  139. package/web/dist/assets/chunk-5VM5RSS4-ZNzvKenW.js +15 -0
  140. package/web/dist/assets/chunk-7S6XSTFO-BCzIiP-6.js +2 -0
  141. package/web/dist/assets/chunk-AQDTSKZB-Dl0NRFuU.js +72 -0
  142. package/web/dist/assets/chunk-DSNLSHJZ-zhHCjjN9.js +129 -0
  143. package/web/dist/assets/chunk-DUW6YSOI-Dgx8z5s3.js +1 -0
  144. package/web/dist/assets/chunk-HAGFOTED-BDQqU2EH.js +62 -0
  145. package/web/dist/assets/chunk-HNE4Q36P-B-qRzMjX.js +1 -0
  146. package/web/dist/assets/chunk-J5ZVWO5B-oDCd-gWO.js +1 -0
  147. package/web/dist/assets/chunk-JWPE2WC7-DVXcaiue.js +1 -0
  148. package/web/dist/assets/chunk-NGNAAXSQ-C2Wy9Xmz.js +136 -0
  149. package/web/dist/assets/chunk-NQOKRVIF-CNcvhMn_.js +213 -0
  150. package/web/dist/assets/chunk-UHW7PFBP-Dwr8LUzr.js +1 -0
  151. package/web/dist/assets/chunk-VQ5W62QI-O8sN6jJu.js +1 -0
  152. package/web/dist/assets/chunk-WQQL4CDK-B6-59Zg2.js +10 -0
  153. package/web/dist/assets/chunk-XXDRQBXY-DvSbeUlZ.js +1 -0
  154. package/web/dist/assets/chunk-Y2CYZVJY-DsF7k-Jl.js +1 -0
  155. package/web/dist/assets/chunk-YZO67HFG-BXpKYKsw.js +1 -0
  156. package/web/dist/assets/chunk-ZAUX2LTX-B1Z5VSkz.js +1 -0
  157. package/web/dist/assets/chunk-ZCHMQSOR-h_5mBLIA.js +2 -0
  158. package/web/dist/assets/classDiagram-v2-4MYWR3UA-Dr6JnaaV.js +217 -0
  159. package/web/dist/assets/cose-bilkent-JH36ORCC-36ShkR7R.js +1 -0
  160. package/web/dist/assets/cynefin-EF2NZ3EQ-Dg6bI7pC.js +1 -0
  161. package/web/dist/assets/cynefinDiagram-WF24UDRP-B0YHpBlR.js +62 -0
  162. package/web/dist/assets/cytoscape.esm-BegBNzOV.js +321 -0
  163. package/web/dist/assets/dagre-NK4GIZVX-Cx3mn7YS.js +4 -0
  164. package/web/dist/assets/defaultLocale-BFoDCU3G.js +1 -0
  165. package/web/dist/assets/diagram-CBK3MWTC-l8aZG_Bm.js +24 -0
  166. package/web/dist/assets/diagram-I5XIIV2D-Bd5f14_h.js +24 -0
  167. package/web/dist/assets/diagram-ODIL2UCW-hBsxCYUj.js +30 -0
  168. package/web/dist/assets/diagram-PFBEJUXE-BgpIBUYl.js +3 -0
  169. package/web/dist/assets/diagram-RJA3I4VV-CDU1gUVD.js +41 -0
  170. package/web/dist/assets/diagram-TYUNFSNR-Iuxh7Tqf.js +200 -0
  171. package/web/dist/assets/dist-C86cKTuE.js +1 -0
  172. package/web/dist/assets/ebnfDiagram-V4P3TTPT-Cms0HFKh.js +1 -0
  173. package/web/dist/assets/elk-QONTBCTQ-B7yEy0PQ.js +27 -0
  174. package/web/dist/assets/erDiagram-KYQIGQAA-CL48j4aU.js +99 -0
  175. package/web/dist/assets/eventmodeling-K75KTNOO-CFvkaejh.js +1 -0
  176. package/web/dist/assets/flowDiagram-IUGLLWBU-6UyKXpqG.js +1 -0
  177. package/web/dist/assets/ganttDiagram-R7GPNTJY-vdMr-0ZV.js +292 -0
  178. package/web/dist/assets/gitGraph-VSP46ZUC-2z85Wuwo.js +1 -0
  179. package/web/dist/assets/gitGraphDiagram-PDYL7XHY-BY4GPiqC.js +106 -0
  180. package/web/dist/assets/graphlib-DS17s2tU.js +1 -0
  181. package/web/dist/assets/index-Bjn56a2i.js +76 -0
  182. package/web/dist/assets/index-Drp6e5iU.css +1 -0
  183. package/web/dist/assets/info-OHQRW6UA-ECzkYTx-.js +1 -0
  184. package/web/dist/assets/infoDiagram-MVDRKAX5-DDk5EAeb.js +2 -0
  185. package/web/dist/assets/init-C-OQMol4.js +1 -0
  186. package/web/dist/assets/ishikawaDiagram-HPEHV2GE-9yPH4J94.js +70 -0
  187. package/web/dist/assets/journeyDiagram-BOSHW7O7-BPTIap3l.js +139 -0
  188. package/web/dist/assets/kanban-definition-FNSA4HC5-BbADHrA8.js +89 -0
  189. package/web/dist/assets/katex-B_JcIwqj.js +257 -0
  190. package/web/dist/assets/line-CHV9_4lL.js +1 -0
  191. package/web/dist/assets/linear-C-eZsBTv.js +1 -0
  192. package/web/dist/assets/mermaid-parser.core-BiAhX1l1.js +7 -0
  193. package/web/dist/assets/mermaid.core-BxP_A_zj.js +44 -0
  194. package/web/dist/assets/mindmap-definition-6OY57UG3-BMWlit95.js +98 -0
  195. package/web/dist/assets/ordinal-BDEzSJ7C.js +1 -0
  196. package/web/dist/assets/packet-JDAUHWVQ-FVApuKOp.js +1 -0
  197. package/web/dist/assets/path-fybaL0A-.js +1 -0
  198. package/web/dist/assets/pegDiagram-ECIUJNBX-WjWJvDHM.js +1 -0
  199. package/web/dist/assets/pie-XZMESJXO-BGCZnvhp.js +1 -0
  200. package/web/dist/assets/pieDiagram-GNMPY74T-DJpAC_JC.js +39 -0
  201. package/web/dist/assets/quadrantDiagram-D57K4MC3-hxx5c7oq.js +7 -0
  202. package/web/dist/assets/radar-ABXABTNO-BU9Shc-O.js +1 -0
  203. package/web/dist/assets/railroad-I3PHUGI6-pWj8d-G4.js +1 -0
  204. package/web/dist/assets/railroad-abnf-LNEFI6M7-D7HZBTAj.js +1 -0
  205. package/web/dist/assets/railroad-ebnf-DWYD2UWJ-CKiXJSuM.js +1 -0
  206. package/web/dist/assets/railroad-peg-JR7BVNR7-DB3VJHgR.js +1 -0
  207. package/web/dist/assets/railroadDiagram-Y72NRBL7-Cev7Y65k.js +1 -0
  208. package/web/dist/assets/requirementDiagram-EQYSW5RA-CqbwMLD8.js +84 -0
  209. package/web/dist/assets/rough.esm-Dy-Kn_BL.js +1 -0
  210. package/web/dist/assets/sankeyDiagram-SY24JHO5-V2cyVi8q.js +40 -0
  211. package/web/dist/assets/sequenceDiagram-BLEHNHQU-By6NJOPM.js +169 -0
  212. package/web/dist/assets/sizeCapture-INFHLROL-3uHXrFqA.js +1 -0
  213. package/web/dist/assets/src-Da91fG3g.js +1 -0
  214. package/web/dist/assets/stateDiagram-v2-A6IESKWZ-BnPGX5UI.js +291 -0
  215. package/web/dist/assets/swimlanes-B3ENRKFQ-C58BpIpm.js +1 -0
  216. package/web/dist/assets/swimlanesDiagram-AYQRV4AK-RaivxSsc.js +8 -0
  217. package/web/dist/assets/timeline-definition-JXYKGLGB-Hgo1DhnS.js +120 -0
  218. package/web/dist/assets/treeView-D4JQ5SDB-DF0dfjqB.js +1 -0
  219. package/web/dist/assets/treemap-SAJKECNS-CSSM5FqB.js +1 -0
  220. package/web/dist/assets/usecaseDiagram-WPOLBNNX-BkBBD1NY.js +328 -0
  221. package/web/dist/assets/vennDiagram-Q3Y3IDCW-Bm28keX_.js +34 -0
  222. package/web/dist/assets/wardley-7MLQ67FV-By7KgEQX.js +1 -0
  223. package/web/dist/assets/wardleyDiagram-IVAIDKWA-oVtIrnGa.js +78 -0
  224. package/web/dist/assets/xychartDiagram-4URNHDU4-aI8FH4g2.js +7 -0
  225. package/web/dist/favicon-32.png +0 -0
  226. package/web/dist/favicon.ico +0 -0
  227. package/web/dist/favicon.svg +20 -8
  228. package/web/dist/icons/apple-touch-icon-180.png +0 -0
  229. package/web/dist/icons/icon-192.png +0 -0
  230. package/web/dist/icons/icon-512.png +0 -0
  231. package/web/dist/icons/icon-maskable-512.png +0 -0
  232. package/web/dist/index.html +21 -27
  233. package/web/dist/manifest.webmanifest +17 -0
  234. package/web/dist/maskable.svg +25 -0
  235. package/web/dist/sw.js +40 -0
  236. package/bin/oh-my-agent-web-ps.mjs +0 -203
  237. package/bin/oh-my-agent-web-ws.mjs +0 -782
  238. package/bin/oh-my-agent-web.mjs +0 -321
  239. package/bin/update-check.mjs +0 -142
  240. package/dist/server/codex-client.js +0 -310
  241. package/dist/server/codex-supervisor.js +0 -446
  242. package/dist/server/fs-service.js +0 -144
  243. package/dist/server/request-inspector.js +0 -458
  244. package/dist/shared/protocol.js +0 -112
  245. package/scripts/manage-server.mjs +0 -155
  246. package/scripts/omaw.mjs +0 -74
  247. package/shared/protocol.ts +0 -228
  248. package/web/dist/assets/index-5LJ5fRcO.js +0 -42
  249. package/web/dist/assets/index-QiDfPKFo.css +0 -1
  250. package/web/dist/assets/markdown-CYXe6JZx.js +0 -55
package/README.md CHANGED
@@ -1,491 +1,122 @@
1
1
  # oh-my-agent-web
2
2
 
3
- A browser cockpit for the [Codex CLI](https://github.com/openai/codex) `app-server`.
4
- Chat, tool calls, diffs and approval dialogs in one tab.
3
+ 把编码智能体(pi / Codex / DeepSeek Harness)包进一个**本机网页工作台**:左边是多项目 + 会话列表,中间是对话,右边随时看文件、跑终端。
5
4
 
6
- The server is a **transparent JSON-RPC proxy + process supervisor**. It starts
7
- `codex app-server` on boot, keeps it alive, and lets the browser invoke any
8
- app-server method — while adding a few local `omaw/*` helpers.
5
+ 单用户、只听回环、会话事实源是引擎自己的落盘文件 —— 不引数据库、不建账号体系,`agent-web` 起一个进程就是一个人的工作台。
9
6
 
10
- ```
11
- browser <--ws /ws--> oh-my-agent-web server <--ws--> codex app-server (ws://127.0.0.1:25258)
12
- ```
13
-
14
- ## Install
15
-
16
- The published package is **`oh-my-agent-web`**. It installs two equivalent
17
- commands: **`oh-my-agent-web`** and the short alias **`omaw`**.
18
-
19
- ```bash
20
- # global install
21
- npm install -g oh-my-agent-web
22
- npm install -g oh-my-agent-web@latest # force the newest version
23
-
24
- # or run without installing
25
- npx oh-my-agent-web # start the UI
26
- npx oh-my-agent-web ws # WS client (default ws://127.0.0.1:25258)
27
- npx oh-my-agent-web ws --port 25258 # WS client on an explicit port
28
- npx oh-my-agent-web ps # list processes and ports
29
- ```
30
-
31
- After a global install, `oh-my-agent-web` and `omaw` are the same program:
32
-
33
- ```bash
34
- omaw # http://127.0.0.1:25257 (= oh-my-agent-web)
35
- omaw ws # interactive WS client
36
- omaw ws --port 25259
37
- omaw ps # processes + ports
38
- ```
7
+ ## 它是什么
39
8
 
40
- > Requires Node.js >= 22. If `npx oh-my-agent-web` fails to find the binary
41
- > on your setup, use `npx -p oh-my-agent-web oh-my-agent-web ...` or a global
42
- > install instead.
9
+ - **一个仓库一个项目**:侧栏按目录分组,会话就是引擎的会话文件(pi 的 `.pi/agent/sessions/**/*.jsonl`、Codex 的 thread、DSH 的会话),在 CLI 里看到的名字/内容与网页里一致。
10
+ - **对话 + 工具 + 审批**:工具调用卡片、流式输出、命令/文件改动按审批规则放行或逐次询问。
11
+ - **文件管理**:目录树、按名搜索、预览(markdown / 图片 / PDF / 音视频流)、上传、拖拽附件;项目在 git 仓库里时右上角多一枚分支标签,点开可切换本地分支(工作区有未提交改动会先确认)。
12
+ - **内嵌终端**:基于 `node-pty` 的真 PTY(xterm.js 渲染),和会话共用工作目录。
13
+ - **模型与供应商**:在「模型」面板里配置 provider / 模型清单,支持从别的客户端导入、逐个试连。
14
+ - **技能面板**:列出 pi 技能并启停,读单个技能的文件。
15
+ - **推送**:Web Push 订阅,回合结束时通知(需要 https 或 localhost)。
16
+ - **手机可用**:窄屏自适应布局,侧栏可收起。
43
17
 
44
- ### Update notification
18
+ ## 快速开始
45
19
 
46
- Every run of `oh-my-agent-web` (including the `ws` and `ps` subcommands) checks npm for
47
- a newer version and prints a short notice when one exists:
48
-
49
- ```
50
- Update available: oh-my-agent-web 0.1.0 → 0.2.0
51
- npm install -g oh-my-agent-web@latest
52
- (disable this check with OMAW_NO_UPDATE_CHECK=1)
53
- ```
54
-
55
- The check hits the registry at most once per 24h (result cached in
56
- `~/.cache/oh-my-agent-web/update-check.json`), never blocks on errors, and is skipped
57
- for `--help` / `--version` / `--json`.
58
-
59
- | Env | Default | Meaning |
60
- | --- | --- | --- |
61
- | `OMAW_NO_UPDATE_CHECK` | *(unset)* | `1` disables the version check |
62
- | `OMAW_UPDATE_CHECK_INTERVAL_MS` | `86400000` (24h) | Minimum gap between registry checks |
63
-
64
- Also skipped automatically when `CI` or `NO_UPDATE_NOTIFIER` is set.
65
-
66
- ## Quick start (from source)
20
+ 要求 **Node.js ≥ 22.19**(macOS / Linux;Windows 未验证,`node-pty` 需要能编译或拿到预编译产物)。
67
21
 
68
22
  ```bash
69
23
  npm install
70
- npm run build # builds web/ (Vite) + server/ (tsc)
71
- npm start # http://127.0.0.1:25257
72
- ```
73
-
74
- `npm start` boots the server, spawns `codex app-server --listen ws://127.0.0.1:25258`
75
- (unless a healthy one is already running), and opens your browser. The app-server
76
- is started as-is: by default oh-my-agent-web injects **no** `chatgpt_base_url` /
77
- `model_providers.capture.base_url` overrides and runs no capture proxy. Set
78
- `OMAW_REQUEST_INSPECTOR=1` to opt into the loopback request/response inspector
79
- (which is what makes each session show live request/response logs).
80
-
81
- ## Development
82
-
83
- ```bash
84
- npm run dev
24
+ npm run build
25
+ npm start # 前台运行;Ctrl-C 退出
85
26
  ```
86
27
 
87
- Runs the backend (`tsx watch`, port **25257**) and mounts Vite **in the same
88
- process** as middleware (`OMAW_DEV_WEB=1`). There is only one port and one entry
89
- point — **http://127.0.0.1:25257** — which serves the live frontend source (with
90
- HMR) and the `/ws` hub from the same origin. No build step, no second dev port.
28
+ 浏览器打开 <http://127.0.0.1:25257>。
91
29
 
92
- Use `npm run build:web` (or `npm start`) when you want the static `web/dist`
93
- bundle instead. The frontend lives in `web/`; backend in `server/`.
94
-
95
- To iterate on the UI without spending model tokens, `web/dev-mock-server.mjs`
96
- is a scripted stand-in for the backend that speaks the same protocol and
97
- replays a recorded turn (reasoning, streamed message, command output, diff,
98
- token usage, an approval request). It listens on `:25257/ws`, so the Vite proxy
99
- picks it up with no config change. This is the one flow where the plain `vite`
100
- CLI is the entry point (there is no backend to host it as middleware), so open
101
- the URL Vite prints — `npm run dev:web`:
30
+ 装成全局命令后,可以用简写 `omaw` 或 `agent-web`(`oh-my-agent-web` / `omaw` / `agent-web` 三个命令指向同一入口,完全等价):
102
31
 
103
32
  ```bash
104
- node web/dev-mock-server.mjs # 代替 npm run dev(它只提供 :25257/ws)
105
- npm run dev:web
106
- ```
107
-
108
- Other useful scripts:
109
-
110
- | Script | What it does |
111
- | ------------------------ | ----------------------------------------------------- |
112
- | `npm run build:server` | `tsc -p tsconfig.server.json` → `dist/` |
113
- | `npm run stop` | Gracefully stops the service on `OMAW_PORT` (default 25257) |
114
- | `npm run restart` | Stops and starts the service again |
115
- | `npm run typecheck` | Typechecks server + web without emitting |
116
- | `npm run smoke` | End-to-end smoke test against a real codex app-server |
117
- | `npm run ws` | WebSocket client for the app-server (see below) |
118
- | `npm run omaw` | Run from source: no args → dev stack on http://127.0.0.1:25257 (Vite in-process, no build) |
119
- | `npm run omaw -- <args>` | Run the CLI from source, e.g. `npm run omaw -- ps`, `npm run omaw -- ws -p 25259` |
120
-
121
- ## CLI
122
-
33
+ npm i -g .
34
+ agent-web -d # 后台启动(日志写到 <dataDir>/daemon.log)
35
+ agent-web status # 看 pid / 端口 / 运行时长 / 会话数
36
+ agent-web restart -d # 改完代码重启
37
+ agent-web stop
123
38
  ```
124
- oh-my-agent-web [options]
125
39
 
126
- --port <n> Port for the web UI (env OMAW_PORT, default 25257)
127
- --host <h> Host to bind (env OMAW_HOST, default 127.0.0.1)
128
- --cwd <path> Working directory for codex (env OMAW_CWD, default cwd)
129
- --codex-port <n> app-server port (env OMAW_CODEX_PORT, default 25258)
130
- --codex-bin <name> codex executable (env OMAW_CODEX_BIN, default "codex")
131
- --no-browser Do not open the browser (env OMAW_OPEN=0)
132
- --help, -h Show help
133
- --version, -v Show version
40
+ ### 常用参数
134
41
 
135
- ws [options] ["msg"] WebSocket client for the app-server
136
- ps [--json] Running processes and their ports
137
- stop [--port <n>] Stop the service listening on the UI port
138
- restart [options] Stop the service, then serve again in the foreground
139
- ```
140
-
141
- Flags win over environment variables.
142
-
143
- Anything that is not a flag and not one of the subcommands above is rejected —
144
- only `[options]` starts a server, so a mistyped subcommand can never silently
145
- launch one.
42
+ | 参数 | 环境变量 | 默认 | 说明 |
43
+ | --- | --- | --- | --- |
44
+ | `-p, --port` | `AGENT_WEB_PORT` | `25257` | 监听端口 |
45
+ | `-H, --host` | `AGENT_WEB_HOST` | `127.0.0.1` | 监听地址;对外访问才需要改 |
46
+ | `-P, --password` | `AGENT_WEB_PASSWORD` | 无 | 访问密码;不设 = 只允许本机 |
47
+ | `--allow-host` | `AGENT_WEB_ALLOWED_HOSTS` | 只认 loopback | 额外允许的域名 / 局域网 IP(可多次或逗号分隔) |
48
+ | `--data-dir` | `AGENT_WEB_DATA_DIR` | `~/.oh-my-agent-web` | 密码、设置、上传、日志、会话缓存都放这 |
49
+ | — | `AGENT_WEB_LOG` | `info` | `debug` / `info` / `warn` / `error` |
50
+ | — | `AGENT_WEB_CWD` | `process.cwd()` | 默认工作区(还没开会话时用) |
146
51
 
147
- ### `oh-my-agent-web stop` / `restart`
148
-
149
- Gracefully stop the service listening on the UI port (the same code path as
150
- `npm run stop`): SIGTERM, then SIGKILL after an 8s grace period. It refuses to
151
- touch the port if the listener is not one of ours.
152
-
153
- ```bash
154
- oh-my-agent-web stop # stop on OMAW_PORT (default 25257)
155
- oh-my-agent-web stop --port 3000 # stop the instance on another port
156
- oh-my-agent-web restart --no-browser # stop, then serve again in this process
157
- ```
52
+ 数据目录里会有:`password`(设过一次就记住)、`allowed-hosts`、`settings.json`、`pi-sessions-cache.json`、`uploads/`、`logs/`、`server.lock`。
158
53
 
159
- ### `oh-my-agent-web ws` — WebSocket client
54
+ > 想从手机访问:`agent-web -d -H 0.0.0.0 -P 你的密码 --allow-host 你的域名`,反代 / 隧道请带上 `X-Forwarded-For`(来源校验会看它)。
160
55
 
161
- Connect straight to the app-server over its WebSocket (default
162
- `ws://127.0.0.1:25258`), without going through the browser UI:
56
+ ## 开发
163
57
 
164
58
  ```bash
165
- oh-my-agent-web ws # interactive: type a message, Enter to send (Ctrl-D to exit)
166
- oh-my-agent-web ws "list the files here" # one-shot, then exit
167
- echo "write a hello world" | oh-my-agent-web ws
168
- oh-my-agent-web ws --port 25259 # explicit port
169
- oh-my-agent-web ws --url ws://host:port # explicit address
170
- oh-my-agent-web ws -t <threadId> "continue" # resume an existing thread
171
- oh-my-agent-web ws -y --model gpt-5.5 "..." # auto-approve approvals, pick a model
59
+ npm run dev # 一条命令起两个进程
172
60
  ```
173
61
 
174
- Interactive mode prints the active model on connect and shows it in the prompt; use
175
- `/model` to pick from the server's models with ↑/↓ + Enter (or `/model <name>` to switch
176
- directly; applies from the next turn), `/help` for commands and `/quit` to exit. A turn
177
- that fails with the upstream "prompt flagged" false-positive is retried automatically
178
- once (`--retry <n>` / `--no-retry`).
179
-
180
- Run the same client through npm (pass flags after `--`):
181
-
182
- ```bash
183
- npm run ws # interactive
184
- npm run ws -- --port 25259
185
- npm run ws -- -t <threadId> "continue"
186
- ```
62
+ - 对外仍然只有一个 **25257**(Vite 监听并反代),后端躲在内部 **25258**:开发和生产记同一个地址。
63
+ - 前端热更新走 Vite,后端 `tsx --watch` 自动重启。
64
+ - 手机调试:`npm run dev -- --host 0.0.0.0`。
187
65
 
188
- | Flag | Meaning |
66
+ | 命令 | 作用 |
189
67
  | --- | --- |
190
- | `--url <ws://host:port>` | Full address (bare `host:port` also works) |
191
- | `--addr <host:port>` / `--host <h>` / `-p, --port <n>` | Address or port (default `127.0.0.1:25258`) |
192
- | `--cwd <dir>` | Working directory (default: current dir) |
193
- | `-t, --thread <id>` | Resume an existing thread |
194
- | `--model <name>` | Model id (`/model` in interactive mode to list/switch) |
195
- | `--sandbox <mode>` / `--approval <mode>` | Session sandbox / approval policy |
196
- | `-y, --auto-approve` / `--decline` | Auto-answer approvals instead of prompting |
197
- | `-v, --verbose` / `--json` | Print reasoning deltas / raw event JSON |
198
- | `--timeout <sec>` | Max wait per turn (default 1800) |
199
- | `--retry <n>` / `--no-retry` | Retry a flagged/transient turn up to n times (default 1) |
200
- | `--retry-delay <ms>` | Base retry delay, default 1000 (grows per attempt) |
201
-
202
- Env: `CODEX_WS_URL` / `CODEX_WS_HOST` / `CODEX_WS_PORT`.
203
-
204
- Connection priority: `--url` > `--host`/`--port` (`--addr`) > env vars > defaults
205
- (`127.0.0.1:25258`).
206
-
207
- ### `oh-my-agent-web ps` — processes & ports
208
-
209
- Show every running oh-my-agent-web / codex app-server process, whether it is managed by
210
- this project or external, and which TCP ports it listens on:
211
-
212
- ```bash
213
- oh-my-agent-web ps # table
214
- oh-my-agent-web ps --json # machine-readable
215
- ```
216
-
217
- ```
218
- TYPE PID PPID SCOPE PORTS COMMAND
219
- app-server 16397 96476 managed 25258 node .../codex app-server --listen ws://127.0.0.1:25258
220
- app-server 5567 5216 external - /Applications/ChatGPT.app/.../codex app-server ...
221
- oh-my-agent-web 96476 1 - 25257 node bin/oh-my-agent-web.mjs --no-browser
222
-
223
- ports: ui=25257 app-server=25258
224
- 25257 listening: yes pid: 96476
225
- 25258 listening: yes pid: 16398
226
- ```
227
-
228
- ## Environment variables
229
-
230
- | Variable | Default | Meaning |
231
- | ------------------ | ------------- | ---------------------------------------------------------------- |
232
- | `OMAW_PORT` | `25257` | Web UI / HTTP port |
233
- | `OMAW_HOST` | `127.0.0.1` | Bind host (loopback by default) |
234
- | `OMAW_CWD` | `process.cwd()` | Default working directory for codex |
235
- | `OMAW_CODEX_PORT` | `25258` | app-server port |
236
- | `OMAW_CODEX_BIN` | `codex` | codex executable |
237
- | `OMAW_ALLOW_ORIGINS` | *(unset)* | Comma-separated extra allowed WS origins. When unset: same-origin + localhost only |
238
- | `OMAW_OPEN` | *(unset)* | `0` disables auto-opening the browser |
239
- | `OMAW_REQUEST_INSPECTOR` | *(unset)* | Set to `1` to enable the loopback request/response capture proxy. Off by default; when off, no `chatgpt_base_url` / `model_providers.capture.base_url` overrides are injected |
240
- | `OMAW_CODEX_UPSTREAM` | `https://chatgpt.com/backend-api/codex` | Upstream URL for the capture proxy |
241
- | `OMAW_LOG_MAX_BODY` | `16 MiB` | Maximum body retained per exchange |
242
-
243
- ## Architecture
244
-
245
- - **`server/request-inspector.ts`** — optional (opt-in via `OMAW_REQUEST_INSPECTOR=1`)
246
- loopback Responses API proxy: forwards
247
- managed Codex traffic, redacts sensitive headers, incrementally captures SSE,
248
- persists `data/YYYY-MM-DD/*.json` with `0600` permissions, and serves
249
- thread-filtered summaries/details to the UI.
250
- - **`server/codex-supervisor.ts`** — owns the `codex app-server` child:
251
- - Reuses a healthy app-server if the port already answers `GET /readyz`
252
- (external attach); otherwise spawns one.
253
- - Readiness via stdout (`listening on:`) **and** `/readyz` polling.
254
- - stdout/stderr → 500-line ring buffer (`omaw/codex/log`).
255
- - Auto-restart with exponential backoff (cap 10s), `restarts` counter.
256
- - Clean shutdown: SIGTERM then SIGKILL; only kills children **we** spawned.
257
- - **`server/codex-client.ts`** — WS JSON-RPC client: `initialize` on every
258
- (re)connect, id-correlated `request()`, `notification` / `serverRequest`
259
- events, `respond()` / `respondError()`.
260
- - **`server/fs-service.ts`** — `omaw/paths`, `omaw/fs/list`, `omaw/fs/read`.
261
- - **`server/index.ts`** — express + `ws` hub, `/api/health`, `/api/version`,
262
- static SPA serving from `web/dist`, origin checks, 30s heartbeat.
263
- - **`bin/oh-my-agent-web.mjs`** — CLI entry, loads `dist/server/index.js`.
264
-
265
- ## Browser ↔ server protocol
266
-
267
- See [`shared/protocol.ts`](./shared/protocol.ts) for the frozen envelope.
268
- Everything except `omaw/*` is proxied verbatim to codex.
269
-
270
- Client → server: `rpc`, `reply`, `ping`.
271
- Server → client: `welcome`, `status`, `rpcResult`, `event`, `serverRequest`, `pong`.
272
-
273
- ### Local methods (`omaw/*`)
274
-
275
- | Method | Params | Result |
276
- | --------------------- | ----------------------------- | ---------------------------------------- |
277
- | `omaw/paths` | — | `{ cwd, home, codexHome }` |
278
- | `omaw/fs/list` | `{ path?, maxEntries? }` | `{ path, entries: FsEntry[] }` |
279
- | `omaw/fs/read` | `{ path, maxBytes? }` | `{ path, text, truncated }` |
280
- | `omaw/codex/status` | — | `{ status: CodexStatus }` |
281
- | `omaw/codex/restart` | — | `{ ok: true }` |
282
- | `omaw/codex/log` | — | `{ lines: string[] }` |
283
- | `omaw/request-logs/list` | `{ threadId, limit? }` | Thread-filtered live/history summaries |
284
- | `omaw/request-logs/detail` | `{ id }` | Full request/response exchange |
285
-
286
- `omaw/fs/list` sorts directories first and skips `node_modules` / `.git` unless
287
- you are already inside one. `omaw/fs/read` refuses binary files (NUL byte) and
288
- truncates at `maxBytes` (default 256 KB).
289
-
290
- ### Error codes
291
-
292
- RPC failures come back as `{ type: "rpcResult", ok: false, error: { code, message, data? } }`:
293
-
294
- | Code | Meaning |
295
- | -------- | -------------------------------------------------------------- |
296
- | `-32001` | codex app-server not connected (proxy guard) |
297
- | `-32002` | codex connection closed / client closed |
298
- | `-32003` | local request timeout (initialize only) |
299
- | `-32000` | generic fs / internal error |
300
- | `-32601` | unknown `omaw/*` method |
301
- | `-32602` | invalid params |
302
-
303
- ### Approvals / server requests
304
- Codex server→client requests (approvals, user input, dynamic tool calls) are
305
- broadcast to **all** connected tabs as `serverRequest`. The first `reply` with a
306
- matching `id` wins; later replies are ignored. After resolving, the server
307
- broadcasts a codex-style notification:
308
-
309
- ```jsonc
310
- { "type": "event", "method": "serverRequest/resolved", "params": { "threadId": "...", "requestId": 123 } }
311
- ```
312
-
313
- so other tabs can dismiss their dialog.
314
-
315
- ### Notes for the frontend
316
-
317
- - Messages are accepted with or without `"jsonrpc": "2.0"`.
318
- - `status.codex.pid === null && status.codex.phase === "ready"` means the server
319
- attached to an **external** app-server (it will not be killed on shutdown).
320
- - The server re-sends `initialize` after every codex reconnect; browsers can
321
- hydrate a thread mid-session with `thread/read` (`includeTurns: true`).
322
- - `ServerInfo.codexVersion` is parsed from the handshake `userAgent` and may be
323
- `null` until the first connection completes.
324
-
325
- ## Approvals never show up?
326
-
327
- Codex routes escalation requests (sandbox escapes, blocked network access, MCP
328
- prompts) to a **reviewer**, configurable per thread via `approvalsReviewer`:
329
-
330
- | Value | Behaviour |
331
- | -------------------- | ---------------------------------------------------------------- |
332
- | `user` | Every request becomes a dialog in this UI |
333
- | `auto_review` | A prompted subagent decides — **no dialog is ever sent to the UI** |
334
- | `guardian_subagent` | Same idea, guardian variant |
335
-
336
- The default is `user`, but if your `~/.codex/config.toml` contains
337
- `approvals_reviewer = "auto_review"` the browser will stay silent and commands
338
- just run. Open **Settings → Who reviews approvals** and pick **Ask me** to route
339
- them to this UI for a thread you start (or the running turn).
340
-
341
- Read-only commands that the sandbox already allows never prompt at all — ask
342
- codex to write outside the workspace (e.g. into `~`) or hit the network to
343
- exercise the dialog.
344
-
345
- ## Frontend features
346
-
347
- - **Thread sidebar** — paginated/searchable `thread/list`, rename, archive,
348
- delete, fork; status dots and relative times. The list shows **active threads
349
- only** and the project picker scopes it, so there is no active/archived tab;
350
- `Archive` is available from a thread's `…` menu and hides it.
351
- - **Streaming transcript** — agent text, reasoning summaries, plans, live
352
- command output, `turn/diff/updated`. Deltas are coalesced on
353
- `requestAnimationFrame` so long turns stay smooth.
354
- - **Markdown** rendering with GFM + syntax highlighting; `[path](/abs/path)`
355
- links open a file preview sheet backed by `omaw/fs/read`.
356
- - **Command cards** — command, cwd, streamed output; only running/failed
357
- statuses are shown when they carry useful signal.
358
- - **Diff cards** — unified-diff rendering with line numbers and +/- colouring.
359
- Note that codex's `FileUpdateChange.diff` is **not** always a diff: it is raw
360
- file content for `add`/`delete` and bare `@@` hunks for `update`, so the
361
- renderer normalises all three.
362
- - **Approval dialogs** — command / file-change / user-input requests, with
363
- Accept, Accept for session, Decline, Cancel, plus an auto-approve toggle.
364
- - **Composer** — Enter to send, Stop to interrupt, `@file` mentions via
365
- `fuzzyFileSearch`, image paste, message queueing while a turn runs.
366
- - **Header** — model + reasoning effort, approval policy, sandbox, approvals
367
- reviewer, token/context meter, codex status + restart + log drawer.
368
- - **Session logs** — open from the active thread's terminal icon or `…` menu;
369
- groups requests by turn, polls live exchanges, and provides readable,
370
- request JSON, response JSON, and raw SSE views. Capture is enabled for
371
- app-server processes managed by this project; an external app-server cannot
372
- be intercepted and will show no new captures.
373
-
374
- ## Skins
375
-
376
- The UI ships four skins, switchable from the palette button in the header and
377
- remembered per browser (`localStorage`):
378
-
379
- | Skin | Look |
68
+ | `npm run typecheck` | 服务端 + 前端两套 `tsc --noEmit` |
69
+ | `npm run lint` | oxlint(`server` / `web/src` / `scripts`) |
70
+ | `npm run format` | prettier 全仓格式化(`format:check` 只检查) |
71
+ | `npm run build` | 服务端 `tsc` + 前端 `vite build` 到 `web/dist` |
72
+ | `npm run icons` | 重新生成 PWA 图标 |
73
+
74
+ ## 目录结构
75
+
76
+ ```
77
+ oh-my-agent-web/
78
+ ├─ server/ 后端(Express + ws)
79
+ │ ├─ index.ts 进程入口:路由、WS、静态产物、优雅退出
80
+ │ ├─ cli.ts agent-web / omaw 命令(start / stop / restart / status / upgrade)
81
+ │ ├─ protocol.ts WS 协议单源(前端通过 web/src/types.ts 复用类型)
82
+ │ ├─ engine/ 引擎适配层:pi(原生 SDK)/ codex / dsh / fake(测试)
83
+ │ ├─ session/ 会话运行时:切换、改名、删除、模型控制、审批桥
84
+ │ ├─ sessions/ 会话文件扫描(标题 / 模型 / 缓存)
85
+ │ ├─ files/ 文件树、预览、搜索、上传、git 分支
86
+ │ ├─ terminal/ PTY 终端
87
+ │ ├─ approval/ 审批规则与作用域判断
88
+ │ ├─ providers/ 自定义 provider / 模型清单
89
+ │ ├─ push/ Web Push
90
+ │ └─ skills/ 技能发现与启停
91
+ ├─ web/ 前端(React 19 + Vite)
92
+ │ └─ src/
93
+ │ ├─ components/ 侧栏、消息流、输入框、文件树、终端、各类面板
94
+ │ ├─ styles/ 按职责拆分的 CSS(无框架,一套 CSS 变量)
95
+ │ └─ use-*.ts 搜索 / 分支 / 分栏 / 复制等小 hooks
96
+ ├─ scripts/ dev 双进程、图标生成
97
+ ```
98
+
99
+ ## 引擎
100
+
101
+ | 引擎 | 说明 |
380
102
  | --- | --- |
381
- | **White** *(default)* | White canvas, grey chrome, blue accent — GitHub / pi-web style |
382
- | **Warm paper** | Cream canvas, ochre accent, easier on the eyes |
383
- | **Mist** | Cool grey-green canvas, teal accent |
384
- | **Midnight** | Near-black canvas, violet accent |
385
-
386
- Implementation notes:
387
-
388
- - A skin is nothing but a `[data-theme="<id>"]` block of CSS variables in
389
- `web/src/styles.css`; the layout never changes between skins.
390
- - `<html>` carries **two** attributes: `data-theme` (the skin) and `data-scheme`
391
- (`light` / `dark`). Rules that only make sense for light backgrounds — the
392
- syntax-highlighting palette, for instance — key off `data-scheme` so they are
393
- written once instead of per skin.
394
- - The registry lives in `web/src/lib/theme.ts`. Adding a skin = one entry there
395
- plus one variable block in `styles.css`.
396
- - `web/index.html` applies the stored skin in an inline script *before first
397
- paint*, otherwise the `:root` (dark) fallback flashes on load.
398
-
399
- ## Projects (workspaces)
400
-
401
- The selector at the top of the sidebar switches the **project** — codex's `cwd`.
402
- It is the app's primary navigation control:
403
-
404
- - The list is derived from the `cwd` of known codex threads, so projects appear
405
- automatically as soon as you use them anywhere (CLI, TUI, this UI).
406
- - Each row shows a compact path, a dot and the number of known threads; the
407
- current project is checked, and the app-server's default directory is pinned
408
- to the top.
409
- - Selecting a project **re-scopes the thread list** (via `thread/list`'s `cwd`
410
- filter), clears the transcript, and becomes the `cwd` for new threads.
411
- - `Use default directory` reverts to the app-server's cwd; `Custom path…` opens
412
- a thread in any directory you type. The choice persists across reloads.
413
- - Counts come from a separate, **unscoped** `thread/list` (`refreshProjects`),
414
- because the visible list is filtered and therefore cannot provide totals.
415
-
416
- ## Layout controls
417
-
418
- Everything about the workspace layout is draggable and remembered per browser:
419
-
420
- | Control | How | Persisted as |
421
- | --- | --- | --- |
422
- | Collapse the sidebar | Header panel button, the `X` in the sidebar, or `⌘/Ctrl+B` | `cw-sidebar-collapsed` |
423
- | Sidebar width | Drag its right edge (220–560px, max 50% of the window) | `cw-sidebar-width` |
424
- | File panel width | Drag its left edge | `cw-file-panel-width` |
425
-
426
- Details worth knowing:
427
-
428
- - **Double-click a resize handle** to reset that panel to its default width.
429
- - Widths are applied through CSS variables (`--sidebar-w`, `--file-panel-w`)
430
- rather than inline `width`, so the mobile media queries can still turn the
431
- sidebar into a drawer and the file panel into a full-height sheet. Resize
432
- handles are not rendered at all in those modes.
433
- - Dragging uses **pointer capture**, so the drag survives the cursor leaving the
434
- handle or the window.
435
- - `⌘/Ctrl+K` reveals the sidebar before focusing search, so it works while
436
- collapsed. `⌘/Ctrl+N` starts a thread, `⌘/Ctrl+B` toggles the sidebar.
437
-
438
- ## Composer
439
-
440
- The message box is deliberately compact and self-sizing — there is nothing to
441
- configure:
442
-
443
- - It **hugs the pane**: 10px from either side (no centred column), with the text
444
- ~9px from the box's left edge and the Send button ~5px from its right edge.
445
- - It is **one line tall** by default, with the Send button on the same row,
446
- vertically centred. The button is a flex sibling (not an overlay), so long
447
- text can never slide underneath it.
448
- - It **grows automatically** as the text wraps, up to ~9 lines (200px); past
449
- that the textarea scrolls internally instead of pushing the transcript off
450
- screen. Deleting lines shrinks it back.
451
- - `Enter` sends, `Shift+Enter` inserts a newline, and IME composition is
452
- respected (the keydown is ignored while composing).
453
- - While a turn is running the row swaps to **Stop** + **Queue**, and queued
454
- messages are flushed automatically when the turn ends.
455
-
456
- ## Verification
103
+ | **pi**(默认) | 完整的插件 / 技能生态、工具延迟加载、审批门禁、目标模式与子代理;模型与 provider 由本工作台管理 |
104
+ | **Codex** | codex 官方 agent,独立 loop 与沙箱,会话与 Codex Desktop / CLI 共用;审批是命令 / 文件级的 |
105
+ | **DeepSeek Harness** | DeepSeek 官方 agent(ACP),模型与思考档可切,权限逐次确认 |
106
+ | **fake** | 零 token 的脚本化引擎,只用来验证协议 / 工具 / 审批流程(`AGENT_WEB_ENGINE=fake`,默认不进切换面板) |
457
107
 
458
- `npm run smoke` runs a real end-to-end pass (spawns an app-server, starts a
459
- thread, runs a turn, asserts streamed events, `thread/read` hydration, and
460
- approval broadcast/dedupe).
108
+ 装没装的引擎不影响启动:只有切到它时才会报「没找到」。
461
109
 
462
- The UI was additionally driven in headless Chromium against a real
463
- `codex-cli 0.156.1` app-server and verified for: thread creation, streamed
464
- turn completion, command cards, add/update/delete diff rendering, the full
465
- approval round-trip (dialog → Accept → escalated command executes → turn
466
- completes), all four skins, project switching (thread list re-scoping +
467
- persistence across reload), sidebar collapse/expand, panel resizing
468
- (sidebar 288→428px, file panel 560→740px, both persisted), and the composer
469
- (48px / one line with Send on the same row → 87px at three lines → capped at
470
- 200px and scrolling at twenty lines → shrinks back) — plus no theme flash before
471
- first paint and zero console errors throughout.
110
+ ## 安全模型
472
111
 
473
- ### Startup races and process ownership
112
+ - 默认只监听 `127.0.0.1`,并校验 `Origin` / `Host`;要远程访问必须显式给 `-H` + `-P` + `--allow-host`。
113
+ - 工具与命令走审批:只读命令自动放行,其余按规则询问(规则可积累)。
114
+ - 删除会话是**改名到 `.deleted-<时间戳>`**,文件还在磁盘上,能捞回来。
115
+ - 上传的临时文件、会话缓存都在数据目录里,不写进你的项目目录。
474
116
 
475
- Two things the server does so clients don't have to care:
117
+ ## 文档
476
118
 
477
- - **Ready wait.** A browser can attach while `codex app-server` is still booting
478
- (or while the supervisor restarts it after a crash). Instead of failing the
479
- client's first `model/list` / `thread/list` with `-32001`, the proxy waits up to
480
- `CODEX_READY_WAIT_MS` (20s) for the app-server and only then reports an error.
481
- The UI additionally re-runs its codex-dependent bootstrap whenever the
482
- app-server transitions to connected, so a crash-restart recovers by itself.
483
- - **Process-group ownership.** `codex app-server` re-execs: the spawned shim forks
484
- the real listener. The child is therefore started `detached: true` and stopped
485
- by signalling the whole **process group** (`-pid`), with a group `SIGKILL` on
486
- exit as a safety net. Signalling only the direct child would orphan the
487
- listener, which keeps the port bound — the next start would then "attach" to
488
- that stale process and `restart()` would be a silent no-op.
119
+ 代码里的 `ADR-00xx` 引用是设计决策编号;具体缘由写在对应文件的头注释里。
489
120
 
490
121
  ## License
491
122