1) dsh-server-docs/ 从工作区(原 E:\...\aliyun-dsh-server\dsh-server-docs)**整体并入本仓**,
保留目录名 ⇒ 仓库内 dsh-server-docs/... 的相对引用天然继续有效;旧目录(含其 .git)已归档到
工作区 _中间产物_待清理/,未随本提交带入。
2) .gitattributes:新增 `dsh-server-docs/** -text` —— 原文档库是 `* -text` + autocrlf=false,
必须保持纯 LF,否则会被本仓的 CRLF 规则翻掉。
3) 活引用里的绝对路径已全部改到新位置(docs 的 INDEX / README / scripts / skills + 用户级 skills
+ ~/.workbuddy/settings.json 的 hooks);历史档案(04-调整方案/、archive/)按「只增不改」未动。
⚠️ hooks 路径改动需「完全重启会话」才生效(配置是会话启动快照)。
4) 交接单/T08:新增 §16「生产整体切换执行记录」(形态 / 落地动作 / **4 个只有真上线才暴露的真 bug** /
验收证据 / 回滚命令 / 残留项);台账 T08 行 → 已完成并归档;03-路线图 §二 登记 T08 收尾项。
5) 统一称谓:**「本机」只指跑 WorkBuddy 的开发机**,47 / 106 一律写「远程服务器」。
9.1 KiB
9.1 KiB
27 · MCN 工作台插件平台化评估
- 日期:2026-09-11
- 输入:用户提问「能否模拟 admin 安装到 dsh 服务器功能插件中/是否支持多用户/数据与产物如何存储/每个插件自带数据库有无风险/功能插件调用 skill 应整合还是外置」
- 分析对象:
C://Users//Administrator//.dsh//profiles//web//node_modules//下的dsh-plugin-mcn(主)、dsh-plugin-social-workbench、dsh-plugin-mcn-schedule、dsh-plugin-douyin-* - 结论一句话:机制上可作为"功能插件"投放,但有 3 处必须先改(DSH_HOME 路径、技能路径硬编码、agent preset 随包投放);多用户天然成立(每用户独立实例 → 每用户一份 DB);技能应"外置"(平台共享技能层),插件只按名引用。
一、先看结论(对应你的 5 个问题)
| # | 你的问题 | 结论 |
|---|---|---|
| 1 | 能否模拟 admin 安装为功能插件 | ✅ 机制可行(标准 bundle:dsh.client + cordis.patch.yml insert 一行)。但需 3 处改造(见 §三),否则装上去功能会残 |
| 2 | 是否支持多用户 | ✅ 天然成立:平台是"每用户独立实例 + 独立 DSH_HOME + uid/bwrap 隔离"→ 插件的单租户 DB 变成每用户一份,无需加 userId 列 |
| 3 | 数据与产物存储 | DB 在 DSH_HOME(平台里 = <userRoot>/home,用户在 ws 里默认看不到);产物写在用户工作区内(如 视频对标/…/analysis.json)→ 天然按用户隔离 |
| 4 | 插件自带数据库有无风险 | 总体可接受:node:sqlite 在平台 Node 22.23.2 实测可用;风险点见 §五(实验 API 随 Node 变动、用户可损坏自己的库、需备份/重建路径) |
| 5 | 功能插件调用 skill 应整合还是外置 | ✅ 外置(放平台共享技能层),插件只按技能名引用;preset 随插件投放;MCP 建议预装而非每次 npx 拉包 |
二、插件形态解剖(实测证据)
| 维度 | 事实 |
|---|---|
| 包形态 | dsh-plugin-mcn(569K):dsh.client{platform:web, inject:[dsh-client-runtime, dsh-client-ui-sidebar]} + dsh.bundle.patch → cordis.patch.yml(insert: mcn-nav → dsh-plugin-mcn) |
| Host 面拆分 | lib/{index,db,data,http,mcp,imports,video-tools,workshop,config}.js |
| 数据库 | node:sqlite(DatabaseSync),DB_PATH = join(homedir(), ".dsh", "mcn-plugin.db");另读 homedir()/.dsh/storages/workspace.json、写 homedir()/.dsh/mcn-rank-update.json |
| 表结构 | 10 张表(hot_accounts / account_videos(362 行) / account_video_analysis / account_persona / account_analysis / account_video_source / creative_log / rewrite_log / storyboard_log / script_review):按 account_id 组织,无 userId/owner 字段(= 单租户设计) |
| 技能调用方式 | 插件不执行技能:UI 收集参数 → 拼提示词要求 agent 调用具名技能("请调用「mcn-dou-analysis」技能(路径 ~/.dsh/skills/mcn-dou-analysis/,已全局注册)…") |
| 硬编码技能路径 | ~/.dsh/skills/ 下:mcn-dou-analysis ×6、script-review ×3、short-video-script ×2、storyboard-prompt ×1、mcn-data-insight ×1 |
| 能力来源 | agentPreset:ctx.get("agentPresets").resolve("mcn") + presets.mount(agentCtx, resolvedId);preset 实体在 <DSH_HOME>/.agent-presets/mcn/{preset.yml, agent.cordis.yml}(挂 persona / agent-instructions / tool-bash / tool-fs / tool-fs-search / … ) |
| MCP | 自带 stdio MCP 客户端(mcp.js):npx myai-mcp(NPX_CMD / MCP_PACKAGE / MCP_ENV);且该文件已优先读 DSH_HOME(正确写法) |
| 产物落点 | 用户工作区(如 {产出根}/<账号>/视频对标/<视频>/analysis.json);Excel 导入用 xlsx |
关键洞察:插件的能力 = preset(preset 决定挂哪些工具/技能/MCP),插件本体只是 UI + 数据 + 提示词编排。
三、平台化必改清单
| 优先级 | 改动 | 现状 → 目标 | 为什么 |
|---|---|---|---|
| P0 | DSH_HOME 路径 | join(homedir(), '.dsh') → process.env.DSH_HOME ?? join(homedir(), '.dsh')(config.js 3 处:DB_PATH / storages/workspace.json / mcn-rank-update.json) |
平台里 HOME=<userRoot>/ws、DSH_HOME=<userRoot>/home,两者不等 → 现状会写到 <ws>/.dsh/,并读不到真正的 storages/workspace.json(工作区/账号目录定位失效)。mcp.js 已是正确写法,可对照 |
| P0 | 技能路径 | 删除 ~/.dsh/skills/<name>/ 硬编码(共 13 处),只保留技能名;或读平台注入的技能根(共享只读层 env) |
平台技能是"共享只读层 + 个人层"两段式(档案 10/11),且实例 HOME=ws → ~/.dsh/skills 不存在;agent 按"已注册技能名"即可加载,不必给路径 |
| P0 | agent preset 随包投放 | <DSH_HOME>/.agent-presets/mcn/ 必须在用户实例里存在 |
平台每用户 DSH_HOME 独立 → preset 无人写进去就退化为默认 preset(注释已写明"否则工具集为空/能力缺失")。建议:随插件包或平台 provisioning 写入 |
| P1 | MCP 预装 | npx myai-mcp → 预装到镜像/实例(或内置实现) |
平台实例有 512M 内存 + 出网护栏 + 无外网缓存,每次 npx 拉包会慢且可能首启失败 |
| P1 | DB 备份/重建路径 | 增加"库损坏 → 重建空库"的兜底(表结构可重建) | 用户在实例内可写 DSH_HOME(只有 cordis.patch.yml/package.json/pnpm-lock.yaml 被 ro-bind,DB 不在其中)→ 有自伤风险 |
| P2 | 技能依赖声明 | 插件 README/元数据声明"需要哪些技能" | 便于平台侧按需投放;避免"装了插件但技能缺失"的静默失败 |
四、投放与隔离(怎么做)
- 投放路径:admin 在门户
plugins.html上传 tgz → 进候选池(默认禁用)→ 用户在实例设置「功能插件」勾选启用 → 重启实例生效(档案 16 的既有机制)。 - 安装:平台走
pnpm add file:<tgz>(HOME=<userRoot>/ws)→ 每个用户 profile 一份;新用户由ensure-*脚本族 + provisioning 钩子补齐(参照目录选择器插件的做法)。 - 隔离:DB/产物/技能都在该用户自己的实例内(uid + bwrap)→ 用户间互不可见;跨租户不成立。
- 多用户注意:
mcn-schedule(定时任务)与dsh-plugin-social-workbench是独立包,要一起投放否则功能缺失;mcn-schedule.json同样在DSH_HOME根 → 与 P0 同改。
五、自带数据库的风险评估
| 风险 | 评估 |
|---|---|
| 引擎可用性 | ✅ 实测:平台 Node 22.23.2 直接 require('node:sqlite') 成功(仅 ExperimentalWarning) |
| 与平台 DB 冲突 | ❌ 无:平台用 better-sqlite3(/var/lib/dshs/*.db),插件用自己的文件,互不相干 |
| 并发 | ❌ 无:每用户独立实例,DB 无跨进程并发 |
| 实验 API 变动 | ⚠️ 中:node:sqlite 在不同 Node 版本间 API 可能变 → 应补进档案 26 升级耦合点(Node 升级时回归) |
| 用户可损坏自己的库 | ⚠️ 中(自伤):实例内可写 DSH_HOME → 建议加"重建空库"兜底(P1) |
| 体积/性能 | ✅ 低:本地 4.2MB(10 表、362 视频行);每用户一份,磁盘可控 |
六、技能:为什么"外置"而不是"整合进插件"
| 维度 | 整合进插件 | 外置(推荐) |
|---|---|---|
| 体积 | 技能副本 × 用户数(每个 profile 一份) | 共享只读层一份(档案 10/11) |
| 更新 | 改技能要重装插件 + 重启 | 改技能层即可,插件不动 |
| 与平台能力冲突 | 与"技能管理面(共享/个人技能上传)"冲突 | 复用平台既有技能管理面 |
| agent 加载 | 插件得自己把技能挂进 preset | agent 按技能名加载已注册技能 ✓ |
| 结论 | ✗ | ✅ |
做法:插件里把 13 处 ~/.dsh/skills/<name>/ 换成只写技能名(或由平台注入技能根,插件读 env);技能本体由平台技能层(共享只读 + 个人)投放;preset 仍需随插件投放(它是"这次会话挂哪些工具"的清单,属插件能力的一部分)。
七、落地建议(分三步,建议顺序)
- 改造(插件侧,P0 三项):DSH_HOME、技能路径、preset 投放 → 这是"能不能跑"的门槛;
- 投放(平台侧):按功能插件机制上架 + 新用户自动铺开(复用
ensure-workspace-picker.cjs的--user-id模式,扩成通用ensure-plugin脚本); - 加固(P1):MCP 预装、DB 重建兜底、技能依赖声明。
八、红线与回归
- 不修改官方 dsh 包;投放走功能插件机制(档案 16);新用户铺开走 provisioning 钩子(档案 18 v3 做法)。
- 升级回归需补两条:①
node:sqliteAPI(Node 升级)② 功能插件 client bundle 契约(档案 26 §C4)。
本文为评估(只读分析 + 推荐),未改动插件源码;改造需按 §七 分步实施并逐项验证。