← Silent Star

X-Ray · ZCode

我在 ZCode 的本地快照里找到了 Git 历史

本机 ZCode 的 checkpoints 目录里,留着六个工作区的仓库快照。harness 那份清单总计 965 MB,其中 961 MB 来自 Git 目录。网上关于上传 Git 历史的讨论,在这里有了可以继续核对的材料:文件清单、加密包,还有客户端记录的上传状态。

快照里留下了什么

我检查的应用位于 /Applications/ZCode.app,版本字符串是 3.10.1.6272。快照在 ~/.zcode/v2/checkpoints/,六个工作区各有一份 repo_snapshot_manifest/v2 清单,文件时间落在 2026 年 8 月 16 日晚上 20 点 08 分到 23 点 41 分。这些是当时留下的记录,需要与现在检查的客户端代码分开看。

harness 清单里最大的 pack 文件有 915 MB。page-lingo、vibeguard、remem 也有类似结构:Git 目录占了大量空间,工作区里的部分源码文件却被 1 MB 的单文件上限拦住了。两类文件经过的过滤不同,下文再展开。

状态文件的 captureStage 是 prompt。结合客户端的调度代码,可以看到发送提示词会触发仓库快照流程。不过,触发采集、生成包和上传成功是几件事,不能只看见快照目录就认定整个仓库已经传走。

小包显示已接收,大包还在 pending

工作区 GitHub 本地记录的状态 体积
remem 公开 已接收 增量 103 KB,说明此前已有 baseline
voice-input 公开 已接收 185 KB
ultrastudio-dev-videos 没有 git 已接收 空包
harness 公开 pending 加密包 945 MB
vibeguard 公开 pending 加密包 162 MB
page-lingo 私有 pending 加密包 287 MB

表格里的“已接收”有对应的客户端状态:三个小包都有 lastAcceptedManifestHash,pending 目录也已清空。代码会在同一次状态写入中更新这个哈希、清掉 activeUpload,因此这些记录支持客户端已完成上传的判断。它们不说明服务端后来保留了多久、怎样使用内容。

三个大包仍在本地,attemptCount 都是 1。实现给对象上传设了 60 秒超时,但仅凭包体积和这个时限,不能断定每个 pending 都由超时导致。能确认的是,私有仓库 page-lingo 这份记录没有显示上传成功。

remem 和 voice-input 的仓库本来就是公开的,另一个已接收记录对应空包。我还扫描了五个 Git 仓库的全部历史 blob,没有发现真实密钥、私钥或带口令的远程地址。这个结果只适用于这几份仓库,不能说明采集器会替其他用户过滤 Git 历史里的凭据。

发送提示词后,客户端做了哪些事

在检查的 3.10.1 代码里,host 进程直接创建了仓库快照 sidecar。本地会话会在 sessionSend 之前调用 scheduleRepoSnapshotSidecar;远程工作区带有 workspaceIdentity 时则跳过。流程还需要登录 token,拿不到 token 或上传凭证,就不会继续打包。

发送提示词之后的采集、加密和上传流程
根据客户端代码还原的流程。缺少 token 或拿不到上传凭证时,后续打包不会开始。

获取凭证用的是 GET /api/v1/snapshot/upload-credential。查询参数取工作区绝对路径 sha256 的前 12 位,checkpoints 目录也用这个短哈希命名。返回值包括 snapshot_id、RSA 公钥,以及可选的体积上限。

文件随后被打成 tar.gz,再用 AES-256-CTR 加密。IV 放在密文前面,内容密钥由服务端给出的 RSA 公钥封装。按这个设计,持有对应私钥的服务端可以解开内容密钥;看到“加密包”不能理解成厂商也读不到。包里还包含 meta/prompt.json,其中 content 保存了那一轮提示词,和仓库状态归在同一个 snapshot_id 下。

为什么文件过滤没有拦住 Git 历史

客户端分开收集工作区文件和 Git 元数据。前者使用 git ls-files --cached --others --exclude-standard,会应用 gitignore;后者由 walkGitMetadataFiles 递归扫描整个 .git,最后合并两份列表。

区别出在过滤顺序:路径只要包含 .git 这一段,就会直接收录。后面的敏感文件名检查、1 MB 上限和前 8 KB 空字节检测都不再执行,因此 pack 文件可以绕过这些检查。

扫描过滤流程,.git 路径无条件收录
图中的过滤顺序来自已检查的实现。工作区里的 .env 可以被排除,Git pack 中的历史内容没有经过同一套检查。

工作区文件的排除名单包括 .env、.npmrc、id_rsa、*.pem、*.key,以及文件名含 token 或 secret 的项目。harness 当时跟踪着 .env.example,8 月那份清单里没有它,这与工作区过滤相符。但曾经提交、后来删掉的内容仍可能留在 Git 历史中;只检查当前文件名,处理不了已经被打进 pack 的内容。

设置页关着,host 有没有读到

设置里的“索引库—代码库”有“索引新文件夹”开关,说明是自动索引少于五万文件的新目录。旁边的“即时搜索”则写明数据存在本地。这两项文案本身,不能用来判断仓库快照调度是否停止。

设置页开关写入的状态与 host 调度读取情况
renderer 会写入开关状态;检查的 3.10.1 host 采集路径没有读取对应的两个设置字段。

查证时,setting.json 中 repoSnapshotIndexingEnabled 是 false,repoSnapshotIndexingUserConfigured 不存在。renderer 根据这两个字段显示关闭状态。host 里前一个字段只出现在 normalizeSettingsPatch,没有进入已检查的采集调度条件。

这能说明当前检查的 3.10.1 代码没有把这两个设置接入快照调度,不能反推出 8 月 16 日的设置也是同样状态。8 月记录说明快照曾经生成;现在的代码检查说明发送时仍会调度 sidecar。这两部分证据各自回答的问题不同。

要停掉这条流程,能检查哪些位置

退出登录、拦截凭证接口、删除本地 checkpoints
退出登录和阻断凭证请求对应已检查的前置条件。清理本地文件是另一件事,不会删除服务端可能已经收到的副本。

对检查的这份实现,退出登录会让 tokenProvider() 拿不到 zcodeJwtToken 或 accessToken,采集函数随即返回。另一处可阻断的位置是凭证请求 /api/v1/snapshot/upload-credential:获取失败后,后续扫描和加密不会开始。是否在自己的环境中生效,还需要检查对应版本和网络控制方式。

本地文件也值得单独处理。我检查时,~/.zcode/v2/checkpoints/ 的 pending 中还有约 1.4 GB,包含 page-lingo 的私有仓库快照。决定删除前,先退出应用,并保留自己需要的调查记录。清理这个目录只处理本机副本,不能撤回已经传出的内容。

在检查的 3.10.1 启动路径中,没有发现扫描 pending 并续传的逻辑;flushWorkspace 只在采集成功后有一处调用。设置页开关仍可保持关闭,但是否真正停止这条采集路径,要看相应版本的 host 是否读取它,不能只看界面上的勾选状态。

本文依据本机检查的 ZCode 3.10.1,以及 2026 年 8 月 16 日留下的 checkpoints。没有检查其他版本和账号,也没有验证服务端的留存或训练用途。

文章目录6
Silent Star约 5 分钟