用户令逐字:「E:/ProgramData/.workbuddy/skills 提交仓库是指的这里」—— 即本目录就是仓库(2026-10-07 已在本目录建仓,见当日日志 §22),本轮把余下未纳管的 9 个技能一并提交。 本次入库(9 个技能,46 个文件): 1、`AI HOT` 2、`draw-ui` 3、`dsh-diagnose` 4、`dsh-knowledge` 5、`dsh-local-env` 6、`dsh-opensource-release` 7、`dsh-workflow` 8、`oil-motion` 9、`skills-security-check` 提交前核对: · **凭据类扫描**(`*.env` / `*token*` / `*.key` / `*secret*` / `*.pem`)⇒ **零命中** ✓; · 体积合计约 20 MB(`draw-ui` 12M + `oil-motion` 6.5M 是大头,形态为配图/素材 —— 仓库 `.gitignore` 里明写「`assets/*.png` 是内容不是产物」⇒ 属刻意入库); · 运行产物仍按既定规则排除(`__pycache__` / `logs/` / `tmp/` / `.venv/` / `*.egg-info` / `uv.lock` / `.workbuddy/`)。
8.3 KiB
机制速查(一)· Profile 层 cordis patch / Skill 装载机制 / Skill 管理面
归属:技能
dsh-change-workflow的详情档(按需读,不是每次都要读)。 本档覆盖:Profile 层 cordis patch 机制 · Skill 装载机制 · Skill 管理面 · dsh 沙箱与权限预设机制(原行 L481–L504 + L555–L600)。 主文件 / 判据与流程主干 =../SKILL.md(§1 六阶段流程 · §2 红线 R1–R8 原文速查 · §3 本机 Git Bash 环境坑 · §4 并行调度结论)。 来源:2026-09-22「技能重组线」把../SKILL.md的 L481–L504 + L555–L600 段逐行原样下沉到本文件,未改一字。 跨档引用:正文里的「§N / 见 §8 坑 N / 见下表」等编号,用../SKILL.md末节「详情索引」的原章节列定位。 维护:本文件与../SKILL.md的指针行成对;改内容时同时核对主文件的指针描述是否仍准确。
Profile 层 cordis patch 机制(角色化 UI 裁剪,档案 09)
- client 插件行 id = 短 id(
ui-settings-models,非包名),见dsh --profile web --dump-config。 - 禁用官方 client 插件(如设置面板「模型」分区对普通用户):profile
cordis.patch.yml写- id: <短id>\n name: "@deepseek-ai/<包名>"\n disabled: true(dsh-app-boot applyEntryPatches:非 insert patch 按 id 合入 overrides)。--dump-config验证:目标行出现disabled: true+# == ... patched by <path>注释。 - 生效必须重启实例(client bundle 启动时打包);
patchReload: live对 client 插件增减不生效(实测 5 轮)。 - 当前生产 spawn 不带
--patchoverlay(enablePatch=false),disable 只能写 profile 层cordis.patch.yml。 - 幂等工具:
/opt/dshs/ensure-role-profile-patch.cjs [--restart] <username>(全量=非 admin 用户;含管理标记头则跳过;非默认空内容不覆盖)。admin profile 不动 = admin 保留该分区。
Skill 装载机制(全员共享只读技能 = bundledSkillDir,档案 10)
- 技能由 agent preset 注册:
@deepseek-ai/dsh-agent-presets/presets/standard/agent.cordis.ymlL83-88(skill-filesystem+tool-skill),preset 无 config 块 → provider 配置走 env。 - 技能分层 rank(
dsh-skill-filesystem/lib/index.jsroots()):project-dsh 100(<项目>/.dsh/skills)/ project-agents 200 / custom 300 / user-dsh 400($DSH_HOME/skills,每用户独立)/ user-agents 500 / bundled 600($DSH_BUNDLED_SKILL_DIR,trustedHost: true只读共享)。 - 扫描粒度:
discoverRoot只扫 1 层(root 下每目录须含SKILL.md;或直接 .md 文件);root/主技能/subskills/子技能/SKILL.md不会被发现 → subskill 要独立可调需平铺到技能根。 - 编排器 env 白名单(关键卡点):
/opt/dshs/lib/supervisor/spawn.jsALLOWED_ENV仅 PATH/HOME/USER/TMP/LANG 等基础变量;baseEnv()={...scrubEnv(process.env), HOME, DSH_HOME, DEEPSEEK_API_KEY}→ 新 env 变量必须同时加白名单 + baseEnv 显式注入(src/*.ts 同步),否则被 scrub 丢弃。这是改编排器(自研,非红线 2 对象)。 - MCN V1.0 技能跨平台部署注意:
subskills/browser-harness/envs/为 Windows venv(Scripts/*.exe),Linux 服务器不可用需重建;海外节点直连抖音风控风险高,数据类优先 RedFox API。
Skill 管理面(编排器 API + 静态页,档案 11)
- dsh 技能名硬规则:
/^[a-z0-9]+(?:-[a-z0-9]+)*$/(@deepseek-ai/dsh-skill/lib/index.jsSKILL_NAME)—— 中文名技能 dsh 静默丢弃。MCN 等含中文名技能需先改SKILL.mdfrontmattername为 kebab(如mcn-workstation)。 - API 形态:
/api/skills/shared(admin 三件套 GET/POST/DELETE)+/api/skills/mine(任何登录用户);上传 base64 body{ file, filename, force? };后端走系统tar/unzip解压、路径穿越校验、合法名校验。包结构:单顶层目录 + 含 SKILL.md。 - 落盘属主:shared → root:root 0755(OS 权限兜底只读);mine →
home属主用户 uid/gid(确保用户可改自己的技能)。踩坑:chownTree须 chown 顶层目录自身(首次实现只 chown 子项,目录保留 tar 包内 owner)。 - watch 即时生效:
skill-filesystem对共享根 watchManager 监听 addDir/unlinkDir/SKILL.md → 自动 invalidate registry(无需重启实例,源码已核实)。 - 编排器 env 注入 DSH_BUNDLED_SKILL_DIR:spawn.ts ALLOWED_ENV 加变量 + orchestrator.ts baseEnv 显式注入(
config.bundledSkillDir,默认<dataRoot>/bundled-skills);这是上一节「全员共享只读技能层」的实例侧落地。
dsh 沙箱与权限预设机制(2026-09-11 源码核实,改默认值必看)
两层隔离,别混淆:
| 层 | 谁提供 | 说明 |
|---|---|---|
| 内层 | dsh 自带沙箱 read-only / workspace-write / danger-full-access |
靠 Landlock 或 bubblewrap 后端。本机不可用:内核 5.10(Landlock 需 5.13+,LSM 无 landlock),bwrap 嵌套探测失败 → fail-closed 拒绝执行任何 shell(@deepseek-ai/dsh-sandbox/lib/index.js:185) |
| 外层 | 平台 systemd-run --scope + bwrap + setpriv |
真正的边界:mount 路径隔离 + uid 隔离 + cgroup(基础 448M → 上界 1024M:MemoryHigh=MIN 软限 + MemoryMax=MAX 硬限;与插件开关无关(档案 96)/150%/128)。内层失效不影响它 |
权限预设插件(row @deepseek-ai/dsh-permission-presets,短 id 一般即 permission-presets):
- 内置预设表(sandbox 与 approval 成对绑定,这是关键坑):
'workspace-write': { sandbox: 'workspace-write', approval: 'ask' } 'danger-full-access': { sandbox: 'danger-full-access', approval: 'never' } // ← 选它=同时摘掉审批 defaultPreset = config.defaultPreset ?? inferredDefault;默认落workspace-write(→ 本机即「shell 全废」)。- 设置持久化命名空间 =
permission(settings keypermission.defaultPreset,值必须是presets里的键名)。
改默认值的官方做法(不碰官方主程序,R2 合规):
⭐ 首选:
DSH_PERMISSION_MODE环境变量(2026-09-11 定案,档案 33)。 官方@deepseek-ai/dsh-base/cordis.patch.yml:217/233直接读它:mode: !!js process.env.DSH_PERMISSION_MODE ?? 'workspace-write' policy: !!js "(process.env.DSH_PERMISSION_MODE ?? 'workspace-write') === 'danger-full-access' ? 'never' : 'ask'"在编排器 spawn 时注入
DSH_PERMISSION_MODE=danger-full-access即可 全局默认「完全权限」+ 免审批,且: ① 不必铺 profile(env 随 spawn,新用户自动生效);② 完全复用官方逻辑(预设表 / 设置 UI 都不动)。 落地两处:spawn.ts的ALLOWED_ENV加该键 +orchestrator.ts的baseEnv()注入(值取process.env.X ?? 'danger-full-access',运维可覆盖)。 ⚠️ 副作用:权限档位是会话级播种(会话创建时写permission/preset/sandbox/mode/approval/policy三条种子事件)→ 旧会话不跟随新默认,必须新建会话才生效。给用户的话术是「新开一个会话」,不是「刷新页面」。
其余做法(需要更细粒度时才用):
- profile 层
cordis.patch.yml改该行config—— 已核实applyEntryPatches里const { id, insert, name, ...overrides } = patch→ patch 的其它键会作为 overrides 合入目标行,所以config:可覆盖。 注意config是整体替换不是深合并 → 必须把内置的两个预设一并写全。 - 或改设置:
$DSH_HOME/settings.yaml加permission: defaultPreset: <presets 里的键名> - profile 是每用户一份 → 要像
ensure-role-profile-patch.cjs那样给每个用户(含新用户)铺;改完必须重启该用户实例才生效。 - 用户仍可在实例「设置 → 权限」自助切换(
ui-permission),这是设计内的。
推荐形态:不要直接用 danger-full-access(会连审批一起摘掉)。在 patch 里新增一个自定义预设:
sandbox: danger-full-access + approval: ask,语义 = 「隔离由平台容器提供,高风险操作仍需确认」。