feat(remote-desktop): 手机远程桌面、网络协商与断线恢复 - #4065
Conversation
Signed-off-by: Dash <125997726+dashhuang@users.noreply.github.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
Security findingsAdvisory findings (3)
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
| Filename | Overview |
|---|---|
| apps/desktop/src/main/remote-desktop/controller.ts | 实现远程桌面租约、接管、控制和异步操作门控,但分辨率路径没有绑定发起时的控制 generation。 |
| apps/desktop/src/renderer/features/remote-desktop/RemoteDesktopHost.tsx | 在可信桌面 Renderer 中建立捕获与 WebRTC 通道,但原生视频回退会在请求音频失败时静默建立无音轨连接。 |
| apps/desktop/src/main/remote-desktop/index.ts | 注册本机 IPC、权限、捕获授权和平台能力,并将远程请求接入控制器。 |
| apps/desktop/native/remote-desktop/windows-host/src/service.rs | 新增受保护的 Windows SYSTEM 服务、会话 worker 和命名管道授权边界。 |
| apps/mobile/src/remote-desktop/RemoteDesktopScreen.tsx | 实现手机端连接恢复、输入、剪贴板、显示设置、画中画和会话生命周期。 |
| packages/device-link/src/remoteDesktop.ts | 定义远程桌面协议、能力、租约、输入和有界请求校验。 |
Sequence Diagram
sequenceDiagram
participant P as 手机端
participant R as Device Link Relay
participant M as 桌面 Main
participant H as 可信 Renderer
participant N as 原生捕获/输入 Helper
P->>R: capabilities / start
R->>M: 已认证同账号 invoke
M->>M: 校验远控开关、撤销状态与租约
M-->>P: display + lease
P->>M: control / offer
M->>N: 启动输入或原生捕获
M->>H: WebRTC offer 与单次捕获授权
H-->>P: WebRTC 视频、音频与 DataChannel
P->>M: heartbeat / input / clipboard
M->>M: 校验 peer、lease、sequence、generation
M->>N: 注入输入或读取帧
P->>M: stop
M->>N: 释放输入与捕获
Prompt To Fix All With AI
### Issue 1
apps/desktop/src/main/remote-desktop/controller.ts:281-284
**旧分辨率请求仍会执行**
当分辨率切换正在等待显示模式枚举或原生 helper 准备时,同一连接可以先释放控制再重新取得控制。这里仅检查当前是否处于控制状态,没有校验发起请求时的 `controlGeneration`,因此旧请求会在新一代控制状态下重新变为有效,继续修改电脑分辨率,并在完成后断开刚建立的新控制。请像剪贴板和输入启动路径一样捕获并校验 generation,使释放控制后的旧请求永久失效。
### Issue 2
apps/desktop/src/renderer/features/remote-desktop/RemoteDesktopHost.tsx:153-156
**音频失败被静默忽略**
用户开启“声音”后,如果 Chromium 系统音频捕获失败,原生视频路径会吞掉错误并继续建立仅视频连接;后面的音轨检查又在 `nativeCapture` 为 true 时被跳过。macOS 始终使用该原生路径,启用 Windows 服务时也会进入此路径,因此手机仍显示实时连接且声音开关保持开启,却没有音轨或错误提示。应在请求音频但最终没有音轨时报告失败,或显式关闭声音状态。
```suggestion
if (command.settings?.audio && !captured.getAudioTracks().length) {
captured.getTracks().forEach((track) => track.stop());
throw new Error('DESKTOP_AUDIO_UNAVAILABLE');
}
```
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.Reviews (1): Last reviewed commit: "feat(remote-desktop): 支持手机远程查看与操作电脑桌面" | Re-trigger Greptile
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2c26b914b9
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@dashhuang 👋 这个 PR 还有 10 条 review conversation 没 resolve(apps/desktop/src/main/remote-desktop/controller.ts / apps/desktop/src/renderer/features/remote-desktop/RemoteDesktopHost.tsx / apps/mobile/app.json / apps/desktop/native/remote-desktop/windows-host/src/lib.rs / apps/desktop/native/remote-desktop/windows-host/src/security.rs 等),auto-review 因此暂时跳过、没法继续审查 / 合并。 如果你已经按评论改完或回应了,请到对应 thread 上点 Resolve conversation;全部 resolve 后,下一轮 auto-review 会自动重新审查这个 PR。 |
Signed-off-by: Dash <125997726+dashhuang@users.noreply.github.com>
|
命中 UI 路径(apps/desktop/src/renderer/App.tsx / apps/desktop/src/renderer/components/settings/ComputerPermissionRow.tsx / apps/desktop/src/renderer/components/settings/ComputerUseSection.tsx 等)但 description 未附界面效果证据——建议补充改动后效果:截图/录屏,或改动后界面的 HTML 页面(```html 代码块、.html 附件或在线预览链接),便于确认界面符合 DESIGN.md 设计规范 |
Signed-off-by: Dash <125997726+dashhuang@users.noreply.github.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7cc27a3f91
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Signed-off-by: Dash <125997726+dashhuang@users.noreply.github.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 32bdfa8c72
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@dashhuang 👋 这个 PR 还有 1 条 review conversation 没 resolve(apps/desktop/src/main/remote-desktop/controller.ts),auto-review 因此暂时跳过、没法继续审查 / 合并。 如果你已经按评论改完或回应了,请到对应 thread 上点 Resolve conversation;全部 resolve 后,下一轮 auto-review 会自动重新审查这个 PR。 |
Signed-off-by: Dash <125997726+dashhuang@users.noreply.github.com>
Signed-off-by: Dash <125997726+dashhuang@users.noreply.github.com>
There was a problem hiding this comment.
💡 Codex Security Review
Here are some automated security review suggestions for this pull request.
Reviewed commit: b5d0959530
ℹ️ About Codex security reviews in GitHub
This is an experimental Codex feature. Security reviews are triggered when:
- You comment "@codex security review"
- A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review
Once complete, Codex will leave suggestions, or a comment if no findings are found.
Signed-off-by: Dash <125997726+dashhuang@users.noreply.github.com>
Signed-off-by: Dash <125997726+dashhuang@users.noreply.github.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e6d41a5e62
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Signed-off-by: Dash <125997726+dashhuang@users.noreply.github.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: af028cc1d2
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Signed-off-by: Dash <125997726+dashhuang@users.noreply.github.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: cefbca1db7
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Signed-off-by: Dash <125997726+dashhuang@users.noreply.github.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0a23d92fed
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Signed-off-by: Dash <125997726+dashhuang@users.noreply.github.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2582f7dcac
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Signed-off-by: Dash <125997726+dashhuang@users.noreply.github.com>
Signed-off-by: Dash <125997726+dashhuang@users.noreply.github.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e5806b1eb7
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Signed-off-by: Dash <125997726+dashhuang@users.noreply.github.com>
Signed-off-by: Dash <125997726+dashhuang@users.noreply.github.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ed798f1947
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Signed-off-by: Dash <125997726+dashhuang@users.noreply.github.com>
MagicLizi
left a comment
There was a problem hiding this comment.
PR #4065 Review Report — feat(remote-desktop): Mobile remote desktop, network negotiation & reconnect recovery
PR: #4065
Head: 0981a66cd58ae8209db59dc893bc299abe9137ef
Base: afa8a51b221c2fbb5cda3d7ee2c60bbbf481886d (main)
Review tier: heavy (security-sensitive triggers + 18K-line diff)
Reviewer: magiclizi (auto-review)
Summary
Large feature PR adding mobile-to-desktop remote viewing and control via same-account device link. Includes WebRTC video, input forwarding, clipboard transfer, macOS native capture/input helper, Windows SYSTEM service, capture process isolation, and incremental ICE/media recovery.
Security Assessment
0 P0, 0 P1 findings.
Capture Window Isolation (verified)
- Separate BrowserWindow with dedicated session partition (cindy-desktop-capture, cache: false)
- Extremely restrictive CSP: default-src 'none'; script-src 'self'; connect-src 'none'
- Sandbox: true, contextIsolation: true, nodeIntegration: false, webviewTag: false
- Narrow preload (desktopCapturePreload.ts): only 7 IPC channels, no filesystem/chat/credential access
- Navigation, redirect, window-open, webview-attach all blocked; violations trigger disposal
- Custom protocol handler (cindy-desktop-capture://) with strict whitelist regex for paths
- assertSender validates exact sender identity, top-level frame, null parent, and fixed URL
App Session Protection (verified)
- denyAppDesktopCapture removes desktop capture from the default app session entirely
- setDisplayMediaRequestHandler returns empty callback (denies all)
- Physical media (audio/video) and clipboard-write confined to trusted top-level app renderer pages
Controller & Protocol Security (verified)
- All operations bound to authenticated peer + random UUID lease with 12-second expiry
- Generation counter invalidates async operations across lease transitions
- Input sequence numbers prevent replay after reconnect
- userStopped map prevents automatic reconnection after explicit local disconnect
- parseRemoteDesktopRequest: strict type validation, bounded lengths (SDP <= 64KB, events <= 64 per batch, clipboard <= 16384 chars)
IPC Boundary (verified)
- Renderer-facing handlers use assertTrustedAppRendererEvent
- Capture-facing handlers use captureWindow.assertSender + event.sender === host
- Display media grant consumed atomically; single-use per offer
Flagged Patterns Disposition
- dynamic-eval (controller.ts): False positive; this.require() is an internal method name, not eval()
- dynamic-eval (test files): test harnesses only, not production code
- permission-bypass: These ARE the permission handlers implementing restrictive policies
- navigation-escape: Event handlers that PREVENT navigation
- csp-relax: Test asserting restrictive CSP; mobile viewer unsafe-inline in zero-network context
Verification
- Credential/privacy scan: pass (0 hard hits)
- Heavy security scan: no new dependencies; semgrep not executed incrementally
- Format gate: pass
- All 37 review threads resolved
- All signoff triggers released by zqchris (APPROVED 2026-09-07)
- CI: CLEAN, reviewDecision: APPROVED
- Bot settle: timed out at 263 min (copilot/codex still pending; settled by timeout)
Non-blocking Notes
- UI evidence not attached (private desktop screenshots)
- Android/Windows real-device testing not completed
- No TURN deployment
Conclusion
Clean review: 0 P0, 0 P1. Proceed to approve and merge.
Signed-off-by: Dash <125997726+dashhuang@users.noreply.github.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 183c102943
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Signed-off-by: Dash <125997726+dashhuang@users.noreply.github.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7939926c8b
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…d-harness Take makecindy#4065 mobile remote-desktop. Keep grok-build on AgentKind and source-ready / device-link contracts. Signed-off-by: Bill Yuchen Lin <10104354+yuchenlin@users.noreply.github.com>
这次改了什么
摘要
手机可通过同账号设备查看和操作电脑桌面,提供触屏、触摸板、电脑键盘、剪贴板和显示设置。电脑端先允许本机远程控制,再开启远程桌面;权限与连接状态在同一处呈现。网络支持增量 ICE、短断线保留画面和有界媒体恢复。
桌面采集和 WebRTC 发送运行在独立、沙箱化的捕获页面中,不加载聊天或 Markdown。聊天页面不能通过远程桌面捕获接口取得屏幕 source ID、原始帧或捕获桥接;停止和撤权由 Main 销毁捕获窗口,不依赖页面自行停止媒体流。macOS 输入 helper 同时校验 Main 的调用者身份与签名资源。
变更类型
feat新功能fix缺陷修复refactor/perf重构或性能优化docs/test/chore文档、测试或工程维护范围
UI 变化
docs/design-rules/DESIGN.md§2、§10 使用语义颜色并实现 Light/Dark;§4 Buttons / Select & Dropdown、§14.6 复用原生菜单和图标按钮并保留无障碍名称;§5、§8 压缩横屏工具栏与键盘留白,按安全区布局;§14.1 限制远程画面的本地文本选中;设备图标中性化,状态色移至字幕旁圆点。怎么验证的
自动验证
7939926:78 项定向测试、Mobile/Desktop typecheck、根 test:unit:related(全仓)通过。覆盖 PiP 请求回复丢失后旧 lease 释放与恢复;分辨率原生写入前停止旧几何、系统通知先到、helper 成败不影响替代连接,以及释放/接管/撤权后禁止旧请求执行。未做实机 PiP 或显示模式切换验证。
0981a66:补齐 PiP 失败时后台暂停,录屏权限探测复用既有 5 秒枚举上限。50 项定向测试、Mobile/Desktop typecheck、根 pnpm test:unit:related(扩展为全仓)通过。故障半径分别为当前桌面 lease 和本地单次权限请求,共享 device-link/relay 未改变;未做实机 PiP/TCC 验证。上一 head Windows 技能容量测试超时与本 PR 无差异,待新 head CI 复核。
ed798f1:默认 session 权限改为拒绝未知能力,仅在登记应用顶层页面或既有语音浮窗且 URL 匹配时允许物理音视频及剪贴板写入。截图枚举超时只产生空帧,其他错误和捕获后的撤权校验保留。49 项定向测试、Desktop typecheck、全仓 test:unit:related 通过;首次全仓暴露旧初始化调用断言,更新为带语音窗口判据的调用后全仓通过。未做实际麦克风/相机与 Linux portal 实机验证。
c23a2a9:修复开发版独立采集页面无法加载内部协议依赖而反复 10 秒超时。采集页面使用独立 Vite 缓存,两个内部协议包直接走源码解析。实际 Vite 服务 + sandbox Electron 加载真实 capture entry/preload 并完成 register-host;生产 capture 构建、Desktop typecheck、全仓 test:unit:related 通过。未重启个人客户端或进行手机实机连接验收。
e5806b1:Main 对来自当前捕获页面、当前 lease 的输入,仅将控制器的 DESKTOP_VIEW_ONLY 判为丢弃,不再导致共享心跳 DataChannel 关闭;38 项定向测试、Desktop typecheck 与全仓 test:unit:related 通过。未验证实机 PiP 切换时序。
5ad2e35:PiP 续租校验值保留至收到回复,避免 RTT 超过 2 秒时有效回复被不断替换的校验值拒绝。3 项定向测试、Desktop typecheck、全仓
pnpm test:unit:related通过;假时钟覆盖等待 8 秒后回复、收到回复后产生新校验值、旧连接迟到回复不影响新连接。未做实机 PiP 弱网验证。0a23d92:经 Dash 确认,iOS 播放初始化失败时保留桌面连接,暂时无声。39 项界面测试、Mobile typecheck、全仓 test:unit:related 通过,覆盖静音 init/offer、继续控制、声音偏好不变、不重复建 lease、关闭再开启声音后恢复。提示复用操作面板的主题样式,五种语言同步;未做实机音频中断或 Light/Dark 目检。
cefbca1:心跳丢包及首帧竞争修复。49 项定向测试、Desktop/Mobile typecheck、
pnpm test:unit:related(全仓)通过。覆盖连续心跳回复丢失、撤权拒绝、ready/source/offer 三阶段截图排他、原生首帧仍可读取,以及协商成功/超时后恢复截图。未进行实机弱网和双 peer smoke。af028cc:冷启动等待预算修复;
pnpm test:unit:related(自动扩展全仓)、Desktop/Mobile typecheck、device-linkbuild(tsc --noEmit)通过。新增虚拟时钟测试覆盖 54 秒后合法答案仍被接受、停止后无遗留定时器,保留连接超时及旧代次答案拒绝测试。未做实机慢启动验证。4fe4211:退出远程播放先停用 AVAudioSession,再恢复旧配置;仅精确配置匹配时操作,失败保留恢复记录。实际函数体的 Swift stub 行为验证覆盖释放顺序、重复退出、新语音 owner、options 改变及失败重试;Swift parse、Mobile typecheck、test:unit:related(全仓)通过。未做真机其他 App 音频恢复验收。
本地授权入口补齐:41 项定向测试通过,覆盖非可信来源在副作用前拒绝、本地授权/撤销仍可用、账号能力与远程 allowlist 边界;Desktop typecheck 通过。本轮重新执行
pnpm test:unit:related(自动扩展全仓),全部通过;DCO 与 diff check 通过。捕获隔离:Desktop 定向测试覆盖取消期间的 ready/source 迟到、外部和子 frame IPC 拒绝、offer 与 ICE 超时、强制销毁、崩溃/导航/加载失败、旧 owner 迟到、应用采集权限与麦克风兼容。修正模块导入与旧后台节流契约后,相关 132 项测试通过。
实际 Electron 41.10.3:使用生产捕获 bundle、实际窄 preload、实际窗口控制器和自定义协议;只采集合成 WebFrameMain 画面/音频,验证 WebRTC 收到 video/audio tracks。普通页面的 getDisplayMedia 与旧式 desktop getUserMedia 均被拒绝,假麦克风采集正常,dispose 后 webContents 确实销毁。混合麦克风/旧式桌面请求在 Chromium bad-IPC 校验处被拒绝,不将其误记为权限回调的结果。
pnpm --filter desktop exec vite build --config vite.capture.config.ts:捕获入口生产构建通过。pnpm --filter desktop run --if-present typecheck:通过。pnpm test:unit:related与 Git skillrun-unit-gate.sh:全部通过(相关测试自动扩展为全仓);DCO 与 diff check 通过。测试清除
CINDY_AUTH_REGION、VITE_CINDY_AUTH_REGION、XDT_OFFICIAL_SHARED_PROFILE、XDT_DESKTOP_DEV_MODE四项宿主注入变量。此前已验证:macOS helper 原生编译及拒绝/通道重定向/签名资源测试;真实 Developer ID 临时应用调用 helper 的允许与拒绝路径;Swift/TS 剪贴板大小边界对照;Desktop/Mobile 类型检查与相关单测;Windows 两个 Rust 程序的 MSVC 目标交叉检查;实际 NSIS 卸载宏编译。
网络此前通过真实 Chromium 合成回环 smoke,覆盖视频、输入、迟到候选、丢失一次协商回复与媒体恢复。命令:
node --import tsx apps/mobile/scripts/remote-desktop-network-smoke.mjs <chromium-executable>。手工验证
开发期间用户在 iPhone Air 与 iPhone 17 Pro 模拟器体验连接、键盘、鼠标、剪贴板和显示交互。
7cc27a3f9对应源码曾构建 Global iOS Release 内置包并安装到 iPhone Air,启动成功。以上不代表最新提交已重新安装或完成实机验收。未执行的验证
风险
已知非阻塞限制
P2 后续优化:设备 A 改分辨率的原生写入窗口内,若设备 B 刚对同一显示器建立新 lease,随后真实几何通知仍会停止 B 的旧几何连接,需要按新尺寸重新连接。此为已知的短暂重连体验限制,不是跨账号授权绕过,也不重建共享 relay。按 Dash 2026-09-09 的收敛指示,本 PR 不再新增改屏锁或通知屏蔽,后续按实机证据优化;该场景未修复。
已接受的剩余安全风险(2026-09-08)
Dash 在获知两条 review 的具体风险后明确回复:“好的,那我接受这两条风险。你把这两个问题解决掉”。据此将以下讨论按风险接受闭环,不表示漏洞已修复:
本 PR 保留现有终端、文件编辑和 Agent 能力,不增加原生确认框或独立录屏服务;已有捕获隔离、来源校验及风险说明保留。本决定仅接受这两项剩余风险,不构成冷更专项批准、最终 Approve 或合并授权。
风险分类
影响与回滚
捕获隔离状态与故障半径
Main 是捕获窗口的唯一 owner:
absent → starting → active → destroyed。每次媒体 offer 新建窗口,使用独立内存 session、固定页面、独立构建入口和窄 preload;没有预热、隐藏复用或崩溃自动重启。捕获页面不加载聊天/Markdown、不能导航/开窗/下载;CSP 禁止普通 HTTP/WebSocket 连接与子页面,仅保留本地脚本和媒体所需资源。应用 session 拒绝标准及旧式桌面采集,保留物理麦克风/摄像头请求。原生帧读取同样校验 owner、lease 和代次。只结束当前桌面连接,不重建共享 device-link/relay,不影响其它任务;UI 无须配合停止才能撤销采集。
网络、输入和剪贴板不变量
iOS playback 初始化失败仅关闭本次有效音频,不覆盖持久声音偏好,不循环重建桌面 lease;操作面板提示关闭再开启声音重试。失败后尽力恢复原生音频状态,异步迟到按连接代次拒绝。该行为已获 Dash 明确确认;不涉及原生指纹改动。
心跳等待与协商分离:Mobile 续租 invoke 为 5 秒,现有 3 秒 interval 在结算后继续续租;单次超时不替换 live lease,明确拒绝仍停止,连续无回复仍进入既有设备级熔断。晚到旧 lease 错误不得影响新 lease。
捕获 owner:offer 先停止旧原生读取,再由现有 preparingOffer 标记阻止截图回退争抢首帧;成功、异常、取消后恢复截图入口。没有新增采集器、锁、缓存或重试。故障及恢复都限制在当前桌面请求/peer,不重建共享 relay,未改变其它 peer 的授权;双 peer 实机验证未执行。
冷启动协商预算统一由共享常量定义:捕获窗口就绪、Windows 服务状态/管道探测、屏幕枚举和媒体 offer 的串行上限共 54 秒,invoke 预留到 59 秒,手机答案等待到 61 秒;收到答案立即继续。仅调整单次桌面请求等待,不重建共享 relay、不增加重试次数、不影响其它 peer 的授权。旧端仍保留旧等待预算,需更新控制端才能获得完整慢启动改善。
单 active lease + generation;相同 peer/display 的 resume 可以轮换自己的 lease,其它连接保持 busy,需用户显式接管。停止/撤权后旧端不能自动抢回;输入序号随新 lease 重置,异步结果再次校验身份和代次。
lease 管授权,attemptId 管媒体连接,exchangeId 管 ICE 交换。双方声明增量能力才补发候选,旧端用完整 SDP;每批最多 16 个、每次最多 128 个。短断线宽限 5 秒,媒体重试 1/3/8 秒,稳定 30 秒后恢复预算;恢复不重取 lease、不接管、不重启共享连接。
截图中转统一执行 180 KB 上限;枚举有界等待,不能取消底层 Electron 调用时丢弃迟到结果。失败只作用于单帧/当前请求,不拆另一 peer 的活动桌面。
剪贴板只传便携文本/HTML/RTF/PNG。文件混合项目已有内联图片时只传 PNG,不读取路径;文件-only 拒绝。单个临时传输上限为 32 Mi UTF-16 字符,成功分片刷新既有 60 秒空闲计时,无效请求不续期;commit 先消费缓冲,失败不重放粘贴。Swift 与 TS 使用同一字符长度语义;PNG 像素/字节限制保留。
Windows 卸载仅在服务不存在或停止并删除成功后继续;UAC 取消、失败或超时保留文件。普通 per-user 安装无服务时不提权;旧版本已生成的卸载器不会被新宏追溯修改,首次升级可能需管理员身份。
提交前检查
git commit -s)本轮原生音频修复指纹比较(同环境 @expo/fingerprint 0.20.10):iOS 9812b3e3d51db506a2984453dfdb93f3c0417ccb → 297fc25b6ace29785d45720b4617ccfc8470743a;Android a6c6f787bb1eeb96f6b6cb485a33bfc7a4a957a2 不变。需随本 PR 冷更出包,不能仅 OTA;正式发版仍以 release check 和指定把关人批准为准。
PiP 心跳不变量:仅有一个未回复的校验值,收到匹配回复后才允许发送下一个;原有 host lease 限制无回复时长,停止及换连接沿用原有定时器清理与 generation 隔离,无新增重试或缓存机制。
画中画输入/续租不变量:控制器仍是控制权限唯一判据;本地 capture INPUT 的只读拒绝不终止观看,成功或重复输入保持原有处理。无效来源、旧 lease、停止/过期及其他输入错误仍拒绝;relay input/clipboard 的权限错误不变。心跳继续独立验证 lease,停止/替换仍由既有 generation 和 host 销毁隔离,无新队列或排空机制。
权限/截图边界:窗口身份复用现有注册判据,无新权限注册表;两个 session hook 均校验当前顶层 URL,未列出的权限默认拒绝,独立捕获 session 不变。仅截图源枚举的 DESKTOP_VIDEO_TIMEOUT 降为本帧暂缺,offer 超时与租约/权限终态保持原行为;返回空帧后控制器仍校验当前授权,不能用超时绕过撤权。
转换收敛不变量(7939926c8):画中画收到宿主确认后才禁用输入;不确定的失败仅释放原 lease 并复用现有恢复,迟到响应不修改新 lease。分辨率复用原有停止动作,在枚举/构建之后、原生写入之前同步校验原 lease/控制代次/授权并释放旧几何;完成后不再检查已主动释放的 lease,也不停止替代连接。保留显示移除/几何变更监听,不增加通知屏蔽、计时器或状态机。故障半径均是当前桌面请求/lease,共享 relay 不变;回归覆盖另一控制端的替代 lease 不受旧完成影响。