oh-my-agent-web 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (250) hide show
  1. package/README.md +86 -447
  2. package/dist/server/approval/read-only.js +107 -0
  3. package/dist/server/approval/rules.js +85 -0
  4. package/dist/server/approval/scope.js +150 -0
  5. package/dist/server/brand.js +2 -0
  6. package/dist/server/cli-config.js +52 -0
  7. package/dist/server/cli-info.js +101 -0
  8. package/dist/server/cli.js +304 -0
  9. package/dist/server/engine/builtin.js +61 -0
  10. package/dist/server/engine/catalog.js +8 -0
  11. package/dist/server/engine/codex-approvals.js +45 -0
  12. package/dist/server/engine/codex-map.js +298 -0
  13. package/dist/server/engine/codex-sessions.js +159 -0
  14. package/dist/server/engine/codex-transport.js +49 -0
  15. package/dist/server/engine/codex.js +314 -0
  16. package/dist/server/engine/dsh-history.js +195 -0
  17. package/dist/server/engine/dsh-log.js +245 -0
  18. package/dist/server/engine/dsh-map.js +221 -0
  19. package/dist/server/engine/dsh-sessions.js +207 -0
  20. package/dist/server/engine/dsh-transport.js +37 -0
  21. package/dist/server/engine/dsh.js +284 -0
  22. package/dist/server/engine/fake.js +231 -0
  23. package/dist/server/engine/jsonrpc-stdio.js +241 -0
  24. package/dist/server/engine/model-registry-reload.js +115 -0
  25. package/dist/server/engine/pi-events.js +148 -0
  26. package/dist/server/engine/pi-rename.js +14 -0
  27. package/dist/server/engine/pi-sdk.js +343 -0
  28. package/dist/server/engine/pi-session-model.js +23 -0
  29. package/dist/server/engine/pi-thinking.js +34 -0
  30. package/dist/server/engine/pi-transcript.js +225 -0
  31. package/dist/server/engine/pi-version.js +11 -0
  32. package/dist/server/engine/port.js +1 -0
  33. package/dist/server/engine/registry.js +47 -0
  34. package/dist/server/engine/scratch.js +13 -0
  35. package/dist/server/engine/suggestion-guidance.js +9 -0
  36. package/dist/server/engine/switchable.js +22 -0
  37. package/dist/server/engine/wiring.js +107 -0
  38. package/dist/server/files/dir-routes.js +40 -0
  39. package/dist/server/files/file-search.js +63 -0
  40. package/dist/server/files/file-service.js +232 -0
  41. package/dist/server/files/files-routes.js +182 -0
  42. package/dist/server/files/git-info.js +186 -0
  43. package/dist/server/http/auth-routes.js +99 -0
  44. package/dist/server/http/auth.js +191 -0
  45. package/dist/server/http/aux-routes.js +24 -0
  46. package/dist/server/http/compress.js +75 -0
  47. package/dist/server/http/health-and-static.js +33 -0
  48. package/dist/server/http/live-routes.js +113 -0
  49. package/dist/server/http/login-page.js +200 -0
  50. package/dist/server/index.js +342 -520
  51. package/dist/server/markers/actions.js +262 -0
  52. package/dist/server/protocol-parse.js +201 -0
  53. package/dist/server/protocol-settings.js +1 -0
  54. package/dist/server/protocol.js +6 -0
  55. package/dist/server/providers/catalog-store.js +85 -0
  56. package/dist/server/providers/catalog-writes.js +197 -0
  57. package/dist/server/providers/catalog.js +77 -0
  58. package/dist/server/providers/enabled-models.js +118 -0
  59. package/dist/server/providers/import-models.js +69 -0
  60. package/dist/server/providers/import-routes.js +136 -0
  61. package/dist/server/providers/model-test.js +52 -0
  62. package/dist/server/providers/probe.js +64 -0
  63. package/dist/server/providers/provider-handlers.js +203 -0
  64. package/dist/server/providers/provider-store.js +327 -0
  65. package/dist/server/providers/request-headers.js +7 -0
  66. package/dist/server/providers/validate.js +241 -0
  67. package/dist/server/push/push-routes.js +114 -0
  68. package/dist/server/push/push.js +120 -0
  69. package/dist/server/session/approval-bridge.js +103 -0
  70. package/dist/server/session/attachment-resolve.js +21 -0
  71. package/dist/server/session/client-view.js +82 -0
  72. package/dist/server/session/conversation-create.js +65 -0
  73. package/dist/server/session/delete-session.js +84 -0
  74. package/dist/server/session/engine-switch.js +108 -0
  75. package/dist/server/session/lock.js +82 -0
  76. package/dist/server/session/model-controller.js +111 -0
  77. package/dist/server/session/notices.js +31 -0
  78. package/dist/server/session/pi-opener.js +123 -0
  79. package/dist/server/session/pi-refresh.js +51 -0
  80. package/dist/server/session/pi-sessions-provider.js +46 -0
  81. package/dist/server/session/pi-sessions.js +272 -0
  82. package/dist/server/session/refresh-actions.js +42 -0
  83. package/dist/server/session/rename-session.js +23 -0
  84. package/dist/server/session/runtime-services.js +28 -0
  85. package/dist/server/session/runtime-types.js +1 -0
  86. package/dist/server/session/runtime.js +358 -0
  87. package/dist/server/session/session-stats.js +88 -0
  88. package/dist/server/session/settings.js +367 -0
  89. package/dist/server/session/snapshot-for.js +7 -0
  90. package/dist/server/session/stats-refresher.js +50 -0
  91. package/dist/server/session/switch-conversation.js +86 -0
  92. package/dist/server/session/throttle.js +14 -0
  93. package/dist/server/session/turn-events.js +126 -0
  94. package/dist/server/session/turn-finish.js +79 -0
  95. package/dist/server/session/turn-markers.js +26 -0
  96. package/dist/server/session/turn-queue.js +111 -0
  97. package/dist/server/session/turn-send.js +88 -0
  98. package/dist/server/session/turn-watchdog.js +77 -0
  99. package/dist/server/sessions/session-routes.js +17 -0
  100. package/dist/server/skills/skill-routes.js +28 -0
  101. package/dist/server/skills/skill-store.js +134 -0
  102. package/dist/server/snapshot/fan-out.js +10 -0
  103. package/dist/server/snapshot/messages.js +75 -0
  104. package/dist/server/snapshot/sender.js +62 -0
  105. package/dist/server/snapshot/state.js +193 -0
  106. package/dist/server/terminal/terminal-routes.js +176 -0
  107. package/dist/server/terminal/terminal-session.js +140 -0
  108. package/dist/server/uploads/upload-routes.js +64 -0
  109. package/dist/server/uploads/upload-store.js +115 -0
  110. package/dist/server/util/data-dir.js +36 -0
  111. package/dist/server/util/env.js +140 -0
  112. package/dist/server/util/ids.js +28 -0
  113. package/dist/server/util/log-file.js +67 -0
  114. package/dist/server/util/log.js +52 -0
  115. package/dist/server/util/origin.js +75 -0
  116. package/dist/server/util/paths.js +60 -0
  117. package/dist/server/util/pricing-index.js +121 -0
  118. package/dist/server/util/pricing.js +214 -0
  119. package/dist/server/util/startup.js +34 -0
  120. package/dist/server/util/upstream-version.js +140 -0
  121. package/dist/server/util/usage.js +19 -0
  122. package/dist/server/util/version.js +50 -0
  123. package/dist/server/ws/handle-message.js +95 -0
  124. package/package.json +49 -63
  125. package/web/dist/apple-touch-icon-precomposed.png +0 -0
  126. package/web/dist/apple-touch-icon.png +0 -0
  127. package/web/dist/assets/abnfDiagram-WEYOIA3C-NLp09iEC.js +1 -0
  128. package/web/dist/assets/arc-DviL9o3c.js +1 -0
  129. package/web/dist/assets/architecture-WOLXFQ4H-fjsM_Sy3.js +1 -0
  130. package/web/dist/assets/architectureDiagram-ZHVYKT53-Cn3B4TE8.js +36 -0
  131. package/web/dist/assets/array-BifhSqXX.js +1 -0
  132. package/web/dist/assets/blockDiagram-RJAE7QA3-CIuvxWvi.js +140 -0
  133. package/web/dist/assets/c4Diagram-XDPPPE54-DvdKmEpF.js +38 -0
  134. package/web/dist/assets/channel-C3AQ6nAs.js +1 -0
  135. package/web/dist/assets/chunk-2E7WHVMD-HNNASGCS.js +88 -0
  136. package/web/dist/assets/chunk-2Q5K7J3B-C1jixKkw.js +1 -0
  137. package/web/dist/assets/chunk-4EMNKR2T-Cg-eRwBE.js +1 -0
  138. package/web/dist/assets/chunk-55XCU76K-BweiisZL.js +1 -0
  139. package/web/dist/assets/chunk-5VM5RSS4-ZNzvKenW.js +15 -0
  140. package/web/dist/assets/chunk-7S6XSTFO-BCzIiP-6.js +2 -0
  141. package/web/dist/assets/chunk-AQDTSKZB-Dl0NRFuU.js +72 -0
  142. package/web/dist/assets/chunk-DSNLSHJZ-zhHCjjN9.js +129 -0
  143. package/web/dist/assets/chunk-DUW6YSOI-Dgx8z5s3.js +1 -0
  144. package/web/dist/assets/chunk-HAGFOTED-BDQqU2EH.js +62 -0
  145. package/web/dist/assets/chunk-HNE4Q36P-B-qRzMjX.js +1 -0
  146. package/web/dist/assets/chunk-J5ZVWO5B-oDCd-gWO.js +1 -0
  147. package/web/dist/assets/chunk-JWPE2WC7-DVXcaiue.js +1 -0
  148. package/web/dist/assets/chunk-NGNAAXSQ-C2Wy9Xmz.js +136 -0
  149. package/web/dist/assets/chunk-NQOKRVIF-CNcvhMn_.js +213 -0
  150. package/web/dist/assets/chunk-UHW7PFBP-Dwr8LUzr.js +1 -0
  151. package/web/dist/assets/chunk-VQ5W62QI-O8sN6jJu.js +1 -0
  152. package/web/dist/assets/chunk-WQQL4CDK-B6-59Zg2.js +10 -0
  153. package/web/dist/assets/chunk-XXDRQBXY-DvSbeUlZ.js +1 -0
  154. package/web/dist/assets/chunk-Y2CYZVJY-DsF7k-Jl.js +1 -0
  155. package/web/dist/assets/chunk-YZO67HFG-BXpKYKsw.js +1 -0
  156. package/web/dist/assets/chunk-ZAUX2LTX-B1Z5VSkz.js +1 -0
  157. package/web/dist/assets/chunk-ZCHMQSOR-h_5mBLIA.js +2 -0
  158. package/web/dist/assets/classDiagram-v2-4MYWR3UA-Dr6JnaaV.js +217 -0
  159. package/web/dist/assets/cose-bilkent-JH36ORCC-36ShkR7R.js +1 -0
  160. package/web/dist/assets/cynefin-EF2NZ3EQ-Dg6bI7pC.js +1 -0
  161. package/web/dist/assets/cynefinDiagram-WF24UDRP-B0YHpBlR.js +62 -0
  162. package/web/dist/assets/cytoscape.esm-BegBNzOV.js +321 -0
  163. package/web/dist/assets/dagre-NK4GIZVX-Cx3mn7YS.js +4 -0
  164. package/web/dist/assets/defaultLocale-BFoDCU3G.js +1 -0
  165. package/web/dist/assets/diagram-CBK3MWTC-l8aZG_Bm.js +24 -0
  166. package/web/dist/assets/diagram-I5XIIV2D-Bd5f14_h.js +24 -0
  167. package/web/dist/assets/diagram-ODIL2UCW-hBsxCYUj.js +30 -0
  168. package/web/dist/assets/diagram-PFBEJUXE-BgpIBUYl.js +3 -0
  169. package/web/dist/assets/diagram-RJA3I4VV-CDU1gUVD.js +41 -0
  170. package/web/dist/assets/diagram-TYUNFSNR-Iuxh7Tqf.js +200 -0
  171. package/web/dist/assets/dist-C86cKTuE.js +1 -0
  172. package/web/dist/assets/ebnfDiagram-V4P3TTPT-Cms0HFKh.js +1 -0
  173. package/web/dist/assets/elk-QONTBCTQ-B7yEy0PQ.js +27 -0
  174. package/web/dist/assets/erDiagram-KYQIGQAA-CL48j4aU.js +99 -0
  175. package/web/dist/assets/eventmodeling-K75KTNOO-CFvkaejh.js +1 -0
  176. package/web/dist/assets/flowDiagram-IUGLLWBU-6UyKXpqG.js +1 -0
  177. package/web/dist/assets/ganttDiagram-R7GPNTJY-vdMr-0ZV.js +292 -0
  178. package/web/dist/assets/gitGraph-VSP46ZUC-2z85Wuwo.js +1 -0
  179. package/web/dist/assets/gitGraphDiagram-PDYL7XHY-BY4GPiqC.js +106 -0
  180. package/web/dist/assets/graphlib-DS17s2tU.js +1 -0
  181. package/web/dist/assets/index-Bjn56a2i.js +76 -0
  182. package/web/dist/assets/index-Drp6e5iU.css +1 -0
  183. package/web/dist/assets/info-OHQRW6UA-ECzkYTx-.js +1 -0
  184. package/web/dist/assets/infoDiagram-MVDRKAX5-DDk5EAeb.js +2 -0
  185. package/web/dist/assets/init-C-OQMol4.js +1 -0
  186. package/web/dist/assets/ishikawaDiagram-HPEHV2GE-9yPH4J94.js +70 -0
  187. package/web/dist/assets/journeyDiagram-BOSHW7O7-BPTIap3l.js +139 -0
  188. package/web/dist/assets/kanban-definition-FNSA4HC5-BbADHrA8.js +89 -0
  189. package/web/dist/assets/katex-B_JcIwqj.js +257 -0
  190. package/web/dist/assets/line-CHV9_4lL.js +1 -0
  191. package/web/dist/assets/linear-C-eZsBTv.js +1 -0
  192. package/web/dist/assets/mermaid-parser.core-BiAhX1l1.js +7 -0
  193. package/web/dist/assets/mermaid.core-BxP_A_zj.js +44 -0
  194. package/web/dist/assets/mindmap-definition-6OY57UG3-BMWlit95.js +98 -0
  195. package/web/dist/assets/ordinal-BDEzSJ7C.js +1 -0
  196. package/web/dist/assets/packet-JDAUHWVQ-FVApuKOp.js +1 -0
  197. package/web/dist/assets/path-fybaL0A-.js +1 -0
  198. package/web/dist/assets/pegDiagram-ECIUJNBX-WjWJvDHM.js +1 -0
  199. package/web/dist/assets/pie-XZMESJXO-BGCZnvhp.js +1 -0
  200. package/web/dist/assets/pieDiagram-GNMPY74T-DJpAC_JC.js +39 -0
  201. package/web/dist/assets/quadrantDiagram-D57K4MC3-hxx5c7oq.js +7 -0
  202. package/web/dist/assets/radar-ABXABTNO-BU9Shc-O.js +1 -0
  203. package/web/dist/assets/railroad-I3PHUGI6-pWj8d-G4.js +1 -0
  204. package/web/dist/assets/railroad-abnf-LNEFI6M7-D7HZBTAj.js +1 -0
  205. package/web/dist/assets/railroad-ebnf-DWYD2UWJ-CKiXJSuM.js +1 -0
  206. package/web/dist/assets/railroad-peg-JR7BVNR7-DB3VJHgR.js +1 -0
  207. package/web/dist/assets/railroadDiagram-Y72NRBL7-Cev7Y65k.js +1 -0
  208. package/web/dist/assets/requirementDiagram-EQYSW5RA-CqbwMLD8.js +84 -0
  209. package/web/dist/assets/rough.esm-Dy-Kn_BL.js +1 -0
  210. package/web/dist/assets/sankeyDiagram-SY24JHO5-V2cyVi8q.js +40 -0
  211. package/web/dist/assets/sequenceDiagram-BLEHNHQU-By6NJOPM.js +169 -0
  212. package/web/dist/assets/sizeCapture-INFHLROL-3uHXrFqA.js +1 -0
  213. package/web/dist/assets/src-Da91fG3g.js +1 -0
  214. package/web/dist/assets/stateDiagram-v2-A6IESKWZ-BnPGX5UI.js +291 -0
  215. package/web/dist/assets/swimlanes-B3ENRKFQ-C58BpIpm.js +1 -0
  216. package/web/dist/assets/swimlanesDiagram-AYQRV4AK-RaivxSsc.js +8 -0
  217. package/web/dist/assets/timeline-definition-JXYKGLGB-Hgo1DhnS.js +120 -0
  218. package/web/dist/assets/treeView-D4JQ5SDB-DF0dfjqB.js +1 -0
  219. package/web/dist/assets/treemap-SAJKECNS-CSSM5FqB.js +1 -0
  220. package/web/dist/assets/usecaseDiagram-WPOLBNNX-BkBBD1NY.js +328 -0
  221. package/web/dist/assets/vennDiagram-Q3Y3IDCW-Bm28keX_.js +34 -0
  222. package/web/dist/assets/wardley-7MLQ67FV-By7KgEQX.js +1 -0
  223. package/web/dist/assets/wardleyDiagram-IVAIDKWA-oVtIrnGa.js +78 -0
  224. package/web/dist/assets/xychartDiagram-4URNHDU4-aI8FH4g2.js +7 -0
  225. package/web/dist/favicon-32.png +0 -0
  226. package/web/dist/favicon.ico +0 -0
  227. package/web/dist/favicon.svg +20 -8
  228. package/web/dist/icons/apple-touch-icon-180.png +0 -0
  229. package/web/dist/icons/icon-192.png +0 -0
  230. package/web/dist/icons/icon-512.png +0 -0
  231. package/web/dist/icons/icon-maskable-512.png +0 -0
  232. package/web/dist/index.html +21 -27
  233. package/web/dist/manifest.webmanifest +17 -0
  234. package/web/dist/maskable.svg +25 -0
  235. package/web/dist/sw.js +40 -0
  236. package/bin/oh-my-agent-web-ps.mjs +0 -203
  237. package/bin/oh-my-agent-web-ws.mjs +0 -593
  238. package/bin/oh-my-agent-web.mjs +0 -321
  239. package/bin/update-check.mjs +0 -142
  240. package/dist/server/codex-client.js +0 -310
  241. package/dist/server/codex-supervisor.js +0 -446
  242. package/dist/server/fs-service.js +0 -144
  243. package/dist/server/request-inspector.js +0 -458
  244. package/dist/shared/protocol.js +0 -112
  245. package/scripts/manage-server.mjs +0 -155
  246. package/scripts/omaw.mjs +0 -74
  247. package/shared/protocol.ts +0 -228
  248. package/web/dist/assets/index-B8-VzDf2.css +0 -1
  249. package/web/dist/assets/index-DeC2eiiq.js +0 -42
  250. package/web/dist/assets/markdown-CYXe6JZx.js +0 -55
@@ -1,310 +0,0 @@
1
- /**
2
- * CodexClient — WebSocket JSON-RPC client to the codex app-server.
3
- *
4
- * - 连接后立即 `initialize`(客户端信息 + experimentalApi),记录 userAgent /
5
- * codexHome / platformOs。
6
- * - socket 断开 / supervisor 重启后自动重连(指数退避),每次重连都重发 initialize。
7
- * - `request(method, params)` 用自增数字 id 关联响应;JSON-RPC error 以带 code 的
8
- * 对象 reject。
9
- * - server -> client 的通知(无 id)走 `notification` 事件;带 id 的请求(审批 /
10
- * user input / 动态工具调用)走 `serverRequest` 事件。
11
- * - 连接状态变化走 `state` 事件(index 借此刷新并广播 `status`)。
12
- *
13
- * 注意:codex 的报文可能不带 `jsonrpc` 字段,因此我们收发都兼容有无。
14
- */
15
- import { EventEmitter } from "node:events";
16
- import { WebSocket } from "ws";
17
- const RECONNECT_BASE_MS = 500;
18
- const RECONNECT_MAX_MS = 5_000;
19
- const INIT_TIMEOUT_MS = 20_000;
20
- const NOT_CONNECTED = { code: -32001, message: "codex app-server not connected" };
21
- function isRecord(value) {
22
- return typeof value === "object" && value !== null;
23
- }
24
- export class CodexClient extends EventEmitter {
25
- url;
26
- version;
27
- ws = null;
28
- connectPromise = null;
29
- manualClose = false;
30
- reconnectTimer = null;
31
- reconnectAttempts = 0;
32
- nextId = 1;
33
- pending = new Map();
34
- handshakeData = null;
35
- connState = { connected: false, error: null, since: null };
36
- constructor(url, version) {
37
- super();
38
- this.url = url;
39
- this.version = version;
40
- }
41
- state() {
42
- return { ...this.connState };
43
- }
44
- handshake() {
45
- return this.handshakeData;
46
- }
47
- isReady() {
48
- return this.connState.connected && this.ws !== null && this.ws.readyState === WebSocket.OPEN;
49
- }
50
- /**
51
- * Resolve once the client is ready, or after `timeoutMs` (returns `false`).
52
- *
53
- * The browser can attach while the app-server is still booting, and its very
54
- * first requests (`model/list`, `thread/list`, …) would otherwise fail with
55
- * `-32001`. Waiting here removes that startup race for every client instead of
56
- * pushing the problem into each one.
57
- */
58
- async waitUntilReady(timeoutMs) {
59
- if (this.isReady())
60
- return true;
61
- // Nudge a connection along in case nothing else is driving it yet.
62
- void this.connect();
63
- return new Promise((resolve) => {
64
- let settled = false;
65
- let timer = null;
66
- const finish = (ok) => {
67
- if (settled)
68
- return;
69
- settled = true;
70
- if (timer)
71
- clearTimeout(timer);
72
- this.off("state", onState);
73
- resolve(ok);
74
- };
75
- const onState = () => {
76
- if (this.isReady())
77
- finish(true);
78
- };
79
- this.on("state", onState);
80
- timer = setTimeout(() => finish(this.isReady()), timeoutMs);
81
- });
82
- }
83
- setState(patch) {
84
- this.connState = { ...this.connState, ...patch };
85
- this.emit("state", this.state());
86
- }
87
- /** 建立连接;已连接 / 正在连接时幂等。 */
88
- connect() {
89
- if (this.isReady())
90
- return Promise.resolve();
91
- if (this.connectPromise)
92
- return this.connectPromise;
93
- this.manualClose = false;
94
- this.connectPromise = new Promise((resolve) => {
95
- const ws = new WebSocket(this.url);
96
- this.ws = ws;
97
- ws.on("open", () => {
98
- this.reconnectAttempts = 0;
99
- void this.sendInitialize()
100
- .then(() => resolve())
101
- .catch(() => {
102
- // initialize 失败:close 处理器会负责重连,这里只解除等待。
103
- resolve();
104
- });
105
- });
106
- ws.on("message", (data) => this.onMessage(data));
107
- ws.on("error", (err) => {
108
- this.setState({ connected: false, error: err instanceof Error ? err.message : String(err) });
109
- });
110
- ws.on("close", () => {
111
- const wasConnected = this.connState.connected;
112
- this.ws = null;
113
- this.handshakeData = null;
114
- this.connectPromise = null;
115
- this.rejectAllPending({ code: -32002, message: "codex app-server connection closed" });
116
- this.setState({ connected: false, error: wasConnected ? "connection closed" : this.connState.error });
117
- if (!this.manualClose)
118
- this.scheduleReconnect();
119
- resolve();
120
- });
121
- });
122
- return this.connectPromise;
123
- }
124
- scheduleReconnect() {
125
- if (this.reconnectTimer)
126
- return;
127
- const exp = Math.min(RECONNECT_BASE_MS * 2 ** this.reconnectAttempts, RECONNECT_MAX_MS);
128
- this.reconnectAttempts += 1;
129
- this.reconnectTimer = setTimeout(() => {
130
- this.reconnectTimer = null;
131
- void this.connect();
132
- }, exp);
133
- }
134
- /** 强制断开并重连(supervisor 重启后由 index 调用)。 */
135
- reconnect() {
136
- if (this.reconnectTimer) {
137
- clearTimeout(this.reconnectTimer);
138
- this.reconnectTimer = null;
139
- }
140
- this.reconnectAttempts = 0;
141
- const ws = this.ws;
142
- if (ws && (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING)) {
143
- try {
144
- ws.close();
145
- }
146
- catch {
147
- /* ignore */
148
- }
149
- }
150
- else {
151
- void this.connect();
152
- }
153
- // close 事件会触发 scheduleReconnect;这里立即再拉一次以避免等待。
154
- setTimeout(() => {
155
- if (!this.isReady())
156
- void this.connect();
157
- }, 50);
158
- }
159
- close() {
160
- this.manualClose = true;
161
- if (this.reconnectTimer) {
162
- clearTimeout(this.reconnectTimer);
163
- this.reconnectTimer = null;
164
- }
165
- this.rejectAllPending({ code: -32002, message: "codex client closed" });
166
- const ws = this.ws;
167
- this.ws = null;
168
- this.handshakeData = null;
169
- this.setState({ connected: false, error: null });
170
- if (ws) {
171
- try {
172
- ws.close();
173
- }
174
- catch {
175
- /* ignore */
176
- }
177
- }
178
- }
179
- async sendInitialize() {
180
- const params = {
181
- clientInfo: { name: "oh-my-agent-web", title: "Oh My Agent Web", version: this.version },
182
- // requestAttestation 在生成类型里是必填布尔;实测 handshake 需要它。
183
- capabilities: { experimentalApi: true, requestAttestation: false },
184
- };
185
- const result = await this.requestInternal("initialize", params, INIT_TIMEOUT_MS);
186
- if (isRecord(result)) {
187
- this.handshakeData = {
188
- userAgent: typeof result.userAgent === "string" ? result.userAgent : "unknown",
189
- codexHome: typeof result.codexHome === "string" ? result.codexHome : "",
190
- platformOs: typeof result.platformOs === "string" ? result.platformOs : process.platform,
191
- };
192
- }
193
- this.setState({ connected: true, error: null, since: Date.now() });
194
- }
195
- onMessage(data) {
196
- let msg;
197
- try {
198
- const text = typeof data === "string" ? data : Buffer.isBuffer(data) ? data.toString("utf8") : String(data);
199
- msg = JSON.parse(text);
200
- }
201
- catch {
202
- return; // 忽略畸形报文,绝不 crash
203
- }
204
- if (!isRecord(msg))
205
- return;
206
- const hasId = "id" in msg && msg.id !== null && msg.id !== undefined;
207
- const method = typeof msg.method === "string" ? msg.method : null;
208
- const hasResult = "result" in msg;
209
- const hasError = "error" in msg;
210
- // 1) 对我们请求的响应。
211
- if (hasId && method === null && (hasResult || hasError)) {
212
- const id = msg.id;
213
- if (typeof id === "number")
214
- this.settle(id, hasResult ? { ok: true, value: msg.result } : { ok: false, error: msg.error });
215
- return;
216
- }
217
- // 2) server -> client 请求(需要 reply)。
218
- if (method !== null && hasId) {
219
- const evt = { id: msg.id, method, params: msg.params };
220
- this.emit("serverRequest", evt);
221
- return;
222
- }
223
- // 3) 通知。
224
- if (method !== null) {
225
- const evt = { method, params: msg.params };
226
- this.emit("notification", evt);
227
- }
228
- }
229
- settle(id, outcome) {
230
- const entry = this.pending.get(id);
231
- if (!entry)
232
- return;
233
- this.pending.delete(id);
234
- if (entry.timer)
235
- clearTimeout(entry.timer);
236
- if (outcome.ok) {
237
- entry.resolve(outcome.value);
238
- return;
239
- }
240
- entry.reject(normalizeError(outcome.error));
241
- }
242
- rejectAllPending(error) {
243
- for (const [, entry] of this.pending) {
244
- if (entry.timer)
245
- clearTimeout(entry.timer);
246
- entry.reject(error);
247
- }
248
- this.pending.clear();
249
- }
250
- requestInternal(method, params, timeoutMs) {
251
- const ws = this.ws;
252
- if (!ws || ws.readyState !== WebSocket.OPEN)
253
- return Promise.reject(NOT_CONNECTED);
254
- const id = this.nextId++;
255
- return new Promise((resolve, reject) => {
256
- const timer = timeoutMs > 0
257
- ? setTimeout(() => {
258
- this.pending.delete(id);
259
- reject({ code: -32003, message: `${method} timed out after ${timeoutMs}ms` });
260
- }, timeoutMs)
261
- : null;
262
- this.pending.set(id, { method, resolve, reject, timer });
263
- const payload = { method, id };
264
- if (params !== undefined)
265
- payload.params = params;
266
- try {
267
- ws.send(JSON.stringify(payload));
268
- }
269
- catch (err) {
270
- this.pending.delete(id);
271
- if (timer)
272
- clearTimeout(timer);
273
- reject({ code: -32002, message: err instanceof Error ? err.message : String(err) });
274
- }
275
- });
276
- }
277
- /** 透明代理用:任意 codex 方法。未连接时立即以 -32001 reject。 */
278
- request(method, params) {
279
- if (!this.isReady())
280
- return Promise.reject(NOT_CONNECTED);
281
- return this.requestInternal(method, params, 0);
282
- }
283
- respond(id, result) {
284
- this.send({ id, result });
285
- }
286
- respondError(id, error) {
287
- this.send({ id, error });
288
- }
289
- send(payload) {
290
- const ws = this.ws;
291
- if (!ws || ws.readyState !== WebSocket.OPEN)
292
- return;
293
- try {
294
- ws.send(JSON.stringify(payload));
295
- }
296
- catch {
297
- /* 忽略:连接多半已断,重连逻辑会接手 */
298
- }
299
- }
300
- }
301
- function normalizeError(raw) {
302
- if (isRecord(raw)) {
303
- return {
304
- code: typeof raw.code === "number" ? raw.code : -32000,
305
- message: typeof raw.message === "string" ? raw.message : "codex error",
306
- data: raw.data,
307
- };
308
- }
309
- return { code: -32000, message: typeof raw === "string" ? raw : "codex error" };
310
- }