Repository navigation
Added
- 面向人的数字有了唯一来源(
scripts/visualization/metrics.mjs):文件数 / 行数 / 用例数 / 路由数 / 门禁列表 / 依赖版本 / 覆盖率阈值集中在一处,generate_readme_numbers.mjs与新的generate_overview.mjs都从它取。此前 README 表格、架构图、全景页各算各的,同一件事在三个地方有不同答案。配套scripts/coverage-thresholds.mjs:阈值原先只能写在scripts/coverage.mjs里,而那个文件顶层就 spawn 整个测试套件,谁import它谁跑一遍测试——所以阈值搬出来,两处(门禁与页面)读同一份。 - 全景页纳入漂移门禁(
scripts/visualization/generate_overview.mjs+docs:overview/docs:overview:check,已接进docs:check):docs/project_overview/原先整页手写,现在数值、src/顶层文件清单、docs/scripts/根目录清单、完整 REST 路由表、npm run verify门禁列表都由源码生成(标记区内),data-metric元素的文本同时被回写成同一个值,关掉 JS 与开着 JS 一致。四条断言:结构树与src/子目录双向对齐、每个docs/*.md都在文档索引里、每条真实路由必须落进且只落进一个分组、本地引用文件必须存在且外部链接一律 https。负向验证逐条做过:把/health改成/healthz同时报「路由不存在」与「/health 没归组」(退 2 且不写文件)、把memory/改成ghost/两个方向都红、../architecture.svg改成不存在的文件立刻红。 - 单图名片
docs/project_overview/project_card.html:800px 固定宽度的长图版项目概览,自带「Export as PNG」(html2canvas,CDN 走 https,scale: 2输出 1600×3876),导出时把按钮条摘掉,失败时明确提示改用系统截图而不是静默什么都不做。CSS/JS 全部内联、只用系统字体栈(CDN 字体在导出那一刻可能还没到位,出一张字距错位的图没人看得出来)。徽章、数字卡、许可行是generate_overview.mjs的生成区,与全景页同源,因此两份页面不可能报出不同的数;project_card.html还额外受「必须纯英文 + 引用必须存在」两条断言约束。实测:导出链路在浏览器里跑通(状态saved pi-starter_card_2026-10-10.png),并对生成的 canvas 做了像素级核对——架构图所在纵向区间内#22c55e8398 px、#38bdf85185 px、文字色#e6edf76692 px,说明内联 SVG 与文字确实进了图片而不是空白。 - 两份 README 的文档导航补上全景页这一行(此前
docs/project_overview/只在目录树里出现,读者不会知道它是docs/的入口页),并写明它的数值是生成的。目录树那行同时把 Pages 状态说清楚:本仓库当前未启用 GitHub Pages(实测https://lpk3215.github.io/pi-starter/与/project_overview/均 404),docs/index.html的重定向只是「经典模式从docs/发布」所需的目录结构,不是一条已经能打开的链接。
Fixed
-
docs:overview:check在远端红、本地绿(generate_overview.mjs,CNB 构建cnb-t41-1k4iphsec实测):清单取自git ls-files,而 git 默认core.quotePath=true会把非 ASCII 路径转义成"docs/\344\275\277...";开发机普遍把它关成 false,CI 容器不继承任何人的 gitconfig——于是中文文件名一进 CI 就与页面里的清单对不上,报的是「漂移」而不是「环境不同」。改为固定git -c core.quotePath=false ls-files -z(-z顺带解决带换行的文件名)。复现与验证:在一份全新克隆里把core.quotePath设回 true,旧代码立刻漂移、新代码 in sync。同时把漂移信息做成可诊断的——打印变了的METRICS键、变了的标记区、以及第一处不同的行;只说「drift」的门禁等于让人手工复现 CI。 -
「58 个 HTTP 路由处理器」里有 11 个不是路由(
generate_readme_numbers.mjs):计数用的是裸.get(正则,于是src/http/log-routes.ts里search.get("limit")这类 URLSearchParams 读取被一并算进去,标榜「可验证的数字」其实不可验证。口径改为只认app./router.上的方法,真数 47,标签同步写成HTTP route handlers (app. / router. methods);两份 README 的生成表已重算。 -
全景页整页手写到过期(
docs/project_overview/index.html):代码已是 v0.4.1,页面仍挂着release v0.2.0、308 cases · 37 files(实际 505 · 53)、17 项 WS 冒烟(实际 23);结构树缺conversation/与memory/两个目录;能力清单缺记忆、联网、HITL、会话导入等已上线的能力;API 表里/interrupt、/compact、/thinking、GET /model、/session、/session/edit、/session/rollback、/mcp/servers、/subagents/run、/approvals/:id这几条 REST 路由根本不存在(它们是 WS 命令或 SDK 工具)。现在版本、数值、路由、门禁都由生成器写,手写部分只保留说明文字;e2e断言数(48)与 WS 冒烟断言数(23)改为统计脚本里的check(调用点,不再手抄。 -
发版顺序让每个 tag 都带着过期的派生文档,并让
publish:local恒红(scripts/release.mjs):脚本的顺序是「跑门禁 → 回写版本号 → 打 tag → 推送」,而版本号是派生文档的输入——docs/architecture.svg里就印着它。于是回写之后 tag 里的生成物必然旧一格,紧接着npm run publish:local再跑一次门禁时就红在docs:check上(v0.4.1 现场复现:漂移:docs/architecture.svg,同一个 tag 出不了包)。现在回写之后立刻重算派生文档(docs:svg/docs:numbers/docs:reference/docs:overview,项目定义了才跑)、再跑一次docs:check兜底,并把它们一起收进 bump 提交;不一致时不打 tag,并打印「此时版本文件尚未提交,git checkout -- .回退」。另外补一条:回写后若工作区没有任何改动就直接失败——版本号已经是目标值,静默打个空 tag 更糟。
Changed
- 全套文档做了一次口径对齐(逐条对着源码与生成物复核,不是润色):
docs/能力与边界.md:基线从v0.3.0更正到v0.4.1;「60+ REST 路由」→ 47;npm run e2e的实测行从35 通过 / 1 跳过更正为43 通过 / 1 跳过 / 0 失败(共 44)(本轮实跑);删掉一条指向不存在文件的说明(「静态全景页可视化总览.html」,真实路径是docs/project_overview/,含project_card.html);docs/分工从「三篇活文档 + 其余历史稿」改为按「手写维护 / 生成 / 参考与历史稿」三类列全 10 篇。docs/使用指南.md:npm run verify的组成原写成「typecheck / lint / 覆盖率 / 换模型门禁」——覆盖率不在 verify 里(它是远端单独一步),「换模型门禁」这个脚本从来不存在,同时漏了docs:check、verify:audit、build、verify:embed。改为九项真门禁逐条列出,并补verify:all与test:coverage两行。docs/嵌入指南.md:接口清单漏了随包必挂的GET /providers、POST /model/cycle、GET /db/notes/:id,也没说清哪些路由是按装配情况挂载的(memory / files / approvals / provider-keys / logs / settings / capabilities)——嵌入方按「一定有」写客户端就会踩空;补全并指向生成的参考手册。WS 扩展点原写「commands/gate/sessionStats/connectionCount/approvalStats都能在 runtime 里传」,后三个其实是createApp()的选项(src/app.ts:71-75),runtime 里真正可选的是commands/gate/uiBridge/metrics(src/transport/ws.ts:58-76)——已按源码改正,并补上漏写的logQuery: { dir }(不开就没有/logs)。另修掉一段抄下去编译不过的示例:同一个块里const { app }声明了两次。CONTRIBUTING.md/FAQ.md/docs/能力与边界.md/docs/智能体视角评估.md:四处「两套远端门禁都跑在 node:24(Linux)容器」不成立——ci.yml是 ubuntu/windows/macos 三 OS 矩阵且本账号跑不起来,真正生效的只有.cnb.yml。统一改成准确表述,并把本轮新踩到的一侧写进去:本地绿 ≠ 远端绿(docs:overview:check远端红过一次而本地全绿,成因是 CI 不继承core.quotePath)。CONTRIBUTING 的项目地图把 HTTP 层写成只有src/app.ts,漏了src/http/六个路由模块与整条对话内核(conversation/→session-hub→snapshot/protocol→transport/ws),已补。docs/智能体视角评估.md:正文里以「现状」口吻出现的旧数就地改对——门禁链(376/11/39 → 505/19/44 并补docs:check)、498 通过 / 0 失败(漏了 7 例平台跳过,读起来像全绿)、覆盖率实测行(92.94/81.20/85.77 + 470 用例 → 本轮实测 92.90/81.51/86.30 + 505 用例)、棘轮阈值(92/79/84 与 88/77/82 → 现在住在scripts/coverage-thresholds.mjs的 92/81/85)、「57 个消息类型」(其实是 34 + 21 = 55)、§0 那句「没有任何联网能力、没有跨会话记忆」(与本文 §0.2 的 P7-1 / P7-2 自相矛盾,现标注为最初走查判断并指向更正行)。附录 A / B 保留原值——文首已有「不要再引用本文档的数字,以 README 的 Numbers 表为准」的显式声明,实测记录被改写成今天的数就失去了它的证据价值。docs/assistant-ui.md/docs/前端调研.md:两篇都自称「暂不实现 / 只调研」,而前端早已落地。各加一条状态说明(依赖位置、真正手写的两处web/src/pi/client.ts与usePiRuntime.ts、实际选型是 assistant-ui 而非文中推荐的pi-web-ui壳),研究正文保留不动。
- 全景页 e2e 那张卡的标签写准了:48 是
scripts/e2e-restart.mjs里的断言数(静态计数),每轮实际执行 44 项(43 通过 + 1 平台跳过),所以标签从「e2e assertions」改为「e2e assertions inscripts/e2e-restart.mjs」,避免被读成「跑了 48 项」。 - README 可视化与结构树对齐真实项目:两版 README 的
src/目录树此前只列 7 个子目录,实际有 19 个——memory/、conversation/、approval/、mcp/、modes/、subagents/等全部缺席,读者会以为那些能力不存在;现已补全(含errors.ts/sdk-adapter.ts/test-tmp.ts这类运行时底座),两版逐行对应。顶部那条指向 GitHub Actions 的 CI 徽章实测渲染成CI: failing,而本账号的 Actions 根本跑不起来(远端门禁是.cnb.yml)——红着的假状态比没有徽章更误导人,换成静态gates: CNB pipeline并链到实际跑门禁的仓库;.github/workflows/ci.yml那行注释补上它其实也跑docs:check与覆盖率门禁,并注明它当前不生效。三张 SVG 复核结论:文字节点零中文、数值全部运行时从源码读取、版本号已是v0.4.1,无需改动;docs/未启用 GitHub Pages(实测 404),因此不写任何 Pages 链接。 - 新增一条门禁断言,防目录树再次腐烂(
generate_reference.mjs):两份 README 的src/树必须与文件系统一致,漏列(能力隐身)与多列(指向已不存在的目录)两个方向都判失败。负向验证:从英文树里删掉memory/一行,检查立刻红并点名「漏了 1 个实际存在的目录:memory」;还原后恢复绿。