日期: 2026-06-24
范围: mcpp 侧 —— mcpp build 等命令的索引刷新策略(离线优先)、mcpp index
命令、以及 mcpp-index(mcpp 的库索引)的发布机制。
配套: xlings 侧的 xim-pkgindex 发布解耦见 xlings 仓
.agents/docs/2026-06-24-pkgindex-publish-decoupling-ci.md。
背景: 2026-06 Termux 适配中发现两个痛点 —— ① mcpp build 每次自动 xlings update
联网(被墙网络下卡 5 分钟,见 termux-android-adaptation §3);② 改了索引仓后默认客户端
拿不到(artifact 不刷新)。
- 资源仓:
xlings-res/mcpp-index(github + gitcode 两端均已创建)—— 放 mcpp 索引 artifact + 指针。 复用 xlings-res(mcpp 二进制本就在xlings-res/mcpp),不另起 mcpp-res 组织。 - secrets:
mcpp-community/mcpp-index仓已配XLINGS_RES_TOKEN+GITCODE_TOKEN。 - Actions:mcpp-index 仓已启用。
- 逐仓自文档:发布机制说明见
mcpp-community/mcpp-index仓.agents/docs/2026-06-24-artifact-publish-mechanism.md。 - 剩待办:① mcpp-index 仓加
publish-artifact.yml;② mcpp 侧加 artifact 拉取 + 离线优先(本文档 P0/P1)。
mcpp build自动联网刷索引:package_fetcher在装 xim 包前调ensure_official_package_index_fresh()→ 若 TTL 过期则xlings update(git 同步多个 索引仓,含被墙的 github 子索引)。每次构建都可能联网,离线/弱网体验差。- mcpp 已有
index子命令:mcpp index list|add|remove|update|pin|unpin(cli.cppm)。 即"显式刷新"的入口已存在,但 build 仍走"隐式自动刷新"。 - mcpp-index 是 git-only:mcpp git-clone
mcpp-community/mcpp-index到~/.mcpp/registry/data/mcpplibs,受 mcpp 的 index TTL 缓存影响("改了不刷"根因)。
区分两个阶段:
mcpp 第一次跑 / 沙盒初始化时(当前日志:Initialize mcpp sandbox layout (one-time) +
Fetching package index (one-time)),必须确保本地有一份可用索引 —— 这是唯一允许
"自动联网"的时刻:
- 优先用随发行版内置/种子索引(seed):mcpp 二进制包里捎带一份索引快照,首次直接落地, 零网络也能起步(离线装机也能用,后续再显式刷新)。
- 无 seed 或 seed 不可用时,首次自动拉一次(指针+artifact,失败回退 git);拉不到则 明确报错"首次初始化需要网络/或提供离线索引包",而不是静默半残。
- 首次落地后写入索引的版本/时间/sha 标记,作为后续
index status与 TTL 的依据。
索引一旦存在,命令默认只用本地索引,绝不为"顺手刷新"而联网;联网刷新由用户显式触发。
| 命令 | 联网? | 行为 |
|---|---|---|
| 首次 init | 是(仅此一次) | seed 落地 / 或自动拉一次,保证有索引 |
mcpp build / run / add |
否(默认) | 只读本地索引;缺包才提示 mcpp index update |
mcpp index update [--force] |
是 | 显式刷新(steady-state 唯一默认联网入口) |
mcpp index status |
否(可选 --check 联网比指针) |
显示本地索引版本/时间/来源 |
mcpp index list/search |
否 | 本地查询 |
要点:
- build 不再自动
xlings update(首次 init 已保证有索引)。本地索引存在即用;仅当解析 失败(包/版本本地查不到)时,提示"运行mcpp index update刷新",而不是默默联网卡住。 - 保留一个很长的软 TTL(如 24h)做"温和提醒"(stderr 一行 hint),但不阻塞、不自动拉。
mcpp index status:打印本地索引的 版本/时间戳/sha/来源(seed|artifact|git), 让用户/CI 知道是否该刷。- 不变量:任何 steady-state 命令在离线下都能跑(只要首次 init 成功过)。
如果某些场景(如 CI 首次)仍要自动刷,刷新动作要满足:
- 先查轻量指针:只 GET 一个小 JSON(
*-latest.json,几百字节)比对本地 sha; 命中(sha 相同)→ 零下载、零 git。这是"低成本重查"的核心,远比 git pull / 全量xlings update便宜。 - 未命中才下 artifact(整包 tar.gz,一次,带 sha 校验)。
- 指针/artifact 拉取失败 → 静默降级用本地(离线可用),不报错中止。
- 绝不在 build 主路径上做 git clone/pull(慢、易卡、被墙)。
对比现状:
ensure_official_package_index_fresh → xlings update是"全量 git 同步多个 仓",最重最易卡。改成"指针 sha 比对"后,绝大多数 build 不产生任何索引网络流量。
现状 git-only 的两个问题:① 客户端 git clone 慢/弱网易失败;② 没有"指针 sha"可做 低成本比对(只能 git fetch)。建议与 xim-pkgindex 统一为 artifact 模型:
- mcpp-index 仓加
publish-artifact.yml(pushpathspkgs/**+workflow_dispatch- 可选
schedule):打包pkgs/→ 生成mcpp-index-<gitsha>.tar.gz+ manifest - 更新指针
mcpp-index-latest.json,发到资源仓(github + gitcode,复用XLINGS_RES_TOKEN/GITCODE_TOKEN或 mcpp-res 等价物)。改索引 push → 自动发布, 不必发 mcpp 版本。
- 可选
- mcpp 侧加 artifact 拉取:
mcpp index update优先拉指针+artifact(命中 sha 跳过), git clone 仅作回退(MCPP_INDEX_SOURCE=artifact|git|auto,默认 auto),对齐 xlings 的XLINGS_INDEX_SOURCE模型。 - artifact 按内容哈希命名(解绑 mcpp/xlings 版本),指针随改随移。
收益:① 改 mcpp-index 即时生效(不绑发版);② build 的自动刷新可降级成"指针 sha 比对", 离线可用;③ 两套索引(xim-pkgindex / mcpp-index)发布+拉取模型统一,维护成本低。
- P0(离线优先):① 首次 init 保证有索引(优先内置 seed,否则自动拉一次,失败明确报错);
②
mcpp build去掉"自动xlings update",改为"本地优先 + 解析失败提示mcpp index update"; ③ 加mcpp index status。纯 mcpp 改动,立刻提升弱网/离线体验。 - P1(低成本刷新):
mcpp index update走"指针 sha 比对 → 命中跳过 / 未命中下 artifact"。 依赖 mcpp-index 有指针(见 P2)。 - P2(发布解耦):mcpp-index 仓加 artifact 发布 CI + mcpp 侧 artifact 拉取(与 xim-pkgindex 对齐)。
- ✅ P0②(build 离线优先 + 缺包触发刷新):
ensure_official_package_index_fresh(src/xlings.cppm) 不再因 TTL 过期就跑联网xlings update。改为 miss-triggered:- 依赖在本地索引里 → 直接用,零网络(常态 build,消除 Termux 首跑/构建卡几分钟的根因);
- 依赖在本地索引里查不到 → 自动刷新一次去拉它(
mcpp build路径以quiet=false调用, 打印一行Refreshing package index — \` not found locally`,让一次性网络停顿不像卡死)。 - 防重:刚刷过(<120s)且包仍缺失 → 不再重复跑
xlings update(上游确实没有,重拉无益), 避免一个 build 里多个缺包各跑一遍全量 git 同步。 commitf0f57ae(初版纯离线)→ 增补 miss-triggered + 防重 + 可见提示。
即"完全不联网"过严;稳态(依赖齐全)不联网,缺包则联网刷一次,二者兼得。
- ✅ P0③(
mcpp index status):新增只读、全程不联网的mcpp index status,显示 xim/mcpplibs 两索引的 present/fresh/age/path;缺索引时提示显式mcpp index update,否则确认本地可离线用。src/xlings.cppm导出IndexStatus+{default,official}_index_status;src/pm/index_management.cppmindex_status();CLI 接线 + e2etests/e2e/75_index_status_offline.sh(commitba92265)。 - P0①(seed 内置索引):暂沿用"缺则自动拉一次"(已满足首次保证有索引);随发行版捎带 seed 快照为后续优化。
- P1 / P2(指针 sha 比对 + mcpp 侧 artifact 拉取):mcpp-index 发布侧已就绪(WS2,资源仓
xlings-res/mcpp-indexpush 触发发 artifact + 指针);mcpp 客户端的 artifact 拉取/比对为后续 PR。 当前闭环经 git 路径已可用(稳态离线、缺包显式刷新)。
动机:mcpp 第一次运行常卡很久(Termux 实战),但日志太粗,看不出卡在哪一步。
需要在首次 init 全过程加 --verbose 才可见的细粒度 debug log,且每条带时间戳,
方便事后定位"卡很长时间"的具体步骤与耗时。
要覆盖的步骤(日志现状只有一行,需细化):
Initialize mcpp sandbox layout (one-time)
Fetching package index (one-time)
Bootstrap patchelf into mcpp sandbox (one-time) ← 重点
Bootstrap ninja into mcpp sandbox (one-time) ← 重点
First run no toolchain configured — installing gcc@15.1.0-musl ... ← 重点
每个步骤前后打 [verbose][HH:MM:SS.mmm] <step> start/done (Δ=<ms>),尤其:
- 每个 bootstrap(patchelf/ninja)的下载 URL、镜像、connect/下载/解压各阶段用时;
- toolchain 安装的 resolve / download / extract 各阶段用时;
- 索引 fetch 的 pointer 比对 / 下载 / git 各阶段用时。
约束:
- 仅
--verbose(或MCPP_LOG=debug)可见,日常用户输出不变。 - 时间戳统一(单调时钟取 Δ,墙钟取绝对时间)。
- 和最新版一起发布(随 mcpp 下个版本)。
配套铁律(已并入发布流程):每次 xlings / mcpp 发新版,对应索引也要更新到 latest
—— xim-pkgindex(xim:mcpp/xim:xlings 版本块 + artifact)、mcpp-index(若涉及库)都要随发版同步,
否则默认客户端装不到新版(见本仓 + xim-pkgindex 仓发布机制文档)。现已有 push 触发的
publish-artifact CI,改索引即自动发 artifact;版本块(mcpp.lua/xlings.lua 的 latest ref)
仍需在发版流程里 bump。
首次 init 保证有索引(内置 seed 优先,否则自动拉一次);之后离线优先(默认不联网刷索引,
缺包才提示显式 mcpp index update),刷新走"轻量指针 sha 比对"而非全量 git;mcpp-index
补齐 artifact + push 触发发布 CI,与 xim-pkgindex 统一模型。
相关:.agents/docs/2026-05-31-index-refresh-cache-labels-plan.md、
.agents/docs/2026-05-08-package-index-config.md;Termux 背景见
.agents/docs/2026-06-23-termux-android-adaptation.md §3。