1实现原理 · 为什么它能做到
核心是逆向 X 的 GraphQL 接口:先抓 x.com 页面 HTML 里的 queryId 与 featureSwitches,再把变量拼进 /i/api/graphql/<queryId>/<Operation> 请求。
const url = new URL(`https://x.com/i/api/graphql/${queryInfo.queryId}/TweetResultByRestId`);
请求带的是 X 网页端公开 bearer token 与固定 UA——这是“冒充官方 Web 客户端”的实现手段,也是它不需要申请 API Key 的原因。
export const DEFAULT_BEARER_TOKEN =
鉴权靠 cookie:优先读环境变量 X_AUTH_TOKEN / X_CT0(可加 X_GUEST_TOKEN / X_TWID),其次本地 cookie 文件,最后经 CDP 从 Chrome 读。
const authToken = process.env.X_AUTH_TOKEN?.trim();
抓到的推文/文章被转成 markdown:线程按 TweetDetail 的会话结构串联,Article 走 articleEntity 全文,引用推文另有解析,最终产出带 YAML front matter 的文件。
**File structure**: `x-to-markdown/{username}/{tweet-id}/{content-slug}.md`
媒体本地化是可选步骤:开启 --download-media 后下载图片/视频到 markdown 同级 imgs/ 与 videos/,并把链接改写为本地相对路径。
if (hostname.includes("video.twimg.com")) return "video";
同意门禁是硬要求:没有 consent.json(accepted + disclaimerVersion 1.0)时必须先向用户展示免责声明并取得同意,拒绝即退出。
This tool uses a reverse-engineered X API, NOT official.
首次设置同样强制:EXTEND.md 不存在时必须用交互工具问偏好(媒体处理策略、默认输出目录、保存位置),明确禁止静默写默认值。
**CRITICAL**: When EXTEND.md is not found, you **MUST use `AskUserQuestion`** to ask the user for their preferences before creating EXTEND.md.
媒体处理默认“先出 markdown 再问”:先不带下载参数跑一次,检查产出里是否还有远端媒体 URL,有才询问是否下载并二次运行覆盖链接。
5. If user confirms → run script **again** with `--download-media` (overwrites markdown with localized links)
2核心能力
3外部依赖
| Kind | Dependency / Endpoint |
|---|---|
| network | x.com(GraphQL /i/api/graphql/… 与首页 HTML 抓 queryId) |
| network | pbs.twimg.com(图片媒体下载) |
| network | video.twimg.com(视频媒体下载) |
| package | baoyu-chrome-cdp ^0.1.1(npm,CDP 取 cookie) |
| cli | bun / npx(${BUN_X} 运行时) |
4管控建议与判定依据
- SKILL.md / 脚本: 调用未公开或逆向工程的私有 API / 伪造客户端标识
- SKILL.md / 脚本参数: 包含绕过自动化检测、关闭宿主沙箱或跳过 SSL 证书校验
- SKILL.md / 会话存储: 读取或复用浏览器用户登录态与会话 Cookie
- 本地凭据 / 浏览器配置: 读取用户登录 Cookie/会话/密钥环: cookie:auth_token、ct0(必需),另可带 gt、twid;来源=env(X_AUTH_TOKEN / X_CT0 / X_GUEST
- scripts/: 执行本地脚本或命令: scripts/main.ts(bun 运行;会按需启动/接管 Chrome 调试会话读 cookie)
- 网络端点: 声明外部网络访问: https://x.com/i/api/graphql/<queryId>/<Operation>(TweetResultByRestId / Twe
- 本地工作目录: 文件读写与工件输出: x-to-markdown/{username}/{tweet-id}/{content-slug}.md(或 -o 指定路径)
5第二遍独立确认
- [ok] 逆向 GraphQL 请求 + 客户端冒充(red 主因) — graphql.ts 从首页 HTML 抓 queryId/featureSwitches,拼 https://x.com/i/api/graphql/${queryId}/Operation;constants.ts 提供 FALLBACK_QUERY_ID 与硬编码 bearer/UA。
- [ok] 浏览 cookie 读取 — cookies.ts:buildInlineCookiesFromEnv 读 X_AUTH_TOKEN/X_CT0/X_GUEST_TOKEN/X_TWID;loadXCookiesFromFile 读本地文件;loadXCookiesFromCdp 经 CDP 取;hasRequiredXCookies 校验 auth_token 与 ct0。
- [ok] 媒体下载范围 — media-localizer.ts 仅对 pbs.twimg.com / video.twimg.com 判定类型并 fetch 下载,且只在 --download-media 路径调用(SKILL.md 的三态策略)。
- [ok] 两道用户门禁 — SKILL.md:consent.json(accepted + disclaimerVersion 1.0)与 EXTEND.md 首次设置(三问,禁止静默默认),后者被单独标为 BLOCKING。
- [ok] 无 TLS 降级 / 无 stealth 伪装 / 无任意代码执行 — 相关 token 全目录零命中;入口是单个 URL;无 eval/动态 import 远程模块。
- [ok] 与 baoyu-post-to-x 的路线差异(避免档位观感不一致) — post-to-x 走真实 UI + CDP 自动化(另行定级);本 skill 走私有 API 伪造请求 → red。差异来源是技术路线,已在 reason 写明。
- [ok] meta 元数据 — GitHub API:MIT、25926 stars、pushed_at 2026-09-10T15:13:43Z;本地 HEAD 与 pin 1567581c26ec… 一致。
6结论
bb27420994157cc5…