fix(extension-host): refuse a plugin providing the core subagents service (CW-7054)

A plugin could call `ctx.provide('subagents', ...)` or
`ctx.root.provide('subagents', ...)` and activate successfully, putting a
plugin-owned object under the name of a service the Engine owns. Add
`subagents` to REFUSED_SERVICES in crates/tui/extension-host/src/root.ts,
next to `agents`, and rebuild the committed dist bundle (one added line).

Scope: REFUSED_SERVICES is read only by the patched `reflect.provide` guard
in root.ts. Adding the name changes what an extension may provide and
nothing else. The Engine's own sub-agents run in Rust
(crates/tui/src/tools/subagent); their MCP pool fork, tool access and
extension host attachment do not go through Cordis `provide`. No host shim,
built-in module, DSH upstream code or in-repo plugin provides or injects
`subagents` (git grep). Built-in module digests (builtin-modules.json,
tier.rs pins) are unchanged, and no file pins the main bundle digest.

Verification run:
- extension host, Node 22.20.0: `npm ci --ignore-scripts`, `npm run build`,
  `npm test` 420 tests: 413 pass, 0 fail, 7 skipped; `npm run typecheck`
  exit 0; `git diff -- dist` shows only the one added line.
- Before/after probe (scratch plugins, not committed) through the test
  harness: with the HEAD bundle, `ctx.provide('subagents')` and
  `ctx.root.provide('subagents')` activated `ok`; with the rebuilt bundle
  both fail with "extension may not provide core service `subagents`".
  A non-core name still activates `ok`; `agents` stays refused.
- `scripts/dev-test.sh tui extension_host::` (nextest, build lock): 179
  tests run, 179 passed, 15172 skipped.
- Repo gate `npm test`: root 101/101, runtime-sdk 19/19,
  extension host 413 pass / 0 fail / 7 skipped of 420, web node 7/7,
  web vitest 772/772 in 74 files; `npm run check:web` exit 0.
- ./scripts/sync-changelog.sh; ./scripts/release/check-versions.sh
  --require-dated-release exit 0.

Not verified: Bun host runtime suites, hosted CI, and a real plugin in a
running Codewhale session. CW-7054's other items remain open.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01NBKbhx19BRbZtvWK8rVKjz
This commit is contained in:
CodeWhale BotandClaude Opus 5.5 committed 2026-10-16 03:14:30 -07:00
1 parent a38062bd07
commit 32fbcddc17
4 files changed
+12

No files matched your search

+5
View File
@@ -25,6 +25,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
without `success: true` still fails. Thanks @luestr for the response headers
and sanitized body in #6981; the `/new` refusal reported there is not
changed by this fix.
- Experimental extension host: a plugin can no longer provide the core
`subagents` service. Its activation fails with "extension may not provide
core service `subagents`", as it already did for `agents`, `approval` and
the other core names. Codewhale's own sub-agents and the tools they can use
are unchanged (CW-7054).
## [0.10.2] - 2026-10-13
+5
View File
@@ -25,6 +25,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
without `success: true` still fails. Thanks @luestr for the response headers
and sanitized body in #6981; the `/new` refusal reported there is not
changed by this fix.
- Experimental extension host: a plugin can no longer provide the core
`subagents` service. Its activation fails with "extension may not provide
core service `subagents`", as it already did for `agents`, `approval` and
the other core names. Codewhale's own sub-agents and the tools they can use
are unchanged (CW-7054).
## [0.10.2] - 2026-10-13
@@ -14277,6 +14277,7 @@ var init_root = __esm({
// one host-owned composition loader; plugins may not replace it
"approval",
"agents",
"subagents",
"sessions",
"llm",
"sandboxPolicy",
+1
View File
@@ -65,6 +65,7 @@ export const REFUSED_SERVICES = new Set(['shellHooks',
'loader', // one host-owned composition loader; plugins may not replace it
'approval',
'agents',
'subagents',
'sessions',
'llm',
'sandboxPolicy',