oh-my-agent-web 0.6.0 → 0.7.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/LICENSE +21 -0
- package/README.en.md +385 -0
- package/README.md +322 -81
- package/dist/server/cli-info.js +4 -1
- package/dist/server/cli.js +54 -11
- package/dist/server/engine/builtin.js +28 -3
- package/dist/server/engine/codex-sessions.js +3 -3
- package/dist/server/engine/dsh.js +3 -1
- package/dist/server/engine/jsonrpc-stdio.js +33 -3
- package/dist/server/engine/opencode-sessions.js +8 -2
- package/dist/server/engine/opencode.js +3 -1
- package/dist/server/engine/pi-sdk.js +157 -15
- package/dist/server/engine/pi-subagent-tool.js +35 -13
- package/dist/server/engine/pi-subagents.js +38 -1
- package/dist/server/engine/registry.js +2 -1
- package/dist/server/engine/wiring.js +1 -0
- package/dist/server/files/dir-routes.js +7 -5
- package/dist/server/files/file-search.js +4 -3
- package/dist/server/files/file-service.js +45 -9
- package/dist/server/files/files-routes.js +8 -1
- package/dist/server/files/git-info.js +34 -7
- package/dist/server/http/auth.js +27 -1
- package/dist/server/http/aux-routes.js +6 -1
- package/dist/server/http/file-headers.js +75 -0
- package/dist/server/index.js +54 -77
- package/dist/server/mcp/mcp-auth.js +9 -3
- package/dist/server/mcp/mcp-command.js +50 -5
- package/dist/server/mcp/mcp-probe.js +43 -7
- package/dist/server/mcp/pi-mcp-config.js +30 -2
- package/dist/server/protocol-parse.js +11 -1
- package/dist/server/providers/catalog-store.js +7 -3
- package/dist/server/providers/catalog-writes.js +5 -3
- package/dist/server/providers/enabled-models.js +5 -3
- package/dist/server/providers/import-routes.js +15 -5
- package/dist/server/providers/model-test.js +72 -11
- package/dist/server/providers/probe.js +20 -0
- package/dist/server/providers/provider-handlers.js +27 -10
- package/dist/server/providers/provider-pool.js +63 -0
- package/dist/server/providers/provider-store.js +139 -20
- package/dist/server/providers/validate.js +13 -4
- package/dist/server/push/push-routes.js +3 -3
- package/dist/server/push/push.js +74 -12
- package/dist/server/session/approval-bridge.js +31 -19
- package/dist/server/session/conversation-create.js +1 -1
- package/dist/server/session/engine-switch.js +4 -1
- package/dist/server/session/model-controller.js +20 -2
- package/dist/server/session/notices.js +4 -2
- package/dist/server/session/pi-opener.js +44 -4
- package/dist/server/session/pi-sessions.js +79 -9
- package/dist/server/session/refresh-actions.js +3 -2
- package/dist/server/session/runtime-services.js +1 -0
- package/dist/server/session/runtime.js +50 -15
- package/dist/server/session/settings.js +4 -4
- package/dist/server/session/stats-refresher.js +7 -2
- package/dist/server/session/switch-conversation.js +1 -2
- package/dist/server/session/turn-events.js +1 -1
- package/dist/server/session/turn-finish.js +26 -8
- package/dist/server/session/turn-markers.js +6 -5
- package/dist/server/session/turn-queue.js +79 -14
- package/dist/server/session/turn-send.js +34 -10
- package/dist/server/skills/skill-install.js +2 -2
- package/dist/server/snapshot/fan-out.js +0 -5
- package/dist/server/snapshot/sender.js +0 -9
- package/dist/server/snapshot/state.js +60 -6
- package/dist/server/subagents/profile-store.js +2 -1
- package/dist/server/terminal/terminal-routes.js +50 -23
- package/dist/server/terminal/terminal-session.js +63 -6
- package/dist/server/uploads/upload-routes.js +3 -0
- package/dist/server/util/atomic-write.js +18 -0
- package/dist/server/util/env.js +58 -14
- package/dist/server/util/file-mode.js +44 -0
- package/dist/server/util/origin.js +61 -0
- package/dist/server/util/paths.js +79 -1
- package/dist/server/util/spawn-cli.js +147 -0
- package/dist/server/ws/handle-message.js +7 -1
- package/docs/screenshots/01-chat.png +0 -0
- package/docs/screenshots/02-answer.png +0 -0
- package/docs/screenshots/03-files-diff.png +0 -0
- package/docs/screenshots/04-terminal.png +0 -0
- package/docs/screenshots/05-models.png +0 -0
- package/docs/screenshots/06-skills.png +0 -0
- package/docs/screenshots/07-skills-hub.png +0 -0
- package/docs/screenshots/08-mcp.png +0 -0
- package/docs/screenshots/09-subagents.png +0 -0
- package/docs/screenshots/10-settings.png +0 -0
- package/docs/screenshots/11-plugins.png +0 -0
- package/docs/screenshots/12-voice.png +0 -0
- package/docs/screenshots/13-push.png +0 -0
- package/docs/screenshots/README.md +45 -0
- package/package.json +43 -19
- package/scripts/prune-prebuilds.mjs +42 -0
- package/web/dist/assets/_omaw-mermaid-pruned_chunk_abnfDiagram-WEYOIA3C-CvNbnJ75.js +1 -0
- package/web/dist/assets/_omaw-mermaid-pruned_chunk_architectureDiagram-ZHVYKT53-T7NZZ4ao.js +1 -0
- package/web/dist/assets/_omaw-mermaid-pruned_chunk_c4Diagram-XDPPPE54-ByuAPg39.js +1 -0
- package/web/dist/assets/_omaw-mermaid-pruned_chunk_cynefinDiagram-WF24UDRP-BY5DHttT.js +1 -0
- package/web/dist/assets/_omaw-mermaid-pruned_chunk_diagram-CBK3MWTC-D7ZYyrF7.js +1 -0
- package/web/dist/assets/_omaw-mermaid-pruned_chunk_diagram-ODIL2UCW-C6kcOZFc.js +1 -0
- package/web/dist/assets/_omaw-mermaid-pruned_chunk_diagram-PFBEJUXE-CzFPFq0D.js +1 -0
- package/web/dist/assets/_omaw-mermaid-pruned_chunk_diagram-TYUNFSNR-B4G4T8SL.js +1 -0
- package/web/dist/assets/_omaw-mermaid-pruned_chunk_ebnfDiagram-V4P3TTPT-BkQ4xwD0.js +1 -0
- package/web/dist/assets/_omaw-mermaid-pruned_chunk_ishikawaDiagram-HPEHV2GE-52xqckJv.js +1 -0
- package/web/dist/assets/_omaw-mermaid-pruned_chunk_mindmap-definition-6OY57UG3-7cQksbFn.js +1 -0
- package/web/dist/assets/_omaw-mermaid-pruned_chunk_pegDiagram-ECIUJNBX-udgtBpwv.js +1 -0
- package/web/dist/assets/_omaw-mermaid-pruned_chunk_railroadDiagram-Y72NRBL7-Cd2dcQWz.js +1 -0
- package/web/dist/assets/_omaw-mermaid-pruned_chunk_swimlanes-B3ENRKFQ-p34pL1Yk.js +1 -0
- package/web/dist/assets/_omaw-mermaid-pruned_chunk_swimlanesDiagram-AYQRV4AK-BslfPs4r.js +1 -0
- package/web/dist/assets/_omaw-mermaid-pruned_chunk_usecaseDiagram-WPOLBNNX-DJZoN9Xk.js +1 -0
- package/web/dist/assets/_omaw-mermaid-pruned_chunk_vennDiagram-Q3Y3IDCW-DPXo67cZ.js +1 -0
- package/web/dist/assets/_omaw-mermaid-pruned_chunk_wardleyDiagram-IVAIDKWA-BE6ukwkg.js +1 -0
- package/web/dist/assets/_omaw-mermaid-pruned_katex_katex-Zojedrce.js +1 -0
- package/web/dist/assets/arc-BTAvbR16.js +1 -0
- package/web/dist/assets/architecture-WOLXFQ4H-fewLD5_7.js +1 -0
- package/web/dist/assets/{blockDiagram-RJAE7QA3-4SqX2RCZ.js → blockDiagram-RJAE7QA3-ClmgyxZl.js} +5 -5
- package/web/dist/assets/channel-DfaYIFFE.js +1 -0
- package/web/dist/assets/{chunk-55XCU76K-BAQkUXw9.js → chunk-55XCU76K-DdC5EhZG.js} +1 -1
- package/web/dist/assets/chunk-7S6XSTFO-CgToWHK6.js +2 -0
- package/web/dist/assets/chunk-AQDTSKZB-D-rQMnp7.js +72 -0
- package/web/dist/assets/{chunk-DSNLSHJZ-CQfLJsEG.js → chunk-DSNLSHJZ-cuZoTGMH.js} +9 -9
- package/web/dist/assets/chunk-HNE4Q36P-CiKr9iSN.js +1 -0
- package/web/dist/assets/{chunk-NGNAAXSQ-C2Wy9Xmz.js → chunk-NGNAAXSQ-DuHRe0y2.js} +1 -1
- package/web/dist/assets/chunk-VQ5W62QI-DbTfXAAT.js +1 -0
- package/web/dist/assets/chunk-WQQL4CDK-DHanHfB5.js +10 -0
- package/web/dist/assets/chunk-ZAUX2LTX-SrjFXpy2.js +62 -0
- package/web/dist/assets/chunk-ZCHMQSOR-7Wy8xXQ5.js +2 -0
- package/web/dist/assets/{classDiagram-v2-4MYWR3UA-ByZcqRlk.js → classDiagram-v2-4MYWR3UA-CBe5ZDvZ.js} +4 -4
- package/web/dist/assets/cose-bilkent-JH36ORCC-Dljdyvhw.js +1 -0
- package/web/dist/assets/cynefin-EF2NZ3EQ-CcZU7GFP.js +1 -0
- package/web/dist/assets/dagre-NK4GIZVX-Bq_6y8qp.js +4 -0
- package/web/dist/assets/diagram-I5XIIV2D-C2lnnYVG.js +24 -0
- package/web/dist/assets/{diagram-RJA3I4VV-D-1dWVjH.js → diagram-RJA3I4VV-Bqf8Z6wJ.js} +1 -1
- package/web/dist/assets/elk-QONTBCTQ-Cdzq_cJ5.js +27 -0
- package/web/dist/assets/{erDiagram-KYQIGQAA-BkQvVdNn.js → erDiagram-KYQIGQAA-ZJLCjPFC.js} +2 -2
- package/web/dist/assets/eventmodeling-K75KTNOO-DHqeIpes.js +1 -0
- package/web/dist/assets/flowDiagram-IUGLLWBU-AVgYvXKN.js +213 -0
- package/web/dist/assets/ganttDiagram-R7GPNTJY-CR1SG1M7.js +292 -0
- package/web/dist/assets/gitGraph-VSP46ZUC-CIZQPK0R.js +1 -0
- package/web/dist/assets/gitGraphDiagram-PDYL7XHY-BhOCWEh6.js +106 -0
- package/web/dist/assets/index-CZQjJbRg.js +104 -0
- package/web/dist/assets/index-ChDUWKZX.css +1 -0
- package/web/dist/assets/info-OHQRW6UA-C2wuRxeQ.js +1 -0
- package/web/dist/assets/{infoDiagram-MVDRKAX5-Ct4k2rOv.js → infoDiagram-MVDRKAX5-BP5doAB5.js} +1 -1
- package/web/dist/assets/{journeyDiagram-BOSHW7O7-B0ommDDF.js → journeyDiagram-BOSHW7O7-BcIDRTPS.js} +4 -4
- package/web/dist/assets/{kanban-definition-FNSA4HC5-C5IHOEO9.js → kanban-definition-FNSA4HC5-CRH_bcoT.js} +5 -5
- package/web/dist/assets/{line-XIlcDZrk.js → line-iA4GPA_S.js} +1 -1
- package/web/dist/assets/linear-BGUKwkTH.js +1 -0
- package/web/dist/assets/math-DgNW_bVP.js +1 -0
- package/web/dist/assets/{mermaid-parser.core-9OmqIOQj.js → mermaid-parser.core-CsqmgpEv.js} +5 -5
- package/web/dist/assets/mermaid.core-C1yCGQK6.js +44 -0
- package/web/dist/assets/packet-JDAUHWVQ-2ggaoz2g.js +1 -0
- package/web/dist/assets/pie-XZMESJXO-h_yslQQs.js +1 -0
- package/web/dist/assets/{pieDiagram-GNMPY74T-BUKhe6YN.js → pieDiagram-GNMPY74T-6-JZMFyk.js} +2 -2
- package/web/dist/assets/{quadrantDiagram-D57K4MC3-COMDA2G7.js → quadrantDiagram-D57K4MC3-K5r1HOgL.js} +3 -3
- package/web/dist/assets/radar-ABXABTNO-6fOJGGgq.js +1 -0
- package/web/dist/assets/railroad-I3PHUGI6-B_gUgQ3d.js +1 -0
- package/web/dist/assets/railroad-abnf-LNEFI6M7-CJ_eqiXZ.js +1 -0
- package/web/dist/assets/railroad-ebnf-DWYD2UWJ-BTsgjLTU.js +1 -0
- package/web/dist/assets/railroad-peg-JR7BVNR7-D91uiLln.js +1 -0
- package/web/dist/assets/{requirementDiagram-EQYSW5RA-DilR-z_d.js → requirementDiagram-EQYSW5RA-uapnV_OO.js} +3 -3
- package/web/dist/assets/{sankeyDiagram-SY24JHO5-mnLwPz1t.js → sankeyDiagram-SY24JHO5-BQsbFgUb.js} +3 -3
- package/web/dist/assets/{sequenceDiagram-BLEHNHQU-BdH-2WXg.js → sequenceDiagram-BLEHNHQU-iRoSYX_e.js} +6 -6
- package/web/dist/assets/{src-DrBGN2Yi.js → src-BBrKcs9r.js} +1 -1
- package/web/dist/assets/{stateDiagram-v2-A6IESKWZ-Byl9Wc56.js → stateDiagram-v2-A6IESKWZ-Bzj9z5KH.js} +2 -2
- package/web/dist/assets/{timeline-definition-JXYKGLGB-D2DwVY9P.js → timeline-definition-JXYKGLGB-DLUUuJX0.js} +2 -2
- package/web/dist/assets/treeView-D4JQ5SDB-CphIQ3n5.js +1 -0
- package/web/dist/assets/treemap-SAJKECNS-DqU3insw.js +1 -0
- package/web/dist/assets/wardley-7MLQ67FV-Ch7d8cmC.js +1 -0
- package/web/dist/assets/{xychartDiagram-4URNHDU4-CUJ-AhMv.js → xychartDiagram-4URNHDU4-DdxpWBeM.js} +3 -3
- package/web/dist/index.html +2 -2
- package/web/dist/assets/abnfDiagram-WEYOIA3C-C0scvgfK.js +0 -1
- package/web/dist/assets/arc-DQWQXZ0D.js +0 -1
- package/web/dist/assets/architecture-WOLXFQ4H-DRYAlsMA.js +0 -1
- package/web/dist/assets/architectureDiagram-ZHVYKT53-DURI6MT_.js +0 -36
- package/web/dist/assets/c4Diagram-XDPPPE54-CyzS6It3.js +0 -38
- package/web/dist/assets/channel-sSfIOMg7.js +0 -1
- package/web/dist/assets/chunk-2E7WHVMD-B-50G064.js +0 -88
- package/web/dist/assets/chunk-4EMNKR2T-DsXkPvfB.js +0 -1
- package/web/dist/assets/chunk-7S6XSTFO-MNTmDz5n.js +0 -2
- package/web/dist/assets/chunk-AQDTSKZB-DxchdDrD.js +0 -72
- package/web/dist/assets/chunk-HAGFOTED-BaVCqyAB.js +0 -62
- package/web/dist/assets/chunk-HNE4Q36P-BachKm72.js +0 -1
- package/web/dist/assets/chunk-NQOKRVIF-D38mfZCv.js +0 -213
- package/web/dist/assets/chunk-UHW7PFBP-DzvEYnNC.js +0 -1
- package/web/dist/assets/chunk-VQ5W62QI-D7Rb-hYZ.js +0 -1
- package/web/dist/assets/chunk-WQQL4CDK-Dt2FUoIk.js +0 -10
- package/web/dist/assets/chunk-XXDRQBXY-DasKl82Z.js +0 -1
- package/web/dist/assets/chunk-YZO67HFG-3YefBeUz.js +0 -1
- package/web/dist/assets/chunk-ZAUX2LTX-CUoEknd1.js +0 -1
- package/web/dist/assets/chunk-ZCHMQSOR-Da3GBE09.js +0 -2
- package/web/dist/assets/cose-bilkent-JH36ORCC-PGAAEchc.js +0 -1
- package/web/dist/assets/cynefin-EF2NZ3EQ-BBkeqM17.js +0 -1
- package/web/dist/assets/cynefinDiagram-WF24UDRP-DOEytVty.js +0 -62
- package/web/dist/assets/cytoscape.esm-BegBNzOV.js +0 -321
- package/web/dist/assets/dagre-NK4GIZVX-Bei2BCmp.js +0 -4
- package/web/dist/assets/defaultLocale-BFoDCU3G.js +0 -1
- package/web/dist/assets/diagram-CBK3MWTC-BdeyWllS.js +0 -24
- package/web/dist/assets/diagram-I5XIIV2D-BmNMrWWj.js +0 -24
- package/web/dist/assets/diagram-ODIL2UCW-D8Kz7g8s.js +0 -30
- package/web/dist/assets/diagram-PFBEJUXE-BNSD58Rk.js +0 -3
- package/web/dist/assets/diagram-TYUNFSNR-8YHZJhel.js +0 -200
- package/web/dist/assets/dist-BBxVlYHc.js +0 -1
- package/web/dist/assets/ebnfDiagram-V4P3TTPT-CtgdOqHX.js +0 -1
- package/web/dist/assets/elk-QONTBCTQ-DM5bxyWI.js +0 -27
- package/web/dist/assets/eventmodeling-K75KTNOO-DWnHI7Q0.js +0 -1
- package/web/dist/assets/flowDiagram-IUGLLWBU-DYv3kVGg.js +0 -1
- package/web/dist/assets/ganttDiagram-R7GPNTJY-hF6RKzBy.js +0 -292
- package/web/dist/assets/gitGraph-VSP46ZUC-Dg0BaeiY.js +0 -1
- package/web/dist/assets/gitGraphDiagram-PDYL7XHY-CEJB8ISX.js +0 -106
- package/web/dist/assets/index-BLsWuXKg.js +0 -104
- package/web/dist/assets/index-Bph00xIt.css +0 -1
- package/web/dist/assets/info-OHQRW6UA-X0qorfja.js +0 -1
- package/web/dist/assets/ishikawaDiagram-HPEHV2GE-JsH1yFOe.js +0 -70
- package/web/dist/assets/katex-B_JcIwqj.js +0 -257
- package/web/dist/assets/linear-BXwFphKE.js +0 -1
- package/web/dist/assets/mermaid.core-B9yDV3Hs.js +0 -44
- package/web/dist/assets/mindmap-definition-6OY57UG3-Bc8uZ5T9.js +0 -98
- package/web/dist/assets/packet-JDAUHWVQ-9EbXSBeV.js +0 -1
- package/web/dist/assets/pegDiagram-ECIUJNBX-nYdgRfAO.js +0 -1
- package/web/dist/assets/pie-XZMESJXO-DNvb9i1G.js +0 -1
- package/web/dist/assets/radar-ABXABTNO-DAG-ygGV.js +0 -1
- package/web/dist/assets/railroad-I3PHUGI6-CjnKFfHL.js +0 -1
- package/web/dist/assets/railroad-abnf-LNEFI6M7-DOpu4hdH.js +0 -1
- package/web/dist/assets/railroad-ebnf-DWYD2UWJ-B7kV2hyB.js +0 -1
- package/web/dist/assets/railroad-peg-JR7BVNR7-Cy4mKxpf.js +0 -1
- package/web/dist/assets/railroadDiagram-Y72NRBL7-CJek641i.js +0 -1
- package/web/dist/assets/rough.esm-Dy-Kn_BL.js +0 -1
- package/web/dist/assets/swimlanes-B3ENRKFQ-D_Mnemnr.js +0 -1
- package/web/dist/assets/swimlanesDiagram-AYQRV4AK-D6uQfcsx.js +0 -8
- package/web/dist/assets/treeView-D4JQ5SDB-BPseZx68.js +0 -1
- package/web/dist/assets/treemap-SAJKECNS-DbkR3mjV.js +0 -1
- package/web/dist/assets/usecaseDiagram-WPOLBNNX-ClThWCPc.js +0 -328
- package/web/dist/assets/vennDiagram-Q3Y3IDCW-B50-oQjz.js +0 -34
- package/web/dist/assets/wardley-7MLQ67FV-Ct_6HXw3.js +0 -1
- package/web/dist/assets/wardleyDiagram-IVAIDKWA-B7Z8k44J.js +0 -78
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 oh-my-agent-web contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.en.md
ADDED
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
# oh-my-agent-web
|
|
2
|
+
|
|
3
|
+
[中文](README.md) · **English**
|
|
4
|
+
|
|
5
|
+
One line: **an external control surface for the agent you're already running.** The engine keeps running on your own machine; you use the web page to watch it work, manage its tools and models, cut in whenever it drifts, and jump into files or a shell when you need to.
|
|
6
|
+
|
|
7
|
+
Single user, loopback only, and the engine's own on-disk files are the source of truth for conversations — no database, no accounts. One `omaw` process is one person's workbench.
|
|
8
|
+
|
|
9
|
+

|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
npm ci && npm run build && npm start → http://127.0.0.1:25257
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Modules
|
|
18
|
+
|
|
19
|
+
The top bar *is* the menu; the sidebar holds projects, sessions and files; the right pane is preview and terminal.
|
|
20
|
+
|
|
21
|
+
| Module | Where | What it does |
|
|
22
|
+
|---|---|---|
|
|
23
|
+
| **Conversation** | center | Streaming text + collapsible thinking blocks + tool cards (arguments / full command / output / duration / ok or failed) + a "N steps" process block + a usage footer (tokens / cache / cost) + chips for changed files |
|
|
24
|
+
| **Steer & queue** | composer | Cut in mid-turn and the next message takes effect immediately; queued messages can be retracted; sent messages fold into the process block |
|
|
25
|
+
| **Engines** | top bar picker | pi / Codex / DeepSeek Harness / opencode each with its native loop (not one prompt in four costumes); every session remembers its engine, model and thinking level |
|
|
26
|
+
| **Subagents** | top bar "subagents" + the strip under the conversation | The main agent gets an `Agent` tool and can run several **real sessions** in parallel; run cards show status / duration / tool count / tokens / cost, expand in place for the result, and can be stopped individually. The panel manages templates: tool allowlist, model, thinking level, max turns, concurrency (1–12) |
|
|
27
|
+
| **Models & providers** | top bar "models" | The 41 providers in pi's official catalog work **with just a key** — no base URLs, no hand-copied model IDs. Custom providers expose the api shape (openai-completions / responses / anthropic-messages / codex / typesafe), base URL and custom headers; tick models, batch-test speed, pull the list from `/models`, save a whitelist. **Keys never leave the server** (only the last four digits come back) |
|
|
28
|
+
| **Skills** | top bar "skills" | Installed list with enable/disable and a reader for `SKILL.md` plus the skill's files; **Skill Hub** search and one-click install (200k+ index), install from a Git repo, or create by hand. Enabling means renaming `SKILL.md` — there is no second state file |
|
|
29
|
+
| **MCP** | top bar "MCP" | Edit both `mcp.json` files (global and project; a project entry with the same name wins), enable/disable, pick an exposure level (codemode / deferred / direct / hidden), **test the connection** (real handshake + tool list), OAuth login, browse a marketplace |
|
|
30
|
+
| **Plugins** | top bar "plugins" | pi packages (npm / git / local dir) with four states (loaded / installed / missing / disabled), per-package disabling, plus loose single-file extensions; state comes from pi's own resolution — only install/uninstall/update touch the disk |
|
|
31
|
+
| **File manager** | sidebar "files" | Directory tree (switchable root), search by name, show hidden files, collapse all, upload and download, reveal in Finder; uncommitted changes are dotted in the tree |
|
|
32
|
+
| **File viewer** | right pane (multi-tab) | Markdown / source with line numbers / images / PDF / audio-video streams; select lines and "add to conversation" to use them as context; full screen and draggable width |
|
|
33
|
+
| **Diff** | "diff" at the top of the viewer | Compared against HEAD: a `+285 −78` summary, line-level red/green highlighting, switch between diff and full file; opening from a "changed files" chip lands straight on the diff |
|
|
34
|
+
| **git** | top of the files pane | Branch chip (click to switch local branches, confirms first on a dirty tree), `M` / `U` / `D` markers after filenames |
|
|
35
|
+
| **Terminal** | files pane `>_`, right-pane tab | A real PTY (`node-pty` + xterm.js) sharing the session's cwd, with an optional initial command; on Linux it tells you exactly which build tools are missing |
|
|
36
|
+
| **Push** | top bar "push" | Web Push subscriptions (VAPID); one notification per finished turn — title is the project, body the session, with ❌ for failures and ⏹ for interrupts. Multiple devices, test push, clear all; needs https or localhost |
|
|
37
|
+
| **Voice** | top bar "voice" | Four event sounds (start / finish / error / waiting for approval) with preview and volume; local TTS (the browser's own voices, no network) that can read the final reply, with speed and voice selection |
|
|
38
|
+
| **Settings** | top bar "settings" | Four pages: **UI** (which chunks appear in the top bar and status bar), **general** (saved phrases, etc.), **appearance** (chat font size ×4, content width ×4, six palettes: bright white, warm paper, mist, Tokyo night, mocha, nord), **language** (Chinese / English, applies instantly) |
|
|
39
|
+
| **Sessions** | sidebar | Grouped by directory into "projects"; pin, rename, archive (undoable), delete (renames to `.deleted-<timestamp>`, the file survives). A session *is* the engine's own file — identical to what the CLI shows |
|
|
40
|
+
| **Attachments** | composer | Drag-and-drop upload, `@` file mentions, pasted images; uploads land in the data dir, never in your project |
|
|
41
|
+
| **Mobile** | — | Responsive: the sidebar becomes a drawer, process blocks collapse to a caret, below 400px it switches to the phone layout |
|
|
42
|
+
|
|
43
|
+
> Every screenshot below comes from a **real, running instance** (taken on this project's own session) — nothing is mocked up.
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## Screens
|
|
48
|
+
|
|
49
|
+
| | |
|
|
50
|
+
|---|---|
|
|
51
|
+
|  |  |
|
|
52
|
+
| **Answer**: markdown, tables, code highlighting, token and cost footer | **Diff**: against HEAD, line-level red/green |
|
|
53
|
+
|  |  |
|
|
54
|
+
| **Terminal**: a real PTY in the session's cwd | **Models**: the 41 built-ins need only a key; ticked models apply |
|
|
55
|
+
|  |  |
|
|
56
|
+
| **Skills**: installed list, toggles, and `SKILL.md` | **Skill Hub**: search by category, install in one click |
|
|
57
|
+
|  |  |
|
|
58
|
+
| **MCP**: global and project config, exposure, connection test | **Subagents**: who is running, results, templates and tool allowlists |
|
|
59
|
+
|  |  |
|
|
60
|
+
| **Settings → appearance**: font size, width, six palettes | **Plugins**: load state of pi packages, with toggles |
|
|
61
|
+
|
|
62
|
+
Two more: [voice (event sounds + local TTS)](docs/screenshots/12-voice.png), [push (subscriptions and devices)](docs/screenshots/13-push.png).
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## Quick start
|
|
67
|
+
|
|
68
|
+
Requires **Node.js ≥ 22.19** (a hard requirement of `@earendil-works/pi-*` 1.x) and **npm ≥ 9**. macOS / Linux / Windows all work.
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
npm ci # recommended: exact versions from the lockfile (no re-resolution)
|
|
72
|
+
npm run build
|
|
73
|
+
npm start # foreground; Ctrl-C to quit
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Open <http://127.0.0.1:25257>.
|
|
77
|
+
|
|
78
|
+
### One-line install (never touches global npm)
|
|
79
|
+
|
|
80
|
+
macOS / Linux:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
curl -fsSL https://raw.githubusercontent.com/duzhenxun/oh-my-agent-web/main/scripts/install.sh | sh
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Windows (PowerShell):
|
|
87
|
+
|
|
88
|
+
```powershell
|
|
89
|
+
powershell -c "irm https://raw.githubusercontent.com/duzhenxun/oh-my-agent-web/main/scripts/install.ps1 | iex"
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
The script does four things: **finds a new enough Node** (downloading the official build into `~/.omaw/node` with a sha256 check if needed), **runs `npm install -g --prefix ~/.omaw`** (no system-wide directory, no sudo), **links `omaw` into `~/.local/bin`** (patching PATH if necessary), and **smoke-tests once** (version string plus whether `node-pty` can be required — i.e. whether the terminal will open).
|
|
93
|
+
|
|
94
|
+
| What you want to change | How (`sh` version; the PowerShell version uses env vars) |
|
|
95
|
+
|---|---|
|
|
96
|
+
| Version | `OMAW_VERSION=0.7.0` (or `--version 0.7.0`) |
|
|
97
|
+
| Install location | `OMAW_HOME=/opt/omaw` (or `--home /opt/omaw`) |
|
|
98
|
+
| Registry mirror | `OMAW_REGISTRY=https://registry.npmmirror.com` (or `--registry …`) |
|
|
99
|
+
| Leave PATH alone | `OMAW_NO_PATH=1` (or `--no-modify-path`) |
|
|
100
|
+
| Install build tools | `OMAW_BUILD_TOOLS=1` (or `--with-build-tools`) |
|
|
101
|
+
| Uninstall | `… \| sh -s -- --uninstall` (removes the install dir and symlink only, never your data dir) |
|
|
102
|
+
|
|
103
|
+
On Linux the script also checks for `make` / `g++` / `python3`: `node-pty` ships prebuilds for macOS / Windows only, so Linux compiles the PTY in place. If the tools are missing it tells you what to install, or you can pass `--with-build-tools` and let it handle that.
|
|
104
|
+
|
|
105
|
+
> You can also just type `omaw` in your home directory after installing, but the home directory is an unsafe workspace (the file tree, search and the agent's cwd would all be your entire home). In that case it falls back to `<dataDir>/workspace` and prints a note. To point it at a real project use `AGENT_WEB_CWD=/path/to/project`.
|
|
106
|
+
|
|
107
|
+
### Install as a global command
|
|
108
|
+
|
|
109
|
+
`oh-my-agent-web` / `omaw` / `agent-web` are three bin names for the same entry point:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
npm i -g .
|
|
113
|
+
omaw -d # start in background (logs to <dataDir>/daemon.log)
|
|
114
|
+
omaw status # pid / port / uptime / engine / session count
|
|
115
|
+
omaw restart -d # restart after code changes
|
|
116
|
+
omaw stop
|
|
117
|
+
omaw version # current version; omaw upgrade upgrades to the latest release
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### CLI flags
|
|
121
|
+
|
|
122
|
+
| Flag | Env var | Default | Notes |
|
|
123
|
+
| --- | --- | --- | --- |
|
|
124
|
+
| `-p, --port` | `AGENT_WEB_PORT` | `25257` | Listen port |
|
|
125
|
+
| `-H, --host` | `AGENT_WEB_HOST` | `127.0.0.1` | Bind address; only change it for remote access |
|
|
126
|
+
| `-P, --password` | `AGENT_WEB_PASSWORD` | none | Access password; unset = local machine only |
|
|
127
|
+
| `--allow-host` | `AGENT_WEB_ALLOWED_HOSTS` | loopback only | Extra allowed domains / LAN IPs (repeatable or comma-separated) |
|
|
128
|
+
| `--data-dir` | `AGENT_WEB_DATA_DIR` | `~/.oh-my-agent-web` | Settings, password, uploads, logs, lock file |
|
|
129
|
+
| — | `AGENT_WEB_CWD` | `process.cwd()` | Default workspace (used before any session exists) |
|
|
130
|
+
| — | `AGENT_WEB_ENGINE` | `pi` | Default engine |
|
|
131
|
+
| — | `AGENT_WEB_APPROVAL_MODE` | `allow` | Default approval mode for new sessions; set `ask` to confirm every time |
|
|
132
|
+
| — | `AGENT_WEB_TURN_TIMEOUT_MS` | 20 min | Per-turn watchdog timeout |
|
|
133
|
+
| — | `AGENT_WEB_LOG` | `info` | `debug` / `info` / `warn` / `error` |
|
|
134
|
+
|
|
135
|
+
> To use it from your phone: `omaw -d -H 0.0.0.0 -P your-password --allow-host your.domain`. If you put a reverse proxy or tunnel in front, make sure it forwards `X-Forwarded-For` (origin checks look at it).
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## UI tour
|
|
140
|
+
|
|
141
|
+
```
|
|
142
|
+
┌─ top bar: brand · new chat · engine picker · subagent badge · panels · right-pane toggle ─┐
|
|
143
|
+
├────────────┬──────────────────────────────┬──────────────────────┤
|
|
144
|
+
│ sidebar │ conversation │ right pane │
|
|
145
|
+
│ · projects │ · message stream (thinking │ · file preview │
|
|
146
|
+
│ · sessions │ blocks + tool cards) │ (multi-tab) │
|
|
147
|
+
│ · archived │ · steer / queued messages │ · terminal │
|
|
148
|
+
│ · files │ · subagent run strip │ · status bar │
|
|
149
|
+
│ │ · composer (attachments, /) │ │
|
|
150
|
+
└────────────┴──────────────────────────────┴──────────────────────┘
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
The sidebar and right pane can both be dragged wider or collapsed; widths persist in `localStorage`. The composer takes `/` slash commands, `@` file mentions, drag-and-drop attachments and pasted images; the chips above it are prompt templates, the thinking toggle and suggested actions.
|
|
154
|
+
|
|
155
|
+
On narrow screens (mobile UA or ≤400px) the layout switches to overlay drawers and the sidebar collapses shortly after you pick a session. Which chunks appear in the top bar and status bar — and whether process blocks start expanded — are all switchable in settings.
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## Engines
|
|
160
|
+
|
|
161
|
+
| Engine | Notes |
|
|
162
|
+
| --- | --- |
|
|
163
|
+
| **pi** (default) | The full plugin / skill ecosystem, lazy tool loading, approval gate, goal mode and subagents; providers and models are managed by this workbench |
|
|
164
|
+
| **Codex** | The official Codex agent (app-server JSON-RPC) with its own loop and sandbox; sessions are shared with Codex Desktop / CLI; approvals are command/file level |
|
|
165
|
+
| **DeepSeek Harness** | The official DeepSeek agent (ACP); model and thinking level are switchable; permissions confirmed one by one |
|
|
166
|
+
| **opencode** | The official opencode agent (ACP) with its own tools / MCP / plugin ecosystem; sessions are shared with the opencode CLI / TUI. **Approvals follow opencode's own `permission` config** (a global allow means you will never be asked) |
|
|
167
|
+
| **fake** | A scripted, zero-token engine used only to exercise the protocol / tools / approvals (`AGENT_WEB_ENGINE=fake`, not shown in the picker by default) |
|
|
168
|
+
|
|
169
|
+
Capability matrix (`server/engine/registry.ts`):
|
|
170
|
+
|
|
171
|
+
| Capability | pi | codex | dsh | opencode |
|
|
172
|
+
| --- | :-: | :-: | :-: | :-: |
|
|
173
|
+
| Approvals | ✅ | ✅ | ✅ | per config |
|
|
174
|
+
| Model / thinking level | ✅ | ✅ | ✅ | ✅ |
|
|
175
|
+
| Resume sessions | ✅ | ✅ | ✅ | ✅ |
|
|
176
|
+
| Steering | ✅ | — | — | — |
|
|
177
|
+
| Subagent panel | ✅ | — | — | — |
|
|
178
|
+
| Workbench-managed providers | ✅ | — | — | — |
|
|
179
|
+
|
|
180
|
+
A missing engine does not block startup: you only get "not found" when you switch to it.
|
|
181
|
+
|
|
182
|
+
Per-engine escape hatches (all have defaults, usually leave them alone):
|
|
183
|
+
|
|
184
|
+
| Variable | Purpose |
|
|
185
|
+
| --- | --- |
|
|
186
|
+
| `AGENT_WEB_OPENCODE_BIN` / `_ARGS` / `_MODEL` | opencode binary, extra args (e.g. `--pure` to skip external plugins), preferred model for new sessions (`provider/model`) |
|
|
187
|
+
| `AGENT_WEB_DSH_BIN` / `_HOME` / `_MODEL` / `_PATCH` | DSH binary, data dir, model, patch toggle |
|
|
188
|
+
| `AGENT_WEB_CODEX_BIN` / `_HOME` | Codex binary and data dir |
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## Sessions and on-disk state
|
|
193
|
+
|
|
194
|
+
No database: **the engine's own files are always the source of truth** for a conversation. The web UI only reads them, renames them, and deletes them when asked.
|
|
195
|
+
|
|
196
|
+
| What | Where |
|
|
197
|
+
| --- | --- |
|
|
198
|
+
| pi sessions | `~/.pi/agent/sessions/<encoded cwd>/<ISO>_<uuid>.jsonl` (first line `{type:"session",id,timestamp,cwd}`) |
|
|
199
|
+
| Codex sessions | Codex's own thread store (via `thread/list \| resume \| delete`) |
|
|
200
|
+
| opencode / DSH sessions | Their own data dirs (opencode lists by cwd; DSH reads the workspace projection under `~/.dsh`) |
|
|
201
|
+
| Session title | pi takes the first user message (reads only the first 60 lines); renaming appends `session_info.name` to the end of the jsonl |
|
|
202
|
+
| Workbench state | `<dataDir>/settings.json`, `approval-rules.json`, `server.lock`, `logs/`, `uploads/`, `push-subscriptions.json`, `vapid-keys.json` |
|
|
203
|
+
|
|
204
|
+
"Delete session" **renames to `.deleted-<timestamp>`** (native delete APIs win when the engine has one). The file stays on disk and can be recovered.
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
## Models and providers
|
|
209
|
+
|
|
210
|
+
The models panel groups providers into two columns: **official built-ins** (the ones pi's catalog has models for) and **custom providers**.
|
|
211
|
+
|
|
212
|
+
- Built-ins need only **an API key** — endpoint and model table come from pi's catalog.
|
|
213
|
+
- Custom providers let you add models, edit base URLs, **import** from another client (actually `GET {baseUrl}/models` and tick the ones you want) and **test each one**.
|
|
214
|
+
- **Keys never leave the server**: the API returns only `hasKey` and the last four digits; writes are serialized inside the process so concurrent edits can't corrupt files.
|
|
215
|
+
|
|
216
|
+
The config truth is spread over three files plus the engine catalog: `~/.pi/agent/models.json` (pi's own writable provider catalog), `models-store.json` (legacy location), `auth.json` (`api_key` or oauth subscription credentials), with the allowlist in `settings.json.enabledModels`.
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## Approvals and security model
|
|
221
|
+
|
|
222
|
+
- Binds `127.0.0.1` by default and validates `Origin` / `Host` (including the `AGENT_WEB_ALLOWED_HOSTS` allowlist, the vite port and LAN addresses).
|
|
223
|
+
- Identity: loopback peer **and** loopback Host → allowed. With no password set, remote requests always get 403. With a password, either the cookie (`agent-web-auth`, 7 days, HttpOnly) or HTTP Basic will do; failed logins are throttled at 20 attempts / 10 minutes.
|
|
224
|
+
- Tools and commands go through approvals: **read-only tools** (read / grep / find / ls) and read-only commands pass automatically, everything else is asked per `scopeKey` (tool + executable name or target directory). Picking "always allow" writes the rule into `approval-rules.json` (atomic write; a corrupt file is treated as empty).
|
|
225
|
+
- When a turn ends, every pending approval for that session is cleared so nothing hangs waiting for a human.
|
|
226
|
+
- Uploaded temp files and session caches live in the data directory, never in your project.
|
|
227
|
+
|
|
228
|
+
> Exposing it remotely is explicit: `-H`, `-P` and `--allow-host` must all be present, or it won't work.
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
## Subagents (parallel, manageable)
|
|
233
|
+
|
|
234
|
+
The pi engine ships its own subagent implementation (**no pi-subagents plugin required**):
|
|
235
|
+
|
|
236
|
+
- **How**: the main agent gets an `Agent` tool (`subagent_type` / `prompt` / `description` / `run_in_background`) and can run several at once. Every delegation is **a real pi session** with its own context, session file and tool allowlist.
|
|
237
|
+
- **Where to watch**: run cards appear under the conversation (the strip above the composer) with status, duration, tool count, tokens and cost. Expand one to see the raw result and its session file path, and stop any of them at any time. Switching sessions swaps the strip to that session's runs. A top-bar badge gives the at-a-glance count.
|
|
238
|
+
- **Management**: the panel manages **templates** (built-in explore / general-purpose / plan, each disableable; create / edit / delete your own). Templates live at `~/.pi/agent/agents/*.md` with frontmatter `name / display_name / description / tools / model / thinking / max_turns`; the body is the system prompt — the same format pi uses, so they're readable, editable and git-friendly.
|
|
239
|
+
- **Concurrency**: a cap of 1–12 (default 4) in the panel; extra delegations queue. Turn the master switch off and the model no longer sees the `Agent` tool.
|
|
240
|
+
- **Isolation**: subagents load no skills / plugins / themes / context files by default (fast and predictable). They inherit the parent's model when they don't pin their own. Models registered by extensions fail inside subagents with "specify a model in the template".
|
|
241
|
+
|
|
242
|
+
Subagent session files are archived next to the parent session (`<parent session dir>/<parent name>/subagents/`) and never appear in the sidebar.
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
## MCP · plugins · skills
|
|
247
|
+
|
|
248
|
+
**MCP**: reads and writes `~/.pi/agent/mcp.json` (global) plus `<workspace>/.pi/mcp.json` (project), where a project entry with the same name overrides the global one. Writes preserve indentation and CRLF.
|
|
249
|
+
Exposure has four levels `codemode | deferred | direct | hidden` and tools are namespaced `mcp__<name>`.
|
|
250
|
+
**The config is the truth** — pi connects at session start, so panel changes apply to **new sessions**. Testing a connection does a real handshake with `@earendil-works/pi-mcp` (`tools/list`) and disconnects immediately; OAuth goes through `pi mcp login`. There's also a marketplace (registry / smithery / github) and a "paste a command / URL / JSON and let it parse" flow.
|
|
251
|
+
|
|
252
|
+
**Plugins**: these are pi packages — `settings.json`'s `packages` (npm / git / local) plus loose `~/.pi/agent/extensions/` and `<ws>/.pi/extensions/`. State is decided by the pi SDK's `resolve()` (querying **never** triggers `npm install`), with four states: `loaded / installed / missing / disabled`. Disabling writes `autoload:false` and deletes nothing.
|
|
253
|
+
|
|
254
|
+
**Skills**: read from `~/.agents/skills/<dir>/SKILL.md`; the list parses frontmatter only (no yaml dependency) and caps the file listing at 200 entries.
|
|
255
|
+
**Toggling = renaming `SKILL.md` to `.SKILL.md.disabled`** — there is no second state file. Skill Hub supports category search plus zip installs, and git clone can target `skills/<name>`.
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
## Architecture: SSE + RPC, no WebSocket
|
|
260
|
+
|
|
261
|
+
Early versions used WS; today there are **only two HTTP channels** (ADR-0032):
|
|
262
|
+
|
|
263
|
+
```
|
|
264
|
+
browser ──GET /api/events (SSE)──▶ server snapshot · message_delta · notice
|
|
265
|
+
──POST /api/rpc (JSON)──▶ ClientRequest → { reply } consumed in place
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
- **Downstream**: one full snapshot first, then deltas only. Message text arrives as `message_delta` chunks; structural changes (tool cards, errors, state) push a new snapshot, coalesced in a 60 ms window — snapshots are droppable, events are not. SSE sends a heartbeat every 25 s and supports gzip `Z_SYNC_FLUSH`.
|
|
269
|
+
- **Upstream**: `send_message` (text / attachments / mode), `interrupt`, `approve`, `new_chat`, `switch_conversation`, `set_engine` / `set_model` / `set_thinking_level` / `set_approval_mode`, `cancel_queued`, `rename_session`, and a handful for providers and subagents.
|
|
270
|
+
- **The protocol lives in one place**, `server/protocol.ts`, and the frontend reuses its types; unit tests keep both ends aligned.
|
|
271
|
+
- **The snapshot is the single source of truth**: the frontend's `store.ts` uses `useSyncExternalStore` and replaces state wholesale when a snapshot arrives. Locally it keeps only optimistic state like `preview` / `draft` / `pendingActive`.
|
|
272
|
+
|
|
273
|
+
**Process model**: `cli.ts` parses flags → `session/lock.ts` grabs `<dataDir>/server.lock` (`{pid,port,startedAt}`; a live pid means refuse to start, a dead pid means take over the stale lock) → `runtime.init()` → `listen`. `SIGINT/SIGTERM` and `/api/shutdown` share one graceful shutdown path (flush, disconnect engines, release the lock).
|
|
274
|
+
|
|
275
|
+
---
|
|
276
|
+
|
|
277
|
+
## Development
|
|
278
|
+
|
|
279
|
+
```bash
|
|
280
|
+
npm run dev # starts both processes with one command
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
- Externally there is still a single port **25257** (Vite listens and proxies); the backend hides on internal **25258**, so dev and prod use the same URL.
|
|
284
|
+
- Frontend HMR via Vite, backend auto-restart via `tsx --watch`.
|
|
285
|
+
- Phone debugging: `npm run dev -- --host 0.0.0.0`.
|
|
286
|
+
|
|
287
|
+
| Command | Purpose |
|
|
288
|
+
| --- | --- |
|
|
289
|
+
| `npm test` | `node --test` over `tests/unit/*.test.ts` (22 files, no extra dependencies) |
|
|
290
|
+
| `npm run typecheck` | Two `tsc --noEmit` runs: server + web |
|
|
291
|
+
| `npm run lint` | oxlint over `server` / `web/src` / `scripts` |
|
|
292
|
+
| `npm run format` | Prettier across the repo (`format:check` only checks; `*.md` is deliberately skipped) |
|
|
293
|
+
| `npm run build` | Server `tsc` + frontend `vite build` into `web/dist` |
|
|
294
|
+
| `npm run icons` | Regenerate PWA icons with playwright-core |
|
|
295
|
+
|
|
296
|
+
CI (`.github/workflows/ci.yml`): `npm ci` → typecheck → lint → test → build, on ubuntu + Node 22.
|
|
297
|
+
|
|
298
|
+
### Directory layout
|
|
299
|
+
|
|
300
|
+
```
|
|
301
|
+
oh-my-agent-web/
|
|
302
|
+
├─ server/ Backend (Express 5, TypeScript ESM)
|
|
303
|
+
│ ├─ cli.ts Command entry: start / stop / restart / status / version / upgrade
|
|
304
|
+
│ ├─ index.ts Process assembly: middleware, routes, static assets, graceful exit
|
|
305
|
+
│ ├─ protocol.ts Single source for the protocol (frontend reuses the types)
|
|
306
|
+
│ ├─ engine/ Engine adapters: pi (native SDK) / codex / dsh / opencode (ACP) / fake
|
|
307
|
+
│ │ plus the capability matrix (registry), catalog, wiring, pi-plugins
|
|
308
|
+
│ ├─ session/ Runtime: runtime, turn-*, approval bridge, rename/delete, lock, settings
|
|
309
|
+
│ ├─ sessions/ HTTP routes for deleting sessions (scanning lives in session/pi-sessions.ts)
|
|
310
|
+
│ ├─ snapshot/ Server state snapshots: state, buildSnapshot, fan-out, 60 ms coalescing
|
|
311
|
+
│ ├─ http/ auth, live-routes (SSE + RPC), aux-routes, compression, file headers
|
|
312
|
+
│ ├─ files/ File tree, preview, search, media streaming, git branches
|
|
313
|
+
│ ├─ terminal/ PTY sessions and their SSE stream
|
|
314
|
+
│ ├─ approval/ Approval scopes and rules
|
|
315
|
+
│ ├─ providers/ Providers / model catalogs / probes / imports / subscription OAuth
|
|
316
|
+
│ ├─ mcp/ mcp.json read-write, connectivity probe, OAuth, marketplace
|
|
317
|
+
│ ├─ skills/ Skill discovery, toggling, Hub installs
|
|
318
|
+
│ ├─ subagents/ Subagent template storage (`~/.pi/agent/agents/*.md`)
|
|
319
|
+
│ ├─ plugins/ HTTP routes for plugin packages
|
|
320
|
+
│ ├─ push/ Web Push (VAPID)
|
|
321
|
+
│ ├─ markers/ Parsing and stream-filtering `[[action:suggest:…]]` markers
|
|
322
|
+
│ └─ util/ env, paths, spawn-cli (cross-platform), origin, etc.
|
|
323
|
+
├─ web/ Frontend (React 19 + Vite + TypeScript)
|
|
324
|
+
│ ├─ src/components/ ~70 components: sidebar, message stream, composer, file tree, terminal, panels
|
|
325
|
+
│ ├─ src/styles/ ~45 sectioned CSS files + six theme palettes (no CSS framework)
|
|
326
|
+
│ ├─ src/ws.ts SSE + RPC client (the name is historical)
|
|
327
|
+
│ └─ src/store.ts Snapshot store (useSyncExternalStore)
|
|
328
|
+
├─ scripts/ Dev dual-process, installers, prebuild pruning, icon generation
|
|
329
|
+
├─ tests/unit/ node:test unit tests
|
|
330
|
+
├─ docs/adr/README.md ADR index
|
|
331
|
+
└─ docs/screenshots/ Real screenshots used by the READMEs (PNG 256 colors, ~1.4 MB)
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
### Code conventions
|
|
335
|
+
|
|
336
|
+
- Prettier: **tab indentation**, `printWidth 120`. oxlint runs its default rule set.
|
|
337
|
+
- 400 lines per file is a guardrail; exceeding it means splitting (`cli-info.ts` and `snapshot/*` exist for that reason).
|
|
338
|
+
- **ADR prose lives in the file-header comment of the code it constrains**, not in standalone `docs/` files — anyone editing the code will read it. `docs/adr/README.md` is only an index from number to file. Update that table when you change the code.
|
|
339
|
+
|
|
340
|
+
---
|
|
341
|
+
|
|
342
|
+
## Install size: pick the command that fits
|
|
343
|
+
|
|
344
|
+
Most of the dependency tree is frontend build-time weight (`mermaid` alone is 121 MB, plus React) and build tools that only matter on your machine. At runtime the server needs just
|
|
345
|
+
`express` / `web-push` / `node-pty` / `@earendil-works/pi-*` — the browser half already ships as `web/dist`.
|
|
346
|
+
That's why `react` / `mermaid` / `xterm` / `highlight.js` all live in `devDependencies`:
|
|
347
|
+
|
|
348
|
+
| Scenario | Command | Packages | Disk |
|
|
349
|
+
|---|---|---|---|
|
|
350
|
+
| Developing / building yourself | `npm ci` | 456 | 547 MB |
|
|
351
|
+
| Already built, just run it | `npm ci --omit=dev` | 192 | **158 MB** (~3 s) |
|
|
352
|
+
| Build then slim down | `npm ci && npm run build && npm prune --omit=dev` | 192 | **158 MB** |
|
|
353
|
+
| Ship to another machine | `npm pack` → `npm i -g ./oh-my-agent-web-*.tgz` | 193 | 223 MB (3.1 MB tarball, README screenshots included) |
|
|
354
|
+
|
|
355
|
+
Two automatic slimming steps run in `postinstall` (`scripts/prune-prebuilds.mjs`):
|
|
356
|
+
|
|
357
|
+
- **Keep only the current platform's `node-pty` prebuilds**: the package ships binaries for four platforms, and the two Windows ones alone are 58 MB. Pruning on macOS / Linux takes 62 MB → 5 MB; `npm ci` restores them as-is.
|
|
358
|
+
- Fix the executable bit on `spawn-helper`.
|
|
359
|
+
|
|
360
|
+
> Of the remaining 158 MB, almost everything is pi's model layer: the official SDKs for each provider (`openai` 17.6 MB, `@google/genai` 10.8 MB, `@anthropic-ai/sdk` 9.1 MB, `@aws-sdk/*` + `@smithy/*` 5.2 MB) —
|
|
361
|
+
> all hard dependencies of `@earendil-works/pi-ai`, unavoidable without trimming vendors.
|
|
362
|
+
|
|
363
|
+
---
|
|
364
|
+
|
|
365
|
+
## Troubleshooting
|
|
366
|
+
|
|
367
|
+
> **Why `npm ci` and not `npm install`**: this project's direct dependencies are all very new (most within a month of release).
|
|
368
|
+
> `npm install` re-resolves the version ranges from `package.json` against the registry, so if your mirror (corporate Nexus, npmmirror, etc.) hasn't synced those versions yet you get `npm error notarget No matching version found for …`.
|
|
369
|
+
> `npm ci` uses the exact versions from the lockfile and never touches that path.
|
|
370
|
+
|
|
371
|
+
Check these in order:
|
|
372
|
+
|
|
373
|
+
1. `npm error notarget No matching version found` → the mirror is behind. Check `npm config get registry`, then retry against the official one: `npm ci --registry=https://registry.npmjs.org/`.
|
|
374
|
+
2. `EBADENGINE` / pi complains about the Node version right at startup → you need Node ≥ 22.19 (`node -v`).
|
|
375
|
+
3. `node-pty` fails to build (mostly on Linux) → prebuilds ship for macOS / Windows only, so Linux compiles it in place and needs `python3`, `make`, `g++`.
|
|
376
|
+
4. Won't start but `omaw status` mentions a stale lock → a previous process didn't exit cleanly; the next `start` takes over automatically. If it's truly stuck, delete `<dataDir>/server.lock`.
|
|
377
|
+
5. Port already in use → `omaw -p 25258`, or run `omaw stop` first.
|
|
378
|
+
|
|
379
|
+
Windows pitfalls we've already hit (shell parsing, killTree, path checks, chmod, CRLF) are catalogued with P0/P1/P2 severities in `WINDOWS-COMPAT.md`.
|
|
380
|
+
|
|
381
|
+
---
|
|
382
|
+
|
|
383
|
+
## License
|
|
384
|
+
|
|
385
|
+
MIT
|