oh-my-agent-web 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +108 -450
- package/dist/server/approval/read-only.js +107 -0
- package/dist/server/approval/rules.js +85 -0
- package/dist/server/approval/scope.js +150 -0
- package/dist/server/brand.js +2 -0
- package/dist/server/cli-config.js +52 -0
- package/dist/server/cli-info.js +101 -0
- package/dist/server/cli.js +304 -0
- package/dist/server/engine/builtin.js +84 -0
- package/dist/server/engine/catalog.js +8 -0
- package/dist/server/engine/codex-approvals.js +45 -0
- package/dist/server/engine/codex-map.js +298 -0
- package/dist/server/engine/codex-sessions.js +159 -0
- package/dist/server/engine/codex-transport.js +49 -0
- package/dist/server/engine/codex.js +314 -0
- package/dist/server/engine/dsh-history.js +195 -0
- package/dist/server/engine/dsh-log.js +245 -0
- package/dist/server/engine/dsh-map.js +221 -0
- package/dist/server/engine/dsh-sessions.js +207 -0
- package/dist/server/engine/dsh-transport.js +37 -0
- package/dist/server/engine/dsh.js +284 -0
- package/dist/server/engine/fake.js +231 -0
- package/dist/server/engine/jsonrpc-stdio.js +241 -0
- package/dist/server/engine/model-registry-reload.js +115 -0
- package/dist/server/engine/narrate-guidance.js +22 -0
- package/dist/server/engine/opencode-map.js +499 -0
- package/dist/server/engine/opencode-projects.js +61 -0
- package/dist/server/engine/opencode-sessions.js +195 -0
- package/dist/server/engine/opencode-transport.js +48 -0
- package/dist/server/engine/opencode.js +394 -0
- package/dist/server/engine/pi-events.js +148 -0
- package/dist/server/engine/pi-plugins.js +310 -0
- package/dist/server/engine/pi-rename.js +14 -0
- package/dist/server/engine/pi-sdk.js +503 -0
- package/dist/server/engine/pi-session-model.js +23 -0
- package/dist/server/engine/pi-subagent-tool.js +166 -0
- package/dist/server/engine/pi-subagents.js +372 -0
- package/dist/server/engine/pi-thinking.js +34 -0
- package/dist/server/engine/pi-transcript.js +225 -0
- package/dist/server/engine/pi-version.js +11 -0
- package/dist/server/engine/port.js +1 -0
- package/dist/server/engine/registry.js +47 -0
- package/dist/server/engine/scratch.js +13 -0
- package/dist/server/engine/subagent-guidance.js +22 -0
- package/dist/server/engine/suggestion-guidance.js +9 -0
- package/dist/server/engine/switchable.js +22 -0
- package/dist/server/engine/wiring.js +166 -0
- package/dist/server/files/dir-routes.js +40 -0
- package/dist/server/files/file-search.js +63 -0
- package/dist/server/files/file-service.js +232 -0
- package/dist/server/files/files-routes.js +210 -0
- package/dist/server/files/git-info.js +361 -0
- package/dist/server/http/auth-routes.js +99 -0
- package/dist/server/http/auth.js +191 -0
- package/dist/server/http/aux-routes.js +40 -0
- package/dist/server/http/compress.js +77 -0
- package/dist/server/http/health-and-static.js +33 -0
- package/dist/server/http/live-routes.js +113 -0
- package/dist/server/http/login-page.js +200 -0
- package/dist/server/index.js +363 -520
- package/dist/server/markers/actions.js +262 -0
- package/dist/server/mcp/mcp-auth.js +184 -0
- package/dist/server/mcp/mcp-command.js +94 -0
- package/dist/server/mcp/mcp-import.js +290 -0
- package/dist/server/mcp/mcp-market-sources.js +192 -0
- package/dist/server/mcp/mcp-market-types.js +5 -0
- package/dist/server/mcp/mcp-market.js +175 -0
- package/dist/server/mcp/mcp-probe.js +134 -0
- package/dist/server/mcp/mcp-routes.js +70 -0
- package/dist/server/mcp/mcp-store.js +286 -0
- package/dist/server/mcp/pi-mcp-config.js +280 -0
- package/dist/server/plugins/plugin-routes.js +21 -0
- package/dist/server/protocol-parse.js +262 -0
- package/dist/server/protocol-settings.js +1 -0
- package/dist/server/protocol.js +6 -0
- package/dist/server/providers/catalog-store.js +85 -0
- package/dist/server/providers/catalog-writes.js +197 -0
- package/dist/server/providers/catalog.js +77 -0
- package/dist/server/providers/codex-models.js +96 -0
- package/dist/server/providers/codex-test.js +124 -0
- package/dist/server/providers/enabled-models.js +118 -0
- package/dist/server/providers/import-models.js +69 -0
- package/dist/server/providers/import-routes.js +203 -0
- package/dist/server/providers/model-test.js +52 -0
- package/dist/server/providers/probe.js +64 -0
- package/dist/server/providers/provider-handlers.js +223 -0
- package/dist/server/providers/provider-store.js +359 -0
- package/dist/server/providers/request-headers.js +7 -0
- package/dist/server/providers/subscription-routes.js +181 -0
- package/dist/server/providers/validate.js +241 -0
- package/dist/server/push/push-routes.js +114 -0
- package/dist/server/push/push.js +120 -0
- package/dist/server/session/approval-bridge.js +103 -0
- package/dist/server/session/attachment-resolve.js +21 -0
- package/dist/server/session/client-view.js +82 -0
- package/dist/server/session/conversation-create.js +65 -0
- package/dist/server/session/delete-session.js +84 -0
- package/dist/server/session/engine-switch.js +108 -0
- package/dist/server/session/lock.js +82 -0
- package/dist/server/session/model-controller.js +119 -0
- package/dist/server/session/notices.js +31 -0
- package/dist/server/session/pi-opener.js +123 -0
- package/dist/server/session/pi-refresh.js +51 -0
- package/dist/server/session/pi-sessions-provider.js +46 -0
- package/dist/server/session/pi-sessions.js +272 -0
- package/dist/server/session/refresh-actions.js +42 -0
- package/dist/server/session/rename-session.js +23 -0
- package/dist/server/session/runtime-services.js +28 -0
- package/dist/server/session/runtime-types.js +1 -0
- package/dist/server/session/runtime.js +380 -0
- package/dist/server/session/session-stats.js +91 -0
- package/dist/server/session/settings.js +367 -0
- package/dist/server/session/snapshot-for.js +7 -0
- package/dist/server/session/stats-refresher.js +50 -0
- package/dist/server/session/subagents.js +116 -0
- package/dist/server/session/switch-conversation.js +86 -0
- package/dist/server/session/throttle.js +14 -0
- package/dist/server/session/turn-events.js +126 -0
- package/dist/server/session/turn-finish.js +79 -0
- package/dist/server/session/turn-markers.js +26 -0
- package/dist/server/session/turn-queue.js +111 -0
- package/dist/server/session/turn-send.js +108 -0
- package/dist/server/session/turn-watchdog.js +77 -0
- package/dist/server/sessions/session-routes.js +17 -0
- package/dist/server/skills/skill-install.js +186 -0
- package/dist/server/skills/skill-routes.js +134 -0
- package/dist/server/skills/skill-store.js +163 -0
- package/dist/server/skills/skillhub.js +214 -0
- package/dist/server/skills/zip.js +121 -0
- package/dist/server/snapshot/fan-out.js +10 -0
- package/dist/server/snapshot/messages.js +75 -0
- package/dist/server/snapshot/sender.js +62 -0
- package/dist/server/snapshot/state.js +202 -0
- package/dist/server/subagents/profile-store.js +287 -0
- package/dist/server/terminal/terminal-routes.js +176 -0
- package/dist/server/terminal/terminal-session.js +140 -0
- package/dist/server/uploads/upload-routes.js +64 -0
- package/dist/server/uploads/upload-store.js +115 -0
- package/dist/server/util/data-dir.js +36 -0
- package/dist/server/util/env.js +146 -0
- package/dist/server/util/ids.js +28 -0
- package/dist/server/util/log-file.js +67 -0
- package/dist/server/util/log.js +52 -0
- package/dist/server/util/origin.js +75 -0
- package/dist/server/util/paths.js +60 -0
- package/dist/server/util/pricing-index.js +121 -0
- package/dist/server/util/pricing.js +214 -0
- package/dist/server/util/startup.js +34 -0
- package/dist/server/util/upstream-version.js +140 -0
- package/dist/server/util/usage.js +19 -0
- package/dist/server/util/version.js +50 -0
- package/dist/server/ws/handle-message.js +107 -0
- package/package.json +50 -63
- package/web/dist/apple-touch-icon-precomposed.png +0 -0
- package/web/dist/apple-touch-icon.png +0 -0
- package/web/dist/assets/abnfDiagram-WEYOIA3C-VUKLHHSn.js +1 -0
- package/web/dist/assets/arc-BeUkaHhk.js +1 -0
- package/web/dist/assets/architecture-WOLXFQ4H-B9I4s0NV.js +1 -0
- package/web/dist/assets/architectureDiagram-ZHVYKT53-CaEkLhfq.js +36 -0
- package/web/dist/assets/array-BifhSqXX.js +1 -0
- package/web/dist/assets/blockDiagram-RJAE7QA3-IR49UNE_.js +140 -0
- package/web/dist/assets/c4Diagram-XDPPPE54-B-81CloB.js +38 -0
- package/web/dist/assets/channel-B_mTTjGt.js +1 -0
- package/web/dist/assets/chunk-2E7WHVMD-CaWVF7qv.js +88 -0
- package/web/dist/assets/chunk-2Q5K7J3B-C1jixKkw.js +1 -0
- package/web/dist/assets/chunk-4EMNKR2T-BvXf2tq-.js +1 -0
- package/web/dist/assets/chunk-55XCU76K-Bz_d2e2D.js +1 -0
- package/web/dist/assets/chunk-5VM5RSS4-ZNzvKenW.js +15 -0
- package/web/dist/assets/chunk-7S6XSTFO-B_SPMiU8.js +2 -0
- package/web/dist/assets/chunk-AQDTSKZB-Cen-_xej.js +72 -0
- package/web/dist/assets/chunk-DSNLSHJZ-DEw1kFwj.js +129 -0
- package/web/dist/assets/chunk-DUW6YSOI-Dgx8z5s3.js +1 -0
- package/web/dist/assets/chunk-HAGFOTED-BwpOOcw8.js +62 -0
- package/web/dist/assets/chunk-HNE4Q36P-BjCwi2uW.js +1 -0
- package/web/dist/assets/chunk-J5ZVWO5B-oDCd-gWO.js +1 -0
- package/web/dist/assets/chunk-JWPE2WC7-DVXcaiue.js +1 -0
- package/web/dist/assets/chunk-NGNAAXSQ-C2Wy9Xmz.js +136 -0
- package/web/dist/assets/chunk-NQOKRVIF-WcqhWFS5.js +213 -0
- package/web/dist/assets/chunk-UHW7PFBP-quDvQby8.js +1 -0
- package/web/dist/assets/chunk-VQ5W62QI-DZBwmhzq.js +1 -0
- package/web/dist/assets/chunk-WQQL4CDK-wYyHYuui.js +10 -0
- package/web/dist/assets/chunk-XXDRQBXY-DfJzC7nt.js +1 -0
- package/web/dist/assets/chunk-Y2CYZVJY-DsF7k-Jl.js +1 -0
- package/web/dist/assets/chunk-YZO67HFG-CWLraGk_.js +1 -0
- package/web/dist/assets/chunk-ZAUX2LTX-ChBUt_FJ.js +1 -0
- package/web/dist/assets/chunk-ZCHMQSOR-C57UFT60.js +2 -0
- package/web/dist/assets/classDiagram-v2-4MYWR3UA-Bo4i7SNY.js +217 -0
- package/web/dist/assets/cose-bilkent-JH36ORCC-CK360NdH.js +1 -0
- package/web/dist/assets/cynefin-EF2NZ3EQ-DlXFjIFm.js +1 -0
- package/web/dist/assets/cynefinDiagram-WF24UDRP-zvZIqA1c.js +62 -0
- package/web/dist/assets/cytoscape.esm-BegBNzOV.js +321 -0
- package/web/dist/assets/dagre-NK4GIZVX-CnKhCu-v.js +4 -0
- package/web/dist/assets/defaultLocale-BFoDCU3G.js +1 -0
- package/web/dist/assets/diagram-CBK3MWTC-3QTR8Fjx.js +24 -0
- package/web/dist/assets/diagram-I5XIIV2D-D9lSd7z6.js +24 -0
- package/web/dist/assets/diagram-ODIL2UCW-DWJD6lPM.js +30 -0
- package/web/dist/assets/diagram-PFBEJUXE-CWJmoUg4.js +3 -0
- package/web/dist/assets/diagram-RJA3I4VV-D1SZHQcQ.js +41 -0
- package/web/dist/assets/diagram-TYUNFSNR-DCCjGi1x.js +200 -0
- package/web/dist/assets/dist-VOk_Iv17.js +1 -0
- package/web/dist/assets/ebnfDiagram-V4P3TTPT-CQLdqEiW.js +1 -0
- package/web/dist/assets/elk-QONTBCTQ-Dp2pEp6b.js +27 -0
- package/web/dist/assets/erDiagram-KYQIGQAA-BFGNoFQ-.js +99 -0
- package/web/dist/assets/eventmodeling-K75KTNOO-CFfAemGw.js +1 -0
- package/web/dist/assets/flowDiagram-IUGLLWBU-DmSp3cbW.js +1 -0
- package/web/dist/assets/ganttDiagram-R7GPNTJY-vK3jPGDq.js +292 -0
- package/web/dist/assets/gitGraph-VSP46ZUC-rXBgHTdq.js +1 -0
- package/web/dist/assets/gitGraphDiagram-PDYL7XHY-CBbGhago.js +106 -0
- package/web/dist/assets/graphlib-DS17s2tU.js +1 -0
- package/web/dist/assets/index-DBOF_OJe.js +104 -0
- package/web/dist/assets/index-nlY_-OaR.css +1 -0
- package/web/dist/assets/info-OHQRW6UA-Cd9vp-6C.js +1 -0
- package/web/dist/assets/infoDiagram-MVDRKAX5-Ce-Sg_qu.js +2 -0
- package/web/dist/assets/init-C-OQMol4.js +1 -0
- package/web/dist/assets/ishikawaDiagram-HPEHV2GE-DWlmR6BY.js +70 -0
- package/web/dist/assets/journeyDiagram-BOSHW7O7-DmDG97ae.js +139 -0
- package/web/dist/assets/kanban-definition-FNSA4HC5-1Z4sDrgV.js +89 -0
- package/web/dist/assets/katex-B_JcIwqj.js +257 -0
- package/web/dist/assets/line-DGM1-9KW.js +1 -0
- package/web/dist/assets/linear-B6hyeGHu.js +1 -0
- package/web/dist/assets/mermaid-parser.core-D1HmdkA4.js +7 -0
- package/web/dist/assets/mermaid.core-DeUJrhO1.js +44 -0
- package/web/dist/assets/mindmap-definition-6OY57UG3-C3-FByy8.js +98 -0
- package/web/dist/assets/ordinal-BDEzSJ7C.js +1 -0
- package/web/dist/assets/packet-JDAUHWVQ-BoOr7DaW.js +1 -0
- package/web/dist/assets/path-fybaL0A-.js +1 -0
- package/web/dist/assets/pegDiagram-ECIUJNBX-Bn7m75TZ.js +1 -0
- package/web/dist/assets/pie-XZMESJXO-CGuMTDBp.js +1 -0
- package/web/dist/assets/pieDiagram-GNMPY74T-DHhaPwZe.js +39 -0
- package/web/dist/assets/quadrantDiagram-D57K4MC3-DxTgFHLK.js +7 -0
- package/web/dist/assets/radar-ABXABTNO-BiKxmALL.js +1 -0
- package/web/dist/assets/railroad-I3PHUGI6-BKYufgg4.js +1 -0
- package/web/dist/assets/railroad-abnf-LNEFI6M7-DmOrjlyL.js +1 -0
- package/web/dist/assets/railroad-ebnf-DWYD2UWJ-BgMyVDd1.js +1 -0
- package/web/dist/assets/railroad-peg-JR7BVNR7-BN6NL8S-.js +1 -0
- package/web/dist/assets/railroadDiagram-Y72NRBL7-BsbA-9gP.js +1 -0
- package/web/dist/assets/requirementDiagram-EQYSW5RA-HUw4YqWd.js +84 -0
- package/web/dist/assets/rough.esm-Dy-Kn_BL.js +1 -0
- package/web/dist/assets/sankeyDiagram-SY24JHO5-Dx1MOFRu.js +40 -0
- package/web/dist/assets/sequenceDiagram-BLEHNHQU-C0-Rzg3g.js +169 -0
- package/web/dist/assets/sizeCapture-INFHLROL-3uHXrFqA.js +1 -0
- package/web/dist/assets/src-CuHygcpj.js +1 -0
- package/web/dist/assets/stateDiagram-v2-A6IESKWZ-BnEICGtg.js +291 -0
- package/web/dist/assets/swimlanes-B3ENRKFQ-CwDRCHZD.js +1 -0
- package/web/dist/assets/swimlanesDiagram-AYQRV4AK-DZ_aAXmG.js +8 -0
- package/web/dist/assets/timeline-definition-JXYKGLGB-C4BVpgzc.js +120 -0
- package/web/dist/assets/treeView-D4JQ5SDB-BBsvEMP3.js +1 -0
- package/web/dist/assets/treemap-SAJKECNS-BYw6cxC8.js +1 -0
- package/web/dist/assets/usecaseDiagram-WPOLBNNX-BkOXLgwP.js +328 -0
- package/web/dist/assets/vennDiagram-Q3Y3IDCW-Kgjk_n6B.js +34 -0
- package/web/dist/assets/wardley-7MLQ67FV-BGVObhvJ.js +1 -0
- package/web/dist/assets/wardleyDiagram-IVAIDKWA-i97uD6tL.js +78 -0
- package/web/dist/assets/xychartDiagram-4URNHDU4-awJi5TfJ.js +7 -0
- package/web/dist/favicon-32.png +0 -0
- package/web/dist/favicon.ico +0 -0
- package/web/dist/favicon.svg +20 -8
- package/web/dist/icons/apple-touch-icon-180.png +0 -0
- package/web/dist/icons/icon-192.png +0 -0
- package/web/dist/icons/icon-512.png +0 -0
- package/web/dist/icons/icon-maskable-512.png +0 -0
- package/web/dist/index.html +31 -24
- package/web/dist/manifest.webmanifest +17 -0
- package/web/dist/maskable.svg +25 -0
- package/web/dist/sw.js +40 -0
- package/bin/oh-my-agent-web-ps.mjs +0 -203
- package/bin/oh-my-agent-web-ws.mjs +0 -782
- package/bin/oh-my-agent-web.mjs +0 -321
- package/bin/update-check.mjs +0 -142
- package/dist/server/codex-client.js +0 -310
- package/dist/server/codex-supervisor.js +0 -446
- package/dist/server/fs-service.js +0 -144
- package/dist/server/request-inspector.js +0 -458
- package/dist/shared/protocol.js +0 -112
- package/scripts/manage-server.mjs +0 -155
- package/scripts/omaw.mjs +0 -74
- package/shared/protocol.ts +0 -228
- package/web/dist/assets/index-5LJ5fRcO.js +0 -42
- package/web/dist/assets/index-QiDfPKFo.css +0 -1
- package/web/dist/assets/markdown-CYXe6JZx.js +0 -55
package/README.md
CHANGED
|
@@ -1,491 +1,149 @@
|
|
|
1
1
|
# oh-my-agent-web
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
Chat, tool calls, diffs and approval dialogs in one tab.
|
|
3
|
+
把编码智能体(pi / Codex / DeepSeek Harness)包进一个**本机网页工作台**:左边是多项目 + 会话列表,中间是对话,右边随时看文件、跑终端。
|
|
5
4
|
|
|
6
|
-
|
|
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
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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
|
-
|
|
18
|
+
## 快速开始
|
|
45
19
|
|
|
46
|
-
|
|
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
|
|
71
|
-
npm start
|
|
24
|
+
npm run build
|
|
25
|
+
npm start # 前台运行;Ctrl-C 退出
|
|
72
26
|
```
|
|
73
27
|
|
|
74
|
-
|
|
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).
|
|
28
|
+
浏览器打开 <http://127.0.0.1:25257>。
|
|
80
29
|
|
|
81
|
-
|
|
30
|
+
装成全局命令后,可以用简写 `omaw` 或 `agent-web`(`oh-my-agent-web` / `omaw` / `agent-web` 三个命令指向同一入口,完全等价):
|
|
82
31
|
|
|
83
32
|
```bash
|
|
84
|
-
npm
|
|
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
|
|
85
38
|
```
|
|
86
39
|
|
|
87
|
-
|
|
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.
|
|
91
|
-
|
|
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`:
|
|
40
|
+
### 常用参数
|
|
102
41
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
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()` | 默认工作区(还没开会话时用) |
|
|
107
51
|
|
|
108
|
-
|
|
52
|
+
数据目录里会有:`password`(设过一次就记住)、`allowed-hosts`、`settings.json`、`pi-sessions-cache.json`、`uploads/`、`logs/`、`server.lock`。
|
|
109
53
|
|
|
110
|
-
|
|
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` |
|
|
54
|
+
> 想从手机访问:`agent-web -d -H 0.0.0.0 -P 你的密码 --allow-host 你的域名`,反代 / 隧道请带上 `X-Forwarded-For`(来源校验会看它)。
|
|
120
55
|
|
|
121
|
-
##
|
|
122
|
-
|
|
123
|
-
```
|
|
124
|
-
oh-my-agent-web [options]
|
|
125
|
-
|
|
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
|
|
134
|
-
|
|
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.
|
|
146
|
-
|
|
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.
|
|
56
|
+
## 开发
|
|
152
57
|
|
|
153
58
|
```bash
|
|
154
|
-
|
|
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
|
|
59
|
+
npm run dev # 一条命令起两个进程
|
|
157
60
|
```
|
|
158
61
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
`ws://127.0.0.1:25258`), without going through the browser UI:
|
|
163
|
-
|
|
164
|
-
```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
|
|
172
|
-
```
|
|
62
|
+
- 对外仍然只有一个 **25257**(Vite 监听并反代),后端躲在内部 **25258**:开发和生产记同一个地址。
|
|
63
|
+
- 前端热更新走 Vite,后端 `tsx --watch` 自动重启。
|
|
64
|
+
- 手机调试:`npm run dev -- --host 0.0.0.0`。
|
|
173
65
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
66
|
+
| 命令 | 作用 |
|
|
67
|
+
| --- | --- |
|
|
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 / opencode(ACP)/ fake(测试)
|
|
83
|
+
│ ├─ session/ 会话运行时:切换、改名、删除、模型控制、审批桥
|
|
84
|
+
│ ├─ sessions/ 会话文件扫描(标题 / 模型 / 缓存)
|
|
85
|
+
│ ├─ files/ 文件树、预览、搜索、上传、git 分支
|
|
86
|
+
│ ├─ terminal/ PTY 终端
|
|
87
|
+
│ ├─ approval/ 审批规则与作用域判断
|
|
88
|
+
│ ├─ providers/ 自定义 provider / 模型清单
|
|
89
|
+
│ ├─ push/ Web Push
|
|
90
|
+
│ ├─ skills/ 技能发现与启停
|
|
91
|
+
│ └─ subagents/ 子代理模板(落 ~/.pi/agent/agents/*.md,与 pi 共用同一套)
|
|
92
|
+
├─ web/ 前端(React 19 + Vite)
|
|
93
|
+
│ └─ src/
|
|
94
|
+
│ ├─ components/ 侧栏、消息流、输入框、文件树、终端、各类面板
|
|
95
|
+
│ ├─ styles/ 按职责拆分的 CSS(无框架,一套 CSS 变量)
|
|
96
|
+
│ └─ use-*.ts 搜索 / 分支 / 分栏 / 复制等小 hooks
|
|
97
|
+
├─ scripts/ dev 双进程、图标生成
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## 引擎
|
|
101
|
+
|
|
102
|
+
| 引擎 | 说明 |
|
|
103
|
+
| --- | --- |
|
|
104
|
+
| **pi**(默认) | 完整的插件 / 技能生态、工具延迟加载、审批门禁、目标模式与子代理;模型与 provider 由本工作台管理 |
|
|
105
|
+
| **Codex** | codex 官方 agent,独立 loop 与沙箱,会话与 Codex Desktop / CLI 共用;审批是命令 / 文件级的 |
|
|
106
|
+
| **DeepSeek Harness** | DeepSeek 官方 agent(ACP),模型与思考档可切,权限逐次确认 |
|
|
107
|
+
| **opencode** | opencode 官方 agent(ACP),自带工具 / MCP / 插件生态,模型与思考档可切,会话与 opencode CLI / TUI 共用;**审批取决于 opencode 自身的 `permission` 配置**(配成全局 allow 时不会询问) |
|
|
108
|
+
| **fake** | 零 token 的脚本化引擎,只用来验证协议 / 工具 / 审批流程(`AGENT_WEB_ENGINE=fake`,默认不进切换面板) |
|
|
179
109
|
|
|
180
|
-
|
|
110
|
+
装没装的引擎不影响启动:只有切到它时才会报「没找到」。
|
|
181
111
|
|
|
182
|
-
|
|
183
|
-
npm run ws # interactive
|
|
184
|
-
npm run ws -- --port 25259
|
|
185
|
-
npm run ws -- -t <threadId> "continue"
|
|
186
|
-
```
|
|
112
|
+
opencode 相关的环境变量(都有默认值,通常不用配):
|
|
187
113
|
|
|
188
|
-
|
|
|
114
|
+
| 变量 | 作用 |
|
|
189
115
|
| --- | --- |
|
|
190
|
-
|
|
|
191
|
-
|
|
|
192
|
-
|
|
|
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) |
|
|
116
|
+
| `AGENT_WEB_OPENCODE_BIN` | opencode 可执行文件路径(默认 PATH 里的 `opencode`) |
|
|
117
|
+
| `AGENT_WEB_OPENCODE_ARGS` | 传给 `opencode acp` 的额外参数,空格分隔(例如 `--pure` 跳过外部插件) |
|
|
118
|
+
| `AGENT_WEB_OPENCODE_MODEL` | 新会话优先用的模型(`provider/model`);不设就沿用 opencode 自己的默认 |
|
|
201
119
|
|
|
202
|
-
|
|
120
|
+
## 子代理(多开 + 可管理)
|
|
203
121
|
|
|
204
|
-
|
|
205
|
-
(`127.0.0.1:25258`).
|
|
122
|
+
pi 引擎带一套自己的子代理实现(**不依赖 pi-subagents 插件**):
|
|
206
123
|
|
|
207
|
-
|
|
124
|
+
- **怎么开**:主 Agent 拿到 `Agent` 工具(`subagent_type` / `prompt` / `description` / `run_in_background`),
|
|
125
|
+
一次可以并行开好几个;每次委派都是**一个真实的 pi 会话**(自己的上下文、会话文件、工具白名单)。
|
|
126
|
+
- **在哪看**:运行卡片**就在对话下方**(输入区上方那条「子代理」卡片条):状态、耗时、工具次数、token 与花费,点「查看结果」原地展开结果原文与会话文件路径,随时**停掉某一个**;
|
|
127
|
+
卡片条可折叠,切会话自动换成本会话的那批。顶栏「子代理」徽标保留一眼概览(几个在跑 / 合计花销),点开是小浮层。
|
|
128
|
+
- **怎么管**:同一个面板只剩**模板**(内置 explore / general-purpose / plan,可停用;可新建 / 编辑 / 删除),运行记录不在面板里。
|
|
129
|
+
模板落 `~/.pi/agent/agents/*.md`,frontmatter 写 `name / description / tools / model / thinking / max_turns`,
|
|
130
|
+
正文就是子代理的系统指令 —— 与 pi / pi-web 的 agent 文件同一套格式,直接可读可改可进 git。
|
|
131
|
+
- **并发**:面板右上角设上限(1–12,默认 4),超出的排队;总开关关掉后模型不再看到 `Agent` 工具。
|
|
132
|
+
- **隔离**:子代理默认不加载技能 / 插件 / 主题 / 上下文文件(快、可预期);模型不跟随父会话时会沿用父会话的模型。
|
|
133
|
+
有的模型由扩展注册 provider,这类模型在子代理里会失败并提示「在模板里指定模型」。
|
|
208
134
|
|
|
209
|
-
|
|
210
|
-
this project or external, and which TCP ports it listens on:
|
|
135
|
+
子代理的会话文件紧挨着父会话归档(`<父会话目录>/<父会话名>/subagents/`),不进侧栏的项目清单。
|
|
211
136
|
|
|
212
|
-
|
|
213
|
-
oh-my-agent-web ps # table
|
|
214
|
-
oh-my-agent-web ps --json # machine-readable
|
|
215
|
-
```
|
|
137
|
+
## 安全模型
|
|
216
138
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
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
|
-
```
|
|
139
|
+
- 默认只监听 `127.0.0.1`,并校验 `Origin` / `Host`;要远程访问必须显式给 `-H` + `-P` + `--allow-host`。
|
|
140
|
+
- 工具与命令走审批:只读命令自动放行,其余按规则询问(规则可积累)。
|
|
141
|
+
- 删除会话是**改名到 `.deleted-<时间戳>`**,文件还在磁盘上,能捞回来。
|
|
142
|
+
- 上传的临时文件、会话缓存都在数据目录里,不写进你的项目目录。
|
|
227
143
|
|
|
228
|
-
##
|
|
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
|
-
```
|
|
144
|
+
## 文档
|
|
312
145
|
|
|
313
|
-
|
|
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 |
|
|
380
|
-
| --- | --- |
|
|
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
|
|
457
|
-
|
|
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).
|
|
461
|
-
|
|
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.
|
|
472
|
-
|
|
473
|
-
### Startup races and process ownership
|
|
474
|
-
|
|
475
|
-
Two things the server does so clients don't have to care:
|
|
476
|
-
|
|
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.
|
|
146
|
+
代码里的 `ADR-00xx` 引用是设计决策编号;具体缘由写在对应文件的头注释里。
|
|
489
147
|
|
|
490
148
|
## License
|
|
491
149
|
|