feat(daemon): support local path extension installs - #10131
Conversation
E2E test reportVerified against the PR head with a real daemon started from the current TypeScript source, using bearer authentication, an isolated workspace, and a temporary
Additional regression coverage passed for the compatibility route, the V2 route, relative-path rejection, |
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. |
|
Thanks for the PR! Template looks good ✓ Problem: not theoretical — the parity gap is real. The daemon install routes today reject local sources with an explicit error ("Only GitHub, Git, and npm extension installs are supported over the daemon endpoint"), while the CLI happily installs from daemon-local paths. The old route-level test even pinned that rejection, so this is observed behavior being changed, not a hypothetical. Direction: aligned. Daemon-side Extension management is an actively shipped area (authenticated HTTPS git installs, batch activation APIs, local archive installs all landed recently), and this closes the obvious remaining REST/CLI asymmetry. It also follows the established capability-gating pattern — Size: small. ~80 production logic lines (route validator + one capability registry entry), ~267 test lines, ~73 docs lines. The Approach: the scope feels right. It reuses the existing source parser and install pipeline (no new route, no new SDK method), extracts one shared validator where three inline copies lived, and the relative-path rejection is justified by actual parser behavior — Risk: no elevated risk signals (no match against historically revert-prone paths). Moving on to code review. 🔍 中文说明感谢贡献! 模板完整 ✓ 问题:不是理论问题——这个能力差距真实存在。daemon 安装路由目前会以明确错误("Only GitHub, Git, and npm extension installs are supported over the daemon endpoint")拒绝本地来源,而 CLI 可以直接从 daemon 本地路径安装。旧的路由级测试甚至固化了这个拒绝行为,所以这是被观察到的行为变更,不是假设。 方向:对齐。daemon 侧 Extension 管理是近期持续交付的领域(认证 HTTPS git 安装、批量激活 API、本地压缩包安装均已落地),本 PR 补齐了 REST/CLI 之间显见的不对称。它也沿用了既有的能力标记模式—— 规模:很小。约 80 行生产逻辑(路由校验器 + 一个能力注册项)、约 267 行测试、约 73 行文档。 方案:范围合理。复用了现有的来源解析器和安装流水线(没有新路由、没有新 SDK 方法),把三处内联检查抽成一个共享校验器;相对路径拒绝有真实的解析器行为支撑—— 风险:无升级风险信号(未命中历史上高回滚率的路径)。 进入代码审查 🔍 — Qwen Code · qwen3.8-max Reviewed at |
Code reviewOne blocking finding. The capabilities envelope integration test was not updated for the new tag. Everything else checked out cleanly:
Testing evidence (this PR's own CI, via API — PR code was not executed here)The Ubuntu unit suite and the Serve A/B job are still running on the reviewed commit; no failures so far, so no log excerpt to quote. The macOS/Windows test jobs and the CLI integration job show Final CI results for
One row per check name (latest run); skipped checks omitted; failures sort first. / 每个检查名一行(取最新一次运行),省略 skipped,失败项排在最前。 Sandboxed verification would settle the remaining gap: Not verified: real-daemon behavior on Windows/Linux (author marked both 中文说明代码审查一处阻塞性问题。 能力清单的集成测试没有为新标记更新。 其余部分核对无误:
测试证据(来自本 PR 自身的 CI,通过 API 获取——此处未执行 PR 代码)Ubuntu 单元测试与 Serve A/B 任务在受审提交上仍在运行;目前没有失败,因此没有日志摘录可引用。macOS/Windows 测试任务与 CLI 集成任务显示 沙箱验证可以补齐剩余缺口: 未验证:Windows/Linux 上的真实 daemon 行为(作者两项均标记 — Qwen Code · qwen3.8-max Reviewed at |
|
Confidence: 2/5 — direction, design, and code review all point at approval; one deterministic test regression is the only thing standing in the way. My independent proposal for this problem — widen the allowed source set to What holds it back is the one gap: the PR deliberately changes the capabilities envelope and updated both unit-level feature lists, but missed the exact-match integration assertion. That test contradicts shipped behavior the moment it runs, and it belongs to this change, not to a follow-up. It's a one-line fix; once the integration list carries the new tag, this is ready. Requesting changes on that single item. 中文说明针对这个问题的独立方案——把允许的来源集合放宽到 唯一的缺口:本 PR 有意变更了能力清单,更新了两处单元测试的特性列表,却漏掉了精确匹配的集成断言。该测试一旦运行就会与已交付的行为矛盾,它属于本次改动,不属于后续跟进。修复只需一行;集成清单补上新标记后即可合入。 基于这唯一一项请求修改。 — Qwen Code · qwen3.8-max Reviewed at |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
One item to fix before this can merge — see my review notes above: the exact-match capabilities list in integration-tests/cli/qwen-serve-routes.test.ts needs the new extension_local_path_install tag added after extension_git_credentials, otherwise the envelope test contradicts the shipped behavior. Everything else checks out. 🙏
🩺 serve daemon A/BBuilt the PR base vs this PR head
|
| field | PR base (before) | this PR (after) |
|---|---|---|
features[] |
— | "extension_local_path_install" |
— Qwen Code · serve A/B
|
Addressed the blocking capability-envelope finding in Verification:
There are no review threads, and the only requested change on the reviewed head |
The automated review requested one exact capability-envelope update on eb316e8. Current head b0d1ace adds extension_local_path_install in registry order; the focused integration test and independent rerun both pass (1 passed, 35 skipped), and there are no review threads. The blocking review is stale.
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Partially reviewed — gaps disclosed. Suggestions are inline.
Not reviewed: build-and-test — Test (windows-latest, Node 22.x) was skipped in CI (merge_group-gated) and the platform-native unit suite did not run locally.
中文说明
仅完成部分审查,审查缺口已披露。 建议见行内评论。
未审查:build-and-test — Test (windows-latest, Node 22.x) was skipped in CI (merge_group-gated) and the platform-native unit suite did not run locally。
— qwen3.8-max via Qwen Code /review (v0.22.0)
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Partially reviewed — gaps disclosed. Suggestions are inline.
Not reviewed: build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI (merge_group-gated) and its suite did not run locally.
Not reviewed: build-and-test — Test (windows-latest, Node 22.x) was skipped in CI (merge_group-gated) and the platform-native unit suite did not run locally.
中文说明
仅完成部分审查,审查缺口已披露。 建议见行内评论。
未审查:build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI (merge_group-gated) and its suite did not run locally。
未审查:build-and-test — Test (windows-latest, Node 22.x) was skipped in CI (merge_group-gated) and the platform-native unit suite did not run locally。
— qwen3.8-max via Qwen Code /review (v0.22.0)
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
No issues found. LGTM! ✅
中文说明
未发现问题。LGTM!✅
— qwen3.8-max via Qwen Code /review (v0.22.2)
qqqys
left a comment
There was a problem hiding this comment.
Approving. Independent review of the current head (9ac5cab2) found no blocking (Critical) issues:
- The daemon install paths now admit
localsources only as absolute daemon-host paths (path.isAbsoluteon the host platform), rejectref/autoUpdatefor them, and keep git/github-release/npm behavior unchanged. The three previously duplicated inline checks collapse into one assertion applied consistently on the workspace-route sync check, the queued-operation path, and the global V2 route. - No escalation over the existing trust model: daemon-token/loopback callers could already install git/npm extensions (arbitrary code), and absolute-path local installs already exist via the interactive CLI. Installs copy into managed storage (
~/.qwen/extensions/…) rather than loading the source directory in place;installed.path≠ source is pinned by the integration test. - Relative sources fail before any
prepareExtensionInstall, including theowner/reposhadowing case (a relative path that also exists as a local directory is still rejected), and cross-host path shapes (e.g. a Windows-style path on a Linux daemon) fail the host-platform absoluteness check. - The previously flagged exact-match capabilities assertion now carries
extension_local_path_installat this head. - CI is green at this head (Test ubuntu 23m, Serve A/B, web-shell E2E smoke, Desktop Shell); the integration lane is skip-gated for fork PRs as usual.
The bot has approved at this head; concur.
What this PR does
This PR allows both daemon Extension install contracts to accept an existing absolute path on the daemon host through their existing
sourcefield. It preserves the current asynchronous operation and activation models, advertises the behavior throughextension_local_path_install, and documents the shared TypeScript SDK request contract.Local directories and supported local archives use the existing Extension installation pipeline and are copied into managed storage. Relative paths are rejected to prevent daemon process cwd from changing source identity or shadowing a GitHub
owner/reposhorthand. Local sources also rejectrefandautoUpdate, matching the CLI contract.Why it's needed
The CLI already installs Extensions from daemon-local paths, but REST clients can only install remote GitHub, Git, or npm sources (or upload an archive through a separate binary endpoint). A caller that has already placed an Extension on the daemon filesystem currently has to open a terminal and invoke the CLI instead of using the authenticated operation API.
Reviewer Test Plan
How to verify
/capabilitiesincludesextension_local_path_install.202operation that reachessucceededand a catalog entry withinstallType: "local"..or an existing relativeowner/repopath. Expect rejection before installation preparation, with no Extension committed.reforautoUpdate: true. Expect rejection as an inapplicable option.Evidence (Before & After)
N/A — REST, SDK contract, and documentation change with no UI surface.
Tested on
Environment (optional)
Current TypeScript source, bearer-authenticated daemon, isolated temporary workspace and home directory. The real-daemon smoke installed the repository's context example from an absolute directory, reached a succeeded operation, and confirmed a managed copy. Full build, typecheck, lint, focused CLI tests, and SDK tests passed locally.
Risk & Scope
extension_local_path_installbefore sending a local path to an older daemon.Linked Issues
N/A
中文说明
本 PR 做了什么
本 PR 允许两个 daemon Extension 安装契约通过现有
source字段接收 daemon 宿主机上已存在的绝对路径。它保留当前异步操作和激活模型,通过extension_local_path_install声明该能力,并补充共享 TypeScript SDK 请求契约的文档。本地目录和受支持的本地压缩包复用现有 Extension 安装流水线,并复制到托管存储。相对路径会被拒绝,避免 daemon 进程工作目录改变来源含义,或本地
owner/repo路径遮蔽 GitHub 简写。本地来源也会拒绝ref和autoUpdate,与 CLI 契约保持一致。为什么需要
CLI 已经支持从 daemon 本地路径安装 Extension,但 REST 客户端只能安装远程 GitHub、Git、npm 来源,或通过独立二进制接口上传压缩包。调用方已经把 Extension 放到 daemon 文件系统后,目前仍需打开终端调用 CLI,无法直接使用带鉴权的操作接口。
Reviewer 测试计划
如何验证
/capabilities包含extension_local_path_install。202,操作最终达到succeeded,目录条目显示installType: "local"。.或一个已存在的相对owner/repo路径。预期在安装准备前被拒绝,且不会提交 Extension。ref或autoUpdate: true的绝对本地路径。预期因参数不适用而被拒绝。证据(Before & After)
N/A —— 这是 REST、SDK 契约和文档变更,不涉及 UI。
测试平台
环境(可选)
当前 TypeScript 源码、Bearer 鉴权 daemon、隔离的临时工作区和 home 目录。真实 daemon 冒烟测试从绝对目录安装了仓库内的 context 示例,操作成功,并确认生成的是托管副本。本地完整 build、typecheck、lint、聚焦 CLI 测试和 SDK 测试均已通过。
风险与范围
extension_local_path_install。关联 Issue
N/A