Files
workbuddy_skills/dsh-workflow/references/dsh-change-workflow/05-插件与数据源口径.md
T

54 lines
6.8 KiB
Markdown
Raw Normal View History

# 插件与数据源口径 · 缓存版本守卫 / 白名单来源 / 技能 vs 插件 / 术语与环境约定
> **归属**:技能 `dsh-change-workflow` 的详情档(**按需读**,不是每次都要读)。
> **本档覆盖**:外部数据源缓存必须带结构版本守卫 · 官方白名单插件来源 · 技能 vs 插件:怎么区分 · 术语与环境约定(原行 L539–L554 + L907–L934)。
> **主文件 / 判据与流程主干** = `../SKILL.md`(§1 六阶段流程 · §2 红线 R1–R8 原文速查 · §3 本机 Git Bash 环境坑 · §4 并行调度结论)。
> **来源**:2026-09-22「技能重组线」把 `../SKILL.md` 的 L539–L554 + L907–L934 段**逐行原样**下沉到本文件,未改一字。
> **跨档引用**:正文里的「§N / 见 §8 坑 N / 见下表」等编号,用 `../SKILL.md` 末节「详情索引」的原章节列定位。
> **维护**:本文件与 `../SKILL.md` 的指针行成对;改内容时同时核对主文件的指针描述是否仍准确。
---
## 外部数据源缓存必须带结构版本守卫(2026-09-11 实证)
换数据源或在缓存条目里增删字段时,**必须同时 bump 一个 `CACHE_VERSION`**,并在读缓存时校验版本/结构(不符即视为未命中重拉)。
踩坑实录(档案 29):白名单路由从「git clone + 解析 yml」改为「拉 `plugins.json`」后,`whitelist-cache/index.json` 仍是**旧格式**且 `fetchedAt` 在 TTL(6h)内 → 被直接复用 → 条目缺 `owner`/`importKind` 字段 → 按字段过滤时 `e.owner.toLowerCase()` 抛异常 → **接口 500**。加 `CACHE_VERSION` 守卫后自动重拉修复。
配套好习惯:① 缓存读失败/不可用时**降级用旧缓存并返回 `stale: true`**,前端提示;② 排序按「热度」字段降序,让无效条目自然沉底,默认首页就是最有价值的那些。
## 官方白名单插件来源(档案 29 定型口径)
- **数据源**:`https://awesome-dsh-plugin.com/plugins.json`(官方规范地址,3.1MB / 3408 条 / 23 分类;npm 镜像包 `dsh-plugin-catalog`)。字段:`name/owner/url/page/category/description{zh,en}/npm/version/stars/downloads/install/added`。**不要**再去 git clone 仓库解析 3431 个 yml —— 其 `tarball` 是可选字段,覆盖率仅 6%(211/3431)。
- **导入口径 = 仅预构建**(平台侧绝不执行第三方构建脚本):有 `npm` → `registry.npmjs.org/<name>` → `dist-tags.latest` → `dist.tarball`(scoped 包地址 `@scope%2Fname`,即 `encodeURIComponent(name).replace('%40','@')`);有 `tarball` → release 资产;两者皆无(`install` 为 `github:owner/repo`)→ 拒绝并回显原因。**可导入 1792/3408 = 52.6%**,官方下载量 TOP10 全覆盖。
- **npm 官方 tarball 可直接喂现有 `stageTgzArchive`**(`package/` 包装层已被 `findPackageJson` 兼容)→ 无需改 DB schema。
- **筛选排序技巧**:给列表加 `onlyImportable=1`,并在前端把「只看可导入」默认打开;按 `downloads` 降序使未发 npm 的条目自然沉底。
- **安全兜底不外包**:收录 ≠ 安全审计(上游 README 明确)。所有导入包仍走平台 `stageTgzArchive` 扫描,P0 命中即阻断,并把原因**在页面内回显**给 admin 判断(例:热门插件 `FuRongJun-1999/dsh-memory` 因 `docs/…example.yml` 被判 P0,疑似误报)。
## 技能 vs 插件:怎么区分(2026-09-11 更正,别用"有没有代码/界面"判)
**先纠正一个常见误解**:技能**可以带 `scripts/`**(实证:`短视频工作台/scripts/MCN_CYLG_API.py`、`mcp-config.json`)。所以「技能=纯内容无代码」「不带界面的插件就是技能」**都不成立**。
**正确判据 = 「代码何时、被谁执行」**:
| | 技能(skills) | dsh 插件(plugins) |
|---|---|---|
| 包形态 | 目录 + `SKILL.md`(+ `scripts/`、`references/`) | npm 包 + **`dsh.bundle.patch`**(+ 可选 `client.js`) |
| **代码执行者** | **agent 通过 bash 工具按需调用**(SKILL.md 指示 → 模型决定) | **cordis 在实例启动时加载执行**(无人决定) |
| 是否经审批/沙箱 | ✅ 走统一工具管线(approval + 沙箱 + uid/cgroup) | ❌ **不经**,它自己就是实例进程的一部分 |
| 参与框架生命周期 | 否(纯文件) | 是(注册服务/工具/UI,进 `profile.bundles`) |
| 装载时机 | 运行时按需发现,**watch 即时生效** | **启动时**,改后必须重启 |
| 失败后果 | 脚本报错 / agent 表现不佳 | **实例起不来(崩溃循环)** |
| 透明度 | 命令进会话记录,可追溯 | 静默运行 |
**可编程判据(我们代码里已在用)**:看包里有没有 **`dsh.bundle`**(`isBundle()` 判 `dsh.bundle.patch`)→ 有=插件,无=技能。**有无 client 面(UI)只是插件的可选属性**,与"是不是技能"无关。
**风险分层(理由要准)**:技能低风险靠三条——**惰性**(不调用不执行)+ **可见**(命令在 transcript)+ **失败不致命**;插件高风险的核心理由是 **开机即执行、无人介入、失败致命**。
> ⚠️ 注意:档案 33 把默认档改成 `danger-full-access` + `approval: never` 后,**技能脚本也不再弹确认**(仍受沙箱/uid/cgroup 约束),两条路线的"人工拦截面"差距因此缩小——分层的主要依据从"审批"转为"是否被框架主动加载 + 失败是否致命"。
## 术语与环境约定(2026-09-11 档案 38b)
- **术语:统一叫「功能插件」**(2026-09-11 起由「业务插件」改名)。**只改显示文案/注释,代码标识符保持不变**:表名 `business_plugins`、包名 `@dsh-local/business-plugins`、section id `business-plugins`、API 路径 `/api/plugins/{business,mine}`、文件名 `business-plugins.ts` / `ensure-biz-plugins.cjs`、目录 `poc/business-plugins/`。
- **`ensure-biz-plugins.cjs` 已是「版本感知 + 自动取最新产物」**:升级流程 = 把新包丢进 `/opt/dsh/artifacts/` → 跑一次脚本(落后会自动 `pnpm add`)。**升级时不要先删旧包**,否则依赖表里的旧 `file:` 指向失效文件会让 `pnpm` 整体 ENOENT 失败(正确顺序:先放新包 + 改依赖指向 → `pnpm add` → 再删旧包)。
- **`.gitignore` 已忽略 `*.bak-*`**:`git add <dir>` 会把同目录的未跟踪备份一并暂存(已踩一次)。提交前用 `git status --short` 核对,或定向 `git add <具体文件>`。
- **服务器 Python 是 3.6.8,不要动系统 `python3`**:`/usr/libexec/platform-python` 是 `dnf`/`yum` 的 shebang,替换/升级会直接搞坏包管理器。**运维脚本一律用 Node**(平台技术栈就是 Node);必须用 Python 时写 3.6 兼容代码(无 `subprocess.run(capture_output=)`、无 f-string `=` 调试等 3.7+ 特性)。确需现代 Python 就**并行装 `python3.11`**(仓库有),别切 alternatives。