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.
Files changed (233) hide show
  1. package/LICENSE +21 -0
  2. package/README.en.md +385 -0
  3. package/README.md +322 -81
  4. package/dist/server/cli-info.js +4 -1
  5. package/dist/server/cli.js +54 -11
  6. package/dist/server/engine/builtin.js +28 -3
  7. package/dist/server/engine/codex-sessions.js +3 -3
  8. package/dist/server/engine/dsh.js +3 -1
  9. package/dist/server/engine/jsonrpc-stdio.js +33 -3
  10. package/dist/server/engine/opencode-sessions.js +8 -2
  11. package/dist/server/engine/opencode.js +3 -1
  12. package/dist/server/engine/pi-sdk.js +157 -15
  13. package/dist/server/engine/pi-subagent-tool.js +35 -13
  14. package/dist/server/engine/pi-subagents.js +38 -1
  15. package/dist/server/engine/registry.js +2 -1
  16. package/dist/server/engine/wiring.js +1 -0
  17. package/dist/server/files/dir-routes.js +7 -5
  18. package/dist/server/files/file-search.js +4 -3
  19. package/dist/server/files/file-service.js +45 -9
  20. package/dist/server/files/files-routes.js +8 -1
  21. package/dist/server/files/git-info.js +34 -7
  22. package/dist/server/http/auth.js +27 -1
  23. package/dist/server/http/aux-routes.js +6 -1
  24. package/dist/server/http/file-headers.js +75 -0
  25. package/dist/server/index.js +54 -77
  26. package/dist/server/mcp/mcp-auth.js +9 -3
  27. package/dist/server/mcp/mcp-command.js +50 -5
  28. package/dist/server/mcp/mcp-probe.js +43 -7
  29. package/dist/server/mcp/pi-mcp-config.js +30 -2
  30. package/dist/server/protocol-parse.js +11 -1
  31. package/dist/server/providers/catalog-store.js +7 -3
  32. package/dist/server/providers/catalog-writes.js +5 -3
  33. package/dist/server/providers/enabled-models.js +5 -3
  34. package/dist/server/providers/import-routes.js +15 -5
  35. package/dist/server/providers/model-test.js +72 -11
  36. package/dist/server/providers/probe.js +20 -0
  37. package/dist/server/providers/provider-handlers.js +27 -10
  38. package/dist/server/providers/provider-pool.js +63 -0
  39. package/dist/server/providers/provider-store.js +139 -20
  40. package/dist/server/providers/validate.js +13 -4
  41. package/dist/server/push/push-routes.js +3 -3
  42. package/dist/server/push/push.js +74 -12
  43. package/dist/server/session/approval-bridge.js +31 -19
  44. package/dist/server/session/conversation-create.js +1 -1
  45. package/dist/server/session/engine-switch.js +4 -1
  46. package/dist/server/session/model-controller.js +20 -2
  47. package/dist/server/session/notices.js +4 -2
  48. package/dist/server/session/pi-opener.js +44 -4
  49. package/dist/server/session/pi-sessions.js +79 -9
  50. package/dist/server/session/refresh-actions.js +3 -2
  51. package/dist/server/session/runtime-services.js +1 -0
  52. package/dist/server/session/runtime.js +50 -15
  53. package/dist/server/session/settings.js +4 -4
  54. package/dist/server/session/stats-refresher.js +7 -2
  55. package/dist/server/session/switch-conversation.js +1 -2
  56. package/dist/server/session/turn-events.js +1 -1
  57. package/dist/server/session/turn-finish.js +26 -8
  58. package/dist/server/session/turn-markers.js +6 -5
  59. package/dist/server/session/turn-queue.js +79 -14
  60. package/dist/server/session/turn-send.js +34 -10
  61. package/dist/server/skills/skill-install.js +2 -2
  62. package/dist/server/snapshot/fan-out.js +0 -5
  63. package/dist/server/snapshot/sender.js +0 -9
  64. package/dist/server/snapshot/state.js +60 -6
  65. package/dist/server/subagents/profile-store.js +2 -1
  66. package/dist/server/terminal/terminal-routes.js +50 -23
  67. package/dist/server/terminal/terminal-session.js +63 -6
  68. package/dist/server/uploads/upload-routes.js +3 -0
  69. package/dist/server/util/atomic-write.js +18 -0
  70. package/dist/server/util/env.js +58 -14
  71. package/dist/server/util/file-mode.js +44 -0
  72. package/dist/server/util/origin.js +61 -0
  73. package/dist/server/util/paths.js +79 -1
  74. package/dist/server/util/spawn-cli.js +147 -0
  75. package/dist/server/ws/handle-message.js +7 -1
  76. package/docs/screenshots/01-chat.png +0 -0
  77. package/docs/screenshots/02-answer.png +0 -0
  78. package/docs/screenshots/03-files-diff.png +0 -0
  79. package/docs/screenshots/04-terminal.png +0 -0
  80. package/docs/screenshots/05-models.png +0 -0
  81. package/docs/screenshots/06-skills.png +0 -0
  82. package/docs/screenshots/07-skills-hub.png +0 -0
  83. package/docs/screenshots/08-mcp.png +0 -0
  84. package/docs/screenshots/09-subagents.png +0 -0
  85. package/docs/screenshots/10-settings.png +0 -0
  86. package/docs/screenshots/11-plugins.png +0 -0
  87. package/docs/screenshots/12-voice.png +0 -0
  88. package/docs/screenshots/13-push.png +0 -0
  89. package/docs/screenshots/README.md +45 -0
  90. package/package.json +43 -19
  91. package/scripts/prune-prebuilds.mjs +42 -0
  92. package/web/dist/assets/_omaw-mermaid-pruned_chunk_abnfDiagram-WEYOIA3C-CvNbnJ75.js +1 -0
  93. package/web/dist/assets/_omaw-mermaid-pruned_chunk_architectureDiagram-ZHVYKT53-T7NZZ4ao.js +1 -0
  94. package/web/dist/assets/_omaw-mermaid-pruned_chunk_c4Diagram-XDPPPE54-ByuAPg39.js +1 -0
  95. package/web/dist/assets/_omaw-mermaid-pruned_chunk_cynefinDiagram-WF24UDRP-BY5DHttT.js +1 -0
  96. package/web/dist/assets/_omaw-mermaid-pruned_chunk_diagram-CBK3MWTC-D7ZYyrF7.js +1 -0
  97. package/web/dist/assets/_omaw-mermaid-pruned_chunk_diagram-ODIL2UCW-C6kcOZFc.js +1 -0
  98. package/web/dist/assets/_omaw-mermaid-pruned_chunk_diagram-PFBEJUXE-CzFPFq0D.js +1 -0
  99. package/web/dist/assets/_omaw-mermaid-pruned_chunk_diagram-TYUNFSNR-B4G4T8SL.js +1 -0
  100. package/web/dist/assets/_omaw-mermaid-pruned_chunk_ebnfDiagram-V4P3TTPT-BkQ4xwD0.js +1 -0
  101. package/web/dist/assets/_omaw-mermaid-pruned_chunk_ishikawaDiagram-HPEHV2GE-52xqckJv.js +1 -0
  102. package/web/dist/assets/_omaw-mermaid-pruned_chunk_mindmap-definition-6OY57UG3-7cQksbFn.js +1 -0
  103. package/web/dist/assets/_omaw-mermaid-pruned_chunk_pegDiagram-ECIUJNBX-udgtBpwv.js +1 -0
  104. package/web/dist/assets/_omaw-mermaid-pruned_chunk_railroadDiagram-Y72NRBL7-Cd2dcQWz.js +1 -0
  105. package/web/dist/assets/_omaw-mermaid-pruned_chunk_swimlanes-B3ENRKFQ-p34pL1Yk.js +1 -0
  106. package/web/dist/assets/_omaw-mermaid-pruned_chunk_swimlanesDiagram-AYQRV4AK-BslfPs4r.js +1 -0
  107. package/web/dist/assets/_omaw-mermaid-pruned_chunk_usecaseDiagram-WPOLBNNX-DJZoN9Xk.js +1 -0
  108. package/web/dist/assets/_omaw-mermaid-pruned_chunk_vennDiagram-Q3Y3IDCW-DPXo67cZ.js +1 -0
  109. package/web/dist/assets/_omaw-mermaid-pruned_chunk_wardleyDiagram-IVAIDKWA-BE6ukwkg.js +1 -0
  110. package/web/dist/assets/_omaw-mermaid-pruned_katex_katex-Zojedrce.js +1 -0
  111. package/web/dist/assets/arc-BTAvbR16.js +1 -0
  112. package/web/dist/assets/architecture-WOLXFQ4H-fewLD5_7.js +1 -0
  113. package/web/dist/assets/{blockDiagram-RJAE7QA3-4SqX2RCZ.js → blockDiagram-RJAE7QA3-ClmgyxZl.js} +5 -5
  114. package/web/dist/assets/channel-DfaYIFFE.js +1 -0
  115. package/web/dist/assets/{chunk-55XCU76K-BAQkUXw9.js → chunk-55XCU76K-DdC5EhZG.js} +1 -1
  116. package/web/dist/assets/chunk-7S6XSTFO-CgToWHK6.js +2 -0
  117. package/web/dist/assets/chunk-AQDTSKZB-D-rQMnp7.js +72 -0
  118. package/web/dist/assets/{chunk-DSNLSHJZ-CQfLJsEG.js → chunk-DSNLSHJZ-cuZoTGMH.js} +9 -9
  119. package/web/dist/assets/chunk-HNE4Q36P-CiKr9iSN.js +1 -0
  120. package/web/dist/assets/{chunk-NGNAAXSQ-C2Wy9Xmz.js → chunk-NGNAAXSQ-DuHRe0y2.js} +1 -1
  121. package/web/dist/assets/chunk-VQ5W62QI-DbTfXAAT.js +1 -0
  122. package/web/dist/assets/chunk-WQQL4CDK-DHanHfB5.js +10 -0
  123. package/web/dist/assets/chunk-ZAUX2LTX-SrjFXpy2.js +62 -0
  124. package/web/dist/assets/chunk-ZCHMQSOR-7Wy8xXQ5.js +2 -0
  125. package/web/dist/assets/{classDiagram-v2-4MYWR3UA-ByZcqRlk.js → classDiagram-v2-4MYWR3UA-CBe5ZDvZ.js} +4 -4
  126. package/web/dist/assets/cose-bilkent-JH36ORCC-Dljdyvhw.js +1 -0
  127. package/web/dist/assets/cynefin-EF2NZ3EQ-CcZU7GFP.js +1 -0
  128. package/web/dist/assets/dagre-NK4GIZVX-Bq_6y8qp.js +4 -0
  129. package/web/dist/assets/diagram-I5XIIV2D-C2lnnYVG.js +24 -0
  130. package/web/dist/assets/{diagram-RJA3I4VV-D-1dWVjH.js → diagram-RJA3I4VV-Bqf8Z6wJ.js} +1 -1
  131. package/web/dist/assets/elk-QONTBCTQ-Cdzq_cJ5.js +27 -0
  132. package/web/dist/assets/{erDiagram-KYQIGQAA-BkQvVdNn.js → erDiagram-KYQIGQAA-ZJLCjPFC.js} +2 -2
  133. package/web/dist/assets/eventmodeling-K75KTNOO-DHqeIpes.js +1 -0
  134. package/web/dist/assets/flowDiagram-IUGLLWBU-AVgYvXKN.js +213 -0
  135. package/web/dist/assets/ganttDiagram-R7GPNTJY-CR1SG1M7.js +292 -0
  136. package/web/dist/assets/gitGraph-VSP46ZUC-CIZQPK0R.js +1 -0
  137. package/web/dist/assets/gitGraphDiagram-PDYL7XHY-BhOCWEh6.js +106 -0
  138. package/web/dist/assets/index-CZQjJbRg.js +104 -0
  139. package/web/dist/assets/index-ChDUWKZX.css +1 -0
  140. package/web/dist/assets/info-OHQRW6UA-C2wuRxeQ.js +1 -0
  141. package/web/dist/assets/{infoDiagram-MVDRKAX5-Ct4k2rOv.js → infoDiagram-MVDRKAX5-BP5doAB5.js} +1 -1
  142. package/web/dist/assets/{journeyDiagram-BOSHW7O7-B0ommDDF.js → journeyDiagram-BOSHW7O7-BcIDRTPS.js} +4 -4
  143. package/web/dist/assets/{kanban-definition-FNSA4HC5-C5IHOEO9.js → kanban-definition-FNSA4HC5-CRH_bcoT.js} +5 -5
  144. package/web/dist/assets/{line-XIlcDZrk.js → line-iA4GPA_S.js} +1 -1
  145. package/web/dist/assets/linear-BGUKwkTH.js +1 -0
  146. package/web/dist/assets/math-DgNW_bVP.js +1 -0
  147. package/web/dist/assets/{mermaid-parser.core-9OmqIOQj.js → mermaid-parser.core-CsqmgpEv.js} +5 -5
  148. package/web/dist/assets/mermaid.core-C1yCGQK6.js +44 -0
  149. package/web/dist/assets/packet-JDAUHWVQ-2ggaoz2g.js +1 -0
  150. package/web/dist/assets/pie-XZMESJXO-h_yslQQs.js +1 -0
  151. package/web/dist/assets/{pieDiagram-GNMPY74T-BUKhe6YN.js → pieDiagram-GNMPY74T-6-JZMFyk.js} +2 -2
  152. package/web/dist/assets/{quadrantDiagram-D57K4MC3-COMDA2G7.js → quadrantDiagram-D57K4MC3-K5r1HOgL.js} +3 -3
  153. package/web/dist/assets/radar-ABXABTNO-6fOJGGgq.js +1 -0
  154. package/web/dist/assets/railroad-I3PHUGI6-B_gUgQ3d.js +1 -0
  155. package/web/dist/assets/railroad-abnf-LNEFI6M7-CJ_eqiXZ.js +1 -0
  156. package/web/dist/assets/railroad-ebnf-DWYD2UWJ-BTsgjLTU.js +1 -0
  157. package/web/dist/assets/railroad-peg-JR7BVNR7-D91uiLln.js +1 -0
  158. package/web/dist/assets/{requirementDiagram-EQYSW5RA-DilR-z_d.js → requirementDiagram-EQYSW5RA-uapnV_OO.js} +3 -3
  159. package/web/dist/assets/{sankeyDiagram-SY24JHO5-mnLwPz1t.js → sankeyDiagram-SY24JHO5-BQsbFgUb.js} +3 -3
  160. package/web/dist/assets/{sequenceDiagram-BLEHNHQU-BdH-2WXg.js → sequenceDiagram-BLEHNHQU-iRoSYX_e.js} +6 -6
  161. package/web/dist/assets/{src-DrBGN2Yi.js → src-BBrKcs9r.js} +1 -1
  162. package/web/dist/assets/{stateDiagram-v2-A6IESKWZ-Byl9Wc56.js → stateDiagram-v2-A6IESKWZ-Bzj9z5KH.js} +2 -2
  163. package/web/dist/assets/{timeline-definition-JXYKGLGB-D2DwVY9P.js → timeline-definition-JXYKGLGB-DLUUuJX0.js} +2 -2
  164. package/web/dist/assets/treeView-D4JQ5SDB-CphIQ3n5.js +1 -0
  165. package/web/dist/assets/treemap-SAJKECNS-DqU3insw.js +1 -0
  166. package/web/dist/assets/wardley-7MLQ67FV-Ch7d8cmC.js +1 -0
  167. package/web/dist/assets/{xychartDiagram-4URNHDU4-CUJ-AhMv.js → xychartDiagram-4URNHDU4-DdxpWBeM.js} +3 -3
  168. package/web/dist/index.html +2 -2
  169. package/web/dist/assets/abnfDiagram-WEYOIA3C-C0scvgfK.js +0 -1
  170. package/web/dist/assets/arc-DQWQXZ0D.js +0 -1
  171. package/web/dist/assets/architecture-WOLXFQ4H-DRYAlsMA.js +0 -1
  172. package/web/dist/assets/architectureDiagram-ZHVYKT53-DURI6MT_.js +0 -36
  173. package/web/dist/assets/c4Diagram-XDPPPE54-CyzS6It3.js +0 -38
  174. package/web/dist/assets/channel-sSfIOMg7.js +0 -1
  175. package/web/dist/assets/chunk-2E7WHVMD-B-50G064.js +0 -88
  176. package/web/dist/assets/chunk-4EMNKR2T-DsXkPvfB.js +0 -1
  177. package/web/dist/assets/chunk-7S6XSTFO-MNTmDz5n.js +0 -2
  178. package/web/dist/assets/chunk-AQDTSKZB-DxchdDrD.js +0 -72
  179. package/web/dist/assets/chunk-HAGFOTED-BaVCqyAB.js +0 -62
  180. package/web/dist/assets/chunk-HNE4Q36P-BachKm72.js +0 -1
  181. package/web/dist/assets/chunk-NQOKRVIF-D38mfZCv.js +0 -213
  182. package/web/dist/assets/chunk-UHW7PFBP-DzvEYnNC.js +0 -1
  183. package/web/dist/assets/chunk-VQ5W62QI-D7Rb-hYZ.js +0 -1
  184. package/web/dist/assets/chunk-WQQL4CDK-Dt2FUoIk.js +0 -10
  185. package/web/dist/assets/chunk-XXDRQBXY-DasKl82Z.js +0 -1
  186. package/web/dist/assets/chunk-YZO67HFG-3YefBeUz.js +0 -1
  187. package/web/dist/assets/chunk-ZAUX2LTX-CUoEknd1.js +0 -1
  188. package/web/dist/assets/chunk-ZCHMQSOR-Da3GBE09.js +0 -2
  189. package/web/dist/assets/cose-bilkent-JH36ORCC-PGAAEchc.js +0 -1
  190. package/web/dist/assets/cynefin-EF2NZ3EQ-BBkeqM17.js +0 -1
  191. package/web/dist/assets/cynefinDiagram-WF24UDRP-DOEytVty.js +0 -62
  192. package/web/dist/assets/cytoscape.esm-BegBNzOV.js +0 -321
  193. package/web/dist/assets/dagre-NK4GIZVX-Bei2BCmp.js +0 -4
  194. package/web/dist/assets/defaultLocale-BFoDCU3G.js +0 -1
  195. package/web/dist/assets/diagram-CBK3MWTC-BdeyWllS.js +0 -24
  196. package/web/dist/assets/diagram-I5XIIV2D-BmNMrWWj.js +0 -24
  197. package/web/dist/assets/diagram-ODIL2UCW-D8Kz7g8s.js +0 -30
  198. package/web/dist/assets/diagram-PFBEJUXE-BNSD58Rk.js +0 -3
  199. package/web/dist/assets/diagram-TYUNFSNR-8YHZJhel.js +0 -200
  200. package/web/dist/assets/dist-BBxVlYHc.js +0 -1
  201. package/web/dist/assets/ebnfDiagram-V4P3TTPT-CtgdOqHX.js +0 -1
  202. package/web/dist/assets/elk-QONTBCTQ-DM5bxyWI.js +0 -27
  203. package/web/dist/assets/eventmodeling-K75KTNOO-DWnHI7Q0.js +0 -1
  204. package/web/dist/assets/flowDiagram-IUGLLWBU-DYv3kVGg.js +0 -1
  205. package/web/dist/assets/ganttDiagram-R7GPNTJY-hF6RKzBy.js +0 -292
  206. package/web/dist/assets/gitGraph-VSP46ZUC-Dg0BaeiY.js +0 -1
  207. package/web/dist/assets/gitGraphDiagram-PDYL7XHY-CEJB8ISX.js +0 -106
  208. package/web/dist/assets/index-BLsWuXKg.js +0 -104
  209. package/web/dist/assets/index-Bph00xIt.css +0 -1
  210. package/web/dist/assets/info-OHQRW6UA-X0qorfja.js +0 -1
  211. package/web/dist/assets/ishikawaDiagram-HPEHV2GE-JsH1yFOe.js +0 -70
  212. package/web/dist/assets/katex-B_JcIwqj.js +0 -257
  213. package/web/dist/assets/linear-BXwFphKE.js +0 -1
  214. package/web/dist/assets/mermaid.core-B9yDV3Hs.js +0 -44
  215. package/web/dist/assets/mindmap-definition-6OY57UG3-Bc8uZ5T9.js +0 -98
  216. package/web/dist/assets/packet-JDAUHWVQ-9EbXSBeV.js +0 -1
  217. package/web/dist/assets/pegDiagram-ECIUJNBX-nYdgRfAO.js +0 -1
  218. package/web/dist/assets/pie-XZMESJXO-DNvb9i1G.js +0 -1
  219. package/web/dist/assets/radar-ABXABTNO-DAG-ygGV.js +0 -1
  220. package/web/dist/assets/railroad-I3PHUGI6-CjnKFfHL.js +0 -1
  221. package/web/dist/assets/railroad-abnf-LNEFI6M7-DOpu4hdH.js +0 -1
  222. package/web/dist/assets/railroad-ebnf-DWYD2UWJ-B7kV2hyB.js +0 -1
  223. package/web/dist/assets/railroad-peg-JR7BVNR7-Cy4mKxpf.js +0 -1
  224. package/web/dist/assets/railroadDiagram-Y72NRBL7-CJek641i.js +0 -1
  225. package/web/dist/assets/rough.esm-Dy-Kn_BL.js +0 -1
  226. package/web/dist/assets/swimlanes-B3ENRKFQ-D_Mnemnr.js +0 -1
  227. package/web/dist/assets/swimlanesDiagram-AYQRV4AK-D6uQfcsx.js +0 -8
  228. package/web/dist/assets/treeView-D4JQ5SDB-BPseZx68.js +0 -1
  229. package/web/dist/assets/treemap-SAJKECNS-DbkR3mjV.js +0 -1
  230. package/web/dist/assets/usecaseDiagram-WPOLBNNX-ClThWCPc.js +0 -328
  231. package/web/dist/assets/vennDiagram-Q3Y3IDCW-B50-oQjz.js +0 -34
  232. package/web/dist/assets/wardley-7MLQ67FV-Ct_6HXw3.js +0 -1
  233. 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
+ ![Four subagents running in parallel in one session: projects and sessions on the left, process and tool cards in the middle, file preview on the right](docs/screenshots/01-chat.png)
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
+ | ![Answer with a markdown table, changed files and usage](docs/screenshots/02-answer.png) | ![Diff view of a file](docs/screenshots/03-files-diff.png) |
52
+ | **Answer**: markdown, tables, code highlighting, token and cost footer | **Diff**: against HEAD, line-level red/green |
53
+ | ![Embedded terminal](docs/screenshots/04-terminal.png) | ![Models and providers](docs/screenshots/05-models.png) |
54
+ | **Terminal**: a real PTY in the session's cwd | **Models**: the 41 built-ins need only a key; ticked models apply |
55
+ | ![Skills panel](docs/screenshots/06-skills.png) | ![Skill Hub](docs/screenshots/07-skills-hub.png) |
56
+ | **Skills**: installed list, toggles, and `SKILL.md` | **Skill Hub**: search by category, install in one click |
57
+ | ![MCP](docs/screenshots/08-mcp.png) | ![Subagents](docs/screenshots/09-subagents.png) |
58
+ | **MCP**: global and project config, exposure, connection test | **Subagents**: who is running, results, templates and tool allowlists |
59
+ | ![Settings](docs/screenshots/10-settings.png) | ![Plugins](docs/screenshots/11-plugins.png) |
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