feat(core): support Qoder plugin extensions - #8661
Conversation
E2E Test Report
|
|
Re-run on the post-review head — gate re-checked, still passing. Template looks good ✓ Problem: unchanged from the first pass — this is a feature, not a bug fix, so there is no reproduction to ask for. There is still no linked user request, which I would normally flag, but plugin-format compatibility is an established, documented capability of this repo (Gemini extensions and Claude plugins install through the same converter pipeline, and the user docs advertise that compatibility), so "Qoder plugins are not recognized by the installer" is a concrete gap in an existing capability rather than a speculative addition. Direction: aligned. The CHANGELOG has no Qoder mention yet, but it carries multiple entries maintaining the Claude/Gemini plugin compatibility surface, so extending that surface to a third format follows where the product already invests. Size: core paths touched ( Approach: the scope still feels right, and the seven fix commits since the first pass went into exactly the places a careful review would have pointed at: the update-check lifecycle (recorded commits, nested marketplace provenance, annotated tags), context-file merging and dedupe, MCP validation, and error-message sanitization. The increments map one-to-one onto review feedback — no drive-by growth. Risk: no elevated risk signals — none of the changed files match the revert-correlated paths from this repo's history. Moving on to code review. 🔍 中文说明在评审修复后的 head 上重跑——重新检查准入门槛,仍然通过。 模板完整 ✓ 问题: 与首轮一致——这是功能新增而非 bug 修复,没有需要复现的问题。PR 依旧没有关联的用户请求,这一点通常会提出来,但插件格式兼容已经是本仓库既有且已文档化的能力(Gemini 扩展和 Claude 插件走同一条转换器管线安装,用户文档也明确宣传了这一兼容性),所以"Qoder 插件无法被安装器识别"是现有能力上的一个具体缺口,而不是投机性的新增。 方向: 对齐。CHANGELOG 暂时没有 Qoder 相关条目,但有多条维护 Claude/Gemini 插件兼容面的记录,把该兼容面扩展到第三种格式符合产品已有的投入方向。 规模: 触及核心路径( 方案: 范围仍然合理,首轮之后的 7 个修复提交恰好都落在认真评审会指出的位置:更新检查链路(记录 commit、嵌套 marketplace 溯源、annotated tag)、context 文件合并与去重、MCP 校验和报错信息净化。每一处增量都与评审反馈一一对应——没有顺手膨胀。 风险: 无升级风险信号——变更文件均未命中仓库历史中与 revert 相关的高风险路径。 进入代码审查 🔍 — Qwen Code · qwen3.8-max Reviewed at |
Code review (re-run on the post-review head)Independent baseline first: given "make Qoder plugins installable through the existing extension pipeline", I would have written a third converter modeled on the Claude/Gemini ones, reused the existing confined copy logic, added the manifest to the shared detection list so archive validation comes for free, extended the three origin unions, and recorded the checked-out commit so update checks survive The ten findings from the maintainer's manual review round are all resolved:
The genuinely new machinery since the first pass is the Things re-verified against the base code rather than taken on faith: the renamed dispatcher's three call sites are all updated; the origin union's three mirrors (core config, acp-bridge, sdk-typescript) are all updated; appending the Qoder manifest keeps Not blocking, worth knowing: the Claude path's own string- How the install/update lifecycle works nowsequenceDiagram
participant P1 as User
participant P2 as ExtensionManager
participant P3 as cloneFromGit
participant P4 as Converter
participant P5 as Update check
P1->>P2: install from git or marketplace source
P2->>P3: clone into temp dir
P3-->>P2: checked-out commit
P2->>P4: convert (confined copy, strips git metadata)
P4-->>P2: converted extension, origin, provenance
P2->>P2: keep commit only when it describes the content
P1->>P5: extensions update, later
P5->>P5: compare recorded commit with ls-remote (peeled for tags)
Files changed (15 of 15)
Testing evidenceUnattended CI run — nothing was built or executed locally; the evidence below is the PR's own CI read through the API at the reviewed commit. Everything that ran is green: the full CI results for
One row per check name (latest run); skipped checks omitted; failures sort first. / 每个检查名一行(取最新一次运行),省略 skipped,失败项排在最前。 Sandboxed verification would settle the one claim static review cannot, and it is already in flight: the Not verified: the converter's fidelity to the real Qoder plugin layout (docs unreachable from this environment; a mismatch fails closed as a conversion error) and live third-party Git/npm hosts (covered with synthetic installer tests, per the author's own scope note). 中文说明代码审查(评审修复后的 head 重跑):先独立推演方案——要让 Qoder 插件走现有扩展管线安装,自然做法是仿照 Claude/Gemini 写第三个转换器、复用现有受限复制逻辑、把 manifest 加进共享检测列表让归档校验自动生效、扩展三处 origin 联合类型、并记录检出 commit 以便在剥离 维护者人工评审轮次的 10 个发现全部解决:1)更新检查不再就地转换用户自己的源目录——本地更新时的转换只作用于归档解压的临时目录或 Qoder 来源,且 Qoder 走 首轮之后真正的新机制是 已对照基线代码逐一核实而非轻信:重命名分发器的三个调用点全部更新;origin 联合类型的三处镜像(core config、acp-bridge、sdk-typescript)全部更新;追加 Qoder manifest 后 SUPPORTED_EXTENSION_MANIFESTS 索引 [0]/[3] 稳定且归档校验自动扩展;buildQwenExtensionFromPlugin 是"源 → 临时目录"的拷贝(从不写入源)且剥离 .git;ExtensionConfig 已有 displayName 与 contextFileName: string | string[] 类型。 非阻塞但值得了解:Claude 路径自身的字符串 mcpServers 解析仍未展开 wrapper(main 上的既有问题;本 PR 让 Qoder 绕开了它)。转换器与真实 Qoder 布局的契合度仍只由合成 fixture 验证——不匹配时以转换错误 fail-closed。 测试证据:无人值守 CI 运行,未本地构建或执行任何 PR 代码;以上为通过 API 读取的该 commit 的 PR 自身 CI。所有实际运行的检查均为绿色:Qwen Code CI 全程(ubuntu 单测、双平台 desktop shell、web-shell smoke、覆盖率)、Qwen Live Host CI、SDK Java(全部矩阵腿)均成功完成。三条腿显示 skipped 属设计使然而非本 PR 所致:macOS/Windows 单测腿与 Integration Tests (CLI, No Sandbox)——后者在 ci.yml 中仅由 merge_group 事件触发,即 PR 进入合并队列时运行,PR push 时永不运行。这也是此前评审轮次反复看到它被跳过的原因;PR 自带的 Qoder 安装 CLI 集成测试已在 diff 中,会在那里运行。 沙箱验证可以补上静态审查无法证明的承重声明,且已在进行:触发本次重跑的 /triage 调用同时启动了隔离的 verify 任务(见上方链接)——本 PR 的全部 Qoder fixture 都是按转换器实现的同一规格合成的,只有对基线构建的 A/B 运行才能证明基线确实拒绝 .qoder-plugin/plugin.json、且正是本 diff 移除了该拒绝。运行结束后报告会发布在这里。 未验证:真实 Qoder 插件布局的保真度(本环境无法访问其文档;不匹配时以转换错误 fail-closed);真实第三方 Git/npm 源(按作者自己的范围说明,由合成安装器测试覆盖)。 — Qwen Code · qwen3.8-max Reviewed at |
Code Coverage Summary
CLI Package - Full Text ReportCore Package - Full Text ReportFor detailed HTML reports, please see the 'coverage-reports-22.x-ubuntu-latest' artifact from the main CI run. |
|
Confidence: 4/5 — the fix rounds turned this into exactly what a careful review asks for: every one of the ten maintainer findings is resolved with a test that pins it, the new provenance machinery closes a real update-check hole, and CI is settled green on the reviewed commit. The remaining unknowns are external to the diff. Stepping back: the approach still matches my independent proposal, and I found no simpler path it missed. Every increment since the first pass maps one-to-one onto review feedback — no drive-by growth, nothing to carve out. The one judgment call worth surfacing honestly is finding 7's resolution: explicit marketplace selection now wins over root-Qoder-manifest detection, the opposite of what the review suggested — and I think it is the better trade-off, because silently installing different content than the user selected would be worse than a clear error. The test-to-production ratio is now ~2.6:1. My reservations, named plainly: the converter's contract with the real Qoder plugin format is still validated only against synthetic fixtures built from the same understanding as the implementation (a mismatch fails closed as a conversion error, and plugin-format compatibility is an established, documented investment of this repo), and the CLI integration leg runs only in the merge queue by design. The sandboxed verify run triggered alongside this re-run is still in flight and will post its A/B evidence separately; if it surfaces anything, this assessment should be revisited. One housekeeping note for the maintainer: the standing change-request reviews on this PR are the automated review flow flagging that CI is settled green on the reviewed commit and no pull-request workflow runs are pending, so approval attaches to that commit directly rather than being deferred. 中文说明置信度:4/5 —— 修复轮次把这个 PR 打磨成了认真评审所要求的样子:维护者的 10 个发现全部解决且每条都有测试锁定,新的溯源机制堵住了更新检查上的真实漏洞,该 commit 的 CI 已全部落定为绿。剩余的不确定性都在 diff 之外。 整体来看:方案仍与我独立推演的一致,也没有找到它遗漏的更简路径。首轮之后的每一处增量都与评审反馈一一对应——没有顺手膨胀,也没有可裁剪的部分。值得坦率指出的唯一判断分歧是第 7 条的解决方式:显式 marketplace 选择现在优先于根 Qoder manifest 检测,与评审建议的方向相反——但我认为这是更好的取舍,因为静默安装与用户所选不同的内容,比给出一个明确的错误更糟。测试与生产代码比现在约为 2.6:1。 明确说明我的保留意见:转换器与真实 Qoder 插件格式的契合仍只通过与实现同源的合成 fixture 验证(不匹配时以转换错误 fail-closed,且插件格式兼容是本仓库既有且已文档化的投入方向);CLI 集成腿按设计只在合并队列运行。随本次重跑启动的沙箱 verify 运行仍在进行,其 A/B 证据会单独发布;若发现问题,本结论应重新评估。 给维护者的一个说明:PR 上挂着的 request-changes 评审来自自动评审流程对 "Integration Tests (CLI, No Sandbox) 在 CI 中被跳过" 的标记——该任务在 ci.yml 中仅由 merge_group 触发,PR push 时永不运行,所以它会在本 PR 进入合并队列时运行,而不是在那之前。 该 commit 的 CI 已全部落定为绿,且没有仍在进行的 pull_request 工作流运行,因此批准直接绑定该 commit,而非延迟等待。 — Qwen Code · qwen3.8-max Reviewed at |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
LGTM, looks ready to ship — CI landed green after the review. ✅
Code reviewNice addition — the Qoder manifest/converter shape mirrors the Claude path closely, and reusing 1.
|
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Not reviewed: build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally.
中文说明
未审查:build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally。
— qwen3.8-max via Qwen Code /review (v0.21.7)
|
fix(core): address Qoder extension review feedback Addressed the review findings:
Validation: focused unit tests, focused CLI integration, build, typecheck, and lint. |
|
fix(core): handle annotated tags and unsafe parse errors Follow-up fixes for the two current Critical review findings:
Validation: focused unit tests, Core build, typecheck, lint, diff check, and confidentiality scan. |
|
fix(core): harden Qoder conversion edge cases Addressed the remaining verified conversion suggestions:
Validation: focused unit tests, focused CLI integration, Core build, typecheck, lint, diff check, and confidentiality scan. |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Not reviewed: build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally.
中文说明
未审查:build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally。
— qwen3.8-max via Qwen Code /review (v0.21.7)
|
@qwen-code /takeover |
|
🤝 Takeover engaged: the autofix loop now manages this PR — it will address new review feedback and resolve base conflicts until the label is removed or the round cap is reached. Remove the 中文说明🤝 已接管:autofix 循环现在管理此 PR —— 将持续处理新的评审反馈与 base 冲突,直到移除标签或达到轮次上限。移除 |
|
fix(core): sanitize Qoder conversion inputs Addressed the two Critical findings on the latest head:
Validation: Qoder converter unit tests, full build, typecheck, lint, focused CLI integration, diff check, independent reproduction, and confidentiality scan passed. The full CLI integration suite was also attempted; unrelated authenticated model tests failed because the local test environment had no valid credentials. Remaining Suggestions are deferred to follow-up work under the repository's review-round scope rule. |
|
🤖 Reviewed the latest feedback — no changes needed. Why, point by point: · 已审阅最新反馈——无需改动。逐点说明原因如下: Autofix round summary (PR #8661) — no code changesThis round triaged all feedback newer than the last evaluation. The two Critical findings from the latest automated review are already fixed on the current head, every remaining Suggestion already has a recorded disposition (fixed in earlier commits or deferred under the repository's review-round scope rule), and the one outstanding review objection — the skipped integration suite — is cleared below with a local run of the exact suite the merge-queue CI job executes. No commits were made this round. Clearing the CHANGES_REQUESTED objection: integration suiteBoth
Dispositions of the remaining feedback
VerificationCommands actually run this round against head
中文说明Autofix 轮次总结(PR #8661)—— 无代码变更本轮对上次评估之后的所有反馈进行了分类处理。最新一轮自动审查的两个 Critical 发现已在当前 head 上修复;其余所有 Suggestion 均已有记录在案的处理结论(要么已在更早的提交中修复,要么已按仓库的审查轮次范围规则延期);唯一未决的审查异议——集成测试套件未运行——已通过在本地运行与合并队列 CI job 完全相同的套件予以澄清。本轮未产生任何提交。 澄清 CHANGES_REQUESTED 异议:集成测试套件两个
其余反馈的处理结论
验证本轮在 head
Base-conflict check · 基分支冲突检查: no conflict with main. · 与 main 无冲突。 🧠 Handled by Qwen Code · model/模型 |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Reviewed. Suggestions are inline. Not reviewed: build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally.
中文说明
已审查。 建议见行内评论。 未审查:build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally。
— qwen3.8-max via Qwen Code /review (v0.21.7)
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
|
🤖 Addressed the latest review feedback (round 1/100). What changed, and what I pushed back on: · 已处理最新评审反馈(第 1/100 轮)。改动内容与我反驳保留之处如下: Round 3 review feedback addressedAll three inline suggestions are resolved in commit Findings and dispositions1. Nested-external marketplace installs record the wrong commit — RESOLVED[Suggestion] Verified against the code: the outer clone's hash is recorded before conversion, and all four external paths in Fix — implemented the suggested NOT_UPDATABLE option rather than threading nested commits/URLs into persisted metadata (impossible for nested release-archive sources, and a larger persisted-shape change):
Tests: new install tests assert the commit is retained for an internal marketplace plugin and dropped for a 2. Qoder local-update test does not pin source-directory immutability — RESOLVED[Suggestion] 3.
|
|
🤖 Reviewed the latest feedback — no changes needed. Why, point by point: · 已审阅最新反馈——无需改动。逐点说明原因如下: 🤖 Reviewed the latest feedback — no changes needed. Why, point by point: · 已审阅最新反馈——无需改动。逐点说明原因如下: Autofix round summary (PR #8661) — no code changesThis round's feedback contains exactly three new items: replies from @callmeYe on the three round-3 Key context: all three replies were posted ~27 seconds after commit Findings and dispositions1. rc:3737011114 — nested external marketplace sources: update-metadata limitation — NO ACTION (deferred by reviewer)Reply on the The in-PR mitigation already landed in 2. rc:3737011695 — Qoder local-update test hardening — NO ACTION (deferred by reviewer)Reply on the The requested assertion already landed in 3. rc:3737012104 — optional-null consistency in the Qoder converter — NO ACTION (deferred by reviewer)Reply on the The concrete defect (a JSON Why no changes
VerificationNo code changed this round, so no verification commands were executed. Head 中文说明Autofix 轮次小结(PR #8661)—— 无代码改动本轮反馈仅包含三条新内容:@callmeYe 在第 3 轮三条 关键背景:这三条回复都发布于提交 发现与处理1. rc:3737011114 —— 嵌套外部 marketplace 源的更新元数据局限 —— 不处理(评审方已推迟)
PR 内的缓解措施已在 2. rc:3737011695 —— Qoder 本地更新测试加固 —— 不处理(评审方已推迟)
所要求的断言已在 3. rc:3737012104 —— Qoder 转换器中的 optional-null 一致性 —— 不处理(评审方已推迟)
具体缺陷(JSON 中 为什么不做改动
验证本轮未改动任何代码,因此未执行任何验证命令。当前 head Base-conflict check · 基分支冲突检查: no conflict with main. · 与 main 无冲突。 🧠 Handled by Qwen Code · model/模型 |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Not reviewed: build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally.
中文说明
未审查:build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally。
— qwen3.8-max via Qwen Code /review (v0.21.7)
| } else if (fs.existsSync(path.join(extensionDir, QODER_PLUGIN_MANIFEST))) { | ||
| newExtensionDir = (await convertQoderPlugin(extensionDir)).convertedDir; | ||
| originSource = 'Qoder'; | ||
| } else if (pluginName) { | ||
| newExtensionDir = ( | ||
| await convertClaudePluginPackage( | ||
| extensionDir, | ||
| pluginName, | ||
| networkPolicy, | ||
| signal, | ||
| ) | ||
| ).convertedDir; | ||
| const converted = await convertClaudePluginPackage( | ||
| extensionDir, | ||
| pluginName, | ||
| networkPolicy, | ||
| signal, | ||
| ); | ||
| newExtensionDir = converted.convertedDir; | ||
| originSource = 'Claude'; | ||
| externalContent = converted.externalContent; |
There was a problem hiding this comment.
[Critical] R4-1: The Qoder manifest check runs before the pluginName branch, so a repo carrying both .claude-plugin/marketplace.json and a root .qoder-plugin/plugin.json always converts the repo root as one Qoder plugin — an explicit marketplace selection is silently ignored and different content is installed. — Failure scenario: probe-verified at this commit against a dual-manifest fixture: convertCompatibleExtension(root, 'requested-plugin') returned originSource: 'Qoder' and installed the root Qoder plugin; the requested plugin name was never consulted. Reachable via explicit owner/repo:name, interactive plugin choice on bare owner/repo, and local ./dir:name. Consent shows the substituted identity, but non-interactive consent defaults to yes, and the interactive flow asks "Select a plugin to install from marketplace" and then discards the answer. The stated rationale ("Qoder detection now precedes marketplace plugin selection") and its test fixture cover only the Qoder-only repo state (no marketplace.json), not dual-manifest installs. Suggested fix: honor an explicit selection first — reorder the two branches (safe for the local-update-check path, which passes pluginName as undefined), or guard the Qoder branch with !pluginName.
| } else if (fs.existsSync(path.join(extensionDir, QODER_PLUGIN_MANIFEST))) { | |
| newExtensionDir = (await convertQoderPlugin(extensionDir)).convertedDir; | |
| originSource = 'Qoder'; | |
| } else if (pluginName) { | |
| newExtensionDir = ( | |
| await convertClaudePluginPackage( | |
| extensionDir, | |
| pluginName, | |
| networkPolicy, | |
| signal, | |
| ) | |
| ).convertedDir; | |
| const converted = await convertClaudePluginPackage( | |
| extensionDir, | |
| pluginName, | |
| networkPolicy, | |
| signal, | |
| ); | |
| newExtensionDir = converted.convertedDir; | |
| originSource = 'Claude'; | |
| externalContent = converted.externalContent; | |
| } else if (pluginName) { | |
| const converted = await convertClaudePluginPackage( | |
| extensionDir, | |
| pluginName, | |
| networkPolicy, | |
| signal, | |
| ); | |
| newExtensionDir = converted.convertedDir; | |
| originSource = 'Claude'; | |
| externalContent = converted.externalContent; | |
| } else if (fs.existsSync(path.join(extensionDir, QODER_PLUGIN_MANIFEST))) { | |
| newExtensionDir = (await convertQoderPlugin(extensionDir)).convertedDir; | |
| originSource = 'Qoder'; |
中文说明
R4-1:Qoder manifest 检查位于 pluginName 分支之前,因此同时包含 .claude-plugin/marketplace.json 和根目录 .qoder-plugin/plugin.json 的仓库永远会把仓库根目录整体转换成一个 Qoder 插件——显式的 marketplace 选择会被静默忽略,最终安装的是不同的内容。
失败场景:已在本提交上用双 manifest 夹具探针验证:convertCompatibleExtension(root, 'requested-plugin') 返回 originSource: 'Qoder' 并安装了根目录 Qoder 插件;被请求的插件名从未被查询。可通过显式 owner/repo:name、裸 owner/repo 的交互式插件选择、本地 ./dir:name 三种方式触发。consent 界面会显示被替换后的身份,但非交互 consent 默认同意,且交互流程询问 "Select a plugin to install from marketplace" 之后却丢弃了用户的答案。已陈述的理由("Qoder detection now precedes marketplace plugin selection")及其配套测试夹具只覆盖纯 Qoder 仓库状态(无 marketplace.json),未覆盖双 manifest 安装状态。
建议修复:优先尊重显式选择——交换两个分支的顺序(对以 pluginName 为 undefined 调用本函数的本地更新检查路径安全),或用 !pluginName 保护 Qoder 分支。
— qwen3.8-max via Qwen Code /review (v0.21.7)
|
🤖 Addressed the latest review feedback (round 2/100). What changed, and what I pushed back on: · 已处理最新评审反馈(第 2/100 轮)。改动内容与我反驳保留之处如下: Autofix round summary (PR #8661)Two feedback items were triaged this round; both are addressed. No base-conflict merge was needed ( 1. [Critical] R4-1 — Qoder manifest check runs before the
|
|
Follow-up to the automatic round-three changes: external marketplace content is now recorded independently from the outer install source. Git and GitHub Release update checks conservatively return not updatable for nested external content, while repository-contained plugins continue using the outer revision or tag. Legacy Claude marketplace metadata without provenance preserves prior behavior. Verified with synthetic fixtures: 294 focused unit tests, the packaged CLI integration test, build, typecheck, lint, and diff checks. |
|
🤖 Reviewed the latest feedback — no changes needed. Why, point by point: · 已审阅最新反馈——无需改动。逐点说明原因如下: 🤖 Reviewed the latest feedback — no changes needed. Why, point by point: The only feedback newer than the last evaluation (2026-08-07T18:03:28Z) is the previous autofix round's own summary comment. There are no new reviews, no inline comments, no failed checks, and no still-red checks to address.
The branch remains at 中文说明🤖 已审阅最新反馈——无需更改。逐点说明如下: 上次评估(2026-08-07T18:03:28Z)之后唯一的反馈是上一轮 autofix 流程自己发布的总结评论。没有新的评审、没有内联评论、没有失败的检查,也没有持续红色的检查需要处理。
分支保持在 Base-conflict check · 基分支冲突检查: no conflict with main. · 与 main 无冲突。 🧠 Handled by Qwen Code · model/模型 |
|
@qwen-code /triage |
|
Sandboxed verification: ✅ passed — merge-ready (agent verdict) - workflow run Ran the PR in an isolated, token-free container: A/B against the base build, mock-free harness assertions, targeted gates. Advisory evidence for human reviewers — not a review, an approval, or a CI check. Scripted assertions: 375 passed · 0 failed · 375 total 中文 — 判定:✅ 通过 · 可合入(agent 判定)沙箱验证在隔离、无凭证的容器中执行了该 PR 的代码(与 base 构建 A/B 对照、无 mock harness 断言、定向门禁)。仅作为评审证据,不构成评审、批准或 CI 检查。 脚本断言:375 通过 · 0 失败 · 375 总计 Verification reportPR #8661 verification — feat(core): support Qoder plugin extensionsVerdict: 中文摘要
Scope
Central claim — A/B proofEnvironment: head = CI-built
Context merge semantics verified: configured files keep order, Secondary A — security probes (21/21,
|
| mutation | suite | result |
|---|---|---|
| none (control) | qoder + manager | 144/144 green |
M1 delete addContextFile('system-prompt.md') |
qoder-converter.test.ts | 3 red at intended context assertions |
| M2 delete manifest-symlink guard | qoder-converter.test.ts | 1 red ("rejects invalid manifests and escaping manifest symlinks") |
| M3 delete Qoder detection branch | qoder + manager | 7 red (all Qoder install paths: local, archive-url, npm, Git) |
No survivor among the introduced guards I mutated; the one surviving test under M1 ("merges explicit context … without duplicates") survives because its fixture lists system-prompt.md explicitly — the auto-add is pinned by the three tests M1 killed.
Targeted gates
- Unit:
qoder-converter(25) +claude-converter(52) +github(98) +extensionManager(119) +gemini-converter(11) = 305/305 on head (logs/gate-core-extension.log). - E2E: bundled CLI
extensions-install.test.ts2/2, including the new "installs a local Qoder plugin" (logs/e2e-cli-install.log). - Typecheck: core, acp-bridge, sdk-typescript clean (3 scripted checks).
Reviewer Test Plan walkthrough
- Dir install with metadata/resources/MCP/both context files — verified (cell A + E2E). 2. Wrapped-archive flatten — verified (cell B). 3. Git origin verified live (G1); archive-url/npm origins via the manager unit tests (mocked downloads; M3 proves they execute) — live network not exercised (no network in this container). 4. Update detection + uninstall — verified live (G1, cell A). 5. Escaping symlinks/manifest/context/resource — verified (S1/S2/S5/S7, M2).
Findings
F1 (advisory, non-blocking, pre-existing class): validateName echoes the raw untrusted name into error output
extensionManager.ts:2785 interpolates the manifest name verbatim into Invalid extension name: "${name}"…. The PR sanitizes its own new error paths with stripAnsiAndControl (proven by S9) but this shared door is untouched: a Qoder plugin named bad\u001b[31mRED\u0007BELL reaches the CLI user's terminal with raw ESC/BEL bytes on stderr (evidence/05-validate-name-echoes-control-chars.png, logs/ansi-qoder.err). The same echo reproduces on the pre-existing native qwen-extension.json path, so this is not a regression the PR introduced — the PR adds a new reachable surface for an existing class. Install is still safely rejected (schema + store direct-child guards hold), so severity is display-level terminal injection.
Measured minimal fix (advisory)
Wrap the echoed name: `Invalid extension name: "${stripAnsiAndControl(name)}". …` (import already exists in the package). Measured in a scratch tree: all three hostile names produce control-char-free errors (clean-error=true), benign installs byte-identical (edge probes 4/4), and the qoder+manager suites stay 144/144. Not applied to the PR — pre-existing code, author's call.
Not covered
- Live npm-registry / archive-URL / GitHub-hosted installs (no network); those source types are covered at the manager level by the PR's unit tests and share the verified conversion seam.
- Qoder hooks variable substitution (
usesPluginVariablesnow includes Qoder): no test pins it; the sharedperformVariableReplacementis tested for Claude. Untested axis, noted. - Daemon/ACP/SDK/Web-Shell consumption of the widened origin union: type-only widening; acp-bridge + sdk typecheck clean; no behavioral route test run.
- Per-commit attribution: depth-2 checkout exposes only the merge commit; the snapshot lists 8 commits,
git rev-list HEAD^1..HEAD^2returns 1 (shallow boundary) — aggregate diff verified instead. - Snapshot
baseRefOid(7edc16ba…) drifted from the merge-ref parent; A/B usedHEAD^1per the merge-ref contract. - Windows/macOS path behavior (container is Linux).
Methodology
Container = CI's node:22-bookworm image, tree = refs/pull/8661/merge at depth 2. Harnesses (ab-install.mjs, security-probes.mjs, git-provenance.mjs, edge-probes.mjs, vacuity-matrix.sh) are mock-free: they import the compiled dist of the arm under test (realpath-pinned), drive the real ExtensionManager/checkForExtensionUpdate over real filesystems and real git processes with local bare remotes, and encode every expectation as a scripted PASS/FAIL. Raw logs in logs/; captures in evidence/ via scripts/verify-capture.mjs. Base control rebuilt only packages/core (the PR's changed workspace; zero internal @qwen-code deps, lockfile untouched).
Evidence images
Harness scripts and raw logs are in the workflow run artifacts (7-day retention).
— Qwen Code · sandboxed verification
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
LGTM, looks ready to ship. ✅
|
🤖 Reviewed the latest feedback — no changes needed. Why, point by point: · 已审阅最新反馈——无需改动。逐点说明原因如下: No action required this roundThe review feedback collected for this round contains no actionable items:
The only issue-level comment is an automated status notice from No code changes were made, and no commit was created. The PR head remains at 中文说明本轮无需处理本轮收集的评审反馈中没有任何需要处理的项目:
唯一一条 Issue 级别的评论来自 本轮未做任何代码修改,也没有创建提交。PR 的 head 仍停留在 Base-conflict check · 基分支冲突检查: no conflict with main. · 与 main 无冲突。 🧠 Handled by Qwen Code · model/模型 |
Resolve the conflict between main's Qoder support (QwenLM#8661), which renamed convertGeminiOrClaudeExtension to convertCompatibleExtension and added externalContent tracking, and this PR's Claude-first manifest detection with Gemini fallback. The merged dispatch keeps the PR's detection flow, inserts the Qoder branch between the Claude and Gemini fallbacks, and propagates externalContent on every path. A deprecated alias keeps the pre-rename export for this branch's converter tests. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
|
Released in v0.21.9. |





What this PR does
This PR adds native installation compatibility for Qoder plugins across local directories, archives, Git repositories, archive URLs, and scoped npm packages. The compatibility layer converts public plugin metadata, standard commands, agents, skills, and MCP servers into a Qwen extension while preserving ordinary resources.
A root
system-prompt.mdis automatically loaded as extension context. It is merged and deduplicated with explicitly configured context, and it loads alongside the defaultQWEN.mdwhen present. Disabling the extension continues to exclude all of its context through the existing extension enablement gate.The conversion rejects manifests, context paths, resources, and symlinks that escape the plugin root, removes Git metadata from installed content, and records the checked-out revision needed for Git update checks. The
Qoderorigin is also represented consistently in Core, daemon SDK, and ACP status payloads.Why it's needed
Qoder plugins use a public manifest and resource layout that is close to the existing compatible plugin formats but is not currently recognized by the Qwen extension installer. Supporting that layout lets users install the same plugin through the existing extension workflows without repackaging it or manually creating a Qwen manifest.
Reviewer Test Plan
How to verify
sample-qoder-pluginwith public metadata, standard resource directories, a root MCP configuration,QWEN.md, andsystem-prompt.md; install it from a directory and confirm the generated extension exposes the metadata, resources, MCP server, and both context files.Qoderas its origin.Evidence (Before & After)
N/A — this is an installer compatibility, type, and documentation change with no UI layout change.
Tested on
Environment (optional)
Node.js 22, no sandbox. Focused converter, installer, archive, update, and shared compatibility unit tests passed; the focused CLI installation integration test, lint, type checking, build, and bundle also passed.
Risk & Scope
Linked Issues
N/A
中文说明
本 PR 做了什么
本 PR 为 Qoder 插件补充原生安装兼容,覆盖本地目录、归档、Git 仓库、归档 URL 和 scoped npm 包。兼容层会把公开插件元数据、标准 commands、agents、skills 和 MCP servers 转换为 Qwen Extension,同时保留普通资源。
根目录的
system-prompt.md会自动作为 Extension context 加载。它会与显式配置的 context 合并并去重;存在默认QWEN.md时,两者会同时加载。禁用 Extension 后,仍通过现有 Extension 启用开关排除该 Extension 的全部 context。转换会拒绝逃逸插件根目录的 manifest、context 路径、资源和 symlink,从安装内容中移除 Git 元数据,并记录 Git 更新检查所需的检出版本。Core、Daemon SDK 和 ACP 状态数据也统一支持
Qoder来源。为什么需要
Qoder 插件使用公开的 manifest 和资源布局,与现有兼容插件格式接近,但目前无法被 Qwen Extension 安装器识别。支持该布局后,用户可以直接复用现有 Extension 安装流程,无需重新打包或手工创建 Qwen manifest。
Reviewer 测试计划
如何验证
sample-qoder-plugin的合成插件,包含公开元数据、标准资源目录、根 MCP 配置、QWEN.md和system-prompt.md;从目录安装后,确认生成的 Extension 暴露对应元数据、资源、MCP server 和两个 context 文件。Qoder来源。证据(Before & After)
N/A —— 这是安装兼容、类型和文档变更,不涉及 UI 布局变化。
测试平台
环境(可选)
Node.js 22,无 sandbox。聚焦的转换器、安装器、归档、更新和共享兼容单测均通过;聚焦 CLI 安装集成测试、lint、类型检查、build 和 bundle 也均通过。
风险与范围
关联 Issue
N/A