
OpenCode 集成指南用 dcg 插件为 OpenCode 的 bash 工具调用装上破坏性命令防护【免费下载链接】destructive_command_guardThe Destructive Command Guard (dcg) is for blocking dangerous git and shell commands from being executed by agents.项目地址: https://gitcode.com/GitHub_Trending/de/destructive_command_guard本文基于 Destructive Command Guarddcg仓库的 docs/opencode-integration.md 编写并结合仓库源码src/cli.rs、src/agent.rs、src/hook.rs、install.sh补充实现级细节。dcgDestructive Command Guard是一款面向 AI 编码 Agent 的破坏性命令拦截器用于阻止 Agent 执行危险的 git 与 shell 命令。OpenCode 不像 Claude Code、Codex 或 Gemini 那样暴露 PreToolUse 风格的钩子配置文件它的拦截面是一套插件系统。本文讲解 dcg 官方提供的 OpenCode 插件生成器dcg install --opencode的安装方式、插件工作原理、所有权与卸载机制、dcg doctor覆盖验证以及手工测试插件契约的方法帮助你为 OpenCode 会话的每一条 bash 工具调用建立与其它 Agent 一致的 fail-closed 防护。为什么 OpenCode 必须走插件而非钩子OpenCode 的拦截面是插件系统JavaScript/TypeScript 模块由 OpenCode 的 Bun 运行时从以下两个目录加载全局用户级~/.config/opencode/plugins/受XDG_CONFIG_HOME影响项目级仓库级.opencode/plugins/一个实现了tool.execute.before钩子的插件可以在每个工具调用执行之前检查它并通过抛出Error来否决该调用——这是 OpenCode 文档化的 veto否决机制。与 Grok 不同OpenCode没有任何 Claude 兼容层如果不安装插件它的 shell 命令永远不会经过 dcg防护完全不生效。这一点在 src/cli.rs 的 doctor 检查注释中有明确说明OpenCode has NO Claude compatibility layer: without the native plugin its shell calls never reach dcg, so a missing plugin is an error, not a nudge.安装一行命令生成官方插件dcg 自带 first-party 插件生成器通过dcg install的子命令触发src/cli.rs 定义了--opencode参数dcg install --opencode # 用户级~/.config/opencode/plugins/dcg-guard.js dcg install --opencode --project # 仓库级repo/.opencode/plugins/dcg-guard.js dcg install --opencode --force # 原地刷新 dcg 所有的插件升级后保持嵌入的二进制路径最新安装完成后必须重启 OpenCode开启新会话因为插件在启动时加载。安装器的行为细节从 install_opencode_plugin 的实现可以看到安装器的三个关键行为拒绝覆盖用户自有文件如果dcg-guard.js已存在但不含dcg-opencode-plugin标记安装器直接报错退出提示把文件移开或手动合并绝不覆盖属于你的插件。--force语义文件已存在且带标记时不带--force会提示 Plugin already installed! 并返回带--force才原地刷新保证升级 dcg 后插件内嵌的二进制路径仍然指向新版本。原子写入通过write_settings_atomic写文件避免半成品文件被 OpenCode 加载。路径解析规则插件路径由源码中的两个函数决定src/cli.rs用户级opencode_user_plugin_path()优先取$XDG_CONFIG_HOME/opencode/plugins/dcg-guard.js未设置时回退到~/.config/opencode/plugins/dcg-guard.js所有平台一致。项目级project_opencode_plugin_path()基于当前 git 仓库根目录拼接repo/.opencode/plugins/dcg-guard.js如果当前不在 git 仓库内会直接报错。install.sh 的自动配置当install.sh检测到${XDG_CONFIG_HOME:-~/.config}/opencode目录存在或opencode命令在PATH上时会自动调用configure_opencodeinstall.sh它用刚安装的 dcg 二进制执行dcg install --opencode --force并按结果记录状态——created新建、merged刷新已有 dcg 插件、conflict已有非 dcg 所有文件、failed二进制缺失等状态会呈现在安装摘要里。uninstall.sh则对称地移除带标记的插件文件。插件的工作原理生成出的dcg-guard.js是完整的tool.execute.before插件。源码 build_opencode_plugin_source 直接以字符串模板生成该文件其工作流程如下1. 只关注 bash 工具插件注册tool.execute.before处理器并忽略除bash之外的所有工具tool.execute.before: async (input, output) { if (!input || input.tool ! bash) return; const command output?.args?.command; if (typeof command ! string || command.length 0) return; ...2. 用绝对路径直连 dcg不查 PATH插件通过Bun.spawn直接拉起 dcg 二进制路径是安装时嵌入的绝对路径const DCG_BIN ...从不做裸PATH查找——因为 Agent 派生的进程经常运行在精简过的PATH环境下靠 PATH 找二进制很可能失败。路径以JSON 字符串字面量合法 JSON 字符串同时也是合法 JS 字符串嵌入而非 shell 引号形式因为插件是无 shell 直连spawn见 executable_javascript_literal 的注释说明。dcg 以 Claude 兼容的 hook envelope 通过 stdin 接收命令const proc Bun.spawn([process.env.DCG_BIN || DCG_BIN], { stdin: new TextEncoder().encode( JSON.stringify({ tool_name: Bash, tool_input: { command } }) ), stdout: pipe, stderr: ignore, env: { ...process.env, OPENCODE: 1 }, });环境变量OPENCODE1让 dcg 识别出调用方是 OpenCode。对应地src/agent.rs 的 Agent 检测逻辑在存在OPENCODE环境变量时返回Agent::OpenCodeconfig_key()为opencode随后可应用[agents.opencode]配置档的信任级别与规则覆盖。3. 解析 dcg stdout空输出放行deny/ask 否决插件对 dcg 输出的解释与其它 harness 完全一致stdout 为空 放行stdout 中的hookSpecificOutput.permissionDecision为deny或ask时抛出携带完整阻断信息的Error原因、规则 ID、allow-once 码、建议中止工具调用。由于 OpenCode没有 operator-review 状态没有像 Claude Code 那样的用户审批流程ask请求人工审核会fail closed——即视同拒绝而不是放行。这也是 src/hook.rs 中hookSpecificOutput/permissionDecision/permissionDecisionReason这一 Claude 兼容 JSON 契约的标准读法。插件对非 JSON 输出同样按其它 harness 的惯例处理视为放行。4. 基础设施错误才 fail open只有 dcg 二进制缺失或不可运行时基础设施错误插件才fail open并在 OpenCode 的 stderr 上打印[dcg]前缀的提示} catch (err) { // dcg missing or unrunnable is an infrastructure failure, not a // safety verdict: fail open, but say so. console.error([dcg] OpenCode guard could not run dcg: ${err}); return; }注意区分两个层次基础设施层面dcg 跑不起来fail open 并可见安全评估层面dcg 内部对命令的判定始终保持 dcg 有界的 fail-closed 语义。也就是说评估失败就当拒绝处理的兜底规则仍然生效。所有权标记与卸载安全生成的插件文件头部带有dcg-opencode-plugin标记注释源码常量 OPENCODE_PLUGIN_MARKER// dcg-opencode-plugin: generated by dcg install --opencode — do not edit.这一标记承担所有权判定职责安装器拒绝覆盖不带标记的dcg-guard.js那是你自己的文件不属于 dcguninstall.sh只删除带标记的文件绝不会误删用户自有的插件。源码中还实现了OpencodePluginProbe三态探测src/cli.rs进一步区分是否健康状态含义MissingOrUnowned文件不存在、不可读或不带标记Current带标记且与以插件自身内嵌路径重新生成的规范源码逐字节一致OwnedStale带标记但字节与规范源码不一致——被编辑、被 stub 掉、或由其它 dcg 版本生成关键在于有标记只证明文件归 dcg 所有不证明防护仍在工作。一个被手工编辑或 stub 掉的插件可以保留标记却不再把任何命令路由到 dcg所以 doctor 必须对比字节是否与规范源码一致而不是只看标记存在与否。校验时以插件自身嵌入的const DCG_BIN ...路径为准重新生成规范源码因此从其它位置合法安装的插件不会仅仅因为路径差异被误报。用 dcg doctor 验证覆盖dcg doctor在 OpenCode 似乎被使用时配置目录存在或存在OPENCODE*环境变量见 opencode_appears_in_use会包含opencode_plugin检查项。三种结果的处理src/cli.rsOKCurrent插件已注册且字节一致显示插件路径OUTDATED OR MODIFIEDOwnedStale插件被改过或被 stub 掉可能守而不护提示运行dcg install --opencode --force恢复NOT REGISTEREDMissingOrUnowned按 error 级别处理——再次强调与 Grok 不同OpenCode 没有 Claude 兼容层缺插件时其 shell 命令完全不会经过 dcg所以缺失即错误而不是提示。dcg doctor --fix会自动执行安装缺失时install_opencode_plugin(false, false)过期时install_opencode_plugin(true, false)并打印修复结果。同一检查也存在于collect_doctor_reportidopencode_plugin保证--strict与--format json两种输出口径一致。端到端的最终证明doctor 全绿只证明wiring接线正确不证明拦截真的生效。端到端的证明是一次真实的拒绝让一个 OpenCode 会话在临时仓库里执行一条被守卫的无害命令例如git reset --hard确认工具调用以BLOCKED by dcg中止并出现预期的规则 ID。手工测试插件契约不启动 OpenCode 也能验证插件与 dcg 之间的约定是否成立——直接把插件发送的 envelope 通过管道喂给 dcg# 插件发送与接收的内容 echo {tool_name:Bash,tool_input:{command:git reset --hard}} | dcg # → stdout 输出拒绝 JSON插件据此 throw中止调用 echo {tool_name:Bash,tool_input:{command:git status}} | dcg # → stdout 为空exit 0插件据此放行这套约定的依据是 dcg 的 hook 模式tool_name/tool_input.command的 snake_case Claude 兼容形状在 src/hook.rs 的 HookInput 结构中被解析阻断时按hookSpecificOutput.permissionDecisionpermissionDecisionReason的 JSON 契约输出src/hook.rs放行时 stdout 为空。这一空输出 允许的判读规则在其它 harnessClaude Code、Codex、Gemini、Copilot 等中完全一致插件只需复用同一套读法。限制与注意事项插件运行在 OpenCode 自己的运行时内。模型先把脚本写到磁盘、再在后续bash调用里执行它的情况仍然会被评估dcg 能看到那条调用但 dcg无法静态追踪的内容会像其它 harness 一样回退到它有界的 fail-closed 规则——这是所有 harness 共有的边界不是 OpenCode 特有。项目级安装--project要求仓库先被 OpenCode 信任插件才会加载这与 Grok 的/hooks-trust流程对称。插件路径依赖 git 仓库根project_opencode_plugin_path不在 git 仓库内无法安装项目级插件。插件在每次工具调用时都会用嵌入的绝对路径重新 spawn dcg因此移动或删除 dcg 二进制会产生可见的基础设施失败fail open stderr 提示而路径处的字节被替换则会影响后续回调执行的逻辑——保护 dcg 二进制及其父目录免受不可信写入者的影响是保证防护不被架空的前提。安装或刷新插件后必须重启 OpenCode 会话插件只在启动时加载。小结OpenCode 的防护完全依赖插件系统dcg install --opencode生成一个带所有权标记的tool.execute.before插件它把每条bash工具调用以 Claude 兼容 envelope 交给嵌入绝对路径的 dcg 二进制按空 stdout 放行、deny/ask 否决、基础设施错误才 fail open的契约执行拦截dcg doctor负责验证插件的存在与字节级健康dcg doctor --fix可一键修复。对照源码src/cli.rs 的生成/探测逻辑、src/agent.rs 的OPENCODE1检测、install.sh 的自动配置可以确认这套集成为 OpenCode 提供了与其它 Agent 一致的 fail-closed 安全评估只是接线面换成了 OpenCode 唯一支持的插件机制。【免费下载链接】destructive_command_guardThe Destructive Command Guard (dcg) is for blocking dangerous git and shell commands from being executed by agents.项目地址: https://gitcode.com/GitHub_Trending/de/destructive_command_guard创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考