构建 antigravity-with-chatgpt:双脑协同架构与对抗审查实战
记录今天从零设计并重构 antigravity-with-chatgpt 的完整工程历程。涵盖纯原生四层架构设计、毫秒级 DOM 注入与 FNV-1a 指纹校验、User Turn 因果强收据提交状态机、跨平台反斜杠字符身份防御,以及基于 Chrome CDP 与 ChatGPT 实机对抗性审查最终达成 [APPROVED] 的闭环实践。
在当下的 AI Agent 辅助编程实践中,本地 Agent(例如 Google Antigravity 2.0 IDE、Gemini CLI、Claude Code)具备极高的本地操作权限,能够自如地读写文件、执行 Shell 终端命令、启动单元测试并管理 Git 仓库。但在面对高难度的复杂系统重构、深奥算法推导、疑难故障根因定位以及严苛的代码审查时,单模型在自身单一上下文内容易陷入逻辑自洽与验证盲区。
社区优秀的先驱项目(如 XiaoDuoYa/codex-with-chatgpt)展示了将“本地执行 Agent”与“云端高阶推理模型”清晰分工的协同潜力。今天我将这套思路推进到了 Google Antigravity 2.0 环境中,构建了 antigravity-with-chatgpt。
本文完整记录今天构建该桥梁的整个工程演进历程,包括通信架构选型、超大 Prompt 传输瓶颈攻关、提交状态机因果性重构、跨平台文件字符身份防御,以及通过实机 CDP 隧道与 ChatGPT 开展数十轮对抗性闭环审查并最终获得 [APPROVED] 裁决的全过程。
1. 架构目标与技术选型
整个项目的核心诉求是建立双脑协同:
- 本地 Agent 负责确定性执行(Execution):代码修改、终端调试、测试运行与版本控制均由本地 Antigravity 2.0 完成。
- 云端 ChatGPT 负责高阶推理与验证(Reasoning & Review):高阶架构规划、算法公式推导与对抗性代码审查均委托给 ChatGPT 网页版。
- 复用个人已登录会话:通过本地 Chrome DevTools Protocol(CDP 端口
9222)接入独立浏览器 Profile 中已登录的个人 ChatGPT 网页版(Free / Plus / Pro),无需单独申请受限的商业 API Key。 - 坚持零第三方运行时依赖:生产依赖项保持完全为 0(
dependencies: {}),全部采用 Node.js 22+ 原生标准库实现,避免引入庞大的node_modules依赖树与安全攻击面。
整体系统划分为清晰的四层架构:
┌─────────────────────────────────────────────────────────┐
│ Antigravity 2.0 / Gemini │
└───────────────────────────┬─────────────────────────────┘
│ JSON-RPC 2.0 stdio / CLI
┌───────────────────────────▼─────────────────────────────┐
│ 1. 接入层 (scripts/) │
│ - ask_chatgpt.mjs: 命令行交互入口 │
│ - mcp_server.mjs: Antigravity 2.0 原生 MCP 服务 │
│ - setup.mjs: 跨平台一键自动化配置脚本 │
├─────────────────────────────────────────────────────────┤
│ 2. 调度与协议层 (src/brain/) │
│ - orchestrator.mjs: Proxy-Pull 上下文经纪人 │
│ - prompts.mjs: 5 大专业模式结构化信封 │
├─────────────────────────────────────────────────────────┤
│ 3. 数据面与安全审计层 (src/security/, src/workspace/) │
│ - path_guard.mjs: 原生相对路径收敛与 Symlink 防护 │
│ - sensitive.mjs: 密钥正则掩码与 .env 阻断 │
│ - ignore.mjs: .brainignore 规则解析器 │
│ - context_provider.mjs: 只读文件切片与工作区提取 │
│ - git_helper.mjs: 只读 Git 状态与预算约束 Diff │
│ - recorder.mjs: 本地命令执行与测试证据记录器 │
├─────────────────────────────────────────────────────────┤
│ 4. 传输层 (src/transport/) │
│ - cdp_transport.mjs: 零依赖原生 CDP 驱动 (端口 9222) │
│ * AsyncMutex 单飞行并发排队隔离 │
│ * Base64 快速 DOM 注入 │
│ * FNV-1a 双端同构哈希指纹校验 │
│ * User Turn 递增因果收据判定 │
└───────────────────────────┬─────────────────────────────┘
│ Chrome DevTools Protocol
┌───────────────────────────▼─────────────────────────────┐
│ 独立 Profile Chrome 实例 (127.0.0.1:9222) │
│ └── ChatGPT 网页版 (https://chatgpt.com/) │
└─────────────────────────────────────────────────────────┘
2. 毫秒级 DOM 注入与输入性能瓶颈
在通过 CDP 与网页版 ChatGPT 交互时,传统自动化方案通常使用逐字符派发输入事件(如 Puppeteer 的 page.type())。当传输大段架构说明或几千行代码时,逐字触发事件需要耗费数分钟,且极易导致页面卡顿崩溃。
我们采用的初始注入策略是:在 Node.js 端将待输入的 UTF-8 文本转换为 Base64 编码,通过 CDP Runtime.evaluate 注入一小段浏览器端代码,在浏览器内存中完成 Base64 解码,随后直接调用 document.execCommand('insertText', false, decodedText)。这套方案能够直接被 ChatGPT 的 ProseMirror 富文本编辑器捕获,万字长文在 5 毫秒内即可完成写入。
然而,随着后续引入代码审查模式,审查 Prompt 中需要挂载真实 Git Diff、CI 执行日志与多个源码切片,Prompt 总体积迅速膨胀至 20KB 到 50KB。在注入此类超大文本时,我们遇到了新的稳定性挑战:
- 主线程瞬时计算过重:ProseMirror 对超长文本建立文档节点树时会短暂占满浏览器主线程。
- 固定超时机制失灵:原先设置的 25 秒
Runtime.evaluate调用可能触发 CDP 超时异常。 - 假失败陷阱:CDP 超时抛错时,浏览器内部的注入操作实际上可能已经完整结束,文本已妥善停留在输入框中。盲目发起二次重试会导致相同内容被连续追加两次,造成严重的 DOM 混乱。
3. 大文本传输可靠性加固:阶梯超时与 FNV-1a 指纹校验
为了根治大文本注入时的偶发超时与误重试问题,传输层进行了专项升级,引入了两项核心技术:
自适应阶梯超时(Adaptive Timeout Ladder)
摒弃原先单一的固定超时阈值,依据待注入文本的字节长度动态计算合理的等待窗口:
export function getInjectionTimeout(byteLength) {
if (byteLength < 5000) return 20000; // 20s
if (byteLength < 20000) return 35000; // 35s
if (byteLength < 50000) return 60000; // 60s
if (byteLength < 100000) return 90000; // 90s
return 180000; // 180s
}
梯级阈值为复杂页面的文档重排留出了充裕的弹性缓冲。
FNV-1a 双端同构哈希指纹验证
单靠拉长超时时间不能保证极端情况下的幂等性。我们需要一种轻量、确定且同构的校验算法,在 Node.js 端与浏览器内运行完全一致的逻辑。
我们选用了 FNV-1a 32 位哈希算法。在文本注入之前,Node 端预先计算出该文本的字符长度与十六进制指纹:
export function computeFingerprint(str) {
let hash = 0x811c9dc5;
for (let i = 0; i < str.length; i++) {
hash ^= str.charCodeAt(i);
hash = Math.imul(hash, 0x01000193) >>> 0;
}
return {
charLength: str.length,
hashHex: hash.toString(16).padStart(8, '0'),
};
}
当 Runtime.evaluate 发生超时时,系统不立刻认定失败,而是迅速向浏览器下发一段轻量的探针脚本,提取输入框当前纯文本的 FNV-1a 指纹。
若探针回报的字符长度与哈希值与 Node 端的预期值完全一致,表明文本已经完整注入成功,系统直接消除超时错误并推进到提交步骤。仅在指纹不匹配(例如输入框内容被截断或为空)时,系统才执行清空操作,并受控重试唯一一次。这套机制彻底保障了超大内容注入的幂等性。
4. 提交状态机演进:建立 User Turn 因果强收据
输入内容后,如何准确判定消息已被网页成功提交?
早期实现中往往通过轮询页面是否存在“停止生成按钮”(Stop button)或是否存在流式输出元素来判断。这种做法存在显著的逻辑漏洞:
- 若用户是在已有历史会话中追加提问,上一轮对话遗留的 DOM 状态可能导致探针过早产生假阳性判定;
- 发送按钮在某些网络波动下处于禁用态时,回车事件会被静默忽略,但外层程序因超时而误判状态。
为了实现真正的状态机闭环,我们将提交判定升级为基于回合因果性的强收据机制(Causal Turn Receipts):
- 基准采样:在按下发送键前,首先探测当前页面中用户对话气泡(User Turns)的实际数量
beforeUserTurns。 - 状态跳转触发:模拟回车并点击发送按钮后,高频轮询用户对话气泡的数量。
- 强收据认定:只有当明确观测到气泡总数产生严格递增(
currentUserTurns > beforeUserTurns)时,状态机才跳转至SUBMITTED终态。 - Fail-Closed 保护:若在等待周期内未捕获到用户回合数递增,状态机一律返回
UNKNOWN状态。此时系统严格禁止盲目重新点击发送,而是抛出明确的异常终止流程,防止单次请求被重复发送多次。
5. 安全防御纵深:脱敏重叠窗口与 POSIX 路径字符身份
作为打通本地特权 Agent 与外部 Web 服务的桥梁,数据安全边界至关重要。本次开发中重点解决了两个深层安全与正确性隐患:
跨分页边界的敏感凭据脱敏
在代码审查模式下,系统通过 Git 分页提取变更差量。如果一段包含私钥或 API 密钥的文本恰好被分页切片切断在缓冲区边界处,普通的全局正则脱敏会因为无法匹配完整前缀而失效。
我们在 git_helper.mjs 中构建了滑动重叠上下文窗口:在按页读取 Git Diff 时,当前切片的开头保留上一页末尾的重叠边界区域统一送入脱敏管道,确保无论敏感凭据跨越在哪个字节位置,都能被完整识别并替换为 ***REDACTED***。同时,未跟踪文件的证据提取将 Markdown 代码围栏、元数据头部以及截断标记统一计入总字节预算(Byte Budget),防止预算超额溢出。
POSIX 文件系统下的反斜杠字符身份防御
在构建按需证据读取(readFileSafe)与审查清单规范化(canonicalizeManifestPath)时,我们经历了一场关于跨平台路径语义的深度排查。
起初,路径规范化逻辑为了杜绝目录逃逸,在相对路径判断中包含了这样的硬编码校验:
// 早期有缺陷的写法:
if (rel.startsWith('../') || rel.startsWith('..\\')) {
return null;
}
在 Windows 系统下,\ 是标准的路径分隔符,..\foo 确实代表向上一级目录逃逸。但在 POSIX 系统(Linux 与 macOS)中,反斜杠 \ 只是一个普通的合法文件名字符。在 Linux 工作区内,一个名为 ..\foo 的文件是合法且物理存在于当前目录内的独立文件。
上述硬编码导致 POSIX 环境下任何包含反斜杠前缀的合法文件被误杀拦截。
我们将其修正为严格遵循平台原生分隔符的段敏感检测:
// 修正后的跨平台原生写法:
if (!rel || rel === '.' || rel === '..' || rel.startsWith(`..${path.sep}`) || path.isAbsolute(rel)) {
return null;
}
在 POSIX 环境下 path.sep 为 /,因此 ..\foo 被正确识别为当前目录内的合法文件名;在 Windows 环境下 path.sep 为 \,..\foo 会被精确识别为父级逃逸并予以拦截。
此外,我们在证据拉取解析函数 parseEvidenceRequests 中移除了对请求路径的提前 .trim() 操作,确保路径在从 AI 输出标签、清单匹配到底层物理读取的整条链路中,字符与字节身份始终保持严格一致,杜绝了由于首尾空格归一化导致的 Confused-Deputy 权限混淆漏洞。
6. 让 ChatGPT 充当严苛的审稿人:数十轮对抗性闭环审查
在整个研发过程中,最具工程趣味的环节是:我们直接利用该项目自身的 CDP 传输通道,将每一次代码提交打包成 Diff 发送给 ChatGPT 网页版,由它作为独立且严苛的第三方代码审查员对本项目进行 Code Review。
我们在审查 Prompt 中明确注入了“反阿谀奉承契约”:
“Critical: Do not simply agree with or flatter the author. Independently verify the attached real Git Diff and execution records: Correctness, Side Effects & Regressions, Security & Boundaries, and give explicit [APPROVED] or [CHANGES REQUESTED].”
这种机制迫使每一次迭代都必须拿出确凿的工程证据:
- 审查阶段一(v2.1.3 ~ v2.1.6):ChatGPT 连续指出了大文本 evaluate 超时误判、未跟踪文件预算记账漏计外层标签、以及滑动分页时可能存在的越界截断风险。我们逐项完善了 FNV-1a 指纹与全额预算记账。
- 审查阶段二(v2.1.7 ~ v2.2.0):ChatGPT 指出 Git status 解析在遇到合并冲突(7 种 conflict 状态)与文件名含空格时的健壮性不足。我们将解析层全面重写为
git status --porcelain=v1 -z,引入八进制 UTF-8 转义解码与表驱动冲突状态映射。 - 审查阶段三(v2.2.1):针对空格路径身份一致性进行了重构,通过了 P1 审查,但 ChatGPT 在独立复现时敏锐地指出了前文提到的 POSIX 反斜杠文件名误判缺陷,直接打回并给出了
[CHANGES REQUESTED]。 - 审查终审(v2.2.2):我们在
v2.2.2中落地了基于原生path.sep的段敏感逃逸重构,并在测试套件中增加了 Linux/macOS 下物理创建..\foo文件的全闭环读取端到端测试。
当最后一份审查 Prompt 发出后,ChatGPT 给出了终审裁决:
=== ChatGPT Review Verdict (v2.2.2) ===
Verdict: [APPROVED]
I found no blocking correctness, regression, or security issue in cbb542a.
The actual GitHub commit is cbb542ab21640fa27e4e74b0433a210c078506da...
1. Correctness — PASS
2. Regression / side-effect review — PASS
3. Test quality / closed-loop verification — PASS
4. Security boundaries — PASS
5. CI evidence — VERIFIED
Final verdict: [APPROVED] — the previous P2 blocker is resolved, the change does
not introduce an observable traversal regression, and the POSIX physical-file
evidence path is covered end-to-end.
这种由被构建工具本身驱动的、面向外部大模型的对抗性审查,极大程度消除了开发者的认知盲区与自我偏见。
7. 自动化安装、多平台 CI 与 Release 发布
在确认核心代码全部达标后,我们对项目的易用性与发布工程化进行了闭环收尾:
一句话让 AI 帮忙安装
在 Agent 辅助编程时代,用户往往不需要手动复制 Bash 脚本去终端执行。我们编写了全自动跨平台配置脚本 scripts/setup.mjs,并在项目文档顶部提供了面向 AI Agent 的一键接入 Prompt:
帮我接入 antigravity-with-chatgpt:克隆 https://github.com/dreamfarer-space/antigravity-with-chatgpt.git 并执行 node scripts/setup.mjs 完成环境配置与自检。
Antigravity 2.0 收到这句指令后,能够自动完成代码克隆、MCP 服务全局挂载(~/.gemini/config/mcp_config.json)、Skill 软链接建立、Windows 桌面专属 Profile 快捷方式生成以及 37 项架构自检。
自动化跨平台 CI 矩阵
我们在 GitHub Actions 中配置了完整的测试矩阵:
- 操作系统:Ubuntu Latest, macOS Latest, Windows Latest
- Node.js 环境:Node 22.x, Node 24.x
6 个矩阵任务全部执行对抗性安全测试套件(67 项)与架构自检套件(37 项),连续多次 Commit 均实现 6/6 全绿通过。
正式发布 Release v2.2.2
随后我们在仓库打上了 Git 标签,并通过 GitHub CLI 正式发布了项目的第一个生产版本:
本文由 择梦舟 执笔撰作,收录于 Zemengzhou Space。
Discussion
Comments
Share questions, corrections, or extra notes about this post.