failproofai 0.0.5 → 0.0.6-beta.1
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 +112 -0
- package/.next/standalone/.failproofai/policies/workflow-policies.mjs +2 -1
- package/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/build-manifest.json +5 -5
- 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/build-manifest.json +2 -2
- 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/build-manifest.json +2 -2
- 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/build-manifest.json +2 -2
- 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/build-manifest.json +2 -2
- 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/build-manifest.json +2 -2
- 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/build-manifest.json +2 -2
- 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/build-manifest.json +2 -2
- 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]__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]__0okos0k._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0a~g15g._.js → [root-of-the-server]__0rh.18_._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0w6l33k._.js +6 -6
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0qn95h3._.js → [root-of-the-server]__0~kmh8w._.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 +5 -5
- 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/{0sme4lkv.tgn-.js → 01b~z8f1ws0rk.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0lgbwkfqmnsmc.js → 03rz6ykw-a2xi.js} +1 -1
- package/.next/standalone/.next/static/chunks/{17manv47o-~wp.js → 08t08igdql9yt.js} +1 -1
- package/.next/standalone/.next/static/chunks/09_k80d~cq2wg.js +4 -0
- package/.next/standalone/.next/static/chunks/{0ksdlt_1hucdm.js → 0bvhsa6zva2o..js} +1 -1
- package/.next/standalone/.next/static/chunks/{09ikntpt2-o9b.js → 0gbf4cphy8ksq.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0yumumfzx_f27.js → 0v.yd0kg_ld3r.js} +1 -1
- package/.next/standalone/.next/static/chunks/{13juklu.vksks.js → 0wlyoif4_kj_t.js} +1 -1
- package/.next/standalone/.next/static/chunks/{09e7drilkf1sn.js → 12simlrcfk3g2.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0em7tspi4kylh.js → 12~yi9oj8av8p.js} +2 -2
- package/.next/standalone/.next/static/chunks/{turbopack-0r26pc8h0y_-e.js → turbopack-0o7k.hakttp4k.js} +1 -1
- package/.next/standalone/CHANGELOG.md +13 -0
- package/.next/standalone/README.md +2 -2
- package/.next/standalone/bun.lock +43 -85
- package/.next/standalone/dist/cli.mjs +107 -3
- package/.next/standalone/docs/ar/architecture.mdx +65 -64
- package/.next/standalone/docs/ar/configuration.mdx +42 -42
- package/.next/standalone/docs/ar/custom-policies.mdx +62 -64
- package/.next/standalone/docs/built-in-policies.mdx +37 -0
- package/.next/standalone/docs/custom-policies.mdx +1 -1
- package/.next/standalone/docs/de/architecture.mdx +92 -92
- package/.next/standalone/docs/de/configuration.mdx +34 -34
- package/.next/standalone/docs/de/custom-policies.mdx +49 -50
- package/.next/standalone/docs/es/architecture.mdx +72 -72
- package/.next/standalone/docs/es/configuration.mdx +25 -25
- package/.next/standalone/docs/es/custom-policies.mdx +48 -49
- package/.next/standalone/docs/examples.mdx +54 -0
- package/.next/standalone/docs/fr/architecture.mdx +53 -53
- package/.next/standalone/docs/fr/configuration.mdx +25 -25
- package/.next/standalone/docs/fr/custom-policies.mdx +42 -43
- package/.next/standalone/docs/getting-started.mdx +52 -0
- package/.next/standalone/docs/he/architecture.mdx +66 -66
- package/.next/standalone/docs/he/configuration.mdx +53 -52
- package/.next/standalone/docs/he/custom-policies.mdx +72 -73
- package/.next/standalone/docs/hi/architecture.mdx +106 -106
- package/.next/standalone/docs/hi/configuration.mdx +39 -39
- package/.next/standalone/docs/hi/custom-policies.mdx +75 -76
- package/.next/standalone/docs/i18n/README.ar.md +66 -66
- package/.next/standalone/docs/i18n/README.de.md +38 -38
- package/.next/standalone/docs/i18n/README.es.md +38 -38
- package/.next/standalone/docs/i18n/README.fr.md +42 -42
- package/.next/standalone/docs/i18n/README.he.md +67 -67
- package/.next/standalone/docs/i18n/README.hi.md +70 -70
- package/.next/standalone/docs/i18n/README.it.md +62 -62
- package/.next/standalone/docs/i18n/README.ja.md +54 -54
- package/.next/standalone/docs/i18n/README.ko.md +58 -58
- package/.next/standalone/docs/i18n/README.pt-br.md +43 -43
- package/.next/standalone/docs/i18n/README.ru.md +69 -69
- package/.next/standalone/docs/i18n/README.tr.md +76 -76
- package/.next/standalone/docs/i18n/README.vi.md +70 -70
- package/.next/standalone/docs/i18n/README.zh.md +52 -52
- package/.next/standalone/docs/it/architecture.mdx +54 -53
- package/.next/standalone/docs/it/configuration.mdx +44 -45
- package/.next/standalone/docs/it/custom-policies.mdx +76 -78
- package/.next/standalone/docs/ja/architecture.mdx +93 -93
- package/.next/standalone/docs/ja/configuration.mdx +47 -47
- package/.next/standalone/docs/ja/custom-policies.mdx +62 -63
- package/.next/standalone/docs/ko/architecture.mdx +66 -66
- package/.next/standalone/docs/ko/configuration.mdx +35 -35
- package/.next/standalone/docs/ko/custom-policies.mdx +71 -72
- package/.next/standalone/docs/pt-br/architecture.mdx +55 -55
- package/.next/standalone/docs/pt-br/configuration.mdx +35 -35
- package/.next/standalone/docs/pt-br/custom-policies.mdx +60 -61
- package/.next/standalone/docs/ru/architecture.mdx +59 -60
- package/.next/standalone/docs/ru/configuration.mdx +52 -53
- package/.next/standalone/docs/ru/custom-policies.mdx +68 -69
- package/.next/standalone/docs/tr/architecture.mdx +124 -124
- package/.next/standalone/docs/tr/configuration.mdx +45 -46
- package/.next/standalone/docs/tr/custom-policies.mdx +75 -75
- package/.next/standalone/docs/vi/architecture.mdx +65 -64
- package/.next/standalone/docs/vi/configuration.mdx +41 -41
- package/.next/standalone/docs/vi/custom-policies.mdx +68 -69
- package/.next/standalone/docs/zh/architecture.mdx +67 -67
- package/.next/standalone/docs/zh/configuration.mdx +34 -34
- package/.next/standalone/docs/zh/custom-policies.mdx +53 -54
- package/.next/standalone/node_modules/@next/env/package.json +1 -1
- package/.next/standalone/node_modules/next/dist/build/swc/index.js +1 -1
- package/.next/standalone/node_modules/next/dist/compiled/next-server/pages-turbo.runtime.prod.js +7 -7
- package/.next/standalone/node_modules/next/dist/lib/patch-incorrect-lockfile.js +3 -3
- package/.next/standalone/node_modules/next/dist/server/config-schema.js +10 -2
- package/.next/standalone/node_modules/next/dist/server/config.js +1 -1
- package/.next/standalone/node_modules/next/dist/server/dev/hot-reloader-turbopack.js +2 -2
- package/.next/standalone/node_modules/next/dist/server/dev/hot-reloader-webpack.js +1 -1
- package/.next/standalone/node_modules/next/dist/server/lib/app-info-log.js +1 -1
- package/.next/standalone/node_modules/next/dist/server/lib/start-server.js +1 -1
- package/.next/standalone/node_modules/next/dist/server/render.js +27 -20
- package/.next/standalone/node_modules/next/dist/shared/lib/errors/canary-only-config-error.js +1 -1
- package/.next/standalone/node_modules/next/dist/telemetry/anonymous-meta.js +1 -1
- package/.next/standalone/node_modules/next/dist/telemetry/events/swc-load-failure.js +1 -1
- package/.next/standalone/node_modules/next/dist/telemetry/events/version.js +2 -2
- package/.next/standalone/node_modules/next/package.json +15 -15
- package/.next/standalone/package.json +2 -2
- package/.next/standalone/server.js +1 -1
- package/.next/standalone/src/hooks/builtin-policies.ts +131 -0
- package/README.md +2 -2
- package/dist/cli.mjs +107 -3
- package/package.json +2 -2
- package/src/hooks/builtin-policies.ts +131 -0
- package/.next/standalone/.next/static/chunks/0_yayar~bpphd.js +0 -4
- /package/.next/standalone/.next/static/{hYQM6iCWnF1W5XDpsIRhV → CkmOT-ZvDN-sVULinGVKT}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{hYQM6iCWnF1W5XDpsIRhV → CkmOT-ZvDN-sVULinGVKT}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{hYQM6iCWnF1W5XDpsIRhV → CkmOT-ZvDN-sVULinGVKT}/_ssgManifest.js +0 -0
|
@@ -1,29 +1,29 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: 架构
|
|
3
|
-
description: "
|
|
3
|
+
description: "Hook 处理器、配置加载和策略评估的内部工作原理"
|
|
4
4
|
icon: sitemap
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
本文档介绍 failproofai
|
|
7
|
+
本文档介绍 failproofai 的内部工作机制:Hook 系统如何拦截 Agent 工具调用、配置如何加载和合并、策略如何评估,以及 Dashboard 如何监控 Agent 活动。
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
##
|
|
11
|
+
## 概览
|
|
12
12
|
|
|
13
13
|
failproofai 包含两个独立的子系统:
|
|
14
14
|
|
|
15
|
-
1.
|
|
16
|
-
2. **Agent
|
|
15
|
+
1. **Hook 处理器** - 一个快速的 CLI 子进程,Claude Code 在每次 Agent 工具调用时都会调用它。负责评估策略并返回决策结果。
|
|
16
|
+
2. **Agent 监控(Dashboard)** - 一个用于监控 Agent 会话和管理策略的 Next.js Web 应用。
|
|
17
17
|
|
|
18
|
-
两个子系统共享 `~/.failproofai/`
|
|
18
|
+
两个子系统共享 `~/.failproofai/` 和项目 `.failproofai/` 目录中的配置文件,但它们作为独立进程运行,仅通过文件系统进行通信。
|
|
19
19
|
|
|
20
20
|
---
|
|
21
21
|
|
|
22
|
-
##
|
|
22
|
+
## Hook 处理器
|
|
23
23
|
|
|
24
24
|
### 与 Claude Code 的集成
|
|
25
25
|
|
|
26
|
-
运行 `failproofai policies --install`
|
|
26
|
+
运行 `failproofai policies --install` 后,它会在 `~/.claude/settings.json` 中写入如下配置:
|
|
27
27
|
|
|
28
28
|
```json
|
|
29
29
|
{
|
|
@@ -44,9 +44,9 @@ failproofai 包含两个独立的子系统:
|
|
|
44
44
|
}
|
|
45
45
|
```
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
随后,Claude Code 会在每次工具调用前将 `failproofai --hook PreToolUse` 作为子进程调用,并通过 stdin 传入一个 JSON 数据包。
|
|
48
48
|
|
|
49
|
-
###
|
|
49
|
+
### 数据包格式
|
|
50
50
|
|
|
51
51
|
```json
|
|
52
52
|
{
|
|
@@ -60,9 +60,9 @@ failproofai 包含两个独立的子系统:
|
|
|
60
60
|
}
|
|
61
61
|
```
|
|
62
62
|
|
|
63
|
-
对于 `PostToolUse`
|
|
63
|
+
对于 `PostToolUse` 事件,数据包还包含 `tool_result` 字段,其中包含工具的输出结果。
|
|
64
64
|
|
|
65
|
-
|
|
65
|
+
处理器对 stdin 限制为 1 MB。超过此限制的数据包将被丢弃,所有策略默认隐式允许。
|
|
66
66
|
|
|
67
67
|
### 响应格式
|
|
68
68
|
|
|
@@ -85,7 +85,7 @@ failproofai 包含两个独立的子系统:
|
|
|
85
85
|
}
|
|
86
86
|
```
|
|
87
87
|
|
|
88
|
-
**指令(除 Stop
|
|
88
|
+
**指令(除 Stop 以外的任何事件):**
|
|
89
89
|
```json
|
|
90
90
|
{
|
|
91
91
|
"hookSpecificOutput": {
|
|
@@ -94,7 +94,7 @@ failproofai 包含两个独立的子系统:
|
|
|
94
94
|
}
|
|
95
95
|
```
|
|
96
96
|
|
|
97
|
-
**Stop
|
|
97
|
+
**Stop 事件指令:**
|
|
98
98
|
- 退出码:`2`
|
|
99
99
|
- 原因写入 stderr(而非 stdout)
|
|
100
100
|
|
|
@@ -102,9 +102,9 @@ failproofai 包含两个独立的子系统:
|
|
|
102
102
|
- 退出码:`0`
|
|
103
103
|
- stdout 为空
|
|
104
104
|
|
|
105
|
-
|
|
105
|
+
**带消息的允许:**
|
|
106
106
|
|
|
107
|
-
`allow(message)`
|
|
107
|
+
`allow(message)` 允许策略在操作被允许时向 Claude 发送信息性上下文。Hook 处理器将以下 JSON 写入 **stdout**(而非配置文件——这是处理器对 Claude Code 的响应,与 deny 和 instruct 响应一样):
|
|
108
108
|
|
|
109
109
|
```json
|
|
110
110
|
// Written to stdout by the hook handler process
|
|
@@ -115,8 +115,8 @@ failproofai 包含两个独立的子系统:
|
|
|
115
115
|
}
|
|
116
116
|
```
|
|
117
117
|
- 退出码:`0`(操作被允许)
|
|
118
|
-
- 当多个策略返回带消息的 `allow`
|
|
119
|
-
-
|
|
118
|
+
- 当多个策略返回带消息的 `allow` 时,这些消息会以换行符合并为单个 `additionalContext` 字符串
|
|
119
|
+
- 若没有策略提供消息,则 stdout 为空(与之前相同)
|
|
120
120
|
|
|
121
121
|
### 处理流水线
|
|
122
122
|
|
|
@@ -124,28 +124,28 @@ failproofai 包含两个独立的子系统:
|
|
|
124
124
|
|
|
125
125
|
```text
|
|
126
126
|
stdin JSON
|
|
127
|
-
→
|
|
127
|
+
→ 解析数据包(最大 1 MB)
|
|
128
128
|
→ 提取会话元数据(session_id、cwd、tool_name、tool_input 等)
|
|
129
129
|
→ readMergedHooksConfig(cwd) ← 合并项目 + 本地 + 全局配置
|
|
130
|
-
→
|
|
130
|
+
→ 注册已启用的内置策略及其解析后的参数
|
|
131
131
|
→ 从 customPoliciesPath 加载自定义策略(如已设置)
|
|
132
132
|
→ 将自定义策略注册到策略注册表
|
|
133
|
-
→
|
|
134
|
-
→
|
|
135
|
-
→ instruct
|
|
136
|
-
→ allow
|
|
133
|
+
→ 评估所有策略(先内置策略,后自定义策略)
|
|
134
|
+
→ 第一个 deny 会短路后续评估
|
|
135
|
+
→ instruct 决策会累积
|
|
136
|
+
→ allow 消息会累积
|
|
137
137
|
→ 将 JSON 决策写入 stdout
|
|
138
138
|
→ 将事件持久化到 ~/.failproofai/hook-activity.jsonl
|
|
139
139
|
→ 退出
|
|
140
140
|
```
|
|
141
141
|
|
|
142
|
-
|
|
142
|
+
整个过程在典型数据包下运行耗时不超过 100ms,且不涉及任何 LLM 调用。
|
|
143
143
|
|
|
144
144
|
---
|
|
145
145
|
|
|
146
146
|
## 配置加载
|
|
147
147
|
|
|
148
|
-
`src/hooks/hooks-config.ts`
|
|
148
|
+
`src/hooks/hooks-config.ts` 实现了三层作用域的配置加载。
|
|
149
149
|
|
|
150
150
|
```text
|
|
151
151
|
[1] {cwd}/.failproofai/policies-config.json ← 项目级(最高优先级)
|
|
@@ -154,39 +154,39 @@ stdin JSON
|
|
|
154
154
|
```
|
|
155
155
|
|
|
156
156
|
合并逻辑:
|
|
157
|
-
- `enabledPolicies` -
|
|
158
|
-
- `policyParams` -
|
|
157
|
+
- `enabledPolicies` - 对三个文件进行去重并集
|
|
158
|
+
- `policyParams` - 按策略键,第一个定义该键的文件完全优先
|
|
159
159
|
- `customPoliciesPath` - 第一个定义它的文件优先
|
|
160
160
|
- `llm` - 第一个定义它的文件优先
|
|
161
161
|
|
|
162
|
-
|
|
162
|
+
Web Dashboard 使用 `readHooksConfig()`(仅全局)进行读写,因为它不带项目 cwd 调用。
|
|
163
163
|
|
|
164
164
|
---
|
|
165
165
|
|
|
166
166
|
## 策略评估
|
|
167
167
|
|
|
168
|
-
`src/hooks/policy-evaluator.ts`
|
|
168
|
+
`src/hooks/policy-evaluator.ts` 按顺序运行策略。
|
|
169
169
|
|
|
170
|
-
|
|
170
|
+
对于每条策略:
|
|
171
171
|
|
|
172
|
-
1. 查找策略的 `params`
|
|
172
|
+
1. 查找策略的 `params` 模式(如有)。
|
|
173
173
|
2. 从合并后的配置中读取 `policyParams[policy.name]`。
|
|
174
|
-
3.
|
|
174
|
+
3. 将用户提供的值覆盖到模式默认值之上,生成 `ctx.params`。
|
|
175
175
|
4. 以解析后的上下文调用 `policy.fn(ctx)`。
|
|
176
176
|
5. 若结果为 `deny`,立即停止并返回该决策。
|
|
177
177
|
6. 若结果为 `instruct`,累积消息并继续。
|
|
178
|
-
7. 若结果为 `allow
|
|
178
|
+
7. 若结果为 `allow`,继续执行下一条策略。
|
|
179
179
|
|
|
180
|
-
|
|
181
|
-
-
|
|
182
|
-
- 若收集到任意 `instruct
|
|
183
|
-
-
|
|
180
|
+
所有策略运行完毕后:
|
|
181
|
+
- 若有任意 `deny` 返回,发出拒绝响应。
|
|
182
|
+
- 若收集到任意 `instruct` 返回,发出单条指令响应,将所有消息合并。
|
|
183
|
+
- 否则,发出允许响应(stdout 为空,退出码 0)。
|
|
184
184
|
|
|
185
185
|
---
|
|
186
186
|
|
|
187
187
|
## 内置策略
|
|
188
188
|
|
|
189
|
-
`src/hooks/builtin-policies.ts`
|
|
189
|
+
`src/hooks/builtin-policies.ts` 将所有 26 个内置策略定义为 `BuiltinPolicyDefinition` 对象:
|
|
190
190
|
|
|
191
191
|
```typescript
|
|
192
192
|
interface BuiltinPolicyDefinition {
|
|
@@ -204,15 +204,15 @@ interface BuiltinPolicyDefinition {
|
|
|
204
204
|
}
|
|
205
205
|
```
|
|
206
206
|
|
|
207
|
-
接受 `params` 的策略会声明一个 `PolicyParamsSchema`,为每个参数指定类型和默认值。策略评估器在调用 `fn`
|
|
207
|
+
接受 `params` 的策略会声明一个 `PolicyParamsSchema`,为每个参数指定类型和默认值。策略评估器在调用 `fn` 之前将解析后的值注入 `ctx.params`。策略函数读取 `ctx.params` 时无需进行空值检查,因为默认值始终已被应用。
|
|
208
208
|
|
|
209
|
-
策略内部的模式匹配使用已解析的命令 token(argv),而非原始字符串匹配。这可防止通过
|
|
209
|
+
策略内部的模式匹配使用已解析的命令 token(argv),而非原始字符串匹配。这可防止通过 Shell 运算符注入进行绕过(例如,针对 `sudo systemctl status *` 的模式无法通过在命令后追加 `; rm -rf /` 来绕过)。
|
|
210
210
|
|
|
211
211
|
---
|
|
212
212
|
|
|
213
213
|
## 自定义策略
|
|
214
214
|
|
|
215
|
-
`src/hooks/custom-hooks-registry.ts`
|
|
215
|
+
`src/hooks/custom-hooks-registry.ts` 实现了基于 `globalThis` 的注册表:
|
|
216
216
|
|
|
217
217
|
```typescript
|
|
218
218
|
const REGISTRY_KEY = "__failproofai_custom_hooks__";
|
|
@@ -229,21 +229,21 @@ export function clearCustomHooks(): void { ... } // used in tests
|
|
|
229
229
|
|
|
230
230
|
1. 从配置中读取 `customPoliciesPath`;若不存在则跳过。
|
|
231
231
|
2. 解析为绝对路径;检查文件是否存在。
|
|
232
|
-
3. 将所有 `from "failproofai"`
|
|
233
|
-
4.
|
|
234
|
-
5. 写入临时 `.mjs`
|
|
235
|
-
6. 调用 `getCustomHooks()`
|
|
232
|
+
3. 将所有 `from "failproofai"` 的导入重写为实际的 dist 路径,确保 `customPolicies` 解析到同一个 `globalThis` 注册表。
|
|
233
|
+
4. 递归重写传递性本地导入,以确保 ESM 兼容性。
|
|
234
|
+
5. 写入临时 `.mjs` 文件并 `import()` 入口文件。
|
|
235
|
+
6. 调用 `getCustomHooks()` 获取已注册的 Hook。
|
|
236
236
|
7. 在 `finally` 块中清理所有临时文件。
|
|
237
237
|
|
|
238
|
-
|
|
238
|
+
发生任何错误时(文件不存在、语法错误、导入失败),错误将记录到 `~/.failproofai/hook.log`,加载器返回空数组。内置策略不受影响。
|
|
239
239
|
|
|
240
|
-
自定义策略在所有内置策略之后评估。自定义策略的 `deny`
|
|
240
|
+
自定义策略在所有内置策略之后评估。自定义策略的 `deny` 仍会短路后续自定义策略的执行(但此时所有内置策略均已运行完毕)。
|
|
241
241
|
|
|
242
242
|
---
|
|
243
243
|
|
|
244
244
|
## 活动日志
|
|
245
245
|
|
|
246
|
-
|
|
246
|
+
每次 Hook 事件后,处理器会向 `~/.failproofai/hook-activity.jsonl` 追加一行 JSONL 记录:
|
|
247
247
|
|
|
248
248
|
```json
|
|
249
249
|
{
|
|
@@ -258,13 +258,13 @@ export function clearCustomHooks(): void { ... } // used in tests
|
|
|
258
258
|
}
|
|
259
259
|
```
|
|
260
260
|
|
|
261
|
-
|
|
261
|
+
每条非允许决策对应一行记录。允许决策不会被记录(以保持文件精简)。
|
|
262
262
|
|
|
263
263
|
---
|
|
264
264
|
|
|
265
|
-
##
|
|
265
|
+
## Dashboard 架构
|
|
266
266
|
|
|
267
|
-
|
|
267
|
+
Dashboard 是一个 **Next.js 16** 应用,使用 App Router,结合 React Server Components 和 Server Actions。
|
|
268
268
|
|
|
269
269
|
```text
|
|
270
270
|
app/
|
|
@@ -279,47 +279,47 @@ app/
|
|
|
279
279
|
update-hooks-config.ts ← 开启/关闭策略
|
|
280
280
|
update-policy-params.ts ← 更新策略参数
|
|
281
281
|
get-hook-activity.ts ← 分页/搜索活动日志
|
|
282
|
-
install-hooks-web.ts ←
|
|
282
|
+
install-hooks-web.ts ← 通过浏览器安装/移除 Hook
|
|
283
283
|
api/
|
|
284
284
|
download/[project]/[session]/route.ts ← 将会话导出为 ZIP/JSONL
|
|
285
285
|
```
|
|
286
286
|
|
|
287
287
|
**数据流:**
|
|
288
288
|
|
|
289
|
-
- 页面组件调用 `lib/projects.ts` 和 `lib/log-entries.ts
|
|
290
|
-
-
|
|
289
|
+
- 页面组件调用 `lib/projects.ts` 和 `lib/log-entries.ts` 直接从文件系统读取项目/会话数据(读取操作无需 API 层)。
|
|
290
|
+
- 策略页面的所有变更操作(切换、参数更新、安装/移除)均使用 Server Actions。
|
|
291
291
|
- 会话查看器解析 Claude 的 JSONL 转录格式,并渲染消息和工具调用的时间线。
|
|
292
292
|
|
|
293
293
|
**关键设计决策:**
|
|
294
294
|
|
|
295
|
-
-
|
|
295
|
+
- 无数据库——所有持久化状态均存储在纯文本文件中(`~/.failproofai/`、`~/.claude/projects/`)。
|
|
296
296
|
- 变更操作使用 Server Actions——CRUD 操作无需 REST API。
|
|
297
|
-
- 读取页面使用 React Server Components
|
|
297
|
+
- 读取页面使用 React Server Components——更快的首次加载,数据获取无需客户端 bundle。
|
|
298
298
|
- 仅在需要交互的地方使用客户端组件(策略切换、活动搜索、日志查看器)。
|
|
299
299
|
|
|
300
300
|
---
|
|
301
301
|
|
|
302
|
-
##
|
|
302
|
+
## 文件布局
|
|
303
303
|
|
|
304
304
|
```text
|
|
305
305
|
failproofai/
|
|
306
306
|
├── bin/
|
|
307
307
|
│ └── failproofai.mjs # CLI 路由器(hook / dashboard / install 等)
|
|
308
308
|
├── src/hooks/
|
|
309
|
-
│ ├── handler.ts #
|
|
310
|
-
│ ├── builtin-policies.ts # 26
|
|
309
|
+
│ ├── handler.ts # Hook 事件流水线
|
|
310
|
+
│ ├── builtin-policies.ts # 26 个策略定义
|
|
311
311
|
│ ├── policy-evaluator.ts # 策略执行引擎
|
|
312
312
|
│ ├── policy-registry.ts # 策略注册与查找
|
|
313
313
|
│ ├── policy-types.ts # TypeScript 接口
|
|
314
|
-
│ ├── hooks-config.ts #
|
|
315
|
-
│ ├── custom-hooks-registry.ts # 基于 globalThis
|
|
316
|
-
│ ├── custom-hooks-loader.ts # 用户 JS
|
|
314
|
+
│ ├── hooks-config.ts # 多作用域配置加载
|
|
315
|
+
│ ├── custom-hooks-registry.ts # 基于 globalThis 的 Hook 注册表
|
|
316
|
+
│ ├── custom-hooks-loader.ts # 用户 JS Hook 的 ESM 加载器
|
|
317
317
|
│ ├── manager.ts # 安装 / 移除 / 列出操作
|
|
318
318
|
│ ├── install-prompt.ts # 交互式策略选择提示
|
|
319
|
-
│ ├── hook-logger.ts #
|
|
319
|
+
│ ├── hook-logger.ts # 记录日志到 hook.log
|
|
320
320
|
│ ├── hook-activity-store.ts # 将活动持久化到 hook-activity.jsonl
|
|
321
321
|
│ └── llm-client.ts # LLM API 客户端(用于 AI 驱动的策略)
|
|
322
|
-
├── app/ # Next.js
|
|
322
|
+
├── app/ # Next.js Dashboard(页面 + Server Actions)
|
|
323
323
|
├── lib/ # 共享工具库
|
|
324
324
|
│ ├── projects.ts # 从文件系统枚举 Claude 项目
|
|
325
325
|
│ ├── log-entries.ts # 解析 Claude 转录 JSONL 格式
|
|
@@ -327,6 +327,6 @@ failproofai/
|
|
|
327
327
|
│ └── ...
|
|
328
328
|
├── components/ # 共享 React UI 组件
|
|
329
329
|
├── contexts/ # React Context 提供者(主题、自动刷新、遥测)
|
|
330
|
-
├── examples/ #
|
|
331
|
-
└── __tests__/ #
|
|
330
|
+
├── examples/ # 自定义 Hook 示例文件
|
|
331
|
+
└── __tests__/ # 单元测试和 E2E 测试
|
|
332
332
|
```
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: 配置
|
|
3
|
-
description: "
|
|
3
|
+
description: "配置文件格式、三层作用域系统及合并规则"
|
|
4
4
|
icon: gear
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
failproofai 使用 JSON
|
|
7
|
+
failproofai 使用 JSON 配置文件来控制哪些策略处于激活状态、它们的行为方式,以及自定义策略的加载路径。配置设计上便于与团队共享——将其提交到代码仓库,每位开发者都能获得相同的 Agent 安全保障。
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
|
|
@@ -14,15 +14,15 @@ failproofai 使用 JSON 配置文件来控制哪些策略处于激活状态、
|
|
|
14
14
|
|
|
15
15
|
| 作用域 | 文件路径 | 用途 |
|
|
16
16
|
|-------|-----------|---------|
|
|
17
|
-
| **project
|
|
18
|
-
| **local
|
|
19
|
-
| **global
|
|
17
|
+
| **project(项目)** | `.failproofai/policies-config.json` | 仓库级设置,提交至版本控制 |
|
|
18
|
+
| **local(本地)** | `.failproofai/policies-config.local.json` | 个人仓库级覆盖,已加入 gitignore |
|
|
19
|
+
| **global(全局)** | `~/.failproofai/policies-config.json` | 适用于所有项目的用户级默认设置 |
|
|
20
20
|
|
|
21
|
-
当 failproofai 接收到 hook
|
|
21
|
+
当 failproofai 接收到 hook 事件时,会加载并合并当前工作目录下存在的全部三个文件。
|
|
22
22
|
|
|
23
23
|
### 合并规则
|
|
24
24
|
|
|
25
|
-
**`enabledPolicies`** —
|
|
25
|
+
**`enabledPolicies`** — 取三个作用域的并集。任意层级启用的策略均处于激活状态。
|
|
26
26
|
|
|
27
27
|
```text
|
|
28
28
|
project: ["block-sudo"]
|
|
@@ -32,7 +32,7 @@ global: ["block-sudo", "sanitize-api-keys"]
|
|
|
32
32
|
resolved: ["block-sudo", "block-rm-rf", "sanitize-api-keys"] ← 去重后的并集
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
-
**`policyParams`** —
|
|
35
|
+
**`policyParams`** — 对于某个策略,最先定义其参数的作用域完全生效。策略参数内部的值不会进行深度合并。
|
|
36
36
|
|
|
37
37
|
```text
|
|
38
38
|
project: block-sudo → { allowPatterns: ["sudo apt-get update"] }
|
|
@@ -46,12 +46,12 @@ project: (无 block-sudo 条目)
|
|
|
46
46
|
local: (无 block-sudo 条目)
|
|
47
47
|
global: block-sudo → { allowPatterns: ["sudo systemctl status"] }
|
|
48
48
|
|
|
49
|
-
resolved: { allowPatterns: ["sudo systemctl status"] } ←
|
|
49
|
+
resolved: { allowPatterns: ["sudo systemctl status"] } ← 回退至 global
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
-
**`customPoliciesPath`** —
|
|
52
|
+
**`customPoliciesPath`** — 最先定义它的作用域生效。
|
|
53
53
|
|
|
54
|
-
**`llm`** —
|
|
54
|
+
**`llm`** — 最先定义它的作用域生效。
|
|
55
55
|
|
|
56
56
|
---
|
|
57
57
|
|
|
@@ -96,15 +96,15 @@ resolved: { allowPatterns: ["sudo systemctl status"] } ← 向下回落到 glob
|
|
|
96
96
|
|
|
97
97
|
---
|
|
98
98
|
|
|
99
|
-
##
|
|
99
|
+
## 字段说明
|
|
100
100
|
|
|
101
101
|
### `enabledPolicies`
|
|
102
102
|
|
|
103
103
|
类型:`string[]`
|
|
104
104
|
|
|
105
|
-
|
|
105
|
+
需要启用的策略名称列表。名称必须与 `failproofai policies` 命令显示的策略标识符完全匹配。完整列表请参阅[内置策略](/zh/built-in-policies)。
|
|
106
106
|
|
|
107
|
-
|
|
107
|
+
未包含在 `enabledPolicies` 中的策略处于非激活状态,即使在 `policyParams` 中存在相应条目也不例外。
|
|
108
108
|
|
|
109
109
|
### `policyParams`
|
|
110
110
|
|
|
@@ -112,17 +112,17 @@ resolved: { allowPatterns: ["sudo systemctl status"] } ← 向下回落到 glob
|
|
|
112
112
|
|
|
113
113
|
各策略的参数覆盖配置。外层键为策略名称,内层键为策略专属参数。每个策略的可用参数详见[内置策略](/zh/built-in-policies)。
|
|
114
114
|
|
|
115
|
-
|
|
115
|
+
若某策略有参数但未指定,则使用该策略的内置默认值。未配置 `policyParams` 的用户与旧版本行为完全一致。
|
|
116
116
|
|
|
117
|
-
策略参数块中的未知键在 hook
|
|
117
|
+
策略参数块中的未知键在 hook 触发时会被静默忽略,但在执行 `failproofai policies` 时会作为警告提示。
|
|
118
118
|
|
|
119
|
-
#### `hint
|
|
119
|
+
#### `hint`(通用参数)
|
|
120
120
|
|
|
121
121
|
类型:`string`(可选)
|
|
122
122
|
|
|
123
|
-
当策略返回 deny 或 instruct
|
|
123
|
+
当策略返回 `deny` 或 `instruct` 时,附加到原因说明末尾的消息。可用于为 Claude 提供可操作的指引,而无需修改策略本身。
|
|
124
124
|
|
|
125
|
-
|
|
125
|
+
适用于所有策略类型——内置策略、自定义策略(`custom/`)、项目约定策略(`.failproofai-project/`)以及用户约定策略(`.failproofai-user/`)。
|
|
126
126
|
|
|
127
127
|
```json
|
|
128
128
|
{
|
|
@@ -141,7 +141,7 @@ resolved: { allowPatterns: ["sudo systemctl status"] } ← 向下回落到 glob
|
|
|
141
141
|
}
|
|
142
142
|
```
|
|
143
143
|
|
|
144
|
-
当 block-force-push 拒绝操作时,Claude 会看到:*"Force-pushing is blocked. Try creating a fresh branch instead."*
|
|
144
|
+
当 `block-force-push` 拒绝操作时,Claude 会看到:*"Force-pushing is blocked. Try creating a fresh branch instead."*
|
|
145
145
|
|
|
146
146
|
非字符串值和空字符串会被静默忽略。若未设置 `hint`,行为保持不变(向后兼容)。
|
|
147
147
|
|
|
@@ -149,24 +149,24 @@ resolved: { allowPatterns: ["sudo systemctl status"] } ← 向下回落到 glob
|
|
|
149
149
|
|
|
150
150
|
类型:`string`(绝对路径)
|
|
151
151
|
|
|
152
|
-
包含自定义 hook 策略的 JavaScript
|
|
152
|
+
包含自定义 hook 策略的 JavaScript 文件路径。该字段通常由 `failproofai policies --install --custom <path>` 自动设置(路径在存储前会被解析为绝对路径)。
|
|
153
153
|
|
|
154
|
-
每次 hook
|
|
154
|
+
每次 hook 事件触发时,该文件都会被重新加载,不存在缓存机制。自定义策略的编写详情请参阅[自定义策略](/zh/custom-policies)。
|
|
155
155
|
|
|
156
156
|
### 基于约定的策略
|
|
157
157
|
|
|
158
|
-
|
|
158
|
+
除了显式的 `customPoliciesPath` 之外,failproofai 还会自动发现并加载 `.failproofai/policies/` 目录中的策略文件:
|
|
159
159
|
|
|
160
|
-
|
|
|
160
|
+
| 层级 | 目录 | 作用域 |
|
|
161
161
|
|-------|-----------|-------|
|
|
162
162
|
| 项目 | `.failproofai/policies/` | 通过版本控制与团队共享 |
|
|
163
163
|
| 用户 | `~/.failproofai/policies/` | 个人级别,适用于所有项目 |
|
|
164
164
|
|
|
165
|
-
**文件匹配规则:**
|
|
165
|
+
**文件匹配规则:** 仅加载匹配 `*policies.{js,mjs,ts}` 的文件(例如 `security-policies.mjs`、`workflow-policies.js`),目录中的其他文件会被忽略。
|
|
166
166
|
|
|
167
|
-
|
|
167
|
+
**无需额外配置:** 约定策略无需在 `policies-config.json` 中添加任何条目,只需将文件放入对应目录,下次 hook 事件触发时即可自动加载。
|
|
168
168
|
|
|
169
|
-
**联合加载:**
|
|
169
|
+
**联合加载:** 项目级和用户级约定目录都会被扫描,两个层级中所有匹配的文件均会被加载(与 `customPoliciesPath` 的首个作用域优先规则不同)。
|
|
170
170
|
|
|
171
171
|
更多详情和示例请参阅[自定义策略](/zh/custom-policies)。
|
|
172
172
|
|
|
@@ -174,7 +174,7 @@ resolved: { allowPatterns: ["sudo systemctl status"] } ← 向下回落到 glob
|
|
|
174
174
|
|
|
175
175
|
类型:`object`(可选)
|
|
176
176
|
|
|
177
|
-
|
|
177
|
+
针对需要进行 AI 调用的策略的 LLM 客户端配置。大多数场景下无需配置。
|
|
178
178
|
|
|
179
179
|
```json
|
|
180
180
|
{
|
|
@@ -189,16 +189,16 @@ resolved: { allowPatterns: ["sudo systemctl status"] } ← 向下回落到 glob
|
|
|
189
189
|
|
|
190
190
|
## 通过 CLI 管理配置
|
|
191
191
|
|
|
192
|
-
`policies --install` 和 `policies --uninstall`
|
|
192
|
+
`policies --install` 和 `policies --uninstall` 命令写入的是 Claude Code 的 `settings.json`(即 hook 入口点),而 `policies-config.json` 则是由您直接管理的文件。两者相互独立:
|
|
193
193
|
|
|
194
|
-
- **`settings.json`** —
|
|
195
|
-
- **`policies-config.json`** —
|
|
194
|
+
- **`settings.json`** — 指示 Claude Code 在每次工具调用时执行 `failproofai --hook <event>`
|
|
195
|
+
- **`policies-config.json`** — 指示 failproofai 评估哪些策略以及使用哪些参数
|
|
196
196
|
|
|
197
|
-
|
|
197
|
+
您可以随时直接编辑 `policies-config.json`,更改将在下一次 hook 事件时立即生效,无需重启。
|
|
198
198
|
|
|
199
199
|
---
|
|
200
200
|
|
|
201
|
-
##
|
|
201
|
+
## 示例:包含团队默认设置的项目级配置
|
|
202
202
|
|
|
203
203
|
将 `.failproofai/policies-config.json` 提交到代码仓库:
|
|
204
204
|
|
|
@@ -219,4 +219,4 @@ resolved: { allowPatterns: ["sudo systemctl status"] } ← 向下回落到 glob
|
|
|
219
219
|
}
|
|
220
220
|
```
|
|
221
221
|
|
|
222
|
-
|
|
222
|
+
每位开发者可以创建 `.failproofai/policies-config.local.json`(已加入 gitignore)来进行个人级别的覆盖,而不会影响其他团队成员。
|