failproofai 0.0.1-beta.5 → 0.0.1-beta.7
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/.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/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 +17 -17
- package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +17 -17
- 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 +11 -11
- 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 +2 -2
- package/.next/standalone/.next/server/app/index.html +1 -1
- package/.next/standalone/.next/server/app/index.rsc +16 -16
- package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +16 -16
- package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +11 -11
- package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +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/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]__02nt~6d._.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]__0unoyb1._.js → [root-of-the-server]__0cnhb7_._.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]__0osi8nq._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0w6l33k._.js +4 -4
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0g.-ow8._.js → [root-of-the-server]__0xmjv9e._.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 +2 -2
- 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/{0y-7a0dcrw047.js → 00qeuetfdsgjk.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0ke6dphc4axsb.js → 07nvevyjq47qo.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0s-.ej3z1p-ke.js → 0b.lzb_keexdb.js} +3 -3
- package/.next/standalone/.next/static/chunks/{0ca6y7bjo.ijt.js → 0iv-rbjm2j5nc.js} +1 -1
- package/.next/standalone/.next/static/chunks/{10d1jgbx0dgle.js → 0jfhld9mk1zm4.js} +1 -1
- package/.next/standalone/.next/static/chunks/{128ogw.xok4x2.js → 0jzowkzl-dd6s.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0d2zd7ikio.lc.js → 0w4.ug1d.ok15.js} +2 -2
- package/.next/standalone/.next/static/chunks/15jpradyu_531.css +1 -0
- package/.next/standalone/.next/static/chunks/{12tzy91t9mk_w.js → 16_nu40klq96n.js} +1 -1
- package/.next/standalone/README.md +2 -2
- package/.next/standalone/app/actions/get-hooks-config.ts +4 -4
- package/.next/standalone/app/policies/hooks-client.tsx +2 -2
- package/.next/standalone/bin/failproofai.mjs +162 -57
- package/.next/standalone/components/reach-developers.tsx +11 -1
- package/.next/standalone/docs/architecture.md +6 -6
- package/.next/standalone/docs/cli-reference.md +5 -5
- package/.next/standalone/docs/configuration.md +12 -12
- package/.next/standalone/docs/custom-hooks.md +7 -7
- package/.next/standalone/docs/dashboard.md +1 -1
- package/.next/standalone/docs/getting-started.md +3 -3
- package/.next/standalone/docs/index.md +1 -1
- package/.next/standalone/docs/testing.md +1 -1
- package/.next/standalone/package.json +1 -1
- package/.next/standalone/scripts/launch.ts +2 -0
- package/.next/standalone/scripts/postinstall.mjs +2 -2
- package/.next/standalone/src/hooks/custom-hooks-loader.ts +6 -6
- package/.next/standalone/src/hooks/handler.ts +2 -2
- package/.next/standalone/src/hooks/hooks-config.ts +13 -13
- package/.next/standalone/src/hooks/install-prompt.ts +2 -2
- package/.next/standalone/src/hooks/llm-client.ts +2 -2
- package/.next/standalone/src/hooks/manager.ts +34 -26
- package/.next/standalone/src/hooks/policy-types.ts +1 -1
- package/README.md +2 -2
- package/bin/failproofai.mjs +162 -57
- package/package.json +1 -1
- package/scripts/launch.ts +2 -0
- package/scripts/postinstall.mjs +2 -2
- package/src/hooks/custom-hooks-loader.ts +6 -6
- package/src/hooks/handler.ts +2 -2
- package/src/hooks/hooks-config.ts +13 -13
- package/src/hooks/install-prompt.ts +2 -2
- package/src/hooks/llm-client.ts +2 -2
- package/src/hooks/manager.ts +34 -26
- package/src/hooks/policy-types.ts +1 -1
- package/.next/standalone/.next/static/chunks/08f78tecvx61l.css +0 -1
- /package/.next/standalone/.next/static/{W2hv3TMvrp7iPePv6-jJA → H15OMlkQejMvLowzdBldp}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{W2hv3TMvrp7iPePv6-jJA → H15OMlkQejMvLowzdBldp}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{W2hv3TMvrp7iPePv6-jJA → H15OMlkQejMvLowzdBldp}/_ssgManifest.js +0 -0
|
@@ -5,9 +5,8 @@
|
|
|
5
5
|
* Handles:
|
|
6
6
|
* --hook <event> Hook event from Claude Code (minimal startup latency)
|
|
7
7
|
* --version / -v Print version and exit
|
|
8
|
-
* --
|
|
9
|
-
*
|
|
10
|
-
* --list-policies List available policies and their status
|
|
8
|
+
* --help / -h Show usage and exit
|
|
9
|
+
* policies Manage policies (list / install / uninstall)
|
|
11
10
|
* (default) Launch production dashboard
|
|
12
11
|
*/
|
|
13
12
|
import { realpathSync } from "node:fs";
|
|
@@ -27,6 +26,52 @@ if (!process.env.FAILPROOFAI_PACKAGE_ROOT) {
|
|
|
27
26
|
|
|
28
27
|
const args = process.argv.slice(2);
|
|
29
28
|
|
|
29
|
+
// --help / -h (only when not inside a subcommand that handles its own --help)
|
|
30
|
+
const SUBCOMMANDS = ["policies"];
|
|
31
|
+
if ((args.includes("--help") || args.includes("-h")) && !SUBCOMMANDS.includes(args[0])) {
|
|
32
|
+
console.log(`
|
|
33
|
+
failproofai v${version}
|
|
34
|
+
|
|
35
|
+
USAGE
|
|
36
|
+
failproofai [command] [options]
|
|
37
|
+
|
|
38
|
+
COMMANDS
|
|
39
|
+
(no args) Launch the policy dashboard
|
|
40
|
+
|
|
41
|
+
policies List all available policies and their status
|
|
42
|
+
policies --install, -i Enable policies in Claude Code settings
|
|
43
|
+
[names...] Specific policy names to enable
|
|
44
|
+
--scope user|project|local Config scope to write to (default: user)
|
|
45
|
+
--beta Include beta policies
|
|
46
|
+
--custom, -c <path> Path to a JS file of custom policies
|
|
47
|
+
|
|
48
|
+
policies --uninstall, -u Disable policies or remove hooks
|
|
49
|
+
[names...] Specific policy names to disable
|
|
50
|
+
--scope user|project|local|all Config scope to remove from (default: user)
|
|
51
|
+
--beta Remove only beta policies
|
|
52
|
+
--custom, -c Clear the customPoliciesPath from config
|
|
53
|
+
|
|
54
|
+
policies --help, -h Show this help for the policies command
|
|
55
|
+
|
|
56
|
+
--version, -v Print version and exit
|
|
57
|
+
--help, -h Show this help message
|
|
58
|
+
|
|
59
|
+
EXAMPLES
|
|
60
|
+
failproofai policies
|
|
61
|
+
failproofai policies --install
|
|
62
|
+
failproofai policies --install block-sudo sanitize-api-keys --scope project
|
|
63
|
+
failproofai policies --install --custom ./my-policies.js
|
|
64
|
+
failproofai policies -i -c ./my-policies.js
|
|
65
|
+
failproofai policies --uninstall block-sudo
|
|
66
|
+
failproofai policies --uninstall --custom
|
|
67
|
+
|
|
68
|
+
LINKS
|
|
69
|
+
⭐ Star us: https://github.com/exospherehost/failproofai
|
|
70
|
+
📖 Docs: https://befailproof.ai
|
|
71
|
+
`.trimStart());
|
|
72
|
+
process.exit(0);
|
|
73
|
+
}
|
|
74
|
+
|
|
30
75
|
// --version / -v
|
|
31
76
|
if (args.includes("--version") || args.includes("-v")) {
|
|
32
77
|
console.log(version);
|
|
@@ -41,70 +86,121 @@ if (hookIdx >= 0 && args[hookIdx + 1]) {
|
|
|
41
86
|
process.exit(exitCode);
|
|
42
87
|
}
|
|
43
88
|
|
|
44
|
-
// --install
|
|
45
|
-
if (args
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
const
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
89
|
+
// policies [--install|-i|--uninstall|-u|--help|-h] [names...] [--scope] [--beta] [--custom|-c <path>]
|
|
90
|
+
if (args[0] === "policies") {
|
|
91
|
+
const subArgs = args.slice(1);
|
|
92
|
+
|
|
93
|
+
const isInstall = subArgs.includes("--install") || subArgs.includes("-i");
|
|
94
|
+
const isUninstall = subArgs.includes("--uninstall") || subArgs.includes("-u");
|
|
95
|
+
const isHelp = subArgs.includes("--help") || subArgs.includes("-h");
|
|
96
|
+
|
|
97
|
+
if (isHelp) {
|
|
98
|
+
console.log(`
|
|
99
|
+
failproofai policies — manage Failproof AI policies
|
|
100
|
+
|
|
101
|
+
USAGE
|
|
102
|
+
failproofai policies List all policies and their status
|
|
103
|
+
failproofai policies --install, -i Enable policies
|
|
104
|
+
failproofai policies --uninstall, -u Disable policies or remove hooks
|
|
105
|
+
|
|
106
|
+
OPTIONS (install)
|
|
107
|
+
[names...] Specific policy names to enable (omit for interactive)
|
|
108
|
+
--scope user|project|local Config scope to write to (default: user)
|
|
109
|
+
--beta Include beta policies
|
|
110
|
+
--custom, -c <path> Path to a JS file of custom policies
|
|
111
|
+
(skips interactive prompt; validates file first)
|
|
112
|
+
|
|
113
|
+
OPTIONS (uninstall)
|
|
114
|
+
[names...] Specific policy names to disable (omit to remove hooks)
|
|
115
|
+
--scope user|project|local|all Config scope to remove from (default: user)
|
|
116
|
+
--beta Remove only beta policies
|
|
117
|
+
--custom, -c Clear the customPoliciesPath from config
|
|
118
|
+
|
|
119
|
+
EXAMPLES
|
|
120
|
+
failproofai policies
|
|
121
|
+
failproofai policies --install
|
|
122
|
+
failproofai policies --install block-sudo sanitize-api-keys
|
|
123
|
+
failproofai policies --install --custom ./my-policies.js
|
|
124
|
+
failproofai policies -i -c ./my-policies.js
|
|
125
|
+
failproofai policies --uninstall block-sudo
|
|
126
|
+
failproofai policies -u
|
|
127
|
+
failproofai policies --uninstall --custom
|
|
128
|
+
`.trimStart());
|
|
129
|
+
process.exit(0);
|
|
130
|
+
}
|
|
74
131
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
const { removeHooks } = await import("../src/hooks/manager");
|
|
132
|
+
if (isInstall) {
|
|
133
|
+
const { installHooks } = await import("../src/hooks/manager");
|
|
78
134
|
|
|
79
|
-
|
|
80
|
-
|
|
135
|
+
const scopeIdx = subArgs.indexOf("--scope");
|
|
136
|
+
const scope = scopeIdx >= 0 ? subArgs[scopeIdx + 1] : "user";
|
|
81
137
|
|
|
82
|
-
|
|
138
|
+
const customIdx = subArgs.includes("--custom") ? subArgs.indexOf("--custom")
|
|
139
|
+
: subArgs.includes("-c") ? subArgs.indexOf("-c")
|
|
140
|
+
: -1;
|
|
141
|
+
const customPoliciesPath = customIdx >= 0 ? subArgs[customIdx + 1] : undefined;
|
|
83
142
|
|
|
84
|
-
|
|
85
|
-
const policyNames = args
|
|
86
|
-
.slice(removeIdx + 1)
|
|
87
|
-
.filter((a) => !a.startsWith("--") && a !== scope);
|
|
143
|
+
const includeBeta = subArgs.includes("--beta");
|
|
88
144
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
scope,
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
}
|
|
145
|
+
// Collect positional policy names — args that don't start with - and aren't
|
|
146
|
+
// values consumed by --scope or --custom/-c.
|
|
147
|
+
const consumed = new Set([scope, customPoliciesPath].filter(Boolean));
|
|
148
|
+
const flags = new Set(["--install", "-i", "--scope", "--beta", "--custom", "-c"]);
|
|
149
|
+
const explicitPolicyNames = subArgs.filter(
|
|
150
|
+
(a) => !a.startsWith("-") && !flags.has(a) && !consumed.has(a)
|
|
151
|
+
);
|
|
97
152
|
|
|
98
|
-
// --
|
|
99
|
-
|
|
153
|
+
// When --custom/-c is present but no explicit policy names, pass [] so
|
|
154
|
+
// installHooks uses the existing enabled policies and skips the interactive
|
|
155
|
+
// prompt — validation of the custom file happens inside installHooks.
|
|
156
|
+
const policyNames =
|
|
157
|
+
explicitPolicyNames.length > 0 ? explicitPolicyNames
|
|
158
|
+
: customPoliciesPath !== undefined ? []
|
|
159
|
+
: undefined;
|
|
160
|
+
|
|
161
|
+
await installHooks(
|
|
162
|
+
policyNames,
|
|
163
|
+
scope,
|
|
164
|
+
undefined,
|
|
165
|
+
includeBeta,
|
|
166
|
+
undefined,
|
|
167
|
+
customPoliciesPath,
|
|
168
|
+
);
|
|
169
|
+
process.exit(0);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (isUninstall) {
|
|
173
|
+
const { removeHooks } = await import("../src/hooks/manager");
|
|
174
|
+
|
|
175
|
+
const scopeIdx = subArgs.indexOf("--scope");
|
|
176
|
+
const scope = scopeIdx >= 0 ? subArgs[scopeIdx + 1] : "user";
|
|
177
|
+
|
|
178
|
+
const betaOnly = subArgs.includes("--beta");
|
|
179
|
+
const removeCustomHooks = subArgs.includes("--custom") || subArgs.includes("-c");
|
|
180
|
+
|
|
181
|
+
const consumed = new Set([scope].filter(Boolean));
|
|
182
|
+
const flags = new Set(["--uninstall", "-u", "--scope", "--beta", "--custom", "-c"]);
|
|
183
|
+
const policyNames = subArgs.filter(
|
|
184
|
+
(a) => !a.startsWith("-") && !flags.has(a) && !consumed.has(a)
|
|
185
|
+
);
|
|
186
|
+
|
|
187
|
+
await removeHooks(
|
|
188
|
+
policyNames.length > 0 ? policyNames : undefined,
|
|
189
|
+
scope,
|
|
190
|
+
undefined,
|
|
191
|
+
{ betaOnly, removeCustomHooks },
|
|
192
|
+
);
|
|
193
|
+
process.exit(0);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Default: list policies
|
|
100
197
|
const { listHooks } = await import("../src/hooks/manager");
|
|
101
198
|
await listHooks();
|
|
102
199
|
process.exit(0);
|
|
103
200
|
}
|
|
104
201
|
|
|
105
202
|
// Unknown flag guard — must appear after all known-flag branches
|
|
106
|
-
const knownFlags = ["--version", "-v", "--
|
|
107
|
-
"--remove-policies", "--list-policies"];
|
|
203
|
+
const knownFlags = ["--version", "-v", "--help", "-h", "--hook"];
|
|
108
204
|
const unknownFlag = args.find(a => a.startsWith("-") && !knownFlags.includes(a));
|
|
109
205
|
|
|
110
206
|
if (unknownFlag) {
|
|
@@ -121,8 +217,7 @@ if (unknownFlag) {
|
|
|
121
217
|
return dp[m][n];
|
|
122
218
|
}
|
|
123
219
|
|
|
124
|
-
const primary = ["--version", "--hook", "
|
|
125
|
-
"--remove-policies", "--list-policies"];
|
|
220
|
+
const primary = ["--version", "--help", "--hook", "policies"];
|
|
126
221
|
const closest = primary.reduce((best, flag) => {
|
|
127
222
|
const dist = levenshtein(unknownFlag, flag);
|
|
128
223
|
return dist < best.dist ? { flag, dist } : best;
|
|
@@ -130,6 +225,16 @@ if (unknownFlag) {
|
|
|
130
225
|
|
|
131
226
|
console.error(`Unknown flag: ${unknownFlag}`);
|
|
132
227
|
console.error(`Did you mean: ${closest.flag}?`);
|
|
228
|
+
console.error(`Run \`failproofai --help\` for usage details.`);
|
|
229
|
+
process.exit(1);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Unknown subcommand guard (non-flag args that aren't "policies")
|
|
233
|
+
const unknownSubcommand = args.find(a => !a.startsWith("-") && a !== "policies");
|
|
234
|
+
if (unknownSubcommand) {
|
|
235
|
+
console.error(`Unknown command: ${unknownSubcommand}`);
|
|
236
|
+
console.error(`Did you mean: failproofai policies?`);
|
|
237
|
+
console.error(`Run \`failproofai --help\` for usage details.`);
|
|
133
238
|
process.exit(1);
|
|
134
239
|
}
|
|
135
240
|
|
|
@@ -2,13 +2,23 @@
|
|
|
2
2
|
"use client";
|
|
3
3
|
|
|
4
4
|
import React, { useState, useCallback } from "react";
|
|
5
|
-
import { GitBranch, Lightbulb, Bug, MessageSquare, ChevronDown } from "lucide-react";
|
|
5
|
+
import { GitBranch, Lightbulb, Bug, MessageSquare, ChevronDown, Star, BookOpen } from "lucide-react";
|
|
6
6
|
import { Button } from "@/components/ui/button";
|
|
7
7
|
|
|
8
8
|
const GITHUB_REPO = "https://github.com/exospherehost/failproofai";
|
|
9
9
|
const CONTACT_EMAIL = "failproofai@exosphere.host";
|
|
10
10
|
|
|
11
11
|
const options = [
|
|
12
|
+
{
|
|
13
|
+
label: "Star us on GitHub",
|
|
14
|
+
icon: Star,
|
|
15
|
+
href: "https://github.com/exospherehost/failproofai",
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
label: "Documentation",
|
|
19
|
+
icon: BookOpen,
|
|
20
|
+
href: "https://befailproof.ai",
|
|
21
|
+
},
|
|
12
22
|
{
|
|
13
23
|
label: "Request a Feature",
|
|
14
24
|
icon: Lightbulb,
|
|
@@ -108,7 +108,7 @@ stdin JSON
|
|
|
108
108
|
→ extract session metadata (session_id, cwd, tool_name, tool_input, etc.)
|
|
109
109
|
→ readMergedHooksConfig(cwd) ← merges project + local + global config
|
|
110
110
|
→ register enabled builtin policies with resolved params
|
|
111
|
-
→ load custom hooks from
|
|
111
|
+
→ load custom hooks from customPoliciesPath (if set)
|
|
112
112
|
→ register custom hooks into policy registry
|
|
113
113
|
→ evaluate all policies (builtins first, then custom)
|
|
114
114
|
→ first deny short-circuits
|
|
@@ -127,15 +127,15 @@ The entire process runs in under 100ms for typical payloads with no LLM calls.
|
|
|
127
127
|
`src/hooks/hooks-config.ts` implements three-scope config loading.
|
|
128
128
|
|
|
129
129
|
```
|
|
130
|
-
[1] {cwd}/.failproofai/
|
|
131
|
-
[2] {cwd}/.failproofai/
|
|
132
|
-
[3] ~/.failproofai/
|
|
130
|
+
[1] {cwd}/.failproofai/policies-config.json ← project (highest priority)
|
|
131
|
+
[2] {cwd}/.failproofai/policies-config.local.json ← local
|
|
132
|
+
[3] ~/.failproofai/policies-config.json ← global (lowest priority)
|
|
133
133
|
```
|
|
134
134
|
|
|
135
135
|
Merge logic:
|
|
136
136
|
- `enabledPolicies` — deduplicated union across all three files
|
|
137
137
|
- `policyParams` — per-policy key, first file that defines it wins entirely
|
|
138
|
-
- `
|
|
138
|
+
- `customPoliciesPath` — first file that defines it wins
|
|
139
139
|
- `llm` — first file that defines it wins
|
|
140
140
|
|
|
141
141
|
The web dashboard uses `readHooksConfig()` (global only) for reading and writing, since it is not invoked with a project cwd.
|
|
@@ -206,7 +206,7 @@ export function clearCustomHooks(): void { ... } // used in tests
|
|
|
206
206
|
|
|
207
207
|
`src/hooks/custom-hooks-loader.ts` loads the user's hooks file:
|
|
208
208
|
|
|
209
|
-
1. Read `
|
|
209
|
+
1. Read `customPoliciesPath` from config; skip if absent.
|
|
210
210
|
2. Resolve to absolute path; check file exists.
|
|
211
211
|
3. Rewrite all `from "failproofai"` imports to the actual dist path so `customPolicies` resolves to the same `globalThis` registry.
|
|
212
212
|
4. Recursively rewrite transitive local imports to ensure ESM compatibility.
|
|
@@ -66,7 +66,7 @@ Writes hook entries into Claude Code's `settings.json` so that failproofai inter
|
|
|
66
66
|
| `--scope user` | Install into `~/.claude/settings.json` (default — all sessions) |
|
|
67
67
|
| `--scope project` | Install into `.claude/settings.json` in the current directory |
|
|
68
68
|
| `--scope local` | Install into `.claude/settings.local.json` in the current directory |
|
|
69
|
-
| `--custom
|
|
69
|
+
| `--custom <path>` | Path to a JS file containing custom hook policies |
|
|
70
70
|
| `--beta` | Include beta policies in installation |
|
|
71
71
|
|
|
72
72
|
**Examples:**
|
|
@@ -79,10 +79,10 @@ failproofai --install-policies
|
|
|
79
79
|
failproofai --install-policies block-sudo sanitize-api-keys --scope project
|
|
80
80
|
|
|
81
81
|
# Install with a custom hooks file
|
|
82
|
-
failproofai --install-policies --custom
|
|
82
|
+
failproofai --install-policies --custom ./my-policies.js
|
|
83
83
|
```
|
|
84
84
|
|
|
85
|
-
When `--custom
|
|
85
|
+
When `--custom <path>` is provided, the resolved absolute path is saved to `policies-config.json` as `customPoliciesPath`. The file is loaded and executed at hook-fire time (not at install time).
|
|
86
86
|
|
|
87
87
|
---
|
|
88
88
|
|
|
@@ -102,7 +102,7 @@ Removes failproofai hook entries from Claude Code's `settings.json`.
|
|
|
102
102
|
| `--scope project` | Remove from project settings |
|
|
103
103
|
| `--scope local` | Remove from local settings |
|
|
104
104
|
| `--scope all` | Remove from all scopes |
|
|
105
|
-
| `--
|
|
105
|
+
| `--custom` | Clear the `customPoliciesPath` from config |
|
|
106
106
|
|
|
107
107
|
**Examples:**
|
|
108
108
|
|
|
@@ -114,7 +114,7 @@ failproofai --remove-policies
|
|
|
114
114
|
failproofai --remove-policies block-sudo
|
|
115
115
|
|
|
116
116
|
# Remove custom hooks path
|
|
117
|
-
failproofai --remove-policies --
|
|
117
|
+
failproofai --remove-policies --custom
|
|
118
118
|
```
|
|
119
119
|
|
|
120
120
|
---
|
|
@@ -10,9 +10,9 @@ There are three configuration scopes, evaluated in priority order:
|
|
|
10
10
|
|
|
11
11
|
| Scope | File path | Purpose |
|
|
12
12
|
|-------|-----------|---------|
|
|
13
|
-
| **project** | `.failproofai/
|
|
14
|
-
| **local** | `.failproofai/
|
|
15
|
-
| **global** | `~/.failproofai/
|
|
13
|
+
| **project** | `.failproofai/policies-config.json` | Per-repo settings, committed to version control |
|
|
14
|
+
| **local** | `.failproofai/policies-config.local.json` | Personal per-repo overrides, gitignored |
|
|
15
|
+
| **global** | `~/.failproofai/policies-config.json` | User-level defaults across all projects |
|
|
16
16
|
|
|
17
17
|
When failproofai receives a hook event, it loads and merges all three files that exist for the current working directory.
|
|
18
18
|
|
|
@@ -45,7 +45,7 @@ global: block-sudo → { allowPatterns: ["sudo systemctl status"] }
|
|
|
45
45
|
resolved: { allowPatterns: ["sudo systemctl status"] } ← falls through to global
|
|
46
46
|
```
|
|
47
47
|
|
|
48
|
-
**`
|
|
48
|
+
**`customPoliciesPath`** — first scope that defines it wins.
|
|
49
49
|
|
|
50
50
|
**`llm`** — first scope that defines it wins.
|
|
51
51
|
|
|
@@ -86,7 +86,7 @@ resolved: { allowPatterns: ["sudo systemctl status"] } ← falls through to glo
|
|
|
86
86
|
"thresholdKb": 512
|
|
87
87
|
}
|
|
88
88
|
},
|
|
89
|
-
"
|
|
89
|
+
"customPoliciesPath": "/home/alice/myproject/my-policies.js"
|
|
90
90
|
}
|
|
91
91
|
```
|
|
92
92
|
|
|
@@ -112,11 +112,11 @@ If a policy has parameters but you don't specify them, the policy's built-in def
|
|
|
112
112
|
|
|
113
113
|
Unknown keys inside a policy's params block are silently ignored at hook-fire time but flagged as warnings when you run `failproofai --list-policies`.
|
|
114
114
|
|
|
115
|
-
### `
|
|
115
|
+
### `customPoliciesPath`
|
|
116
116
|
|
|
117
117
|
Type: `string` (absolute path)
|
|
118
118
|
|
|
119
|
-
Path to a JavaScript file containing custom hook policies. This is set automatically by `failproofai --install-policies --custom
|
|
119
|
+
Path to a JavaScript file containing custom hook policies. This is set automatically by `failproofai --install-policies --custom <path>` (the path is resolved to absolute before being stored).
|
|
120
120
|
|
|
121
121
|
The file is loaded fresh on every hook event — there is no caching. See [Custom Hooks](./custom-hooks.md) for authoring details.
|
|
122
122
|
|
|
@@ -139,18 +139,18 @@ LLM client configuration for policies that make AI calls. Not required for most
|
|
|
139
139
|
|
|
140
140
|
## Managing configuration from the CLI
|
|
141
141
|
|
|
142
|
-
The `--install-policies` and `--remove-policies` commands write to Claude Code's `settings.json` (the hook entry points), while `
|
|
142
|
+
The `--install-policies` and `--remove-policies` commands write to Claude Code's `settings.json` (the hook entry points), while `policies-config.json` is the file you manage directly. The two are separate:
|
|
143
143
|
|
|
144
144
|
- **`settings.json`** — tells Claude Code to call `failproofai --hook <event>` on each tool use
|
|
145
|
-
- **`
|
|
145
|
+
- **`policies-config.json`** — tells failproofai which policies to evaluate and with what params
|
|
146
146
|
|
|
147
|
-
You can edit `
|
|
147
|
+
You can edit `policies-config.json` directly at any time; changes take effect immediately on the next hook event with no restart needed.
|
|
148
148
|
|
|
149
149
|
---
|
|
150
150
|
|
|
151
151
|
## Example: project-level config with team defaults
|
|
152
152
|
|
|
153
|
-
Commit `.failproofai/
|
|
153
|
+
Commit `.failproofai/policies-config.json` to your repo:
|
|
154
154
|
|
|
155
155
|
```json
|
|
156
156
|
{
|
|
@@ -169,4 +169,4 @@ Commit `.failproofai/hooks-config.json` to your repo:
|
|
|
169
169
|
}
|
|
170
170
|
```
|
|
171
171
|
|
|
172
|
-
Each developer can then create `.failproofai/
|
|
172
|
+
Each developer can then create `.failproofai/policies-config.local.json` (gitignored) for personal overrides without affecting teammates.
|
|
@@ -28,7 +28,7 @@ customPolicies.add({
|
|
|
28
28
|
Install it:
|
|
29
29
|
|
|
30
30
|
```bash
|
|
31
|
-
failproofai --install-policies --custom
|
|
31
|
+
failproofai --install-policies --custom ./my-policies.js
|
|
32
32
|
```
|
|
33
33
|
|
|
34
34
|
---
|
|
@@ -37,16 +37,16 @@ failproofai --install-policies --custom-hooks ./my-policies.js
|
|
|
37
37
|
|
|
38
38
|
```bash
|
|
39
39
|
# Install with a custom hooks file
|
|
40
|
-
failproofai --install-policies --custom
|
|
40
|
+
failproofai --install-policies --custom ./my-policies.js
|
|
41
41
|
|
|
42
42
|
# Replace the hooks file path
|
|
43
|
-
failproofai --install-policies --custom
|
|
43
|
+
failproofai --install-policies --custom ./new-policies.js
|
|
44
44
|
|
|
45
45
|
# Remove the custom hooks path from config
|
|
46
|
-
failproofai --remove-policies --
|
|
46
|
+
failproofai --remove-policies --custom
|
|
47
47
|
```
|
|
48
48
|
|
|
49
|
-
The resolved absolute path is stored in `
|
|
49
|
+
The resolved absolute path is stored in `policies-config.json` as `customPoliciesPath`. The file is loaded fresh on every hook event — there is no caching between events.
|
|
50
50
|
|
|
51
51
|
---
|
|
52
52
|
|
|
@@ -172,7 +172,7 @@ Custom hooks are **fail-open**: errors never block built-in policies or crash th
|
|
|
172
172
|
|
|
173
173
|
| Failure | Behavior |
|
|
174
174
|
|---------|----------|
|
|
175
|
-
| `
|
|
175
|
+
| `customPoliciesPath` not set | No custom hooks run; built-ins continue normally |
|
|
176
176
|
| File not found | Warning logged to `~/.failproofai/hook.log`; built-ins continue |
|
|
177
177
|
| Syntax/import error | Error logged to `~/.failproofai/hook.log`; all custom hooks skipped |
|
|
178
178
|
| `fn` throws at runtime | Error logged; that hook treated as `allow`; other hooks continue |
|
|
@@ -253,5 +253,5 @@ The `examples/` directory contains ready-to-run hook files:
|
|
|
253
253
|
Install the basic examples:
|
|
254
254
|
|
|
255
255
|
```bash
|
|
256
|
-
failproofai --install-policies --custom
|
|
256
|
+
failproofai --install-policies --custom ./examples/policies-basic.js
|
|
257
257
|
```
|
|
@@ -65,7 +65,7 @@ A two-tab page for managing policies and reviewing activity.
|
|
|
65
65
|
|
|
66
66
|
**Policies tab:**
|
|
67
67
|
|
|
68
|
-
- Toggle individual policies on or off with a single click (writes to `~/.failproofai/
|
|
68
|
+
- Toggle individual policies on or off with a single click (writes to `~/.failproofai/policies-config.json`)
|
|
69
69
|
- Expand a policy to configure its parameters (for policies that support `policyParams`)
|
|
70
70
|
- Install or remove hooks for a given scope
|
|
71
71
|
- Set a custom hooks file path
|
|
@@ -89,11 +89,11 @@ failproofai stores all configuration and logs locally:
|
|
|
89
89
|
|
|
90
90
|
| Path | Contents |
|
|
91
91
|
|------|----------|
|
|
92
|
-
| `~/.failproofai/
|
|
92
|
+
| `~/.failproofai/policies-config.json` | Global policy configuration |
|
|
93
93
|
| `~/.failproofai/hook-activity.jsonl` | Hook execution history (one JSON line per event) |
|
|
94
94
|
| `~/.failproofai/hook.log` | Debug log for custom hook errors |
|
|
95
|
-
| `.failproofai/
|
|
96
|
-
| `.failproofai/
|
|
95
|
+
| `.failproofai/policies-config.json` | Per-project policy configuration (committed) |
|
|
96
|
+
| `.failproofai/policies-config.local.json` | Per-project personal overrides (gitignored) |
|
|
97
97
|
|
|
98
98
|
---
|
|
99
99
|
|
|
@@ -147,7 +147,7 @@ __tests__/e2e/
|
|
|
147
147
|
import { createFixtureEnv } from "../helpers/fixture-env";
|
|
148
148
|
|
|
149
149
|
const env = createFixtureEnv();
|
|
150
|
-
// env.cwd — temp dir; pass as payload.cwd to pick up .failproofai/
|
|
150
|
+
// env.cwd — temp dir; pass as payload.cwd to pick up .failproofai/policies-config.json
|
|
151
151
|
// env.home — isolated home dir; no real ~/.failproofai leaks in
|
|
152
152
|
|
|
153
153
|
env.writeConfig({
|
|
@@ -20,6 +20,8 @@ export function launch(mode: "dev" | "start"): void {
|
|
|
20
20
|
/_/ \\__,_/_/_/ .___/_/ \\____/\\____/_/ /_/ |_/___/
|
|
21
21
|
/_/ v${version}
|
|
22
22
|
`);
|
|
23
|
+
console.log(` ⭐ Star us: https://github.com/exospherehost/failproofai`);
|
|
24
|
+
console.log(` 📖 Docs: https://befailproof.ai\n`);
|
|
23
25
|
|
|
24
26
|
let claudeProjectsPath = parsedPath;
|
|
25
27
|
|
|
@@ -30,7 +30,7 @@ function hashToId(raw) {
|
|
|
30
30
|
* @returns {{ configured: boolean, registered: boolean, policyCount: number }}
|
|
31
31
|
*/
|
|
32
32
|
function checkHooks() {
|
|
33
|
-
const hooksConfigPath = resolve(homedir(), ".failproofai", "
|
|
33
|
+
const hooksConfigPath = resolve(homedir(), ".failproofai", "policies-config.json");
|
|
34
34
|
if (!existsSync(hooksConfigPath)) {
|
|
35
35
|
return { configured: false, registered: false, policyCount: 0 };
|
|
36
36
|
}
|
|
@@ -87,7 +87,7 @@ function printHooksWarning() {
|
|
|
87
87
|
console.log(
|
|
88
88
|
`\n[failproofai] Warning: hooks config exists with enabled policies, but hooks are not registered in Claude Code settings.\n` +
|
|
89
89
|
` To re-register hooks, run:\n` +
|
|
90
|
-
` failproofai
|
|
90
|
+
` failproofai policies --uninstall && failproofai policies --install\n`
|
|
91
91
|
);
|
|
92
92
|
}
|
|
93
93
|
|
|
@@ -16,18 +16,18 @@ import type { CustomHook } from "./policy-types";
|
|
|
16
16
|
const LOADING_KEY = "__FAILPROOFAI_LOADING_HOOKS__";
|
|
17
17
|
|
|
18
18
|
export async function loadCustomHooks(
|
|
19
|
-
|
|
19
|
+
customPoliciesPath: string | undefined,
|
|
20
20
|
opts?: { strict?: boolean },
|
|
21
21
|
): Promise<CustomHook[]> {
|
|
22
|
-
if (!
|
|
22
|
+
if (!customPoliciesPath) return [];
|
|
23
23
|
|
|
24
|
-
const absPath = isAbsolute(
|
|
25
|
-
?
|
|
26
|
-
: resolve(process.cwd(),
|
|
24
|
+
const absPath = isAbsolute(customPoliciesPath)
|
|
25
|
+
? customPoliciesPath
|
|
26
|
+
: resolve(process.cwd(), customPoliciesPath);
|
|
27
27
|
|
|
28
28
|
if (!existsSync(absPath)) {
|
|
29
29
|
if (opts?.strict) throw new Error(`Custom hooks file not found: ${absPath}`);
|
|
30
|
-
hookLogWarn(`
|
|
30
|
+
hookLogWarn(`customPoliciesPath not found: ${absPath}`);
|
|
31
31
|
return [];
|
|
32
32
|
}
|
|
33
33
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Hook event handler — invoked when Claude Code triggers a hook.
|
|
3
3
|
*
|
|
4
4
|
* Reads the JSON payload from stdin, loads enabled policies from
|
|
5
|
-
* ~/.failproofai/
|
|
5
|
+
* ~/.failproofai/policies-config.json, evaluates matching policies, persists
|
|
6
6
|
* activity to disk, and returns the appropriate exit code + stdout response.
|
|
7
7
|
*/
|
|
8
8
|
import type { HookEventType, SessionMetadata } from "./types";
|
|
@@ -71,7 +71,7 @@ export async function handleHookEvent(eventType: string): Promise<number> {
|
|
|
71
71
|
registerBuiltinPolicies(config.enabledPolicies);
|
|
72
72
|
|
|
73
73
|
// Load and register custom hooks (layer 2, after builtins)
|
|
74
|
-
const customHooksList = await loadCustomHooks(config.
|
|
74
|
+
const customHooksList = await loadCustomHooks(config.customPoliciesPath);
|
|
75
75
|
for (const hook of customHooksList) {
|
|
76
76
|
const hookName = hook.name;
|
|
77
77
|
const fn: PolicyFunction = async (ctx): Promise<PolicyResult> => {
|