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.
Files changed (115) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/build-manifest.json +3 -3
  3. package/.next/standalone/.next/prerender-manifest.json +3 -3
  4. package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
  5. package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
  6. package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  7. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  8. package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
  9. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +2 -2
  10. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
  11. package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +3 -3
  12. package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +3 -3
  13. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  14. package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  15. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  16. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  17. package/.next/standalone/.next/server/app/_not-found.html +2 -2
  18. package/.next/standalone/.next/server/app/_not-found.rsc +17 -17
  19. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +17 -17
  20. package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
  21. package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +11 -11
  22. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
  23. package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
  24. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  25. package/.next/standalone/.next/server/app/index.html +1 -1
  26. package/.next/standalone/.next/server/app/index.rsc +16 -16
  27. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  28. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +16 -16
  29. package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +4 -4
  30. package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +11 -11
  31. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  32. package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
  33. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  34. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  35. package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +8 -8
  36. package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
  37. package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
  38. package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
  39. package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
  40. package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
  41. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
  42. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
  43. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
  44. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
  45. package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
  46. package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
  47. package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  48. package/.next/standalone/.next/server/chunks/[root-of-the-server]__02nt~6d._.js +1 -1
  49. package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_0z7w.hh._.js +1 -1
  50. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__092s1ta._.js +2 -2
  51. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__09icjsf._.js +2 -2
  52. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0unoyb1._.js → [root-of-the-server]__0cnhb7_._.js} +2 -2
  53. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0g.lg8b._.js +2 -2
  54. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0h..k-e._.js +2 -2
  55. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0osi8nq._.js +2 -2
  56. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0w6l33k._.js +4 -4
  57. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0g.-ow8._.js → [root-of-the-server]__0xmjv9e._.js} +2 -2
  58. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__11pa2ra._.js +2 -2
  59. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__12t-wym._.js +2 -2
  60. package/.next/standalone/.next/server/chunks/ssr/_10lm7or._.js +2 -2
  61. package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_0xerkr6._.js +1 -1
  62. package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_0q-m0y-._.js +2 -2
  63. package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
  64. package/.next/standalone/.next/server/pages/404.html +2 -2
  65. package/.next/standalone/.next/server/pages/500.html +1 -1
  66. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  67. package/.next/standalone/.next/server/server-reference-manifest.json +9 -9
  68. package/.next/standalone/.next/static/chunks/{0y-7a0dcrw047.js → 00qeuetfdsgjk.js} +1 -1
  69. package/.next/standalone/.next/static/chunks/{0ke6dphc4axsb.js → 07nvevyjq47qo.js} +1 -1
  70. package/.next/standalone/.next/static/chunks/{0s-.ej3z1p-ke.js → 0b.lzb_keexdb.js} +3 -3
  71. package/.next/standalone/.next/static/chunks/{0ca6y7bjo.ijt.js → 0iv-rbjm2j5nc.js} +1 -1
  72. package/.next/standalone/.next/static/chunks/{10d1jgbx0dgle.js → 0jfhld9mk1zm4.js} +1 -1
  73. package/.next/standalone/.next/static/chunks/{128ogw.xok4x2.js → 0jzowkzl-dd6s.js} +1 -1
  74. package/.next/standalone/.next/static/chunks/{0d2zd7ikio.lc.js → 0w4.ug1d.ok15.js} +2 -2
  75. package/.next/standalone/.next/static/chunks/15jpradyu_531.css +1 -0
  76. package/.next/standalone/.next/static/chunks/{12tzy91t9mk_w.js → 16_nu40klq96n.js} +1 -1
  77. package/.next/standalone/README.md +2 -2
  78. package/.next/standalone/app/actions/get-hooks-config.ts +4 -4
  79. package/.next/standalone/app/policies/hooks-client.tsx +2 -2
  80. package/.next/standalone/bin/failproofai.mjs +162 -57
  81. package/.next/standalone/components/reach-developers.tsx +11 -1
  82. package/.next/standalone/docs/architecture.md +6 -6
  83. package/.next/standalone/docs/cli-reference.md +5 -5
  84. package/.next/standalone/docs/configuration.md +12 -12
  85. package/.next/standalone/docs/custom-hooks.md +7 -7
  86. package/.next/standalone/docs/dashboard.md +1 -1
  87. package/.next/standalone/docs/getting-started.md +3 -3
  88. package/.next/standalone/docs/index.md +1 -1
  89. package/.next/standalone/docs/testing.md +1 -1
  90. package/.next/standalone/package.json +1 -1
  91. package/.next/standalone/scripts/launch.ts +2 -0
  92. package/.next/standalone/scripts/postinstall.mjs +2 -2
  93. package/.next/standalone/src/hooks/custom-hooks-loader.ts +6 -6
  94. package/.next/standalone/src/hooks/handler.ts +2 -2
  95. package/.next/standalone/src/hooks/hooks-config.ts +13 -13
  96. package/.next/standalone/src/hooks/install-prompt.ts +2 -2
  97. package/.next/standalone/src/hooks/llm-client.ts +2 -2
  98. package/.next/standalone/src/hooks/manager.ts +34 -26
  99. package/.next/standalone/src/hooks/policy-types.ts +1 -1
  100. package/README.md +2 -2
  101. package/bin/failproofai.mjs +162 -57
  102. package/package.json +1 -1
  103. package/scripts/launch.ts +2 -0
  104. package/scripts/postinstall.mjs +2 -2
  105. package/src/hooks/custom-hooks-loader.ts +6 -6
  106. package/src/hooks/handler.ts +2 -2
  107. package/src/hooks/hooks-config.ts +13 -13
  108. package/src/hooks/install-prompt.ts +2 -2
  109. package/src/hooks/llm-client.ts +2 -2
  110. package/src/hooks/manager.ts +34 -26
  111. package/src/hooks/policy-types.ts +1 -1
  112. package/.next/standalone/.next/static/chunks/08f78tecvx61l.css +0 -1
  113. /package/.next/standalone/.next/static/{W2hv3TMvrp7iPePv6-jJA → H15OMlkQejMvLowzdBldp}/_buildManifest.js +0 -0
  114. /package/.next/standalone/.next/static/{W2hv3TMvrp7iPePv6-jJA → H15OMlkQejMvLowzdBldp}/_clientMiddlewareManifest.js +0 -0
  115. /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
- * --install-policies Install hooks + enable policies in Claude Code settings
9
- * --remove-policies Remove hooks or disable policies from Claude Code settings
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-policies [policyNames...] [--scope user|project|local] [--beta] [--custom-hooks <path>] [--remove-custom-hooks]
45
- if (args.includes("--install-policies")) {
46
- const { installHooks } = await import("../src/hooks/manager");
47
-
48
- const scopeIdx = args.indexOf("--scope");
49
- const scope = scopeIdx >= 0 ? args[scopeIdx + 1] : "user";
50
-
51
- const customHooksIdx = args.indexOf("--custom-hooks");
52
- const customHooksPath = customHooksIdx >= 0 ? args[customHooksIdx + 1] : undefined;
53
-
54
- const includeBeta = args.includes("--beta");
55
- const removeCustomHooks = args.includes("--remove-custom-hooks");
56
-
57
- // Collect positional policy names (args after --install-policies that don't start with --)
58
- const installIdx = args.indexOf("--install-policies");
59
- const policyNames = args
60
- .slice(installIdx + 1)
61
- .filter((a) => !a.startsWith("--") && a !== scope && a !== customHooksPath);
62
-
63
- await installHooks(
64
- policyNames.length > 0 ? policyNames : undefined,
65
- scope,
66
- undefined,
67
- includeBeta,
68
- undefined,
69
- customHooksPath,
70
- removeCustomHooks,
71
- );
72
- process.exit(0);
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
- // --remove-policies [policyNames...] [--scope user|project|local|all] [--beta-only]
76
- if (args.includes("--remove-policies")) {
77
- const { removeHooks } = await import("../src/hooks/manager");
132
+ if (isInstall) {
133
+ const { installHooks } = await import("../src/hooks/manager");
78
134
 
79
- const scopeIdx = args.indexOf("--scope");
80
- const scope = scopeIdx >= 0 ? args[scopeIdx + 1] : "user";
135
+ const scopeIdx = subArgs.indexOf("--scope");
136
+ const scope = scopeIdx >= 0 ? subArgs[scopeIdx + 1] : "user";
81
137
 
82
- const betaOnly = args.includes("--beta-only");
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
- const removeIdx = args.indexOf("--remove-policies");
85
- const policyNames = args
86
- .slice(removeIdx + 1)
87
- .filter((a) => !a.startsWith("--") && a !== scope);
143
+ const includeBeta = subArgs.includes("--beta");
88
144
 
89
- await removeHooks(
90
- policyNames.length > 0 ? policyNames : undefined,
91
- scope,
92
- undefined,
93
- { betaOnly },
94
- );
95
- process.exit(0);
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
- // --list-policies
99
- if (args.includes("--list-policies")) {
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", "--hook", "--install-policies",
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", "--install-policies",
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 customHooksPath (if set)
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/hooks-config.json ← project (highest priority)
131
- [2] {cwd}/.failproofai/hooks-config.local.json ← local
132
- [3] ~/.failproofai/hooks-config.json ← global (lowest priority)
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
- - `customHooksPath` — first file that defines it wins
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 `customHooksPath` from config; skip if absent.
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-hooks <path>` | Path to a JS file containing custom hook policies |
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-hooks ./my-policies.js
82
+ failproofai --install-policies --custom ./my-policies.js
83
83
  ```
84
84
 
85
- When `--custom-hooks <path>` is provided, the resolved absolute path is saved to `hooks-config.json` as `customHooksPath`. The file is loaded and executed at hook-fire time (not at install time).
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
- | `--remove-custom-hooks` | Clear the `customHooksPath` from config |
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 --remove-custom-hooks
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/hooks-config.json` | Per-repo settings, committed to version control |
14
- | **local** | `.failproofai/hooks-config.local.json` | Personal per-repo overrides, gitignored |
15
- | **global** | `~/.failproofai/hooks-config.json` | User-level defaults across all projects |
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
- **`customHooksPath`** — first scope that defines it wins.
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
- "customHooksPath": "/home/alice/myproject/my-policies.js"
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
- ### `customHooksPath`
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-hooks <path>` (the path is resolved to absolute before being stored).
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 `hooks-config.json` is the file you manage directly. The two are separate:
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
- - **`hooks-config.json`** — tells failproofai which policies to evaluate and with what params
145
+ - **`policies-config.json`** — tells failproofai which policies to evaluate and with what params
146
146
 
147
- You can edit `hooks-config.json` directly at any time; changes take effect immediately on the next hook event with no restart needed.
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/hooks-config.json` to your repo:
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/hooks-config.local.json` (gitignored) for personal overrides without affecting teammates.
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-hooks ./my-policies.js
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-hooks ./my-policies.js
40
+ failproofai --install-policies --custom ./my-policies.js
41
41
 
42
42
  # Replace the hooks file path
43
- failproofai --install-policies --custom-hooks ./new-policies.js
43
+ failproofai --install-policies --custom ./new-policies.js
44
44
 
45
45
  # Remove the custom hooks path from config
46
- failproofai --remove-policies --remove-custom-hooks
46
+ failproofai --remove-policies --custom
47
47
  ```
48
48
 
49
- The resolved absolute path is stored in `hooks-config.json` as `customHooksPath`. The file is loaded fresh on every hook event — there is no caching between events.
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
- | `customHooksPath` not set | No custom hooks run; built-ins continue normally |
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-hooks ./examples/policies-basic.js
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/hooks-config.json`)
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/hooks-config.json` | Global policy configuration |
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/hooks-config.json` | Per-project policy configuration (committed) |
96
- | `.failproofai/hooks-config.local.json` | Per-project personal overrides (gitignored) |
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
 
@@ -43,5 +43,5 @@ failproofai --list-policies
43
43
 
44
44
  **Add a custom policy file:**
45
45
  ```bash
46
- failproofai --install-policies --custom-hooks ./my-policies.js
46
+ failproofai --install-policies --custom ./my-policies.js
47
47
  ```
@@ -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/hooks-config.json
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({
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "failproofai",
3
- "version": "0.0.1-beta.5",
3
+ "version": "0.0.1-beta.7",
4
4
  "description": "Open-source hooks, policies, and project visualization for Claude Code & Agents SDK",
5
5
  "bin": {
6
6
  "failproofai": "./bin/failproofai.mjs"
@@ -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", "hooks-config.json");
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 --remove-policies && failproofai --install-policies\n`
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
- customHooksPath: string | undefined,
19
+ customPoliciesPath: string | undefined,
20
20
  opts?: { strict?: boolean },
21
21
  ): Promise<CustomHook[]> {
22
- if (!customHooksPath) return [];
22
+ if (!customPoliciesPath) return [];
23
23
 
24
- const absPath = isAbsolute(customHooksPath)
25
- ? customHooksPath
26
- : resolve(process.cwd(), customHooksPath);
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(`customHooksPath not found: ${absPath}`);
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/hooks-config.json, evaluates matching policies, persists
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.customHooksPath);
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> => {