yyyyolo7a79-sketch/dsh-auto-and-safety
DSH auto-and-safety permission preset: full file access but no delete without user approval
Project Overview项目介绍
dsh-auto-and-safety is a DeepSeek Harness (DSH) permission plugin that adds an auto-and-safety preset, inheriting danger-full-access file rights while blocking all file deletion. It intercepts shell delete commands at tools/pre-execute and injects a safety rule into the system prompt, requiring the agent to list temp file names and locations and request explicit text approval from the user after each task. Use it when you want full-access capabilities but with deletion gated behind human approval. Caveat: detection uses regex, so deletion variants may slip through; approval is granted based on the most recent user message, creating a one-time pass-through window.
dsh-auto-and-safety 是 DeepSeek Harness (DSH) 的权限插件,新增 auto-and-safety 预设:继承 danger-full-access 全文件权限,但禁止一切删除文件的行为。它在 tools/pre-execute 拦截 shell 删除命令,并向 agent 注入安全规范,任务完成后必须列出临时文件名称与位置向用户询问,经用户明确文字批准后才可删除。适用于希望 agent 拥有全权限干活但把删除这类不可逆高危操作锁死为"人批后放行"的场景。需注意:拦截基于正则,无法穷举所有删除变体;批准以最近一条用户消息为准,存在一次放行窗口。
请帮我了解并安装插件:【dsh-auto-and-safety】【https://github.com/yyyyolo7a79-sketch/dsh-auto-and-safety】
Send this message to DSH in your current session. CLI install commands may not be accurate across systems — DSH will figure it out for you.把上面这条消息直接发给当前会话里的 DSH,让它帮你了解并安装。安装命令不一定准确,发给 DSH 更稳。
Or use CLI install (for developers)或使用命令行安装(适合开发者)
CLI Install命令行安装
dsh plugin --profile web add github:yyyyolo7a79-sketch/dsh-auto-and-safety#main
把 yyyyolo7a79-sketch/dsh-auto-and-safety 加入你的 DSH 配置(web profile)即可启用。
READMEREADME
dsh-auto-and-safety 权限插件
为 DeepSeek Harness (DSH) 新增一个
auto-and-safety权限预设:继承danger-full-access(全文件权限)的能力,但禁止一切删除文件的行为;每次任务完成后,agent 必须向用户询问是否删除任务过程中产生的临时(tmp)/ 冗余文件,指明文件是什么、文件位置,经用户明确批准后才可删除。
目录
- 1. 需求背景
- 2. 总体设计
- 3. DSH 权限体系原理(前置知识)
- 4. 实现细节
- 5. 安装步骤
- 6. 使用流程(与演示截图对应)
- 7. 实现效果
- 8. 行为示例(拦截记录)
- 9. 已知限制与边界
- 10. 卸载方法
- 11. 给 dsv4 / 后续整合者的说明
1. 需求背景
用户原始需求(原话):
在你的权限
read only / workspace write / all accuse中再加一条权限auto-and-safety: 内容为继承 all accuse 的权限,但是禁止一切删除文件的行为,每次任务完成后向用户询问是否删除任务过程中产生的 tmp、冗余文件,并指明文件是什么以及文件位置,在用户批准后才可以删除。
即:希望 agent 拥有"全权限"干活能力的同时,把"删除文件"这一不可逆高危操作锁死为人批后放行,防止 agent 自行清理/误删。
2. 总体设计
实现分两层,缺一不可:
| 层 | 载体 | 作用 |
|---|---|---|
| 权限预设层 | cordis.patch.yml 中 permission 行的 presets 表 |
让 auto-and-safety 成为可切换的权限预设(GUI 选择器 + /permission 命令可见可选) |
| 行为强制层 | 本地插件 plugins/auto-and-safety/lib/index.js |
① 向系统提示注入安全规范;② 在 tools/pre-execute 工具执行门上硬拦截删除命令 |
设计要点:
- 预设 = 两个旋钮的组合:DSH 的权限预设表每项只有
sandbox(文件沙箱模式)和approval(审批策略)两个字段。auto-and-safety=sandbox: danger-full-access(继承 all access)+approval: ask(保留审批通道)。 - "禁止删除"无法用旋钮表达:DSH 沙箱模式枚举只有
read-only/workspace-write/danger-full-access,没有"禁止删除"模式。因此"禁止删除 + 批准后放行"必须落在工具执行前的拦截钩子上。 - 官方 fs 工具本身没有删除能力:DSH 的 fs 工具只有
read/write/edit/read_image,删除文件只能通过 shell(pwsh/bash)命令或 .NET 调用。所以拦截点聚焦 shell 命令即可覆盖实际删除路径。
3. DSH 权限体系原理(前置知识)
以下基于 @deepseek-ai/dsh rc.6 源码,整合时如版本变化请以实际源码为准。
3.1 三个硬编码枚举
| 概念 | 定义位置 | 取值 |
|---|---|---|
沙箱模式 SandboxMode |
@deepseek-ai/dsh-sandbox-policy 的 SANDBOX_MODES |
read-only / workspace-write / danger-full-access |
审批策略 ApprovalPolicy |
@deepseek-ai/dsh-user-approval 的 APPROVAL_POLICIES |
ask / never |
| 沙箱升级阶梯 | @deepseek-ai/dsh-sandbox 的 WIDER_MODES |
read-only → workspace-write → danger-full-access(只升不降) |
3.2 权限预设表(permission presets)
- 插件:
@deepseek-ai/dsh-permission-presets(行 id:permission,位于dsh-basebundle)。 - 配置:
presets是一个 dict,每项{ sandbox, approval, name?, description? }。 - 切换机制:切换预设会向会话日志追加
permission/preset事件,并分别写sandbox/mode、approval/policy事件;会话通过日志回放(fold)恢复当前预设,因此重启不丢状态。 - 派生逻辑
derive():按"当前折叠的 sandbox + approval 值"匹配表项;匹配不到显示为custom。 custom是保留名,不能用作家表项名。- 默认预设推断:无显式
defaultPreset时取组合默认值(workspace-write+ask)能匹配到的表项。
3.3 组合补丁机制(patch)
- DSH 的 profile 组合 = 多个 bundle 的
cordis.patch.yml按顺序叠加 + 用户 patch 层(<DSH_HOME>/profiles/<profile>/cordis.patch.yml)。 - patch 条目语法(顶层 YAML 数组):
- id: <行id>+ 其余字段 → 整行覆盖目标行的对应字段(config整体替换,不是合并);- insert: [...]→ 插入新行(顶层或指定组);- id: <行id>+disabled: true→ 禁用。
dsh-base中permission行的默认 presets 只有三个:read-only/workspace-write/danger-full-access。- 用户 patch 层被 HMR 监听,修改后热重载,无需重启 web。
3.4 工具执行前拦截门(tools/pre-execute waterfall)
- 每个工具调用执行前,工具注册表跑一个 waterfall:
ctx.waterfall(carrier, 'tools/pre-execute', exec, () => ({ kind: 'allow' }))。 - 任何插件可用
ctx.on('tools/pre-execute', (exec, next) => ...)注册监听;返回{ kind: 'deny', reason }即拒绝本次调用,工具结果会显示Error: <reason>;返回next()放行。 exec结构:{ name, arguments, agent, callId, signal, ... };exec.agent.session是调用方会话,exec.arguments.command是 shell 命令文本。- 语义:任一监听可 deny,且没有监听可以强制放行已被 deny 的调用。
3.5 系统提示动态注入(systemPrompt context)
ctx.systemPrompt.context({ name, order, text: (context) => string })注册动态提示段,text每次构建提示时调用,可读context.agent.session按会话状态决定输出。- 参考:
dsh-sandbox-policy用 order 110 注入 "Current DSH file policy: ...";本插件用 order 111 注入安全规范。
4. 实现细节
4.1 预设表配置(cordis.patch.yml 片段)
- id: permission
config:
presets:
read-only:
sandbox: read-only
approval: ask
workspace-write:
sandbox: workspace-write
approval: ask
danger-full-access:
sandbox: danger-full-access
approval: never
auto-and-safety:
sandbox: danger-full-access
approval: ask
name: auto-and-safety
description: 继承 danger-full-access 的全部文件权限,但禁止一切删除文件的行为;任务完成后向用户询问是否删除任务产生的临时/冗余文件(指明文件与位置),批准后才可删除
- insert:
- id: auto-and-safety
name: ./plugins/auto-and-safety/lib/index.js
⚠️ 因为是整行替换,必须写全全部四个预设,漏掉任何一个都会使它在权限选择器中消失。
4.2 插件逻辑(plugins/auto-and-safety/lib/index.js)
纯 ES Module,无第三方依赖(不 import 任何包),导出 name / inject / apply,符合 Cordis 本地插件格式。
export const name = 'auto-and-safety';
export const inject = ['systemPrompt', 'permissionPresets'];
① 删除命令识别正则(DELETE_CMD_RE,大小写不敏感,安全优先宁可误拦):
| 目标 | 匹配 |
|---|---|
| PowerShell cmdlet 与别名 | remove-item ri rm del erase rmdir rd empty-recyclebin |
| cmd 命令 | del erase rmdir rd |
| bash 命令 | rm rmdir unlink shred |
| .NET 静态调用 | [IO.File]::Delete(...) → ::delete\s*\( |
rd 单独要求后随路径/开关(rd "路径" / rd /s ...),避免把参数里的目录名误判为删除命令。
② 批准放行判定(GRANT_RE + QUESTION_RE):
- 扫描会话事件(倒序),找最后一条
user/message事件且source.kind === 'user'(排除工具注入、系统消息); - 其文本命中批准短语 → 放行;命中疑问句(
[吗么呢??]\s*$)→ 视为询问而非批准; - 批准短语覆盖:"批准/同意/允许/确认(的|了)删除/删掉/移除/清理"、"请删除/请删掉"、"可以删除(了|吧)"、"删除吧/删掉吧/清理掉"等。
③ 拦截器(tools/pre-execute,prepend: true):
ctx.on('tools/pre-execute', (exec, next) => {
if (exec?.name !== 'pwsh' && exec?.name !== 'bash') return next();
const session = exec.agent?.session;
if (!session || currentPreset(ctx, session) !== 'auto-and-safety') return next();
const command = exec.arguments?.command ?? '';
if (!DELETE_CMD_RE.test(command)) return next();
if (hasUserGrant(session)) return next();
return { kind: 'deny', reason: DENY_REASON }; // 拒绝,附流程指引
}, { prepend: true });
判定链:仅当 ①工具是 shell、②会话预设为 auto-and-safety、③命令命中删除模式、④最近用户消息无批准 → 拒绝。任何一步不满足都放行,因此不影响其他预设与其他工具。
④ 系统提示注入(systemPrompt.context,order 111):
仅当会话预设为 auto-and-safety 时输出安全规范:禁止一切删除;任务完成后必须用 ask_user_question 列出文件(名称 + 完整路径 + 用途)询问;批准后才可删;无临时文件时明确说明。
5. 安装步骤
无论哪种安装方式,都必须手动合并
cordis.patch.yml中的两个补丁条目(①- id: permission预设表、②- insert:挂载条目)——dsh 的 patch 是用户 profile 的配置层,安装命令不会代你改配置。合并时注意 permission 条目必须写全四个预设(整行替换语义,漏写会从权限选择器消失)。
5.1 快速安装(复制 GitHub 链接即可)
方式 A:git clone 到 plugins 目录(推荐,与 dsh-session-search 同款方式,挂载用本地路径)
# ① 克隆仓库到 profile 的 plugins 目录(以 web profile 为例)
git clone https://github.com/yyyyolo7a79-sketch/dsh-auto-and-safety.git <DSH_HOME>/profiles/web/plugins/dsh-auto-and-safety
# ② 把仓库根目录 cordis.patch.yml 的两个条目并入你的 patch 层:
# <DSH_HOME>/profiles/web/cordis.patch.yml。
# 其中 - insert: 的挂载路径要写完整(克隆后仓库根在 plugins/dsh-auto-and-safety/,
# 插件本体在其内部的 plugins/auto-and-safety/lib/index.js):
# - insert:
# - id: auto-and-safety
# name: ./plugins/dsh-auto-and-safety/plugins/auto-and-safety/lib/index.js
# ③ 验证生效(配置走 HMR 热重载,通常无需重启;若权限选择器无新选项则重启 web)
dsh --profile web --dump-config | grep auto-and-safety
方式 B:dsh plugin 命令安装(装进 profile 的 node_modules,pnpm 方式)
# ① 安装插件包(等价于在该 profile 目录执行 pnpm add;#main 可换成实际默认分支)
dsh plugin --profile web add github:yyyyolo7a79-sketch/dsh-auto-and-safety#main
# ② 同样把 cordis.patch.yml 两个条目并入,但 insert 的 name 改用包名(插件在 node_modules 里):
# - insert:
# - id: auto-and-safety
# name: dsh-auto-and-safety
安装完成后,在会话中执行 /permission auto-and-safety(或在 GUI 会话权限选择器中选择)即可启用。
5.2 手动安装
- 放插件源码:把
plugins/auto-and-safety/整个目录复制到<DSH_HOME>/profiles/<profile名>/plugins/下(与dsh-session-search等本地插件同级)。- 例如:
C:\Users\PC\.dsh\profiles\web\plugins\auto-and-safety\lib\index.js
- 例如:
- 改配置:把
cordis.patch.yml中的两个条目(- id: permission与- insert:)并入<DSH_HOME>/profiles/<profile名>/cordis.patch.yml。- 若你的 patch 层已有
- id: permission条目,用新 presets 覆盖即可(注意写全四个预设)。
- 若你的 patch 层已有
- 生效:
- 配置走 HMR 热重载,通常无需重启;若 GUI 权限选择器未出现新选项,重启 web。
- 验证组合:
dsh --profile web --dump-config,应能看到auto-and-safety预设与插件行。
- 启用:在会话中执行
/permission auto-and-safety,或在 GUI 会话权限选择器中选择auto-and-safety。
6. 使用流程(与演示截图对应)
| 步骤 | 动作 | 截图 |
|---|---|---|
| 1 | 权限栏出现新的 auto-and-safety 预设 |
docs/权限栏新增.png |
| 2 | 任务完成后,agent 用 ask_user_question 列出临时文件(名称 + 路径 + 用途)询问 |
docs/拦截演示1.png |
| 3 | 选择框选择 ≠ 批准,删除命令被硬拦截,要求对话内文字明确批准 | docs/拦截演示2.png |
| 4 | 用户对话回复"批准删除/可以删除/删除吧"等批准短语 | docs/拦截记录/session.jsonl |
| 5 | agent 重试删除命令 → 拦截器检测到最近用户消息含批准短语 → 放行,删除成功 | docs/批准后成功删除.png |
演示截图
① 权限选择器:新增的 auto-and-safety 预设(当前已选中)

② 任务完成后,agent 列出临时文件询问用户是否清理(ask_user_question)

③ 选择框选择不算批准,删除命令被硬拦截,要求对话内文字明确批准

④ 用户在对话中回复"批准删除"后,删除执行成功

7. 实现效果
agent 视角(会话内):
系统提示出现
auto-and-safety专属规则段(order 111),agent 从第一轮起就知道:- 禁止一切删除文件/目录的行为;
- 任务完成后必须主动列出 tmp/冗余文件(名称 + 完整路径 + 用途)并询问;
- 只有用户明确批准后才可删除;没产生临时文件时明确说明"无临时文件需要清理"。
删除命令(shell / .NET)在工具执行门被硬拦截,返回:
Error: auto-and-safety 权限预设禁止直接删除文件/目录:此命令包含删除操作且本会话尚未获得用户批准,已拦截。正确流程:先用 ask_user_question 向用户列出要删除的每个文件(名称 + 完整路径 + 用途/是什么),征得用户批准;用户回复明确的批准(如"批准删除""同意删除""可以删除""删除吧")后,再重试删除该文件的命令。不得用脚本、编码或其他命令变体规避拦截。拦截提示会引导 agent 走"询问 → 批准 → 重试"闭环,而不是绕过。
用户视角:
- 权限选择器/
/permission多一个auto-and-safety选项,切换即时生效; - 每次任务完成后收到明确的清理询问(文件是什么、在哪、要不要删);
- 删除永远发生在自己点头之后。
8. 行为示例(拦截记录)
以下为真实会话回放(
docs/拦截记录/session.jsonl,DSH 会话日志)的完整「拦截 → 询问 → 批准 → 放行」闭环。
场景:搭建 deepseek + dsh 工作流时,agent 批量安装 12 个目标插件(最终装 8 个插件 + 5 个技能),任务完成后产生约 20MB 临时文件(readme_dsh_plugins.md、plugin-install\ 研究目录等),触发 auto-and-safety 清理流程。
| 阶段 | 事件 | 要点 |
|---|---|---|
| 任务执行 | 安装插件与技能,全程未触碰 .agents / .claude 目录 |
产生临时文件:1 个 94KB README + 安装研究目录(12 份文档 + 10 个 git 克隆) |
| ① 拦截 | agent 尝试直接清理临时文件 | 删除命令在 tools/pre-execute 被硬拦截,返回 Error 并提示正确流程 |
| ② 询问 | agent 改用 ask_user_question 列出待删文件(名称 + 完整路径 + 用途) |
但选择框点击不算批准——工具层未收到批准标记 |
| ③ 引导 | agent 说明规则,请用户在对话内文字明确批准 | "我不会绕开这个保护,请你直接回复确认" |
| ④ 批准 | 用户回复「批准删除」 | 命中批准短语(GRANT_RE),授权生效 |
| ⑤ 放行 | agent 重试删除命令 | 拦截器检测到最近用户消息含批准短语 → 放行 |
| ⑥ 完成 | 删除成功并验证 | 仅删除批准的两个对象,工作区其余文件未动 |
完整对话回放见 docs/拦截记录/session.jsonl(JSONL 格式,可用 DSH 会话查看器打开)。
9. 已知限制与边界
- shell 命令拦截无法穷举所有删除形态:正则覆盖常见删除命令(Remove-Item/rm/del/erase/rmdir/rd/unlink/shred/Empty-RecycleBin/.NET ::Delete),但理论上仍存在变体(脚本文件内部删除、编码混淆、外部程序调用等)。设计上"宁可误拦、不可漏放",且 prompt 规范 + 拦截双重约束,实际已覆盖 99% 场景。
- 一次批准放行窗口:拦截器以"最近一条用户消息是否含批准短语"为准,用户批准后到下一次用户消息之前的所有删除命令都会被放行。因此应引导 agent 一次性列出全部待删文件问清,避免逐文件多次询问。
- 子代理(subagent)会话:子代理会话默认走默认预设(
workspace-write),拦截不直接作用于子代理的 shell 调用;但父会话的 prompt 规范会传导,行为上仍受约束。 - 审批策略旋钮:预设的
approval: ask使会话审批策略为 ask;在danger-full-access下沙箱无升级需求,ask 主要保留审批通道与提示语义,不产生额外弹窗。 - HMR 依赖:配置热重载依赖 web 的 HMR 服务;极端情况下(插件文件损坏、配置 YAML 语法错误)会导致 loader 报错,此时重启 web 并按报错修复。
10. 卸载方法
- 从
cordis.patch.yml删除- id: auto-and-safety的insert条目(可保留permission行的 presets,去掉auto-and-safety一项即可恢复三预设)。 - 删除
plugins/auto-and-safety/目录。 - HMR 自动生效或重启 web。
11. 给 dsv4 / 后续整合者的说明
- 文件清单:
plugins/auto-and-safety/lib/index.js— 插件本体(唯一代码文件,零依赖)cordis.patch.yml— 配置补丁(预设表 + 插件挂载)README.md— 本文档docs/:需求.md(原始需求)、4 张演示截图、拦截记录/session.jsonl(演示会话回放)
- 整合最小改动:复制插件目录 + 合并两个 patch 条目,改改
description文案即可。 - 版本兼容:基于
@deepseek-ai/dsh0.1.0-rc.6。升级 DSH 后若权限体系接口变化(SANDBOX_MODES/APPROVAL_POLICIES/tools/pre-execute/permissionPresets.current()),按新源码调整。 - 可扩展方向:
- 把"批准短语"做成插件 Config(
z.object({...})),允许用户自定义放行词表; - 增加"删除前自动询问"(不 deny 而是转 ask_user_question)模式;
- 将拦截扩展到
run_code语言派发(如 Pythonos.remove)等更多删除形态。
- 把"批准短语"做成插件 Config(
Minglink/dsh-infinite-gen-4
howmp/dsh-pentest
SeaOf0/dsh-redteam-model
NanmiCoder/dsh-auto-mode
lire1131/dsh-undo-savepoint
dhicoc/dsh-reverse-skill