Skip to content
Open
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
4 changes: 2 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ Versions follow the merge of a `*_release-v*` branch; CI publishes to npm on tag
- **compress-at-fold-point 整功能移除(owner 指令 2026-11-10,#6132;v1 #5471 + 未发布的 v2 #5949)**:删除 `compress.compressAtFoldPoint` / `compress.compressAtFoldPointClearThinking` 配置键、`BILI_COMPRESS_AT_FOLD_POINT` / `BILI_COMPRESS_AT_FOLD_POINT_CLEAR_THINKING` env、kernel 的 `relocate-compress-carriers` 管线节点与 `relocateCompressCarriers` / `planRelocateCompressCarriers` 导出、`Config.reasoningDroppable`、v2 的 `already-folded-echo` 解析 kind、web 配置行与 i18n 文案、config-reference/站点文档与博客文章(owner 指令直接删除)。移除原因:9 天内在其目标模型家族(qwen3-27b 系)出现两次不同的真实事故——2026-11-08 v1 引发的自发重复压缩循环(#5949 现场报告,v2 的设计动机)与 2026-11-10 生产会话(v0.1.213,v1 语义)中的作者误认:同轮「回答 + compress」被重放时,压缩对挪位后该轮回答文本裸挂在 transcript 尾部(无 pending 工具调用、无工具结果、无用户输入),27B 模型把自己的最后一条发言当成用户消息(m00376 链),重复回答了自己的答案且错误认知被固化进折叠块主题。v2 从未发布(最新 tag v0.1.213 仍为 v1,`git tag --contains` 为空),移除零迁移成本:开关关闭时布局就是移除后的布局(字节级一致)。旧配置残留的键:一次性 INERT 警告(`warnInertRemovedCompressKeys`,含 top-level 残留)并忽略值。kernel 0.0.192 → 0.0.193。回归面:`tests/removed-compress-keys-inert.test.ts`(新增移除键用例)、`tests/compress-reject-reasons.test.ts`(删除 echo 用例)、`kernel/tests/parse-compress-input.test.ts`(删除两个 pointer-echo 用例)、`kernel/tests/pipeline.test.ts`(节点清单)。

### Changed
- **会话详情「交接文档」(handoff) web 渲染升级:Markdown 正文 + 语法高亮 + 角色卡片(eWork 风格)**:此前 handoff 页把每条消息正文按纯文本转义直出——assistant 回复里的粗体/行内代码/链接全是字面量,代码块原样显示 ``` 围栏,工具输入输出是一大块无语言、无高亮、无复制按钮的 pre。现在:① 消息正文(含思维链)按 Markdown 渲染,服务端 `markdownToHtml`(博客文章、handoff 兜底)与浏览器 IIFE 共用同一实现——新共享核心 `src/web/mdrender.ts`(转义优先、零运行时依赖,dist 零依赖守卫不变,`.toString()` 内联进 IIFE,附自包含契约测试防转译破坏);② 代码块按语言高亮(json/diff/js/ts/py/sh 等手写词法器,GitHub 明/暗双配色,未知语言退化为纯文本转义,注入面全转义);③ 消息改角色卡片布局(user/assistant/tool 左边框 + 徽章,思维链默认收起,工具卡输入/输出标签 + 语言标注 + 复制按钮 + JSON 美化,≤20 行默认展开);④ 文档头元信息(标题/session id/token 数/压缩块)不再被客户端跳过,渲染为灰底 key-value 盒;新增 GFM task list 复选框。回归:tests/mdrender.test.ts(18 用例,含 esbuild-minify 复刻 tsup 产线的内联契约)、tests/web-handoff-roles.test.ts 适配新 markup(#2065 语义不变量保留:正文 `### N.N` 标题不成为角色分隔线)、tests/web-sessions.test.ts(XSS/unsafe-link/handoffHtml 断言原样穿过新实现),全部 web 沙箱测试套件绿。
- **AGENTS.md 瘦身(owner 指令 2026-11-08):76 KB → 50.6 KB(−34%),规则零丢失,编号不变**。KDD 分两级:Tier A(#2/#4/#6/#7/#8/#10,每会话操作规则)留 AGENTS.md 全文;Tier B(#1/#3/#5/#9/#11–#18)全文逐字搬入新文件 `reference/design-decisions.md`(append-only 台账,**KDD 编号 = 稳定公共 API,原样保留**),AGENTS.md 每条留 1–3 行操作性后果 + 指针。Issue 分类与标签规则整节搬入 `reference/triage.md`(p1 口径与总账讨论链接留在正文)。E2E/Release 细则收敛为指向既有 `reference/testing.md` / `reference/release.md` 的硬规则。被反向引用的 heading 锚点(`#4-git-safety-rules-mandatory` 等 6 处)文本原样不动。
- **自动更新的错峰抽取窗口上限从 48 小时拉长到 7 天**:发现新版本后,每台实例在 15 分钟 – 7 天内随机抽一个时刻到点再升(原来 48 小时)。改动同时落在两处:内置默认值(`STAGGER_MAX_DELAY_DEFAULT_MS`,远程策略文件不可达/未配置时的兑底)和本仓库官方策略文件 `auto-update-policy.json` 的 `default.maxDelay`(2d→7d,远程默认优先于内置,不改它的话内置改动不会生效)。已抽中的时刻按 `(dist-tag, 版本)` 落盘持久化,升级到本版后**不会重摇**——已生效的旧抽取照旧到点执行,只有升级后新发现的版本才在 7 天窗口内抽。手动 `bili update`、`staggerMinDelayMs:0 + staggerMaxDelayMs:0`(或对应环境变量)照旧绕过/恢复立即升级;远程策略与本机 config/env 的优先级不变(本地 > 远程 > 内置)。
- **会话详情「交接文档」(handoff) web 渲染升级:Markdown 正文 + 语法高亮 + 角色卡片(eWork 风格)**:此前 handoff 页把每条消息正文按纯文本转义直出——assistant 回复里的粗体/行内代码/链接全是字面量,代码块原样显示 ``` 围栏,工具输入输出是一大块无语言、无高亮、无复制按钮的 pre。现在:① 消息正文(含思维链)按 Markdown 渲染,服务端 `markdownToHtml`(博客文章、handoff 兜底)与浏览器 IIFE 共用同一实现——新共享核心 `src/web/mdrender.ts`(转义优先、零运行时依赖,dist 零依赖守卫不变,`.toString()` 内联进 IIFE,附自包含契约测试防转译破坏);② 代码块按语言高亮(json/diff/js/ts/py/sh 等手写词法器,GitHub 明/暗双配色,未知语言退化为纯文本转义,注入面全转义);③ 消息改角色卡片布局(user/assistant/tool 左边框 + 徽章,思维链默认收起,工具卡输入/输出标签 + 语言标注 + 复制按钮 + JSON 美化,≤20 行默认展开);④ 文档头元信息(标题/session id/token 数/压缩块)不再被客户端跳过,渲染为灰底 key-value 盒;新增 GFM task list 复选框。回归:tests/mdrender.test.ts(18 用例,含 esbuild-minify 复刻 tsup 产线的内联契约)、tests/web-handoff-roles.test.ts 适配新 markup(#2065 语义不变量保留:正文 `### N.N` 标题不成为角色分隔线)、tests/web-sessions.test.ts(XSS/unsafe-link/handoffHtml 断言原样穿过新实现),全部 web 沙箱测试套件绿。- **AGENTS.md 瘦身(owner 指令 2026-11-08):76 KB → 50.6 KB(−34%),规则零丢失,编号不变**。KDD 分两级:Tier A(#2/#4/#6/#7/#8/#10,每会话操作规则)留 AGENTS.md 全文;Tier B(#1/#3/#5/#9/#11–#18)全文逐字搬入新文件 `reference/design-decisions.md`(append-only 台账,**KDD 编号 = 稳定公共 API,原样保留**),AGENTS.md 每条留 1–3 行操作性后果 + 指针。Issue 分类与标签规则整节搬入 `reference/triage.md`(p1 口径与总账讨论链接留在正文)。E2E/Release 细则收敛为指向既有 `reference/testing.md` / `reference/release.md` 的硬规则。被反向引用的 heading 锚点(`#4-git-safety-rules-mandatory` 等 6 处)文本原样不动。
- **系统架构文档体系落地(owner 指令 2026-11-08):`docs/architecture/` 成为实时维护的架构枢纽**:新增 `docs/architecture.md` / `docs/architecture.zh-CN.md` 总枢纽(整体架构图中英双版转正 + 8 模块总表),首个样板模块页 `docs/architecture/storage.{md,zh-CN.md}`(统一存储:职责/原理/工作机制/硬不变量,配模块图中英双版)。文件级地图 `reference/architecture.md` 补齐 125 个缺失条目(新存储层 / marker / fastpath / lanes 等全部新模块)并升级为 CI 强制全量覆盖。新增 CI 车道 `architecture-docs`(`tools/check-architecture-docs.mjs`):地图覆盖全 `src/` 文件、总表↔页面成对、图 svg 优先 + png 备选齐备、SVG 基础良构(未转义 `&` 曾让英文图线上破图)。AGENTS.md「Documentation Layout」新增实时维护规则:改结构 ⇒ 同 PR 更新页 + 图 + 总表。其余 7 个模块页(pipeline / lanes / kernel / identity / fastpaths / webui / update)同一 PR 全部补齐——总表 8 行全 ✅(每页 = 中英双版文档 + 中英双版图)。

### Fixed
Expand Down
2 changes: 1 addition & 1 deletion README.ja.md
Original file line number Diff line number Diff line change
Expand Up @@ -515,7 +515,7 @@ bili --bin /path/to/client # launcher: spawn this exact client binary instead

プロキシは、起動時と 3 分ごとに npm を確認します。新しいバージョンはその場でインストールされ、通知がログに出ます。**それを使うには `bili` を再起動してください**。ただし、任意の自己再起動(`--auto-restart-on-update` のフラグ、環境変数 `ACP_AUTO_RESTART_ON_UPDATE=1`、または設定の `"autoRestartOnUpdate": true` — デフォルトはオフ)を有効にした場合は別です:処理中のリクエストがゼロのときに、新しいインストールを確認し、接続の受け付けを止め、処理を終わらせ、同じポートで代わりのプロセスを起動し、それが接続を受け付けたら終了します(クライアントは自動で再接続し、セッションの状態はディスク上に残ります)。安全のための関門:処理を終わらせる間の処理中のリクエストがゼロであること、再実行の前のインストールの健全性の確認、そして揺れ動くバージョンがループして再起動し続けないための 10 分間のクールダウンの印です。何かが失敗すると、元のリスナーを再開し、普通の通知に戻ります。

**段階的な展開(#3619):** 見つかったバージョンが、自動アップデートですぐに適用されることはありません。各インスタンスは、遅延の範囲(組み込みのデフォルトは **15 分〜48 時間**)の中でランダムな時点を 1 つ引き、その時点が来たらアップグレードします。引いた時点は保存されるので、再起動しても引き直すことはありません。そのため、全体のアップグレードはリリースから数分で終わるのではなく、その範囲に分散し、悪いリリースを展開の途中で見つける時間が残ります(#3401/#3600/#3394)。範囲と緊急時の操作は、公開のポリシーファイル(このリポジトリの `auto-update-policy.json`。ETag のキャッシュを使って匿名で取得します)にあります:`hold` は全体の自動アップグレードを凍結し、`blocked` は一覧したバージョンを飛ばし、`pinned` はアップグレードの上限を決めます。設計上、失敗しても開いたままです — 届かないファイルや壊れたファイルはローカルのデフォルトにフォールバックするだけで、このファイルが操作できるのはタイミング/飛ばすもの/固定だけで、何がインストールされるかは決して操作できません。マシンごとの抜け道:手動の `bili update` は `hold`/段階的な展開を迂回します(`blocked`/`pinned` には引き続き従います)。`"staggerMinDelayMs": 0` + `"staggerMaxDelayMs": 0`(または `BILI_UPDATE_STAGGER_MIN_MS`/`BILI_UPDATE_STAGGER_MAX_MS`)で、以前のすぐにアップグレードする動作に戻し、`ACP_AUTO_UPDATE=0` で自動アップデートを完全に無効にします。形式と意味の詳細:[docs/configuration.md → `update`](docs/configuration.md#update)。
**段階的な展開(#3619):** 見つかったバージョンが、自動アップデートですぐに適用されることはありません。各インスタンスは、遅延の範囲(組み込みのデフォルトは **15 分〜7 日**)の中でランダムな時点を 1 つ引き、その時点が来たらアップグレードします。引いた時点は保存されるので、再起動しても引き直すことはありません。そのため、全体のアップグレードはリリースから数分で終わるのではなく、その範囲に分散し、悪いリリースを展開の途中で見つける時間が残ります(#3401/#3600/#3394)。範囲と緊急時の操作は、公開のポリシーファイル(このリポジトリの `auto-update-policy.json`。ETag のキャッシュを使って匿名で取得します)にあります:`hold` は全体の自動アップグレードを凍結し、`blocked` は一覧したバージョンを飛ばし、`pinned` はアップグレードの上限を決めます。設計上、失敗しても開いたままです — 届かないファイルや壊れたファイルはローカルのデフォルトにフォールバックするだけで、このファイルが操作できるのはタイミング/飛ばすもの/固定だけで、何がインストールされるかは決して操作できません。マシンごとの抜け道:手動の `bili update` は `hold`/段階的な展開を迂回します(`blocked`/`pinned` には引き続き従います)。`"staggerMinDelayMs": 0` + `"staggerMaxDelayMs": 0`(または `BILI_UPDATE_STAGGER_MIN_MS`/`BILI_UPDATE_STAGGER_MAX_MS`)で、以前のすぐにアップグレードする動作に戻し、`ACP_AUTO_UPDATE=0` で自動アップデートを完全に無効にします。形式と意味の詳細:[docs/configuration.md → `update`](docs/configuration.md#update)。

動いているプロセスがディスク上のインストールより古い(「stale」)間は、Web UI にバナー(動いているバージョンとインストール済みのバージョン、自動再起動の状態)が表示され、スクリプト用に `GET /__bili/status` が `{version, diskVersion, stale, autoRestartOnUpdate, advisory, updatePolicy, inFlight}` を返します(`advisory` は有効な重大な欠陥の項目か `null` です。下記を参照。`updatePolicy` は #3619 の展開の状態 — ポリシーの出どころ、`hold`/`pinned`/`blocked`、そして期限付きの保留中の段階的なアップグレード — を報告します)。設定の `"autoUpdate": false` か `ACP_AUTO_UPDATE=0` で永続的に無効にできます。

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -533,7 +533,7 @@ Client-facing connections close gracefully after the final response: when the pr

The proxy checks npm on startup and every 3 minutes; a newer version is installed in place and a notice is logged — **restart `bili` to pick it up**, unless you enable opt-in self-restart (`--auto-restart-on-update` flag, env `ACP_AUTO_RESTART_ON_UPDATE=1`, or `"autoRestartOnUpdate": true` in config — default OFF): with zero in-flight requests it verifies the new install, stops accepting connections, drains, spawns a replacement on the same port, and exits once it accepts connections (clients reconnect automatically; session state survives on disk). Safety gates: zero in-flight through the drain window, an install sanity check before re-exec, and a 10-minute cooldown marker so a flapping version can never loop-restart; any failure resumes the original listener and falls back to the plain reminder.

**Staggered rollout (#3619):** a discovered version is not applied immediately by automatic updates. Each instance draws ONE random moment inside a delay window (built-in default **15 min – 48 h**) and upgrades when it arrives; the drawn moment is persisted, so restarts never re-roll. Fleet upgrades therefore spread across the window instead of completing within minutes of a release, leaving time to catch a bad release mid-rollout (#3401/#3600/#3394). The window plus emergency controls live in a public policy file (`auto-update-policy.json` in this repo, fetched anonymously with ETag caching): `hold` freezes automatic upgrades fleet-wide, `blocked` skips listed versions, `pinned` sets an upgrade ceiling. Fail-open by design — an unreachable or malformed file simply falls back to local defaults, and the file can steer timing/skip/pin only, never what gets installed. Per-machine exits: manual `bili update` bypasses `hold`/stagger (still respects `blocked`/`pinned`), `"staggerMinDelayMs": 0` + `"staggerMaxDelayMs": 0` (or `BILI_UPDATE_STAGGER_MIN_MS`/`BILI_UPDATE_STAGGER_MAX_MS`) restore legacy immediate upgrades, and `ACP_AUTO_UPDATE=0` disables auto-updates entirely. Full format and semantics: [docs/configuration.md → `update`](docs/configuration.md#update).
**Staggered rollout (#3619):** a discovered version is not applied immediately by automatic updates. Each instance draws ONE random moment inside a delay window (built-in default **15 min – 7 days**) and upgrades when it arrives; the drawn moment is persisted, so restarts never re-roll. Fleet upgrades therefore spread across the window instead of completing within minutes of a release, leaving time to catch a bad release mid-rollout (#3401/#3600/#3394). The window plus emergency controls live in a public policy file (`auto-update-policy.json` in this repo, fetched anonymously with ETag caching): `hold` freezes automatic upgrades fleet-wide, `blocked` skips listed versions, `pinned` sets an upgrade ceiling. Fail-open by design — an unreachable or malformed file simply falls back to local defaults, and the file can steer timing/skip/pin only, never what gets installed. Per-machine exits: manual `bili update` bypasses `hold`/stagger (still respects `blocked`/`pinned`), `"staggerMinDelayMs": 0` + `"staggerMaxDelayMs": 0` (or `BILI_UPDATE_STAGGER_MIN_MS`/`BILI_UPDATE_STAGGER_MAX_MS`) restore legacy immediate upgrades, and `ACP_AUTO_UPDATE=0` disables auto-updates entirely. Full format and semantics: [docs/configuration.md → `update`](docs/configuration.md#update).

While the running process is behind the on-disk install ("stale"), the web UI shows a banner (running vs installed version, auto-restart state) and `GET /__bili/status` returns `{version, diskVersion, stale, autoRestartOnUpdate, advisory, updatePolicy, inFlight}` for scripting (`advisory` is the active critical-defect entry or `null`, see below; `updatePolicy` reports the #3619 rollout state — policy source, `hold`/`pinned`/`blocked`, and the pending staggered upgrade with its due time). Disable permanently via `"autoUpdate": false` in config or `ACP_AUTO_UPDATE=0`.

Expand Down
Loading
Loading