## 大白话 宿主端真正把一个 managed plugin 装进去、记上账、卸得掉。三件事: 1. **kind 分流收口** —— 今天 admission 有两处**兜底式 ternary**(`else → 'mcp'`), 一个新 profile 若只在合同侧登记,会被**静默当成 MCP 装进去**,而且 TypeScript 不会红(两处 `as` 断言)。 2. **wrapper 模板** —— **顶层不 import 上游**,`import("./upstream.js")` 放进 `server()` 内。 这样引擎里那个**第二个加载器**(`ConfigExternalPlugin`,ABI 不同、会自己调 npm.add、失败静默吞) 只求值到一个**无副作用空壳**后解码拒绝,V1 调 `server()` 时才载入第三方。 **这替掉了原方案里「全局剥 `plugin` 键」整张票** —— 全局剥会关掉用户**所有**合法 V2 插件。 3. **卸载臂** —— 今天未知 kind 是 fail-closed 拒绝,即「装得上、卸不掉」。 ## 方案基线 [Phase 4 基线 §4 D1/D3/D4 · §5 第 3/6/7/8 类 · §6 T2b](https://github.com/jinjunnn/alpha-code/blob/a828ec81ff04b2a2126fa3704cbf55c0b9e21866/docs/design/2026-08-03-req128-phase4-managed-npm-plugin.md) ## 四条最容易做错的(基线里已写死判据) - **第 7 类要 A+B 两条都测**:五个 profile 的 exact mapping(**期望键集从 `PROFILE_REGISTRY_V1` 派生**) **加上**未登记第六 profile 的具名拒绝。只测后者的话,一个把 `opencode-plugin` 错映成 `skill` 的表**完全满足断言**。 - **第 8 类四条一起断**(目录 / `plugin[]` / grants / **账本记录消失**)。第四条走**生产卸载后重读账本**, **禁止**断言中间值 `graphAfter === null`(那是自己拼等价链,假闸形态⑧)。 - **file item key 必须是 `plugin--<name>--f<i>`** —— 否则 `ext-health-probe-router.ts:40-41` 会 fail-closed 拒掉整次安装。 - **`server()` 返回值验证归本票**:对固定 canary 断言返回键**恰为两项**且**两个值都是 `function`**。 只断「键存在」的话 `{event:1,"permission.ask":1}` 就能过,而真实引擎在 `plugin/index.ts:255`/`:288-290` **直接调用这两个值**。 ## 依赖:T1。out of scope(含「不复用不改 `installPluginFromCas`」)与完整退出条件见基线 §6 T2b 行。 Refs #699
Activity
[#809][CODE] plugin 事务与生命周期:kind 分流收口 + wrapper 模板 + buildPluginTxIte…
[#809][FIX] R1 三条 MAJOR:目录删不掉不许谎报成功、server() 透传改判 identity、四清零观察器去盲区
[#809][CODE] plugin 事务与生命周期:kind 分流收口 + wrapper 模板 + buildPluginTxIte…