Files
ycode/docs/expert-package-evidence-20261016.md

121 lines
16 KiB
Markdown
Raw Permalink 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.
# 专家本地包契约与 REA 原文恢复(2026-10-16)
本轮已取得 WorkBuddy 5.8.2 本地专家扫描、激活、依赖、安装/导出实现,以及完整 expert-manager 技能、4 份规范和 5 个 Python 脚本。11 份技能资源已逐字恢复,另提供可静态 import 的 JSON;未运行原版技能/Python、未安装或启用原版专家。YCode host/环境适配与实际 backend 验收是后续独立工作,不能算本次原文导出已验证。
## 身份、范围与文件
固定根 ASAR SHA `035254bc76310ea46317433e4840602094543ef323d2d5c5aff7c131729de918`。版本依旧以已存 REA package.json(`ev_2caae424199a38371af743ef9111db835504c2dae54c1f02e1f9e5511032cc6b`)的 5.8.2 为准。起点为 `.tmp/rea-workbuddy-takeover-2026-10-15.json` 的 relevant-file inventory,Evidence `ev_df8468f8f31100525395ec493367a16770371db119cce47ca3ce19aacfd89eb7`。未重新全量分析;路径定位、原包读取均经 public REA CLI,未直接读取安装目录/用户目录、手写 ASAR extractor 或 CDP/evaluate。
| REA Evidence | 定向成员 | SHA-256 |
|---|---|---|
| `ev_81de6f628a156599f26ca795f6747ad3f8ec108de66fdba6e3723705905716f3` | `main/module.app-server.js` | `281666dbf81b76d64f95162a19dd2d02a41b35ec54239e0efc4e8e52419eb125` |
| 同上 | `main/runtime-handlers.js` | `6567dd0f9ffdc78fd22a540e993590aa47190be6b6a9501a5fd0115392b0f5cf` |
| `ev_75c9f1cb7975a8d61135abe7d4348024f305be540b10ba789094b0729a20358f` | `main/server.js` | `7e2a95d0615cce057e3076c57730f713bd42b63b146702f14cbf04d8671b7bef` |
| `ev_1b2c1146db5458f4e7e163150512ece87e656c09dba5cffaa5d4cee367525ccc` | `main/tar.js` | `e252bf614cb59ffa96e16ad0ab8cfd8796f5ab920289ca9bd67376e1d9836cf3` |
| `ev_c3df29dcb19c5fcaa9e458b1b9acff92e8c75ac935791e0c81900733e61b6282` | daemon bootstrap/main/entry、expert-manager metadata、builtin marketplace | 每项 SHA/bytes 在同名 `.tmp/rea-expert-package-ev_*.json`;daemon-main SHA `a3b9d6f3ca17954a89d4e442137348b230c8ea9c74181625556bfae2ffe98154` |
| `ev_3cba49fcb15fefc59f54c7691500ad1121a937edb55e606addae17e4186ebfef` | `resources/plugins/workbuddy-builtin/skills/expert-manager/SKILL.md` | `18b0655c3e7573fe9402fd00a605d2dc94918c9eecd028f9f3923e74da17bc45` |
| `ev_a4b0f399496f62f4dc41998e8327fb219ab84f3dca536ec6554553605b106735` | `references/plugin-json-spec.md` | `14e1a6b99c74815c22772a54725ba6d34750a6c9db4c75746c1188e31d2504f3` |
| 同上 | `references/agent-md-spec.md` | `ec7373578a5f84d73ba16dcc71e73755e57aa4170cb07cd9bf379627c0f9c007` |
| 同上 | `references/team-spec.md` | `1400af007c6b1179429c6d8c856dc1d45ae25dae63645097ddbc801d25d324f9` |
| 同上 | `references/avatar-spec.md` | `0b42762e05e311632b2f89af35f34458f851a03cce3fcc0300ca0a75e9f8890e` |
| `ev_25ded03a70790361a3f4fef21a3bd2466d5f7d3d118b7b7aada33b07efcf5cf8` | `scripts/register_expert.py` | `b2dd1a0141c2dc88ed7203246335fd261eca97a17f91f4e280d3ce8b10a65b1e` |
| 同上 | `scripts/init_expert.py` | `742fe9b70085a31850caf327d83f416ff19e9ee7482053e7aa99bd9b780206e4` |
| 同上 | `scripts/validate_expert.py` | `6e85c716af94d6ee2ffc86a24a7230d15cd675a0fbaaf45a8980fd51d9c1c6fd` |
| 同上 | `scripts/package_expert.py` | `e3d82044fd5fc7b749d65c178af0bed18bbc0375a952b878cfa019b09e04d8fb` |
| 同上 | `scripts/batch_create.py` | `c926d7b8721c4ec4179a3d481271bdb01d41764c3301e01cdafd9e96c37e154c` |
恢复目录 `src/main/capabilities/assets/expert-manager/` 含上述 SKILL、refs、scripts、`.codebuddy-plugin/plugin.json`。metadata 的 SHA 为 `6908b9cd71687525e342c2500fa9d32a847f72e3e263190655ca9347402cb389`,声明 `name:skill-expert-manager`、category skill、workbuddy.kind builtin-skill、legacyResourceName expert-manager 与 bundleSegments。该 metadata 是技能资源包装,不是用户创建专家的 plugin schema。
`rea-source-manifest.json` 逐文件记录原 member/Evidence/SHA/bytes/export;目录外 `src/main/capabilities/assets/expert-manager-source.json` 为 `{files:Record<relativePath,string>}`,11 份原文共 82,929 bytes,方便打包时静态导入。完整正文已读;原文没有替换路径、工具、ImageGen 或业务语义。Root 后续 adapter 会明确处理 YCode config/session/受控工具和不可用的头像生成。
## Handler、扫描与会话 marker
所有下列 JS offset 为 UTF-16 code units、end exclusive。`.tmp/rea-expert-package-contracts.json` 为 SHA-verified AST 定义索引,含有限函数正文与函数体 SHA,可直接 review。
`main/server.js` `createExpertServiceObject` `[226652,230495)` 绑定真实服务;`registerExpertServiceHandlers` `[231650,231794)` 与 registerExpertHandlers `[231794,232500)` 注册 expert 通道。它把 scan/get/delete/addUser/clearMarker 转给 ExpertDesktopService.custom,把 fromPath/fromUrl 转给 package manager,把 activate 交给 ExpertPluginService。不能只凭 renderer 的 API 名判断本地实现不存在。
`main/module.app-server.js`:
| 定义 | offset | 已观察行为 |
|---|---|---|
| ExpertCustomRuntime.doScanCustomExperts | 58588–60184 | 读取 `plugins/marketplaces/my-experts/.codebuddy-plugin/marketplace.json` 的 plugins;不任意扫描未注册目录。source 去 `./plugins/`,拒绝含分隔符/上级路径的 ID,忽略缺目录/manifest,修复 trailing comma 与陈旧索引。可按 user ID 清单过滤。 |
| readCustomExpertFromDir | 65233–66184 | plugin manifest 展开;tags/quickPrompts/triggerPrompts 兼容 locale-array,members/connectorIds/bin/references 归一;补 version=1.0.0、id/name/目录名、expertRootDir、isCustomExpert、marketplace。成员缺 id 可从 agent 字段补。 |
| addUserExperts / getUserExpertsJsonPath | 62525–62912 / 64072–64169 | 用户已收录 ID 数组存 `experts/custom/<userId>/experts.json`。不存在返回 null,扫描不强制过滤;现存空数组会过滤掉全部。 |
| archiveCustomExpertSessionMarker | 63187–63574 | `.created-by-session` rename 为 `.pending-preview-session`,清 DTO cache。 |
| clearCustomExpertSessionMarker | 63574–63996 | 删除这两种 marker,清 DTO cache。 |
| readPluginManifestAsync | 58204–58352 | 顺序尝试 `.codebuddy-plugin/plugin.json`、`.workbuddy-plugin/plugin.json`。 |
| deleteCustomExpert | 61604–62525 | 删除磁盘专家、用户索引/marketplace条目并 deactivate;原版行为需与 host 安全校验单独对照。 |
`createdBySession` 从 `.created-by-session` 优先,否则 `.pending-preview-session` 读取 trim 后纯文本。`main/server.js` createCustomExpertWatcher `[203613,205817)` 采用 marker 收录用户专家、archive marker 并广播变化;renderer 预览消费后再 clear。因此 marker 不只是短暂 Toast 标记。
## 激活与依赖
ExpertPluginService.activateExpert `[80288,81496)` 根据身份/缓存映射解析 bundle;my-experts 直接本地目录,官方包可能下载;要求可读 plugin manifest,expertType 缺省 skill。agentName 优先 manifest.agentName,team fallback teamInfo.leadAgent,否则从 agents 路径/Markdown frontmatter匹配。它增量注册 marketplace、移除旧自动 agent override、记录 active set、通知 runtime config 变化,并返回 `{success,expertType,agentName,localPath,pluginRegisteredName}`。这是本地准备/注册的契约,不等于 OMP 已有等价插件运行时。
ExpertBundleRuntime.updateMarketplaceManifest `[51566,52437)` 写 `{name,description,plugins:[{name,source:'./plugins/<bundle>',description}]}`,按 name/source 去重,保留其他项。resolveAgentMarkdownFiles `[88525,88876)` 支持声明数组的目录或 `.md`,无声明时列 agents/*.md。具体 session switch 在同文件 SessionPluginSwitcher,通过 session host 插件端点启停,不能从返回 localPath 推断指令已注入。
ExpertDependencyRuntime `[67977,70095)`:
- `dependencies.connectors` 是非空字符串 ID 数组,产生 `{type:'connector',id}`。
- MCP 声明优先 `dependencies.mcpServers`,再 `manifest.mcpServers`,无声明才用 `.mcp.json`。可为相对 JSON 文件、多个文件路径(后者覆盖同名)、或 object;JSON 同时接受 `{mcpServers:{...}}` 与直接服务器 map。
- 输出 `{type:'mcp',name,displayName,description,icon,config,workbuddy}`;`x-workbuddy` 本地化包括 auth.tokenSchema 标题/说明/字段 label/placeholder。
- `resolveExpertMcpLaunchConfig` `[67472,67614)` 仅处理 args:以 `./` 起始且 resolve 后仍在插件根内的参数转绝对路径,其他值保留。并非把任意 command/cwd 自动改写。
- 相对图标在插件根内解析,特殊 local-file 协议元数据被去除;http/data/file 分支分别处理。这里没有真实连接/授权执行。
## 本地导入、打包
`main/tar.js` installExpertZipFromPath `[42138,44806)`:在临时目录解 ZIP,接受根 manifest 或唯一顶层目录的 manifest;manifest.name 优先确定最终 ID,规范化旧展示数组。最终 ID regex `^[a-zA-Z0-9._-]+$` 且排除 `.`/`..`,目标必须在 my-experts/plugins 内。重复未 overwrite 时返回 duplicate_expert,同时补 marketplace 索引;overwrite 会先删除旧目录再移动新目录,不能将其称为已证实原子回滚。成功 touch manifest、写 marketplace,finally 清理临时目录及按 cleanupZip 选择清 ZIP。
`main/module.app-server.js` BundleRuntime 的下载路径是另一实现:downloadAndExtract `[53066,55378)` 有旧目录备份恢复;extractZipArchive `[56027,56753)` 校验 zip-slip;normalizeExtractedPluginRoot `[56753,57120)` 允许单层包装。应区分市场下载和本地 import 的覆盖语义。
源 Python package_expert.py 先完整 validate,再 ZIP;entry 含 `<expert-dir-name>/` 前缀。除 `.codebuddy-plugin` 外隐藏文件/目录、node_modules、__pycache__ 和常见垃圾文件排除,session marker 不分享。daemon exportExpertZip `[39906,40498)` 使用独立 collectExpertPackageEntries/export,不能假称两个 exporter 完全同一实现。
## expert-manager 创建、编辑与校验
SKILL v2.0 的真实流程:收集角色信息/资料转化 → init → 填 Agent/manifest/可选 skills → 头像生成 → validate → register → package。修改保持 name、agentName、目录名和 Agent 文件名身份,修改后仍 validate/register。Team prompt 要求真实 TeamCreate/Agent/SendMessage,不允许模拟多角色;本轮未实现或运行该调度。
init_expert.py 只允许固定 config/my-experts/plugins 路径、kebab-case 名、agent/team;同名目录拒绝。Agent 模板创建 `.codebuddy-plugin/plugin.json`、agents/<name>.md、avatars/.gitkeep、README;Team 增加主理人/成员占位与 settings.json。模板 TODO 必须后续生成填充。batch_create.py 是流程范例,**明确没有内容生成逻辑**,不是可以一键生成成品的实现。
plugin-json-spec 与 full validator 存在严格程度差异,应分别保留:
| validator 核心 | 实际 error / warning |
|---|---|
| name/version/description | 检查 key 存在;name 非空时 regex至少2字符。version 未真正校验 semver。 |
| expertType / agentName | 只 agent/team;agentName 必须对应 agents/<name>.md,禁止通用 team-lead。 |
| i18n 展示 | displayName/profession/displayDescription/defaultInitPrompt 必须 object、en/zh 非空。 |
| tags / quickPrompts | 若为数组要求各3个;原 validator 对错误的非数组类型并未全面报错,不应夸称完整 schema parser。 |
| 中文描述/首次提示/头像/README | 40–50字、defaultInitPrompt与首条一致、头像存在、README推荐均 warning,不能当原版已做硬拦截。 |
| team | teamInfo与members必需、memberAgents不含lead、members含role=lead;settings.json必需,存在agent时须匹配agentName。 |
| 结构 | fullvalidate只认.codebuddy-plugin/plugin.json;不许hooks/commands/.lsp.json;agents/skills/bin/avatars不能放metadata里。声明agents存在,skills含SKILL.md。 |
| Agent Markdown | 简单frontmatter regex/key:value抽取,源码承认不解析完整YAML;name若提供须同文件名,description缺失warning,tools字段error。 |
| 固定位置 | 专家目录须在WORKBUDDY_CONFIG_DIR(fallback ~/.workbuddy)my-experts/plugins下。 |
register_expert.py 另有 completeness 检查:两种 metadata 都可;name/description/expertType、displayName 不能留 TODO,agents 目录至少一份文件的 TODO 数≤2。它不是直接调用 full validator;所以 fullvalidate 与 register 必须分别验收。session ID 优先 `--session-id`,否则 CODEBUDDY_SESSION_ID,空值/未展开变量忽略。marketplace 可显式指定或从目录推断,按 source/name 更新,写 `.created-by-session`,无 session 时注册成功也提示未必自动进入当前用户列表。
Avatar 规范要求真实 ImageGen 及文件落盘,生成失败要说明需手补并提供 prompt。本轮没有头像生成服务,不能沿用原文收尾语伪称头像已生成。Root host adapter 将明确表达此限制。
## REA 扩展与验证
正式本地 `SelectedArtifactText` adapter 增加 `.md/.txt/.yaml/.yml/.py`,仍只接精确 canonical member、固定根 SHA、strict UTF-8、每文件8MiB/合计16MiB/最多16项、校验 declared size/SHA;Python仅作为文本,不执行。`prepare-css-runtime.mjs` 将正式 patch装入隔离 runtime;全局 REA/registration 不变,没有旁路 extractor。
验证命令:
- `node scripts/rea/expert-package-text-regression.mjs`:自有真实 ASAR public CLI **9/9 PASS**,`.tmp/rea-expert-package-fixture-SNFddk/report.json`,Evidence `ev_bd82287b057029647c8c15910ee079b59bd2616158a7deb2d2b97c3d92468275`;5种新后缀 bytes/SHA、根pin、路径、UTF8、预算、缺member/重复及未选缺unpacked。未执行Python。
- `node scripts/rea/selected-artifact-text-regression.mjs`:原有JS/CSS/JSON/binary、声明SHA tamper、预算、未选unpacked回归 PASS。
- `node scripts/rea/css-runtime-contract-regression.mjs`、`node scripts/rea/css-runtime-integrity.mjs`:PASS,19模块校验、对应global文件未变。
- expert-package-inventory/export/contracts/recover:所有选中正文 SHA、对应已存 inventory SHA 和恢复 bytes核验 PASS;原文bundle逐字等价,manifest提供完整复查链。
未知边界:原版实际创建/编辑/安装运行仍未执行;市场/安全扫描/付费/企业/cloud均有服务依赖;两种包导出器完整排除规则、第三方包兼容和原版所有异常未逐一执行;YCode的真实专家backend/会话模型指令/tool/team能力需另行测试。本轮不把“源码取到”称为功能1:1完成。
## 后续独立 YCode backend QA
Root 实施 `src/main/capabilities/experts.ts` 后,本 worker 新增 `scripts/test-experts-backend.mjs`,没有编辑该生产 service。该测试使用真实 Electron app.getPath(userData) 与真实磁盘包/草稿/marketplace,数据目录、sessionData、OMP home 都在新建 `.tmp/experts-backend-*` 下;不读写真实用户注册表、不调用模型或原版。
`node scripts/test-experts-backend.mjs` 最终 **73/73 PASS**:exercise **59/59**、全新 Electron reload-remove **14/14**,`.tmp/experts-backend-XllrUB/report.json`。被测 service SHA `6ba3fe0b9d489635b2f7c9846aabbe1f3f43206a9beaf150e8d497ca452a0dd3`,独立 esbuild module SHA `10ddff6ea9ef70f5a51c5928d8acc2eb9b4765b623fe170648a9f6f8e2a22806`。
真实链路覆盖 write→validate→register→source-shaped marketplace→list→read Agent prompt→activate identity→编辑/声明 skill preload→重启→remove。另验证二进制资源在文本编辑中保留、null 删除文档、marker、TODO 拦截、Windows/上级路径/会话ID越界、伪造 marker、单文件限额、YAML/tools拒绝、描述长度 warning、可校验 Team 包但明确拒绝激活、目录 junction/包内junction拒绝且外部目标未改,以及完整11份 manager源资源 SHA。
QA 曾捕获真实 stale edit bug:初次 read 不保存 baseHash,两个会话先 read 后编辑时旧用户视图可覆盖新包;`.tmp/experts-backend-QMunm2` 记录 FAIL,不能算通过。Root 修复 read 持久草稿与显式 `refresh:true` 后,最终同一反例拒绝陈旧 register;refresh 丢弃旧草稿、取得最新包后成功编辑并保留先前 Agent 变更。首次修复版 `.tmp/experts-backend-1WVd0H` 为55+14 PASS,最终新增 refresh闭环与source/build SHA后以XllrUB为准。
这是 YCode 后端模块的独立验证。没有驱动完整生产 preload/IPC/UI→真实 OMP 创建专家、图片生成、第三方 ZIP 导入、所有资源执行或专家团调度;这些跨模块/产品验收仍归 Root。REA 源恢复与自有 backend PASS 分开记账。