fix(plugin): 拒收 env/args 的非字符串值 + 保留键收成内置 id 集合 + 启用落盘失败文案
r1 复审 P2-1 + 两条顺手件。
P2-1(必修):`actionStringMap` / `actionStringList` 之前对非字符串值 `continue`,于是
前端 kv 控件里最自然的写法 `{"PORT":8080}` 会被**静默丢掉**、安装仍报 `installed:true`。
现在非字符串值、空键、非数组一律 400 invalid_config,文案只点名**键与类型**(不回显值);
盘上零变更、注册表零工具、快照零行(测试同时断言)。
顺手件 1:`isReservedPanelKey` 从「只挡 mcp」改成内置提供者闭集(mcp / web-search /
browser,写成 switch,新增内置页时漏补一眼可见)。之前一台名为 web-search 的 server 被
卸载时,`forgetPanels → MarkUninstalled` 会把内置「搜索提供商」页在重启前整页摘掉。
顺手件 2:启用「已连上但启用态未落盘」的文案改成事实(原来那句「它仍处于停用状态」与
事实相反)。为此新增 `ErrPluginStatePersist` 哨兵,把「磁盘没记住」与「连不上」分开;
`state=connected` 的派生口径不动。停用失败文案同时补上「server 仍在运行」。
测试:三条新用例,均已验「修前红 → 修后绿」(见 review-request 的取证)。
This commit is contained in:
1 parent
2421a8dac9
commit
2142de92f2
4 files changed
+297
-46
No files matched your search
@@ -186,6 +186,18 @@ func (m *Manager) AttachMCPPanel() error {
|
||||
// isReservedPanelKey 报告该目录键属于**宿主内置面板提供者**(不是热装插件的命名空间)。
|
||||
//
|
||||
// 护栏的方向是单向的:热装插件的安装/停用/卸载绝不许改动内置提供者的目录条目。理由很
|
||||
// 实在 —— 内置提供者的 id 是给人看的短名字(mcp),而 server 的名字由主人随手起;一台
|
||||
// 恰好叫 mcp 的 server 在卸载时若照常 MarkUninstalled("mcp"),整页「MCP 服务器」就消失了。
|
||||
func isReservedPanelKey(key string) bool { return key == MCPPanelPluginID }
|
||||
// 实在 —— 内置提供者的 id 是给人看的短名字(mcp / web-search / browser),而 server 的
|
||||
// 名字由主人随手起;一台恰好同名的 server 在卸载时若照常 MarkUninstalled,那整页内置页
|
||||
// 就在**重启前**消失了(`forgetPanels → MarkUninstalled` 连声明与动作索引一起清)。
|
||||
//
|
||||
// 名单写死成 switch 而不是包级 map:新增内置页时没补这一行,review 时一眼可见(与
|
||||
// paneldecl.shapeOf 同一取舍)。当前三个内置提供者:本包的 mcp 页(MCP 服务器)、
|
||||
// `plugins/tools/io/search` 的 web-search 页、`plugins/tools/browser` 的 browser 页。
|
||||
func isReservedPanelKey(key string) bool {
|
||||
switch key {
|
||||
case MCPPanelPluginID, "web-search", "browser":
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user