npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

opencode-approval-guard

v1.1.1

Published

OpenCode smart command approval plugin with deterministic rules, optional risk scanning, and an AI SDK reviewer.

Readme

opencode-approval-guard

License: MIT

独立 fork:派生自上游 blanboom/opencode-smart-approvalv0.5.0,由 XYRen-FXTech 维护。本项目已与上游完全分离,以独立名称发布。与上游 v0.5.0 的差异:

  • 审查日志:每次审查以 JSONL 记录(含错误码与脱敏原始输出),用于失败诊断。
  • 审查器无工具:审查请求不再提供只读工具——模型必须输出单行紧凑 JSON,消除了工具调用导致的空输出失败并加快审查。
  • 更严格的 JSON 契约:3000 token 输出预算、具体 schema 示例、按失败类型定向的重试提示。
  • Question 回复进上下文:通过 question 工具获得的人工回复会纳入审查 transcript。
  • Agent 显式上下文文件:bash 工具的 context_files 参数可把任意脚本内容喂给审查器。
  • review.max_tool_calls 仅为兼容旧配置而接受,实际被忽略。上游 v0.6.x 系列不兼容 Windows(其 anchored-fs 层仅支持 POSIX);本项目保留 Windows 可用的 v0.5.0 架构。

OpenCode 的 Shell 命令智能审批插件。通过 Tirith、Tree-sitter Shell 分析、确定性规则和失败封闭的 LLM 审查,在不降低安全性的前提下减少审批成本。

OpenCode 不提供命令沙盒。本插件把个人信任决策留给显式用户规则,只提供极小的通用内置快速路径,并在上下文 LLM 审查前交由 Tirith 判断风险。

工作原理

每条 shell 命令(bashshellexec_command 等)经过以下管线:

配置自我保护 → 用户规则 → 内置规则 → Tirith → LLM

| 阶段 | 行为 | |------|------| | 配置自我保护 | 在常规审批前,拒绝 Shell 写入以及 OpenCode Write/Edit/apply_patch 对当前全局或项目策略文件的编辑。默认开启,可配置关闭。 | | 用户规则 | 优先级最高。完整 allow 或 deny 立即终止,不执行任何后续阶段。Tree-sitter 提取静态可执行段,管道一侧不能替另一侧授权。 | | 内置规则 | 只为常见低风险命令提供少量 allow/deny 快速路径,不维护平台专属风险目录。 | | Tirith | 确定性规则未决时扫描完整、未拆分的原始命令。block 为最终结果;allow/warn 继续交给 LLM,warn 会作为证据附带。 | | LLM 审查 | 最终上下文判断,使用完整命令、扫描结果和对话上下文(含 Question 回复)。失败封闭。 |

用户规则阶段中,同一命令段先取最高整数 priority,同优先级按 deny > review > allow 决策;不同命令段也按同样顺序聚合。管道或列表只有每个静态可执行段都被允许时才短路。任一段命中用户 deny 会拒绝整条命令;部分 allow、未匹配或显式 review 会继续进入 Tirith 和 LLM。

前置条件:bash 权限放行

OpenCode 必须允许 bash 工具,命令才能到达本插件。在 ~/.config/opencode/opencode.json 中:

{
  "permission": { "bash": "allow" },
  "plugin": ["opencode-approval-guard"]
}

插件通过 tool.execute.before 钩子拦截——只有在 OpenCode 本来会执行命令时才触发。如果 bash 设为 denyask,插件没有机会审查。

安装

本项目未发布到 npm,与上游 npm 包无关联。请在任何机器上从源码部署:

  1. 克隆仓库并切换到 main 分支:
    git clone [email protected]:XYRen-FXTech/opencode-approval-guard.git
    cd opencode-approval-guard
    git checkout main
    npm install
  2. ~/.config/opencode/opencode.json 中把插件指向本地入口:
    {
      "permission": { "bash": "allow" },
      "plugin": ["F:/path/to/opencode-approval-guard/src/index.ts"]
    }
    路径可使用绝对路径(如上)或 file:// URL;插件条目内不展开 ~
  3. 创建 ~/.config/opencode/approval-guard.jsonc 并配置审查端点(见 配置)。
  4. 重启 OpenCode。通过检查 ~/.local/share/opencode/log/approval-guard-YYYYMMDD.log 中是否有 policy_load 记录来确认插件已加载。

本项目保留 MIT 许可;上游署名见 LICENSE

配置

插件将全局配置作为可信策略边界:

  1. 全局~/.config/opencode/approval-guard.jsonc(或 $XDG_CONFIG_HOME/opencode/)。首次运行时如不存在则自动生成默认配置。
  2. 本地 — 项目目录下的 ./approval-guard.jsonc。项目文件可能不可信,因此默认忽略。只有全局文件显式设置 "allow_local_config": true 时,它才会替代全局配置。

创建全局配置(支持 JSONC 注释):

{
  "version": 2,
  "allow_local_config": false,
  "self_protection": { "enabled": true },
  "review": {
    "base_url": "https://api.openai.com/v1",
    "api_key": "sk-...",
    "model": "gpt-4o-mini",
    "timeout_ms": 45000,
    "max_script_bytes": 20000,
    "max_tool_calls": 3,
    "max_retries": 3,
    "context_messages": 20,
    "log_dir": "",
    "debug": false,
    "enable_context_files": true,
    "expose_context_files": true,
    "max_context_file_count": 8,
    "max_context_file_bytes": 32768,
    "max_context_total_bytes": 65536
    // "prompt": "..."  // 覆盖默认审查策略
  },
  "tirith": {
    "enabled": true,
    "timeout_ms": 5000,
    "fail_open": false
  },
  "rules": {
    "deny": [],
    "review": [
      { "match": "^deploy(?:\\s|$).*", "scope": "segment", "priority": 50 }
    ],
    "allow": [
      {
        "match": "^my-read-only-tool(?:\\s|$).*",
        "scope": "segment",
        "priority": 100,
        "reason": "可信的个人检查工具"
      }
    ]
  }
}

文件不存在时插件首次运行自动生成默认配置。review 端点独立配置——插件不读取 OpenCode 自身的模型/认证配置。

选项

| 选项 | 默认值 | 说明 | |------|--------|------| | version | 2 | 用于生成策略迁移的配置格式标记;只接受版本 1 和 2。 | | allow_local_config | false | 允许项目本地配置完整替代全局策略。只从可信全局文件读取。 | | self_protection.enabled | true | 拒绝 Shell 和 OpenCode 文件工具编辑当前审批配置。动态 Shell 输出路径因无法证明目标安全而失败封闭;可在可信策略中设为 false 关闭。 | | review.base_url | — | OpenAI 兼容端点 URL。必填。 | | review.api_key | — | API 密钥。必填。 | | review.model | — | 模型名。必填。 | | review.timeout_ms | 45000 | LLM 审查超时(5000–300000)。 | | review.max_script_bytes | 20000 | 发送给审查器的脚本最大字节数。 | | review.max_tool_calls | 3 | 已忽略(遗留)——审查器不再暴露工具。仅为兼容旧配置而接受。 | | review.max_retries | 3 | 每次请求的 LLM API 传输重试上限(0–10 整数)。正值还允许在结构化输出畸形后重新发起一次请求;0 同时禁用两类重试。 | | review.context_messages | 20 | 注入为对话上下文的近期会话消息数(0–100,0 禁用)。 | | review.prompt | 内置 | 覆盖审查策略文本。详见 LLM 审查。 | | review.log_dir | ""(自动) | JSONL 审查日志目录。留空 = ~/.local/share/opencode/log。详见 审查日志。 | | review.debug | false | true = 在日志中记录脱敏后的完整 LLM 原始输出(默认仅前 500 字符)。 | | review.enable_context_files | true | Agent context_files 参数的总开关(参数解析与 schema 注入)。 | | review.expose_context_files | true | 仅控制是否向 Agent 的工具 schema 注入 context_files 参数定义。 | | review.max_context_file_count | 8 | 每条命令最多读取的显式上下文文件数(整数 0–64)。 | | review.max_context_file_bytes | 32768 | 单个显式文件的摘录字节预算(0–200000)。 | | review.max_context_total_bytes | 65536 | 所有显式文件的累计内容预算(0–500000)。 | | tirith.enabled | true | 启用 Tirith 扫描。 | | tirith.path | 自动 | 本地二进制路径。跳过自动下载。 | | tirith.timeout_ms | 5000 | 每条命令的扫描超时。 | | tirith.fail_open | false | true = 扫描失败时放行。 | | rules.deny | [] | 用户拒绝规则,在内置规则、Tirith 和 LLM 前终止。 | | rules.block | [] | rules.deny 的旧版兼容别名。 | | rules.review | [] | 需要扫描器和最终 LLM 判断的用户规则。 | | rules.allow | [] | 用户放行规则;完整匹配会跳过内置规则、Tirith 和 LLM。 |

规则

规则可以是正则字符串,也可以是带 match、可选 reasonscopepriority 的对象。旧字符串和旧对象继续按 scope: "command"priority: 0 兼容;新的管道友好规则应使用 scope: "segment"

加载无版本或 version 1 配置时,插件只忽略 v2 之前自动写入的六条精确紧凑字符串 allow 模式,避免过时的宽泛包脚本、构建和测试授权在升级后继续生效。自定义对象和修改过的模式都会保留。如果确实需要其中某条旧 allow,请设置 version: 2,并将其改写为带明确 scope: "segment" 和有意设置的 priority 的规则。

未知的未来配置版本会直接拒绝加载,不会按旧版本语义猜测解释。

"deny": [
  // 旧简洁写法:整条命令、优先级 0
  "^(?:printenv|set)(?:\\s|$).*",

  // 显式写法
  { "match": "^dangerous-tool(?:\\s|$).*", "scope": "segment", "priority": 100 }
],
"review": [
  { "match": "^deploy(?:\\s|$).*", "scope": "segment", "priority": 50 }
],
"allow": [
  { "match": "^my-reader(?:\\s|$).*", "scope": "segment", "priority": 100 }
]

各类型适用场景:

  • deny — 绝不允许执行的命令。立即拒绝,不产生扫描器或 LLM 成本;block 保留为兼容别名。
  • review — 需要上下文判断的命令,会继续经过 Tirith 和 LLM。
  • allow — 按模式显式信任的命令;完整匹配会跳过所有后续阶段。

scope: "segment" 匹配解析后的精确可执行段,因此 my-reader | grep value 只有在两段都放行时才能整体放行。整命令作用域的 allow 仅在命令只有一个静态可执行节点时生效;整命令 block/review 仍可升级复合命令。

分段规则匹配前会规范化静态可执行文件的引号、转义及拼接写法。引号内容保持为字面数据;管道和列表会拆成可执行段;静态嵌套 Shell 会递归分析。重定向、命令替换、后台执行、不支持的控制结构、畸形输入和资源上限超限都会阻止内置 allow 短路。解析器、运行时或资产初始化失败会直接失败封闭阻断。

用户规则对完整静态命令保持最高优先级。对于管道和列表,只有每个可执行兄弟段都被用户显式允许时才会跳过后续阶段。

LLM 审查

审查器接收:命令、工作目录、工具参数、匹配规则、Tirith 发现、脚本证据(自动检测与 Agent 显式提供)、近期对话上下文。返回结构化裁决(outcomerisk_leveluser_authorizationcategoriesreasons)。

审查器不带任何工具调用:模型必须输出单行紧凑 JSON 对象,从而消除"模型把步数预算耗在工具调用上、最终没有产出文本"的失败模式。畸形或不符合 schema 的输出在启用重试时触发一次定向格式修正重试(重试提示词按失败原因区分:截断/畸形 JSON 与 schema 不匹配)。空响应(API 端暂时性故障)会先等待 8 秒退避再重试,以便跨越故障窗口;第二次仍无效,或禁用重试时首次就无效,都会失败封闭。输出 token 预算为 3000。

遗留说明:本 fork 已移除 review.max_tool_callsread_file/list_files 工具。该配置键仅为兼容旧配置而接受,实际被忽略。

对话上下文

插件通过 OpenCode SDK client(session.messages)获取当前会话的近期消息,提取文本和工具调用摘要,注入为对话上下文。这为审查器提供了用户意图和授权信息——对齐 Codex guardian 模型。设 review.context_messages 为 0 可禁用。

用户的明确表态(如"可以,你推吧")作为用户文本始终包含在上下文中。通过 question 工具获得的人工回复("User has answered your questions: ..." 输出)也会包含——人工回复是最高优先级的授权证据。其他工具输出(bash 结果、文件读取)仍只保留 [tool: name (status)] 摘要,防止命令输出污染审查证据。

自定义 prompt

默认审查策略涵盖证据处理、用户授权评分、风险分级、调查指南、裁决策略。通过 review.prompt 可覆盖——提供完整策略文本,插件替换内置策略。JSON 数据(命令、规则、对话上下文等)始终附加在自定义策略之后。

拒绝反馈

审查器拒绝时,reasons 通过 CommandApprovalError 传回 OpenCode——AI agent 看到拒绝原因,可以选择更安全的替代方案或向用户请求明确授权。

当审查器拒绝的命令涉及脚本但没有任何可审阅的文件证据时,拒绝原因中会附带提示,建议使用 context_files 参数(见下)。

Agent 显式上下文参数(context_files

Agent 可以在 bash 工具调用中传一个可选的 context_files 参数(字符串或字面路径数组)。插件读取这些文件并把内容并入审查证据(script_evidencesource: "explicit"),使 LLM 审查器可以评估任何类型的脚本——包括自动检测不认识的解释器场景(如 python train.pynode app.js)。

  • 文件绝不会被执行;该参数只服务于审批审查器。opencode 在命令执行前会剥除该参数。
  • 相对路径优先按 workdir 参数解析,否则按项目目录解析;支持 ~/ 展开。只接受字面路径——无 glob、无 shell 反转义、无逗号/括号处理。
  • 仅接受项目目录与系统临时目录内的正则文件。敏感路径(.env.ssh、审批配置自身等)与符号链接逃逸会被排除。
  • 单文件摘录预算默认 32 KiB,超限按行对齐 head+tail 截断并插入 ... [truncated: skipped N of M bytes] ... 标记;超过 1 MiB 的文件完全排除;二进制文件(无 BOM 且 NUL 密集)排除;UTF-16 与 UTF-8 BOM 文件正确解码。
  • 显式文件内容总预算默认 64 KiB,按声明顺序消耗;每条命令最多读取 8 个文件。
  • 文件无法审阅时命令照常进入审查——审查器看到带排除原因的 path-only 条目,可选择保守拒绝。
  • review.enable_context_files 是总开关(默认 true);review.expose_context_files 只控制是否把参数注入 Agent 看到的工具 schema(默认 true)。schema 注入以 tool_schema_inject 事件记入日志。

审查日志

每次审查尝试都会向 ~/.local/share/opencode/log/approval-guard-YYYYMMDD.log 追加一条 JSONL 记录(可通过 review.log_dir 配置)。审查失败消息内嵌结构化错误码,可立即确认根因:

| 错误码 | 含义 | |--------|------| | empty_output | 模型未返回文本(API 暂时性故障;8 秒退避后重试) | | parse_error | 原始输出无法解析为 JSON | | zod_error | JSON 解析成功但不符合裁决 schema | | timeout | 被 review.timeout_ms 中止 | | api_error | 传输/API 失败 | | unknown | 未知失败 |

每条记录包含:时间戳、会话 ID、工具、命令、模型、尝试次数、总尝试次数、耗时、prompt 大小、原始输出大小、脱敏输出预览、错误码/消息、退避时长(空输出重试时)、以及成功时的裁决原因。Agent 提供了 context_files 时,记录还包含请求的文件路径与被忽略的路径数。原始输出预览默认截断至 500 字符;设置 review.debug: true 记录至多 32K 字符。仅配置的 review.api_key 字面量会在所有字段中被脱敏;命令与 transcript 回显按原样记录,日志文件应视为敏感数据。日志文件与目录以 0600/0700 权限创建。

内置规则

内置规则刻意保持精简且与平台无关:

  • Allow: 基本 Shell 胶水命令(echoprintftruefalsetest)、基本位置/目录查看(lspwdbasenamedirname)和 command -v
  • Deny: 当前为空。风险分类交给 Tirith,不在正则目录中重复实现。

内置 allow 不覆盖输出重定向,复合命令仍要求每个可执行段都匹配。git push、包发布、项目构建、解释器、文件写入及平台专属开发工具默认保持未匹配,并进入 Tirith 和 LLM;用户可为可信命令添加显式规则。

Tirith

Tirith 是用 Rust 编写的终端安全扫描器,负责捕获精简内置规则不应重复覆盖的风险:西里尔字母同形字 URL、ANSI 转义注入、base64 解码执行链、通过 curl 上传的凭证外泄、管道脚本中的混淆载荷和不可见 Unicode 隐写。

自动下载

未设置 tirith.path 时,插件首次使用自动下载适合当前平台的最新发布版本,校验上游 SHA-256,并连同发布版本、压缩包摘要、二进制摘要和新鲜度元数据缓存到用户缓存目录。复用缓存时先校验本地二进制,并在 24 小时后刷新上游发布与 checksum;发现新版本或摘要变化时原子安装。HTTP 响应体、重定向次数、总耗时、压缩包大小、条目边界、解压后大小和二进制大小均有上限。平台不支持或发布资产缺失时,与扫描器执行失败一样按 tirith.fail_open 决策。

| 平台 | 支持 | |------|------| | macOS arm64 / x64 | ✅ | | Linux glibc arm64 / x64 | ✅ | | Linux musl arm64 | ✅ | | Windows x64 | ✅ |

隐私

  • 审查器可见:命令、工作目录、工具参数、匹配规则、Tirith 发现、引用的脚本内容、近期会话对话上下文(含 Question 回复)。
  • 脚本证据覆盖 sh/bash/zsh/pwsh/powershell 调用(含 -File/-f 参数)以及 .sh/.ps1/.cmd/.bat 文件,支持 Windows 绝对路径。超长脚本按行对齐 head+tail 截断并带截断标记;二进制文件被排除。
  • context_files 扩展了上述范围:项目内任何被点名的文件都会被读取(按预算截断)并发送到审查端点,不限扩展名,即使它从未出现在命令中。敏感路径 denylist 是尽力而为,不构成保密承诺。请把审查端点视为不完全可信,不要在 context_files 中引用含密钥的文件。
  • 脚本证据会先规范化,再限制在 cwd 与系统临时目录内;敏感路径和符号链接逃逸会被拒绝。
  • 插件不创建 OpenCode 会话,不调用 opencode run

开发

cd opencode-approval-guard
bun install
bun run typecheck
bun test

参考项目

  • OpenCode — 本插件扩展的开源编码 Agent。提供 tool.execute.before 钩子和 permission 模型,使命令拦截无需修改核心代码即可实现。
  • OpenGuardrails Instrumentation for OpenCode — 采用 OGR 协议的同类 guardrails 插件。同样使用 tool.execute.before 插桩模式,支持文本/正则规则和可选 LLM judge;本项目采用了不同路线,集成了 Tirith 并构建了分阶段的解析与策略管线。
  • OpenAI Codex CLI — OpenAI 的终端编码 Agent。其沙箱自动审批模型启发了本插件的失败封闭默认值、只读工具设计,以及基于对话上下文的证据驱动审批。
  • Dyad — 本地开源 AI 应用构建器。其权限钩子和策略配置模式影响了本插件的 JSONC 配置设计以及确定性规则与上下文审查的分离。
  • Hermes Agent — Nous Research 的自我改进 AI Agent。其内置 Tirith 集成(自动安装、checksum 校验、断路器 fail-open 逻辑)直接启发了本插件的 Tirith 自动下载和失败封闭行为。
  • Tirith — 在用户规则和内置规则未决后运行的终端安全扫描器,在命令执行前拦截同形字 URL、管道注入、ANSI 注入、混淆载荷、凭证外泄和恶意 AI 技能文件。

许可

MIT