1实现原理 · 为什么它能做到
它不用 Playwright/Puppeteer,而是驱动一个真实 Chrome(CDP 连接),让 X 看到的是普通浏览器会话;脚本负责把内容填进真实 UI,发布动作留给用户或 --submit。
Uses real Chrome with CDP to bypass anti-automation.
发图的第一手段不是 CDP 合成事件,而是真实系统级 Cmd+V 键击:先把图片写进系统剪贴板,再让 osascript/xdotool/ydotool 向 Chrome 窗口发粘贴键,CDP 合成事件只作兜底。
Sends real Cmd+V keystroke to Chrome, bypassing CDP's synthetic events that X can detect
常规贴/视频/引用/长文四条路径共用同一套 Chrome 层:解析或复用调试端口、共享 profile、注入文本用 execCommand('insertText') 或 Input.insertText,上传用 DOM.setFileInputFiles 直接塞文件路径。
const X_COMPOSE_URL = 'https://x.com/compose/post';
发布默认不自动:脚本把内容填好后停下并提示人工点发布;只有显式 --submit 才会点 tweetButton / publishButton。
Post composed. Please review and click the publish button in the browser.
凭据面是 X 会话 cookie:通过 CDP Network.getCookies 读 x.com/twitter.com 的 cookie,仅断言 auth_token 与 ct0 存在(值不打印不落盘),凭据仓库就是这个共享 Chrome profile。
const REQUIRED_X_SESSION_COOKIES = ['auth_token', 'ct0'] as const;
复用已运行的 Chrome 是设计内的:先扫 ps aux 找带同一 profile 与 --remote-debugging-port 的进程,找到就连上去,不再新开浏览器。
line.includes(options.profileDir) && line.includes("--remote-debugging-port=")
多平台剪贴板/键击适配是自带的:macOS 用内联 Swift/AppKit 写剪贴板 + osascript 发键,Linux 用 wl-copy/xclip + xdotool/ydotool,Windows 用 PowerShell STA 与 SendKeys。
await runCommand('swift', [swiftPath, 'image', imagePath]);
附带一个会动手的预检脚本:检查 Chrome、profile 隔离性、bun、辅助功能权限、剪贴板往返、粘贴键能力与正在运行的 Chrome 冲突,失败即退出码 1。
Checks: Chrome, profile isolation, Bun, Accessibility, clipboard, paste keystroke, Chrome conflicts.
2核心能力
3外部依赖
| 类型 | 依赖 |
|---|---|
| cli | npx -y bun(跑同目录兄弟脚本与自身) |
| cli | osascript(macOS:激活 Chrome、发送 Cmd+V) |
| cli | swift(macOS:编译内联 AppKit 剪贴板源码) |
| cli | xdotool / ydotool(Linux X11/Wayland 粘贴键) |
| cli | powershell.exe / cmd.exe / wslpath(Windows 与 WSL 路径与键击) |
| cli | ps aux / pgrep / which / where(进程与工具探测) |
| cli | 真实 Chrome/Chromium/Edge 二进制(以 CDP 参数启动) |
| network | X 发帖页与长文编辑器 |
| network | 本地 Chrome DevTools 端点(HTTP 探测 + WebSocket CDP) |
| network | markdown 里引用的任意 http(s) 图片会被下载到本地临时目录(经 baoyu-md) |
| package | baoyu-chrome-cdp / baoyu-md / front-matter / highlight.js / marked / remark-* / unified(scripts/package.json 声明) |
4风险提醒 风险提醒:红色 · 谨慎使用
- 技术性绕过平台反自动化侦测(判红主因) — 以真实浏览器 + 真实键击伪装人类操作;这不仅涉及平台条款风险,也可能导致账号被限制;文档里的 --disable-blink-features 描述与实现不符,实际依赖的是真实键击路径。
- 以你的登录态执行外部动作 — --submit 会直接点发布按钮,把内容以你的账号公之于众且不可撤回;共享 profile 里的会话等同账号凭据,env 可改指到真实 profile。
- 接管/结束已运行的 Chrome — 脚本会连上已运行的调试会话;SKILL.md 还给出 pkill 调试 Chrome 的配方——可能影响你正在用的浏览器会话与未保存页面。
- 桌面级权限 — osascript 发键、Swift 编译、剪贴板读写需要辅助功能/自动化权限;这些权限一旦授予,对该会话内其他命令同样有效。
- 会话与二进制可被环境改写 — X_BROWSER_CHROME_PATH 决定运行哪个浏览器、BAOYU_CHROME_PROFILE_DIR 决定用哪个登录态;能设置 env 的一方即可决定以谁的身份操作。
5第二遍独立确认
- [ok] 反自动化侦测的绕过(判红主因) — README 'bypass anti-automation' + regular-posts.md 的 Cmd+V/合成事件两段 + paste-from-clipboard.ts 顶部注释互相印证;x-browser.ts 里 pasteFromClipboard('Google Chrome', 5, 500) 为首选,CDP 键事件为 fallback。
- [ok] cookie 面边界:只经 CDP 读、不落盘 — x-utils.ts 经 Network.getCookies 取 x.com/twitter.com cookie 并在内存构建 map,仅断言 auth_token/ct0 存在;全目录 grep 未发现写入 cookie 文件或读取 Cookies SQLite('Cookies' 只出现在单测字面量里)。
- [ok] 接管已运行调试会话 — packages/baoyu-chrome-cdp 通过 ps aux 匹配 profileDir + --remote-debugging-port 找端口并连接;x-utils.ts 也自行 spawnSync('ps', ['aux']) 做占用判定。
- [ok] 发布动作默认关闭 — tweetButton/publishButton 的 click 都包在 --submit 分支内;未提交时脚本打印提示让用户自己在浏览器点发布;SKILL.md 另有『必须当轮明确确认』的硬规则。
- [ok] 进程级动作(pkill) — SKILL.md 第 321 行给出 pkill -f "Chrome.*remote-debugging-port" …; sleep 2 的清理配方;该命令不在任何 TS 脚本内,需由 agent 执行——已写入 security.scripts_executed 与 risks。
- [discrepancy] 文档与实现不一致(--disable-blink-features) — references/regular-posts.md 宣称 CDP 路线会用 --disable-blink-features=AutomationControlled 启动 Chrome,但 x-utils.ts 只传 extraArgs: ['--start-maximized'];该参数仅出现在 packages/baoyu-chrome-cdp/src/mermaid.ts 的无头渲染启动里。故『绕过』的实际手段是真实键击 + 真实浏览器,而非该启动参数。
- [ok] 单测是否触碰网络/浏览器 — x-utils.test.ts 与 md-to-html.test.ts 均为纯函数/临时目录测试(锁文件判定、启动重试判定、cookie map、markdown 解析),无网络、无 Chrome 启动。
- [ok] 档位复核(批4 终裁) — 按 Main 终裁与范式红档『反反爬/绕过』字面命中判 red(撤回先前的 orange);同时保留可减轻情节的说明:无 TLS/沙箱降级、无未转义插值、cookie 不落盘、发布默认关闭。
6结论
83fb7a73416e3fe3…1567581c26