背景
为了核对协议字段,我把 command-code npm 包(当前 1.53.0)的反混淆结果过了一遍。esbuild 打包 + keepNames,函数名以字符串形式保留,所以几个关键函数基本是可读的:buildCommandAuthHeaders、buildServerConfig、createModelClient、toWirePermissionMode、toWireThreadId、readStructure、buildMachineFingerprint、recordCliFingerprint。
有几处和本仓库当前实现不一致,想先和你对一下口径,再问进度。
观察到的一些差异
1. x-co-flag 在 CLI 里不存在
请求头名集中在一张常量表里(源码原文):
wy = {
OAUTH_TOKEN: "x-oauth-token", OAUTH_PROVIDER: "x-oauth-provider",
PROJECT_SLUG: "x-project-slug", TASTE_LEARNING: "x-taste-learning",
CLI_ENVIRONMENT: "x-cli-environment", CLI_VERSION: "x-command-code-version",
OSS_PRIMARY_PROVIDER: "x-oss-primary-provider",
SESSION_ID: "x-session-id", CMD_ZDR: "x-cmd-zdr",
PROVIDER_DEEPSEEK_INTERNAL: "x-cmd-provider-deepseek-internal"
}
没有 x-co-flag。buildCommandAuthHeaders 依次下发 Content-Type / User-Agent / 上表各项 / Authorization,也没有它。
2. User-Agent 是 cli
同文件常量 vy = "cli",buildCommandAuthHeaders 里 "User-Agent": vy。另外 recordCliFingerprint(指纹预请求)用的 e.userAgent ?? lb,而 lb = vy —— 也就是预请求同样发 cli,而本仓库的预请求目前不带 UA。
3. 信封里的 threadId 是真字段,且校验是 UUID
function toWireThreadId(e) { return Se.uuid().safeParse(e).success ? e : undefined; }
非 UUID 直接返回 undefined,键被 JSON.stringify 丢掉。而 createModelClient 里实际发的是 body.threadId 与 x-session-id 同值。本仓库这里目前是 buildCcRequest 里的 const threadId = newThreadId(),算完没进入请求体(死代码);我已在自己 fork 里改成同值下发,非 UUID 则省略。
4. memory / taste / skills 三个都是字面 null
body: { config: d, memory: null, taste: null, skills: null,
permissionMode: u, threadId: toWireThreadId(t.threadId),
mode: t.mode, promptCache: t.promptCache, params: {...} }
本仓库是 memory: null, taste: null, skills: '' —— skills 是空串而非 null。
5. 信封已经长到 9 键
抓包规格里是 7 键;1.53.0 多了 mode 与 promptCache。任何更早抓取的规格都已经过期 —— 这可能比任何单个字段都值得记一笔,因为纯抓包路线会随上游版本静默失配。
6. config.environment 是一个平台词
async function buildServerConfig(e) {
const o = t.platform(), s = t.cwd();
...
return { workingDir: s, date: r, environment: o, structure: n, isGitRepo: true, ... };
}
本仓库发的是 ${process.platform}-${process.arch}, Node.js ${version}。
7. structure 的精确算法
readdir(cwd).filter(x => !x.startsWith(".") && !Uw.has(x)).sort()
// Uw = new Set(["node_modules","dist","build",".git",".svn",".hg","coverage",
// ".nyc_output",".cache","tmp","temp",".next",".nuxt","out"])
单层、滤隐藏文件、15 项黑名单、排序。另外 gitStatus 在 git status --porcelain 为空时填字面量 "Working tree clean"。
8. x-taste-learning 是用户设置,不是常量
[wy.TASTE_LEARNING]: e.tasteLearningEnabled.toString()
来自 isTasteLearningEnabled()(读用户配置 + 项目覆盖)。本仓库固定 'false' —— 值本身合法,但要知道它反映的是"该 CLI 用户的设置",不是协议常量。
9. 指纹只以哈希离开本机,且每进程只报一次、可关闭
components 里 machineIdHash / macHashes / osUserHash / hostnameHash / gitEmailHash 全是哈希;明文只有 platform/arch/osRelease/cpuModel/cpuCount/memGiB/isContainer/timezone。上报口是:
function recordCliFingerprint(e) { if (!cb && (cb = true, isTelemetryEnabled())) { ... } }
function isTelemetryEnabled() {
if (process.env.DO_NOT_TRACK === "1" || === "true") return false;
if (isLocalOnly()) return false;
return config.telemetry !== false;
}
即 DO_NOT_TRACK=1 会让真 CLI 自己就不报指纹。
10. 客户端里没有任何检测/风控逻辑
grep 全 bundle:"Proxy use detected" 命中 0 次,minVersion、upgrade_required 同样 0 次。逆向能确定"该发什么",但确定不了"服务端在查什么"。
想请教的问题
-
现有字段值的来源分别是什么? 哪些是反混淆 CLI 得到的、哪些是抓包、哪些是参考其它项目或试错?想标清楚置信度——我这轮只能证明"和 1.53.0 不一致",证明不了"不一致就有后果"。
-
x-co-flag 是保留还是可以去掉? 如果它来自早期某个 CLI 版本、或来自其它项目的相互引用,可能值得在代码里注明出处;如果它有实际作用(哪怕只是对照实验的结果),那也是一条重要信息。
-
x-session-id / threadId 的轮换节奏有实测结论吗? 现在的实现是 per-key 12h + 1h 抖动,且 threadId 从 sessionId 派生。真 CLI 那边我看到的是 x-session-id 随会话轮换、threadId 与它同值,但"一个会话多久换一次"以及服务端是否会比对两者,我这边没有证据。
-
Proxy use detected 或者 upgrade_required 这条路径,有人实际触发过吗? 目前我在公开渠道只找到一份独立报告,触发条件不明。这条大概是整个项目最关键的未知项。
-
进度问题:目前哪些是已经确定、不打算再动的,哪些还在解决中? 特别是:
- 指纹/生命周期这套预请求,是"已确认必要"还是"宁可信其有"?
- 有没有你试过、结论是没用的方案?(负结果对后来者比正结果更省时间)
- 有没有已知的、暂时不打算修的不一致?
-
协议变更怎么追? 1.53.0 已经是 426 个版本里的最新一个,信封从 7 键变 9 键。本仓库的 x-command-code-version 是从 npm registry 动态拉的(这点比大多数项目的硬编码快照好),但信封结构本身目前靠什么发现变化?
可提供的东西
如果你觉得有用,我可以:
- 把我的 fork 里那两处(UA + threadId 同值)开成 PR;
- 或者先只把上面这份字段核对整理成一份文档(含每个字段对应的 CLI 源码片段),放进仓库作为"协议真值参考",供后续版本对比用。
我这边的核对方式(下载 npm tarball → 定位函数名 → 提取片段)是纯本地静态阅读,不含任何对服务端的探测。
背景
为了核对协议字段,我把
command-codenpm 包(当前 1.53.0)的反混淆结果过了一遍。esbuild 打包 +keepNames,函数名以字符串形式保留,所以几个关键函数基本是可读的:buildCommandAuthHeaders、buildServerConfig、createModelClient、toWirePermissionMode、toWireThreadId、readStructure、buildMachineFingerprint、recordCliFingerprint。有几处和本仓库当前实现不一致,想先和你对一下口径,再问进度。
观察到的一些差异
1.
x-co-flag在 CLI 里不存在请求头名集中在一张常量表里(源码原文):
没有
x-co-flag。buildCommandAuthHeaders依次下发Content-Type/User-Agent/ 上表各项 /Authorization,也没有它。2.
User-Agent是cli同文件常量
vy = "cli",buildCommandAuthHeaders里"User-Agent": vy。另外recordCliFingerprint(指纹预请求)用的e.userAgent ?? lb,而lb = vy—— 也就是预请求同样发cli,而本仓库的预请求目前不带 UA。3. 信封里的
threadId是真字段,且校验是 UUID非 UUID 直接返回
undefined,键被JSON.stringify丢掉。而createModelClient里实际发的是body.threadId与x-session-id同值。本仓库这里目前是buildCcRequest里的const threadId = newThreadId(),算完没进入请求体(死代码);我已在自己 fork 里改成同值下发,非 UUID 则省略。4.
memory/taste/skills三个都是字面null本仓库是
memory: null, taste: null, skills: ''——skills是空串而非null。5. 信封已经长到 9 键
抓包规格里是 7 键;1.53.0 多了
mode与promptCache。任何更早抓取的规格都已经过期 —— 这可能比任何单个字段都值得记一笔,因为纯抓包路线会随上游版本静默失配。6.
config.environment是一个平台词本仓库发的是
${process.platform}-${process.arch}, Node.js ${version}。7.
structure的精确算法单层、滤隐藏文件、15 项黑名单、排序。另外
gitStatus在git status --porcelain为空时填字面量"Working tree clean"。8.
x-taste-learning是用户设置,不是常量来自
isTasteLearningEnabled()(读用户配置 + 项目覆盖)。本仓库固定'false'—— 值本身合法,但要知道它反映的是"该 CLI 用户的设置",不是协议常量。9. 指纹只以哈希离开本机,且每进程只报一次、可关闭
components里machineIdHash/macHashes/osUserHash/hostnameHash/gitEmailHash全是哈希;明文只有platform/arch/osRelease/cpuModel/cpuCount/memGiB/isContainer/timezone。上报口是:即
DO_NOT_TRACK=1会让真 CLI 自己就不报指纹。10. 客户端里没有任何检测/风控逻辑
grep全 bundle:"Proxy use detected"命中 0 次,minVersion、upgrade_required同样 0 次。逆向能确定"该发什么",但确定不了"服务端在查什么"。想请教的问题
现有字段值的来源分别是什么? 哪些是反混淆 CLI 得到的、哪些是抓包、哪些是参考其它项目或试错?想标清楚置信度——我这轮只能证明"和 1.53.0 不一致",证明不了"不一致就有后果"。
x-co-flag是保留还是可以去掉? 如果它来自早期某个 CLI 版本、或来自其它项目的相互引用,可能值得在代码里注明出处;如果它有实际作用(哪怕只是对照实验的结果),那也是一条重要信息。x-session-id/threadId的轮换节奏有实测结论吗? 现在的实现是 per-key 12h + 1h 抖动,且threadId从 sessionId 派生。真 CLI 那边我看到的是x-session-id随会话轮换、threadId与它同值,但"一个会话多久换一次"以及服务端是否会比对两者,我这边没有证据。Proxy use detected或者upgrade_required这条路径,有人实际触发过吗? 目前我在公开渠道只找到一份独立报告,触发条件不明。这条大概是整个项目最关键的未知项。进度问题:目前哪些是已经确定、不打算再动的,哪些还在解决中? 特别是:
协议变更怎么追? 1.53.0 已经是 426 个版本里的最新一个,信封从 7 键变 9 键。本仓库的
x-command-code-version是从 npm registry 动态拉的(这点比大多数项目的硬编码快照好),但信封结构本身目前靠什么发现变化?可提供的东西
如果你觉得有用,我可以:
我这边的核对方式(下载 npm tarball → 定位函数名 → 提取片段)是纯本地静态阅读,不含任何对服务端的探测。