failproofai 0.0.6-beta.0 → 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 +113 -0
- 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]__0a.nuas._.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]__0.~fd7s._.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 +6 -6
- 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/{0teq8wdh3po1n.js → 00j0rr7rh8ef8.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0maq.q1t.ri85.js → 05j1px0r8yzh6.js} +2 -2
- package/.next/standalone/.next/static/chunks/0badv41uxa56..js +4 -0
- package/.next/standalone/.next/static/chunks/{0hplx-8c-4vpv.js → 0ijk_kek9_wyx.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0uc0um_uz51m_.js → 0npb~873.wvg3.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0hctoh28rg838.js → 0xpl.oscrakvx.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0.z51twd.0l5z.js → 1052sguyd-.ka.js} +1 -1
- package/.next/standalone/.next/static/chunks/{09e7drilkf1sn.js → 12simlrcfk3g2.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0ul6fk-z.6k-0.js → 14cl9poem30dq.js} +1 -1
- package/.next/standalone/.next/static/chunks/{turbopack-0r26pc8h0y_-e.js → turbopack-0o7k.hakttp4k.js} +1 -1
- package/.next/standalone/CHANGELOG.md +19 -0
- package/.next/standalone/README.md +2 -2
- package/.next/standalone/bun.lock +43 -85
- package/.next/standalone/dist/cli.mjs +91 -4
- 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 +38 -1
- package/.next/standalone/docs/custom-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/examples.mdx +54 -0
- 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/getting-started.mdx +52 -0
- 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/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 +106 -1
- package/README.md +2 -2
- package/dist/cli.mjs +91 -4
- package/package.json +2 -2
- package/src/hooks/builtin-policies.ts +106 -1
- package/.next/standalone/.next/static/chunks/0w9lwqy0-v1dk.js +0 -4
- /package/.next/standalone/.next/static/{8mygPGI5bzrtWK36ZYO59 → A9pNTZdoYJTVyPAYwQMx5}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{8mygPGI5bzrtWK36ZYO59 → A9pNTZdoYJTVyPAYwQMx5}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{8mygPGI5bzrtWK36ZYO59 → A9pNTZdoYJTVyPAYwQMx5}/_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
|
|
@@ -41,26 +41,26 @@ failproofai policies --install --custom ./my-policies.js
|
|
|
41
41
|
|
|
42
42
|
### 방법 1: 컨벤션 기반 (권장)
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
`*policies.{js,mjs,ts}` 파일을 `.failproofai/policies/` 디렉터리에 넣으면 자동으로 로드됩니다. 별도의 플래그나 설정 변경이 필요 없습니다. 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
|
-
컨벤션 정책은
|
|
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
|
-
변환된 절대 경로는 `policies-config.json`의 `customPoliciesPath`에 저장됩니다. 파일은
|
|
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/`, 알파벳 순)
|
|
@@ -98,45 +98,45 @@ 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
|
-
description?: string; // `failproofai policies` 출력에
|
|
106
|
+
description?: string; // `failproofai policies` 출력에 표시
|
|
107
107
|
match?: { events?: HookEventType[] }; // 이벤트 타입으로 필터링; 생략 시 모든 이벤트에 매칭
|
|
108
108
|
fn: (ctx: PolicyContext) => PolicyResult | Promise<PolicyResult>;
|
|
109
109
|
});
|
|
110
110
|
```
|
|
111
111
|
|
|
112
|
-
### 결정 헬퍼
|
|
112
|
+
### 결정 헬퍼 함수
|
|
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)` - 메시지는 `"Blocked by failproofai:"` 접두사와 함께 Claude에게 표시됩니다. 하나의 `deny`가 발생하면
|
|
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/`) 정책 모두에서 동작합니다. 자세한 내용은 [Configuration → hint](/ko/configuration#hint-cross-cutting)를 참고하세요.
|
|
126
126
|
</Tip>
|
|
127
127
|
|
|
128
128
|
### 정보성 allow 메시지
|
|
129
129
|
|
|
130
|
-
`allow(message)`는 작업을 허용하면서 **동시에** Claude에게 정보성 메시지를
|
|
130
|
+
`allow(message)`는 작업을 허용하면서 **동시에** Claude에게 정보성 메시지를 전송합니다. 메시지는 훅 핸들러의 stdout 응답에서 `additionalContext`로 전달됩니다. `instruct`와 동일한 메커니즘을 사용하지만 의미론적으로 다릅니다. 경고가 아닌 상태 업데이트입니다.
|
|
131
131
|
|
|
132
132
|
| 함수 | 효과 | 사용 시점 |
|
|
133
133
|
|----------|--------|----------|
|
|
134
|
-
| `allow(message)` |
|
|
134
|
+
| `allow(message)` | 허용하고 Claude에게 컨텍스트 전송 | 검사가 통과되었음을 확인하거나, 검사가 건너뛰어진 이유를 설명할 때 |
|
|
135
135
|
|
|
136
|
-
|
|
136
|
+
사용 사례:
|
|
137
137
|
- **상태 확인:** `allow("All CI checks passed.")` — Claude에게 모든 것이 정상임을 알림
|
|
138
|
-
- **Fail-open 설명:** `allow("GitHub CLI not installed, skipping CI check.")` — Claude가
|
|
139
|
-
-
|
|
138
|
+
- **Fail-open 설명:** `allow("GitHub CLI not installed, skipping CI check.")` — Claude가 전체 컨텍스트를 파악할 수 있도록 검사가 건너뛰어진 이유를 알림
|
|
139
|
+
- **메시지 누적:** 여러 정책이 각각 `allow(message)`를 반환하면, 모든 메시지가 개행으로 연결되어 함께 전달됩니다
|
|
140
140
|
|
|
141
141
|
```js
|
|
142
142
|
customPolicies.add({
|
|
@@ -160,8 +160,8 @@ customPolicies.add({
|
|
|
160
160
|
| 필드 | 타입 | 설명 |
|
|
161
161
|
|-------|------|-------------|
|
|
162
162
|
| `eventType` | `string` | `"PreToolUse"`, `"PostToolUse"`, `"Notification"`, `"Stop"` |
|
|
163
|
-
| `toolName` | `string \| undefined` |
|
|
164
|
-
| `toolInput` | `Record<string, unknown> \| undefined` |
|
|
163
|
+
| `toolName` | `string \| undefined` | 호출 중인 도구 (예: `"Bash"`, `"Write"`, `"Read"`) |
|
|
164
|
+
| `toolInput` | `Record<string, unknown> \| undefined` | 도구의 입력 파라미터 |
|
|
165
165
|
| `payload` | `Record<string, unknown>` | Claude Code로부터의 전체 원시 이벤트 페이로드 |
|
|
166
166
|
| `session` | `SessionMetadata \| undefined` | 세션 컨텍스트 (아래 참조) |
|
|
167
167
|
|
|
@@ -177,10 +177,10 @@ customPolicies.add({
|
|
|
177
177
|
|
|
178
178
|
| 이벤트 | 발생 시점 | `toolInput` 내용 |
|
|
179
179
|
|-------|--------------|----------------------|
|
|
180
|
-
| `PreToolUse` | Claude가
|
|
181
|
-
| `PostToolUse` |
|
|
180
|
+
| `PreToolUse` | Claude가 도구를 실행하기 전 | 도구의 입력값 (예: Bash의 경우 `{ command: "..." }`) |
|
|
181
|
+
| `PostToolUse` | 도구 실행 완료 후 | 도구의 입력값 + `tool_result` (출력) |
|
|
182
182
|
| `Notification` | Claude가 알림을 보낼 때 | `{ message: "...", notification_type: "idle" \| "permission_prompt" \| ... }` - 훅은 항상 `allow()`를 반환해야 하며, 알림을 차단할 수 없습니다 |
|
|
183
|
-
| `Stop` | Claude 세션이 종료될 때 |
|
|
183
|
+
| `Stop` | Claude 세션이 종료될 때 | 없음 |
|
|
184
184
|
|
|
185
185
|
---
|
|
186
186
|
|
|
@@ -188,13 +188,13 @@ customPolicies.add({
|
|
|
188
188
|
|
|
189
189
|
정책은 다음 순서로 평가됩니다:
|
|
190
190
|
|
|
191
|
-
1.
|
|
192
|
-
2. `customPoliciesPath`의 명시적 커스텀 정책 (`.add()` 순서)
|
|
193
|
-
3. 프로젝트 `.failproofai/policies/`의 컨벤션 정책 (파일 알파벳 순, 파일
|
|
194
|
-
4. 사용자 `~/.failproofai/policies/`의 컨벤션 정책 (파일 알파벳 순, 파일
|
|
191
|
+
1. 내장 정책 (정의 순서)
|
|
192
|
+
2. `customPoliciesPath`의 명시적 커스텀 정책 (`.add()` 호출 순서)
|
|
193
|
+
3. 프로젝트 `.failproofai/policies/`의 컨벤션 정책 (파일 알파벳 순, 파일 내에서는 `.add()` 순서)
|
|
194
|
+
4. 사용자 `~/.failproofai/policies/`의 컨벤션 정책 (파일 알파벳 순, 파일 내에서는 `.add()` 순서)
|
|
195
195
|
|
|
196
196
|
<Note>
|
|
197
|
-
첫 번째 `deny`가
|
|
197
|
+
첫 번째 `deny`가 이후의 모든 정책 평가를 단락시킵니다. 모든 `instruct` 메시지는 누적되어 함께 전달됩니다.
|
|
198
198
|
</Note>
|
|
199
199
|
|
|
200
200
|
---
|
|
@@ -218,46 +218,46 @@ customPolicies.add({
|
|
|
218
218
|
});
|
|
219
219
|
```
|
|
220
220
|
|
|
221
|
-
엔트리 파일에서 도달 가능한 모든 상대 임포트가 해석됩니다. 이는 `from "failproofai"` 임포트를 실제 dist 경로로
|
|
221
|
+
엔트리 파일에서 도달 가능한 모든 상대 임포트가 해석됩니다. 이는 `from "failproofai"` 임포트를 실제 dist 경로로 재작성하고, ESM 호환성을 보장하기 위해 임시 `.mjs` 파일을 생성하는 방식으로 구현됩니다.
|
|
222
222
|
|
|
223
223
|
---
|
|
224
224
|
|
|
225
225
|
## 이벤트 타입 필터링
|
|
226
226
|
|
|
227
|
-
`match.events`를 사용하여 정책이
|
|
227
|
+
`match.events`를 사용하여 정책이 실행될 시점을 제한할 수 있습니다:
|
|
228
228
|
|
|
229
229
|
```js
|
|
230
230
|
customPolicies.add({
|
|
231
231
|
name: "require-summary-on-stop",
|
|
232
232
|
match: { events: ["Stop"] },
|
|
233
233
|
fn: async (ctx) => {
|
|
234
|
-
// 세션이 종료될 때만
|
|
235
|
-
// ctx.session.transcriptPath에 전체 세션 로그가
|
|
234
|
+
// 세션이 종료될 때만 실행됨
|
|
235
|
+
// ctx.session.transcriptPath에 전체 세션 로그가 포함됨
|
|
236
236
|
return allow();
|
|
237
237
|
},
|
|
238
238
|
});
|
|
239
239
|
```
|
|
240
240
|
|
|
241
|
-
`match`를 완전히 생략하면 모든 이벤트 타입에서
|
|
241
|
+
`match`를 완전히 생략하면 모든 이벤트 타입에서 실행됩니다.
|
|
242
242
|
|
|
243
243
|
---
|
|
244
244
|
|
|
245
|
-
##
|
|
245
|
+
## 오류 처리 및 실패 모드
|
|
246
246
|
|
|
247
|
-
커스텀 정책은 **fail-open**
|
|
247
|
+
커스텀 정책은 **fail-open** 방식으로 동작합니다. 오류가 발생해도 내장 정책이 차단되거나 훅 핸들러가 충돌하지 않습니다.
|
|
248
248
|
|
|
249
249
|
| 실패 상황 | 동작 |
|
|
250
250
|
|---------|----------|
|
|
251
|
-
| `customPoliciesPath` 미설정 | 명시적 커스텀 정책이 실행되지
|
|
252
|
-
|
|
|
253
|
-
|
|
|
254
|
-
|
|
|
255
|
-
| `fn`
|
|
256
|
-
| `fn`이 10
|
|
257
|
-
| 컨벤션 디렉터리 없음 | 컨벤션 정책
|
|
251
|
+
| `customPoliciesPath` 미설정 | 명시적 커스텀 정책이 실행되지 않으며, 컨벤션 정책과 내장 정책은 정상적으로 계속됩니다 |
|
|
252
|
+
| 파일을 찾을 수 없음 | `~/.failproofai/hook.log`에 경고 기록; 내장 정책은 계속됩니다 |
|
|
253
|
+
| 구문/임포트 오류 (명시적) | `~/.failproofai/hook.log`에 오류 기록; 명시적 커스텀 정책 건너뜀 |
|
|
254
|
+
| 구문/임포트 오류 (컨벤션) | 오류 기록; 해당 파일 건너뜀, 다른 컨벤션 파일은 정상 로드 |
|
|
255
|
+
| 런타임에서 `fn` 예외 발생 | 오류 기록; 해당 훅은 `allow`로 처리됨; 다른 훅은 계속됩니다 |
|
|
256
|
+
| `fn`이 10초를 초과 | 타임아웃 기록; `allow`로 처리됨 |
|
|
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
|
-
// 에이전트가 secrets/ 디렉터리에
|
|
275
|
+
// 에이전트가 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
|
+
// 에이전트 방향 유지: 커밋 전 테스트 확인
|
|
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",
|
|
@@ -321,33 +321,33 @@ export { customPolicies };
|
|
|
321
321
|
|
|
322
322
|
---
|
|
323
323
|
|
|
324
|
-
##
|
|
324
|
+
## 예제 파일
|
|
325
325
|
|
|
326
|
-
`examples/` 디렉터리에는 바로 실행 가능한 정책 파일들이 있습니다:
|
|
326
|
+
`examples/` 디렉터리에는 바로 실행 가능한 정책 파일들이 포함되어 있습니다:
|
|
327
327
|
|
|
328
328
|
| 파일 | 내용 |
|
|
329
329
|
|------|----------|
|
|
330
|
-
| `examples/policies-basic.js` | 일반적인 에이전트 실패 모드를 다루는 5가지
|
|
330
|
+
| `examples/policies-basic.js` | 일반적인 에이전트 실패 모드를 다루는 5가지 스타터 정책 |
|
|
331
331
|
| `examples/policies-advanced/index.js` | 고급 패턴: 전이적 임포트, 비동기 호출, 출력 스크러빙, 세션 종료 훅 |
|
|
332
|
-
| `examples/convention-policies/security-policies.mjs` | 컨벤션 기반 보안 정책 (.env
|
|
333
|
-
| `examples/convention-policies/workflow-policies.mjs` | 컨벤션 기반 워크플로우 정책 (테스트
|
|
332
|
+
| `examples/convention-policies/security-policies.mjs` | 컨벤션 기반 보안 정책 (.env 쓰기 차단, git 히스토리 재작성 방지) |
|
|
333
|
+
| `examples/convention-policies/workflow-policies.mjs` | 컨벤션 기반 워크플로우 정책 (테스트 알림, 감사 파일 쓰기) |
|
|
334
334
|
|
|
335
|
-
### 명시적 파일
|
|
335
|
+
### 명시적 파일 예제 사용
|
|
336
336
|
|
|
337
337
|
```bash
|
|
338
338
|
failproofai policies --install --custom ./examples/policies-basic.js
|
|
339
339
|
```
|
|
340
340
|
|
|
341
|
-
### 컨벤션 기반
|
|
341
|
+
### 컨벤션 기반 예제 사용
|
|
342
342
|
|
|
343
343
|
```bash
|
|
344
|
-
# 프로젝트
|
|
344
|
+
# 프로젝트 레벨에 복사
|
|
345
345
|
mkdir -p .failproofai/policies
|
|
346
346
|
cp examples/convention-policies/*.mjs .failproofai/policies/
|
|
347
347
|
|
|
348
|
-
# 또는 사용자
|
|
348
|
+
# 또는 사용자 레벨에 복사
|
|
349
349
|
mkdir -p ~/.failproofai/policies
|
|
350
350
|
cp examples/convention-policies/*.mjs ~/.failproofai/policies/
|
|
351
351
|
```
|
|
352
352
|
|
|
353
|
-
설치
|
|
353
|
+
설치 명령이 필요 없습니다. 다음 훅 이벤트 시 파일이 자동으로 감지됩니다.
|
|
@@ -4,13 +4,13 @@ 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는 Claude Code의 [훅 시스템](https://docs.anthropic.com/en/docs/claude-code/hooks)을 통해 통합됩니다. `failproofai policies --install`을
|
|
13
|
+
Failproof AI는 Claude Code의 [훅 시스템](https://docs.anthropic.com/en/docs/claude-code/hooks)을 통해 통합됩니다. `failproofai policies --install`을 실행하면, 모든 도구 호출 시 실행되는 훅 명령어가 Claude Code의 `settings.json`에 등록됩니다.
|
|
14
14
|
|
|
15
15
|
<Steps>
|
|
16
16
|
<Step title="failproofai 설치">
|
|
@@ -18,7 +18,7 @@ Failproof AI는 Claude Code의 [훅 시스템](https://docs.anthropic.com/en/doc
|
|
|
18
18
|
npm install -g failproofai
|
|
19
19
|
```
|
|
20
20
|
</Step>
|
|
21
|
-
<Step title="
|
|
21
|
+
<Step title="내장 정책 전체 활성화">
|
|
22
22
|
```bash
|
|
23
23
|
failproofai policies --install
|
|
24
24
|
```
|
|
@@ -35,15 +35,15 @@ Failproof AI는 Claude Code의 [훅 시스템](https://docs.anthropic.com/en/doc
|
|
|
35
35
|
claude
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
-
이제 모든 도구 호출 시 정책이 자동으로 실행됩니다. Claude에게 `sudo rm -rf
|
|
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 설치">
|
|
@@ -52,7 +52,7 @@ Failproof AI는 Claude Code의 [훅 시스템](https://docs.anthropic.com/en/doc
|
|
|
52
52
|
```
|
|
53
53
|
</Step>
|
|
54
54
|
<Step title="에이전트에 훅 설정">
|
|
55
|
-
에이전트
|
|
55
|
+
에이전트 프로세스 생성 시 훅 명령어를 전달합니다. Claude Code에서와 동일하게 stdin/stdout JSON 방식으로 훅이 실행됩니다:
|
|
56
56
|
|
|
57
57
|
```bash
|
|
58
58
|
failproofai --hook PreToolUse # 각 도구 실행 전 호출
|
|
@@ -65,12 +65,12 @@ Failproof AI는 Claude Code의 [훅 시스템](https://docs.anthropic.com/en/doc
|
|
|
65
65
|
|
|
66
66
|
customPolicies.add({
|
|
67
67
|
name: "limit-to-project-dir",
|
|
68
|
-
description: "
|
|
68
|
+
description: "에이전트를 프로젝트 디렉터리 내로 제한",
|
|
69
69
|
match: { events: ["PreToolUse"] },
|
|
70
70
|
fn: async (ctx) => {
|
|
71
71
|
const path = String(ctx.toolInput?.file_path ?? "");
|
|
72
72
|
if (path.startsWith("/") && !path.startsWith(ctx.session?.cwd ?? "")) {
|
|
73
|
-
return deny("
|
|
73
|
+
return deny("에이전트는 프로젝트 디렉터리로 제한됩니다");
|
|
74
74
|
}
|
|
75
75
|
return allow();
|
|
76
76
|
},
|
|
@@ -86,35 +86,35 @@ Failproof AI는 Claude Code의 [훅 시스템](https://docs.anthropic.com/en/doc
|
|
|
86
86
|
|
|
87
87
|
---
|
|
88
88
|
|
|
89
|
-
##
|
|
89
|
+
## 파괴적인 명령어 차단
|
|
90
90
|
|
|
91
|
-
가장 일반적인
|
|
91
|
+
가장 일반적인 설정 — 에이전트가 되돌릴 수 없는 손상을 입히지 못하도록 방지합니다.
|
|
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` - 원격 스크립트를 셸로 파이프하는 명령 차단
|
|
102
102
|
|
|
103
103
|
---
|
|
104
104
|
|
|
105
105
|
## 시크릿 유출 방지
|
|
106
106
|
|
|
107
|
-
에이전트가 도구 출력에서 자격 증명을
|
|
107
|
+
에이전트가 도구 출력에서 자격 증명을 확인하거나 유출하지 못하도록 차단합니다.
|
|
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` 시점에 실행됩니다 — 도구 실행 후 에이전트가 출력을 보기 전에 민감한 정보를 제거합니다.
|
|
114
114
|
|
|
115
115
|
---
|
|
116
116
|
|
|
117
|
-
##
|
|
117
|
+
## 에이전트가 대기 중일 때 Slack 알림 받기
|
|
118
118
|
|
|
119
119
|
알림 훅을 사용하여 유휴 알림을 Slack으로 전달합니다.
|
|
120
120
|
|
|
@@ -123,7 +123,7 @@ import { customPolicies, allow, instruct } from "failproofai";
|
|
|
123
123
|
|
|
124
124
|
customPolicies.add({
|
|
125
125
|
name: "slack-on-idle",
|
|
126
|
-
description: "
|
|
126
|
+
description: "에이전트가 입력을 기다릴 때 Slack에 알림 전송",
|
|
127
127
|
match: { events: ["Notification"] },
|
|
128
128
|
fn: async (ctx) => {
|
|
129
129
|
const webhookUrl = process.env.SLACK_WEBHOOK_URL;
|
|
@@ -160,20 +160,20 @@ SLACK_WEBHOOK_URL=https://hooks.slack.com/... failproofai policies --install --c
|
|
|
160
160
|
|
|
161
161
|
## 에이전트를 특정 브랜치에 고정
|
|
162
162
|
|
|
163
|
-
에이전트가 브랜치를 전환하거나 보호된 브랜치에
|
|
163
|
+
에이전트가 브랜치를 전환하거나 보호된 브랜치에 푸시하지 못하도록 방지합니다.
|
|
164
164
|
|
|
165
165
|
```javascript
|
|
166
166
|
import { customPolicies, allow, deny } from "failproofai";
|
|
167
167
|
|
|
168
168
|
customPolicies.add({
|
|
169
169
|
name: "stay-on-branch",
|
|
170
|
-
description: "
|
|
170
|
+
description: "에이전트가 다른 브랜치로 체크아웃하지 못하도록 방지",
|
|
171
171
|
match: { events: ["PreToolUse"] },
|
|
172
172
|
fn: async (ctx) => {
|
|
173
173
|
if (ctx.toolName !== "Bash") return allow();
|
|
174
174
|
const cmd = String(ctx.toolInput?.command ?? "");
|
|
175
175
|
if (/git\s+checkout\s+(?!-b)/.test(cmd)) {
|
|
176
|
-
return deny("
|
|
176
|
+
return deny("현재 브랜치를 유지하세요. 새 브랜치가 필요하면 -b 옵션을 사용하세요.");
|
|
177
177
|
}
|
|
178
178
|
return allow();
|
|
179
179
|
},
|
|
@@ -184,20 +184,20 @@ customPolicies.add({
|
|
|
184
184
|
|
|
185
185
|
## 커밋 전 테스트 실행 요구
|
|
186
186
|
|
|
187
|
-
|
|
187
|
+
에이전트에게 커밋 전 테스트를 실행하도록 상기시킵니다.
|
|
188
188
|
|
|
189
189
|
```javascript
|
|
190
190
|
import { customPolicies, allow, instruct } from "failproofai";
|
|
191
191
|
|
|
192
192
|
customPolicies.add({
|
|
193
193
|
name: "test-before-commit",
|
|
194
|
-
description: "
|
|
194
|
+
description: "에이전트에게 커밋 전 테스트 실행을 상기",
|
|
195
195
|
match: { events: ["PreToolUse"] },
|
|
196
196
|
fn: async (ctx) => {
|
|
197
197
|
if (ctx.toolName !== "Bash") return allow();
|
|
198
198
|
const cmd = String(ctx.toolInput?.command ?? "");
|
|
199
199
|
if (/git\s+commit/.test(cmd)) {
|
|
200
|
-
return instruct("
|
|
200
|
+
return instruct("커밋 전에 테스트를 실행하세요. 먼저 `npm test` 또는 `bun test`를 사용하세요.");
|
|
201
201
|
}
|
|
202
202
|
return allow();
|
|
203
203
|
},
|
|
@@ -208,9 +208,9 @@ customPolicies.add({
|
|
|
208
208
|
|
|
209
209
|
## 프로덕션 저장소 잠금
|
|
210
210
|
|
|
211
|
-
팀의 모든 개발자가 동일한 정책을 적용받도록
|
|
211
|
+
프로젝트 수준 설정을 커밋하여 팀의 모든 개발자가 동일한 정책을 적용받도록 합니다.
|
|
212
212
|
|
|
213
|
-
저장소에 `.failproofai/policies-config.json
|
|
213
|
+
저장소에 `.failproofai/policies-config.json` 파일을 생성합니다:
|
|
214
214
|
|
|
215
215
|
```json
|
|
216
216
|
{
|
|
@@ -238,16 +238,70 @@ git add .failproofai/policies-config.json
|
|
|
238
238
|
git commit -m "Add failproofai team policies"
|
|
239
239
|
```
|
|
240
240
|
|
|
241
|
-
failproofai
|
|
241
|
+
failproofai를 설치한 모든 팀원이 이 규칙을 자동으로 적용받게 됩니다.
|
|
242
242
|
|
|
243
243
|
---
|
|
244
244
|
|
|
245
|
-
##
|
|
245
|
+
## 컨벤션 정책으로 조직 전체 품질 기준 구축
|
|
246
246
|
|
|
247
|
-
|
|
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("npm 대신 bun을 사용하세요.");
|
|
268
|
+
return allow();
|
|
269
|
+
},
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
// 에이전트에게 커밋 전 테스트 실행을 상기
|
|
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("커밋 전에 테스트를 실행하세요.");
|
|
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>
|
|
296
|
+
|
|
297
|
+
---
|
|
298
|
+
|
|
299
|
+
## 추가 예시
|
|
300
|
+
|
|
301
|
+
저장소의 [`examples/`](https://github.com/exospherehost/failproofai/tree/main/examples) 디렉터리에는 다음이 포함되어 있습니다:
|
|
248
302
|
|
|
249
303
|
| 파일 | 내용 |
|
|
250
|
-
|
|
251
|
-
| `policies-basic.js` | 기본 정책 — 프로덕션
|
|
304
|
+
|------|---------------|
|
|
305
|
+
| `policies-basic.js` | 기본 정책 — 프로덕션 쓰기, 강제 푸시, 파이프 스크립트 차단 |
|
|
252
306
|
| `policies-notification.js` | 유휴 알림 및 세션 종료 시 Slack 알림 |
|
|
253
307
|
| `policies-advanced/index.js` | 전이적 임포트, 비동기 훅, PostToolUse 출력 스크러빙, Stop 이벤트 처리 |
|