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.3 KiB
10-共享技能只读部署(bundledSkillDir 层)
状态:已实施(机制生效);管理面见档案 11|2026-09-09|对象:dshs + dsh 0.1.2-rc.1 需求来源:能否上传 skill 让所有用户可用、只允许使用不允许修改?用 MCN V1.0 短视频脚本技能(290MB)做可行性分析 + 嵌套 subskill(browser-harness)能否在服务器运行。
TL;DR|结论:共享只读技能层:dsh 原生支持
bundledSkillDir(全员可用、不可修改)。 关键:实测结论:主技能放 bundled 只注册 1 个;6 个 subskill 要各自独立目录平铺才能成为可调技能。 状态:✅ 机制已实施(管理面见档案 11)
一句话结论
支持,且 dsh 原生设计了这一层:skill-filesystem 的 bundledSkillDir(env DSH_BUNDLED_SKILL_DIR,rank 600)就是"系统标准技能层"——所有实例共享、只读、不可改(trustedHost: true 直读 + root 属主 OS 权限兜底)。唯一卡点:dshs 编排器 spawn 子进程时 env 走白名单过滤(ALLOWED_ENV),新变量不会自动透传,需改编排器 2 处(自研代码,不触碰红线 2 的官方 dsh 主程序)。
需求判定
| 子问题 | 结论 |
|---|---|
| dsh 是否支持上传 skill 全员共享 | ✅ 支持,但无"上传"界面——机制是文件系统扫描 + env 注入指向共享只读目录 |
| 只允许使用、不允许修改 | ✅ bundled 层设计即此语义(详见机制表) |
| MCN V1.0(290MB)能否直接放 | ⚠️ 需裁剪(290MB 中 238MB 是 browser-harness 的 Windows venv,服务器 Linux 不可用)+ 拍平(见 subskill 结论) |
| 嵌套 subskill(browser-harness 等)能否被识别 | ⚠️ discoverRoot 只扫 root/<技能名>/SKILL.md 一层,subskills/ 内技能不会自动注册为独立技能;需拍平到 bundled 根目录(每个子技能目录含自己的 SKILL.md 即可独立注册) |
| browser-harness 能否在服务器运行 | ⚠️ 机制上可行但工程量大:自带 envs 是 Windows 构建(Scripts/browser-harness.exe),Linux 需重建 venv + 装 headless Chrome + 依赖;且服务器为海外节点,直连抖音有风控/地区限制风险 |
机制调研表(源码级证据)
1. skill 装配链(谁在装载技能)
| 环节 | 位置 | 证据 |
|---|---|---|
| 注册插件 | @deepseek-ai/dsh-agent-presets/presets/standard/agent.cordis.yml L83-88 |
skill-filesystem(dsh-skill-filesystem)+ tool-skill(dsh-tool-skill,提供技能目录/加载给 agent) |
| provider 实现 | @deepseek-ai/dsh-skill-filesystem/lib/index.js |
apply(ctx, config) → ctx.skills.registerProvider(...) |
| env 来源 | 同文件 L84 | config.bundledSkillDir ?? (includeDefaultRoots ? process.env.DSH_BUNDLED_SKILL_DIR : void 0) → preset 里无 config 块 → 走 env |
| 只读语义 | 同文件 L142 get() |
parseSkillFile(locator.path, ctx, signal, candidate.source === "bundled") —— bundled 走 trustedHost 直读 |
2. 技能分层 rank(roots 构建,L166-190)
| root | 路径 | source | rank | 修改权限 |
|---|---|---|---|---|
| project-dsh | <项目根>/.dsh/skills |
project-dsh | 100 | 项目内 |
| project-agents | <项目根>/.agents/skills |
project-agents | 200 | 项目内 |
| custom | config.customSkillDirs | custom | 300 | 配置方 |
| user-dsh | $DSH_HOME/skills |
user-dsh | 400 | 用户自己(每人独立,改自己的) |
| user-agents | $DSH_AGENTS_HOME 或 ~/.agents/skills |
user-agents | 500 | 用户自己 |
| bundled | $DSH_BUNDLED_SKILL_DIR |
bundled | 600 | 只读共享(trustedHost=true,无修改面) |
rank 600 注释
trustedHost: true:读取绕过沙箱 fs 服务走 Node 原生直读;技能源为系统标准层,模型侧无可写入口。
3. 扫描粒度(决定 subskill 命运)
discoverRoot(root)=readdir(root.path)单层 → 每个 entry:- 目录 → 要求
<entry>/SKILL.md存在 .md文件 → 直接视为技能
- 目录 → 要求
isPotentialSkillPath:相对 root 最多 2 段(root/<技能名>/SKILL.md),更深(如root/主技能/subskills/子技能/SKILL.md)不被发现。- 结论:V1.0 主技能放 bundled 只注册「短视频工作台」一个;6 个 subskill 要成为独立可调技能必须各自独立目录平铺在 bundled 根。
4. 编排器 env 白名单(实施唯一卡点)
/opt/dshs/lib/supervisor/spawn.js L11-27:
const ALLOWED_ENV = new Set(['PATH','HOME','USER','TMP','TEMP','TMPDIR','SYSTEMROOT','SystemRoot',
'PATHEXT','ProgramFiles','ProgramFiles(x86)','LANG','LC_ALL']);
orchestrator.js baseEnv()(L189-205)= {...scrubEnv(process.env), HOME: ws, DSH_HOME: home, DEEPSEEK_API_KEY}。
→ DSH_BUNDLED_SKILL_DIR 不在白名单 → 即使 systemd 里设了也会被 scrub 掉。必须:
spawn.jsALLOWED_ENV 加'DSH_BUNDLED_SKILL_DIR'orchestrator.jsbaseEnv 显式注入(建议读自身 config,如DSH_BUNDLED_SKILL_DIR ?? '/opt/dshs/bundled-skills')- src/*.ts 同步修改(保持与 lib 编译产物一致)
改的是自研编排器,非官方 dsh 主程序 → 不违反红线 2。
推荐实现方案(获批后执行)
| 步骤 | 操作 | 说明 |
|---|---|---|
| 1 | 服务器建共享目录 /opt/dshs/bundled-skills/(root:root 755) |
用户进程只读,OS 权限兜底不可改 |
| 2 | 改编排器 2 文件(spawn.js 白名单 + orchestrator.js baseEnv)+ src 同步 | 重启 systemctl restart dshs |
| 3 | 裁剪 V1.0 → 部署包(见下) | 290MB → ~30MB |
| 4 | 平铺部署:bundled 根下放 mcn-workstation/(主技能)+ 各 subskill 独立目录 |
主技能内 subskills/ 相对引用保留(V1.0 内目录不动);独立注册的子技能解决"按名调用" |
| 5 | 重启 admin/guest 实例(client 面技能目录即时可见) | 实例重启走主域 Host /api/dsh/restart |
| 6 | guest 浏览器实测:技能目录可见 → 发起会话让模型列出技能 → 确认只读 | 见档案 09 同款验证栈 |
V1.0 裁剪清单(290MB → 预计 <30MB)
| 内容 | 大小 | 处置 |
|---|---|---|
subskills/browser-harness/envs/ |
238MB | 删除(Windows venv,Linux 不可用;服务器按需重建) |
mcn-work-shop/*.db.bak-* |
~16MB | 删除(4 份调试备份) |
mcn-work-shop/ 其余(server.js/tmp/png/.mjs) |
~4MB | 视需求——调试工作台,建议不随技能分发(保留 SKILL.md 引用则需评估) |
SKILL.md + references/ + references-add/ + scripts/ |
~1.3MB | 保留(核心) |
| 6 个 subskill(除 browser-harness envs 外) | ~25MB | 保留 + 拍平 |
subskill / browser-harness 服务器可行性
识别(注册)
- 每个 subskill 目录已含独立
SKILL.md(已逐一确认 6/6)→ 平铺到 bundled 根后可独立注册。 - 主技能 SKILL.md 的「子技能索引」用相对路径
subskills/<名>/SKILL.md引用 → 主技能加载后模型可读文件;但要"作为技能被调用"需独立注册(dsh 无宿主递归扫描机制,WorkBuddy 的软链/递归扫描不适用)。
运行(browser-harness)
| 检查项 | 服务器现状 | 结论 |
|---|---|---|
| 自带环境 | envs/browser-harness/Scripts/browser-harness.exe(Windows) |
❌ 不可直接用 |
| Chrome | 未安装(which 空) |
需装 headless chromium + 系统库(libnss3 等) |
| Node | v22.23.2 ✅ | 可跑 node 型脚本 |
| 网络 | 47.77.182.89 海外节点 | 抖音直连风控/地区限制风险高(MCN 数据抓取核心场景) |
| RedFox API 路径 | REDFOX_API_KEY 已具备 |
✅ API 型数据(榜单/诊断)不受浏览器影响,优先走此路 |
→ 结论:browser-harness 服务器机制可行(Linux headless Chrome + 重建 venv),但投入大且抖音网页抓取在海外 IP 收益不确定;建议第一阶段不启用 browser-harness,抖音类技能优先走 RedFox API 子技能;网页交互类需求待业务验证后再评估。
方案对比
| 方案 | 机制 | 全员可用 | 只读 | 改动面 | 结论 |
|---|---|---|---|---|---|
| A. bundledSkillDir(推荐) | env 注入共享只读目录 | ✅ | ✅(原生 trustedHost + OS 权限) | 编排器 2 文件 + 共享目录 | 正解,语义即"系统标准技能层" |
B. 每用户 $DSH_HOME/skills |
编排器建号时播种 | ✅(复制分发) | ❌ 用户可改自己副本 | 播种逻辑 + 同步机制 | 不合"不可改" |
| C. repository 插件全局注册 | preset 注释提到"deployment registered globally" | 未验证 | 未验证 | 机制不透明 | 不做 |
验证记录
- 源码级证据全部取自行机服务器(2026-09-09 18:xx):装配链 / rank 常量 / discoverRoot 单层 / scrubEnv 白名单 / browser-harness envs 为 Windows venv。
- 已实施(2026-09-09):spawn.ts ALLOWED_ENV 加变量 + orchestrator.ts baseEnv 注入 + 建 /var/lib/dshs/bundled-skills;admin dsh 实例
/proc/<pid>/environ已含DSH_BUNDLED_SKILL_DIR=/var/lib/dshs/bundled-skills。 - 后续管理面(API+UI+个人技能)见档案 11。
回滚
- 编排器改动 revert 2 文件 +
systemctl restart dshs即可(bundled 目录删除即技能消失;实例无需逐个回滚)。