oh-my-agent-web 0.6.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (298) hide show
  1. package/LICENSE +21 -0
  2. package/README.en.md +531 -0
  3. package/README.md +481 -100
  4. package/dist/server/approval/rules.js +4 -16
  5. package/dist/server/approval/scope.js +3 -3
  6. package/dist/server/cli-config.js +3 -3
  7. package/dist/server/cli-info.js +13 -10
  8. package/dist/server/cli.js +162 -34
  9. package/dist/server/engine/builtin.js +90 -4
  10. package/dist/server/engine/catalog-probe.js +34 -0
  11. package/dist/server/engine/claude-map.js +296 -0
  12. package/dist/server/engine/claude-sessions.js +581 -0
  13. package/dist/server/engine/claude-transport.js +75 -0
  14. package/dist/server/engine/claude.js +414 -0
  15. package/dist/server/engine/cli-version.js +119 -0
  16. package/dist/server/engine/codex-map.js +19 -23
  17. package/dist/server/engine/codex-sessions.js +8 -8
  18. package/dist/server/engine/codex-subagents.js +349 -0
  19. package/dist/server/engine/codex.js +213 -2
  20. package/dist/server/engine/dsh-history.js +1 -1
  21. package/dist/server/engine/dsh-log.js +47 -36
  22. package/dist/server/engine/dsh-map.js +3 -5
  23. package/dist/server/engine/dsh-sessions.js +10 -11
  24. package/dist/server/engine/dsh-transport.js +2 -2
  25. package/dist/server/engine/dsh.js +48 -3
  26. package/dist/server/engine/engine-versions.js +41 -0
  27. package/dist/server/engine/fake.js +38 -7
  28. package/dist/server/engine/jsonrpc-stdio.js +33 -3
  29. package/dist/server/engine/model-registry-reload.js +1 -1
  30. package/dist/server/engine/opencode-map.js +2 -2
  31. package/dist/server/engine/opencode-projects.js +1 -1
  32. package/dist/server/engine/opencode-sessions.js +10 -4
  33. package/dist/server/engine/opencode.js +42 -2
  34. package/dist/server/engine/pi-events.js +4 -4
  35. package/dist/server/engine/pi-plugins.js +8 -6
  36. package/dist/server/engine/pi-sdk.js +316 -17
  37. package/dist/server/engine/pi-subagent-tool.js +34 -12
  38. package/dist/server/engine/pi-subagents.js +40 -3
  39. package/dist/server/engine/pi-transcript.js +1 -1
  40. package/dist/server/engine/registry.js +13 -2
  41. package/dist/server/engine/wiring.js +47 -3
  42. package/dist/server/files/content-search.js +187 -0
  43. package/dist/server/files/dir-routes.js +7 -5
  44. package/dist/server/files/file-search.js +7 -6
  45. package/dist/server/files/file-service.js +77 -23
  46. package/dist/server/files/files-routes.js +74 -6
  47. package/dist/server/files/git-info.js +84 -17
  48. package/dist/server/files/path-resolve.js +176 -0
  49. package/dist/server/files/pick-dir-routes.js +93 -0
  50. package/dist/server/files/pick-path-routes.js +126 -0
  51. package/dist/server/http/auth-routes.js +71 -4
  52. package/dist/server/http/auth.js +74 -30
  53. package/dist/server/http/aux-routes.js +26 -5
  54. package/dist/server/http/file-headers.js +75 -0
  55. package/dist/server/http/health-and-static.js +1 -1
  56. package/dist/server/http/live-routes.js +4 -4
  57. package/dist/server/http/login-page.js +128 -1
  58. package/dist/server/http/password-store.js +31 -0
  59. package/dist/server/index.js +128 -84
  60. package/dist/server/markers/actions.js +8 -8
  61. package/dist/server/mcp/codex-mcp-store.js +190 -0
  62. package/dist/server/mcp/json-mcp-store.js +276 -0
  63. package/dist/server/mcp/mcp-auth.js +10 -4
  64. package/dist/server/mcp/mcp-command.js +50 -7
  65. package/dist/server/mcp/mcp-engine-shared.js +112 -0
  66. package/dist/server/mcp/mcp-import.js +4 -5
  67. package/dist/server/mcp/mcp-market.js +2 -3
  68. package/dist/server/mcp/mcp-probe.js +43 -7
  69. package/dist/server/mcp/mcp-routes.js +4 -3
  70. package/dist/server/mcp/none-mcp-store.js +27 -0
  71. package/dist/server/mcp/pi-mcp-config.js +31 -3
  72. package/dist/server/plugins/engine-plugin-stores.js +265 -0
  73. package/dist/server/plugins/plugin-routes.js +4 -3
  74. package/dist/server/protocol-parse.js +63 -5
  75. package/dist/server/protocol.js +0 -1
  76. package/dist/server/providers/catalog-store.js +7 -3
  77. package/dist/server/providers/catalog-writes.js +6 -4
  78. package/dist/server/providers/catalog.js +2 -2
  79. package/dist/server/providers/codex-models.js +1 -1
  80. package/dist/server/providers/codex-test.js +1 -1
  81. package/dist/server/providers/enabled-models.js +6 -14
  82. package/dist/server/providers/import-routes.js +15 -5
  83. package/dist/server/providers/model-test.js +72 -11
  84. package/dist/server/providers/probe-routes.js +26 -0
  85. package/dist/server/providers/probe.js +20 -0
  86. package/dist/server/providers/provider-handlers.js +30 -13
  87. package/dist/server/providers/provider-pool.js +63 -0
  88. package/dist/server/providers/provider-store.js +143 -21
  89. package/dist/server/providers/subscription-routes.js +4 -2
  90. package/dist/server/providers/validate.js +26 -18
  91. package/dist/server/push/push-routes.js +35 -6
  92. package/dist/server/push/push.js +116 -20
  93. package/dist/server/session/approval-bridge.js +31 -19
  94. package/dist/server/session/client-view.js +2 -2
  95. package/dist/server/session/close-ephemeral.js +23 -0
  96. package/dist/server/session/conversation-create.js +32 -10
  97. package/dist/server/session/delete-session.js +25 -14
  98. package/dist/server/session/engine-switch.js +16 -6
  99. package/dist/server/session/fork-session.js +38 -0
  100. package/dist/server/session/lock.js +4 -4
  101. package/dist/server/session/model-controller.js +34 -4
  102. package/dist/server/session/move-session.js +40 -0
  103. package/dist/server/session/notices.js +4 -2
  104. package/dist/server/session/persist-ephemeral.js +48 -0
  105. package/dist/server/session/pi-opener.js +44 -4
  106. package/dist/server/session/pi-refresh.js +1 -1
  107. package/dist/server/session/pi-sessions-provider.js +2 -2
  108. package/dist/server/session/pi-sessions.js +174 -15
  109. package/dist/server/session/refresh-actions.js +3 -2
  110. package/dist/server/session/runtime-services.js +1 -0
  111. package/dist/server/session/runtime.js +194 -24
  112. package/dist/server/session/session-stats.js +2 -2
  113. package/dist/server/session/settings.js +34 -53
  114. package/dist/server/session/stats-refresher.js +7 -2
  115. package/dist/server/session/subagents.js +4 -1
  116. package/dist/server/session/suggest-title.js +33 -0
  117. package/dist/server/session/switch-conversation.js +1 -2
  118. package/dist/server/session/title-prompt.js +126 -0
  119. package/dist/server/session/turn-events.js +1 -1
  120. package/dist/server/session/turn-finish.js +28 -10
  121. package/dist/server/session/turn-markers.js +6 -5
  122. package/dist/server/session/turn-queue.js +83 -18
  123. package/dist/server/session/turn-send.js +34 -10
  124. package/dist/server/session/turn-watchdog.js +2 -2
  125. package/dist/server/skills/skill-install.js +5 -7
  126. package/dist/server/skills/skill-store.js +3 -3
  127. package/dist/server/skills/skillhub.js +3 -4
  128. package/dist/server/snapshot/fan-out.js +0 -5
  129. package/dist/server/snapshot/messages.js +2 -8
  130. package/dist/server/snapshot/sender.js +1 -10
  131. package/dist/server/snapshot/state.js +63 -11
  132. package/dist/server/subagents/profile-store.js +13 -10
  133. package/dist/server/terminal/terminal-routes.js +50 -23
  134. package/dist/server/terminal/terminal-session.js +70 -13
  135. package/dist/server/uploads/upload-routes.js +4 -1
  136. package/dist/server/uploads/upload-store.js +4 -6
  137. package/dist/server/util/atomic-write.js +18 -0
  138. package/dist/server/util/env.js +81 -31
  139. package/dist/server/util/file-mode.js +44 -0
  140. package/dist/server/util/ids.js +1 -1
  141. package/dist/server/util/json-file.js +38 -0
  142. package/dist/server/util/log-file.js +3 -3
  143. package/dist/server/util/log.js +4 -4
  144. package/dist/server/util/origin.js +61 -19
  145. package/dist/server/util/paths.js +103 -3
  146. package/dist/server/util/pricing-index.js +2 -6
  147. package/dist/server/util/pricing.js +10 -10
  148. package/dist/server/util/spawn-cli.js +147 -0
  149. package/dist/server/util/upstream-version.js +10 -12
  150. package/dist/server/util/version.js +2 -2
  151. package/dist/server/web-proxy/proxy-routes.js +167 -0
  152. package/dist/server/web-proxy/proxy-url.js +60 -0
  153. package/dist/server/web-proxy/rewrite.js +84 -0
  154. package/dist/server/ws/handle-message.js +28 -3
  155. package/package.json +44 -21
  156. package/scripts/prune-prebuilds.mjs +42 -0
  157. package/web/dist/assets/_oh-my-agent-web-mermaid-pruned_chunk_abnfDiagram-WEYOIA3C-Dq-2fRb4.js +1 -0
  158. package/web/dist/assets/_oh-my-agent-web-mermaid-pruned_chunk_architectureDiagram-ZHVYKT53-Dh5CEs4k.js +1 -0
  159. package/web/dist/assets/_oh-my-agent-web-mermaid-pruned_chunk_c4Diagram-XDPPPE54-Cb19QmmE.js +1 -0
  160. package/web/dist/assets/_oh-my-agent-web-mermaid-pruned_chunk_cynefinDiagram-WF24UDRP-COk-IL9O.js +1 -0
  161. package/web/dist/assets/_oh-my-agent-web-mermaid-pruned_chunk_diagram-CBK3MWTC-Gp_0nfEJ.js +1 -0
  162. package/web/dist/assets/_oh-my-agent-web-mermaid-pruned_chunk_diagram-ODIL2UCW-rzPf_9IN.js +1 -0
  163. package/web/dist/assets/_oh-my-agent-web-mermaid-pruned_chunk_diagram-PFBEJUXE-B5EnLWwl.js +1 -0
  164. package/web/dist/assets/_oh-my-agent-web-mermaid-pruned_chunk_diagram-TYUNFSNR-DVpFKFwC.js +1 -0
  165. package/web/dist/assets/_oh-my-agent-web-mermaid-pruned_chunk_ebnfDiagram-V4P3TTPT-CDL1qiPY.js +1 -0
  166. package/web/dist/assets/_oh-my-agent-web-mermaid-pruned_chunk_ishikawaDiagram-HPEHV2GE-CSkoONzp.js +1 -0
  167. package/web/dist/assets/_oh-my-agent-web-mermaid-pruned_chunk_mindmap-definition-6OY57UG3-B9sdVB6_.js +1 -0
  168. package/web/dist/assets/_oh-my-agent-web-mermaid-pruned_chunk_pegDiagram-ECIUJNBX-B6P7baCF.js +1 -0
  169. package/web/dist/assets/_oh-my-agent-web-mermaid-pruned_chunk_railroadDiagram-Y72NRBL7-W_a8Vy2l.js +1 -0
  170. package/web/dist/assets/_oh-my-agent-web-mermaid-pruned_chunk_swimlanes-B3ENRKFQ-DvGif-RR.js +1 -0
  171. package/web/dist/assets/_oh-my-agent-web-mermaid-pruned_chunk_swimlanesDiagram-AYQRV4AK-D0gFG_EI.js +1 -0
  172. package/web/dist/assets/_oh-my-agent-web-mermaid-pruned_chunk_usecaseDiagram-WPOLBNNX-BjgUBJiR.js +1 -0
  173. package/web/dist/assets/_oh-my-agent-web-mermaid-pruned_chunk_vennDiagram-Q3Y3IDCW-DnVuWTpF.js +1 -0
  174. package/web/dist/assets/_oh-my-agent-web-mermaid-pruned_chunk_wardleyDiagram-IVAIDKWA-B2vDAqpl.js +1 -0
  175. package/web/dist/assets/_oh-my-agent-web-mermaid-pruned_katex_katex-Zojedrce.js +1 -0
  176. package/web/dist/assets/arc-zmD1IRwE.js +1 -0
  177. package/web/dist/assets/architecture-WOLXFQ4H-C5B92zMK.js +1 -0
  178. package/web/dist/assets/{blockDiagram-RJAE7QA3-4SqX2RCZ.js → blockDiagram-RJAE7QA3-BOZKv8NT.js} +5 -5
  179. package/web/dist/assets/channel-DVBc3OcZ.js +1 -0
  180. package/web/dist/assets/{chunk-55XCU76K-BAQkUXw9.js → chunk-55XCU76K-Cqr92VtU.js} +1 -1
  181. package/web/dist/assets/chunk-7S6XSTFO-DDqM0lw8.js +2 -0
  182. package/web/dist/assets/chunk-AQDTSKZB-CeUIfGt5.js +72 -0
  183. package/web/dist/assets/{chunk-DSNLSHJZ-CQfLJsEG.js → chunk-DSNLSHJZ-Bf4nxMnG.js} +9 -9
  184. package/web/dist/assets/chunk-HNE4Q36P-CP_5bmzn.js +1 -0
  185. package/web/dist/assets/{chunk-NGNAAXSQ-C2Wy9Xmz.js → chunk-NGNAAXSQ-DuHRe0y2.js} +1 -1
  186. package/web/dist/assets/chunk-VQ5W62QI-C4KlhrWA.js +1 -0
  187. package/web/dist/assets/chunk-WQQL4CDK-OBr867RS.js +10 -0
  188. package/web/dist/assets/chunk-ZAUX2LTX-BGf21XAP.js +62 -0
  189. package/web/dist/assets/chunk-ZCHMQSOR-B1v2_vIA.js +2 -0
  190. package/web/dist/assets/{classDiagram-v2-4MYWR3UA-ByZcqRlk.js → classDiagram-v2-4MYWR3UA-D73WliGc.js} +4 -4
  191. package/web/dist/assets/cose-bilkent-JH36ORCC-BHjex_ed.js +1 -0
  192. package/web/dist/assets/cynefin-EF2NZ3EQ-BkwUbDxE.js +1 -0
  193. package/web/dist/assets/dagre-NK4GIZVX-HBESSwxd.js +4 -0
  194. package/web/dist/assets/diagram-I5XIIV2D-B0x4b3TO.js +24 -0
  195. package/web/dist/assets/{diagram-RJA3I4VV-D-1dWVjH.js → diagram-RJA3I4VV-D5I3zPSl.js} +1 -1
  196. package/web/dist/assets/elk-QONTBCTQ-Bf1nltwr.js +27 -0
  197. package/web/dist/assets/{erDiagram-KYQIGQAA-BkQvVdNn.js → erDiagram-KYQIGQAA-DPncMSdU.js} +2 -2
  198. package/web/dist/assets/eventmodeling-K75KTNOO-DMA5HThh.js +1 -0
  199. package/web/dist/assets/flowDiagram-IUGLLWBU-tz3GJD8_.js +213 -0
  200. package/web/dist/assets/ganttDiagram-R7GPNTJY-BdLbjwpy.js +292 -0
  201. package/web/dist/assets/gitGraph-VSP46ZUC-D-EmEDwq.js +1 -0
  202. package/web/dist/assets/gitGraphDiagram-PDYL7XHY-C1MNufrt.js +106 -0
  203. package/web/dist/assets/index-DxuhX7Zj.css +1 -0
  204. package/web/dist/assets/index-Zo1mtXrj.js +111 -0
  205. package/web/dist/assets/info-OHQRW6UA-Dnj11J5n.js +1 -0
  206. package/web/dist/assets/{infoDiagram-MVDRKAX5-Ct4k2rOv.js → infoDiagram-MVDRKAX5-CR1Pc-ET.js} +1 -1
  207. package/web/dist/assets/{journeyDiagram-BOSHW7O7-B0ommDDF.js → journeyDiagram-BOSHW7O7-BaQQ5bT0.js} +4 -4
  208. package/web/dist/assets/{kanban-definition-FNSA4HC5-C5IHOEO9.js → kanban-definition-FNSA4HC5-CryJiCse.js} +5 -5
  209. package/web/dist/assets/{line-XIlcDZrk.js → line-DAqohcwr.js} +1 -1
  210. package/web/dist/assets/linear-Aj6QlF4i.js +1 -0
  211. package/web/dist/assets/math-OLjDjiS-.js +1 -0
  212. package/web/dist/assets/{mermaid-parser.core-9OmqIOQj.js → mermaid-parser.core-BfmVJIf8.js} +5 -5
  213. package/web/dist/assets/mermaid.core-DcmL9PWM.js +44 -0
  214. package/web/dist/assets/packet-JDAUHWVQ-DmHJYz0u.js +1 -0
  215. package/web/dist/assets/pie-XZMESJXO-DyIYlEiZ.js +1 -0
  216. package/web/dist/assets/{pieDiagram-GNMPY74T-BUKhe6YN.js → pieDiagram-GNMPY74T-CbmNjslV.js} +2 -2
  217. package/web/dist/assets/{quadrantDiagram-D57K4MC3-COMDA2G7.js → quadrantDiagram-D57K4MC3-b8t3m46P.js} +3 -3
  218. package/web/dist/assets/radar-ABXABTNO-BRduUljF.js +1 -0
  219. package/web/dist/assets/railroad-I3PHUGI6-CS79uNF5.js +1 -0
  220. package/web/dist/assets/railroad-abnf-LNEFI6M7-80I8zkTd.js +1 -0
  221. package/web/dist/assets/railroad-ebnf-DWYD2UWJ-CvMLODGQ.js +1 -0
  222. package/web/dist/assets/railroad-peg-JR7BVNR7-CDA3EuEX.js +1 -0
  223. package/web/dist/assets/{requirementDiagram-EQYSW5RA-DilR-z_d.js → requirementDiagram-EQYSW5RA-Bp5ukALL.js} +3 -3
  224. package/web/dist/assets/{sankeyDiagram-SY24JHO5-mnLwPz1t.js → sankeyDiagram-SY24JHO5-DWEy27rM.js} +3 -3
  225. package/web/dist/assets/{sequenceDiagram-BLEHNHQU-BdH-2WXg.js → sequenceDiagram-BLEHNHQU-Hz6IqSZC.js} +6 -6
  226. package/web/dist/assets/{src-DrBGN2Yi.js → src-DtpyLxw7.js} +1 -1
  227. package/web/dist/assets/{stateDiagram-v2-A6IESKWZ-Byl9Wc56.js → stateDiagram-v2-A6IESKWZ-BXLpOvku.js} +2 -2
  228. package/web/dist/assets/{timeline-definition-JXYKGLGB-D2DwVY9P.js → timeline-definition-JXYKGLGB-COLhHvFy.js} +2 -2
  229. package/web/dist/assets/treeView-D4JQ5SDB-Bv_XbrZv.js +1 -0
  230. package/web/dist/assets/treemap-SAJKECNS-DiIJdbav.js +1 -0
  231. package/web/dist/assets/wardley-7MLQ67FV-9RG35vNe.js +1 -0
  232. package/web/dist/assets/{xychartDiagram-4URNHDU4-CUJ-AhMv.js → xychartDiagram-4URNHDU4-D_SC3zbf.js} +3 -3
  233. package/web/dist/index.html +2 -2
  234. package/web/dist/assets/abnfDiagram-WEYOIA3C-C0scvgfK.js +0 -1
  235. package/web/dist/assets/arc-DQWQXZ0D.js +0 -1
  236. package/web/dist/assets/architecture-WOLXFQ4H-DRYAlsMA.js +0 -1
  237. package/web/dist/assets/architectureDiagram-ZHVYKT53-DURI6MT_.js +0 -36
  238. package/web/dist/assets/c4Diagram-XDPPPE54-CyzS6It3.js +0 -38
  239. package/web/dist/assets/channel-sSfIOMg7.js +0 -1
  240. package/web/dist/assets/chunk-2E7WHVMD-B-50G064.js +0 -88
  241. package/web/dist/assets/chunk-4EMNKR2T-DsXkPvfB.js +0 -1
  242. package/web/dist/assets/chunk-7S6XSTFO-MNTmDz5n.js +0 -2
  243. package/web/dist/assets/chunk-AQDTSKZB-DxchdDrD.js +0 -72
  244. package/web/dist/assets/chunk-HAGFOTED-BaVCqyAB.js +0 -62
  245. package/web/dist/assets/chunk-HNE4Q36P-BachKm72.js +0 -1
  246. package/web/dist/assets/chunk-NQOKRVIF-D38mfZCv.js +0 -213
  247. package/web/dist/assets/chunk-UHW7PFBP-DzvEYnNC.js +0 -1
  248. package/web/dist/assets/chunk-VQ5W62QI-D7Rb-hYZ.js +0 -1
  249. package/web/dist/assets/chunk-WQQL4CDK-Dt2FUoIk.js +0 -10
  250. package/web/dist/assets/chunk-XXDRQBXY-DasKl82Z.js +0 -1
  251. package/web/dist/assets/chunk-YZO67HFG-3YefBeUz.js +0 -1
  252. package/web/dist/assets/chunk-ZAUX2LTX-CUoEknd1.js +0 -1
  253. package/web/dist/assets/chunk-ZCHMQSOR-Da3GBE09.js +0 -2
  254. package/web/dist/assets/cose-bilkent-JH36ORCC-PGAAEchc.js +0 -1
  255. package/web/dist/assets/cynefin-EF2NZ3EQ-BBkeqM17.js +0 -1
  256. package/web/dist/assets/cynefinDiagram-WF24UDRP-DOEytVty.js +0 -62
  257. package/web/dist/assets/cytoscape.esm-BegBNzOV.js +0 -321
  258. package/web/dist/assets/dagre-NK4GIZVX-Bei2BCmp.js +0 -4
  259. package/web/dist/assets/defaultLocale-BFoDCU3G.js +0 -1
  260. package/web/dist/assets/diagram-CBK3MWTC-BdeyWllS.js +0 -24
  261. package/web/dist/assets/diagram-I5XIIV2D-BmNMrWWj.js +0 -24
  262. package/web/dist/assets/diagram-ODIL2UCW-D8Kz7g8s.js +0 -30
  263. package/web/dist/assets/diagram-PFBEJUXE-BNSD58Rk.js +0 -3
  264. package/web/dist/assets/diagram-TYUNFSNR-8YHZJhel.js +0 -200
  265. package/web/dist/assets/dist-BBxVlYHc.js +0 -1
  266. package/web/dist/assets/ebnfDiagram-V4P3TTPT-CtgdOqHX.js +0 -1
  267. package/web/dist/assets/elk-QONTBCTQ-DM5bxyWI.js +0 -27
  268. package/web/dist/assets/eventmodeling-K75KTNOO-DWnHI7Q0.js +0 -1
  269. package/web/dist/assets/flowDiagram-IUGLLWBU-DYv3kVGg.js +0 -1
  270. package/web/dist/assets/ganttDiagram-R7GPNTJY-hF6RKzBy.js +0 -292
  271. package/web/dist/assets/gitGraph-VSP46ZUC-Dg0BaeiY.js +0 -1
  272. package/web/dist/assets/gitGraphDiagram-PDYL7XHY-CEJB8ISX.js +0 -106
  273. package/web/dist/assets/index-BLsWuXKg.js +0 -104
  274. package/web/dist/assets/index-Bph00xIt.css +0 -1
  275. package/web/dist/assets/info-OHQRW6UA-X0qorfja.js +0 -1
  276. package/web/dist/assets/ishikawaDiagram-HPEHV2GE-JsH1yFOe.js +0 -70
  277. package/web/dist/assets/katex-B_JcIwqj.js +0 -257
  278. package/web/dist/assets/linear-BXwFphKE.js +0 -1
  279. package/web/dist/assets/mermaid.core-B9yDV3Hs.js +0 -44
  280. package/web/dist/assets/mindmap-definition-6OY57UG3-Bc8uZ5T9.js +0 -98
  281. package/web/dist/assets/packet-JDAUHWVQ-9EbXSBeV.js +0 -1
  282. package/web/dist/assets/pegDiagram-ECIUJNBX-nYdgRfAO.js +0 -1
  283. package/web/dist/assets/pie-XZMESJXO-DNvb9i1G.js +0 -1
  284. package/web/dist/assets/radar-ABXABTNO-DAG-ygGV.js +0 -1
  285. package/web/dist/assets/railroad-I3PHUGI6-CjnKFfHL.js +0 -1
  286. package/web/dist/assets/railroad-abnf-LNEFI6M7-DOpu4hdH.js +0 -1
  287. package/web/dist/assets/railroad-ebnf-DWYD2UWJ-B7kV2hyB.js +0 -1
  288. package/web/dist/assets/railroad-peg-JR7BVNR7-Cy4mKxpf.js +0 -1
  289. package/web/dist/assets/railroadDiagram-Y72NRBL7-CJek641i.js +0 -1
  290. package/web/dist/assets/rough.esm-Dy-Kn_BL.js +0 -1
  291. package/web/dist/assets/swimlanes-B3ENRKFQ-D_Mnemnr.js +0 -1
  292. package/web/dist/assets/swimlanesDiagram-AYQRV4AK-D6uQfcsx.js +0 -8
  293. package/web/dist/assets/treeView-D4JQ5SDB-BPseZx68.js +0 -1
  294. package/web/dist/assets/treemap-SAJKECNS-DbkR3mjV.js +0 -1
  295. package/web/dist/assets/usecaseDiagram-WPOLBNNX-ClThWCPc.js +0 -328
  296. package/web/dist/assets/vennDiagram-Q3Y3IDCW-B50-oQjz.js +0 -34
  297. package/web/dist/assets/wardley-7MLQ67FV-Ct_6HXw3.js +0 -1
  298. 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,531 @@
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; the web page is where you watch it work, manage its tools and models, cut in to correct it whenever you like, and — when the moment comes — read files, open a terminal, or highlight a passage and ask for a change.
6
+
7
+ Single user, loopback only, and **the engine's own on-disk files are always the source of truth for a conversation** — no database, no account system, no second copy of the session in our own store. One `oh-my-agent-web` process is one person's workbench.
8
+
9
+ ![A real session: projects and sessions on the left, thinking blocks and tool cards in the middle, a file preview of the same repo on the right](docs/screenshots/01-chat.png)
10
+
11
+ > Every screenshot below is the real UI of this repo (the 0.8.0 build) — pi engine + DeepSeek, working on a small `demo-app` project.
12
+ > Directories, commands, the `+6 −1` diff, tokens and cost all come from that actual run — no collages, no mockups.
13
+ > What each shot shows, how it was taken and how it was compressed is in [`docs/screenshots/README.md`](docs/screenshots/README.md).
14
+
15
+ ---
16
+
17
+ ## Install
18
+
19
+ Requires **Node.js ≥ 22.19** and **npm ≥ 9**; macOS / Linux / Windows all work. You end up with an `oh-my-agent-web` command (short aliases: `aw`, `agent-web` — all equivalent).
20
+
21
+ ### Install globally with npm (recommended)
22
+
23
+ ```bash
24
+ npm -g install oh-my-agent-web
25
+ ```
26
+
27
+ No version tag means the current release. To pin a version or use a mirror:
28
+
29
+ ```bash
30
+ npm -g install oh-my-agent-web@latest
31
+ npm -g install oh-my-agent-web@<version> --registry=https://registry.npmmirror.com
32
+ ```
33
+
34
+ You get three commands that all point at the same entry point: **`oh-my-agent-web`** (used throughout this README),
35
+ `aw` (the short alias you'll probably type), and `agent-web`.
36
+
37
+ Upgrade and uninstall:
38
+
39
+ ```bash
40
+ oh-my-agent-web upgrade # same as npm -g install oh-my-agent-web@latest
41
+ npm -g uninstall oh-my-agent-web # uninstall; data in ~/.oh-my-agent-web is left alone
42
+ ```
43
+
44
+ On Linux, `node-pty` (the embedded terminal) ships prebuilds only for macOS / Windows, so Linux compiles it in place: you need `make`, `g++` and `python3`. When those are missing, both the page and the install script say exactly what's missing — the terminal won't open until then.
45
+
46
+ ### One-line install (never touches global npm)
47
+
48
+ macOS / Linux:
49
+
50
+ ```bash
51
+ curl -fsSL https://raw.githubusercontent.com/duzhenxun/oh-my-agent-web/main/scripts/install.sh | sh
52
+ ```
53
+
54
+ Windows (PowerShell):
55
+
56
+ ```powershell
57
+ powershell -c "irm https://raw.githubusercontent.com/duzhenxun/oh-my-agent-web/main/scripts/install.ps1 | iex"
58
+ ```
59
+
60
+ The script does four things: **finds a new enough Node** (downloads an official build into `~/.oh-my-agent-web/node` and checks its sha256 if needed), **`npm install -g --prefix ~/.oh-my-agent-web`** (never the system-wide prefix, no sudo), **links `aw` / `agent-web` / `oh-my-agent-web` into `~/.local/bin`** (patching PATH if necessary), and **smoke-tests once** (version string + whether `node-pty` can be required, i.e. whether the terminal will open).
61
+
62
+ That `~/.oh-my-agent-web` is also the **data directory**: what gets installed (`node/`, `lib/`, `bin/`) sits next to your `settings.json`, `password`, `uploads/` and `logs/`.
63
+
64
+ | What you want to change | How (`sh` version; PowerShell uses env vars) |
65
+ |---|---|
66
+ | Version | `OH_MY_AGENT_WEB_VERSION=<version>` (or `--version <version>`) |
67
+ | Install elsewhere | `OH_MY_AGENT_WEB_HOME=/opt/oh-my-agent-web` (or `--home /opt/oh-my-agent-web`) |
68
+ | Registry mirror | `OH_MY_AGENT_WEB_REGISTRY=https://registry.npmmirror.com` (or `--registry …`) |
69
+ | Leave PATH alone | `OH_MY_AGENT_WEB_NO_PATH=1` (or `--no-modify-path`) |
70
+ | Install build tools | `OH_MY_AGENT_WEB_BUILD_TOOLS=1` (or `--with-build-tools`) |
71
+ | Uninstall | `… \| sh -s -- --uninstall` (removes only what was installed; `settings.json` / password / uploads / logs stay) |
72
+
73
+ ---
74
+
75
+ ## Commands
76
+
77
+ The three commands are completely equivalent; everything below is written as `oh-my-agent-web` (`aw` is its short alias).
78
+
79
+ | Command | What it does |
80
+ |---|---|
81
+ | `oh-my-agent-web` | **Start (default)**: runs in the background and opens the browser, handing the terminal straight back; default workspace = current directory |
82
+ | `oh-my-agent-web start -f` | Run in the foreground, logs right in the terminal, `Ctrl-C` to quit |
83
+ | `oh-my-agent-web status` | pid / port / uptime / engine / session count / workspace |
84
+ | `oh-my-agent-web restart` | Stop then start (background by default; `-f` for foreground) |
85
+ | `oh-my-agent-web stop` | Stop the running instance (foreground or background — it reads the lock file in the data dir instead of guessing a port) |
86
+ | `oh-my-agent-web version` | Version string (`-v` / `--version` are synonyms) |
87
+ | `oh-my-agent-web upgrade` | Upgrade to the latest release (it runs `npm -g install oh-my-agent-web@latest`) |
88
+ | `oh-my-agent-web help` | Show help (`-h` / `--help` are synonyms) |
89
+
90
+ ### Flags
91
+
92
+ | Flag | Env var | Default | Notes |
93
+ |---|---|---|---|
94
+ | `-p, --port` | `AGENT_WEB_PORT` | `25257` | Listen port |
95
+ | `-H, --host` | `AGENT_WEB_HOST` | `127.0.0.1` | Listen address; only change it for remote access |
96
+ | `-P, --password` | `AGENT_WEB_PASSWORD` | none | Login password; unset = loopback only (a remote first visit asks you to set one) |
97
+ | `-f, --foreground` | — | off (background by default) | Foreground run, logs in the terminal; `-d` / `--detach` is the old spelling and now equals the default |
98
+ | `--no-open` | — | on | Don't open the browser |
99
+ | `--allow-host` | `AGENT_WEB_ALLOWED_HOSTS` | loopback only | Extra allowed hostnames / LAN IPs (repeatable or comma-separated) |
100
+ | `--data-dir` | `AGENT_WEB_DATA_DIR` | `~/.oh-my-agent-web` | Settings, password, uploads, logs and the lock file live here |
101
+ | — | `AGENT_WEB_CWD` | `process.cwd()` | Default workspace (before any session exists) |
102
+ | — | `AGENT_WEB_ENGINE` | `pi` | Default engine |
103
+ | — | `AGENT_WEB_APPROVAL_MODE` | `allow` | Default approval mode for new sessions; `ask` confirms every tool call |
104
+ | — | `AGENT_WEB_TURN_TIMEOUT_MS` | 20 minutes | Per-turn watchdog timeout |
105
+ | — | `AGENT_WEB_LOG` | `info` | `debug` / `info` / `warn` / `error` |
106
+
107
+ ### Common examples
108
+
109
+ ```bash
110
+ oh-my-agent-web # background + open the page (the usual one)
111
+ oh-my-agent-web -f # foreground, logs in your face, Ctrl-C to quit
112
+ oh-my-agent-web -p 25258 # different port (when 25257 is taken)
113
+ oh-my-agent-web status && oh-my-agent-web restart # check, then restart
114
+ oh-my-agent-web stop # stop it (works for foreground and background)
115
+ oh-my-agent-web --data-dir ~/agent-web-data # different data directory
116
+ AGENT_WEB_CWD=~/code/my-proj oh-my-agent-web # set the default workspace
117
+ oh-my-agent-web -H 0.0.0.0 --allow-host agent.example.com # allow outside access (first visit asks you to set a password)
118
+ ```
119
+
120
+ > **Reaching it from your phone**: `oh-my-agent-web -H 0.0.0.0 --allow-host your.domain`. The first visit from the phone asks you to **set an access password** (stored as `password` in the data dir; after that you just log in). Reverse proxies / tunnels should pass `X-Forwarded-For` (origin checking looks at it).
121
+ >
122
+ > **Running `oh-my-agent-web` from your home directory** works, but home is an unsafe workspace (the file tree, search and the agent's cwd would be your whole home). In that case it falls back to `<data dir>/workspace` and prints a line about it; to point at a project use `AGENT_WEB_CWD=/path/to/project`.
123
+
124
+ Each engine also has its own escape hatches (all have defaults; you normally don't touch them): `AGENT_WEB_CODEX_BIN` / `_HOME`, `AGENT_WEB_DSH_BIN` / `_HOME` / `_MODEL` / `_PATCH`, `AGENT_WEB_OPENCODE_BIN` / `_ARGS` / `_MODEL`, `AGENT_WEB_CLAUDE_BIN` / `_ARGS` / `_MODEL` (it auto-detects `claude-code-acp` / `claude-agent-acp` and says so when neither is installed).
125
+
126
+ ---
127
+
128
+ ## What it is, what it isn't
129
+
130
+ **It is**: a front end that spreads the agent's *process* out in front of you. Thinking blocks, tool calls, changed files, tokens and cost all live in the conversation stream. You can cut in mid-turn, highlight a passage to file a comment on it, or open a scratch chat that never touches disk just to ask one question.
131
+
132
+ **It is not**: a new agent engine, and it is not a SaaS that moves your sessions into the cloud. It does not rewrite prompts and does not take over tool implementations — what you install is pi / Codex / Claude Code / opencode / DeepSeek Harness, and the workbench just gives them a readable UI, clickable buttons, and a session list that survives restarts.
133
+
134
+ Three hard rules:
135
+
136
+ 1. **No database**: a conversation *is* the JSONL / thread the engine wrote. The web UI reads it, renames it, and deletes it when asked.
137
+ 2. **No pretending**: anything an engine can't do is hidden in the UI (the capability matrix); a panel that can't get data says so, and no other engine's config is passed off as this one's.
138
+ 3. **No overreach**: it listens on `127.0.0.1` only by default; exposing it remotely takes all three of `-H`, `-P` and `--allow-host`.
139
+
140
+ ---
141
+
142
+ ## Conversation
143
+
144
+ **Streaming text + collapsible thinking blocks + tool cards.** A tool card shows arguments, the full command (copyable), output, duration and pass/fail. Thinking and tool calls inside one turn are grouped into "process, N steps" blocks that expand when clicked.
145
+
146
+ ![The footer of one reply: a markdown table, the changed-files chip, and this turn's tokens / cache / cost](docs/screenshots/02-answer.png)
147
+
148
+ The footer of every reply is the usage **for that turn**: input (cache miss) / output / cache read / cost, with a "Copy" that takes the whole block. The running total for the session is behind the context ring in the status bar (subagents are separate sessions billed separately and are not counted there).
149
+
150
+ A few things in the conversation are clickable:
151
+
152
+ - **Changed-files chip**: which files this reply touched (the chip at the bottom of the screenshot above shows `store.ts`); one click lands you straight on the diff in the right pane.
153
+ - **Branch icon**: "Branch from here", which starts a new conversation at this message; the original stays byte-for-byte unchanged.
154
+ - **File paths**: a path like `web/src/App.tsx` in the body opens in the preview.
155
+
156
+ ### Cutting in, queueing, stopping
157
+
158
+ While a turn is running, the composer does not lock up:
159
+
160
+ | Action | Meaning |
161
+ |---|---|
162
+ | **Steer** | Takes effect immediately, inserted into the current turn as the next instruction |
163
+ | **Queue** | Wait until this turn ends; you can see what's at the head of the queue and retract anything |
164
+ | **Stop** | Interrupt the turn and keep whatever was already produced |
165
+
166
+ Steering is pi-only (its SDK has `streamingBehavior: "steer"`). Other engines have no such notion, so the host **degrades it to queueing** rather than firing a second message that would flush the active turn.
167
+
168
+ ---
169
+
170
+ ## Notes: highlight a passage and comment on it
171
+
172
+ **Select some text in the conversation** and a small toolbar floats up: `Add to session` / `Annotate` / `Ask in a temp session`.
173
+
174
+ <table><tr>
175
+ <td width="50%"><img src="docs/screenshots/14-selection-toolbar.png" alt="The toolbar that floats up after you select a passage"></td>
176
+ <td width="50%"><img src="docs/screenshots/15-annotations.png" alt="After annotating: a numbered badge stays in the body, and a 1-note pill shows up in the composer"></td>
177
+ </tr></table>
178
+
179
+ "Annotate" attaches a comment to that text. The body keeps a **①②③ numbered badge**, and an "N notes" pill appears in the composer — open it to read, edit or delete each comment, or `Quote it`.
180
+
181
+ On send it is assembled into a block like this (you can also hit `Quote it` yourself, in which case only your own words go out):
182
+
183
+ ```
184
+ Note 1:
185
+ > The panel starts at y=0, but the top bar's z-index is 45
186
+
187
+ This needs to be one sentence shorter
188
+ ```
189
+
190
+ Notes are **local anchors**: they locate themselves by "quoted text + surrounding context", so badges still find their place after the body reflows or a stream appends more text. They live in this browser's `localStorage`, isolated per session — never on the server, never in the cloud, invisible from another device.
191
+
192
+ **Line references in files** are the other road: select lines in the preview (`Shift+click` for a range, `Ctrl/Cmd+click` to add, right-click for the line menu) and "Add to conversation" writes a **path plus line numbers** such as `@web/src/App.tsx:120-138`, leaving the agent to read it.
193
+
194
+ ---
195
+
196
+ ## Side chat: ask one question and go
197
+
198
+ ![The "side chat" on the right is a channel of its own: never saved, while the main conversation keeps running](docs/screenshots/13-tempchat.png)
199
+
200
+ The `Temp session` button in the top bar (or the first card on the right pane's landing page) opens another conversation **in the right pane**:
201
+
202
+ - **Not persisted**: it lives in memory, dies with the tab, never enters the sidebar and leaves no file;
203
+ - the main conversation keeps running; the two don't interrupt each other;
204
+ - to keep it, hit `Save as a regular chat` — only then is a session file written (history the ephemeral chat never had is preserved too);
205
+ - you can have several open at once, each on its own channel and its own tab.
206
+
207
+ > This depends on the engine having an in-memory session: pi supports it; a Codex thread already lives in Codex's own store, so there is no "save" button. It is not "a new session in a different skin", and it is not a subagent — **an ephemeral chat is a window you opened, a subagent is a subtask the agent dispatched**.
208
+
209
+ ---
210
+
211
+ ## Files, diffs, git, search
212
+
213
+ The files area sits at the bottom of the sidebar and also works as a tab in the right pane. **The web side is read-only**: you can look, compare, reference and search; editing files in place and saving them is not this layer's job — give that to the agent's tools or the terminal, and use the diff here to review it.
214
+
215
+ | Capability | Notes |
216
+ |---|---|
217
+ | Directory tree | Switchable root (follow the session / pick a project), lazy loaded, at most 500 entries per directory, `node_modules` / `.git` / `dist` hidden by default, "show hidden files" reveals `.env` and friends |
218
+ | Search by file name | Matches names only, never reads contents, 250 ms debounce, at most 200 hits |
219
+ | Preview | markdown (tables / code highlighting / mermaid), source with line numbers, images, PDF, audio and video streams; multiple tabs, drag to reorder, right-click to close left / right / all, and it can be spread over the full width |
220
+ | Line references | Select lines → "Add to conversation" writes `@path:line`; a text selection can also be "copy selected text" |
221
+ | Reveal in Finder | macOS `open -R`, Windows `explorer.exe /select,`, Linux opens the parent directory |
222
+ | Uncommitted changes | Status dots in the file tree, plus `M` / `U` / `D` after the filename |
223
+
224
+ ### Diff
225
+
226
+ ![The diff view: against HEAD, a `+6 −1` summary plus line-level red/green](docs/screenshots/03-diff.png)
227
+
228
+ The "diff" toggle at the top of the preview is a comparison against `HEAD`: a `+285 −78` summary, line-level red/green, and a switch between "changes only" and the full file. Coming in from a changed-files chip lands directly on the diff.
229
+
230
+ ### git
231
+
232
+ The branch chip at the top of the files area lists local branches and switches them (a dirty working tree asks first). It only shells out to `git` for reads and branch switches — it never commits. Committing stays with the agent, or with you in a terminal.
233
+
234
+ ### Content search
235
+
236
+ "Search file contents" in the toolbar is a full-text search: add a **path mask** (such as `web/src/**`) to narrow it, results show `file:line` plus a snippet of the source, and clicking one jumps to that line. When there are too many hits it truncates at the cap and says so.
237
+
238
+ ---
239
+
240
+ ## Terminal
241
+
242
+ ![The right-pane terminal is a real PTY: zsh, colors, git output, and a cwd that matches the session](docs/screenshots/04-terminal.png)
243
+
244
+ The terminal in the right pane is a **real PTY** (`node-pty` + xterm.js): vim / top / Ctrl-C / colors / line editing all behave, the cwd matches the session's project, and you can pass one initial command (the upgrade flow uses exactly that).
245
+
246
+ Reloading the page does not restore a terminal session (the PTY exits with the page); switching tabs does not break it. On Linux `node-pty` has to be compiled in place, and when the tools are missing the UI says exactly what to install.
247
+
248
+ ### Built-in web page
249
+
250
+ The right pane also opens web pages: type a URL and view it in an iframe, with requests going through **a local proxy** (`/web/p/<url>`) — it fetches the document and strips the `X-Frame-Options` / CSP framing restrictions, so sites like Baidu open too. The proxy has boundaries: HTML/CSS documents only, **no cookies in and none out**, a 12 MB upstream cap, and an iframe sandbox without `allow-same-origin`. For sites that need a login or heavy JS, hit `⧉` to jump to the system browser.
251
+
252
+ ---
253
+
254
+ ## Engines: each runs its own native loop
255
+
256
+ The engines are not "the same prompt in different costumes" — each is that vendor's own agent loop:
257
+
258
+ | Engine | How it's wired | Notes |
259
+ |---|---|---|
260
+ | **pi** (default) | Native SDK | The full plugin / skill ecosystem, lazy tool loading, the approval gate, subagents, steering; models and providers are managed by this workbench |
261
+ | **Codex** | app-server (JSON-RPC) | Its own loop and sandbox; sessions are shared with Codex Desktop / CLI; approvals are command- and file-level |
262
+ | **DeepSeek Harness** | ACP | Model and thinking level are switchable; permissions confirmed one by one |
263
+ | **opencode** | ACP | Its own tools / MCP / plugin ecosystem; sessions are shared with the opencode CLI / TUI; approvals follow opencode's own `permission` config |
264
+ | **Claude Code** | ACP (the `claude-code-acp` adapter) | Switchable models, per-call tool confirmation; sessions are shared with the `claude` CLI; this ACP surface exposes neither thinking levels nor subagents |
265
+ | **fake** | Built-in scripted engine | Zero tokens, only for exercising the protocol / tools / approval flow (not in the picker by default) |
266
+
267
+ The differences (the capability matrix in `server/engine/registry.ts`, which the UI uses to hide buttons):
268
+
269
+ | Capability | pi | codex | dsh | opencode | claude |
270
+ |---|:-:|:-:|:-:|:-:|:-:|
271
+ | Approvals | ✅ | ✅ | ✅ | per config | ✅ |
272
+ | Model / thinking level | ✅ | ✅ | ✅ | ✅ | model only / no levels |
273
+ | Resume past sessions | ✅ | ✅ | ✅ | ✅ | ✅ |
274
+ | Steering | ✅ | — | — | — | — |
275
+ | Subagent panel | ✅ | — | — | — | — |
276
+ | Workbench-managed providers | ✅ | — | — | — | — |
277
+ | Side chat (in memory) | ✅ | — | — | — | — |
278
+
279
+ **The models / plugins / MCP panels follow the active engine**: switch to Codex and the panels read Codex's own data (`model/list`, `plugin/list`, `config/read`); claude reads `~/.claude.json` and `~/.claude/settings.json`; opencode reads `opencode.json`. A panel that has nothing wired says so instead of borrowing pi's config.
280
+
281
+ Engines are switched in the **bottom status bar** (not the top bar), and every session remembers its own engine, model and thinking level.
282
+
283
+ ---
284
+
285
+ ## Models and providers
286
+
287
+ ![The models panel: the providers with a key or a signed-in subscription on the left, and that provider's endpoint, API shape and model allowlist on the right](docs/screenshots/05-models.png)
288
+
289
+ - **Subscriptions**: OAuth login (9 providers), usable right after signing in — no key to copy by hand.
290
+ - **Official built-ins**: the ones pi's catalog carries models for — **paste one key and it works**; endpoints and model tables come from the catalog.
291
+ - **Bring your own**: change the API shape (openai-completions / responses / anthropic-messages / codex / typesafe), the base URL and custom headers, and add models one by one.
292
+ - Tick models individually (only ticked ones are saved), batch-test connectivity, pull the list from `/models`, and save the ticked set as the allowlist.
293
+
294
+ **Keys never leave the server**: the API returns only `hasKey` and the last 4 digits; writes are serialized inside the process so concurrent edits can't corrupt a file.
295
+
296
+ The truth is spread across `~/.pi/agent/models.json` (the provider catalog), `models-store.json` (the legacy location) and `auth.json` (`api_key` or OAuth credentials), with the allowlist in `settings.json.enabledModels`.
297
+
298
+ ---
299
+
300
+ ## Skills
301
+
302
+ ![The skills panel: installed / enabled / disabled on the left, this skill's SKILL.md summary and its directory files on the right](docs/screenshots/06-skills.png)
303
+
304
+ Reads `~/.agents/skills/<dir>/SKILL.md`; the list parses frontmatter only (no yaml dependency). **Enabling or disabling means renaming `SKILL.md` to `.SKILL.md.disabled`** — there is no second state file, so what you see in the CLI agrees with what you see here.
305
+
306
+ **Skill Hub**: search by category plus one-click install (200k+ index); it can also install a specific `skills/<name>` from a Git repo, or create one by hand.
307
+
308
+ ---
309
+
310
+ ## MCP
311
+
312
+ ![The MCP panel: global and project configs, enable/disable and exposure, test connection, OAuth](docs/screenshots/07-mcp.png)
313
+
314
+ Reads and writes two config files: `~/.pi/agent/mcp.json` (global) and `<workspace>/.pi/mcp.json` (project), where **a project entry with the same name overrides the global one**, and writes preserve indentation and CRLF.
315
+
316
+ - exposure has four levels: **codemode (default) / deferred / direct / hidden**;
317
+ - **Test connection**: a real handshake plus `tools/list`, then disconnect; it reports the connection state and the tool count;
318
+ - OAuth login, pick a server from a marketplace, paste a command / URL / JSON and let it be parsed;
319
+ - **the config is the truth**: pi connects at session start, so edits apply to **new sessions**.
320
+
321
+ ---
322
+
323
+ ## Plugins
324
+
325
+ ![The plugins panel: the four states of a pi package, and disabling per package](docs/screenshots/09-plugins.png)
326
+
327
+ Plugins are pi packages: the `packages` entry in `settings.json` (npm / git / local directory) plus the loose `~/.pi/agent/extensions/` and `<ws>/.pi/extensions/`.
328
+
329
+ State comes from the pi SDK's `resolve()` (**querying never triggers `npm install`**), with four states `loaded / installed / missing / disabled`; disabling per package writes `autoload:false` and deletes nothing.
330
+
331
+ ---
332
+
333
+ ## Subagents: run many, manage each
334
+
335
+ ![The subagents panel: built-in templates, default concurrency, the master switch](docs/screenshots/08-subagents.png)
336
+
337
+ Once the main agent has the `Agent` tool it can run several subagents in parallel, and each one is **a real session** (its own context, session file and tool allowlist).
338
+
339
+ - **Watch**: the subagent card strip above the composer — status, duration, tool count, tokens, cost. "View result" expands the raw result and the session file path in place, and any single run can be stopped. The heading gives the at-a-glance count (`2 running` / `8 finished`).
340
+ - **Manage**: the top-bar "subagents" panel manages **templates** (built in: explore / general-purpose / plan, each disableable; you can also create, edit and delete your own): `name / display_name / description / tools / model / thinking / max_turns`. They land in `~/.pi/agent/agents/*.md`, in the same format as pi's agent files — readable, editable, git-friendly.
341
+ - **Concurrency**: 1–12 (default 4); anything beyond that queues. Turn the master switch off and the model no longer sees the `Agent` tool.
342
+ - **Isolation**: subagents load no skills / plugins / themes / context files by default (fast and predictable); a subagent that doesn't pin a model keeps using the parent session's model.
343
+
344
+ A subagent's session file is archived next to the parent session (`<parent session dir>/<parent name>/subagents/`) and never shows up in the sidebar's project list.
345
+
346
+ ---
347
+
348
+ ## Push and voice
349
+
350
+ <table><tr>
351
+ <td width="50%"><img src="docs/screenshots/11-push.png" alt="Push: local push state, target devices, test push"></td>
352
+ <td width="50%"><img src="docs/screenshots/10-voice.png" alt="Voice: four event sounds plus local TTS"></td>
353
+ </tr></table>
354
+
355
+ **Push**: Web Push (VAPID) subscriptions, one notification per finished turn — title is the project, body is the session, with a ❌ / ⏹ prefix for failures and interrupts. Multiple devices, a test push, and a one-click clear-all. Needs https or localhost.
356
+
357
+ **Voice**: four event sounds (start / finish / error / waiting for approval) with preview and adjustable volume; local TTS reads the final reply using the browser's built-in voices, with adjustable rate and voice, and never touches the network.
358
+
359
+ ---
360
+
361
+ ## Settings
362
+
363
+ ![Settings → Appearance: three font sizes, content width in 4 steps, 6 palettes](docs/screenshots/12-settings.png)
364
+
365
+ The top bar is the entry point for every panel, and **each entry can be hidden in Settings → Interface** (settings and the split toggle are exempt — they're the only way back to the others). The sidebar and the right pane both drag wider and collapse, and their widths are remembered locally in `localStorage`.
366
+
367
+ The "settings" button opens five pages:
368
+
369
+ | Page | Contents |
370
+ |---|---|
371
+ | **Interface** | Which top-bar entries show (text and icon ticked separately), which status-bar chunks show (queue / working / context usage), whether cost shows in the conversation, which blocks sit above the composer (templates / thinking / quick commands), and whether thinking blocks and tool cards start expanded |
372
+ | **General** | The text of your quick phrases and the default thinking level — saved server-side, identical on every device |
373
+ | **Appearance** | Three font sizes (chat body / sidebar project names / sidebar session names, slider 2–20px), content width in 4 steps (720 / 900 / 1100 / full), 6 palettes (bright white, warm paper, mist teal, Tokyo night, mocha, nord), and the top-bar name and logo (hideable, or replaced with your own) |
374
+ | **Language** | Chinese / English, applied immediately |
375
+ | **Shortcuts** | 11 actions, rebindable, clearable and restorable to defaults, plus a cheat sheet |
376
+
377
+ Appearance, interface and language preferences stay on the device only (`localStorage`, with the `agent-web.` prefix) — one copy per phone, tablet and desktop. Only the quick phrases in "General" are shared across devices.
378
+
379
+ ---
380
+
381
+ ## Mobile
382
+
383
+ <table><tr>
384
+ <td width="34%"><img src="docs/screenshots/16-mobile.png" alt="Mobile single column: icon-only top-bar entries, 18px composer"></td>
385
+ <td width="34%"><img src="docs/screenshots/17-mobile-drawer.png" alt="On a phone the project sidebar is an overlay drawer"></td>
386
+ </tr></table>
387
+
388
+ On narrow screens (mobile UA or ≤400px) the layout collapses to a single column:
389
+
390
+ - the sidebar becomes an overlay drawer (`clamp(260px, 76vw, 340px)`, tap the scrim to close, closes on its own after you pick a session);
391
+ - the top bar wraps, keeps icons only, and scrolls horizontally;
392
+ - the right-pane workspace becomes a full-screen second page that starts below the top bar using `100dvh` (dodging the iOS toolbars);
393
+ - the composer is 18px so iOS doesn't zoom on focus; the model menu becomes a bottom sheet;
394
+ - the status bar scrolls horizontally, and the context-usage popover becomes a full-width sheet.
395
+
396
+ ---
397
+
398
+ ## Sessions: pin, archive, fork, move project
399
+
400
+ The sidebar groups sessions into "projects" by directory:
401
+
402
+ | Action | Behaviour |
403
+ |---|---|
404
+ | Pin | Lifts a session or a project to the top |
405
+ | Rename | For pi: append `session_info.name` to the end of the jsonl |
406
+ | Archive | Into "archived", undoable |
407
+ | Delete | Renames to `.deleted-<timestamp>` (the engine's native delete is preferred when it has one) — **the file is still on disk** |
408
+ | Fork | Derive a new session from one message (the title becomes `Branch · …`), the original untouched |
409
+ | Move project | Drag a session row onto another project; the id and history stay, only the `cwd` in the file header changes and the directory is moved |
410
+
411
+ Sorting is a deliberate choice: **newest-created first inside a group** — a new session lands on top, and updating an old one doesn't move it (sort by last activity instead and a single message in an old session shoots it to the top, dragging the whole list along).
412
+
413
+ ---
414
+
415
+ ## Shortcuts and slash commands
416
+
417
+ **Every shortcut** is rebindable in Settings → Shortcuts (a binding must include `Mod`/`Alt`; bare letters are rejected). On macOS `Mod` is ⌘, elsewhere it's Ctrl.
418
+
419
+ | Action | Default | Action | Default |
420
+ |---|---|---|---|
421
+ | New session | `Mod+K` | Open right panel | `Mod+Alt+O` |
422
+ | New project | `Mod+M` | Close right panel | `Mod+Alt+W` |
423
+ | Temp session | `Mod+Shift+K` | Toggle left sidebar | `Mod+Alt+L` |
424
+ | Settings | `Mod+Alt+S` | Files | `Mod+Alt+F` |
425
+ | New terminal | `Mod+Alt+T` | Search file contents | `Mod+Shift+F` |
426
+ | Shortcut cheat sheet | `Mod+/` | | |
427
+
428
+ **Slash commands** pop up when you type `/` in the composer. There are two kinds — `local` ones the workbench runs itself, and `to the agent` ones handed to the engine verbatim as a message:
429
+
430
+ | Command | Kind | What it does |
431
+ |---|---|---|
432
+ | `/new [first message]` | local | New conversation, optionally with its first message |
433
+ | `/name <name>` | local | Rename the current session |
434
+ | `/model <name>` | local | Switch model (fuzzy match on id or display name) |
435
+ | `/thinking <level>` | local | Set the thinking level (off / low / … / max) |
436
+ | `/copy` | local | Copy the last assistant message |
437
+ | `/session` | local | Message count / tokens / cost for the session |
438
+ | `/resume` | local | Refresh the session list (sessions another terminal just opened) |
439
+ | `/skill <skill name>` | to the agent | Use a skill (the panel lists the installed ones) |
440
+ | `/compact [note]` | to the agent | Compact the context |
441
+ | `/plan [on\|off]` | to the agent | Turn plan mode on or off |
442
+ | `/cwd <path>` | to the agent | Change the working directory |
443
+
444
+ ---
445
+
446
+ ## Architecture: SSE + RPC, no WebSocket
447
+
448
+ ```
449
+ browser ──GET /api/events (SSE)──▶ server one snapshot first, deltas afterwards
450
+ ──POST /api/rpc (JSON)──▶ ClientRequest → { reply } consumed in place
451
+ ```
452
+
453
+ - **Downstream**: one complete snapshot first, then deltas only. Text arrives as `message_delta` chunks appended block by block; structural changes (tool cards, errors, state) push a fresh snapshot, coalesced in a 60 ms window — snapshots are droppable, events are not. SSE heartbeats every 25 s.
454
+ - **Upstream**: `send_message`, `interrupt`, `approve`, `new_chat` (optionally with `ephemeral`), `switch_conversation`, `set_engine` / `set_model` / `set_thinking_level` / `set_approval_mode`, `persist_conversation`, `close_ephemeral`, `fork_session`, `move_session`, `cancel_queued`, `rename_session` and more.
455
+ - **The protocol has a single source** in `server/protocol.ts`; the frontend reuses its types, so one definition serves both ends.
456
+ - **The snapshot is the only source of truth**: `store.ts` uses `useSyncExternalStore` and replaces everything when a snapshot arrives. Locally only optimistic state survives (`preview` / `draft` / `pendingActive`).
457
+ - **Each client sees its own session** (ADR-0033): one server, two devices, each parked on a different conversation; bulk data such as the session list is only sent to a client when that client needs it.
458
+
459
+ Process model: `cli.ts` parses the flags → `session/lock.ts` grabs `<dataDir>/server.lock` (a live pid refuses to start, a dead pid means taking over a stale lock) → `runtime.init()` → `listen`. `SIGINT` / `SIGTERM` / `/api/shutdown` all go through the same graceful exit (flush, disconnect engines, release the lock).
460
+
461
+ ---
462
+
463
+ ## Where data lives
464
+
465
+ | Content | Location |
466
+ |---|---|
467
+ | pi sessions | `~/.pi/agent/sessions/<encoded cwd>/<ISO>_<uuid>.jsonl` (first line `{type:"session",id,timestamp,cwd}`) |
468
+ | Codex sessions | Codex's own thread store (`thread/list \| resume \| delete`) |
469
+ | opencode / DSH / claude sessions | Their own data dirs (opencode lists per cwd with `session/list`; DSH reads `~/.dsh`; claude reads `~/.claude`) |
470
+ | Session titles | For pi, the first user message (reads only the first 60 lines); renaming appends `session_info.name` |
471
+ | Workbench state | `<dataDir>/settings.json`, `approval-rules.json`, `server.lock`, `logs/`, `uploads/`, `push-subscriptions.json`, `vapid-keys.json` |
472
+ | Skills / subagent templates / MCP | `~/.agents/skills/`, `~/.pi/agent/agents/`, `~/.pi/agent/mcp.json` |
473
+ | Local UI preferences | Browser `localStorage` (`agent-web.` prefix: theme, font sizes, widths, shortcuts, notes, tabs) |
474
+
475
+ ---
476
+
477
+ ## Security model
478
+
479
+ - Binds `127.0.0.1` by default and validates `Origin` / `Host` (including the `AGENT_WEB_ALLOWED_HOSTS` allowlist, the vite port and LAN addresses).
480
+ - Identity: a loopback peer **and** a 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.
481
+ - 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). Choosing "always allow" writes the rule into `approval-rules.json` (atomic write; a corrupt file counts as empty).
482
+ - When a turn ends, every pending approval for that session is cleared, so nothing hangs waiting for a human.
483
+ - Uploaded temp files and session caches live in the data directory, never in your project.
484
+ - The built-in web page's proxy carries no cookies, and its iframe sandbox omits `allow-same-origin` (otherwise remote JS could reach `localStorage` and the RPC endpoint).
485
+
486
+ > Exposing it remotely is an explicit act: `-H`, `-P` and `--allow-host` must all be present — miss one and it stays shut.
487
+
488
+ ---
489
+
490
+ ## Development
491
+
492
+ From the repo root, run `npm install` first, then:
493
+
494
+ ```bash
495
+ npm run dev # starts both processes with one command
496
+ ```
497
+
498
+ - Externally there is still a single port **25257** (Vite listens and proxies); the backend hides on internal **25258**, so dev and production use the same address.
499
+ - Frontend HMR via Vite; the backend auto-restarts through `tsx --watch`.
500
+ - Phone debugging: `npm run dev -- --host 0.0.0.0`.
501
+
502
+ | Command | Purpose |
503
+ |---|---|
504
+ | `npm run typecheck` | Two `tsc --noEmit` runs: server + web |
505
+ | `npm run lint` | oxlint over `server` / `web/src` / `scripts` |
506
+ | `npm run format` | Prettier across the repo (`format:check` only checks; `*.md` is deliberately skipped) |
507
+ | `npm run build` | Server `tsc` + frontend `vite build` into `web/dist` |
508
+ | `npm run icons` | Regenerate the PWA icons with playwright-core |
509
+
510
+ CI (`.github/workflows/ci.yml`): `npm ci` → typecheck → lint → test → build, on ubuntu + Node 22.
511
+
512
+ ---
513
+
514
+ ## Troubleshooting
515
+
516
+ > **Why `npm ci` and not `npm install`**: the direct dependencies are all very new, and `npm install` re-resolves the version ranges against the registry — if your mirror (corporate Nexus, npmmirror, …) hasn't synced those versions you get `npm error notarget`. `npm ci` uses the exact versions from the lockfile.
517
+
518
+ 1. `npm error notarget No matching version found` → the mirror is behind. Check `npm config get registry`, then fall back to the official one: `npm -g install oh-my-agent-web --registry=https://registry.npmjs.org/`.
519
+ 2. `EBADENGINE` / a Node version complaint at startup → you need Node ≥ 22.19 (check with `node -v`).
520
+ 3. `node-pty` fails to build (mostly on Linux) → install `python3` / `make` / `g++` before `npm -g install`, or let the one-line installer handle it with `--with-build-tools`.
521
+ 4. It won't start but `oh-my-agent-web 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`.
522
+ 5. Port already in use → `oh-my-agent-web -p 25258`, or run `oh-my-agent-web stop` first.
523
+ 6. The built-in web page is blank → that site needs a login or heavy scripts, and the proxy does not tunnel cookies; hit `⧉` to use the system browser.
524
+
525
+ Windows differences in shell resolution, process-tree teardown, path handling, permissions and CRLF are all centralised in three modules: `server/util/spawn-cli.ts` (PATH/PATHEXT, `.cmd` via `cmd.exe`, `killTree`), `server/util/paths.ts` and `web/src/path-utils.ts` (separators and absolute paths), and `server/util/file-mode.ts` (`icacls` on Windows). Read those headers before touching cross-platform code.
526
+
527
+ ---
528
+
529
+ ## License
530
+
531
+ MIT