cc-safety-net/api 子路径导出的 checkCommand。类型、抛出的 TypeError 消息,以及一次调用会读取什么,都由库 API 作为签名参考承载。这一页讲的是围绕它的决策。
进程内检查还是安装 hook
两条路径走的是同一个 guard,区别在于由谁持有这次调用。
判断依据可以从最后一行推出来,但本质是归属问题。如果你的用户运行的是受支持的智能体 CLI,把安装命令给他们,让集成去做这件事;各智能体的接入方式见集成架构。如果你本身就是执行命令的程序,那就调用这个函数。为自己的运行时再造一套 hook 配置生成器,等于重建一个已经存在的集成。
包的根导出是 OpenCode 插件对象,不是引擎。
checkCommand 请从 cc-safety-net/api 导入。嵌入模式下的策略解析
嵌入模式没有单独的配置。一次调用读取的文件和 hook 读取的完全相同,而读哪个项目的文件由cwd 参数决定。
- 用户范围。
~/.cc-safety-net/policy.json和~/.cc-safety-net/rules/;设置了CC_SAFETY_NET_HOME时改到该位置。这是运维者自己的基线,对每次调用都生效。 - 项目范围。
<cwd>/.cc-safety-net/policy.json和<cwd>/.cc-safety-net/rules/,严格按你传入的路径解析,不会向上遍历父目录。跟踪会话子目录的宿主应当把仓库根目录作为cwd传入,否则提交到仓库的项目策略不会被加载。 - **合并。**项目文件按字段叠加在用户文件之上。两个范围的受保护路径列表取并集,项目文件里的
audit会被忽略,项目放宽的每个字段都会被报告而不是无声生效。合并契约由策略承载。 - 环境变量。
CC_SAFETY_NET_LEVEL和各能力开关在每次调用时从process.env读取,而且级别只能高于策略文件的设定。见环境变量。
cwd。同时管理多个检出的宿主,只要传对目录,每个检出就会拿到正确的策略,不需要额外 API。
动手写调用点之前,有两个行为值得先知道。无法 stat 为可读、可搜索目录的 cwd 会返回 fail-closed 的 deny,而不是抛异常,所以路径写错会导致命令被阻止,而不是去解析另一个项目。另外,输入本身不合法时(比如缺少 cwd,或 command 不是字符串)会抛出 TypeError,那是调用方代码的缺陷,不是对命令的判定。
API 保证什么
以下几点跨小版本保持不变,宿主可以据此构建:- 输入形状
{ command, cwd }(cwd是绝对目录路径),以及两种结果 kind:allow,和带reason字符串与可选ruleId的deny。 deny表示不要执行该命令,抛异常同样如此。抛异常永远不等于 allow。cwd是策略解析的基准。命令里的相对路径目标和项目的.cc-safety-net/配置都按你传入的cwd解析,绝不会用process.cwd()。- API 路径不写审计记录,也不发起网络请求。一次调用读取的是本地策略文件、文件系统状态和环境设置;没有任何内容离开这台机器。
reason 的措辞也随之改变,所以一次升级可能把你测试夹具依赖的某条命令从 allow 变成 deny。请按 kind 分支。把 reason 和 ruleId 留给人和日志,而不是拿来做匹配;并像对待任何行为被你测试覆盖的依赖一样,在 lockfile 里锁定版本。
完整示例:插件宿主
采用插件架构的宿主通常会暴露一个执行前的 hook,可以在那里否决一次工具调用。集成点就只有这一处。插件把宿主的事件映射成{ command, cwd },调用 checkCommand,再把 deny 转换成宿主自己的否决形式:
- 只检查命令类工具。
checkCommand解析的是 shell 命令文本。宿主的 read、write、search 等工具不是命令类工具,所以只把 shell 工具路由过来,其余照常放行。 - **
cwd是绝对路径的项目根目录。**无论宿主怎么称呼它,这个值都决定选用哪份项目策略,并作为命令中.env之类相对路径的基准。 - 抛异常就阻止。
catch是契约里 fail-closed 的那一半。让抛出的错误继续流向执行的宿主,等于把一次失败的检查变成了放行。 - **事件不合法也要阻止。**随包发布的进程内集成正是这么做的:command 字段缺失或不是字符串的事件会被阻止,而不是跳过,因为没有任何可供分析的内容。
运维须知
- **日志归你自己管。**这条路径不写审计记录,所以宿主不记录的拒绝就不会留下任何痕迹。
logs命令和 GUI 面板展示的是 hook 与插件的判定,不包含嵌入调用。 - **运维者仍用常规工具配置你。**嵌入宿主读取的是同一批策略文件,因此
status、doctor和explain描述的就是你的宿主会做什么,前提是它们运行在你作为cwd传入的同一个目录里。用户问某条命令为什么被阻止时,指给他们Explain 跟踪。 - **
ruleId仅用于诊断。**打印它、记录它、用它去查规则都可以,但不要拿它做分支条件。 - **调用是同步的。**要批量处理就用循环。这里没有异步或批量入口,加一个也只是掩盖调用本就会做的文件读取。
- 版本可以从包里读。
cc-safety-net/package.json是导出的子路径,会报告自身依赖版本的宿主可以把它一并带上。