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.
- package/README.md +86 -447
- package/dist/server/approval/read-only.js +107 -0
- package/dist/server/approval/rules.js +85 -0
- package/dist/server/approval/scope.js +150 -0
- package/dist/server/brand.js +2 -0
- package/dist/server/cli-config.js +52 -0
- package/dist/server/cli-info.js +101 -0
- package/dist/server/cli.js +304 -0
- package/dist/server/engine/builtin.js +61 -0
- package/dist/server/engine/catalog.js +8 -0
- package/dist/server/engine/codex-approvals.js +45 -0
- package/dist/server/engine/codex-map.js +298 -0
- package/dist/server/engine/codex-sessions.js +159 -0
- package/dist/server/engine/codex-transport.js +49 -0
- package/dist/server/engine/codex.js +314 -0
- package/dist/server/engine/dsh-history.js +195 -0
- package/dist/server/engine/dsh-log.js +245 -0
- package/dist/server/engine/dsh-map.js +221 -0
- package/dist/server/engine/dsh-sessions.js +207 -0
- package/dist/server/engine/dsh-transport.js +37 -0
- package/dist/server/engine/dsh.js +284 -0
- package/dist/server/engine/fake.js +231 -0
- package/dist/server/engine/jsonrpc-stdio.js +241 -0
- package/dist/server/engine/model-registry-reload.js +115 -0
- package/dist/server/engine/pi-events.js +148 -0
- package/dist/server/engine/pi-rename.js +14 -0
- package/dist/server/engine/pi-sdk.js +343 -0
- package/dist/server/engine/pi-session-model.js +23 -0
- package/dist/server/engine/pi-thinking.js +34 -0
- package/dist/server/engine/pi-transcript.js +225 -0
- package/dist/server/engine/pi-version.js +11 -0
- package/dist/server/engine/port.js +1 -0
- package/dist/server/engine/registry.js +47 -0
- package/dist/server/engine/scratch.js +13 -0
- package/dist/server/engine/suggestion-guidance.js +9 -0
- package/dist/server/engine/switchable.js +22 -0
- package/dist/server/engine/wiring.js +107 -0
- package/dist/server/files/dir-routes.js +40 -0
- package/dist/server/files/file-search.js +63 -0
- package/dist/server/files/file-service.js +232 -0
- package/dist/server/files/files-routes.js +182 -0
- package/dist/server/files/git-info.js +186 -0
- package/dist/server/http/auth-routes.js +99 -0
- package/dist/server/http/auth.js +191 -0
- package/dist/server/http/aux-routes.js +24 -0
- package/dist/server/http/compress.js +75 -0
- package/dist/server/http/health-and-static.js +33 -0
- package/dist/server/http/live-routes.js +113 -0
- package/dist/server/http/login-page.js +200 -0
- package/dist/server/index.js +342 -520
- package/dist/server/markers/actions.js +262 -0
- package/dist/server/protocol-parse.js +201 -0
- package/dist/server/protocol-settings.js +1 -0
- package/dist/server/protocol.js +6 -0
- package/dist/server/providers/catalog-store.js +85 -0
- package/dist/server/providers/catalog-writes.js +197 -0
- package/dist/server/providers/catalog.js +77 -0
- package/dist/server/providers/enabled-models.js +118 -0
- package/dist/server/providers/import-models.js +69 -0
- package/dist/server/providers/import-routes.js +136 -0
- package/dist/server/providers/model-test.js +52 -0
- package/dist/server/providers/probe.js +64 -0
- package/dist/server/providers/provider-handlers.js +203 -0
- package/dist/server/providers/provider-store.js +327 -0
- package/dist/server/providers/request-headers.js +7 -0
- package/dist/server/providers/validate.js +241 -0
- package/dist/server/push/push-routes.js +114 -0
- package/dist/server/push/push.js +120 -0
- package/dist/server/session/approval-bridge.js +103 -0
- package/dist/server/session/attachment-resolve.js +21 -0
- package/dist/server/session/client-view.js +82 -0
- package/dist/server/session/conversation-create.js +65 -0
- package/dist/server/session/delete-session.js +84 -0
- package/dist/server/session/engine-switch.js +108 -0
- package/dist/server/session/lock.js +82 -0
- package/dist/server/session/model-controller.js +111 -0
- package/dist/server/session/notices.js +31 -0
- package/dist/server/session/pi-opener.js +123 -0
- package/dist/server/session/pi-refresh.js +51 -0
- package/dist/server/session/pi-sessions-provider.js +46 -0
- package/dist/server/session/pi-sessions.js +272 -0
- package/dist/server/session/refresh-actions.js +42 -0
- package/dist/server/session/rename-session.js +23 -0
- package/dist/server/session/runtime-services.js +28 -0
- package/dist/server/session/runtime-types.js +1 -0
- package/dist/server/session/runtime.js +358 -0
- package/dist/server/session/session-stats.js +88 -0
- package/dist/server/session/settings.js +367 -0
- package/dist/server/session/snapshot-for.js +7 -0
- package/dist/server/session/stats-refresher.js +50 -0
- package/dist/server/session/switch-conversation.js +86 -0
- package/dist/server/session/throttle.js +14 -0
- package/dist/server/session/turn-events.js +126 -0
- package/dist/server/session/turn-finish.js +79 -0
- package/dist/server/session/turn-markers.js +26 -0
- package/dist/server/session/turn-queue.js +111 -0
- package/dist/server/session/turn-send.js +88 -0
- package/dist/server/session/turn-watchdog.js +77 -0
- package/dist/server/sessions/session-routes.js +17 -0
- package/dist/server/skills/skill-routes.js +28 -0
- package/dist/server/skills/skill-store.js +134 -0
- package/dist/server/snapshot/fan-out.js +10 -0
- package/dist/server/snapshot/messages.js +75 -0
- package/dist/server/snapshot/sender.js +62 -0
- package/dist/server/snapshot/state.js +193 -0
- package/dist/server/terminal/terminal-routes.js +176 -0
- package/dist/server/terminal/terminal-session.js +140 -0
- package/dist/server/uploads/upload-routes.js +64 -0
- package/dist/server/uploads/upload-store.js +115 -0
- package/dist/server/util/data-dir.js +36 -0
- package/dist/server/util/env.js +140 -0
- package/dist/server/util/ids.js +28 -0
- package/dist/server/util/log-file.js +67 -0
- package/dist/server/util/log.js +52 -0
- package/dist/server/util/origin.js +75 -0
- package/dist/server/util/paths.js +60 -0
- package/dist/server/util/pricing-index.js +121 -0
- package/dist/server/util/pricing.js +214 -0
- package/dist/server/util/startup.js +34 -0
- package/dist/server/util/upstream-version.js +140 -0
- package/dist/server/util/usage.js +19 -0
- package/dist/server/util/version.js +50 -0
- package/dist/server/ws/handle-message.js +95 -0
- package/package.json +49 -63
- package/web/dist/apple-touch-icon-precomposed.png +0 -0
- package/web/dist/apple-touch-icon.png +0 -0
- package/web/dist/assets/abnfDiagram-WEYOIA3C-NLp09iEC.js +1 -0
- package/web/dist/assets/arc-DviL9o3c.js +1 -0
- package/web/dist/assets/architecture-WOLXFQ4H-fjsM_Sy3.js +1 -0
- package/web/dist/assets/architectureDiagram-ZHVYKT53-Cn3B4TE8.js +36 -0
- package/web/dist/assets/array-BifhSqXX.js +1 -0
- package/web/dist/assets/blockDiagram-RJAE7QA3-CIuvxWvi.js +140 -0
- package/web/dist/assets/c4Diagram-XDPPPE54-DvdKmEpF.js +38 -0
- package/web/dist/assets/channel-C3AQ6nAs.js +1 -0
- package/web/dist/assets/chunk-2E7WHVMD-HNNASGCS.js +88 -0
- package/web/dist/assets/chunk-2Q5K7J3B-C1jixKkw.js +1 -0
- package/web/dist/assets/chunk-4EMNKR2T-Cg-eRwBE.js +1 -0
- package/web/dist/assets/chunk-55XCU76K-BweiisZL.js +1 -0
- package/web/dist/assets/chunk-5VM5RSS4-ZNzvKenW.js +15 -0
- package/web/dist/assets/chunk-7S6XSTFO-BCzIiP-6.js +2 -0
- package/web/dist/assets/chunk-AQDTSKZB-Dl0NRFuU.js +72 -0
- package/web/dist/assets/chunk-DSNLSHJZ-zhHCjjN9.js +129 -0
- package/web/dist/assets/chunk-DUW6YSOI-Dgx8z5s3.js +1 -0
- package/web/dist/assets/chunk-HAGFOTED-BDQqU2EH.js +62 -0
- package/web/dist/assets/chunk-HNE4Q36P-B-qRzMjX.js +1 -0
- package/web/dist/assets/chunk-J5ZVWO5B-oDCd-gWO.js +1 -0
- package/web/dist/assets/chunk-JWPE2WC7-DVXcaiue.js +1 -0
- package/web/dist/assets/chunk-NGNAAXSQ-C2Wy9Xmz.js +136 -0
- package/web/dist/assets/chunk-NQOKRVIF-CNcvhMn_.js +213 -0
- package/web/dist/assets/chunk-UHW7PFBP-Dwr8LUzr.js +1 -0
- package/web/dist/assets/chunk-VQ5W62QI-O8sN6jJu.js +1 -0
- package/web/dist/assets/chunk-WQQL4CDK-B6-59Zg2.js +10 -0
- package/web/dist/assets/chunk-XXDRQBXY-DvSbeUlZ.js +1 -0
- package/web/dist/assets/chunk-Y2CYZVJY-DsF7k-Jl.js +1 -0
- package/web/dist/assets/chunk-YZO67HFG-BXpKYKsw.js +1 -0
- package/web/dist/assets/chunk-ZAUX2LTX-B1Z5VSkz.js +1 -0
- package/web/dist/assets/chunk-ZCHMQSOR-h_5mBLIA.js +2 -0
- package/web/dist/assets/classDiagram-v2-4MYWR3UA-Dr6JnaaV.js +217 -0
- package/web/dist/assets/cose-bilkent-JH36ORCC-36ShkR7R.js +1 -0
- package/web/dist/assets/cynefin-EF2NZ3EQ-Dg6bI7pC.js +1 -0
- package/web/dist/assets/cynefinDiagram-WF24UDRP-B0YHpBlR.js +62 -0
- package/web/dist/assets/cytoscape.esm-BegBNzOV.js +321 -0
- package/web/dist/assets/dagre-NK4GIZVX-Cx3mn7YS.js +4 -0
- package/web/dist/assets/defaultLocale-BFoDCU3G.js +1 -0
- package/web/dist/assets/diagram-CBK3MWTC-l8aZG_Bm.js +24 -0
- package/web/dist/assets/diagram-I5XIIV2D-Bd5f14_h.js +24 -0
- package/web/dist/assets/diagram-ODIL2UCW-hBsxCYUj.js +30 -0
- package/web/dist/assets/diagram-PFBEJUXE-BgpIBUYl.js +3 -0
- package/web/dist/assets/diagram-RJA3I4VV-CDU1gUVD.js +41 -0
- package/web/dist/assets/diagram-TYUNFSNR-Iuxh7Tqf.js +200 -0
- package/web/dist/assets/dist-C86cKTuE.js +1 -0
- package/web/dist/assets/ebnfDiagram-V4P3TTPT-Cms0HFKh.js +1 -0
- package/web/dist/assets/elk-QONTBCTQ-B7yEy0PQ.js +27 -0
- package/web/dist/assets/erDiagram-KYQIGQAA-CL48j4aU.js +99 -0
- package/web/dist/assets/eventmodeling-K75KTNOO-CFvkaejh.js +1 -0
- package/web/dist/assets/flowDiagram-IUGLLWBU-6UyKXpqG.js +1 -0
- package/web/dist/assets/ganttDiagram-R7GPNTJY-vdMr-0ZV.js +292 -0
- package/web/dist/assets/gitGraph-VSP46ZUC-2z85Wuwo.js +1 -0
- package/web/dist/assets/gitGraphDiagram-PDYL7XHY-BY4GPiqC.js +106 -0
- package/web/dist/assets/graphlib-DS17s2tU.js +1 -0
- package/web/dist/assets/index-Bjn56a2i.js +76 -0
- package/web/dist/assets/index-Drp6e5iU.css +1 -0
- package/web/dist/assets/info-OHQRW6UA-ECzkYTx-.js +1 -0
- package/web/dist/assets/infoDiagram-MVDRKAX5-DDk5EAeb.js +2 -0
- package/web/dist/assets/init-C-OQMol4.js +1 -0
- package/web/dist/assets/ishikawaDiagram-HPEHV2GE-9yPH4J94.js +70 -0
- package/web/dist/assets/journeyDiagram-BOSHW7O7-BPTIap3l.js +139 -0
- package/web/dist/assets/kanban-definition-FNSA4HC5-BbADHrA8.js +89 -0
- package/web/dist/assets/katex-B_JcIwqj.js +257 -0
- package/web/dist/assets/line-CHV9_4lL.js +1 -0
- package/web/dist/assets/linear-C-eZsBTv.js +1 -0
- package/web/dist/assets/mermaid-parser.core-BiAhX1l1.js +7 -0
- package/web/dist/assets/mermaid.core-BxP_A_zj.js +44 -0
- package/web/dist/assets/mindmap-definition-6OY57UG3-BMWlit95.js +98 -0
- package/web/dist/assets/ordinal-BDEzSJ7C.js +1 -0
- package/web/dist/assets/packet-JDAUHWVQ-FVApuKOp.js +1 -0
- package/web/dist/assets/path-fybaL0A-.js +1 -0
- package/web/dist/assets/pegDiagram-ECIUJNBX-WjWJvDHM.js +1 -0
- package/web/dist/assets/pie-XZMESJXO-BGCZnvhp.js +1 -0
- package/web/dist/assets/pieDiagram-GNMPY74T-DJpAC_JC.js +39 -0
- package/web/dist/assets/quadrantDiagram-D57K4MC3-hxx5c7oq.js +7 -0
- package/web/dist/assets/radar-ABXABTNO-BU9Shc-O.js +1 -0
- package/web/dist/assets/railroad-I3PHUGI6-pWj8d-G4.js +1 -0
- package/web/dist/assets/railroad-abnf-LNEFI6M7-D7HZBTAj.js +1 -0
- package/web/dist/assets/railroad-ebnf-DWYD2UWJ-CKiXJSuM.js +1 -0
- package/web/dist/assets/railroad-peg-JR7BVNR7-DB3VJHgR.js +1 -0
- package/web/dist/assets/railroadDiagram-Y72NRBL7-Cev7Y65k.js +1 -0
- package/web/dist/assets/requirementDiagram-EQYSW5RA-CqbwMLD8.js +84 -0
- package/web/dist/assets/rough.esm-Dy-Kn_BL.js +1 -0
- package/web/dist/assets/sankeyDiagram-SY24JHO5-V2cyVi8q.js +40 -0
- package/web/dist/assets/sequenceDiagram-BLEHNHQU-By6NJOPM.js +169 -0
- package/web/dist/assets/sizeCapture-INFHLROL-3uHXrFqA.js +1 -0
- package/web/dist/assets/src-Da91fG3g.js +1 -0
- package/web/dist/assets/stateDiagram-v2-A6IESKWZ-BnPGX5UI.js +291 -0
- package/web/dist/assets/swimlanes-B3ENRKFQ-C58BpIpm.js +1 -0
- package/web/dist/assets/swimlanesDiagram-AYQRV4AK-RaivxSsc.js +8 -0
- package/web/dist/assets/timeline-definition-JXYKGLGB-Hgo1DhnS.js +120 -0
- package/web/dist/assets/treeView-D4JQ5SDB-DF0dfjqB.js +1 -0
- package/web/dist/assets/treemap-SAJKECNS-CSSM5FqB.js +1 -0
- package/web/dist/assets/usecaseDiagram-WPOLBNNX-BkBBD1NY.js +328 -0
- package/web/dist/assets/vennDiagram-Q3Y3IDCW-Bm28keX_.js +34 -0
- package/web/dist/assets/wardley-7MLQ67FV-By7KgEQX.js +1 -0
- package/web/dist/assets/wardleyDiagram-IVAIDKWA-oVtIrnGa.js +78 -0
- package/web/dist/assets/xychartDiagram-4URNHDU4-aI8FH4g2.js +7 -0
- package/web/dist/favicon-32.png +0 -0
- package/web/dist/favicon.ico +0 -0
- package/web/dist/favicon.svg +20 -8
- package/web/dist/icons/apple-touch-icon-180.png +0 -0
- package/web/dist/icons/icon-192.png +0 -0
- package/web/dist/icons/icon-512.png +0 -0
- package/web/dist/icons/icon-maskable-512.png +0 -0
- package/web/dist/index.html +21 -27
- package/web/dist/manifest.webmanifest +17 -0
- package/web/dist/maskable.svg +25 -0
- package/web/dist/sw.js +40 -0
- package/bin/oh-my-agent-web-ps.mjs +0 -203
- package/bin/oh-my-agent-web-ws.mjs +0 -593
- package/bin/oh-my-agent-web.mjs +0 -321
- package/bin/update-check.mjs +0 -142
- package/dist/server/codex-client.js +0 -310
- package/dist/server/codex-supervisor.js +0 -446
- package/dist/server/fs-service.js +0 -144
- package/dist/server/request-inspector.js +0 -458
- package/dist/shared/protocol.js +0 -112
- package/scripts/manage-server.mjs +0 -155
- package/scripts/omaw.mjs +0 -74
- package/shared/protocol.ts +0 -228
- package/web/dist/assets/index-B8-VzDf2.css +0 -1
- package/web/dist/assets/index-DeC2eiiq.js +0 -42
- 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
|
-
}
|