ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Maka 逆向工程实录:从 Codex 二进制反汇编到 Electron 画中画镜像的实现移植

Maka 逆向工程实录:从 Codex 二进制反汇编到 Electron 画中画镜像的实现移植 Maka 逆向工程实录从 Codex 二进制反汇编到 Electron 画中画镜像的实现移植【免费下载链接】makaApache Maka (Incubating) is a high-performance agent workspace that keeps a complete record of everything it did.项目地址: https://gitcode.com/GitHub_Trending/mak/makaMakaApache Maka, Incubating的 Computer Use 功能在驱动后台窗口时需要一个画中画Picture-in-PicturePiP镜像窗口来实时展示 Agent 正在操作的目标。本文完整记录了 Maka 团队如何对 Codex 的 PiP 窗口实现进行二进制级逆向工程——从sky.node原生插件和 XPC 服务反汇编中恢复窗口结构、弹簧运动常量与交互算法再逐条移植到 Electron 主进程并刻意在四个设计点上做出差异化选择。读完本文你将掌握一套从反汇编取证 → 行为实验验证 → 源码级移植的完整方法论以及 Maka PiP 镜像pip-window.ts pip-motion.ts从窗口语义到运动物理的全部实现细节。逆向工程概述从两份二进制工件到完整行为模型本文档codex-pip-reverse-engineering.md的核心立场是确认的原生事实confirmed native facts与实现推断implementation inference必须分开记录。这一点与仓库中另一份取证文档 computer-use-cursor-provenance.mdAgent 光标溯源采用同样的方法论——每个移植的常量都附上来源与反汇编出处未经验证的猜测绝不混入事实层。逆向工程的产出物分三类类别内容证据来源Confirmed确认事实面板属性、类结构、弹簧常量、抛出算法、尺寸/缩放/控件反汇编逐条读出Measured实测事实Electron 43 上的基线行为真机行为实验Inference实现推断阻尼比 ζ 的物理含义、设计取舍动机由常量推导这种分层保证了移植代码可以被审计任何后续维护者都能从 pip-motion.ts 的常量注释一路追溯到二进制里的某条指令。检查的工件为什么只查一半是致命的逆向对象是两个进程而两者之间的分工比任何单一个体都重要路径职责service~/.codex/computer-use/Codex Computer Use.app/Contents/MacOS/SkyComputerUseService采集与发布capture and publish半边host/Applications/ChatGPT.app/Contents/Resources/native/sky.node窗口window半边main JS/Applications/ChatGPT.app/Contents/Resources/app.asar→.vite/build/main-Be_0DBuv.js宿主注册service 半边包含RemoteHostedPIPContentPublisher、RemoteHostedPIPCaptureStream、CUAServiceRemoteHostedPIPController等类链接了 AVFoundation 与 ScreenCaptureKit并使用AVSampleBufferDisplayLayer——但没有链接 AVKit。它只负责通过 XPC 捕获与发布帧并不承载窗口。真正的窗口生活在 ChatGPT 自己的原生插件sky.node中属于PIPStack*类族。文档特别警告了一个认知陷阱如果在 service 里搜不到窗口符号就断定窗口不存在是错误的。类名中的RemoteHosted前缀本身就说明另一半在另一个进程里——必须在得出结论前先找到那个进程。这个原则先确认另一半存在再下缺失结论是本文档存在的部分原因。Confirmed面板Panel——setLevel: 0与addChildWindow:是设计支点从RemoteHostedPIPContentCreateStackPanel的反汇编中逐条读出面板创建序列NSPanel initWithContentRect:… styleMask:0x80 // NSWindowStyleMaskNonactivatingPanel backing:2 defer:NO setTitle: setBackgroundColor: [NSColor clearColor] setOpaque: NO setHasShadow: NO setLevel: 0 // NSNormalWindowLevel — 刻意不置顶 setAcceptsMouseMovedEvents: YES setCollectionBehavior: 0x108 // FullScreenAuxiliary | Transient setHidesOnDeactivate: NO setMovableByWindowBackground: NO // 拖拽是手写的见下文随后从-[PIPStackWindow attachToOwnerWindowForPositioning]调用addChildWindow:ordered:。支撑整个设计的是两个事实setLevel: 0NSNormalWindowLevel——刻意不浮动floating。镜像窗口不应悬浮在所有无关应用之上。addChildWindow:——子窗口相对于父窗口排序而非相对于桌面排序并且随父窗口在同一次 window-server 事务中一起移动。这两个选择在 Electron 端的对应实现见 pip-electron.ts 的pipWindowOptionsfocusable: false对应 nonactivating panel 的焦点契约、hasShadow: false原生阴影由pip.html自绘、以及parent: parent as BrowserWindow——只有在找不到应用窗口时才退化为alwaysOnTop: true。Confirmed类结构Structures——PIPStack 家族与窗口服务器的分工PIPStackHost { hostID, ownerWindow, anchorContentRect, anchors[], presentationScope } PIPStackHostAnchor{ contentPoint, alignment } PIPStackWindow attachToHost: / startFollowingOwnerWindow / ownerWindowFrameMayHaveChanged: PIPStackController drag beginDragAtContentPoint: → dragToContentPoint: → endDrag snap nearestTargetAnchorForCurrentAnchor:draggingVelocity: → moveStackToAnchorAlongCurve: motion configureMotionSpringsWithLeadItem:dragging:programmaticMove: hosts moveStackToHostID: / compatibleAnchorsIncludingDragHosts: clamp clampEnvelopeToVisibleScreen: PIPStackItemMotion{ springStiffness, springDamping, velocity, target, origin, restOffset } PIPStackContentView reinstallMouseEventMonitors → addGlobalMonitorForEventsMatchingMask:handler: addLocalMonitorForEventsMatchingMask:handler: updateHoverFromCurrentMouseLocation / contentPointForCurrentMouseLocation关键洞察来自ownerWindowFrameMayHaveChanged:它读取notification.object并比较notification.name说明它是一个针对宿主窗口移动/缩放的通知处理器。它只负责重算锚点recompute the anchor不移动窗口——移动由 window-server 完成因为面板是子窗口。Maka 的移植对应物是 pip-window.ts 中subscribeAnchorChanges订阅回调的注释逻辑只有 resize 被响应move 被刻意忽略。因为子窗口随父窗口在同一次事务中移动若再在此处重定位既冗余又落后一帧——那一帧的滞后正是此前拖动时镜像拖尾trailing的根源。Confirmed常量Constants——弹簧、抛出、尺寸与缩放的逐条复原弹簧两组四列的fcsel从configureMotionSpringsWithLeadItem:dragging:programmaticMove:反汇编出一个cmp w26, #0后跟四个fcsel即两列四组常量非拖动settling拖动dragginglead stiffness主项刚度320900lead damping主项阻尼4255follower stiffness base跟随项刚度基准150260follower damping base跟随项阻尼基准3032跟随项的值分别除以1 0.18·s与1 0.08·s其中s |index| · (1 0.45·|index|)是索引衰减因子。阻尼比是这些数字而非其他数字的原因非拖动时 ζ ≈ 1.17略过阻尼窗口永远不会越过目标角回弹拖动时 ζ ≈ 0.92略欠临界指针拉动时窗口保留一丝韧性。Maka 只有一个镜像没有堆叠所以只使用 lead 列follower 衰减没有适用对象——这一判断直接写在 pip-motion.ts 的注释里。在 Maka 中这两组常量以PIP_SPRING形式定义并由stepSpring半隐式 Euler 积分每轴独立驱动。选择半隐式而非显式 Euler 的原因也在注释中交代显式形式在大dt下会增益能量——掉一帧就会让镜像飞走而不是迟到这是动画绝不能出现的失败模式。同时dt被钳制在1/30秒以内因为后台窗口可能给你数秒的间隙没有任何弹簧能在那种步长下保持稳定。springAtRest用半像素内且速度低于每秒半像素判定到达见 pip-motion.ts。抛出Throw0.55 的比例与点积评分从nearestTargetAnchorForCurrentAnchor:draggingVelocity:恢复的算法throw velocity * 0.55 t min(|throw| / 5000, 0.45) target currentAnchor unit(throw) * t score(a) |a.point − target| − |throw| · max(0, dot(unit(throw), unit(a.point − current))) pick min score另有独立阈值hypot(velocity) 120决定其他宿主上的锚点是否进入候选集。0.55 是窗口飞向你扔的方向与窗口飞向你指的方向之间的差别——只有前者有重量感。点积项则让一次有意的跨窗抛出落在瞄准的位置单靠距离只会选到你正在离开的那个角。Maka 移植在 pip-motion.ts 的pickPipAnchorPIP_THROW_SCALE 0.55、PIP_THROW_REFERENCE 5000、PIP_THROW_MAX 0.45。值得注意的差异化处理Codex 的hypot(velocity) 120阈值被刻意不移植——它用于门控其他显示器上的锚点是否候选而 Maka 的四个锚点是同一宿主窗口的四角没有跨屏候选可门控慢速释放本身已读作放置而非抛出其覆盖距离趋近于零最近角凭距离即可胜出源码注释还记录了一个讽刺的细节该阈值曾移植过一次没有任何读者且断言把字面量和自己比较。尺寸默认 200pt钳制 [100, 400]内边距 24pt默认最长边 200pt钳制到 [100, 400]通过缩放到较短边保持宽高比锚点内边距 24pt。三个边界就是二进制中的字面量双精度浮点0x4069…、0x4059…、0x4079…。Maka 以PIP_MIN_EDGE/PIP_DEFAULT_EDGE/PIP_MAX_EDGE/PIP_MARGIN定义在 pip-motion.ts尺寸计算pipDisplaySize在 pip-electron.ts按长边等比缩放非有限值回退默认。缩放Resize四条指令的垂直手势-[PIPStackResizeInteraction maxDisplaySizeForPointerScreenPoint:]只有四条指令sign (alignment ~1) 2 ? 1 : -1 size initialMaxDisplaySize (pointer.y - initialPointer.y) * sign只有垂直分量驱动缩放符号由镜像所靠的角决定因此手势在任何角落读起来都一样远离锚点即放大。交互保持开始时的边与指针高度不做任何增量累加——抖动指针无法累积漂移。Maka 的pipResizeEdgepip-motion.ts等价实现并补上了 CodexsnapPointToBackingScale:同样的整数化理由透明窗口上的分数像素边缘会闪烁。控件三个标识符减为一个performControlWithIdentifier:接受stop、hide、closesetHoveredControlIdentifier:与_pressedControlIdentifier驱动外观。实测基线写任何代码之前在 Electron 43 上测量结果documentPictureInPictureundefined加不加--enable-featuresDocumentPictureInPictureAPI都是子窗口 父窗口移动子窗口自动跟随零代码同一事务子窗口 父窗口缩放子窗口不动——锚点需要重算子窗口isAlwaysOnTop()false子窗口焦点从不抢焦点向点击穿透窗口注入鼠标事件可送达但被合并且丢包——5 个中 2 个随后 5 个中 1 个这些测量直接定义了 pip-window.ts 的设计注释alwaysOnTop默认floating级别会把镜像放到所有应用之上在每次move时重定位则让第二个事务比拖动落后一帧产生可见拖尾——子窗口排序解决前者子窗口定位解决后者。关于 Document Picture-in-Picture它不仅是在 Electron 中被禁用其实现位于 Chromium 的//chrome浏览器层PictureInPictureWindowManager而 Electron 根本没有这一层。这条路是关闭的而不是变窄的。Maka 复制了什么应用窗口的子窗口普通层级。镜像最初的两个缺陷——浮在无关应用之上、拖动时落后一帧——同源于一个根因镜像自己定位而不是被父窗口携带。hasShadow: false。pip.html自绘阴影原生阴影会由 window-server 根据内容 alpha 在每一帧落地时重新计算——而这正是那个每帧都收到新帧的窗口。200pt 默认边、[100, 400] 钳制、24pt 内边距。弹簧常量、抛出投影与锚点评分全部实现在 pip-motion.ts每个常量旁边都引用了反汇编。hover 由主进程侧指针决定因为这正是 Codex 的 global/localNSEventmonitor 所做之事——它从不询问窗口指针是否在内部。Electron 没有全局鼠标监视器Maka 用 20Hz 轮询scheduleHoverCheck替代见 pip-window.ts 与watchHover。只对 resize 做出反应。move 是 window-server 的职责。五处Maka 刻意不同及其理由两个控件而非三个Codex 的close关掉一块 tile、hide关掉整个栈。Maka 一次只镜像一个窗口两者是同一手势只有一个配得上按钮。PipControlId stop | hide见 pip-window.ts。指到才响应点击click-through until pointed atCodex 的 tile 总是吃掉点击——acceptsFirstMouse:返回 YEShitTest:声明整个视图。但 Codex 的 tile 是可选功能设置文案为 Show backgrounded apps that Computer Use is working on in Picture-in-Picture modeMaka 的镜像在每次 run 开始时就会出现必须做到不打扰才值得存在。因此用setIgnoreMouseEvents(true, { forward: true })——鼠标移动仍然送达主进程可以判断何时收回点击权。setPointerInside逻辑见 pip-window.ts。没有堆叠Codex 用 lead item followers 镜像多块 tilefollower 弹簧列及其索引衰减在单镜像场景无的放矢。抓手grip随控件一起出现Codex 的缩放把手属于同一套 hover 镀铬静止时 tile 不携带任何常驻把手。Maka 同理——200pt 的小窗口承担不起常驻交互元素。帧序列flipbook而非视频流Codex 通过 ScreenCaptureKit 跨 XPC 流式传输。Maka 完全不需要每个改变状态的 Computer Use 动作已经返回目标窗口的截图在 settle 等待之后捕获因此展示的是稳定后的结果动作完成时帧已在手镜像只是 post-action 帧的翻页簿零额外采集成本。这条通路在 pip-feed.ts 中实现——withComputerUsePip包装 cursor 的onActionEnd钩子消费每次动作返回的截图含语义动作光标自身的onActionEnd反而因无结束坐标而跳过它们并把光标坐标从屏幕坐标经窗口缩放换算进截图像素。代价是真实且刻意的动作之间镜像不更新——足够看到 Agent 在做什么而这正是它的目的。没有跨宿主移动moveStackToHostID:在宿主窗口之间移动栈——Codex 注册了多个宿主包括avatar-overlay。Maka 只有一个窗口无可移动之物。跨显示器天然成立因为镜像是应用窗口的子窗口父窗口去哪它去哪。验证真机 smoke 与可精确测试的物理层真窗口集成测试scripts/pip-interaction-smoke.mjs 运行真实链路真实父窗口、真实子面板、真实 preload 与 renderer、真实输入事件。它断言子窗口属性不置顶isAlwaysOnTop() false、不抢焦点、getParentWindow() parent座席位置应用窗口右下角、内缩 24pt随父窗口移动被携带移动 160px 后断言跟随hover 出控件主进程侧指针移动触发controls可见一次抛出落在瞄准的锚点上左上角且控制器currentAlignment()一致应用窗口 resize 后回到用户选中的角而非默认角grip 拖拽放大实测 200x160 → 290x232宽高比保持、仍在角上、在钳制范围内且 grip 位于锚点对角——这个断言修复了一个真实 buggrip 曾钉死在 CSS 的左上角只有默认的右下锚点对齐把镜像扔到左上角后指针在拖拽第一个像素就脱离抓手hide 控件收起镜像pip.isVisible() false。它不需要辅助功能权限、不需要解锁屏幕——只驱动 Electron 窗口——因此在其他真机检查无法运行时它是唯一可持续的真机检查。文件头还记录了运行前置npm --workspace maka/desktop run build:main npm --workspace maka/desktop run build:overlay npx electron scripts/pip-interaction-smoke.mjs。脚本中值得学习的两处工程细节settled()轮询要求连续 6 个相同采样才算静止过阻尼弹簧的收尾段每帧移动不足 1 点两个连续读取可能因取整相同而误判到达拖拽夹具用三个递进采样点保证释放时被读作抛出而非放置。物理层单元测试的现状物理与锚点评分原本由apps/desktop/src/main/__tests__/computer-use-pip-motion.test.ts覆盖无需桌面环境PR #2478 删除了该测试文件只结束了它提供的覆盖——没有替代品。但被测模块本身未受影响pip-motion.ts在 #3293 光标替换#3456 实现重建了 Agent 光标引擎与字形——包括 PiP 字形前后字节级一致上文转录的拖动/落位弹簧与抛出系数仍在那里定义仍驱动着pip-window.ts。文档同时划清了边界光标溯源记录在 computer-use-cursor-provenance.md只涉及 Agent 光标PiP 窗口的运动模型是独立表面没有需要记录溯源变更。方法论总结可复用的逆向-移植流程先分进程再下结论RemoteHosted前缀 另一半在另一个进程找不到符号 ≠ 功能不存在。事实分层confirmed反汇编逐条读出/ measured真机行为实验/ inference由常量推导的动机三层永不混淆。常量带出处移植每个数字在源码注释中附上反汇编来源后续维护者可审计。用真实窗口冒烟测试锁定行为单元测试证明物理与状态机smoke 测试证明 Electron 集成二者互补。差异化而非照搬Codex 的多 tile 栈、无条件点击、视频流等设计在 Maka 单镜像场景下各有明确的不适用理由——每处差异都写明了为什么。这套流程沉淀在 pip-motion.ts纯逻辑、可精确测试、零 Electron 依赖、pip-window.ts控制器与状态机、pip-electron.tsElectron 边界、pip-feed.ts帧来源四个文件与 pip-interaction-smoke.mjs 一个真机验证脚本中构成 Maka Computer Use 镜像的完整证据链。【免费下载链接】makaApache Maka (Incubating) is a high-performance agent workspace that keeps a complete record of everything it did.项目地址: https://gitcode.com/GitHub_Trending/mak/maka创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表