feat(serve): add extensions diagnostic HTTP/ACP surface (issue #4514 T3.9)#4832
Conversation
…T3.9) Add read-only `GET /workspace/extensions` endpoint exposing installed extension status with capability summaries. Follows the hooks pattern: status types + idle factory in acp-bridge, builder in acpAgent, workspace- service facade, REST route, SDK client method, and capability tag. - ServeExtensionEntry with id, name, version, isActive, capabilities (mcpServerCount, skillCount, etc.), redacted source URL - /extensions slash command enabled in ACP/non_interactive mode with text-based list subcommand - DaemonClient.workspaceExtensions() SDK helper - workspace_extensions capability tag (always-on)
|
Thanks for the PR! Template: the PR body doesn't follow the required template. Missing sections: "What this PR does", "Why it's needed", "Reviewer Test Plan" (How to verify, Evidence Before/After, Tested on table), "Risk & Scope", "Linked Issues", and the Chinese translation On direction: clearly aligned — this is issue #4514 T3.9, explicitly tracked as a Tier 3 gap. The hooks PR (#4822) set the exact same precedent and shipped cleanly. Extending the diagnostic surface to extensions is a natural next step. On approach: the scope feels right — follows the same layered pattern as the hooks PR (status types → HTTP route → workspace service → bridge → SDK → command). The Once the template is filled in, happy to proceed to code review. 🔍 中文说明感谢贡献! 模板:PR 描述没有遵循要求的模板。缺少的章节包括:"What this PR does"、"Why it's needed"、"Reviewer Test Plan"(含 How to verify、Evidence Before/After、Tested on 表格)、"Risk & Scope"、"Linked Issues" 以及中文翻译 方向:明确对齐——这是 issue #4514 T3.9,明确列为 Tier 3 缺口。Hooks PR (#4822) 是完全相同的先例,已顺利合入。将诊断接口扩展到 extensions 是自然的延续。 方案:范围合理——遵循与 hooks PR 相同的分层模式(status types → HTTP route → workspace service → bridge → SDK → command)。 模板补全后,继续进入代码审查 🔍 — Qwen Code · qwen3.7-max |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Thanks for the PR!
Template: the PR body doesn't follow the required template. Missing sections: "What this PR does", "Why it's needed", "Reviewer Test Plan" (How to verify, Evidence Before/After, Tested on table), "Risk & Scope", "Linked Issues", and the Chinese translation <details>. The current "Summary" + checkbox "Test plan" format doesn't give reviewers enough to verify the change. Please reformat.
On direction: clearly aligned — this is issue #4514 T3.9, explicitly tracked as a Tier 3 gap. The hooks PR (#4822) set the exact same precedent and shipped cleanly. Extending the diagnostic surface to extensions is a natural next step.
On approach: the scope feels right — follows the same layered pattern as the hooks PR (status types → HTTP route → workspace service → bridge → SDK → command). The /extensions command gaining non_interactive/acp modes with a list subcommand is a sensible addition. One observation: roughly 40% of the diff is prettier reformatting existing code (spreading ternaries in serializeHookConfig, IDLE_HOOK_EVENTS, etc.) that's unrelated to the feature. Not blocking, but splitting those into a separate commit would make the actual feature changes easier to review.
Once the template is filled in, happy to proceed to code review. 🔍
中文说明
感谢贡献!
模板:PR 描述没有遵循要求的模板。缺少的章节包括:"What this PR does"、"Why it's needed"、"Reviewer Test Plan"(含 How to verify、Evidence Before/After、Tested on 表格)、"Risk & Scope"、"Linked Issues" 以及中文翻译 <details>。当前的 "Summary" + 勾选框 "Test plan" 格式无法给审查者提供足够的验证信息,请重新填写。
方向:明确对齐——这是 issue #4514 T3.9,明确列为 Tier 3 缺口。Hooks PR (#4822) 是完全相同的先例,已顺利合入。将诊断接口扩展到 extensions 是自然的延续。
方案:范围合理——遵循与 hooks PR 相同的分层模式(status types → HTTP route → workspace service → bridge → SDK → command)。/extensions 命令增加 non_interactive/acp 模式和 list 子命令是合理的补充。一个观察:大约 40% 的 diff 是 prettier 对现有代码的格式化(serializeHookConfig 中的展开三元、IDLE_HOOK_EVENTS 等),与功能无关。不阻塞,但如果能拆成单独的 commit 会让功能变更更容易审查。
模板补全后,继续进入代码审查 🔍
— Qwen Code · qwen3.7-max
📋 Review SummaryThis PR adds a read-only diagnostic surface for installed extensions via a new HTTP endpoint ( 🔍 General Feedback
🎯 Specific Feedback🟡 High
🟢 Medium
🔵 Low
✅ Highlights
|
There was a problem hiding this comment.
Pull request overview
This PR adds a new read-only “workspace extensions” diagnostic surface across the serve HTTP API/ACP bridge and the TypeScript SDK, and exposes a non-interactive /extensions list text view so clients can inspect installed extensions and their capability summaries.
Changes:
- Add
GET /workspace/extensionsroute backed by a new ACP status method (qwen/status/workspace/extensions) and a newworkspace_extensionscapability tag. - Introduce new “workspace extensions status” types in
@qwen-code/acp-bridgeandpackages/sdk-typescript, plus an SDK helperDaemonClient.workspaceExtensions(). - Extend
/extensionsslash command to supportnon_interactive/acpmodes with a newlistsubcommand and non-interactive default behavior.
Reviewed changes
Copilot reviewed 14 out of 14 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/sdk-typescript/src/daemon/types.ts | Adds SDK-facing types for workspace extension status entries and capability counts. |
| packages/sdk-typescript/src/daemon/index.ts | Re-exports the new SDK types from the daemon module barrel. |
| packages/sdk-typescript/src/daemon/DaemonClient.ts | Adds workspaceExtensions() client helper for GET /workspace/extensions. |
| packages/cli/src/ui/commands/extensionsCommand.ts | Adds /extensions list and enables /extensions in non-interactive/acp with text output. |
| packages/cli/src/serve/workspace-service/types.ts | Extends the workspace service interface with getWorkspaceExtensionsStatus(). |
| packages/cli/src/serve/workspace-service/index.ts | Wires getWorkspaceExtensionsStatus() through queryWorkspaceStatus() with idle fallback. |
| packages/cli/src/serve/server.ts | Registers GET /workspace/extensions route and forwards to workspace service. |
| packages/cli/src/serve/server.test.ts | Adds feature expectations and a supertest asserting the new route bridges correctly. |
| packages/cli/src/serve/index.ts | Re-exports the new workspace extensions status types and idle factory for consumers. |
| packages/cli/src/serve/capabilities.ts | Registers workspace_extensions capability in the serve capability registry. |
| packages/cli/src/acp-integration/acpAgent.ts | Implements serialization/counting for workspace extension status and adds ext-method dispatch. |
| packages/acp-bridge/src/status.ts | Adds ACP method constant, status types, and createIdleWorkspaceExtensionsStatus(). |
| packages/acp-bridge/src/bridgeTypes.ts | Adds getWorkspaceExtensionsStatus() to the AcpSessionBridge interface. |
| packages/acp-bridge/src/bridge.ts | Implements bridge wiring for the new workspace extensions status request. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Remove install hint from empty-state message (install is interactive-only) - Cache Object.keys(ext.mcpServers) count to avoid duplicate computation
parseSlashCommand descends into subCommands without checking supportedModes, so /extensions install and /extensions explore could execute in ACP mode despite declaring interactive-only. Add runtime mode guards to installAction, exploreAction, and listAction (manage dialog) to prevent side effects in non-interactive modes.
- Fix TS2322: use string literal 'info'/'error' instead of MessageType enum for SlashCommandActionReturn messageType field - Wrap user-facing strings in t() for i18n consistency
Review round — wenshao CHANGES_REQUESTED
|
wenshao
left a comment
There was a problem hiding this comment.
[Suggestion] getCommandSubcommandNames in commandMetadata.ts does not filter subcommands by execution mode. Since this PR widens extensionsCommand.supportedModes to ['interactive', 'non_interactive', 'acp'], the ACP available_commands_update now advertises manage, install, and explore to the model — but these subcommands are interactive-only. When the model invokes them, it gets an error response, wasting tokens. Consider filtering subcommands by mode, or documenting that supportedModes on subcommands is advisory only.
— qwen3.7-max via Qwen Code /review
Parameter is used — passed to listTextAction. Remove misleading underscore-prefix convention.
Addressed wenshao's latest review (2026-06-07)Fixed:
Deferred (framework-level):
|
Local Verification ReportPR: #4832 Test Results
New Typecheck Errors (2)Both in
CLI Test Failure Analysis (all pre-existing)All 12 CLI failures are pre-existing on
Build Notes
Verdict✅ PASS with nit — No new test failures. 2 new TS7030 typecheck warnings in Verified locally by wenshao |
exploreAction and installAction return a message object on the non-interactive guard but void on other paths. Add explicit return undefined at function end to satisfy noImplicitReturns.
Addressed wenshao's local verification (2026-06-07)Fixed:
Thanks for the thorough local verification! |
Defensive error handling consistent with the ACP builder pattern.
Addressed wenshao's round 3 review (2026-06-07)
|
Local Verification Report (Re-run after 2 new commits)PR: #4832 Test Results
Previous Issue ResolvedThe 2 TS7030 errors in CLI Test Failure Analysis (all pre-existing)All 12 CLI failures are pre-existing on
Verdict✅ PASS — No new test failures, no new typecheck errors, no lint issues. Previous TS7030 nits resolved. Verified locally by wenshao |
wenshao
left a comment
There was a problem hiding this comment.
No issues found. LGTM! ✅ — qwen3.7-max via Qwen Code /review
chiga0
left a comment
There was a problem hiding this comment.
Review Summary — PR #4832
PR: feat(serve): add extensions diagnostic HTTP/ACP surface (issue #4514 T3.9)
Author: @doudouOUC | +538/-51 | 14 files | 7 commits
HEAD: 724ff59b | Base: daemon_mode_b_main
Independent Review
Follows the hooks/workspace diagnostic pattern from #4822 end-to-end:
| Layer | Verification |
|---|---|
| Types (status.ts) | ServeExtensionEntry, ServeExtensionCapabilities, idle factory — clean |
| Bridge (bridge.ts) | getWorkspaceExtensionsStatus() via requestWorkspaceStatus — correct pattern |
| ACP agent (acpAgent.ts) | buildWorkspaceExtensionsStatus() with try/catch + redactUrlCredentials — solid |
| HTTP route (server.ts) | GET /workspace/extensions with buildWorkspaceCtx + sendBridgeError — standard |
| Workspace service | Wired through DaemonWorkspaceService interface + impl |
| SDK (DaemonClient.ts) | workspaceExtensions() + mirror types — correct |
| CLI command | Mode guards on all 3 interactive-only subcommands + listTextAction with try/catch |
| Tests (server.test.ts) | Full endpoint test with capability array update |
wenshao Finding Resolution (7 commits)
All Critical findings addressed: TS2322 enum (commit 5), mode enforcement gap (commit 4), i18n strings (commit 5), _args rename (commit 6), try/catch (commit 7). wenshao: APPROVED at HEAD.
Verdict: APPROVED — 0 findings.
Reviewed at HEAD 724ff59b.
Summary
GET /workspace/extensionsendpoint exposing installed extension status with capability summariesServeExtensionEntryincludes id, name, version, isActive, redacted source URL, install type, and per-extension capability counts (MCP servers, skills, agents, hooks, commands, context files, channels, settings)/extensionsslash command enabled innon_interactiveandacpmodes with newlistsubcommand (text output);manage/install/exploreremain interactive-onlyDaemonClient.workspaceExtensions()SDK helper +workspace_extensionscapability tagresolvedSettingsnever serialized,installMetadata.sourceredacted viaredactUrlCredentials(), MCP/hook configs only counted (not embedded)Test plan
GET /workspace/extensionsreturns 200 with correct shape and bridge call count (supertest)workspace_extensionsappears ingetRegisteredServeFeatures()andEXPECTED_STAGE1_FEATURESfakeBridgestubs +queryWorkspaceStatusdispatch wired for extensions/extensions listreturns text listing in non-interactive mode/extensionsdefaults to manage dialog in interactive modeinstallMetadatahandled gracefully (optional chaining)🤖 Generated with Qwen Code