
Qwen-Code Web Shell Skill 管理页面Skill 安装、启停与删除的协议设计与源码实现【免费下载链接】qwen-codeAn open-source AI coding agent that lives in your terminal.项目地址: https://gitcode.com/GitHub_Trending/qw/qwen-code本篇围绕 Qwen-Code 的设计文档 web-shell-skill-manager-page.md 展开讲解 Web Shell 中新增的 Skill 管理页面它如何在不依赖活跃聊天会话的前提下完成 Skill 的搜索、启停、安装与删除以及底层 daemon 路由、包校验和文件系统防护的具体实现。读完后你将掌握workspace_skill_manage能力位的协议契约、三类安装源GitHub、本地文件夹、ZIP的请求格式与限制边界并能对照源码理解安装/删除操作的原子性保障机制。一、页面定位无需活跃会话的 Skill 管理入口设计文档的 Goal 一句话概括了本页面的价值新增一个原位in-place的 Skill 管理页面在保留既有调用行为的同时让受信任用户在没有活跃聊天会话的情况下安装、启用、禁用和删除 Skill。入口有两条路径均已在客户端源码中得到印证斜杠命令输入/skills、/skills detail或/skills details均可打开该页面。App.tsx 中对cmd skills的分支会调用openPanel(skills)而 App.test.tsx 用it.each([/skills, /skills detail, /skills details])逐一验证了三种写法的等价性侧边栏 Plugins 页面Skills 作为第三个标签页出现。PluginManagerPage.tsx 中PluginTab extensions | mcp | skills | agents的类型定义与该顺序一致菜单里还有/skills detail的快捷入口见 ChatEditor.tsx。页面组件是 SkillsManagerPage.tsx它通过embedded属性同时支持“独立页面”与“嵌入 Plugins 标签页”两种形态——这正是设计文档 Scope 一节所说“新增独立 Skill 页面并在 Plugins 中复用它”的落点。二、列表页与详情页的交互行为设计文档 Behavior 一节列出的交互细节全部可以在组件源码中逐条对上列表页第一层展示 Skill 列表支持搜索框 级别scope筛选 状态筛选。级别选项为all / user / project / extension / bundledSkillsManagerPage.tsx过滤逻辑集中在纯函数模块 skills-manager-logic.tsfilterSkills依次按级别、启用状态、名称子串小写化后匹配过滤便于单元测试卡片上刻意省略 scope 徽标卡片仅显示名称、描述、启用/禁用状态徽标以及当modelInvocable false时追加的“Manual reference”徽标SkillsManagerPage.tsx。级别信息仍可通过筛选器和详情页获取布局、响应式卡片网格最多 4 列、面包屑与空状态均与 MCP 管理页保持一致头部提供“刷新”按钮和“上传Upload/Install”按钮后者仅在 daemon 宣告了workspace_skill_manage能力时显示SkillsManagerPage.tsx 中canManageSkills的判断空状态区分“无 Skill”与“无匹配结果”两种提示文案SkillsManagerPage.tsx。详情页点击卡片在同页内打开详情展示调用形式/skill-name [argumentHint]、级别、模型可访问性、模型、所属 Extension 等字段返回列表时保留当前 scope 筛选与搜索词——实现上query/levelFilter/statusFilter是页面级 stateselectedName置空即可回到列表当列表数据刷新后preserveSkillSelectionskills-manager-logic.ts会在新列表中校验选中项是否仍有效失效则清空详情页的动作菜单暴露 daemon 的逐 Skill 设置操作启用/禁用该操作受workspace_skill_settings_toggle能力位控制文档特别强调运行期目录元数据如 user 可调用性、父 Extension 激活状态不阻塞workspace 声明写入即使写入成功权威可用性也可能保持不变——这与 UI 中“设置已更新但可用性未变化”的提示分支skills.settingUpdatedAvailabilityUnchanged一一对应SkillsManagerPage.tsx“Reference skill”Run行为返回聊天并把/skill-name填入输入框但不提交由onUseSkill(name)回调实现SkillsManagerPage.tsx。删除操作的安全约束动作菜单仅当canManageSkills且 Skill 级别为project或user对应 workspace/global 两个 scope时才出现 Delete 项SkillsManagerPage.tsxbundled 与 extension Skill 保持只读删除前弹出AlertDialog破坏性确认SkillsManagerPage.tsx前端 scope 映射写在deleteSkill中selectedSkill.level project ? workspace : globalSkillsManagerPage.tsx变更成功后自动刷新列表错误则以内联通知形式保留在当前上下文符合文档“Successful mutations refresh the list; errors remain visible in context”的要求。三、HTTP 协议安装与删除路由设计文档 Protocol 一节声明daemon 通过能力位workspace_skill_manage宣告该功能并暴露 workspace-bound 与 workspace-qualified 两套变体路由。能力位定义见 capabilities.ts路由注册实现集中在 workspace-skills.ts操作workspace-bound 路由workspace-qualified 路由安装POST /workspace/skills/installPOST /workspaces/:workspace/skills/install删除DELETE /workspace/skills/:name?scope...DELETE /workspaces/:workspace/skills/:name?scope...配置侧安装globalPOST /workspace/config/skills/installPOST /workspaces/:workspace/config/skills/install配置侧删除globalDELETE /workspace/config/skills/:nameDELETE /workspaces/:workspace/config/skills/:name单个启用/禁用POST /workspace/skills/:name/enablePOST /workspaces/:workspace/skills/:name/enable批量启用/禁用POST /workspace/skills/enable上限 100 个POST /workspaces/:workspace/skills/enable安装请求体由parseSkillInstallRequestworkspace-skills.ts严格解析要求name非空字符串、scope仅接受workspace或global错误码invalid_skill_scope以及三选一source{ name: my-skill, scope: workspace, source: { type: github, url: 指向 SKILL.md 的 HTTPS GitHub URL } }github{ type: github, url }HTTPS GitHub URL 指向SKILL.mdfolder{ type: folder, path }daemon 宿主上的绝对文件夹路径zip{ type: zip, contentBase64 }单个受尺寸上限约束的 base64 ZIP 归档。类型定义见 workspace-skill-management.ts。删除的 scope 一致性校验scope查询参数必须与发现到的 Skill 级别匹配。deleteConfiguredSkillworkspace-skills.ts先按名称不区分大小写在配置状态中定位 Skill再要求candidate.level等于scope workspace ? project : user若请求 scope 下的匹配项没有可用的installedPath返回409 skill_not_managed。路由所有权互斥为避免两套路由语义冲突workspace-skills.ts 设置了方向性拒绝——singleton 路由/workspace/config/skills/*拒绝scopeworkspace400 workspace_scope_requires_qualified_workspacequalified 路由/workspaces/:workspace/...拒绝scopeglobal400 global_scope_requires_singular_owner。所有写路由还要求 trusted workspacerequireTrustedWorkspaceRuntime/sendUntrustedWorkspaceResponse并经由PathMutexRegistryskillConfigMutationLocks按“scope workspaceCwd skillName”粒度加排他锁防止并发安装/删除互相踩踏。SDK 侧封装TypeScript SDK 的 DaemonClient.ts 提供了installWorkspaceSkill、deleteWorkspaceSkill、installWorkspaceConfigSkill、deleteWorkspaceConfigSkill以及受workspace_skill_settings_toggle/workspace_skill_settings_batch_toggle能力位保护的setWorkspaceSkillEnabled/setWorkspaceSkillsEnabled。协议细节如配置写入先提交持久状态、再排程运行期协调响应中activation取deferred/reconciling可进一步参阅 qwen-serve-protocol.md 中POST /workspace/skills/:name/enable与 config 路由的章节。四、文件系统约束与包校验设计文档 Filesystem 一节描述了“把 Skill 包限制在安全边界内”的完整策略。实现位于 workspace-skill-management.ts其中的限制常量L35-L40比文档更具体约束项上限错误码 / 语义文件数量MAX_FILES128 个invalid_skill_package单文件大小MAX_FILE_BYTES2 MiBskill_package_too_large413聚合大小MAX_TOTAL_BYTES6 MiBskill_package_too_large413路径长度MAX_PATH_LENGTH512 字符invalid_skill_package路径深度MAX_PATH_DEPTH16 层invalid_skill_packageSkill 名称长度MAX_WORKSPACE_SKILL_NAME_LENGTH256 字符invalid_skill_name这些上限刻意低于 daemon JSON 解析器的限制确保恶意大包在解码前就被拒。落盘位置workspace scope 固定写入workspace/.qwen/skills/slugglobal scope 写入QWEN_HOME/skills/slug。skillBaseDirworkspace-skill-management.ts通过Storage.getGlobalQwenDir()解析 QWEN_HOMEslug 仅允许字母、数字、.、_、-且排除.与..正则见validateWorkspaceSkillNameworkspace-skill-management.ts另外rejectInstallArtifactSkillName拒绝以安装暂存目录保留后缀.backup-/.installing-时间戳结尾的名称防止污染暂存命名空间删除路径还接受从兼容的.agents/skillsprovider 目录发现到的 project/user Skill——deleteWorkspaceSkillworkspace-skill-management.ts通过SkillManager.getSkillsBaseDirs()得到允许的基础目录集合逐一比对。各来源的解析与拒绝规则统一包校验normalizePackageFilesL123-L185先剔除平台元数据__MACOSX、.DS_Store、._*再要求包根必须存在SKILL.md若不存在但所有文件共享唯一顶层目录则剥离这一层包裹文件夹文档所说“a single enclosing folder is stripped from folder and ZIP uploads”最后检查归一化路径重复、单文件与聚合大小ZIP 来源filesFromZipL513-L590基于 external attributes 检测符号链接条目0xa000、拒绝加密条目general purpose bit 1、跳过目录条目并在声明大小与流式读取两个阶段双重执行尺寸检查防 ZIP bombbase64 内容先经decodeBase64做格式与总尺寸校验folder 来源filesFromFolderL621-L697路径必须是绝对路径且根目录本身不能是符号链接递归遍历中任意符号链接或特殊文件都会触发unsafe_skill_path根级.git目录被跳过读取前用lstat校验、读取后校验内容长度与 stat 一致防止读取过程中文件被替换GitHub 来源downloadGitHubSkillL387-L473强制 HTTPSraw.githubusercontent.comURL 必须以/SKILL.md结尾github.comURL 必须是/owner/repo/blob/ref/.../SKILL.md形态owner/repo/ref 均受字符集白名单约束ref 不允许以-开头下载默认走 GitHub Contents API 递归拉取404 时回退到git clone --depth 1 --filterblob:none --sparse的稀疏检出方案L338-L385。安装的原子性staging 备份 回滚installWorkspaceSkillworkspace-skill-management.ts的流程完整对应文档“stages into a sibling directory and safely replaces the destination with rollback only after validation succeeds”在skills的同级目录创建.baseName-skillName.installing-rand暂存目录mkdtemp并清理上一次遗留的安装/备份产物把包内文件全部写入暂存目录然后用 core 包的SkillManager.parseSkillContent解析SKILL.mdfrontmatter要求 frontmattername与请求 slug 严格一致否则抛skill_name_mismatch校验全部通过后把既有目录 rename 为.baseName-skillName.backup-ts再把暂存目录 rename 到最终位置任何一步失败若尚未提交则删暂存目录若已移开旧目录则 rename 回去——即文档所述“rollback only after validation succeeds”成功后异步清理备份目录。删除的双重验证deleteWorkspaceSkill在fs.rm之前做了四道检查installedPath必须是某个合法基础目录下的dir/SKILL.md且目录名等于 Skill 名目录与文件本身不能是符号链接目录的realpath父级必须等于基础目录的realpath防 symlink 逃逸最后重新解析该 SKILL.md 的 frontmatter 并确认name匹配才递归删除。这与文档“Deletion validates the discovered canonical SKILL.md and dedicated parent directory before recursively removing it”完全一致。五、变更后的缓存失效与会话刷新设计文档最后一段明确了变更的传播链“After a mutation, cached workspace Skill status is invalidated and active ACP sessions refresh their SkillManager and slash-command snapshots.” 在路由层这一行为由两个机制落实每次安装/删除/开关完成后含异常路径都会调用invalidateSkillsConfigStatus使 workspace Skill 状态缓存失效global scope 变更会遍历 registry 中所有 entry 逐一失效workspace-skills.ts、L609-L620配置侧写操作完成后调用reconcileSkillsworkspace-skills.ts先对各 runtime 调用invalidateWorkspaceSkillsStatus()再对 trusted runtime 尝试coordinator.reconcileSkillsConfiguration()响应体的activation字段返回deferred无运行期可更新或reconciling已排程刷新让客户端知道快照何时真正生效。六、测试布局与设计边界设计文档 Testing 一节列出的验证点在仓库中均有对应落点UI 过滤与选中保留skills-manager-logic.ts 是纯函数实现天然可单测/skills三种路由与面板打开行为的端到端断言在 App.test.tsx路由与服务workspace-skills.test.ts 覆盖两个 scope、各安装源、替换、traversal 与 ZIP-bomb 上限、来源不匹配、受保护来源与刷新服务实现workspace-skill-management.ts本身亦带测试文件协议契约qwen-serve-routes.test.ts 验证workspace_skill_manage能力宣告与路由行为SDK 的请求序列化在 DaemonClient.test.ts 与 DaemonClient.ts 中有对应验证命令文档要求运行 Web Shell 的 typecheck、build 与聚焦测试来验证管理 UI 集成可通过仓库根目录的 pnpm 工作区脚本执行如pnpm --filter qwen-code/web-shell系列命令具体脚本名以 packages/web-shell 下package.json的 scripts 为准。最后设计文档 Scope 一节划定了改动边界本次变更只新增独立 Skill 管理页并在 Plugins 中复用不迁移 Tools 与 Agents 管理页。从 SkillsManagerPage.tsx 的 Propsembedded、workspaceCwd、workspaceControl也能看出该组件被刻意设计为可在多个宿主页面复用的独立单元与 Plugins 页面的标签结构解耦。七、小结Web Shell 的 Skill 管理页面把“Skill 生命周期管理”从依赖聊天会话的斜杠命令升级为一条完整的产品化链路UI 层以能力位workspace_skill_manage、workspace_skill_settings_toggle做渐进增强协议层以 singleton / qualified 双路由 scope 互斥校验保证多 workspace 下的写归属清晰存储层以尺寸/深度/路径多重边界 staging 回滚 符号链接防护抵御恶意包变更层以缓存失效 runtime reconcile 保证目录快照收敛。对集成方而言只要 daemon 宣告了workspace_skill_manage无论是 Web Shell、TypeScript SDK 还是裸 HTTP 客户端都可以用同一套install / delete / enable契约管理 Skill 资产。【免费下载链接】qwen-codeAn open-source AI coding agent that lives in your terminal.项目地址: https://gitcode.com/GitHub_Trending/qw/qwen-code创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考