Files
ycode/docs/skills-implementation-20261016.md
T

70 lines
9.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 本地技能实施与验收(2026-10-16)
本次实现可实际使用的本地技能库:导入目录/ZIP、读取说明、启停、覆盖、卸载、导出,以及当前空间的技能发现和手动/自动调用上下文。技能页接入真实 SkillsApi。在线市场、云端同步、付费权益和安全扫描服务尚未接入;没有伪造在线卡片、安装量、扫描通过或购买状态。本报告不宣称技能整体 1:1 已完成。
## 文件与边界
- `src/main/capabilities/skills.ts`:本地存储、包校验、发现、生命周期和模型上下文。
- `src/renderer/src/capabilities/SkillsPage.tsx`:默认导出技能页;Props 为 `{cwd?, onUseSkill?, onCreateSkill?, onFindSkill?}`。
- `skills-source.mjs` / `skills-source.d.mts` / `skills-source.css` / `skills-source-manifest.json`:固定 REA 源码恢复产物。
- `skills-host.css`:宿主容器、可访问交互、本地状态和原版没有对应服务的提示。
- `scripts/test-skills-reference.mjs`:固定 SHA 校验及恢复(`--write`);不读原版安装目录,不操作原窗口。
- `scripts/test-skills-files.mjs`、`scripts/test-skills-ui.mjs`:隔离真实文件系统与原生 Electron 控件验收。
共享契约、IPC、preload、App、ChatPane、CapabilityCenter、包依赖和生产 out 均由主上下文接线;本 worker 未修改这些文件。复用主上下文导出的 `CapabilityToolbar` / `CapabilitySubpageHeader`,右侧动作通过 portal 使用唯一共享顶栏。
## 主进程契约与语义
导出 `listSkills(cwd?)`、`importSkill(path, overwrite=false)`、`readSkill(id,cwd?)`、`setSkillEnabled(id,enabled,cwd?)`、`removeSkill(id)`、`exportSkill(id,destination)`。UI 的 `SkillsApi.importPath(undefined,overwrite,kind)` 委托根 IPC 展示文件夹或 ZIP picker,不新增手填系统路径流。
存储根为 `app.getPath('userData')/capabilities/skills`:`registry.json` 保存注册/禁用状态,`packages/<24hex>/` 保存导入副本。`user:<name-hash>` 保持同名覆盖身份稳定;空间 ID 基于实际包路径,不把两个空间同名技能混为一个。发现当前 cwd 下 `.agents/skills` 与 `.claude/skills`,不枚举其他空间。空间包可禁用但不能由卸载 API 删除;导入源始终保留。UI 共享 slash 菜单的 cwd 作用域 pin memory key,保留其他 memory 字段。
SKILL.md 必须为 UTF-8、含 YAML name/description;使用 YAML core schema,支持 folded 字段、版本数值和受限 alias,拒绝重复键及把字符串 `"false"` 误当布尔值。支持 `enabled`/`disable`、`user-invocable`/`userInvocable`、`disable-model-invocation`/`disableModelInvocation`。未知前置元数据保留于原文件,不重写包内容。
- `buildSkillContext(ids,cwd)`:显式手选,只允许 enabled + userInvocable;手动专用技能允许注入。
- `buildAvailableSkills(cwd)`:输出真实 `{id,name,description}` JSON 目录,只含 enabled 且未 disableModelInvocation 项。
- `loadSkillContext(id,cwd)`:模型自动加载遵守 enabled + !disableModelInvocation。
- `readSkillResource(id,relative,cwd)`:仅当前可用包的受限相对 UTF-8 文本,最大 1MB。根工具桥另行约束回合 allowedIds,不能仅凭 model 给出的任意 ID 放行。
单个上下文文档限制 65,536 字符,手选总计 131,072 字符。没有直接执行包内脚本;真实模型可以通过根已有工具执行任务,是否与原版内核同义还需独立验证。
损坏、缺失、被重定向或 YAML 无效的注册包按条目返回 `error`、`enabled:false`,保留 ID/name/path 以定位和卸载;不让无关损坏包阻断普通聊天的空选 context 或可用技能目录。空间坏包同样显示不可用。主索引自身损坏仍为明确错误,不静默覆写丢失注册状态。
## 路径与安装事务
导入目录、SKILL.md 和 ZIP 都先校验;包最多 2,000 文件、展开总量 50MB,ZIP 输入最多 20MB,SKILL.md 最大 1MB。不跟随技能存储祖先、源目录、包或资源中的 symlink/junction。拒绝绝对路径、盘符、反斜杠、dot traversal、Windows 设备名、控制字符及大小写/NFKC 重复 ZIP 路径。ZIP 中央目录预检拒绝多卷/ZIP64/加密/设备/链接;再每 4KB 输入分块解压,核对每项实际输出与声明大小,防止只信声明大小的膨胀包。
使用同级 stage/backup + rename 安装替换,索引原子写入,提交失败回滚。覆盖需要明确 overwrite;UI 勾选“替换已导入的同名技能”。导出以 `wx` 创建 ZIP,不覆盖已有文件或技能存储。卸载先重命名隔离再提交索引,缺失目录可清理注册,注册路径已被替换为 junction 时只移除链接本身,不触及指向目录。目录遍历防护不承诺抵御具有同等文件权限的进程在所有 lstat/read 间恶意竞态。
## 原版来源与恢复范围
WorkBuddy **5.8.2**,ASAR SHA-256 `035254bc76310ea46317433e4840602094543ef323d2d5c5aff7c131729de918`。所有原实现信息来自已经保存的 REA 导出;先验证 SHA 再解析。
| 来源 | REA Evidence | 固定 SHA / 范围 |
| --- | --- | --- |
| skills-market-Cwf-NvXV.js | `ev_e8faf60b3d22b99ede302f2d0efdfb3145f53f59789d4a345f5892dc13a589a4` | `f1434cadabf5ed3762f00fc2a356bc7418b0b4aab27db62dc9fbbe5add6f6dfb`,CardFrame UTF-16 `[10076,13702)` 原函数体 |
| standalone-skill-detail-modal-Bi5X8CZ4.js | `ev_717fa5e846e64d67ac19c8925d121bff632c0d3aefb3603b10858559cabb2dcb` | `ee7de2a7123f94110aa01258d3d6b3fcc3ce48f2ec5fd8f91cb3367c817a0f01`,8 个字面 SVG 函数,精确 offset/body SHA 见 manifest |
| skills-market-d_hn_qWB.css | selected Evidence 同上 | `935d55effde68d03b2fbc2529ec94b19a6cd7210d9bc79febd6d115b115f60b6` |
| standalone-skill-detail-modal-fe_BFVdd.css | `ev_377c8790468b3c67dad8577aabb327f98d3140659f0fffdbabfcff5a40cc9e94` | `7967df52bacb7594f934b32d8d5fb24854dbc8c47d0217d4677c7d7da0655f49` |
| src-Bh3YZ35H.css | CSS Evidence 同上 | `88dbdc1cd3f59d0e8b75824512a465a2be714bc7af481d790fe3a9484f85e01a`,button/input/switch/dropdown/popover |
| contexts-BkjwYSZT.css | CSS Evidence 同上 | `50cbd673f7f35fc7f966bdddc6c9f5677fdfe944cb904888d214619fca259380`,skill-upload + 对应 keyframes |
CSS 声明、顺序、media 和 keyframes 保留;选择器限制到 `.yc-capability-center`,原 skill-market 顶栏祖先适配到共享 portal。CardFrame 原体仅替换 JSX runtime 引用;React singleton、Tooltip/Avatar/批量 checkbox、原服务数据为显式宿主适配。详情的 header/view/scroll/intro/overview/file 结构由已导出源重新接本地数据,并非整个原详情组件原体复用。导入结构依据 `contexts-BMeWSUHk.js` 的 SkillUploadModal `[4365603,4372182)`;文件夹/ZIP native picker 取代原宿主 facades。没有拖拽和 web FileList fallback。
原 runtime 对照:市场 `ev_c827c8dc7dee0c67c7870f6bf8417b87ec7b4d90d507ecc5dc592b5878579f10`;稳定已安装 `ev_9d8628a28fed60291e628cebaec55537bfb8274d4b6c8f746bffadcbc277d3fb`;添加菜单 `ev_ddef9315aaf0ff534cf02573212e205ba70e5b69dfc1b3dcf555b430920faf22`。市场和菜单各自 cleanup cancelled,只有动作帧有效;不能宣称 probe 全通过。原已安装 5 个市场/套件数据与本机自定义技能不是同数据集,不作全画面像素相等断言。
## 验证
- `node scripts/test-skills-reference.mjs --write`:6 个固定源码/CSS SHA、9 个函数恢复、4 个输出生成;再不带参数可验证未漂移。
- `node scripts/test-skills-files.mjs`:**59/59 PASS**,`.tmp/skills-files-iAkonv/report.json`。实际临时 FS,唯一 Electron stub 是隔离 userData 路径。覆盖生命周期、持久化、空间隔离、metadata flags、ZIP roundtrip/traversal/碰撞/symlink/虚报解压大小、损坏/缺失/重定向注册包容错和卸载。
- `node scripts/test-skills-ui.mjs`:**37/37 PASS**,`.tmp/skills-ui-fR8rWr/report.json`。普通可见 Electron + SwiftShader,1052×901 内容区;真实 main 模块、preload/IPC 和隔离 FS,仅 OS picker 使用受控路径。以鼠标/键盘点击完成目录/ZIP导入、重复冲突、覆盖、搜索、开关、批量、pin、详情 markdown、使用回调、导出、卸载/取消、损坏包 UI、焦点循环/恢复及3秒提示消失;截图同目录。预期冲突/损坏 IPC reject 有日志,不计为 renderer 未处理异常。
- `npm run typecheck`:node + web 全通过。主上下文负责统一生产 build 与完整应用 OMP/MCP/重启集成验收,本 worker 没有重复写生产 out。
原生局部实测:受管卡片 padding `20px`、radius `16px`、shadow `rgba(0,0,0,.03) 0px 4px 12px`,medium switch `26px`。这些验证了恢复声明在宿主生效,不能替代同数据/同状态的原版像素比较。
## 遗留差异
未接在线推荐/SkillHub/套件目录、URL 导入、云端同步、更新下载与权益/购买流程;当前对应目录显示服务不可用,查找/创建由根真实草稿回调处理。没有安全扫描引擎或风险报告伪造。原版详情的搜索命中、翻译、远程示例/案例、动态价格和权益尚未接入;avatar 为本机名称字母 fallback,Tooltip 使用宿主原生 title,尚未恢复原 tooltip 延迟/浮层。包内图片未通过文字资源 API 越界读取,详情仅渲染可用 markdown 文本及文件清单。暗色及所有状态像素/动效还未完整验收。这些须继续按 REA 证据补齐,不能把本轮本地功能闭环称为技能 1:1 完成。
最终集成由主上下文报告:`.tmp/capability-flows-ZJYiyj/report.json`,完整应用 UI→真实 OMP 两轮 + MCP + 重启 PASS。该结果属于主上下文验收,不替代本报告的原版像素与未知项边界。成功 notice 是3秒自动消失、不占文档流的宿主 status;已存 REA CSS 未找到可直接恢复的 wb-toast primitive,未声称原版 toast 等价。