Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .changeset/nul-gate-covers-all-text.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
---

chore(scripts): `check:nul-bytes` 按载体划范围 —— 扫描所有被 git 跟踪的文本文件,而非只扫 JS/TS (#4890)

这条门禁自己的报错文案就写明了它拦的是什么:一个裸 NUL 会让 grep/ripgrep 把**整个文件**当成二进制、**静默返回零匹配**,文件因此从代码检索和每一条基于 grep 的 lint 里消失。那是 **grep 的行为**,与文件是什么语言无关 —— 但它的扫描面此前是一份 JS/TS 扩展名清单,于是范围(用途:源代码)和理由(载体:文本)对不上。

对不上的代价是 `.claude/` 下的全部 markdown 同时落在三道门禁之外:`check:nul-bytes` 只看 JS/TS,`check:doc-authoring` 的 `ROOTS` 是顶层 `skills/` 与 `content/`,eslint 的 `files` glob 只有 JS/TS 扩展名。#4890 就是这么暴露的:PR #4885 **要写的规则正是「不要写裸 NUL」**,而写的过程中一个真的裸 NUL 落进了 `.claude/skills/pm-dispatch/SKILL.md`,这道门禁报 OK —— 靠一次额外的、非常规的控制字符扫描才发现。一份带裸 NUL 的 SKILL.md 对 `grep -r` 隐形,agent 拿不到它本该遵守的规则,且没有任何信号。

现在扫描面是**所有被 git 跟踪的文本文件**。二进制判据是内容判断,不是扩展名清单(那只是把「为什么是这些文件」挪到下一个新目录去重演):非常规文件(symlink / gitlink)跳过;UTF-16/32 BOM 开头的跳过(那种编码里 NUL 是结构性的);其余**先剔除 NUL 字节、再整文件按 UTF-8 严格解码**,解不通才算二进制。先剔除 NUL 是关键 —— 否则「文件里有 NUL,所以是二进制,所以不检查它有没有 NUL」正是 git 掉进去的那个循环;整文件解码而非只看前缀,也正是因为 git 只嗅前 8000 字节是本检查文案里记着的那个盲区(protocol.ts 的 NUL 在第 147230 字节)。因此一个扩展名从没见过的新文本文件默认被扫到。

实测:2953 个文件 / ~150ms → 4974 个文本文件 / ~505ms(跳过 5 个真二进制资产与 1 个 symlink),main 上无既存文件判红。同时按仓内既有惯例把 `--self-test` 接进 `check:nul-bytes` 脚本(临时 git 仓库里跑**真实的 `scan()` 路径**),否则一条只观察到绿的门禁与一条什么都匹配不上的门禁从外部无法区分。工具链改动,不发版。
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
"i18n:extract": "tsx packages/cli/bin/run-dev.js i18n extract packages/platform-objects/scripts/i18n-extract.config.ts --locales=zh-CN,ja-JP,es-ES --fill=default --out=packages/platform-objects/src/apps/translations",
"check:i18n": "node scripts/check-i18n-bundles.mjs",
"check:i18n-coverage": "node scripts/check-i18n-coverage.mjs",
"check:nul-bytes": "node scripts/check-nul-bytes.mjs",
"check:nul-bytes": "node scripts/check-nul-bytes.mjs --self-test && node scripts/check-nul-bytes.mjs",
"check:doc-authoring": "node scripts/check-doc-authoring.mjs",
"check:role-word": "node scripts/check-role-word.mjs",
"check:adr-anchors": "node scripts/check-adr-anchors.mjs",
Expand Down
Loading
Loading