背景
mcpp 的机器可读输出目前是分散演化的:xpkg parse --json、cache list --json 各自决定输出结构,pack --format 是产物形态不是输出格式,self env 只有人类文本,#372 又引入了第三套(ide snapshot --format json / ide configure --format ndjson + 独立的 envelope 和 ID 体系)。
同时已经有两个真实客户端在等接口:
本 RFC 提议先把契约层统一下来,再谈新增命令。
一、现状盘点(均为实测/源码核对)
1.1 输出格式选项已经分裂,且 --format 有语义冲突
| 命令 |
选项 |
语义 |
状态 |
| mcpp pack --format tar|dir |
--format |
产物形态 |
已发布 |
| mcpp xpkg parse --json |
--json |
输出格式 |
已发布,mcpp-community/mcpp-vscode#8 在用 |
| mcpp cache list --json |
--json |
输出格式 |
已发布 |
| mcpp ide snapshot --format json |
--format |
输出格式 |
仅在 #372 |
| mcpp ide configure --format ndjson |
--format |
输出格式 |
仅在 #372 |
已发布的 mcpp 里,"输出格式"的事实拼写是 --json;--format 被 pack 占用为另一个语义。
1.2 未知格式的响应,#372 内部就不一致
同一个 PR、同一天写的两个命令:
|
输出通道 |
输出格式 |
退出码 |
| ide snapshot --format yaml |
stdout |
JSON 文档 + MCPP_IDE_UNSUPPORTED_FORMAT 诊断 |
3 |
| ide configure --format json |
stderr |
人类文本 |
2 |
三个维度全不同。在把 --format 推广到更多命令之前,必须先定死这一条,否则是把已知缺陷标准化。
1.3 客户端拿不到的东西,mcpp 其实已经在算
mcpp self env 已经打印 MCPP_HOME / xlings home / index repos / default toolchain,但没有 --format json。结果 mcpp-community/mcpp-vscode#8 §2.4 被迫自己重实现整条定位逻辑:
mcpp home 定位按 src/home.cppm 的顺序:$MCPP_HOME > 二进制自包含布局 > ~/.mcpp……判定:二进制位于 <dir>/bin/mcpp,且祖先路径不含 target/ 或 data/xpkgs/……扩展侧补充一条检查:PATH 上的 mcpp 可能是 xlings shim(符号链接追到调度器而非真实二进制),因此自包含分支额外要求 <dir>/registry 实际存在
这段逻辑 100% 依赖 mcpp 内部实现、跨平台、易碎,而且是 mcpp-community/mcpp-vscode#8 全篇里唯一没有契约测试兜底的部分。给 self env 加 JSON 输出约 15 行,可以直接删掉它。
1.4 xpkg parse --json 确实没有 schema 版本字段
实测确认,mcpp-community/mcpp-vscode#8 §7.1 的请求成立且未被满足。成本是一个字段。
1.5 我们自己就是"汇合式协议"的消费者,而且绕开了它
xlings interface 是完整的汇合式设计:interface <capability> --args '<JSON>' + --list(20 个 capability,含 destructive 标记和 inputSchema)+ --version。
而 mcpp 对它的实际用法(src/xlings.cppm:1064-1076,main 分支):
// All platforms: try direct `xlings install ... -y` first.
// The direct command is more reliable for large packages (e.g. LLVM ~800MB) because:
// - it doesn't pipe through NDJSON interface (simpler subprocess chain)
// - xlings manages its own stdin/stdout/stderr
// - extraction subprocess coordination works normally
// The NDJSON interface path is kept as a fallback for progress reporting.
主路径走裸 xlings install -y,把输出全部重定向到 null,然后 mcpp 自己在 stderr 画一个只有秒数的 spinner。也就是说:我们宁愿丢掉 xlings 的全部结构化进度事件,也不走那条 NDJSON 管道。
事件流的唯一独占价值就是进度事件,它在真实压力下不可靠 → 消费者放弃它。这是"汇合传输层"最直接的反证。
另一个观察:xlings interface --list 里 20 个 capability 的 outputSchema 全部是 {"properties":{"exitCode":{"type":"integer"}}}。声明了 schema 但没填 —— 这比不声明更危险,因为客户端会以为有契约。(我们踩过:#238 的 multi-repo 失败模式发出 {"exitCode":1} 且没有 error 事件,所以 InstallProgressHandler 才要用 capturedDiagnostics_ 手工兜住 error/warn 文本。)
1.6 CDB 的 bootstrap 问题比想象中小
实测(mcpp 2026.8.6.3):
src/main.cpp: int main( { return missing_symbol; }
$ mcpp build → rc=1, "3 errors generated"
$ ls compile_commands.json → 1624 bytes,entry 完整
-std=c++23 -fprebuilt-module-path=... --no-default-config -nostdinc++ -isystem .../c++/v1
源码上的原因:src/build/ninja_backend.cppm:1546,write_compile_commands() 在 spawn ninja 之前执行。真正的门槛不是"编译成功",而是 prepare_build() 成功。
因此 IDE 侧真正缺的不是"能在编不过时拿到 CDB"(已经有了),而是:
- 不为拿 CDB 付一次完整编译 + 链接(这才是核心)
- CDB 覆盖 tests/** 及其 dev-dependency 上下文
- 退出码能区分"CDB 没写"和"CDB 写了但编译失败"
- 哪些输入变化会让这份 CDB 失效 —— 目前只有文档散文,没有机器可读输出
二、判据
沿用三档划分:
- 只有 mcpp 能做、且适合 mcpp 做的 → mcpp 做
- mcpp 可以很简单实现、且可复用的 → 可以 mcpp 做
- 外部插件实现与 mcpp 实现复杂度相当的 → mcpp 不做
第 3 档要注意一个反直觉的事实:有些能力 mcpp 做反而更贵,因为 mcpp 是多进程、公开契约、要向后兼容的,必须额外承担只读性保证、路径 containment、选择器语义、诊断降级 —— 而插件在自己进程里读文件,这些负担都不存在。
三、提案
阶段 0 — 先定死"未知 format 怎么办"(前置条件)
客户端在拿到输出之前无法知道 mcpp 支不支持它请求的格式,所以拒绝也必须用客户端能解析的形式说出来。
统一契约:
- 走 stdout(不是 stderr)
- 输出标准 envelope + diagnostics[0].code = MCPP_UNSUPPORTED_FORMAT
- 退出码 2(用法错误,符合 CLI 惯例)
- 不执行任何有副作用的工作
这一条不定,后面所有 --format 推广都是在复制缺陷。
阶段 1 — 通用输出信封(新模块 mcpp.wire)
destructive 字段的价值:mcpp-community/mcpp-vscode#8 §7.2 花了一整段请求"请确认 xpkg parse --json 无写副作用并可作为契约依赖",本机实测过还要请上游固定。有了这个字段,请求当场变成机器可判定的契约。它同时替代 #372 文档里那段"configure 不是 read-only,IDE 必须先拿 workspace trust"的散文 —— VSCode 的 untrusted workspace 门可以直接读字段决定跑不跑。
代码来源:Diagnostic/Position/Range/Severity 模型和 envelope 构造 + 内容寻址 ID 在 #372 里已经写好且质量很高(src/ide/model.cppm、src/ide/snapshot.cppm,约 150 行)。提议把它们从 mcpp.ide.* 提升为 mcpp.wire,服务所有命令而不只是 IDE。
新增协商入口(唯一"汇合"的地方):
mcpp --protocol-version → {"protocol":{"min":1,"max":1}}
一次调用、不需要项目、不触网。客户端启动时判断该走哪条路,不用先 spawn 一个可能失败的命令再解析错误消息(mcpp-community/mcpp-vscode#5 验收标准第 2 条)。
阶段 2 — --format 归一 + 老命令永久兼容
规范拼写:--format json(ndjson 保留给未来真正需要流式的场景)。
选 --format 而非 --json 的理由不是"跟 #372 一致",而是:布尔开关无法表达第二种格式,也无法承载"未知值"这个错误分支——而阶段 0 恰恰需要它。
兼容策略 —— 直接套用本仓库已有的范式(src/toolchain/compat.cppm):
THE ONLY FILE that knows pre-0.0.93 spellings. Core code sees canonical forms exclusively; the public parse entry points call normalize_ first.* Deleting this module would break exactly one thing: old inputs — never a canonical path.
cmdline 入口一处归一化: --json → --format json
核心代码只见 --format
三条硬约束:
- --json 永久保留,不删
- 不打 deprecation 警告 —— design: mcpp.toml 补全重做方案 —— 语义模块 + index 动态数据(#4 重做) mcpp-vscode#8 已经在用它,用户装的 mcpp 版本参差;警告只会污染扩展捕获的输出
- 归一化只在入口做一次,核心代码不得再感知旧拼写
pack --format tar|dir 的语义冲突:它是产物形态不是 stdout 格式。两条路,倾向前者:
- (a) 文档声明 pack 为例外(它没有机器可读输出,不参与本协议)
- (b) 加 --layout tar|dir 为规范拼写,--format 降为别名,走同一套兼容机制
阶段 3 — 补齐机器接口(按判据筛过)
两个设计约束:
- mcpp metadata 默认必须不触网、不解析依赖(对标 cargo metadata --no-deps)。否则 design: mcpp.toml 补全重做方案 —— 语义模块 + index 动态数据(#4 重做) mcpp-vscode#8 的场景(编辑 mcpp.toml 时补全)每次敲键都可能触发网络。需要依赖图和失效清单的,显式加 --resolved。
- CDB 失效输入清单是当前最大的缺口,它是插件绝对拿不到的信息(哪些输入进了指纹),而且数据已经全在 BuildContext::fp 和 BuildPlan 里:
有了它,客户端的 watcher 就有了机器可读依据,而不是照着文档里一段会漂移的散文硬编码。
阶段 4 — 明确不做
| 不做 |
理由 |
| mcpp interface <cap> --args / --list / capability 自描述 |
mcpp 已有 subcommand 树 + --help 作为发现机制;xlings 的 interface 面向 AI agent 编排,mcpp 的消费者是 IDE 插件和 CI 脚本,形态不同 |
| NDJSON 事件流(seq / operationId / progress 事件) |
one-shot 进程用「spawn + 退出码 + 读结果文件」就够(插件侧约 10 行)。事件协议是为 daemon 准备的,daemon 不在计划内。而且我们自己已经绕开了 xlings 的同款设计(§1.5) |
| workspace 成员发现的独立命令(ide snapshot) |
插件读 [workspace].members 约 60 行;mcpp 做要 400+ 行(额外承担只读保证、路径 containment、选择器语义、诊断降级)。成员发现并入 mcpp metadata 即可 |
| artifact 状态枚举 / phase 状态机 / 快照 ID 体系 |
stat() + 客户端自己的状态机 |
| CDB 的版本化发布体系(reply 内容寻址 / current.json / 发布锁 / 回滚) |
插件要「保留上一份可用 CDB」只需 copy + 失败 copy 回来(约 20 行);mcpp 做要 330+ 行且引入 current.json 单例 vs 多 configurationId 的结构性问题。mcpp 侧只需保证「自己写 CDB 时不写坏」(原子 replace,约 30 行) |
四、必须守住的纪律
xlings interface 的 outputSchema 全空(§1.5)教了一课:envelope 的价值全在 data 被真正版本化和文档化上。只做外层信封、内层随手改,客户端会因为"看到 schemaVersion 就以为有契约"而被坑得更惨。
具体到 mcpp:
同一条纪律也适用于错误码:MCPP_IDE_CONFIGURE_FAILED 这种「一个码覆盖全部失败 + 文档明令不许解析人类消息」的形状,是名义结构化、实际空洞。新增的每个失败分支要么有自己的 code,要么显式声明为「不可细分」。
#372 里有三类内容,建议分开处理:
A. 直接可用、建议尽快单独合入
- src/build/test_targets.cppm(81 行)—— 把 tests/** 发现从 run_tests 提取出来,消除了 IDE CDB 与 mcpp test 在 member 选择 / 命名 / per-glob flags 上漂移的可能。是真正的收敛。
- write_fresh_compile_commands + platform::fs::replace_file + FileLock(ec) —— 顺带修掉一个既有缺陷:write_compile_commands() 目前是 ofstream 截断写,非原子、不检查失败,clangd 可能读到半截 JSON。
- prepare.cppm 的 stdout 纪律修复。
- 对应单测(test_compile_commands / test_platform_fs / test_test_options)。
B. 建议捞进本 RFC 复用
- src/ide/model.cppm 的 Diagnostic/Position/Range/Severity + wire_name(~90 行)
- src/ide/snapshot.cppm 的 envelope 构造 + 内容寻址 ID(~60 行)
这两块设计质量高,只是被绑死在一个命令上。提升为 mcpp.wire 后可服务全部 JSON 出口。
C. 建议不合入
inspect.cppm(433) / publish.cppm(333) / events.cppm(106) / cmd_ide.cppm(119) / ide snapshot / ide configure / IdePhase·SnapshotState·ArtifactState(生产代码零使用者)/ describe_std_module(仅单测调用)/ .xlings.json pin bump(与本 PR 无关)/ docs/superpowers/ 目录树(本仓库设计文档惯例是 .agents/docs/)。
另外,若 #372 按现状推进,两个问题需要先修:
- NDJSON stdout 仍有未堵住的污染源。 src/pm/package_fetcher.cppm:1036 硬编码 /*quiet=*/false 调用 ensure_official_package_index_fresh,其内部 xlings::print_status(xlings.cppm:1583)和 update_index_unguarded 的 run_streaming 回调直接 std::println 到 stdout,不看 mcpp::ui::is_quiet()。任一 xim: 包(含工具链)在本地索引缺失且未 debounce 时触发,xlings update 的全量输出会进 NDJSON 流。tests/e2e/198 用 _inherit_toolchain.sh 预置本机工具链,索引永远命中,结构性覆盖不到。
根因是 stdout 归属分散在多个 bool 参数里;建议收敛为单一开关(让 xlings::print_status 走 mcpp::ui::status,或加 ui::stdout_is_protocol() 一票否决)。
- 文档指定的客户端流程在 rooted workspace 的根成员上必然失败。 inspect.cppm 对 rooted workspace 产出 workspacePath == "."(单测 RootedWorkspaceSelectsRoot 明确断言),而文档 §7.2 要求客户端 configure --package <workspacePath> per member;-p . 经 resolve_member_dir 在 [workspace].members 里找不到 . → 报错退出 3。
根因是 member selector 语法在三处独立推导:project.cppm::resolve_member_dir、prepare.cppm:951、ide/inspect.cppm::matches_selector,前两处一致、第三处多了 . 别名。现有测试恰好绕开(e2e 用 virtual workspace;单测里 name/dir/workspacePath 三者相同)。
六、实施顺序
1. 阶段 0:未知 format 的统一契约(前置,不做后面全是复制缺陷)
2. 阶段 1:mcpp.wire envelope + destructive + --protocol-version (~150 行,从 #372 捞)
3. 阶段 2:--format 归一 + --json 入口别名(compat 模式,无警告) (~50 行)
4. 阶段 3a:self env / xpkg parse / cache list 接入 envelope (~35 行)
5. 阶段 3b:mcpp build --configure-only + CDB 失效输入清单 (~170 行)
6. 阶段 3c:mcpp metadata [--resolved] (~250 行)
前 5 步合计约 400 行,即可满足 mcpp-community/mcpp-vscode#5 的全部验收标准和 mcpp-community/mcpp-vscode#8 §7 的两条请求。
七、待确认
@Sunrisepeak
- --format 作为规范拼写、--json 永久别名且不打 deprecation 警告 —— 是否接受?
- pack --format tar|dir 走「声明为例外」还是「加 --layout 别名迁移」?
- mcpp --protocol-version 作为唯一的汇合式协商入口 —— 是否接受?(明确不做 mcpp interface)
- destructive 字段是否接受作为公开契约(等于把 design: mcpp.toml 补全重做方案 —— 语义模块 + index 动态数据(#4 重做) mcpp-vscode#8 §7.2 的人工承诺固化)?
@wellwei
- feat(ide): add versioned project snapshots and pre-build CDB #372 按 §5 的 A/B/C 拆分是否可行?A 部分单独 PR 可以很快合入并发版,不阻塞 feat: integrate mcpp build --configure-only into clangd workflow mcpp-vscode#5。
- feat: integrate mcpp build --configure-only into clangd workflow mcpp-vscode#5 若改为消费 mcpp build --configure-only(spawn + 退出码 + 读 CDB)而非 NDJSON 事件流,扩展侧代码会更少 —— 但已有实现分支需返工,是否值得?
- §5 末尾两个问题(NDJSON 污染、-p .)若 feat(ide): add versioned project snapshots and pre-build CDB #372 继续推进,需要先处理。
@Ximiaw
- mcpp self env --format json 是否能覆盖 design: mcpp.toml 补全重做方案 —— 语义模块 + index 动态数据(#4 重做) mcpp-vscode#8 §2.4 的全部需求(home / registry / index 路径 + shim 情形)?还缺什么字段请列出。
- mcpp metadata --format json(不触网,含 manifest 诊断 code/path/line/column)是否满足 design: mcpp.toml 补全重做方案 —— 语义模块 + index 动态数据(#4 重做) mcpp-vscode#8 §1「不做」栏里那条"等上游版本化 schema"的一部分?还是说静态字段键/枚举值仍需要独立的 schema 出口?
背景
mcpp 的机器可读输出目前是分散演化的:xpkg parse --json、cache list --json 各自决定输出结构,pack --format 是产物形态不是输出格式,self env 只有人类文本,#372 又引入了第三套(ide snapshot --format json / ide configure --format ndjson + 独立的 envelope 和 ID 体系)。
同时已经有两个真实客户端在等接口:
本 RFC 提议先把契约层统一下来,再谈新增命令。
一、现状盘点(均为实测/源码核对)
1.1 输出格式选项已经分裂,且 --format 有语义冲突
已发布的 mcpp 里,"输出格式"的事实拼写是 --json;--format 被 pack 占用为另一个语义。
1.2 未知格式的响应,#372 内部就不一致
同一个 PR、同一天写的两个命令:
三个维度全不同。在把 --format 推广到更多命令之前,必须先定死这一条,否则是把已知缺陷标准化。
1.3 客户端拿不到的东西,mcpp 其实已经在算
mcpp self env 已经打印 MCPP_HOME / xlings home / index repos / default toolchain,但没有 --format json。结果 mcpp-community/mcpp-vscode#8 §2.4 被迫自己重实现整条定位逻辑:
这段逻辑 100% 依赖 mcpp 内部实现、跨平台、易碎,而且是 mcpp-community/mcpp-vscode#8 全篇里唯一没有契约测试兜底的部分。给 self env 加 JSON 输出约 15 行,可以直接删掉它。
1.4 xpkg parse --json 确实没有 schema 版本字段
实测确认,mcpp-community/mcpp-vscode#8 §7.1 的请求成立且未被满足。成本是一个字段。
1.5 我们自己就是"汇合式协议"的消费者,而且绕开了它
xlings interface 是完整的汇合式设计:interface <capability> --args '<JSON>' + --list(20 个 capability,含 destructive 标记和 inputSchema)+ --version。
而 mcpp 对它的实际用法(src/xlings.cppm:1064-1076,main 分支):
主路径走裸 xlings install -y,把输出全部重定向到 null,然后 mcpp 自己在 stderr 画一个只有秒数的 spinner。也就是说:我们宁愿丢掉 xlings 的全部结构化进度事件,也不走那条 NDJSON 管道。
事件流的唯一独占价值就是进度事件,它在真实压力下不可靠 → 消费者放弃它。这是"汇合传输层"最直接的反证。
另一个观察:xlings interface --list 里 20 个 capability 的 outputSchema 全部是 {"properties":{"exitCode":{"type":"integer"}}}。声明了 schema 但没填 —— 这比不声明更危险,因为客户端会以为有契约。(我们踩过:#238 的 multi-repo 失败模式发出 {"exitCode":1} 且没有 error 事件,所以 InstallProgressHandler 才要用 capturedDiagnostics_ 手工兜住 error/warn 文本。)
1.6 CDB 的 bootstrap 问题比想象中小
实测(mcpp 2026.8.6.3):
src/main.cpp: int main( { return missing_symbol; } $ mcpp build → rc=1, "3 errors generated" $ ls compile_commands.json → 1624 bytes,entry 完整 -std=c++23 -fprebuilt-module-path=... --no-default-config -nostdinc++ -isystem .../c++/v1源码上的原因:src/build/ninja_backend.cppm:1546,write_compile_commands() 在 spawn ninja 之前执行。真正的门槛不是"编译成功",而是 prepare_build() 成功。
因此 IDE 侧真正缺的不是"能在编不过时拿到 CDB"(已经有了),而是:
二、判据
沿用三档划分:
第 3 档要注意一个反直觉的事实:有些能力 mcpp 做反而更贵,因为 mcpp 是多进程、公开契约、要向后兼容的,必须额外承担只读性保证、路径 containment、选择器语义、诊断降级 —— 而插件在自己进程里读文件,这些负担都不存在。
三、提案
阶段 0 — 先定死"未知 format 怎么办"(前置条件)
客户端在拿到输出之前无法知道 mcpp 支不支持它请求的格式,所以拒绝也必须用客户端能解析的形式说出来。
这一条不定,后面所有 --format 推广都是在复制缺陷。
阶段 1 — 通用输出信封(新模块 mcpp.wire)
{ "schemaVersion": 1, "kind": "mcpp.metadata", // mcpp.env / mcpp.xpkg / mcpp.cdb / ... "destructive": false, // ← 借鉴 xlings interface 的设计 "mcpp": { "version": "2026.8.8.1", "protocol": { "min": 1, "max": 1 } }, "data": { /* 命令特有 */ }, "diagnostics": [ { "code": "...", "severity": "error|warning", "source": "mcpp", "message": "...", "path": "...", "range": {"start":{"line":1,"column":1},"end":{...}} } ] }destructive 字段的价值:mcpp-community/mcpp-vscode#8 §7.2 花了一整段请求"请确认 xpkg parse --json 无写副作用并可作为契约依赖",本机实测过还要请上游固定。有了这个字段,请求当场变成机器可判定的契约。它同时替代 #372 文档里那段"configure 不是 read-only,IDE 必须先拿 workspace trust"的散文 —— VSCode 的 untrusted workspace 门可以直接读字段决定跑不跑。
代码来源:Diagnostic/Position/Range/Severity 模型和 envelope 构造 + 内容寻址 ID 在 #372 里已经写好且质量很高(src/ide/model.cppm、src/ide/snapshot.cppm,约 150 行)。提议把它们从 mcpp.ide.* 提升为 mcpp.wire,服务所有命令而不只是 IDE。
新增协商入口(唯一"汇合"的地方):
mcpp --protocol-version → {"protocol":{"min":1,"max":1}}一次调用、不需要项目、不触网。客户端启动时判断该走哪条路,不用先 spawn 一个可能失败的命令再解析错误消息(mcpp-community/mcpp-vscode#5 验收标准第 2 条)。
阶段 2 — --format 归一 + 老命令永久兼容
规范拼写:--format json(ndjson 保留给未来真正需要流式的场景)。
选 --format 而非 --json 的理由不是"跟 #372 一致",而是:布尔开关无法表达第二种格式,也无法承载"未知值"这个错误分支——而阶段 0 恰恰需要它。
兼容策略 —— 直接套用本仓库已有的范式(src/toolchain/compat.cppm):
三条硬约束:
pack --format tar|dir 的语义冲突:它是产物形态不是 stdout 格式。两条路,倾向前者:
阶段 3 — 补齐机器接口(按判据筛过)
两个设计约束:
有了它,客户端的 watcher 就有了机器可读依据,而不是照着文档里一段会漂移的散文硬编码。
阶段 4 — 明确不做
四、必须守住的纪律
xlings interface 的 outputSchema 全空(§1.5)教了一课:envelope 的价值全在 data 被真正版本化和文档化上。只做外层信封、内层随手改,客户端会因为"看到 schemaVersion 就以为有契约"而被坑得更惨。
具体到 mcpp:
同一条纪律也适用于错误码:MCPP_IDE_CONFIGURE_FAILED 这种「一个码覆盖全部失败 + 文档明令不许解析人类消息」的形状,是名义结构化、实际空洞。新增的每个失败分支要么有自己的 code,要么显式声明为「不可细分」。
五、与 #372 的关系
#372 里有三类内容,建议分开处理:
A. 直接可用、建议尽快单独合入
B. 建议捞进本 RFC 复用
这两块设计质量高,只是被绑死在一个命令上。提升为 mcpp.wire 后可服务全部 JSON 出口。
C. 建议不合入
inspect.cppm(433) / publish.cppm(333) / events.cppm(106) / cmd_ide.cppm(119) / ide snapshot / ide configure / IdePhase·SnapshotState·ArtifactState(生产代码零使用者)/ describe_std_module(仅单测调用)/ .xlings.json pin bump(与本 PR 无关)/ docs/superpowers/ 目录树(本仓库设计文档惯例是 .agents/docs/)。
另外,若 #372 按现状推进,两个问题需要先修:
根因是 stdout 归属分散在多个 bool 参数里;建议收敛为单一开关(让 xlings::print_status 走 mcpp::ui::status,或加 ui::stdout_is_protocol() 一票否决)。
根因是 member selector 语法在三处独立推导:project.cppm::resolve_member_dir、prepare.cppm:951、ide/inspect.cppm::matches_selector,前两处一致、第三处多了 . 别名。现有测试恰好绕开(e2e 用 virtual workspace;单测里 name/dir/workspacePath 三者相同)。
六、实施顺序
前 5 步合计约 400 行,即可满足 mcpp-community/mcpp-vscode#5 的全部验收标准和 mcpp-community/mcpp-vscode#8 §7 的两条请求。
七、待确认
@Sunrisepeak
@wellwei
@Ximiaw