fix(format): 关掉 pi-lens 的项目级自动改写;修复它被 prettier 改坏的 index.html

# 我上次的修复只做了一半

上一次(429149e)我加了根 biome.jsonc,把 biome 的 formatter 关掉,并撤销了它造成的
约 7000 行重排。那时我以为问题解决了 —— **没有**。

pi-lens 编辑文件后会「安全格式化」它,格式化器是**按扩展名各自挑**的
(FORMATTER_POLICY_BY_EXTENSION)。仓库里没有任何格式化器配置时它走 smart-default 回退:

    .ts/.tsx/.js/.mjs/.json/.css → biome
    .html                        → prettier      ← 这一条我漏了

biome.jsonc 挡得住 biome,对 prettier 完全无效。于是 a404cba(图标提交)里我改了
index.html 加 favicon,prettier 顺手把它改写了:

    -<!DOCTYPE html>          +<!doctype html>
    -classList.add('dark')    +classList.add("dark")     ← 单引号变双引号
    -<meta name="viewport" …> +多行折行

而 test/theme.test.mjs 恰好逐字符断言那一段里是 `classList.add('dark')`(单引号),
两条断言当场变红。**更糟的是我没看见**:验证时我用 `grep -E 'Test Files|Tests |FAIL'`
过滤输出,而这个测试的摘要是中文的(「主题:28 通过,2 失败」),被整行滤掉了,
于是我在提交信息里写了「196 项测试全绿」—— 一句不成立的结论。

(顺带厘清两起事故的元凶不同:19a3161 那次是 **biome**(tab 缩进是它的默认),
a404cba 这次是 **prettier**。我先前把它们当成同一个问题。)

# 根因级修法

不再逐个格式化器打补丁,而是关掉 pi-lens 对本仓库的改写路径。
项目级 `.pi-lens.json` 支持 format.enabled / autofix.enabled(文档
docs/settings.md 的 mutation controls),由当前目录向上查找,覆盖整个仓库:

    {"format": {"enabled": false}, "autofix": {"enabled": false}}

autofix 一并关掉:它同样会在与本次改动无关的行上动手。

biome.jsonc 保留(纵深防御,且它顺带关掉了 biome 的自动修复)。

# 验证

- 修好 index.html:DOCTYPE 恢复大写、viewport 回单行、内联脚本回单引号,
  与 19a3161^(未受污染的原版)逐字节一致,只多出 favicon 四行。
  实验证据:把原始版喂给 prettier,输出与 a404cba 里的版本**逐字节相同** —— 确认元凶。
- `node test/theme.test.mjs` → 主题:30 通过,exit 0
- 加注释后再编辑一次 index.html:单引号与 DOCTYPE 均未被改写(改写路径已断)
- 顺带在注释里写明「引号别统一成双引号,theme.test.mjs 逐字符断言」,防止后人"清理"
This commit is contained in:
2026-09-11 22:01:56 +08:00
parent a404cbad54
commit d50c55da4f
2 changed files with 48 additions and 11 deletions

37
.pi-lens.json Normal file
View File

@ -0,0 +1,37 @@
{
"$schema": "https://pi-lens.dev/schema/project.json",
// 关掉 pi-lens 对本仓库的自动改写。
//
// # 为什么必须显式关
//
// pi-lens 编辑任一文件后会「安全格式化」它。本仓库没有任何格式化器配置时,
// 它走 smart-default 回退:.ts/.tsx/.js → biome**.html → prettier**
// (见 pi-lens 的 FORMATTER_POLICY_BY_EXTENSION。两套默认值都与本仓库的
// 手工排版不兼容 —— biome 默认 tab 缩进 + 双引号prettier 默认双引号、
// 还会把 <!DOCTYPE html> 改成小写、按 80 列折行。
//
// 已经造成过两次真实损失:
// 1) 19a3161 用 `git add -A` 把约 7000 行 biome 重排扫进功能提交,
// 使那次提交无法审查(还掩盖了一处 Go 文件的删行);
// 2) a404cba 里 prettier 改写了 client/electron/index.html —— 单引号变双引号、
// DOCTYPE 变小写,直接打破 test/theme.test.mjs 的两条断言。
// 该测试恰好要求同步内联脚本里是 classList.add('dark')(单引号)。
//
// 根 biome.jsonc 只挡得住 biome挡不住 prettier两者是并列的候选格式化器
// 各有各的配置。所以真正的开关是这里 —— 项目级、两条改写路径一起关。
//
// # 为什么不是「把格式化器配成本仓库风格」
//
// 试过把缩进/引号/lineWidth 全部对齐,`biome format --write` 仍然改动 17 个文件:
// 本仓库的注释按语义换行、数组与调用按可读性手工折行,这些格式化器还原不了。
// 只要它还在跑,每次编辑都会产生与内容无关的大面积 diff把真正的改动埋掉。
//
// 本仓库的静态检查由 tsc / go vet / tree-sitter / ast-grep 与各自的测试套件承担。
"format": {
"enabled": false
},
// autofix 同理:它会在与本次改动无关的行上做自动修复。
"autofix": {
"enabled": false
}
}

View File

@ -1,11 +1,8 @@
<!doctype html>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, viewport-fit=cover, interactive-widget=resizes-content"
/>
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover, interactive-widget=resizes-content" />
<!--
图标放在 public/assets/ 而不是 public/ 根下Gateway 只把 /assets/* 和 /
挂给了静态处理器(见 server/cmd/server/main.go 的静态段),放在根下会 404。
@ -28,18 +25,21 @@
* 这段脚本必须**内联且同步**:外链或 defer 都会晚于首次绘制。
* 逻辑与 themeStore 的 readStored/resolveTheme 一致,
* 改那边的键名或取值时这里要同步。
*
* 引号别「顺手统一」成双引号test/theme.test.mjs 逐字符断言这一段里是
* classList.add('dark')(单引号)。曾经被 prettier 改写过一次,直接让测试变红。
*/
(function () {
try {
var p = localStorage.getItem("agentmail.theme") || "system";
var p = localStorage.getItem('agentmail.theme') || 'system';
var dark =
p === "dark" ||
(p === "system" &&
p === 'dark' ||
(p === 'system' &&
window.matchMedia &&
window.matchMedia("(prefers-color-scheme: dark)").matches);
window.matchMedia('(prefers-color-scheme: dark)').matches);
if (dark) {
document.documentElement.classList.add("dark");
document.documentElement.style.colorScheme = "dark";
document.documentElement.classList.add('dark');
document.documentElement.style.colorScheme = 'dark';
}
} catch (e) {
/* localStorage 不可用(隐私模式)时退回浅色,不阻塞渲染 */