Repository navigation
[PR] feat(#4906): Panel blog auto-pulls new posts from GitHub master | feat(#4906): 面板博客自动从 GitHub master 拉新文章 - #4917
Conversation
📦 Built Package ArtifactBranch: Latest build — install this exact versionnpm install -g billion-context@0.0.6411-pr.4917.2cb0381This exact version is immutable and reproducible. The rolling Recent builds (commit → version)
Download artifact
tar xzf billion-context-pr4917.tgz
npm install -g packageInstall instructions are refreshed on each push. |
(ai: vllm-qwen/qwen3.8-27b) 已把 origin/master 合入本分支并推送:干净自动合并、无冲突(mergeable=true)。推送后 head=b8f7d05e8,base=e4cc68575;当前 mergeable_state=blocked 是等待评审/CI,非冲突。behind 已清零。 |
(ai: vllm-qwen/qwen3.8-27b) 查重: 与 PR #4915 重复(同机制)——两个 PR 都是 #4906「面板博客从 GitHub master 自动拉新文章」的实现,且都改动 标签: pr + p2 + scope/ui(功能增强非 bug;面板界面域;p2 对齐母 issue #4906 的定级)。 开始审核:先读 diff 全文 + 定向跑新增测试 + 查 CI 状态,结论按八问体例回复。 |
(ai: vllm-qwen/qwen3.8-27b) 查重结论:与 PR #4915 重复(同一需求 #4906、同一机制——面板博客从 GitHub master 拉新内容)。按先来后到 #4915 先到,但两个 PR 都改了 结构化八问1. 是什么问题:不是缺陷,是 #4906 的功能请求——面板博客 2. 什么原因导致的(机制):访问驱动拉取,无常驻定时器——打开 3. 影响范围与严重程度:新增行为,无存量可用性影响。波及面:所有打开面板博客页的用户;失败时降级为包内内容 + 页面 offline 提示,不影响面板其他功能。风险面:bili 进程新增对 api.github.com / raw.githubusercontent.com 的匿名出站(≤1 轮/小时/进程 + 冷启动一轮),与 changelog 模块既有节奏一致;内存持有 ≤8MB 图片快照直到下一成功轮替换。 4. 怎么修复的(审核结论 + 审核中所做):方向成立(changelog 模块的第二实例:公开 API、无凭据、无配置项、fail-soft)。审核发现并已修:
5. 是否有回归问题:逐项审过触碰路径的既有行为,无意回归为零:
6. 是否破坏缓存:不涉及。博客 feed 是进程内内存快照,无跨进程缓存/重试/增量游标/去重键;模型侧 prefix-cache 机制零接触。 7. 是否改了设计方向:无架构转向。确立的是「面板静态内容可被 GitHub master 远端覆盖」模式的第二实例(先例 changelog #3719)。与 #4915 有一处有意语义差异需 owner 知悉:#4917 是 floor-merge(master 上删除的文章仍留在面板,包内版本永久兜底);#4915 是权威合并(master 删除即从面板消失)。两者都说得通,floor-merge 更保守(已发布内容不因 master 瞬时状态从用户面板消失)。 8. 是否引入了新的配置:无。无新 env/config/CLI(符合 #4906 验收口径)。 行为变更披露(旧 → 新,均有意)
#4917 vs #4915 对比(owner 拍板用)
建议:保留 #4917——修完后功能完整(覆盖长文)、首屏不阻塞、图片走代理对浏览器出不去 GitHub 的场景更稳、字节预算更细;#4915 可标 superseded。若 owner 更看重与 changelog 先例逐字一致 + 权威合并语义,选 #4915 也成立(floor-merge → 权威合并的移植量很小:丢弃不在远端清单里的包内 id 即可,我可以代做)。关哪个、留哪个请 owner 定——agent 不关单。 收工判定:代码层面本 PR 已就绪(缺陷已修、回归已清点、行为变更已披露),待 CI 全矩阵绿 + owner 在两个 PR 间拍板后可合。 |
Access-driven overlay refresh for the /__bili/blog feed (#4587 serves content frozen at release time): a background round downloads the live master tree (website/blog/posts/*.md + articles.json entries + referenced images) from the public GitHub APIs and registers it as the overlay the feed/asset routes prefer over the bundled bytes; on failure the last good overlay (or bundled floor) stays up with an "offline" marker. - src/web/blog-refresh.ts (new): fail-soft round engine — anonymous public API only, no credentials/config/env surface; single-flight coalescing, 1h TTL between rounds (anonymous rate limit ~60 req/h/IP), per-file timeouts, size/file-count budgets, atomic registration. - src/web/blogfeed.ts: remote-overlay seams — pure resolveRepoRel / collectImageTargets helpers, buildRemoteBlogPosts, registerRemoteBlogFeed, getRemoteBlogAsset; getBlogFeed merges remote-wins per id over the bundled floor, asset route checks the in-memory map before disk. - src/server/admin.ts: GET /__bili/blog fires a fire-and-forget kick after answering (response always instant). - src/plugin.ts: /acp status path warms once while COLD (no master snapshot in-process yet) — same cadence class as warmChangelogOnce; warm processes keep the status path network-free. tests: web-blog-refresh.test.ts (12 cases: merge priority, asset split, image-404 churn, offline degradation, TTL/single-flight, warmer cold/warm semantics); devlog REQ+DESIGN under devlog/2026-10-27_web-blog-github-refresh.
… articles render runRound parsed website/articles.json inline to learn which docs to download but discarded the text; buildRemoteBlogPosts gates its article section on files.get(MANIFEST_REL), which was therefore always undefined — master articles were fetched (bandwidth spent) yet never appeared in the panel feed. Store the raw manifest into the files map under MANIFEST_REL (accounted against the round budget) so the section renders; regression tests pin both the happy path (en+zh pair via slug/title/title_zh) and the malformed-manifest degrade (posts-only round, no throw).
The refresh failure marker (error:"offline" in GET /__bili/blog) was invisible: loadBlog never read data.error, so the advertised corner offline state did not exist. Render a small notice card above the list, empty state and detail view when the feed carries an error (changelog precedent: sys.changelog_offline), with bl.offline i18n keys. Also refresh the bl.sub copy that still claimed content is only shipped inside the install.
Owner review flagged the access-driven-only cadence: with no traffic a served process would show stale content indefinitely. Every process now runs a lazy hourly chain — the first touch of the module (the /__bili/blog route, the status-path warm, or any round) arms a repeating force-kick at ROUND_TTL_MS intervals: - content served by any long-lived process ages out to ~1h even with zero further visits; - the handle is unref'd so short-lived CLIs exit normally and tests never inherit a live timer (_resetBlogRefreshForTest clears it); - force lets a failed round retry on the hour instead of slipping a full window (a failing round costs ~1 anonymous contents-API request); - disabled modules never arm. tests: 2 new cases under mocked clock (~1h/~2h forced rounds without traffic) + disabled-no-arm; devlog REQ/DESIGN updated.
The embedded bili settings UI drives its iframe by hash route; PAGE_IDS never listed "blog", so the master-pulled post feed had no entry point in dsh's own panel even though the framed page (#/blog) already exists. Owner follow-up: expose it as a sixth tab right after 版本/Versions. - src/agent/dsh-native-client.ts: append "blog" to PAGE_IDS (after "updates") + PAGE_KEYS/i18n entries (博客 / Blog). Clicking only flips the iframe hash — no new data channel. Older embedded frames without the #/blog route fall back to their default page inside the frame. - tests/dsh-settings-ui.test.ts: button counts 6→7, zh label list gains 博客, action-button indices shift by one.
dab98b6 to
b1f2bd2
Compare
📦 Merged Build PublishedThis merge to master was published as npm install -g billion-context@0.0.875-master.d4c3355 # this exact build
npm install -g billion-context@master # always the newest merged build
|
Closes #4906
改了什么
面板博客(
/__bili/blog)以前只显示随 npm 包冻结的那批文章,master 上新写的博客要等发版 + self-update 才看得到。现在会自动从 GitHub master 拉最新的博客文章、长文和图片:#/bloghash 路由,零新增数据通道;旧构建的内嵌页面不认识该路由时自行回落默认页,不会白屏)。触发点
/__bili/blog顺带检查一次(页面本身立刻返回旧内容,不等网络)。实现要点
src/web/blog-refresh.ts:拉取引擎。单飞去重 + TTL 节流 + 单文件 5s 超时 + 总量/文件数/图片数预算,注册前全量校验,失败只落 "offline" 标记,任何异常都不会抛出 HTTP 层。website/articles.json的原文随轮下载并计入预算,远端长文(en+zh 对)正常进 feed;清单缺失/畸形自动降级为 posts-only。src/web/blogfeed.ts:展示层改成「远端 master 快照优先、包内内容兜底」,按文章 id 合并去重;图片路由先查内存缓存再落盘。两个纯函数(相对路径解析带越界防护、markdown 图片引用收集)保证下载集合和渲染丢图判定一致。src/server/admin.ts/src/plugin.ts:上面各触发点的一行级接入;offline 标记在面板博客页可见。src/agent/dsh-native-client.ts(owner 跟进):PAGE_IDS在updates后追加blog+ zh/en 各一条 i18n(博客/Blog);tab 栏只改 iframe hash,点击不触发任何网络行为。测试与验证
tests/web-blog-refresh.test.ts(mock 时钟覆盖每小时自驱链的 ~1h/~2h 强制轮、禁用态不起链、articles 清单 happy/degrade、超尺寸预算 fail-soft 等)。本地博客相关三个测试文件共 29/29 全过。tests/dsh-settings-ui.test.ts断言同步更新(6 个 tab、中文标签「博客」、按钮顺序)。tab 相关断言本地全过;该文件另有 8 个宿主侧 inject 测试在本机失败——用 stash 验证过不带我的改动也一样失败(本分支基线就如此),且上一版 tip 的 CI 全绿,属本机并发环境因素,以本次推送后的 CI 判定为准。~/.local/state/billion-context/(bili.log/prefix-affinity 等实时增长),并发压力下大量与本改动无关的测试出现 15s 就绪超时——把本次改动从状态路径临时摘掉后同样复现,确认是并发争用而非代码问题。完整矩阵交给 CI 判定;CI 若出现相关失败我会跟进修掉。Devlog
devlog/2026-10-27_web-blog-github-refresh/:REQ.md(问题与验收,含 owner 追加的"零流量也 ≤1h"要求)、DESIGN.md(模块划分、数据流、关键取舍)。