failproofai 0.0.5 → 0.0.6-beta.0
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/workflow-policies.mjs +2 -1
- 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]__0a~g15g._.js → [root-of-the-server]__0.~fd7s._.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]__0qn95h3._.js → [root-of-the-server]__0a.nuas._.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]__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/{09ikntpt2-o9b.js → 0.z51twd.0l5z.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0sme4lkv.tgn-.js → 0hctoh28rg838.js} +1 -1
- package/.next/standalone/.next/static/chunks/{13juklu.vksks.js → 0hplx-8c-4vpv.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0em7tspi4kylh.js → 0maq.q1t.ri85.js} +2 -2
- package/.next/standalone/.next/static/chunks/{17manv47o-~wp.js → 0teq8wdh3po1n.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0lgbwkfqmnsmc.js → 0uc0um_uz51m_.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0yumumfzx_f27.js → 0ul6fk-z.6k-0.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0_yayar~bpphd.js → 0w9lwqy0-v1dk.js} +1 -1
- package/.next/standalone/CHANGELOG.md +5 -0
- package/.next/standalone/dist/cli.mjs +19 -2
- 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/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/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/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/package.json +1 -1
- package/.next/standalone/server.js +1 -1
- package/.next/standalone/src/hooks/builtin-policies.ts +30 -0
- package/dist/cli.mjs +19 -2
- package/package.json +1 -1
- package/src/hooks/builtin-policies.ts +30 -0
- /package/.next/standalone/.next/static/{hYQM6iCWnF1W5XDpsIRhV → 8mygPGI5bzrtWK36ZYO59}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{hYQM6iCWnF1W5XDpsIRhV → 8mygPGI5bzrtWK36ZYO59}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{hYQM6iCWnF1W5XDpsIRhV → 8mygPGI5bzrtWK36ZYO59}/_ssgManifest.js +0 -0
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: 커스텀 정책
|
|
3
|
-
description: "JavaScript로
|
|
3
|
+
description: "JavaScript로 나만의 정책을 작성하세요 - 컨벤션 강제, 드리프트 방지, 실패 감지, 외부 시스템 연동 등"
|
|
4
4
|
icon: code
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
커스텀 정책을 사용하면 에이전트 동작에 대한 규칙을 직접 작성할 수
|
|
7
|
+
커스텀 정책을 사용하면 에이전트 동작에 대한 규칙을 직접 작성할 수 있습니다: 프로젝트 컨벤션 강제, 드리프트 방지, 위험한 작업 차단, 멈춘 에이전트 감지, Slack 연동, 승인 워크플로우 연동 등 다양한 용도로 활용할 수 있습니다. 빌트인 정책과 동일한 훅 이벤트 시스템과 `allow`, `deny`, `instruct` 결정 방식을 사용합니다.
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
## 빠른
|
|
11
|
+
## 빠른 예시
|
|
12
12
|
|
|
13
13
|
```js
|
|
14
14
|
// my-policies.js
|
|
@@ -37,30 +37,30 @@ failproofai policies --install --custom ./my-policies.js
|
|
|
37
37
|
|
|
38
38
|
---
|
|
39
39
|
|
|
40
|
-
## 커스텀 정책을
|
|
40
|
+
## 커스텀 정책을 로드하는 두 가지 방법
|
|
41
41
|
|
|
42
42
|
### 방법 1: 컨벤션 기반 (권장)
|
|
43
43
|
|
|
44
|
-
`.failproofai/policies/` 디렉터리에 `*policies.{js,mjs,ts}` 파일을
|
|
44
|
+
`.failproofai/policies/` 디렉터리에 `*policies.{js,mjs,ts}` 파일을 넣기만 하면 자동으로 로드됩니다 — 별도의 플래그나 설정 변경이 필요 없습니다. git 훅처럼 파일만 넣으면 바로 동작합니다.
|
|
45
45
|
|
|
46
46
|
```
|
|
47
|
-
# 프로젝트 레벨 — git에 커밋되어
|
|
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}` 패턴에 맞는 파일만
|
|
59
|
-
- 각 파일은 독립적으로
|
|
60
|
-
- 명시적 `--custom` 및
|
|
56
|
+
- 프로젝트 디렉터리와 사용자 디렉터리를 모두 스캔합니다 (합집합 방식 — 스코프 우선순위 방식 아님)
|
|
57
|
+
- 각 디렉터리 내에서 파일은 알파벳 순서로 로드됩니다. 순서를 제어하려면 `01-`, `02-` 등의 접두사를 사용하세요
|
|
58
|
+
- `*policies.{js,mjs,ts}` 패턴에 맞는 파일만 로드되며, 그 외 파일은 무시됩니다
|
|
59
|
+
- 각 파일은 독립적으로 로드됩니다 (파일별 fail-open)
|
|
60
|
+
- 명시적 `--custom` 및 빌트인 정책과 함께 사용할 수 있습니다
|
|
61
61
|
|
|
62
62
|
<Tip>
|
|
63
|
-
컨벤션 정책은 팀 전체에 정책을 공유하는 가장 쉬운 방법입니다. `.failproofai/policies/`를 git에 커밋하면
|
|
63
|
+
컨벤션 정책은 팀 전체에 정책을 공유하는 가장 쉬운 방법입니다. `.failproofai/policies/`를 git에 커밋하면 모든 팀원이 자동으로 적용받습니다.
|
|
64
64
|
</Tip>
|
|
65
65
|
|
|
66
66
|
### 방법 2: 명시적 파일 경로
|
|
@@ -76,11 +76,11 @@ failproofai policies --install --custom ./new-policies.js
|
|
|
76
76
|
failproofai policies --uninstall --custom
|
|
77
77
|
```
|
|
78
78
|
|
|
79
|
-
|
|
79
|
+
변환된 절대 경로는 `policies-config.json`의 `customPoliciesPath`에 저장됩니다. 파일은 매 훅 이벤트마다 새로 로드됩니다 - 이벤트 간 캐싱은 없습니다.
|
|
80
80
|
|
|
81
81
|
### 두 방법 함께 사용하기
|
|
82
82
|
|
|
83
|
-
컨벤션 정책과 명시적 `--custom` 파일은 함께 사용할 수 있습니다.
|
|
83
|
+
컨벤션 정책과 명시적 `--custom` 파일은 함께 사용할 수 있습니다. 로드 순서:
|
|
84
84
|
|
|
85
85
|
1. 명시적 `customPoliciesPath` 파일 (설정된 경우)
|
|
86
86
|
2. 프로젝트 컨벤션 파일 (`{cwd}/.failproofai/policies/`, 알파벳 순)
|
|
@@ -90,7 +90,7 @@ failproofai policies --uninstall --custom
|
|
|
90
90
|
|
|
91
91
|
## API
|
|
92
92
|
|
|
93
|
-
###
|
|
93
|
+
### 임포트
|
|
94
94
|
|
|
95
95
|
```js
|
|
96
96
|
import { customPolicies, allow, deny, instruct } from "failproofai";
|
|
@@ -98,13 +98,13 @@ 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({
|
|
105
105
|
name: string; // 필수 - 고유 식별자
|
|
106
106
|
description?: string; // `failproofai policies` 출력에 표시됨
|
|
107
|
-
match?: { events?: HookEventType[] }; // 이벤트
|
|
107
|
+
match?: { events?: HookEventType[] }; // 이벤트 타입으로 필터링; 생략 시 모든 이벤트에 매칭
|
|
108
108
|
fn: (ctx: PolicyContext) => PolicyResult | Promise<PolicyResult>;
|
|
109
109
|
});
|
|
110
110
|
```
|
|
@@ -113,31 +113,30 @@ customPolicies.add({
|
|
|
113
113
|
|
|
114
114
|
| 함수 | 효과 | 사용 시점 |
|
|
115
115
|
|----------|--------|----------|
|
|
116
|
-
| `allow()` | 조용히 작업을 허용 |
|
|
117
|
-
| `deny(message)` | 작업을 차단 | 에이전트가
|
|
118
|
-
| `instruct(message)` | 차단 없이 컨텍스트 추가 | 에이전트가 올바른 방향을 유지하도록 추가
|
|
116
|
+
| `allow()` | 조용히 작업을 허용 | 동작이 안전하고 메시지가 필요 없을 때 |
|
|
117
|
+
| `deny(message)` | 작업을 차단 | 에이전트가 이 동작을 수행해서는 안 될 때 |
|
|
118
|
+
| `instruct(message)` | 차단 없이 컨텍스트 추가 | 에이전트가 올바른 방향을 유지하도록 추가 컨텍스트를 제공할 때 |
|
|
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` 필드를 추가하면 코드 변경 없이 `deny` 또는 `instruct` 메시지에 추가
|
|
125
|
+
`policyParams`의 `hint` 필드를 추가하면 코드 변경 없이 `deny` 또는 `instruct` 메시지에 추가 가이던스를 붙일 수 있습니다. 커스텀(`custom/`), 프로젝트 컨벤션(`.failproofai-project/`), 사용자 컨벤션(`.failproofai-user/`) 정책 모두에서 동작합니다. 자세한 내용은 [설정 → hint](/ko/configuration#hint-cross-cutting)를 참조하세요.
|
|
126
126
|
</Tip>
|
|
127
127
|
|
|
128
128
|
### 정보성 allow 메시지
|
|
129
129
|
|
|
130
|
-
|
|
131
|
-
`allow(message)`는 작업을 허용하면서 **동시에** 정보성 메시지를 Claude에게 전달합니다. 메시지는 훅 핸들러의 stdout 응답에서 `additionalContext`로 전달됩니다 — `instruct`와 동일한 메커니즘이지만, 의미적으로 다릅니다. 이는 경고가 아닌 상태 업데이트입니다.
|
|
130
|
+
`allow(message)`는 작업을 허용하면서 **동시에** Claude에게 정보성 메시지를 전달합니다. 메시지는 훅 핸들러의 stdout 응답에서 `additionalContext`로 전달되며, `instruct`와 동일한 메커니즘을 사용하지만 의미상 다릅니다: 경고가 아닌 상태 업데이트입니다.
|
|
132
131
|
|
|
133
132
|
| 함수 | 효과 | 사용 시점 |
|
|
134
133
|
|----------|--------|----------|
|
|
135
134
|
| `allow(message)` | 허용하면서 Claude에게 컨텍스트 전달 | 검사가 통과되었음을 확인하거나, 검사가 건너뛰어진 이유를 설명할 때 |
|
|
136
135
|
|
|
137
|
-
|
|
138
|
-
- **상태 확인:** `allow("All CI checks passed.")` — 모든 것이 정상임을
|
|
139
|
-
- **Fail-open 설명:** `allow("GitHub CLI not installed, skipping CI check.")` —
|
|
140
|
-
- **다중 메시지 누적:** 여러 정책이 각각 `allow(message)`를 반환하면 모든 메시지가 줄바꿈으로
|
|
136
|
+
활용 예시:
|
|
137
|
+
- **상태 확인:** `allow("All CI checks passed.")` — Claude에게 모든 것이 정상임을 알림
|
|
138
|
+
- **Fail-open 설명:** `allow("GitHub CLI not installed, skipping CI check.")` — Claude가 완전한 컨텍스트를 갖도록 검사가 건너뛰어진 이유를 알림
|
|
139
|
+
- **다중 메시지 누적:** 여러 정책이 각각 `allow(message)`를 반환하면 모든 메시지가 줄바꿈으로 연결되어 함께 전달됩니다
|
|
141
140
|
|
|
142
141
|
```js
|
|
143
142
|
customPolicies.add({
|
|
@@ -161,9 +160,9 @@ customPolicies.add({
|
|
|
161
160
|
| 필드 | 타입 | 설명 |
|
|
162
161
|
|-------|------|-------------|
|
|
163
162
|
| `eventType` | `string` | `"PreToolUse"`, `"PostToolUse"`, `"Notification"`, `"Stop"` |
|
|
164
|
-
| `toolName` | `string \| undefined` | 호출되는
|
|
165
|
-
| `toolInput` | `Record<string, unknown> \| undefined` |
|
|
166
|
-
| `payload` | `Record<string, unknown>` | Claude Code
|
|
163
|
+
| `toolName` | `string \| undefined` | 호출되는 툴 (예: `"Bash"`, `"Write"`, `"Read"`) |
|
|
164
|
+
| `toolInput` | `Record<string, unknown> \| undefined` | 툴의 입력 파라미터 |
|
|
165
|
+
| `payload` | `Record<string, unknown>` | Claude Code로부터의 전체 원시 이벤트 페이로드 |
|
|
167
166
|
| `session` | `SessionMetadata \| undefined` | 세션 컨텍스트 (아래 참조) |
|
|
168
167
|
|
|
169
168
|
### `SessionMetadata` 필드
|
|
@@ -174,14 +173,14 @@ customPolicies.add({
|
|
|
174
173
|
| `cwd` | `string` | Claude Code 세션의 작업 디렉터리 |
|
|
175
174
|
| `transcriptPath` | `string` | 세션의 JSONL 트랜스크립트 파일 경로 |
|
|
176
175
|
|
|
177
|
-
### 이벤트
|
|
176
|
+
### 이벤트 타입
|
|
178
177
|
|
|
179
178
|
| 이벤트 | 발생 시점 | `toolInput` 내용 |
|
|
180
179
|
|-------|--------------|----------------------|
|
|
181
|
-
| `PreToolUse` | Claude가
|
|
182
|
-
| `PostToolUse` |
|
|
183
|
-
| `Notification` | Claude가 알림을 보낼 때 | `{ message: "...", notification_type: "idle" \| "permission_prompt" \| ... }` - 훅은 항상 `allow()`를 반환해야
|
|
184
|
-
| `Stop` | Claude
|
|
180
|
+
| `PreToolUse` | Claude가 툴을 실행하기 전 | 툴의 입력 (예: Bash의 경우 `{ command: "..." }`) |
|
|
181
|
+
| `PostToolUse` | 툴 실행 완료 후 | 툴의 입력 + `tool_result` (출력) |
|
|
182
|
+
| `Notification` | Claude가 알림을 보낼 때 | `{ message: "...", notification_type: "idle" \| "permission_prompt" \| ... }` - 훅은 항상 `allow()`를 반환해야 하며, 알림을 차단할 수 없습니다 |
|
|
183
|
+
| `Stop` | Claude 세션이 종료될 때 | 비어 있음 |
|
|
185
184
|
|
|
186
185
|
---
|
|
187
186
|
|
|
@@ -189,20 +188,20 @@ customPolicies.add({
|
|
|
189
188
|
|
|
190
189
|
정책은 다음 순서로 평가됩니다:
|
|
191
190
|
|
|
192
|
-
1.
|
|
193
|
-
2. `customPoliciesPath`의 명시적 커스텀 정책 (`.add()`
|
|
194
|
-
3. 프로젝트 `.failproofai/policies/`의 컨벤션 정책 (
|
|
195
|
-
4. 사용자 `~/.failproofai/policies/`의 컨벤션 정책 (
|
|
191
|
+
1. 빌트인 정책 (정의 순서)
|
|
192
|
+
2. `customPoliciesPath`의 명시적 커스텀 정책 (`.add()` 순서)
|
|
193
|
+
3. 프로젝트 `.failproofai/policies/`의 컨벤션 정책 (파일 알파벳 순, 파일 내 `.add()` 순서)
|
|
194
|
+
4. 사용자 `~/.failproofai/policies/`의 컨벤션 정책 (파일 알파벳 순, 파일 내 `.add()` 순서)
|
|
196
195
|
|
|
197
196
|
<Note>
|
|
198
|
-
첫 번째 `deny
|
|
197
|
+
첫 번째 `deny`가 이후 모든 정책 평가를 중단시킵니다. 모든 `instruct` 메시지는 누적되어 함께 전달됩니다.
|
|
199
198
|
</Note>
|
|
200
199
|
|
|
201
200
|
---
|
|
202
201
|
|
|
203
|
-
## 전이적
|
|
202
|
+
## 전이적 임포트
|
|
204
203
|
|
|
205
|
-
커스텀 정책 파일은 상대 경로를
|
|
204
|
+
커스텀 정책 파일은 상대 경로를 사용하여 로컬 모듈을 임포트할 수 있습니다:
|
|
206
205
|
|
|
207
206
|
```js
|
|
208
207
|
// my-policies.js
|
|
@@ -219,46 +218,46 @@ customPolicies.add({
|
|
|
219
218
|
});
|
|
220
219
|
```
|
|
221
220
|
|
|
222
|
-
엔트리 파일에서 도달 가능한 모든 상대
|
|
221
|
+
엔트리 파일에서 도달 가능한 모든 상대 임포트가 해석됩니다. 이는 `from "failproofai"` 임포트를 실제 dist 경로로 재작성하고 ESM 호환성을 보장하기 위해 임시 `.mjs` 파일을 생성하는 방식으로 구현됩니다.
|
|
223
222
|
|
|
224
223
|
---
|
|
225
224
|
|
|
226
|
-
## 이벤트
|
|
225
|
+
## 이벤트 타입 필터링
|
|
227
226
|
|
|
228
|
-
`match.events`를
|
|
227
|
+
`match.events`를 사용하여 정책이 발동되는 시점을 제한합니다:
|
|
229
228
|
|
|
230
229
|
```js
|
|
231
230
|
customPolicies.add({
|
|
232
231
|
name: "require-summary-on-stop",
|
|
233
232
|
match: { events: ["Stop"] },
|
|
234
233
|
fn: async (ctx) => {
|
|
235
|
-
// 세션이 종료될 때만
|
|
236
|
-
// ctx.session.transcriptPath에 전체 세션 로그가
|
|
234
|
+
// 세션이 종료될 때만 발동됨
|
|
235
|
+
// ctx.session.transcriptPath에 전체 세션 로그가 있음
|
|
237
236
|
return allow();
|
|
238
237
|
},
|
|
239
238
|
});
|
|
240
239
|
```
|
|
241
240
|
|
|
242
|
-
`match`를 완전히 생략하면 모든 이벤트
|
|
241
|
+
`match`를 완전히 생략하면 모든 이벤트 타입에서 발동됩니다.
|
|
243
242
|
|
|
244
243
|
---
|
|
245
244
|
|
|
246
|
-
##
|
|
245
|
+
## 에러 처리 및 실패 모드
|
|
247
246
|
|
|
248
|
-
커스텀 정책은 **fail-open** 방식입니다:
|
|
247
|
+
커스텀 정책은 **fail-open** 방식입니다: 에러가 발생해도 빌트인 정책이 차단되거나 훅 핸들러가 크래시되지 않습니다.
|
|
249
248
|
|
|
250
249
|
| 실패 상황 | 동작 |
|
|
251
250
|
|---------|----------|
|
|
252
|
-
| `customPoliciesPath` 미설정 | 명시적 커스텀 정책이 실행되지 않음; 컨벤션 정책과
|
|
253
|
-
|
|
|
254
|
-
|
|
|
255
|
-
|
|
|
256
|
-
| `fn` 런타임
|
|
257
|
-
| `fn
|
|
258
|
-
| 컨벤션 디렉터리 없음 | 컨벤션 정책 실행 안 됨;
|
|
251
|
+
| `customPoliciesPath` 미설정 | 명시적 커스텀 정책이 실행되지 않음; 컨벤션 정책과 빌트인은 정상 계속 |
|
|
252
|
+
| 파일 없음 | `~/.failproofai/hook.log`에 경고 기록; 빌트인 계속 |
|
|
253
|
+
| 문법/임포트 에러 (명시적) | `~/.failproofai/hook.log`에 에러 기록; 명시적 커스텀 정책 건너뜀 |
|
|
254
|
+
| 문법/임포트 에러 (컨벤션) | 에러 기록; 해당 파일 건너뜀, 다른 컨벤션 파일은 계속 로드 |
|
|
255
|
+
| `fn` 런타임 에러 | 에러 기록; 해당 훅은 `allow`로 처리; 다른 훅은 계속 |
|
|
256
|
+
| `fn`이 10초 초과 | 타임아웃 기록; `allow`로 처리 |
|
|
257
|
+
| 컨벤션 디렉터리 없음 | 컨벤션 정책 실행 안 됨; 에러 없음 |
|
|
259
258
|
|
|
260
259
|
<Tip>
|
|
261
|
-
커스텀 정책
|
|
260
|
+
커스텀 정책 에러를 디버깅하려면 로그 파일을 모니터링하세요:
|
|
262
261
|
|
|
263
262
|
```bash
|
|
264
263
|
tail -f ~/.failproofai/hook.log
|
|
@@ -267,7 +266,7 @@ tail -f ~/.failproofai/hook.log
|
|
|
267
266
|
|
|
268
267
|
---
|
|
269
268
|
|
|
270
|
-
## 전체
|
|
269
|
+
## 전체 예시: 다중 정책
|
|
271
270
|
|
|
272
271
|
```js
|
|
273
272
|
// my-policies.js
|
|
@@ -286,7 +285,7 @@ customPolicies.add({
|
|
|
286
285
|
},
|
|
287
286
|
});
|
|
288
287
|
|
|
289
|
-
// 에이전트가 올바른
|
|
288
|
+
// 에이전트가 올바른 방향을 유지하도록: 커밋 전 테스트 확인
|
|
290
289
|
customPolicies.add({
|
|
291
290
|
name: "remind-test-before-commit",
|
|
292
291
|
description: "Keep the agent on track: verify tests pass before committing",
|
|
@@ -301,7 +300,7 @@ customPolicies.add({
|
|
|
301
300
|
},
|
|
302
301
|
});
|
|
303
302
|
|
|
304
|
-
//
|
|
303
|
+
// 동결 기간 중 계획되지 않은 의존성 변경 방지
|
|
305
304
|
customPolicies.add({
|
|
306
305
|
name: "dependency-freeze",
|
|
307
306
|
description: "Prevent unplanned dependency changes during freeze period",
|
|
@@ -322,24 +321,24 @@ export { customPolicies };
|
|
|
322
321
|
|
|
323
322
|
---
|
|
324
323
|
|
|
325
|
-
##
|
|
324
|
+
## 예시 파일
|
|
326
325
|
|
|
327
|
-
`examples/` 디렉터리에는 바로 실행 가능한 정책
|
|
326
|
+
`examples/` 디렉터리에는 바로 실행 가능한 정책 파일들이 있습니다:
|
|
328
327
|
|
|
329
328
|
| 파일 | 내용 |
|
|
330
329
|
|------|----------|
|
|
331
330
|
| `examples/policies-basic.js` | 일반적인 에이전트 실패 모드를 다루는 5가지 기본 정책 |
|
|
332
|
-
| `examples/policies-advanced/index.js` | 고급 패턴: 전이적
|
|
333
|
-
| `examples/convention-policies/security-policies.mjs` | 컨벤션 기반 보안 정책 (.env 쓰기 차단, git 히스토리 재작성 방지) |
|
|
334
|
-
| `examples/convention-policies/workflow-policies.mjs` | 컨벤션 기반 워크플로우 정책 (테스트
|
|
331
|
+
| `examples/policies-advanced/index.js` | 고급 패턴: 전이적 임포트, 비동기 호출, 출력 스크러빙, 세션 종료 훅 |
|
|
332
|
+
| `examples/convention-policies/security-policies.mjs` | 컨벤션 기반 보안 정책 (.env 파일 쓰기 차단, git 히스토리 재작성 방지) |
|
|
333
|
+
| `examples/convention-policies/workflow-policies.mjs` | 컨벤션 기반 워크플로우 정책 (테스트 리마인더, 파일 쓰기 감사) |
|
|
335
334
|
|
|
336
|
-
### 명시적 파일
|
|
335
|
+
### 명시적 파일 예시 사용
|
|
337
336
|
|
|
338
337
|
```bash
|
|
339
338
|
failproofai policies --install --custom ./examples/policies-basic.js
|
|
340
339
|
```
|
|
341
340
|
|
|
342
|
-
### 컨벤션 기반
|
|
341
|
+
### 컨벤션 기반 예시 사용
|
|
343
342
|
|
|
344
343
|
```bash
|
|
345
344
|
# 프로젝트 레벨로 복사
|
|
@@ -351,4 +350,4 @@ mkdir -p ~/.failproofai/policies
|
|
|
351
350
|
cp examples/convention-policies/*.mjs ~/.failproofai/policies/
|
|
352
351
|
```
|
|
353
352
|
|
|
354
|
-
설치
|
|
353
|
+
설치 명령어가 필요 없습니다 — 다음 훅 이벤트 시 파일이 자동으로 감지됩니다.
|
|
@@ -12,18 +12,18 @@ Este documento explica como o failproofai funciona internamente: como o sistema
|
|
|
12
12
|
|
|
13
13
|
O failproofai possui dois subsistemas independentes:
|
|
14
14
|
|
|
15
|
-
1. **
|
|
15
|
+
1. **Handler de hooks** - Um subprocesso CLI rápido que o Claude Code invoca em cada chamada de ferramenta do agente. Avalia as políticas e retorna uma decisão.
|
|
16
16
|
2. **Monitor de Agentes (Dashboard)** - Uma aplicação web Next.js para monitorar sessões de agentes e gerenciar políticas.
|
|
17
17
|
|
|
18
18
|
Ambos os subsistemas compartilham arquivos de configuração em `~/.failproofai/` e no diretório `.failproofai/` do projeto, mas são executados como processos separados e se comunicam apenas pelo sistema de arquivos.
|
|
19
19
|
|
|
20
20
|
---
|
|
21
21
|
|
|
22
|
-
##
|
|
22
|
+
## Handler de hooks
|
|
23
23
|
|
|
24
24
|
### Integração com o Claude Code
|
|
25
25
|
|
|
26
|
-
Quando você executa `failproofai policies --install`, ele escreve entradas como esta
|
|
26
|
+
Quando você executa `failproofai policies --install`, ele escreve entradas como esta no `~/.claude/settings.json`:
|
|
27
27
|
|
|
28
28
|
```json
|
|
29
29
|
{
|
|
@@ -44,7 +44,7 @@ Quando você executa `failproofai policies --install`, ele escreve entradas como
|
|
|
44
44
|
}
|
|
45
45
|
```
|
|
46
46
|
|
|
47
|
-
O Claude Code então invoca `failproofai --hook PreToolUse` como subprocesso antes de cada chamada de ferramenta, passando um payload JSON via stdin.
|
|
47
|
+
O Claude Code então invoca `failproofai --hook PreToolUse` como um subprocesso antes de cada chamada de ferramenta, passando um payload JSON via stdin.
|
|
48
48
|
|
|
49
49
|
### Formato do payload
|
|
50
50
|
|
|
@@ -62,11 +62,11 @@ O Claude Code então invoca `failproofai --hook PreToolUse` como subprocesso ant
|
|
|
62
62
|
|
|
63
63
|
Para eventos `PostToolUse`, o payload também contém `tool_result` com a saída da ferramenta.
|
|
64
64
|
|
|
65
|
-
O handler
|
|
65
|
+
O handler aplica um limite de 1 MB para o stdin. Payloads que excedam esse limite são descartados e todas as políticas implicitamente permitem a operação.
|
|
66
66
|
|
|
67
67
|
### Formato da resposta
|
|
68
68
|
|
|
69
|
-
**
|
|
69
|
+
**Negar (PreToolUse):**
|
|
70
70
|
```json
|
|
71
71
|
{
|
|
72
72
|
"hookSpecificOutput": {
|
|
@@ -76,7 +76,7 @@ O handler impõe um limite de 1 MB para stdin. Payloads que excedam esse tamanho
|
|
|
76
76
|
}
|
|
77
77
|
```
|
|
78
78
|
|
|
79
|
-
**
|
|
79
|
+
**Negar (PostToolUse):**
|
|
80
80
|
```json
|
|
81
81
|
{
|
|
82
82
|
"hookSpecificOutput": {
|
|
@@ -85,7 +85,7 @@ O handler impõe um limite de 1 MB para stdin. Payloads que excedam esse tamanho
|
|
|
85
85
|
}
|
|
86
86
|
```
|
|
87
87
|
|
|
88
|
-
**
|
|
88
|
+
**Instruir (qualquer evento exceto Stop):**
|
|
89
89
|
```json
|
|
90
90
|
{
|
|
91
91
|
"hookSpecificOutput": {
|
|
@@ -94,17 +94,17 @@ O handler impõe um limite de 1 MB para stdin. Payloads que excedam esse tamanho
|
|
|
94
94
|
}
|
|
95
95
|
```
|
|
96
96
|
|
|
97
|
-
**
|
|
97
|
+
**Instruir em evento Stop:**
|
|
98
98
|
- Código de saída: `2`
|
|
99
|
-
- Motivo escrito
|
|
99
|
+
- Motivo escrito no stderr (não no stdout)
|
|
100
100
|
|
|
101
|
-
**
|
|
101
|
+
**Permitir:**
|
|
102
102
|
- Código de saída: `0`
|
|
103
103
|
- stdout vazio
|
|
104
104
|
|
|
105
|
-
**
|
|
105
|
+
**Permitir com mensagem:**
|
|
106
106
|
|
|
107
|
-
`allow(message)` permite que uma política envie contexto informativo de volta ao Claude mesmo quando a operação é permitida. O
|
|
107
|
+
`allow(message)` permite que uma política envie contexto informativo de volta ao Claude mesmo quando a operação é permitida. O handler de hooks escreve o seguinte JSON no **stdout** (não em um arquivo de configuração — esta é a resposta do handler ao Claude Code, assim como as respostas de deny e instruct acima):
|
|
108
108
|
|
|
109
109
|
```json
|
|
110
110
|
// Written to stdout by the hook handler process
|
|
@@ -115,8 +115,8 @@ O handler impõe um limite de 1 MB para stdin. Payloads que excedam esse tamanho
|
|
|
115
115
|
}
|
|
116
116
|
```
|
|
117
117
|
- Código de saída: `0` (a operação é permitida)
|
|
118
|
-
- Quando múltiplas políticas retornam `allow` com uma mensagem,
|
|
119
|
-
- Se nenhuma política fornecer uma mensagem, stdout fica vazio (
|
|
118
|
+
- Quando múltiplas políticas retornam `allow` com uma mensagem, as mensagens são unidas com quebras de linha em uma única string `additionalContext`
|
|
119
|
+
- Se nenhuma política fornecer uma mensagem, o stdout fica vazio (como antes)
|
|
120
120
|
|
|
121
121
|
### Pipeline de processamento
|
|
122
122
|
|
|
@@ -139,7 +139,7 @@ stdin JSON
|
|
|
139
139
|
→ exit
|
|
140
140
|
```
|
|
141
141
|
|
|
142
|
-
Todo o processo é executado em menos de 100ms para payloads típicos, sem nenhuma chamada a
|
|
142
|
+
Todo o processo é executado em menos de 100ms para payloads típicos, sem nenhuma chamada a LLM.
|
|
143
143
|
|
|
144
144
|
---
|
|
145
145
|
|
|
@@ -154,12 +154,12 @@ Todo o processo é executado em menos de 100ms para payloads típicos, sem nenhu
|
|
|
154
154
|
```
|
|
155
155
|
|
|
156
156
|
Lógica de mesclagem:
|
|
157
|
-
- `enabledPolicies` - união
|
|
158
|
-
- `policyParams` - por chave de política, o primeiro arquivo que a define
|
|
159
|
-
- `customPoliciesPath` - o primeiro arquivo que
|
|
160
|
-
- `llm` - o primeiro arquivo que
|
|
157
|
+
- `enabledPolicies` - união deduplicada entre os três arquivos
|
|
158
|
+
- `policyParams` - por chave de política, o primeiro arquivo que a define prevalece inteiramente
|
|
159
|
+
- `customPoliciesPath` - o primeiro arquivo que o define prevalece
|
|
160
|
+
- `llm` - o primeiro arquivo que o define prevalece
|
|
161
161
|
|
|
162
|
-
O dashboard web
|
|
162
|
+
O dashboard web usa `readHooksConfig()` (somente global) para leitura e escrita, pois não é invocado com um cwd de projeto.
|
|
163
163
|
|
|
164
164
|
---
|
|
165
165
|
|
|
@@ -169,24 +169,24 @@ O dashboard web utiliza `readHooksConfig()` (somente global) para leitura e escr
|
|
|
169
169
|
|
|
170
170
|
Para cada política:
|
|
171
171
|
|
|
172
|
-
1. Busca o
|
|
172
|
+
1. Busca o schema de `params` da política (se houver).
|
|
173
173
|
2. Lê `policyParams[policy.name]` da configuração mesclada.
|
|
174
|
-
3. Mescla os valores fornecidos pelo usuário sobre os padrões do
|
|
174
|
+
3. Mescla os valores fornecidos pelo usuário sobre os padrões do schema para produzir `ctx.params`.
|
|
175
175
|
4. Chama `policy.fn(ctx)` com o contexto resolvido.
|
|
176
|
-
5. Se o resultado for `deny`,
|
|
176
|
+
5. Se o resultado for `deny`, para imediatamente e retorna essa decisão.
|
|
177
177
|
6. Se o resultado for `instruct`, acumula a mensagem e continua.
|
|
178
178
|
7. Se o resultado for `allow`, continua para a próxima política.
|
|
179
179
|
|
|
180
180
|
Após todas as políticas serem executadas:
|
|
181
181
|
- Se algum `deny` foi retornado, emite a resposta de deny.
|
|
182
|
-
- Se algum retorno `instruct` foi coletado, emite uma única resposta instruct com todas as mensagens unidas.
|
|
183
|
-
- Caso contrário, emite uma resposta allow (stdout vazio,
|
|
182
|
+
- Se algum retorno `instruct` foi coletado, emite uma única resposta de instruct com todas as mensagens unidas.
|
|
183
|
+
- Caso contrário, emite uma resposta de allow (stdout vazio, exit 0).
|
|
184
184
|
|
|
185
185
|
---
|
|
186
186
|
|
|
187
|
-
## Políticas
|
|
187
|
+
## Políticas integradas
|
|
188
188
|
|
|
189
|
-
`src/hooks/builtin-policies.ts` define todas as 26 políticas
|
|
189
|
+
`src/hooks/builtin-policies.ts` define todas as 26 políticas integradas como objetos `BuiltinPolicyDefinition`:
|
|
190
190
|
|
|
191
191
|
```typescript
|
|
192
192
|
interface BuiltinPolicyDefinition {
|
|
@@ -206,11 +206,11 @@ interface BuiltinPolicyDefinition {
|
|
|
206
206
|
|
|
207
207
|
Políticas que aceitam `params` declaram um `PolicyParamsSchema` com tipos e valores padrão para cada parâmetro. O avaliador de políticas injeta os valores resolvidos em `ctx.params` antes de chamar `fn`. As funções de política leem `ctx.params` sem verificações de nulo porque os padrões são sempre aplicados primeiro.
|
|
208
208
|
|
|
209
|
-
A correspondência de padrões dentro das políticas usa tokens de comando analisados (argv), não correspondência de strings brutas. Isso evita bypass por injeção de operadores shell (por exemplo, um padrão para `sudo systemctl status *` não pode ser
|
|
209
|
+
A correspondência de padrões dentro das políticas usa tokens de comando analisados (argv), não correspondência de strings brutas. Isso evita bypass por injeção de operadores de shell (por exemplo, um padrão para `sudo systemctl status *` não pode ser contornado adicionando `; rm -rf /` ao comando).
|
|
210
210
|
|
|
211
211
|
---
|
|
212
212
|
|
|
213
|
-
## Políticas
|
|
213
|
+
## Políticas customizadas
|
|
214
214
|
|
|
215
215
|
`src/hooks/custom-hooks-registry.ts` implementa um registro baseado em `globalThis`:
|
|
216
216
|
|
|
@@ -225,25 +225,25 @@ export function getCustomHooks(): CustomHook[] { ... }
|
|
|
225
225
|
export function clearCustomHooks(): void { ... } // used in tests
|
|
226
226
|
```
|
|
227
227
|
|
|
228
|
-
`src/hooks/custom-hooks-loader.ts` carrega o arquivo de
|
|
228
|
+
`src/hooks/custom-hooks-loader.ts` carrega o arquivo de política do usuário:
|
|
229
229
|
|
|
230
230
|
1. Lê `customPoliciesPath` da configuração; ignora se ausente.
|
|
231
231
|
2. Resolve para caminho absoluto; verifica se o arquivo existe.
|
|
232
|
-
3. Reescreve todas as importações `from "failproofai"` para o caminho real
|
|
233
|
-
4. Reescreve recursivamente importações locais transitivas para garantir compatibilidade ESM.
|
|
234
|
-
5.
|
|
232
|
+
3. Reescreve todas as importações `from "failproofai"` para o caminho real de dist, de modo que `customPolicies` resolva para o mesmo registro `globalThis`.
|
|
233
|
+
4. Reescreve recursivamente as importações locais transitivas para garantir compatibilidade com ESM.
|
|
234
|
+
5. Escreve arquivos `.mjs` temporários e faz `import()` do arquivo de entrada.
|
|
235
235
|
6. Chama `getCustomHooks()` para recuperar os hooks registrados.
|
|
236
|
-
7.
|
|
236
|
+
7. Remove todos os arquivos temporários em um bloco `finally`.
|
|
237
237
|
|
|
238
|
-
Em caso de qualquer erro (arquivo não encontrado, erro de sintaxe, falha
|
|
238
|
+
Em caso de qualquer erro (arquivo não encontrado, erro de sintaxe, falha de importação), o erro é registrado em `~/.failproofai/hook.log` e o loader retorna um array vazio. As políticas integradas não são afetadas.
|
|
239
239
|
|
|
240
|
-
As políticas
|
|
240
|
+
As políticas customizadas são avaliadas após todas as políticas integradas. Um `deny` de uma política customizada ainda interrompe as demais políticas customizadas (mas todas as políticas integradas já terão sido executadas nesse ponto).
|
|
241
241
|
|
|
242
242
|
---
|
|
243
243
|
|
|
244
|
-
##
|
|
244
|
+
## Registro de atividade
|
|
245
245
|
|
|
246
|
-
Após cada evento de hook, o handler anexa uma linha JSONL
|
|
246
|
+
Após cada evento de hook, o handler anexa uma linha JSONL ao `~/.failproofai/hook-activity.jsonl`:
|
|
247
247
|
|
|
248
248
|
```json
|
|
249
249
|
{
|
|
@@ -258,17 +258,17 @@ Após cada evento de hook, o handler anexa uma linha JSONL em `~/.failproofai/ho
|
|
|
258
258
|
}
|
|
259
259
|
```
|
|
260
260
|
|
|
261
|
-
Uma linha por política que tomou uma decisão diferente de allow. Decisões allow não são registradas (para manter o arquivo pequeno).
|
|
261
|
+
Uma linha por política que tomou uma decisão diferente de allow. Decisões de allow não são registradas (para manter o arquivo pequeno).
|
|
262
262
|
|
|
263
263
|
---
|
|
264
264
|
|
|
265
265
|
## Arquitetura do dashboard
|
|
266
266
|
|
|
267
|
-
O dashboard é uma aplicação **Next.js 16**
|
|
267
|
+
O dashboard é uma aplicação **Next.js 16** que utiliza o App Router com React Server Components e Server Actions.
|
|
268
268
|
|
|
269
269
|
```text
|
|
270
270
|
app/
|
|
271
|
-
layout.tsx ← Layout raiz (tema, telemetria,
|
|
271
|
+
layout.tsx ← Layout raiz (tema, telemetria, nav)
|
|
272
272
|
projects/page.tsx ← Server component: lista todos os projetos Claude
|
|
273
273
|
project/[name]/page.tsx ← Server component: lista sessões em um projeto
|
|
274
274
|
project/[name]/session/
|
|
@@ -277,8 +277,8 @@ app/
|
|
|
277
277
|
actions/
|
|
278
278
|
get-hooks-config.ts ← Lê configuração + lista de políticas
|
|
279
279
|
update-hooks-config.ts ← Ativa/desativa política
|
|
280
|
-
update-policy-params.ts ← Atualiza parâmetros
|
|
281
|
-
get-hook-activity.ts ←
|
|
280
|
+
update-policy-params.ts ← Atualiza parâmetros de política
|
|
281
|
+
get-hook-activity.ts ← Pagina/pesquisa log de atividade
|
|
282
282
|
install-hooks-web.ts ← Instala/remove hooks pelo navegador
|
|
283
283
|
api/
|
|
284
284
|
download/[project]/[session]/route.ts ← Exporta sessão como ZIP/JSONL
|
|
@@ -287,15 +287,15 @@ app/
|
|
|
287
287
|
**Fluxo de dados:**
|
|
288
288
|
|
|
289
289
|
- Os componentes de página chamam `lib/projects.ts` e `lib/log-entries.ts` para ler dados de projeto/sessão diretamente do sistema de arquivos (sem camada de API para leituras).
|
|
290
|
-
- A página de Políticas usa Server Actions para todas as mutações (
|
|
290
|
+
- A página de Políticas usa Server Actions para todas as mutações (toggle, atualização de parâmetros, instalação/remoção).
|
|
291
291
|
- O visualizador de sessão analisa o formato de transcrição JSONL do Claude e renderiza uma linha do tempo de mensagens e chamadas de ferramentas.
|
|
292
292
|
|
|
293
293
|
**Principais decisões de design:**
|
|
294
294
|
|
|
295
|
-
- Sem banco de dados - todo estado persistente está em arquivos simples (`~/.failproofai/`, `~/.claude/projects/`).
|
|
296
|
-
- Server Actions para mutações -
|
|
297
|
-
- React Server Components para páginas de leitura - carregamento inicial mais rápido, sem bundle
|
|
298
|
-
- Client components apenas onde interatividade é necessária (
|
|
295
|
+
- Sem banco de dados - todo o estado persistente está em arquivos simples (`~/.failproofai/`, `~/.claude/projects/`).
|
|
296
|
+
- Server Actions para mutações - nenhuma API REST necessária para operações CRUD.
|
|
297
|
+
- React Server Components para páginas de leitura - carregamento inicial mais rápido, sem bundle do cliente para busca de dados.
|
|
298
|
+
- Client components apenas onde a interatividade é necessária (toggles de política, pesquisa de atividade, visualizador de log).
|
|
299
299
|
|
|
300
300
|
---
|
|
301
301
|
|
|
@@ -313,20 +313,20 @@ failproofai/
|
|
|
313
313
|
│ ├── policy-types.ts # Interfaces TypeScript
|
|
314
314
|
│ ├── hooks-config.ts # Carregamento de configuração multi-escopo
|
|
315
315
|
│ ├── custom-hooks-registry.ts # Registro de hooks baseado em globalThis
|
|
316
|
-
│ ├── custom-hooks-loader.ts #
|
|
316
|
+
│ ├── custom-hooks-loader.ts # Loader ESM para hooks JS do usuário
|
|
317
317
|
│ ├── manager.ts # Operações de instalação / remoção / listagem
|
|
318
318
|
│ ├── install-prompt.ts # Prompt interativo de seleção de políticas
|
|
319
319
|
│ ├── hook-logger.ts # Registro em hook.log
|
|
320
|
-
│ ├── hook-activity-store.ts #
|
|
321
|
-
│ └── llm-client.ts # Cliente de API LLM (para políticas
|
|
320
|
+
│ ├── hook-activity-store.ts # Persistência de atividade em hook-activity.jsonl
|
|
321
|
+
│ └── llm-client.ts # Cliente de API LLM (para políticas baseadas em IA)
|
|
322
322
|
├── app/ # Dashboard Next.js (páginas + server actions)
|
|
323
323
|
├── lib/ # Utilitários compartilhados
|
|
324
324
|
│ ├── projects.ts # Enumera projetos Claude do sistema de arquivos
|
|
325
325
|
│ ├── log-entries.ts # Analisa o formato JSONL de transcrição do Claude
|
|
326
326
|
│ ├── paths.ts # Resolve caminhos do sistema
|
|
327
327
|
│ └── ...
|
|
328
|
-
├── components/ # Componentes React
|
|
329
|
-
├── contexts/ # Provedores de contexto React (tema,
|
|
330
|
-
├── examples/ # Exemplos de arquivos de hooks
|
|
328
|
+
├── components/ # Componentes React UI compartilhados
|
|
329
|
+
├── contexts/ # Provedores de contexto React (tema, auto-refresh, telemetria)
|
|
330
|
+
├── examples/ # Exemplos de arquivos de hooks customizados
|
|
331
331
|
└── __tests__/ # Testes unitários e E2E
|
|
332
332
|
```
|