Skip to content

feat: pause/status 推送到浏览器,消除暂停盲窗 - #5

Closed
0-v-0 wants to merge 1 commit into
better-er:mainfrom
0-v-0:feat/pause-push
Closed

0-v-0 wants to merge 1 commit into
better-er:mainfrom
0-v-0:feat/pause-push

Conversation

@0-v-0

@0-v-0 0-v-0 commented Oct 26, 2026

Copy link
Copy Markdown

背景与影响

原实现靠客户端轮询同步暂停状态,有两个实际代价:

  • 连接池竞争:dsh 走 HTTP/1.1,浏览器每主机仅 6 条连接;密集轮询与突发 RPC
    (如权限预设切换、长轮询)争抢连接池,实测 commands/execute 排队可达 ~20s。
  • 状态盲窗:Enter 拦截器依赖同步到的 paused 状态才挂载,轮询周期内按 Enter
    会绕过暂停门直接提交给 agent。

本 PR 后:推送链路存活时零轮询、状态即时;未注入(preload 缺失/解析失败)
时自动降级,功能完整、行为与不装插件一致,仅状态显示退化。暂停与放行零盲窗。

实现方式

  • 推送:host 的 $events 转发通道只认 harness 核心 dsh-api-remotes 硬编码的
    allowlist,且装配时即绑定、运行期无法追加。新增 preload(NODE_OPTIONS --require,零依赖)在进程最早期把 pause/status 注入该数组,进入官方转发;
    浏览器端经 ctx.remote.$on 订阅。链路确认靠 status RPC 回推(一次性探针会因
    浏览器晚连接而丢失,不可用)。
  • 回退:enabled 时 Enter 拦截常驻(不再依赖状态同步),直接问 host:有门即
    放行,无门则重放官方提交。链路失效仅影响 UI 显示(3s 轮询兜底)。

验证

  • 注入后:status RPC 从 7 次/3s 节奏降为 1 次,零轮询
  • 未注入:3s 回退轮询恢复;Enter 拦截 → 放行/重放均正常,消息正常提交

挂载要求

主进程启动注入 NODE_OPTIONS="--require=<dsh-pause>/lib/preload.cjs";未注入时
插件功能完整,仅状态显示降级。

风险

API_REMOTE_FORWARDED_EVENTS 是 dsh 内部非契约数据结构,上游改动需跟进;
若 dsh 后续开放事件转发注册,可替换 preload 注入。

@better-er
better-er requested a balanced review from Copilot October 26, 2026 08:23

This comment was marked as spam.

@better-er

This comment was marked as outdated.

@better-er

Copy link
Copy Markdown
Owner
  1. 我没有看懂你想解决什么问题

  2. 前提不成立

400ms 一次的 status 是几十字节的小请求,回环上一两毫秒就结束并归还连接。浏览器的 6 条是并行上限,只有 6 条同时未完成才排队。小请求占不住池,commands/execute 的 20 秒排队不能用它解释。

  1. 缺证据

20 秒的说法没有对照实验,也没有 status 的在途数与往返耗时。真要证明,得拿出出现超过 6 个未完成请求的记录。

  1. replaySubmit 改了用户的默认行为

无门时调用 inputActions.submit(),该实现写死 submit("queue"),不读 busyEnter。用户配的 steer 被覆盖成 queue,消息进等待区。

开着暂停时按回车想插话,消息会进下一轮而不是作为插话放行:paused 靠轮询
同步,周期内按键会绕过门直接走官方提交。改为 host 经 $events 把 pause/status
推给浏览器,门状态变化当场 emit,状态即时;推送走 WebSocket,不占 HTTP 并发
连接。

通过往 dsh-api-remotes 的 API_REMOTE_FORWARDED_EVENTS 加一条转发规则实现。
该数组在 remoteEventSource(ctx) 里一次性 map 成监听,而它是 registerRemoteEvents
的入参、注册当刻就建流绑监听,故在 apply 里追加太晚;注入放在模块求值阶段,
Loader 先 import 完全部插件模块再逐个 apply,必定赶在 api-remotes 之前。

- 拦截:只在 paused 时挂 document capture 拦裸 Enter 改走放行,未暂停不碰
  按键,Enter 走官方 keymap,不覆盖用户配置的 busyEnter=steer。
- 回退:推送未建立时轮询按 enabled 分档,关着 5s、开着 400ms。
- 解析:从 argv[1]、execPath、cwd 三处解析,并向上找承载 api-remotes 的宿主包,
  兼容 pnpm hoist 与 npm/yarn 的扁平、嵌套三种布局;解析不到静默降级轮询。
@0-v-0 0-v-0 changed the title feat: 经 preload 注入把 pause/status 推送到浏览器,失败自动回退拦截-重放 feat: pause/status 推送到浏览器,消除暂停盲窗 Oct 26, 2026
@0-v-0

0-v-0 commented Oct 26, 2026 •

Copy link
Copy Markdown
Author

不好意思,原方案和论据都有问题,第4点已修。

要解决的问题

  1. 开着暂停,在工具续跑前想按回车插话,结果按下去之后消息进了下一轮,而不是变成插话。
  2. Chrome DevTools请求列表被本插件0.4s一次的status刷满,DevTools网络Tab开久了页面明显变卡。
    浏览器每主机6条是并行上限,只有6条进行中才排队,小请求占不住池。20秒是DevTools卡的时候测出来的,原论证错了。

怎么改

推送优先,轮询只做回退,删掉原来 400ms 轮询作为主路径。改为 host 经 $events 通道把 pause/status 推给浏览器,在 armGate / release / setEnabled / abortGate 四处当场 emit。状态即时,盲窗消除。
推送走 /api/remote.mux 的 WebSocket,不是 HTTP 请求,不占并发连接。两个问题一起解决。

效果

路径 条件 盲窗 DevTools 记录(空闲 1 分钟)
推送 注入成功 无 零(WebSocket)
回退·开关关 注入失败 无(不会拉门) ~12 条
回退·开关开 注入失败 ≤400ms ~150 条

使用

装完即用,无需启动配置。推送链路建立后状态即时、零轮询;若因模块解析失败未生效,自动降级到轮询(开关关着 5s、开着 400ms),功能完整。

风险

API_REMOTE_FORWARDED_EVENTS 是 dsh 内部非契约数据结构,上游改动需跟进。若 dsh 后续开放事件转发注册 API(registerRemoteEvents 目前是 sole source、由 api-remotes 占用),可替换整个注入环节。

注入时机绑在「Loader 先 import 全部模块、再逐个 apply」这条装配顺序上。若上游改成边 import 边 apply,或把本插件排到 api-remotes 之后才求值,模块顶层的追加就赶不上那次 map——届时需要换手段(如自行注册事件源)。现在的 apply 内幂等兜底只能覆盖「api-remotes 反而更晚」的情形,覆盖不了已经绑完监听的情形。

@better-er

Copy link
Copy Markdown
Owner

抱歉,这个 PR 我不打算合并。让你花了这些时间,尤其在你已经改过一轮之后才说,这点我很抱歉。

第一,方案方向和我这边正在进行的实现冲突,非常不凑巧。我已经把回车拦截改成开关开启期间常驻,每次回车都由主机裁决,没有暂停点但在跑就入队,turn 结束再补发。这个 PR 仍然是「只在暂停点挂着时挂拦截」,推送只是把暂停点挂上到客户端知道之间的窗口压小,并没有消掉。两边的拦截策略是互斥的,合并会把我这边的零盲窗退回去。

第二,注入方式动的是 dsh 内部非契约的 API_REMOTE_FORWARDED_EVENTS,还依赖「Loader 先 import 完再逐个 apply」这条装配顺序。你自己在风险一节也写了,上游一改就得跟着修。这个代价我暂时不想让插件背上。

第三,PR 的说明和代码有几处对不上:body 写「enabled 时拦截常驻」,代码还是 if (!paused) return;body 写新增 preload.cjs,文件清单里没有;body 写回退 3 秒,代码是 4 秒握手加 400/5000 分档。说明交付状态还没收敛,这种情况下合并我也没法验收。

@0-v-0 0-v-0 closed this Oct 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants