failproofai 0.0.6-beta.1 → 0.0.6-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/standalone/.failproofai/policies/review-policies.mjs +4 -3
- package/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/build-manifest.json +3 -3
- package/.next/standalone/.next/prerender-manifest.json +3 -3
- package/.next/standalone/.next/required-server-files.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_global-error.html +1 -1
- package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
- package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
- package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_not-found.html +2 -2
- package/.next/standalone/.next/server/app/_not-found.rsc +15 -15
- package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +15 -15
- package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +10 -10
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/index.html +1 -1
- package/.next/standalone/.next/server/app/index.rsc +15 -15
- package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +15 -15
- package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +10 -10
- package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +8 -8
- package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0g72weg._.js +1 -1
- package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_0z7w.hh._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0~kmh8w._.js → [root-of-the-server]__05akje6._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__092s1ta._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__09icjsf._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0g.lg8b._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0h..k-e._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0rh.18_._.js → [root-of-the-server]__0i5kvry._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0okos0k._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0w6l33k._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__11pa2ra._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__12t-wym._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/_10lm7or._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_0xerkr6._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_0q-m0y-._.js +1 -1
- package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
- package/.next/standalone/.next/server/pages/404.html +2 -2
- package/.next/standalone/.next/server/pages/500.html +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.json +9 -9
- package/.next/standalone/.next/static/chunks/{08t08igdql9yt.js → 00j0rr7rh8ef8.js} +1 -1
- package/.next/standalone/.next/static/chunks/{12~yi9oj8av8p.js → 05j1px0r8yzh6.js} +2 -2
- package/.next/standalone/.next/static/chunks/{09_k80d~cq2wg.js → 0badv41uxa56..js} +1 -1
- package/.next/standalone/.next/static/chunks/{0wlyoif4_kj_t.js → 0ijk_kek9_wyx.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0bvhsa6zva2o..js → 0ksdlt_1hucdm.js} +1 -1
- package/.next/standalone/.next/static/chunks/{03rz6ykw-a2xi.js → 0npb~873.wvg3.js} +1 -1
- package/.next/standalone/.next/static/chunks/{01b~z8f1ws0rk.js → 0xpl.oscrakvx.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0gbf4cphy8ksq.js → 1052sguyd-.ka.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0v.yd0kg_ld3r.js → 14cl9poem30dq.js} +1 -1
- package/.next/standalone/CHANGELOG.md +11 -0
- package/.next/standalone/dist/cli.mjs +3 -3
- package/.next/standalone/docs/ar/built-in-policies.mdx +124 -87
- package/.next/standalone/docs/ar/custom-policies.mdx +72 -72
- package/.next/standalone/docs/ar/examples.mdx +86 -33
- package/.next/standalone/docs/ar/getting-started.mdx +82 -29
- package/.next/standalone/docs/built-in-policies.mdx +1 -1
- package/.next/standalone/docs/de/built-in-policies.mdx +93 -56
- package/.next/standalone/docs/de/custom-policies.mdx +56 -56
- package/.next/standalone/docs/de/examples.mdx +72 -18
- package/.next/standalone/docs/de/getting-started.mdx +72 -20
- package/.next/standalone/docs/es/built-in-policies.mdx +115 -78
- package/.next/standalone/docs/es/custom-policies.mdx +55 -55
- package/.next/standalone/docs/es/examples.mdx +73 -19
- package/.next/standalone/docs/es/getting-started.mdx +72 -20
- package/.next/standalone/docs/fr/built-in-policies.mdx +83 -46
- package/.next/standalone/docs/fr/custom-policies.mdx +51 -51
- package/.next/standalone/docs/fr/examples.mdx +78 -24
- package/.next/standalone/docs/fr/getting-started.mdx +65 -13
- package/.next/standalone/docs/he/built-in-policies.mdx +156 -117
- package/.next/standalone/docs/he/custom-policies.mdx +75 -75
- package/.next/standalone/docs/he/examples.mdx +87 -33
- package/.next/standalone/docs/he/getting-started.mdx +84 -33
- package/.next/standalone/docs/hi/built-in-policies.mdx +101 -60
- package/.next/standalone/docs/hi/custom-policies.mdx +71 -70
- package/.next/standalone/docs/hi/examples.mdx +90 -36
- package/.next/standalone/docs/hi/getting-started.mdx +80 -27
- package/.next/standalone/docs/i18n/README.ar.md +69 -69
- package/.next/standalone/docs/i18n/README.de.md +46 -46
- package/.next/standalone/docs/i18n/README.es.md +42 -42
- package/.next/standalone/docs/i18n/README.fr.md +39 -39
- package/.next/standalone/docs/i18n/README.he.md +83 -83
- package/.next/standalone/docs/i18n/README.hi.md +69 -69
- package/.next/standalone/docs/i18n/README.it.md +72 -72
- package/.next/standalone/docs/i18n/README.ja.md +71 -71
- package/.next/standalone/docs/i18n/README.ko.md +52 -52
- package/.next/standalone/docs/i18n/README.pt-br.md +44 -44
- package/.next/standalone/docs/i18n/README.ru.md +66 -66
- package/.next/standalone/docs/i18n/README.tr.md +82 -83
- package/.next/standalone/docs/i18n/README.vi.md +70 -71
- package/.next/standalone/docs/i18n/README.zh.md +51 -51
- package/.next/standalone/docs/it/built-in-policies.mdx +118 -81
- package/.next/standalone/docs/it/custom-policies.mdx +69 -69
- package/.next/standalone/docs/it/examples.mdx +93 -39
- package/.next/standalone/docs/it/getting-started.mdx +73 -21
- package/.next/standalone/docs/ja/built-in-policies.mdx +98 -61
- package/.next/standalone/docs/ja/custom-policies.mdx +71 -71
- package/.next/standalone/docs/ja/examples.mdx +76 -22
- package/.next/standalone/docs/ja/getting-started.mdx +65 -13
- package/.next/standalone/docs/ko/built-in-policies.mdx +137 -100
- package/.next/standalone/docs/ko/custom-policies.mdx +67 -67
- package/.next/standalone/docs/ko/examples.mdx +87 -33
- package/.next/standalone/docs/ko/getting-started.mdx +61 -9
- package/.next/standalone/docs/pt-br/built-in-policies.mdx +94 -57
- package/.next/standalone/docs/pt-br/custom-policies.mdx +56 -56
- package/.next/standalone/docs/pt-br/examples.mdx +78 -24
- package/.next/standalone/docs/pt-br/getting-started.mdx +64 -12
- package/.next/standalone/docs/ru/built-in-policies.mdx +142 -105
- package/.next/standalone/docs/ru/custom-policies.mdx +82 -81
- package/.next/standalone/docs/ru/examples.mdx +77 -22
- package/.next/standalone/docs/ru/getting-started.mdx +74 -22
- package/.next/standalone/docs/tr/built-in-policies.mdx +104 -67
- package/.next/standalone/docs/tr/custom-policies.mdx +59 -60
- package/.next/standalone/docs/tr/examples.mdx +97 -42
- package/.next/standalone/docs/tr/getting-started.mdx +75 -23
- package/.next/standalone/docs/vi/built-in-policies.mdx +110 -72
- package/.next/standalone/docs/vi/custom-policies.mdx +68 -68
- package/.next/standalone/docs/vi/examples.mdx +93 -38
- package/.next/standalone/docs/vi/getting-started.mdx +74 -22
- package/.next/standalone/docs/zh/built-in-policies.mdx +132 -95
- package/.next/standalone/docs/zh/custom-policies.mdx +49 -49
- package/.next/standalone/docs/zh/examples.mdx +90 -36
- package/.next/standalone/docs/zh/getting-started.mdx +73 -21
- package/.next/standalone/package.json +1 -1
- package/.next/standalone/server.js +1 -1
- package/.next/standalone/src/hooks/builtin-policies.ts +5 -1
- package/dist/cli.mjs +3 -3
- package/package.json +1 -1
- package/src/hooks/builtin-policies.ts +5 -1
- /package/.next/standalone/.next/static/{CkmOT-ZvDN-sVULinGVKT → A9pNTZdoYJTVyPAYwQMx5}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{CkmOT-ZvDN-sVULinGVKT → A9pNTZdoYJTVyPAYwQMx5}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{CkmOT-ZvDN-sVULinGVKT → A9pNTZdoYJTVyPAYwQMx5}/_ssgManifest.js +0 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: 自定义策略
|
|
3
|
-
description: "用 JavaScript
|
|
3
|
+
description: "用 JavaScript 编写自定义策略——强制执行项目规范、防止偏离、检测失败、与外部系统集成"
|
|
4
4
|
icon: code
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
自定义策略允许你为任何 Agent 行为编写规则:强制执行项目规范、防止偏离、限制危险操作、检测卡住的 Agent,或与 Slack、审批工作流等进行集成。它们使用与内置策略相同的 Hook 事件系统和 `allow`、`deny`、`instruct` 决策机制。
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
|
|
@@ -41,32 +41,32 @@ failproofai policies --install --custom ./my-policies.js
|
|
|
41
41
|
|
|
42
42
|
### 方式一:基于约定(推荐)
|
|
43
43
|
|
|
44
|
-
将 `*policies.{js,mjs,ts}` 文件放入 `.failproofai/policies/`
|
|
44
|
+
将 `*policies.{js,mjs,ts}` 文件放入 `.failproofai/policies/` 目录,它们会被自动加载——无需任何参数或配置变更。这与 git hooks 的工作方式类似:放入文件即可生效。
|
|
45
45
|
|
|
46
46
|
```
|
|
47
47
|
# 项目级别——提交到 git,与团队共享
|
|
48
48
|
.failproofai/policies/security-policies.mjs
|
|
49
49
|
.failproofai/policies/workflow-policies.mjs
|
|
50
50
|
|
|
51
|
-
#
|
|
51
|
+
# 用户级别——个人配置,适用于所有项目
|
|
52
52
|
~/.failproofai/policies/my-policies.mjs
|
|
53
53
|
```
|
|
54
54
|
|
|
55
55
|
**工作原理:**
|
|
56
|
-
-
|
|
57
|
-
-
|
|
58
|
-
- 只加载匹配 `*policies.{js,mjs,ts}`
|
|
56
|
+
- 项目目录和用户目录都会被扫描(取并集,而非以第一个作用域为准)
|
|
57
|
+
- 每个目录内的文件按字母顺序加载。可以用 `01-`、`02-` 前缀来控制加载顺序
|
|
58
|
+
- 只加载匹配 `*policies.{js,mjs,ts}` 的文件,其他文件会被忽略
|
|
59
59
|
- 每个文件独立加载(单文件失败不影响其他文件)
|
|
60
|
-
- 可与显式 `--custom`
|
|
60
|
+
- 可与显式 `--custom` 和内置策略共存
|
|
61
61
|
|
|
62
62
|
<Tip>
|
|
63
|
-
|
|
63
|
+
基于约定的策略是为组织建立质量标准的最简单方式。将 `.failproofai/policies/` 提交到 git,每位团队成员就能自动获得相同的规则——无需任何个人配置。随着团队发现新的失败模式,只需添加策略并推送。随着时间推移,这些策略会成为随每次贡献不断完善的活质量标准。
|
|
64
64
|
</Tip>
|
|
65
65
|
|
|
66
|
-
###
|
|
66
|
+
### 方式二:显式文件路径
|
|
67
67
|
|
|
68
68
|
```bash
|
|
69
|
-
#
|
|
69
|
+
# 使用自定义策略文件安装
|
|
70
70
|
failproofai policies --install --custom ./my-policies.js
|
|
71
71
|
|
|
72
72
|
# 替换策略文件路径
|
|
@@ -76,13 +76,13 @@ failproofai policies --install --custom ./new-policies.js
|
|
|
76
76
|
failproofai policies --uninstall --custom
|
|
77
77
|
```
|
|
78
78
|
|
|
79
|
-
|
|
79
|
+
解析后的绝对路径会以 `customPoliciesPath` 的形式存储在 `policies-config.json` 中。每次 Hook 事件触发时都会重新加载该文件,事件之间不存在缓存。
|
|
80
80
|
|
|
81
81
|
### 两种方式同时使用
|
|
82
82
|
|
|
83
83
|
基于约定的策略和显式 `--custom` 文件可以共存。加载顺序如下:
|
|
84
84
|
|
|
85
|
-
1. 显式 `customPoliciesPath`
|
|
85
|
+
1. 显式 `customPoliciesPath` 文件(如已配置)
|
|
86
86
|
2. 项目约定文件(`{cwd}/.failproofai/policies/`,按字母顺序)
|
|
87
87
|
3. 用户约定文件(`~/.failproofai/policies/`,按字母顺序)
|
|
88
88
|
|
|
@@ -98,7 +98,7 @@ import { customPolicies, allow, deny, instruct } from "failproofai";
|
|
|
98
98
|
|
|
99
99
|
### `customPolicies.add(hook)`
|
|
100
100
|
|
|
101
|
-
|
|
101
|
+
注册一个策略。可以在同一文件中多次调用以注册多个策略。
|
|
102
102
|
|
|
103
103
|
```ts
|
|
104
104
|
customPolicies.add({
|
|
@@ -113,30 +113,30 @@ customPolicies.add({
|
|
|
113
113
|
|
|
114
114
|
| 函数 | 效果 | 适用场景 |
|
|
115
115
|
|----------|--------|----------|
|
|
116
|
-
| `allow()` | 静默允许操作 |
|
|
116
|
+
| `allow()` | 静默允许操作 | 操作安全,无需任何消息 |
|
|
117
117
|
| `deny(message)` | 阻止操作 | Agent 不应执行此操作 |
|
|
118
|
-
| `instruct(message)` | 添加上下文但不阻止 | 为 Agent
|
|
118
|
+
| `instruct(message)` | 添加上下文但不阻止 | 为 Agent 提供额外上下文以保持在正确轨道上 |
|
|
119
119
|
|
|
120
|
-
`deny(message)`
|
|
120
|
+
`deny(message)` - 消息会以 `"Blocked by failproofai:"` 为前缀显示给 Claude。单个 `deny` 会短路所有后续评估。
|
|
121
121
|
|
|
122
|
-
`instruct(message)`
|
|
122
|
+
`instruct(message)` - 消息会追加到 Claude 当前工具调用的上下文中。所有 `instruct` 消息会被累积并一起送达。
|
|
123
123
|
|
|
124
124
|
<Tip>
|
|
125
|
-
你可以通过在 `policyParams` 中添加 `hint`
|
|
125
|
+
你可以通过在 `policyParams` 中添加 `hint` 字段,为任何 `deny` 或 `instruct` 消息追加额外指导——无需修改代码。这同样适用于自定义(`custom/`)、项目约定(`.failproofai-project/`)和用户约定(`.failproofai-user/`)策略。详情请参阅[配置 → hint](/zh/configuration#hint-cross-cutting)。
|
|
126
126
|
</Tip>
|
|
127
127
|
|
|
128
|
-
###
|
|
128
|
+
### 信息性 allow 消息
|
|
129
129
|
|
|
130
|
-
`allow(message)` 允许操作**并**向 Claude 发送一条信息性消息。该消息通过 Hook 处理器的 stdout 响应中的 `additionalContext`
|
|
130
|
+
`allow(message)` 允许操作**并**向 Claude 发送一条信息性消息。该消息通过 Hook 处理器的 stdout 响应中的 `additionalContext` 机制送达——与 `instruct` 使用相同的机制,但语义不同:它是状态更新,而非警告。
|
|
131
131
|
|
|
132
132
|
| 函数 | 效果 | 适用场景 |
|
|
133
133
|
|----------|--------|----------|
|
|
134
|
-
| `allow(message)` |
|
|
134
|
+
| `allow(message)` | 允许操作并向 Claude 发送上下文 | 确认检查通过,或说明为何跳过某项检查 |
|
|
135
135
|
|
|
136
136
|
使用场景:
|
|
137
|
-
- **状态确认:** `allow("All CI checks passed.")`
|
|
138
|
-
- **失败开放说明:** `allow("GitHub CLI not installed, skipping CI check.")`
|
|
139
|
-
-
|
|
137
|
+
- **状态确认:** `allow("All CI checks passed.")` — 告知 Claude 一切正常
|
|
138
|
+
- **失败开放说明:** `allow("GitHub CLI not installed, skipping CI check.")` — 告知 Claude 某项检查被跳过的原因,使其拥有完整上下文
|
|
139
|
+
- **消息累积:** 如果多个策略各自返回 `allow(message)`,所有消息会以换行符拼接后一起送达
|
|
140
140
|
|
|
141
141
|
```js
|
|
142
142
|
customPolicies.add({
|
|
@@ -160,9 +160,9 @@ customPolicies.add({
|
|
|
160
160
|
| 字段 | 类型 | 描述 |
|
|
161
161
|
|-------|------|-------------|
|
|
162
162
|
| `eventType` | `string` | `"PreToolUse"`、`"PostToolUse"`、`"Notification"`、`"Stop"` |
|
|
163
|
-
| `toolName` | `string \| undefined` |
|
|
163
|
+
| `toolName` | `string \| undefined` | 被调用的工具(如 `"Bash"`、`"Write"`、`"Read"`) |
|
|
164
164
|
| `toolInput` | `Record<string, unknown> \| undefined` | 工具的输入参数 |
|
|
165
|
-
| `payload` | `Record<string, unknown>` | 来自 Claude Code
|
|
165
|
+
| `payload` | `Record<string, unknown>` | 来自 Claude Code 的完整原始事件载荷 |
|
|
166
166
|
| `session` | `SessionMetadata \| undefined` | 会话上下文(见下文) |
|
|
167
167
|
|
|
168
168
|
### `SessionMetadata` 字段
|
|
@@ -177,9 +177,9 @@ customPolicies.add({
|
|
|
177
177
|
|
|
178
178
|
| 事件 | 触发时机 | `toolInput` 内容 |
|
|
179
179
|
|-------|--------------|----------------------|
|
|
180
|
-
| `PreToolUse` | Claude 运行工具之前 |
|
|
181
|
-
| `PostToolUse` |
|
|
182
|
-
| `Notification` | Claude 发送通知时 | `{ message: "...", notification_type: "idle" \| "permission_prompt" \| ... }`
|
|
180
|
+
| `PreToolUse` | Claude 运行工具之前 | 工具的输入(如 Bash 的 `{ command: "..." }`) |
|
|
181
|
+
| `PostToolUse` | 工具完成之后 | 工具的输入 + `tool_result`(输出结果) |
|
|
182
|
+
| `Notification` | Claude 发送通知时 | `{ message: "...", notification_type: "idle" \| "permission_prompt" \| ... }` - Hook 必须始终返回 `allow()`,不能阻止通知 |
|
|
183
183
|
| `Stop` | Claude 会话结束时 | 空 |
|
|
184
184
|
|
|
185
185
|
---
|
|
@@ -189,19 +189,19 @@ customPolicies.add({
|
|
|
189
189
|
策略按以下顺序评估:
|
|
190
190
|
|
|
191
191
|
1. 内置策略(按定义顺序)
|
|
192
|
-
2. 来自 `customPoliciesPath` 的显式自定义策略(按 `.add()`
|
|
193
|
-
3.
|
|
194
|
-
4.
|
|
192
|
+
2. 来自 `customPoliciesPath` 的显式自定义策略(按 `.add()` 顺序)
|
|
193
|
+
3. 项目 `.failproofai/policies/` 中的约定策略(文件按字母顺序,文件内按 `.add()` 顺序)
|
|
194
|
+
4. 用户 `~/.failproofai/policies/` 中的约定策略(文件按字母顺序,文件内按 `.add()` 顺序)
|
|
195
195
|
|
|
196
196
|
<Note>
|
|
197
|
-
第一个 `deny` 会短路所有后续策略。所有 `instruct`
|
|
197
|
+
第一个 `deny` 会短路所有后续策略。所有 `instruct` 消息会被累积并一起送达。
|
|
198
198
|
</Note>
|
|
199
199
|
|
|
200
200
|
---
|
|
201
201
|
|
|
202
202
|
## 传递性导入
|
|
203
203
|
|
|
204
|
-
|
|
204
|
+
自定义策略文件可以使用相对路径导入本地模块:
|
|
205
205
|
|
|
206
206
|
```js
|
|
207
207
|
// my-policies.js
|
|
@@ -218,7 +218,7 @@ customPolicies.add({
|
|
|
218
218
|
});
|
|
219
219
|
```
|
|
220
220
|
|
|
221
|
-
|
|
221
|
+
所有从入口文件可达的相对导入都会被解析。实现方式是将 `from "failproofai"` 的导入重写为实际的 dist 路径,并创建临时 `.mjs` 文件以确保 ESM 兼容性。
|
|
222
222
|
|
|
223
223
|
---
|
|
224
224
|
|
|
@@ -238,7 +238,7 @@ customPolicies.add({
|
|
|
238
238
|
});
|
|
239
239
|
```
|
|
240
240
|
|
|
241
|
-
|
|
241
|
+
完全省略 `match` 则会在每种事件类型上触发。
|
|
242
242
|
|
|
243
243
|
---
|
|
244
244
|
|
|
@@ -249,15 +249,15 @@ customPolicies.add({
|
|
|
249
249
|
| 失败情况 | 行为 |
|
|
250
250
|
|---------|----------|
|
|
251
251
|
| `customPoliciesPath` 未设置 | 不运行显式自定义策略;约定策略和内置策略正常继续 |
|
|
252
|
-
| 文件未找到 |
|
|
253
|
-
| 语法/导入错误(显式) |
|
|
254
|
-
| 语法/导入错误(约定) |
|
|
252
|
+
| 文件未找到 | 警告记录到 `~/.failproofai/hook.log`;内置策略继续运行 |
|
|
253
|
+
| 语法/导入错误(显式) | 错误记录到 `~/.failproofai/hook.log`;跳过显式自定义策略 |
|
|
254
|
+
| 语法/导入错误(约定) | 错误记录;跳过该文件,其他约定文件仍然加载 |
|
|
255
255
|
| `fn` 运行时抛出异常 | 错误记录;该 Hook 视为 `allow`;其他 Hook 继续运行 |
|
|
256
256
|
| `fn` 执行超过 10 秒 | 超时记录;视为 `allow` |
|
|
257
|
-
| 约定目录不存在 |
|
|
257
|
+
| 约定目录不存在 | 不运行约定策略;不报错 |
|
|
258
258
|
|
|
259
259
|
<Tip>
|
|
260
|
-
|
|
260
|
+
要调试自定义策略错误,可以监视日志文件:
|
|
261
261
|
|
|
262
262
|
```bash
|
|
263
263
|
tail -f ~/.failproofai/hook.log
|
|
@@ -266,13 +266,13 @@ tail -f ~/.failproofai/hook.log
|
|
|
266
266
|
|
|
267
267
|
---
|
|
268
268
|
|
|
269
|
-
##
|
|
269
|
+
## 完整示例:多个策略
|
|
270
270
|
|
|
271
271
|
```js
|
|
272
272
|
// my-policies.js
|
|
273
273
|
import { customPolicies, allow, deny, instruct } from "failproofai";
|
|
274
274
|
|
|
275
|
-
//
|
|
275
|
+
// 防止 Agent 写入 secrets/ 目录
|
|
276
276
|
customPolicies.add({
|
|
277
277
|
name: "block-secrets-dir",
|
|
278
278
|
description: "Prevent agent from writing to secrets/ directory",
|
|
@@ -285,7 +285,7 @@ customPolicies.add({
|
|
|
285
285
|
},
|
|
286
286
|
});
|
|
287
287
|
|
|
288
|
-
//
|
|
288
|
+
// 引导 Agent 保持正轨:提交前先验证测试
|
|
289
289
|
customPolicies.add({
|
|
290
290
|
name: "remind-test-before-commit",
|
|
291
291
|
description: "Keep the agent on track: verify tests pass before committing",
|
|
@@ -300,7 +300,7 @@ customPolicies.add({
|
|
|
300
300
|
},
|
|
301
301
|
});
|
|
302
302
|
|
|
303
|
-
//
|
|
303
|
+
// 在冻结期间防止计划外的依赖变更
|
|
304
304
|
customPolicies.add({
|
|
305
305
|
name: "dependency-freeze",
|
|
306
306
|
description: "Prevent unplanned dependency changes during freeze period",
|
|
@@ -327,8 +327,8 @@ export { customPolicies };
|
|
|
327
327
|
|
|
328
328
|
| 文件 | 内容 |
|
|
329
329
|
|------|----------|
|
|
330
|
-
| `examples/policies-basic.js` |
|
|
331
|
-
| `examples/policies-advanced/index.js` |
|
|
330
|
+
| `examples/policies-basic.js` | 五个涵盖常见 Agent 失败模式的入门策略 |
|
|
331
|
+
| `examples/policies-advanced/index.js` | 高级模式:传递性导入、异步调用、输出清理和会话结束 Hook |
|
|
332
332
|
| `examples/convention-policies/security-policies.mjs` | 基于约定的安全策略(阻止 .env 写入、防止 git 历史重写) |
|
|
333
333
|
| `examples/convention-policies/workflow-policies.mjs` | 基于约定的工作流策略(测试提醒、审计文件写入) |
|
|
334
334
|
|
|
@@ -350,4 +350,4 @@ mkdir -p ~/.failproofai/policies
|
|
|
350
350
|
cp examples/convention-policies/*.mjs ~/.failproofai/policies/
|
|
351
351
|
```
|
|
352
352
|
|
|
353
|
-
|
|
353
|
+
无需安装命令——文件会在下次 Hook 事件触发时自动被加载。
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: 示例
|
|
3
|
-
description: "如何为 Claude Code 和 Agents SDK
|
|
3
|
+
description: "如何为 Claude Code 和 Agents SDK 设置钩子"
|
|
4
4
|
icon: book-open
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
开箱即用的常见场景示例,每个示例均说明了安装方式及预期效果。
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
## 为 Claude Code
|
|
11
|
+
## 为 Claude Code 设置钩子
|
|
12
12
|
|
|
13
|
-
Failproof AI 通过 [
|
|
13
|
+
Failproof AI 通过 [钩子系统](https://docs.anthropic.com/en/docs/claude-code/hooks) 与 Claude Code 集成。运行 `failproofai policies --install` 后,它会在 Claude Code 的 `settings.json` 中注册钩子命令,并在每次工具调用时触发。
|
|
14
14
|
|
|
15
15
|
<Steps>
|
|
16
16
|
<Step title="安装 failproofai">
|
|
@@ -23,27 +23,27 @@ Failproof AI 通过 [hooks 系统](https://docs.anthropic.com/en/docs/claude-cod
|
|
|
23
23
|
failproofai policies --install
|
|
24
24
|
```
|
|
25
25
|
</Step>
|
|
26
|
-
<Step title="
|
|
26
|
+
<Step title="验证钩子已注册">
|
|
27
27
|
```bash
|
|
28
28
|
cat ~/.claude/settings.json | grep failproofai
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
-
你应该能看到 `PreToolUse`、`PostToolUse`、`Notification` 和 `Stop`
|
|
31
|
+
你应该能看到 `PreToolUse`、`PostToolUse`、`Notification` 和 `Stop` 事件的钩子条目。
|
|
32
32
|
</Step>
|
|
33
33
|
<Step title="运行 Claude Code">
|
|
34
34
|
```bash
|
|
35
35
|
claude
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
策略现在会在每次工具调用时自动运行。你可以尝试让 Claude 执行 `sudo rm -rf /`,该命令将被拦截。
|
|
39
39
|
</Step>
|
|
40
40
|
</Steps>
|
|
41
41
|
|
|
42
42
|
---
|
|
43
43
|
|
|
44
|
-
## 为 Agents SDK
|
|
44
|
+
## 为 Agents SDK 设置钩子
|
|
45
45
|
|
|
46
|
-
如果你正在使用 [Agents SDK](https://docs.anthropic.com/en/docs/agents-sdk)
|
|
46
|
+
如果你正在使用 [Agents SDK](https://docs.anthropic.com/en/docs/agents-sdk) 进行开发,可以通过编程方式使用相同的钩子系统。
|
|
47
47
|
|
|
48
48
|
<Steps>
|
|
49
49
|
<Step title="在项目中安装 failproofai">
|
|
@@ -51,12 +51,12 @@ Failproof AI 通过 [hooks 系统](https://docs.anthropic.com/en/docs/claude-cod
|
|
|
51
51
|
npm install failproofai
|
|
52
52
|
```
|
|
53
53
|
</Step>
|
|
54
|
-
<Step title="在 Agent
|
|
55
|
-
在创建 Agent
|
|
54
|
+
<Step title="在 Agent 中配置钩子">
|
|
55
|
+
在创建 Agent 进程时传入钩子命令。钩子的触发方式与 Claude Code 中完全一致——通过 stdin/stdout JSON:
|
|
56
56
|
|
|
57
57
|
```bash
|
|
58
|
-
failproofai --hook PreToolUse #
|
|
59
|
-
failproofai --hook PostToolUse #
|
|
58
|
+
failproofai --hook PreToolUse # 每次工具调用前触发
|
|
59
|
+
failproofai --hook PostToolUse # 每次工具调用后触发
|
|
60
60
|
```
|
|
61
61
|
</Step>
|
|
62
62
|
<Step title="为 Agent 编写自定义策略">
|
|
@@ -86,37 +86,37 @@ Failproof AI 通过 [hooks 系统](https://docs.anthropic.com/en/docs/claude-cod
|
|
|
86
86
|
|
|
87
87
|
---
|
|
88
88
|
|
|
89
|
-
##
|
|
89
|
+
## 阻止破坏性命令
|
|
90
90
|
|
|
91
|
-
最常见的配置——防止 Agent
|
|
91
|
+
最常见的配置——防止 Agent 造成不可逆的破坏。
|
|
92
92
|
|
|
93
93
|
```bash
|
|
94
94
|
failproofai policies --install block-sudo block-rm-rf block-force-push block-curl-pipe-sh
|
|
95
95
|
```
|
|
96
96
|
|
|
97
97
|
各策略说明:
|
|
98
|
-
- `block-sudo`
|
|
99
|
-
- `block-rm-rf`
|
|
100
|
-
- `block-force-push`
|
|
101
|
-
- `block-curl-pipe-sh`
|
|
98
|
+
- `block-sudo` — 阻止所有 `sudo` 命令
|
|
99
|
+
- `block-rm-rf` — 阻止递归删除文件
|
|
100
|
+
- `block-force-push` — 阻止 `git push --force`
|
|
101
|
+
- `block-curl-pipe-sh` — 阻止将远程脚本通过管道传给 Shell 执行
|
|
102
102
|
|
|
103
103
|
---
|
|
104
104
|
|
|
105
|
-
##
|
|
105
|
+
## 防止密钥泄漏
|
|
106
106
|
|
|
107
|
-
阻止 Agent
|
|
107
|
+
阻止 Agent 在工具输出中查看或泄漏凭证。
|
|
108
108
|
|
|
109
109
|
```bash
|
|
110
110
|
failproofai policies --install sanitize-api-keys sanitize-jwt sanitize-connection-strings sanitize-bearer-tokens
|
|
111
111
|
```
|
|
112
112
|
|
|
113
|
-
这些策略在 `PostToolUse`
|
|
113
|
+
这些策略在 `PostToolUse` 阶段触发——工具运行完毕后,会在 Agent 看到输出之前对其进行清理。
|
|
114
114
|
|
|
115
115
|
---
|
|
116
116
|
|
|
117
|
-
##
|
|
117
|
+
## 通过 Slack 接收 Agent 待处理提醒
|
|
118
118
|
|
|
119
|
-
|
|
119
|
+
使用通知钩子将空闲提醒转发到 Slack。
|
|
120
120
|
|
|
121
121
|
```javascript
|
|
122
122
|
import { customPolicies, allow, instruct } from "failproofai";
|
|
@@ -142,7 +142,7 @@ customPolicies.add({
|
|
|
142
142
|
signal: AbortSignal.timeout(5000),
|
|
143
143
|
});
|
|
144
144
|
} catch {
|
|
145
|
-
//
|
|
145
|
+
// 如果 Slack 不可达,绝不阻塞 Agent
|
|
146
146
|
}
|
|
147
147
|
|
|
148
148
|
return allow();
|
|
@@ -160,7 +160,7 @@ SLACK_WEBHOOK_URL=https://hooks.slack.com/... failproofai policies --install --c
|
|
|
160
160
|
|
|
161
161
|
## 将 Agent 限制在指定分支
|
|
162
162
|
|
|
163
|
-
防止 Agent
|
|
163
|
+
防止 Agent 切换分支或推送到受保护的分支。
|
|
164
164
|
|
|
165
165
|
```javascript
|
|
166
166
|
import { customPolicies, allow, deny } from "failproofai";
|
|
@@ -184,7 +184,7 @@ customPolicies.add({
|
|
|
184
184
|
|
|
185
185
|
## 提交前要求运行测试
|
|
186
186
|
|
|
187
|
-
提醒 Agent
|
|
187
|
+
提醒 Agent 在提交之前先运行测试。
|
|
188
188
|
|
|
189
189
|
```javascript
|
|
190
190
|
import { customPolicies, allow, instruct } from "failproofai";
|
|
@@ -206,9 +206,9 @@ customPolicies.add({
|
|
|
206
206
|
|
|
207
207
|
---
|
|
208
208
|
|
|
209
|
-
##
|
|
209
|
+
## 锁定生产仓库
|
|
210
210
|
|
|
211
|
-
|
|
211
|
+
在项目中提交一份项目级配置文件,让团队中每位开发者都使用相同的策略。
|
|
212
212
|
|
|
213
213
|
在仓库中创建 `.failproofai/policies-config.json`:
|
|
214
214
|
|
|
@@ -231,14 +231,68 @@ customPolicies.add({
|
|
|
231
231
|
}
|
|
232
232
|
```
|
|
233
233
|
|
|
234
|
-
|
|
234
|
+
然后提交:
|
|
235
235
|
|
|
236
236
|
```bash
|
|
237
237
|
git add .failproofai/policies-config.json
|
|
238
238
|
git commit -m "Add failproofai team policies"
|
|
239
239
|
```
|
|
240
240
|
|
|
241
|
-
所有已安装 failproofai
|
|
241
|
+
所有已安装 failproofai 的团队成员将自动应用这些规则。
|
|
242
|
+
|
|
243
|
+
---
|
|
244
|
+
|
|
245
|
+
## 通过约定策略构建全组织的质量标准
|
|
246
|
+
|
|
247
|
+
最具影响力的配置方式:将 `.failproofai/policies/` 目录提交到仓库,并在其中编写针对项目量身定制的策略。每位团队成员都会自动获取——无需执行安装命令,无需修改配置。
|
|
248
|
+
|
|
249
|
+
<Steps>
|
|
250
|
+
<Step title="创建目录并添加策略">
|
|
251
|
+
```bash
|
|
252
|
+
mkdir -p .failproofai/policies
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
```js
|
|
256
|
+
// .failproofai/policies/team-policies.mjs
|
|
257
|
+
import { customPolicies, allow, deny, instruct } from "failproofai";
|
|
258
|
+
|
|
259
|
+
// 强制使用团队指定的包管理器
|
|
260
|
+
// (也可以启用内置的 prefer-package-manager 策略)
|
|
261
|
+
customPolicies.add({
|
|
262
|
+
name: "enforce-bun",
|
|
263
|
+
match: { events: ["PreToolUse"] },
|
|
264
|
+
fn: async (ctx) => {
|
|
265
|
+
if (ctx.toolName !== "Bash") return allow();
|
|
266
|
+
const cmd = String(ctx.toolInput?.command ?? "");
|
|
267
|
+
if (/\bnpm\b/.test(cmd)) return deny("Use bun instead of npm.");
|
|
268
|
+
return allow();
|
|
269
|
+
},
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
// 提醒 Agent 在提交前运行测试
|
|
273
|
+
customPolicies.add({
|
|
274
|
+
name: "test-before-commit",
|
|
275
|
+
match: { events: ["PreToolUse"] },
|
|
276
|
+
fn: async (ctx) => {
|
|
277
|
+
if (ctx.toolName !== "Bash") return allow();
|
|
278
|
+
if (/git\s+commit/.test(ctx.toolInput?.command ?? "")) {
|
|
279
|
+
return instruct("Run tests before committing.");
|
|
280
|
+
}
|
|
281
|
+
return allow();
|
|
282
|
+
},
|
|
283
|
+
});
|
|
284
|
+
```
|
|
285
|
+
</Step>
|
|
286
|
+
<Step title="提交到 git">
|
|
287
|
+
```bash
|
|
288
|
+
git add .failproofai/policies/
|
|
289
|
+
git commit -m "Add team quality policies"
|
|
290
|
+
```
|
|
291
|
+
</Step>
|
|
292
|
+
<Step title="持续优化">
|
|
293
|
+
随着团队遇到新的故障模式,不断添加策略并推送。每个人在下次 `git pull` 时即可获取更新。这些策略将成为一套随团队共同成长的活态质量标准。
|
|
294
|
+
</Step>
|
|
295
|
+
</Steps>
|
|
242
296
|
|
|
243
297
|
---
|
|
244
298
|
|
|
@@ -246,8 +300,8 @@ git commit -m "Add failproofai team policies"
|
|
|
246
300
|
|
|
247
301
|
仓库中的 [`examples/`](https://github.com/exospherehost/failproofai/tree/main/examples) 目录包含以下内容:
|
|
248
302
|
|
|
249
|
-
| 文件 |
|
|
250
|
-
|
|
251
|
-
| `policies-basic.js` |
|
|
252
|
-
| `policies-notification.js` |
|
|
253
|
-
| `policies-advanced/index.js` |
|
|
303
|
+
| 文件 | 说明 |
|
|
304
|
+
|------|------|
|
|
305
|
+
| `policies-basic.js` | 入门策略——阻止写入生产环境、强制推送和管道脚本 |
|
|
306
|
+
| `policies-notification.js` | 空闲通知和会话结束时发送 Slack 提醒 |
|
|
307
|
+
| `policies-advanced/index.js` | 传递性导入、异步钩子、PostToolUse 输出清理、Stop 事件处理 |
|