diff --git a/AGENTS.md b/AGENTS.md index e1207da..6bfc4f5 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -58,6 +58,7 @@ - 涉及定时器、重试、缓存、前后台切换时,优先保证时间语义闭合,再考虑 UI 表现。 - 不要把“缓存命中”“回退成功”“页面没报错”误判成“拿到了最新数据”。 - Codex Chrome 的 Playwright `evaluate` sandbox 和 raw CDP 是不同执行面。需要验证页面内 `fetch`、`XMLHttpRequest`、`DOMParser`、DOM mutation、事件或 `postMessage` 时,有 raw CDP 就优先直接用 `Runtime.evaluate` 和 Network events;只有 raw CDP 不可用或目标浏览器没有所需登录态时,才改用 live DOM/截图/console/page assets、真实 DevTools、Tampermonkey、临时 helper extension 或带 referer 的命令行请求。某个受限 evaluation surface 缺少 API,不代表目标页面不能运行该代码。 +- Codex Chrome 的 `openTabs()`、`claimTab()` 和 page-level CDP 是不同故障层。`openTabs()` 正常而单个 `claimTab()` / `tabs.get()` 挂起时,先按 stale browser-session ownership 处理,不要归因于目标网站或代理节点:同一 `node_repl` kernel 只初始化一次 browser runtime 并复用 binding;claim 超时的结果视为 unknown,禁止重复 claim、重复建 client/session 或继续使用旧 handle。能在同一登录态副本页完成的只读诊断优先用一个 agent-created 临时 tab;只有所有新 tab 也失败时才转入 helper/proxy/CDP 排查。browser 验证未完成时不要重置 kernel,任务结束时不要为普通诊断 tab 设置 handoff/deliverable,让 turn cleanup 释放控制权。详细本机 SOP 见 `~/.dotfiles/knowledge/machines/lizhenhai-macbook-pro-14/LOCAL_PROXY_REFERENCE.md` 的“Codex Chrome `claimTab` 结果丢失与 stale session 占用”。 - Chrome/CDP 诊断资源必须限制在当前测量范围内:只启用本轮需要的 CDP domain,事件读取必须带过滤条件和数量上限,证据收集完成后销毁页面探针,并关闭本轮启用的所有 domain。不要在持久 `node_repl` 绑定中长期保留大批事件或完整脚本源码。 - Codex `cua_node` 进程长时间占用超过一个 CPU 核心,并不能证明 userscript 或目标页面仍在忙。应先根据父进程和工作目录确认 PID 归属,检查 JavaScript 事件循环是否真的繁忙,再做短时只读堆栈采样。2026-08-25 的故障中,REPL 事件循环占用只有约 `0.1%`,原生堆栈热点却集中在管道/文件读取、Buffer/UTF-8 转换、typed array 复制和垃圾回收;关闭 CDP domain 后没有恢复,而重置该任务的 `node_repl` 内核会终止高负载 helper,同时保留 Chrome 和 Binance 页面。内核重置会清空所有 REPL 绑定并要求重新连接 Chrome,所以只能在浏览器验证节点完成后使用;清理后必须确认热点 PID 已消失,不要把直接结束 Node 进程作为第一步。 diff --git a/scripts/binance-orderbook-trade.user.js b/scripts/binance-orderbook-trade.user.js index 954c6d7..f67459a 100644 --- a/scripts/binance-orderbook-trade.user.js +++ b/scripts/binance-orderbook-trade.user.js @@ -3,7 +3,7 @@ // @namespace binance.orderbook.trade // @icon data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2064%2064%22%3E%3Crect%20width%3D%2264%22%20height%3D%2264%22%20rx%3D%2214%22%20fill%3D%22%23f0b90b%22%2F%3E%3Ctext%20x%3D%2232%22%20y%3D%2249%22%20text-anchor%3D%22middle%22%20font-family%3D%22Arial%2C%20sans-serif%22%20font-size%3D%2242%22%20font-weight%3D%22800%22%20fill%3D%22%23111827%22%3EJ%3C%2Ftext%3E%3C%2Fsvg%3E // @icon64 data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2064%2064%22%3E%3Crect%20width%3D%2264%22%20height%3D%2264%22%20rx%3D%2214%22%20fill%3D%22%23f0b90b%22%2F%3E%3Ctext%20x%3D%2232%22%20y%3D%2249%22%20text-anchor%3D%22middle%22%20font-family%3D%22Arial%2C%20sans-serif%22%20font-size%3D%2242%22%20font-weight%3D%22800%22%20fill%3D%22%23111827%22%3EJ%3C%2Ftext%3E%3C%2Fsvg%3E -// @version 2.7.139 +// @version 2.7.140 // @author jackhai9 // @description 单击订单簿价格,按当前开仓/平仓 tab 自动填数量并执行下单,内置数量倍率面板 // @match https://www.binance.com/*/futures/* @@ -2295,7 +2295,7 @@ setter?.call(input, value); input.dispatchEvent(new Event("input", { bubbles: true })); input.dispatchEvent(new Event("change", { bubbles: true })); - input.dispatchEvent(new Event("blur", { bubbles: true })); + input.blur(); } function delay(ms) { return new Promise((resolve) => { diff --git a/src/binance-orderbook-trade/index.user.js b/src/binance-orderbook-trade/index.user.js index 70983ea..5a1f628 100644 --- a/src/binance-orderbook-trade/index.user.js +++ b/src/binance-orderbook-trade/index.user.js @@ -3,7 +3,7 @@ // @namespace binance.orderbook.trade // @icon data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2064%2064%22%3E%3Crect%20width%3D%2264%22%20height%3D%2264%22%20rx%3D%2214%22%20fill%3D%22%23f0b90b%22%2F%3E%3Ctext%20x%3D%2232%22%20y%3D%2249%22%20text-anchor%3D%22middle%22%20font-family%3D%22Arial%2C%20sans-serif%22%20font-size%3D%2242%22%20font-weight%3D%22800%22%20fill%3D%22%23111827%22%3EJ%3C%2Ftext%3E%3C%2Fsvg%3E // @icon64 data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2064%2064%22%3E%3Crect%20width%3D%2264%22%20height%3D%2264%22%20rx%3D%2214%22%20fill%3D%22%23f0b90b%22%2F%3E%3Ctext%20x%3D%2232%22%20y%3D%2249%22%20text-anchor%3D%22middle%22%20font-family%3D%22Arial%2C%20sans-serif%22%20font-size%3D%2242%22%20font-weight%3D%22800%22%20fill%3D%22%23111827%22%3EJ%3C%2Ftext%3E%3C%2Fsvg%3E -// @version 2.7.139 +// @version 2.7.140 // @author jackhai9 // @description 单击订单簿价格,按当前开仓/平仓 tab 自动填数量并执行下单,内置数量倍率面板 // @match https://www.binance.com/*/futures/* @@ -518,7 +518,7 @@ import { setter?.call(input, value); input.dispatchEvent(new Event('input', { bubbles: true })); input.dispatchEvent(new Event('change', { bubbles: true })); - input.dispatchEvent(new Event('blur', { bubbles: true })); + input.blur(); } function delay(ms) { diff --git a/test/unit/binance-orderbook-trade/source-regressions.test.js b/test/unit/binance-orderbook-trade/source-regressions.test.js index 5b76a1f..681a004 100644 --- a/test/unit/binance-orderbook-trade/source-regressions.test.js +++ b/test/unit/binance-orderbook-trade/source-regressions.test.js @@ -145,9 +145,15 @@ test('trade mode and Post Only switches wait for observed state instead of fixed }); test('trade input synchronization confirms live controlled values instead of sleeping', () => { + const setInputBody = readFunctionBody('setInputValueReact'); const syncBody = readFunctionBody('syncTradeInputs'); const executeBody = readFunctionBody('executeLadderPlan'); + assert.match(setInputBody, /HTMLInputElement\.prototype/); + assert.match(setInputBody, /dispatchEvent\(new Event\('input'/); + assert.match(setInputBody, /dispatchEvent\(new Event\('change'/); + assert.match(setInputBody, /input\.blur\(\)/); + assert.doesNotMatch(setInputBody, /dispatchEvent\(new Event\('blur'/); assert.match(syncBody, /createTradeInputStateReader/); assert.match(syncBody, /createBoundedInputWriter/); assert.match(syncBody, /resolveInputs:\s*findTradeInputs/);