Files
peoplelib/AGENTS.md
T
lofyer 381c07733a feat: 支持 macOS arm64 打包,修复图标未入库
新增 build-mac.js,产出 ad-hoc 签名的 .app 与 DMG。只能在 macOS 上
构建:DMG 依赖 hdiutil,且 Apple Silicon 拒绝执行未签名二进制,改名
与改 plist 后必须用 codesign 重签。

按官方 darwin-arm64 运行时的真实结构处理四处易错点:用 ditto 解压以
保留 framework 符号链接、删除重打包后失效的 ElectronAsarIntegrity、
为改名后的 helper 补上 CFBundleExecutable、签名由内向外且单独签
Squirrel 的 ShipIt。

打包版数据目录改为按平台决定:macOS 走 appData,避免写进 DMG 挂载后
只读的 .app 内部并在升级覆盖时丢失书库;Windows 便携版行为不变。
窗口图标在非 Windows 平台改用 PNG。

.gitignore 的 dist 规则补上前导斜杠。此前它同时匹配 icons/dist/,
导致构建与单测依赖的图标从未入库,新克隆的仓库无法构建。
2026-08-03 16:18:47 +08:00

105 lines
6.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# AGENTS
面向在本仓库工作的 AI 代理。约定之外的部分按代码里的既有写法照做。
## 项目性质
Electron 桌面应用:多源文献检索 + 本地书库 + 内置阅读器(PDF/EPUB/MOBI/AZW+ 批注笔记 + AI 助手。
Windows x64 免安装版,用户数据在程序同级 `data/`
## 语言与风格
- 界面文案、提交信息、注释一律中文;标识符英文。
- 默认不写注释。只在原因不显然时写:隐藏约束、易踩的坑、绕过某个具体 bug 的原因。不要复述代码在做什么。
- 不用 emoji。散文里避免破折号。
- 回复简洁,不主动扩展用户没要求的事。
## 硬性约束
### 安全边界不可绕过
- 渲染层永远不能传任意路径读盘。所有文件访问必须过 `main.js``resolveReadable()`,它只放行书库中真实登记的条目。
- 分段读取会话(`src/reader/range-sessions.js`)与 sender 绑定,句柄不透明,webContents 销毁即回收。新增 IPC 时必须校验 sender。
- 所有 `ipcMain.handle``wrap()`,同步抛出也要变成 `{ ok:false }`,否则渲染层的 `await` 无 catch,界面会永远卡在加载中。
- 不要把密钥、token 写进日志或错误信息。AI Key 经 `safeStorage` 加密后落盘。
### 依赖
- 前端第三方库全部 vendored 在 `src/ui/vendor/`,版本在 `package.json` 中锁死(不用 `^`)。不要引入新的运行时依赖,除非用户明确要求。
- `src/ui/vendor/pdf.worker.range.mjs` 是**手工 patch 过的** PDF.js worker,不要用上游文件覆盖。见下文。
## PDF 分段读取(易踩坑)
超大 PDF 不整文件读入内存,走 `reader:rangeOpen/rangeRead/rangeClose``reader:bytes` 直接拒绝 PDF。
worker 选择策略在 `pdf-adapter.mjs`
- ≤256 MB:用**官方** worker`pdf.worker.min.mjs`),即使是 range 模式。
- >256 MB:用稀疏 worker`pdf.worker.range.mjs`)。
稀疏 worker 的基础缓冲区是空的(`new Uint8Array(0)`),因此**任何对 `stream.bytes.buffer` 直接建视图的代码都会抛 RangeError**。已知踩过的坑:`preEvaluateFont` 里的 `ToUnicode` 哈希,错误表现是字体静默降级成不可见的 `ErrorFont`(文本项数量正常,但画布上没有墨迹)。必须用 `stream.getByteRange(start, end)`
改动这个 worker 后,用真实 PDF 对比三条路径的渲染结果(文本项数 + 非白像素数):官方 worker 全量数据 / 官方 worker range / 稀疏 worker range。三者应一致。
## AI 助手
- 上下文范围:`selection | page | document | page-image | region-image`
- 只有 `selection` 需要选中文本;`page``document` 不依赖选区。
- `document` 无论多短都强制弹确认框,并提示可能超出模型上下文限制。
- 正文在 `ai-client.js``MAX_CHARS` 截断,保留首尾(结论常在末尾,只留开头会让模型答非所问)。
- 图像只用 JPEG 单一编码路径,1600px / 目标 400 KB。**不要加格式回退**(PNG 等),维护成本高于收益;视觉模型按像素图块计费,格式不影响费用。
- 三种协议:Anthropic `/messages`、OpenAI Responses `/responses`、兼容 Chat `/chat/completions`。图像负载格式各不相同,改动时三条都要验。
## 测试
```bash
npm test # Node 单测
npx electron src/_test/electron/<name>.integration.js # Electron 集成
```
集成套件:`ai-scope``reader-features``library-notes``annotation``download``cover``startup`
要求:
- 完成任务前跑单测 + 相关集成套件。
- 单测里有对源码的正则断言(锁死关键约定)。改了被断言的代码要同步更新断言,不要为了让测试过而弱化断言。
- 集成测试断言"真正离开进程的内容"(真实本地 HTTP 服务收到的 body、真实渲染出的像素),不要 stub 渲染层。
- 不要为了测试往生产代码里加 `window.__test` 之类的全局钩子,通过真实 UI 断言。
- `library-notes` 偶发失败,重跑确认再判断。
## 构建
```bash
npm run build # Windows,输出 dist/PeopleLib-windows-x64/
npm run build:mac # macOS arm64,输出 .app 与 .dmg,只能在 macOS 上跑
```
Windows
- 输出目录固定,不带版本号。改名会导致 `data/` 被遗留在旧目录。
- 构建保留 `data/`,但会清空其余内容。**构建前必须退出该目录下运行中的 `PeopleLib.exe`**,否则清理到一半失败,目录处于不完整状态。
- 涉及 `data/` 的操作前后做逐文件哈希比对,确认书库、笔记、批注未被改动。
macOS`build-mac.js`,易踩坑):
- **不能交叉构建**。DMG 需要 `hdiutil`,且 Apple Silicon 内核直接拒绝执行未签名二进制;改名与改 plist 会让 Electron 原始签名失效,必须用 macOS 的 `codesign` 重签(ad-hoc `--sign -` 即可)。
- 解压官方 zip 必须用 `ditto``Electron Framework.framework` 内有符号链接,用 Node 或 `unzip` 解压会展开成副本,签名随即失效。
- 重打包后 `Info.plist` 里的 `ElectronAsarIntegrity` 必须删除,否则启动即报完整性错误。
- helper 的 plist **没有** `CFBundleExecutable`,靠 bundle 名推断可执行文件名。重命名 helper 后必须显式补上该字段,否则渲染进程起不来,界面一片空白。
- 签名严格由内向外:嵌套可执行文件 → helper → framework → 外层 `.app`。带版本的 framework 签 `Versions/A``Squirrel.framework``Resources/ShipIt` 是独立可执行文件,要单独签。
- 数据目录走 `~/Library/Application Support/PeopleLib`**不要**沿用 Windows 的便携布局:`.app` 在 DMG 里只读,且升级覆盖会删掉用户书库。
- `.icns``npm run icons:icns` 生成,纯 Node 实现(icns 自 10.7 起内嵌 PNG),不依赖 macOS 的 `iconutil`。窗口图标在非 Windows 平台用 PNG`.ico` 只有 Windows 认。
## 仓库
两个远端,用途不同:
- `github`(公开):**只放 README 与截图**,不推源码、不推 `BUILD.md`。历史与本地无共同祖先,用独立的 orphan/docs 提交推送。
- `origin`(私有):完整源码。
其他:
- 根目录 `dist/` 已 gitignore,规则写作 `/dist/`**必须保留前导斜杠**:不加会连 `icons/dist/` 一起忽略,新克隆的仓库缺图标,构建直接失败。诊断产物(`*-diagnostic.png``probe*.json`)也已忽略,不要提交。
- 未跟踪文件视为用户资产,不要删除或覆盖。清理前先看 `git status --porcelain`
- 提交前 `git diff --cached` 检查是否混入密钥。