failproofai 0.0.8 → 0.0.9-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. package/.next/standalone/.codex/hooks.json +77 -0
  2. package/.next/standalone/.next/BUILD_ID +1 -1
  3. package/.next/standalone/.next/build-manifest.json +6 -6
  4. package/.next/standalone/.next/prerender-manifest.json +3 -3
  5. package/.next/standalone/.next/required-server-files.json +1 -1
  6. package/.next/standalone/.next/server/app/_global-error/page/build-manifest.json +3 -3
  7. package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
  8. package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
  9. package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  10. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  11. package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
  12. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +2 -2
  13. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
  14. package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +3 -3
  15. package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +3 -3
  16. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  17. package/.next/standalone/.next/server/app/_not-found/page/build-manifest.json +3 -3
  18. package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  19. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  20. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  21. package/.next/standalone/.next/server/app/_not-found.html +2 -2
  22. package/.next/standalone/.next/server/app/_not-found.rsc +17 -17
  23. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +17 -17
  24. package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
  25. package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +11 -11
  26. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
  27. package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
  28. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  29. package/.next/standalone/.next/server/app/index.html +1 -1
  30. package/.next/standalone/.next/server/app/index.rsc +16 -16
  31. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  32. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +16 -16
  33. package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +4 -4
  34. package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +11 -11
  35. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  36. package/.next/standalone/.next/server/app/page/build-manifest.json +3 -3
  37. package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
  38. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  39. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  40. package/.next/standalone/.next/server/app/policies/page/build-manifest.json +3 -3
  41. package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +8 -8
  42. package/.next/standalone/.next/server/app/policies/page.js +1 -1
  43. package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
  44. package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
  45. package/.next/standalone/.next/server/app/project/[name]/page/build-manifest.json +3 -3
  46. package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
  47. package/.next/standalone/.next/server/app/project/[name]/page.js +1 -1
  48. package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
  49. package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
  50. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/build-manifest.json +3 -3
  51. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
  52. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
  53. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js +1 -1
  54. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
  55. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
  56. package/.next/standalone/.next/server/app/projects/page/build-manifest.json +3 -3
  57. package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
  58. package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
  59. package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  60. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0g72weg._.js +1 -1
  61. package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_05pz9._._.js +1 -1
  62. package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_0z7w.hh._.js +1 -1
  63. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0h3orxc._.js → [root-of-the-server]__0.f_cyx._.js} +2 -2
  64. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0m72uj7._.js → [root-of-the-server]__03rd.z8._.js} +2 -2
  65. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__092s1ta._.js +2 -2
  66. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__09icjsf._.js +2 -2
  67. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0dub28-._.js +3 -0
  68. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0e74wa-._.js +3 -0
  69. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0g.lg8b._.js +2 -2
  70. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0h..k-e._.js +2 -2
  71. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0okos0k._.js → [root-of-the-server]__0vu.o-3._.js} +3 -3
  72. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0w6l33k._.js +7 -7
  73. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0of~riu._.js → [root-of-the-server]__0zqcovi._.js} +2 -2
  74. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__11pa2ra._.js +2 -2
  75. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__12t-wym._.js +2 -2
  76. package/.next/standalone/.next/server/chunks/ssr/_07a1g.3._.js +3 -0
  77. package/.next/standalone/.next/server/chunks/ssr/_0uy6m~m._.js +3 -0
  78. package/.next/standalone/.next/server/chunks/ssr/_0zaq1hm._.js +3 -0
  79. package/.next/standalone/.next/server/chunks/ssr/_10lm7or._.js +2 -2
  80. package/.next/standalone/.next/server/chunks/ssr/_11rg2a_._.js +3 -0
  81. package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_0xerkr6._.js +1 -1
  82. package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_0q-m0y-._.js +2 -2
  83. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_0h9llsw._.js +1 -1
  84. package/.next/standalone/.next/server/chunks/ssr/node_modules_posthog-node_dist_entrypoints_index_node_mjs_0mebn66._.js +1 -1
  85. package/.next/standalone/.next/server/middleware-build-manifest.js +6 -6
  86. package/.next/standalone/.next/server/pages/404.html +2 -2
  87. package/.next/standalone/.next/server/pages/500.html +1 -1
  88. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  89. package/.next/standalone/.next/server/server-reference-manifest.json +9 -9
  90. package/.next/standalone/.next/static/chunks/0.rk1iwdt1d7c.css +1 -0
  91. package/.next/standalone/.next/static/chunks/00b5h4r1el.6f.js +1 -0
  92. package/.next/standalone/.next/static/chunks/{01q52wg_amm60.js → 0_c_yox08g_44.js} +2 -2
  93. package/.next/standalone/.next/static/chunks/0bghqwo4iloy0.js +1 -0
  94. package/.next/standalone/.next/static/chunks/0fw2h.g66c0h3.js +1 -0
  95. package/.next/standalone/.next/static/chunks/0gu87mlr5ssnt.js +6 -0
  96. package/.next/standalone/.next/static/chunks/{0mbc8hyeqe2c4.js → 0igf3xbisp1lx.js} +1 -1
  97. package/.next/standalone/.next/static/chunks/{175-vim0.ztb2.js → 0jryicwtm9z2g.js} +2 -2
  98. package/.next/standalone/.next/static/chunks/{12simlrcfk3g2.js → 0kzk5-mh1_x53.js} +1 -1
  99. package/.next/standalone/.next/static/chunks/0p5zh2diw90a1.js +1 -0
  100. package/.next/standalone/.next/static/chunks/{0eowehbf5egcz.js → 0ufq8smh~i7wc.js} +1 -1
  101. package/.next/standalone/.next/static/chunks/{0vlk_pv4somht.js → 0vwqucikost_q.js} +1 -1
  102. package/.next/standalone/.next/static/chunks/{0t3euwspxi_zg.js → 0w1f.k~gi-y6..js} +1 -1
  103. package/.next/standalone/.next/static/chunks/{151bdxm9n-pry.js → 0z-jh701rc~j8.js} +1 -1
  104. package/.next/standalone/.next/static/chunks/{turbopack-0o7k.hakttp4k.js → turbopack-0s36is87fc9r2.js} +1 -1
  105. package/.next/standalone/app/actions/install-hooks-web.ts +21 -5
  106. package/.next/standalone/app/policies/hooks-client.tsx +23 -0
  107. package/.next/standalone/assets/logos/claude.svg +1 -0
  108. package/.next/standalone/assets/logos/openai-dark.svg +1 -0
  109. package/.next/standalone/assets/logos/openai-light.svg +1 -0
  110. package/.next/standalone/package.json +2 -2
  111. package/.next/standalone/server.js +1 -1
  112. package/README.md +22 -3
  113. package/bin/failproofai.mjs +89 -9
  114. package/dist/cli.mjs +1123 -281
  115. package/package.json +2 -2
  116. package/src/hooks/builtin-policies.ts +29 -6
  117. package/src/hooks/handler.ts +39 -10
  118. package/src/hooks/hook-activity-store.ts +2 -0
  119. package/src/hooks/install-prompt.ts +165 -0
  120. package/src/hooks/integrations.ts +373 -0
  121. package/src/hooks/manager.ts +96 -171
  122. package/src/hooks/policy-evaluator.ts +28 -1
  123. package/src/hooks/policy-types.ts +3 -1
  124. package/src/hooks/resolve-permission-mode.ts +147 -0
  125. package/src/hooks/types.ts +30 -1
  126. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0_rr1ty._.js +0 -3
  127. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0dj-tbi._.js +0 -3
  128. package/.next/standalone/.next/server/chunks/ssr/_0h21oar._.js +0 -3
  129. package/.next/standalone/.next/server/chunks/ssr/_0i~.gk_._.js +0 -3
  130. package/.next/standalone/.next/server/chunks/ssr/_0q3h.2s._.js +0 -3
  131. package/.next/standalone/.next/server/chunks/ssr/_0x..fj-._.js +0 -3
  132. package/.next/standalone/.next/static/chunks/096~b1zwv69ph.js +0 -1
  133. package/.next/standalone/.next/static/chunks/0bkir2pd22ski.js +0 -1
  134. package/.next/standalone/.next/static/chunks/0ksdlt_1hucdm.js +0 -1
  135. package/.next/standalone/.next/static/chunks/0lua3p__elu_..js +0 -6
  136. package/.next/standalone/.next/static/chunks/0mir9jdxn35~s.css +0 -1
  137. package/.next/standalone/.next/static/chunks/0s_18.dox44e9.js +0 -1
  138. /package/.next/standalone/.next/static/{RYld7TSCDXm2_WhJq20rD → CiVeb_yiVt-O2JYrzGzB7}/_buildManifest.js +0 -0
  139. /package/.next/standalone/.next/static/{RYld7TSCDXm2_WhJq20rD → CiVeb_yiVt-O2JYrzGzB7}/_clientMiddlewareManifest.js +0 -0
  140. /package/.next/standalone/.next/static/{RYld7TSCDXm2_WhJq20rD → CiVeb_yiVt-O2JYrzGzB7}/_ssgManifest.js +0 -0
@@ -116,6 +116,25 @@ function EventTypeBadge({ eventType }: { eventType: string }) {
116
116
  );
117
117
  }
118
118
 
119
+ function IntegrationBadge({ integration }: { integration?: string }) {
120
+ if (!integration) return null;
121
+ const label =
122
+ integration === "claude" ? "Claude Code" : integration === "codex" ? "OpenAI Codex" : integration;
123
+ const isCodex = integration === "codex";
124
+ return (
125
+ <span
126
+ className={`inline-flex items-center rounded px-1.5 py-0.5 text-[0.6rem] font-medium border ${
127
+ isCodex
128
+ ? "bg-purple-500/10 text-purple-400 border-purple-500/20"
129
+ : "bg-orange-500/10 text-orange-400 border-orange-500/20"
130
+ }`}
131
+ title={`Agent CLI: ${label}`}
132
+ >
133
+ {label}
134
+ </span>
135
+ );
136
+ }
137
+
119
138
  function ModeBadge({ mode }: { mode: string }) {
120
139
  const isDefault = mode === "default";
121
140
  return (
@@ -461,6 +480,7 @@ function ActivityTab({
461
480
  <th className="px-4 py-2.5 font-medium w-6" />
462
481
  <th className="px-3 py-2.5 font-medium">Decision</th>
463
482
  <th className="px-3 py-2.5 font-medium">Event</th>
483
+ <th className="px-3 py-2.5 font-medium">CLI</th>
464
484
  <th className="px-3 py-2.5 font-medium">Tool</th>
465
485
  <th className="px-3 py-2.5 font-medium">Policy</th>
466
486
  <th className="px-3 py-2.5 font-medium">Reason</th>
@@ -502,6 +522,9 @@ function ActivityTab({
502
522
  <td className="px-3 py-2">
503
523
  <EventTypeBadge eventType={item.eventType} />
504
524
  </td>
525
+ <td className="px-3 py-2">
526
+ <IntegrationBadge integration={item.integration} />
527
+ </td>
505
528
  <td className="px-3 py-2 font-mono text-foreground">
506
529
  {item.toolName ?? "\u2014"}
507
530
  </td>
@@ -0,0 +1 @@
1
+ <svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill="#D97757"><title>Claude</title><path d="m4.7144 15.9555 4.7174-2.6471.079-.2307-.079-.1275h-.2307l-.7893-.0486-2.6956-.0729-2.3375-.0971-2.2646-.1214-.5707-.1215-.5343-.7042.0546-.3522.4797-.3218.686.0608 1.5179.1032 2.2767.1578 1.6514.0972 2.4468.255h.3886l.0546-.1579-.1336-.0971-.1032-.0972L6.973 9.8356l-2.55-1.6879-1.3356-.9714-.7225-.4918-.3643-.4614-.1578-1.0078.6557-.7225.8803.0607.2246.0607.8925.686 1.9064 1.4754 2.4893 1.8336.3643.3035.1457-.1032.0182-.0728-.164-.2733-1.3539-2.4467-1.445-2.4893-.6435-1.032-.17-.6194c-.0607-.255-.1032-.4674-.1032-.7285L6.287.1335 6.6997 0l.9957.1336.419.3642.6192 1.4147 1.0018 2.2282 1.5543 3.0296.4553.8985.2429.8318.091.255h.1579v-.1457l.1275-1.706.2368-2.0947.2307-2.6957.0789-.7589.3764-.9107.7468-.4918.5828.2793.4797.686-.0668.4433-.2853 1.8517-.5586 2.9021-.3643 1.9429h.2125l.2429-.2429.9835-1.3053 1.6514-2.0643.7286-.8196.85-.9046.5464-.4311h1.0321l.759 1.1293-.34 1.1657-1.0625 1.3478-.8804 1.1414-1.2628 1.7-.7893 1.36.0729.1093.1882-.0183 2.8535-.607 1.5421-.2794 1.8396-.3157.8318.3886.091.3946-.3278.8075-1.967.4857-2.3072.4614-3.4364.8136-.0425.0304.0486.0607 1.5482.1457.6618.0364h1.621l3.0175.2247.7892.522.4736.6376-.079.4857-1.2142.6193-1.6393-.3886-3.825-.9107-1.3113-.3279h-.1822v.1093l1.0929 1.0686 2.0035 1.8092 2.5075 2.3314.1275.5768-.3218.4554-.34-.0486-2.2039-1.6575-.85-.7468-1.9246-1.621h-.1275v.17l.4432.6496 2.3436 3.5214.1214 1.0807-.17.3521-.6071.2125-.6679-.1214-1.3721-1.9246L14.38 17.959l-1.1414-1.9428-.1397.079-.674 7.2552-.3156.3703-.7286.2793-.6071-.4614-.3218-.7468.3218-1.4753.3886-1.9246.3157-1.53.2853-1.9004.17-.6314-.0121-.0425-.1397.0182-1.4328 1.9672-2.1796 2.9446-1.7243 1.8456-.4128.164-.7164-.3704.0667-.6618.4008-.5889 2.386-3.0357 1.4389-1.882.929-1.0868-.0062-.1579h-.0546l-6.3385 4.1164-1.1293.1457-.4857-.4554.0608-.7467.2307-.2429 1.9064-1.3114Z"/></svg>
@@ -0,0 +1 @@
1
+ <svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill="#FFFFFF"><title>OpenAI</title><path d="M22.2819 9.8211a5.9847 5.9847 0 0 0-.5157-4.9108 6.0462 6.0462 0 0 0-6.5098-2.9A6.0651 6.0651 0 0 0 4.9807 4.1818a5.9847 5.9847 0 0 0-3.9977 2.9 6.0462 6.0462 0 0 0 .7427 7.0966 5.98 5.98 0 0 0 .511 4.9107 6.051 6.051 0 0 0 6.5146 2.9001A5.9847 5.9847 0 0 0 13.2599 24a6.0557 6.0557 0 0 0 5.7718-4.2058 5.9894 5.9894 0 0 0 3.9977-2.9001 6.0557 6.0557 0 0 0-.7475-7.0729zm-9.022 12.6081a4.4755 4.4755 0 0 1-2.8764-1.0408l.1419-.0804 4.7783-2.7582a.7948.7948 0 0 0 .3927-.6813v-6.7369l2.02 1.1686a.071.071 0 0 1 .038.052v5.5826a4.504 4.504 0 0 1-4.4945 4.4944zm-9.6607-4.1254a4.4708 4.4708 0 0 1-.5346-3.0137l.142.0852 4.783 2.7582a.7712.7712 0 0 0 .7806 0l5.8428-3.3685v2.3324a.0804.0804 0 0 1-.0332.0615L9.74 19.9502a4.4992 4.4992 0 0 1-6.1408-1.6464zM2.3408 7.8956a4.485 4.485 0 0 1 2.3655-1.9728V11.6a.7664.7664 0 0 0 .3879.6765l5.8144 3.3543-2.0201 1.1685a.0757.0757 0 0 1-.071 0l-4.8303-2.7865A4.504 4.504 0 0 1 2.3408 7.872zm16.5963 3.8558L13.1038 8.364 15.1192 7.2a.0757.0757 0 0 1 .071 0l4.8303 2.7913a4.4944 4.4944 0 0 1-.6765 8.1042v-5.6772a.79.79 0 0 0-.407-.667zm2.0107-3.0231l-.142-.0852-4.7735-2.7818a.7759.7759 0 0 0-.7854 0L9.409 9.2297V6.8974a.0662.0662 0 0 1 .0284-.0615l4.8303-2.7866a4.4992 4.4992 0 0 1 6.6802 4.66zM8.3065 12.863l-2.02-1.1638a.0804.0804 0 0 1-.038-.0567V6.0742a4.4992 4.4992 0 0 1 7.3757-3.4537l-.142.0805L8.704 5.459a.7948.7948 0 0 0-.3927.6813zm1.0976-2.3654l2.602-1.4998 2.6069 1.4998v2.9994l-2.5974 1.4997-2.6067-1.4997Z"/></svg>
@@ -0,0 +1 @@
1
+ <svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill="#000000"><title>OpenAI</title><path d="M22.2819 9.8211a5.9847 5.9847 0 0 0-.5157-4.9108 6.0462 6.0462 0 0 0-6.5098-2.9A6.0651 6.0651 0 0 0 4.9807 4.1818a5.9847 5.9847 0 0 0-3.9977 2.9 6.0462 6.0462 0 0 0 .7427 7.0966 5.98 5.98 0 0 0 .511 4.9107 6.051 6.051 0 0 0 6.5146 2.9001A5.9847 5.9847 0 0 0 13.2599 24a6.0557 6.0557 0 0 0 5.7718-4.2058 5.9894 5.9894 0 0 0 3.9977-2.9001 6.0557 6.0557 0 0 0-.7475-7.0729zm-9.022 12.6081a4.4755 4.4755 0 0 1-2.8764-1.0408l.1419-.0804 4.7783-2.7582a.7948.7948 0 0 0 .3927-.6813v-6.7369l2.02 1.1686a.071.071 0 0 1 .038.052v5.5826a4.504 4.504 0 0 1-4.4945 4.4944zm-9.6607-4.1254a4.4708 4.4708 0 0 1-.5346-3.0137l.142.0852 4.783 2.7582a.7712.7712 0 0 0 .7806 0l5.8428-3.3685v2.3324a.0804.0804 0 0 1-.0332.0615L9.74 19.9502a4.4992 4.4992 0 0 1-6.1408-1.6464zM2.3408 7.8956a4.485 4.485 0 0 1 2.3655-1.9728V11.6a.7664.7664 0 0 0 .3879.6765l5.8144 3.3543-2.0201 1.1685a.0757.0757 0 0 1-.071 0l-4.8303-2.7865A4.504 4.504 0 0 1 2.3408 7.872zm16.5963 3.8558L13.1038 8.364 15.1192 7.2a.0757.0757 0 0 1 .071 0l4.8303 2.7913a4.4944 4.4944 0 0 1-.6765 8.1042v-5.6772a.79.79 0 0 0-.407-.667zm2.0107-3.0231l-.142-.0852-4.7735-2.7818a.7759.7759 0 0 0-.7854 0L9.409 9.2297V6.8974a.0662.0662 0 0 1 .0284-.0615l4.8303-2.7866a4.4992 4.4992 0 0 1 6.6802 4.66zM8.3065 12.863l-2.02-1.1638a.0804.0804 0 0 1-.038-.0567V6.0742a4.4992 4.4992 0 0 1 7.3757-3.4537l-.142.0805L8.704 5.459a.7948.7948 0 0 0-.3927.6813zm1.0976-2.3654l2.602-1.4998 2.6069 1.4998v2.9994l-2.5974 1.4997-2.6067-1.4997Z"/></svg>
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "failproofai",
3
- "version": "0.0.8",
3
+ "version": "0.0.9-beta.1",
4
4
  "description": "The easiest way to manage policies that keep your AI agents reliable, on-task, and running autonomously — for Claude Code & the Agents SDK",
5
5
  "bin": {
6
6
  "failproofai": "./dist/cli.mjs"
@@ -90,7 +90,7 @@
90
90
  "tailwind-merge": "^3.4.0",
91
91
  "tailwindcss": "^4.1.18",
92
92
  "typescript": "^6.0.2",
93
- "@anthropic-ai/sdk": "^0.90.0",
93
+ "@anthropic-ai/sdk": "^0.91.1",
94
94
  "vitest": "^4.0.18"
95
95
  },
96
96
  "dependencies": {
@@ -9,7 +9,7 @@ const currentPort = parseInt(process.env.PORT, 10) || 3000
9
9
  const hostname = process.env.HOSTNAME || '0.0.0.0'
10
10
 
11
11
  let keepAliveTimeout = parseInt(process.env.KEEP_ALIVE_TIMEOUT, 10)
12
- const nextConfig = {"env":{"NEXT_PUBLIC_APP_VERSION":"0.0.8"},"typescript":{"ignoreBuildErrors":false},"typedRoutes":false,"distDir":"./.next","cleanDistDir":true,"assetPrefix":"","cacheMaxMemorySize":52428800,"configOrigin":"next.config.ts","useFileSystemPublicRoutes":true,"generateEtags":true,"pageExtensions":["tsx","ts","jsx","js"],"poweredByHeader":true,"compress":true,"images":{"deviceSizes":[640,750,828,1080,1200,1920,2048,3840],"imageSizes":[32,48,64,96,128,256,384],"path":"/_next/image","loader":"default","loaderFile":"","domains":[],"disableStaticImages":false,"minimumCacheTTL":14400,"formats":["image/webp"],"maximumRedirects":3,"maximumResponseBody":50000000,"dangerouslyAllowLocalIP":false,"dangerouslyAllowSVG":false,"contentSecurityPolicy":"script-src 'none'; frame-src 'none'; sandbox;","contentDispositionType":"attachment","localPatterns":[{"pathname":"**","search":""}],"remotePatterns":[],"qualities":[75],"unoptimized":true,"customCacheHandler":false},"devIndicators":{"position":"bottom-left"},"onDemandEntries":{"maxInactiveAge":60000,"pagesBufferLength":5},"basePath":"","sassOptions":{},"trailingSlash":false,"i18n":null,"productionBrowserSourceMaps":false,"excludeDefaultMomentLocales":true,"reactProductionProfiling":false,"reactStrictMode":null,"reactMaxHeadersLength":6000,"httpAgentOptions":{"keepAlive":true},"logging":{"serverFunctions":true,"browserToTerminal":"warn"},"compiler":{},"expireTime":31536000,"staticPageGenerationTimeout":60,"output":"standalone","modularizeImports":{"@mui/icons-material":{"transform":"@mui/icons-material/{{member}}"},"lodash":{"transform":"lodash/{{member}}"}},"outputFileTracingRoot":"/home/runner/work/failproofai/failproofai","cacheComponents":false,"cacheLife":{"default":{"stale":300,"revalidate":900,"expire":4294967294},"seconds":{"stale":30,"revalidate":1,"expire":60},"minutes":{"stale":300,"revalidate":60,"expire":3600},"hours":{"stale":300,"revalidate":3600,"expire":86400},"days":{"stale":300,"revalidate":86400,"expire":604800},"weeks":{"stale":300,"revalidate":604800,"expire":2592000},"max":{"stale":300,"revalidate":2592000,"expire":31536000}},"cacheHandlers":{},"experimental":{"appNewScrollHandler":false,"useSkewCookie":false,"cssChunking":true,"multiZoneDraftMode":false,"appNavFailHandling":false,"prerenderEarlyExit":true,"serverMinification":true,"linkNoTouchStart":false,"caseSensitiveRoutes":false,"cachedNavigations":false,"partialFallbacks":false,"dynamicOnHover":false,"varyParams":false,"prefetchInlining":false,"preloadEntriesOnStart":true,"clientRouterFilter":true,"clientRouterFilterRedirects":false,"fetchCacheKeyPrefix":"","proxyPrefetch":"flexible","optimisticClientCache":true,"manualClientBasePath":false,"cpus":3,"memoryBasedWorkersCount":false,"imgOptConcurrency":null,"imgOptTimeoutInSeconds":7,"imgOptMaxInputPixels":268402689,"imgOptSequentialRead":null,"imgOptSkipMetadata":null,"isrFlushToDisk":true,"workerThreads":false,"optimizeCss":false,"nextScriptWorkers":false,"scrollRestoration":false,"externalDir":false,"disableOptimizedLoading":false,"gzipSize":true,"craCompat":false,"esmExternals":true,"fullySpecified":false,"swcTraceProfiling":false,"forceSwcTransforms":false,"largePageDataBytes":128000,"typedEnv":false,"parallelServerCompiles":false,"parallelServerBuildTraces":false,"ppr":false,"authInterrupts":false,"webpackMemoryOptimizations":false,"optimizeServerReact":true,"strictRouteTypes":false,"viewTransition":false,"removeUncaughtErrorAndRejectionListeners":false,"validateRSCRequestHeaders":false,"staleTimes":{"dynamic":0,"static":300},"reactDebugChannel":true,"serverComponentsHmrCache":true,"staticGenerationMaxConcurrency":8,"staticGenerationMinPagesPerWorker":25,"transitionIndicator":false,"gestureTransition":false,"inlineCss":false,"useCache":false,"globalNotFound":false,"browserDebugInfoInTerminal":"warn","lockDistDir":true,"proxyClientMaxBodySize":10485760,"hideLogsAfterAbort":false,"mcpServer":true,"turbopackFileSystemCacheForDev":true,"turbopackFileSystemCacheForBuild":false,"turbopackInferModuleSideEffects":true,"turbopackPluginRuntimeStrategy":"childProcesses","optimizePackageImports":["lucide-react","date-fns","lodash-es","ramda","antd","react-bootstrap","ahooks","@ant-design/icons","@headlessui/react","@headlessui-float/react","@heroicons/react/20/solid","@heroicons/react/24/solid","@heroicons/react/24/outline","@visx/visx","@tremor/react","rxjs","@mui/material","@mui/icons-material","recharts","react-use","effect","@effect/schema","@effect/platform","@effect/platform-node","@effect/platform-browser","@effect/platform-bun","@effect/sql","@effect/sql-mssql","@effect/sql-mysql2","@effect/sql-pg","@effect/sql-sqlite-node","@effect/sql-sqlite-bun","@effect/sql-sqlite-wasm","@effect/sql-sqlite-react-native","@effect/rpc","@effect/rpc-http","@effect/typeclass","@effect/experimental","@effect/opentelemetry","@material-ui/core","@material-ui/icons","@tabler/icons-react","mui-core","react-icons/ai","react-icons/bi","react-icons/bs","react-icons/cg","react-icons/ci","react-icons/di","react-icons/fa","react-icons/fa6","react-icons/fc","react-icons/fi","react-icons/gi","react-icons/go","react-icons/gr","react-icons/hi","react-icons/hi2","react-icons/im","react-icons/io","react-icons/io5","react-icons/lia","react-icons/lib","react-icons/lu","react-icons/md","react-icons/pi","react-icons/ri","react-icons/rx","react-icons/si","react-icons/sl","react-icons/tb","react-icons/tfi","react-icons/ti","react-icons/vsc","react-icons/wi"],"trustHostHeader":false,"isExperimentalCompile":false},"htmlLimitedBots":"[\\w-]+-Google|Google-[\\w-]+|Chrome-Lighthouse|Slurp|DuckDuckBot|baiduspider|yandex|sogou|bitlybot|tumblr|vkShare|quora link preview|redditbot|ia_archiver|Bingbot|BingPreview|applebot|facebookexternalhit|facebookcatalog|Twitterbot|LinkedInBot|Slackbot|Discordbot|WhatsApp|SkypeUriPreview|Yeti|googleweblight","bundlePagesRouterDependencies":false,"configFileName":"next.config.ts","outputFileTracingExcludes":{"*":["node_modules/@img/**","node_modules/sharp/**"]},"turbopack":{"root":"/home/runner/work/failproofai/failproofai"},"distDirRoot":".next"}
12
+ const nextConfig = {"env":{"NEXT_PUBLIC_APP_VERSION":"0.0.9-beta.1"},"typescript":{"ignoreBuildErrors":false},"typedRoutes":false,"distDir":"./.next","cleanDistDir":true,"assetPrefix":"","cacheMaxMemorySize":52428800,"configOrigin":"next.config.ts","useFileSystemPublicRoutes":true,"generateEtags":true,"pageExtensions":["tsx","ts","jsx","js"],"poweredByHeader":true,"compress":true,"images":{"deviceSizes":[640,750,828,1080,1200,1920,2048,3840],"imageSizes":[32,48,64,96,128,256,384],"path":"/_next/image","loader":"default","loaderFile":"","domains":[],"disableStaticImages":false,"minimumCacheTTL":14400,"formats":["image/webp"],"maximumRedirects":3,"maximumResponseBody":50000000,"dangerouslyAllowLocalIP":false,"dangerouslyAllowSVG":false,"contentSecurityPolicy":"script-src 'none'; frame-src 'none'; sandbox;","contentDispositionType":"attachment","localPatterns":[{"pathname":"**","search":""}],"remotePatterns":[],"qualities":[75],"unoptimized":true,"customCacheHandler":false},"devIndicators":{"position":"bottom-left"},"onDemandEntries":{"maxInactiveAge":60000,"pagesBufferLength":5},"basePath":"","sassOptions":{},"trailingSlash":false,"i18n":null,"productionBrowserSourceMaps":false,"excludeDefaultMomentLocales":true,"reactProductionProfiling":false,"reactStrictMode":null,"reactMaxHeadersLength":6000,"httpAgentOptions":{"keepAlive":true},"logging":{"serverFunctions":true,"browserToTerminal":"warn"},"compiler":{},"expireTime":31536000,"staticPageGenerationTimeout":60,"output":"standalone","modularizeImports":{"@mui/icons-material":{"transform":"@mui/icons-material/{{member}}"},"lodash":{"transform":"lodash/{{member}}"}},"outputFileTracingRoot":"/home/runner/work/failproofai/failproofai","cacheComponents":false,"cacheLife":{"default":{"stale":300,"revalidate":900,"expire":4294967294},"seconds":{"stale":30,"revalidate":1,"expire":60},"minutes":{"stale":300,"revalidate":60,"expire":3600},"hours":{"stale":300,"revalidate":3600,"expire":86400},"days":{"stale":300,"revalidate":86400,"expire":604800},"weeks":{"stale":300,"revalidate":604800,"expire":2592000},"max":{"stale":300,"revalidate":2592000,"expire":31536000}},"cacheHandlers":{},"experimental":{"appNewScrollHandler":false,"useSkewCookie":false,"cssChunking":true,"multiZoneDraftMode":false,"appNavFailHandling":false,"prerenderEarlyExit":true,"serverMinification":true,"linkNoTouchStart":false,"caseSensitiveRoutes":false,"cachedNavigations":false,"partialFallbacks":false,"dynamicOnHover":false,"varyParams":false,"prefetchInlining":false,"preloadEntriesOnStart":true,"clientRouterFilter":true,"clientRouterFilterRedirects":false,"fetchCacheKeyPrefix":"","proxyPrefetch":"flexible","optimisticClientCache":true,"manualClientBasePath":false,"cpus":3,"memoryBasedWorkersCount":false,"imgOptConcurrency":null,"imgOptTimeoutInSeconds":7,"imgOptMaxInputPixels":268402689,"imgOptSequentialRead":null,"imgOptSkipMetadata":null,"isrFlushToDisk":true,"workerThreads":false,"optimizeCss":false,"nextScriptWorkers":false,"scrollRestoration":false,"externalDir":false,"disableOptimizedLoading":false,"gzipSize":true,"craCompat":false,"esmExternals":true,"fullySpecified":false,"swcTraceProfiling":false,"forceSwcTransforms":false,"largePageDataBytes":128000,"typedEnv":false,"parallelServerCompiles":false,"parallelServerBuildTraces":false,"ppr":false,"authInterrupts":false,"webpackMemoryOptimizations":false,"optimizeServerReact":true,"strictRouteTypes":false,"viewTransition":false,"removeUncaughtErrorAndRejectionListeners":false,"validateRSCRequestHeaders":false,"staleTimes":{"dynamic":0,"static":300},"reactDebugChannel":true,"serverComponentsHmrCache":true,"staticGenerationMaxConcurrency":8,"staticGenerationMinPagesPerWorker":25,"transitionIndicator":false,"gestureTransition":false,"inlineCss":false,"useCache":false,"globalNotFound":false,"browserDebugInfoInTerminal":"warn","lockDistDir":true,"proxyClientMaxBodySize":10485760,"hideLogsAfterAbort":false,"mcpServer":true,"turbopackFileSystemCacheForDev":true,"turbopackFileSystemCacheForBuild":false,"turbopackInferModuleSideEffects":true,"turbopackPluginRuntimeStrategy":"childProcesses","optimizePackageImports":["lucide-react","date-fns","lodash-es","ramda","antd","react-bootstrap","ahooks","@ant-design/icons","@headlessui/react","@headlessui-float/react","@heroicons/react/20/solid","@heroicons/react/24/solid","@heroicons/react/24/outline","@visx/visx","@tremor/react","rxjs","@mui/material","@mui/icons-material","recharts","react-use","effect","@effect/schema","@effect/platform","@effect/platform-node","@effect/platform-browser","@effect/platform-bun","@effect/sql","@effect/sql-mssql","@effect/sql-mysql2","@effect/sql-pg","@effect/sql-sqlite-node","@effect/sql-sqlite-bun","@effect/sql-sqlite-wasm","@effect/sql-sqlite-react-native","@effect/rpc","@effect/rpc-http","@effect/typeclass","@effect/experimental","@effect/opentelemetry","@material-ui/core","@material-ui/icons","@tabler/icons-react","mui-core","react-icons/ai","react-icons/bi","react-icons/bs","react-icons/cg","react-icons/ci","react-icons/di","react-icons/fa","react-icons/fa6","react-icons/fc","react-icons/fi","react-icons/gi","react-icons/go","react-icons/gr","react-icons/hi","react-icons/hi2","react-icons/im","react-icons/io","react-icons/io5","react-icons/lia","react-icons/lib","react-icons/lu","react-icons/md","react-icons/pi","react-icons/ri","react-icons/rx","react-icons/si","react-icons/sl","react-icons/tb","react-icons/tfi","react-icons/ti","react-icons/vsc","react-icons/wi"],"trustHostHeader":false,"isExperimentalCompile":false},"htmlLimitedBots":"[\\w-]+-Google|Google-[\\w-]+|Chrome-Lighthouse|Slurp|DuckDuckBot|baiduspider|yandex|sogou|bitlybot|tumblr|vkShare|quora link preview|redditbot|ia_archiver|Bingbot|BingPreview|applebot|facebookexternalhit|facebookcatalog|Twitterbot|LinkedInBot|Slackbot|Discordbot|WhatsApp|SkypeUriPreview|Yeti|googleweblight","bundlePagesRouterDependencies":false,"configFileName":"next.config.ts","outputFileTracingExcludes":{"*":["node_modules/@img/**","node_modules/sharp/**"]},"turbopack":{"root":"/home/runner/work/failproofai/failproofai"},"distDirRoot":".next"}
13
13
 
14
14
  process.env.__NEXT_PRIVATE_STANDALONE_CONFIG = JSON.stringify(nextConfig)
15
15
 
package/README.md CHANGED
@@ -17,13 +17,32 @@
17
17
 
18
18
  **Translations**: [简体中文](docs/i18n/README.zh.md) | [日本語](docs/i18n/README.ja.md) | [한국어](docs/i18n/README.ko.md) | [Español](docs/i18n/README.es.md) | [Português](docs/i18n/README.pt-br.md) | [Deutsch](docs/i18n/README.de.md) | [Français](docs/i18n/README.fr.md) | [Русский](docs/i18n/README.ru.md) | [हिन्दी](docs/i18n/README.hi.md) | [Türkçe](docs/i18n/README.tr.md) | [Tiếng Việt](docs/i18n/README.vi.md) | [Italiano](docs/i18n/README.it.md) | [العربية](docs/i18n/README.ar.md) | [עברית](docs/i18n/README.he.md)
19
19
 
20
- The easiest way to manage policies that keep your AI agents reliable, on-task, and running autonomously - for **Claude Code** & the **Agents SDK**.
20
+ The easiest way to manage policies that keep your AI agents reliable, on-task, and running autonomously - for **Claude Code**, **OpenAI Codex** & the **Agents SDK**.
21
21
 
22
22
  <p align="center">
23
23
  <img src="failproofai-hq.gif" alt="Failproof AI in action" width="800" />
24
24
  </p>
25
25
 
26
- - **32 Built-in Policies** - Catch common agent failure modes out of the box. Block destructive commands, prevent secret leakage, keep agents inside project boundaries, detect loops, and more.
26
+ ## Supported agent CLIs
27
+
28
+ <p align="center">
29
+ <a href="https://claude.com/claude-code" title="Claude Code">
30
+ <img src="assets/logos/claude.svg" alt="Claude Code" width="64" height="64" />
31
+ </a>
32
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
33
+ <a href="https://developers.openai.com/codex" title="OpenAI Codex">
34
+ <picture>
35
+ <source media="(prefers-color-scheme: dark)" srcset="assets/logos/openai-dark.svg" />
36
+ <img src="assets/logos/openai-light.svg" alt="OpenAI Codex" width="64" height="64" />
37
+ </picture>
38
+ </a>
39
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
40
+ <strong>+ more coming soon</strong>
41
+ </p>
42
+
43
+ > Install hooks for one or both: `failproofai policies --install --cli codex` (or `--cli claude codex`). Omit `--cli` to auto-detect installed CLIs and prompt.
44
+
45
+ - **39 Built-in Policies** - Catch common agent failure modes out of the box. Block destructive commands, prevent secret leakage, keep agents inside project boundaries, detect loops, and more.
27
46
  - **Custom Policies** - Write your own reliability rules in JavaScript. Use the `allow`/`deny`/`instruct` API to enforce conventions, prevent drift, gate operations, or integrate with external systems.
28
47
  - **Easy Configuration** - Tune any policy without writing code. Set allowlists, protected branches, thresholds per-project or globally. Three-scope config merges automatically.
29
48
  - **Agent Monitor** - See what your agents did while you were away. Browse sessions, inspect every tool call, and review exactly where policies fired.
@@ -258,7 +277,7 @@ FAILPROOFAI_TELEMETRY_DISABLED=1 failproofai
258
277
  | Guide | Description |
259
278
  |-------|-------------|
260
279
  | [Getting Started](docs/getting-started.mdx) | Installation and first steps |
261
- | [Built-in Policies](docs/built-in-policies.mdx) | All 32 built-in policies with parameters |
280
+ | [Built-in Policies](docs/built-in-policies.mdx) | All 39 built-in policies with parameters |
262
281
  | [Custom Policies](docs/custom-policies.mdx) | Write your own policies |
263
282
  | [Configuration](docs/configuration.mdx) | Config file format and scope merging |
264
283
  | [Dashboard](docs/dashboard.mdx) | Monitor sessions and review policy activity |
@@ -37,18 +37,24 @@ const args = process.argv.slice(2);
37
37
  // Normalize 'p' → 'policies' (shorthand alias)
38
38
  if (args[0] === "p") args[0] = "policies";
39
39
 
40
- // --hook <event> — called by Claude Code hooks; fast path, outside runCli()
41
- // because it has its own exit code contract with Claude Code.
40
+ // --hook <event> [--cli <name>] — called by an agent CLI hook; fast path, outside
41
+ // runCli() because it has its own exit code contract with the calling agent.
42
42
  const hookIdx = args.indexOf("--hook");
43
43
  if (hookIdx >= 0) {
44
44
  if (!args[hookIdx + 1]) {
45
45
  console.error("Error: Missing event type after --hook");
46
- console.error("Usage: failproofai --hook <event> (e.g. PreToolUse, PostToolUse)");
46
+ console.error("Usage: failproofai --hook <event> [--cli <claude|codex>]");
47
47
  process.exit(1);
48
48
  }
49
+ const eventType = args[hookIdx + 1];
50
+ const cliIdx = args.indexOf("--cli");
51
+ const cliArg = cliIdx >= 0 ? args[cliIdx + 1] : undefined;
52
+ // Default cli=claude preserves back-compat for hooks installed before
53
+ // multi-CLI support landed.
54
+ const cli = cliArg && (cliArg === "claude" || cliArg === "codex") ? cliArg : "claude";
49
55
  try {
50
56
  const { handleHookEvent } = await import("../src/hooks/handler");
51
- const exitCode = await handleHookEvent(args[hookIdx + 1]);
57
+ const exitCode = await handleHookEvent(eventType, cli);
52
58
  process.exit(exitCode);
53
59
  } catch (err) {
54
60
  const msg = err instanceof Error ? err.message : String(err);
@@ -94,14 +100,19 @@ COMMANDS
94
100
  (no args) Launch the policy dashboard
95
101
 
96
102
  policies, p List all available policies and their status
97
- policies --install, -i Enable policies in Claude Code settings
103
+ policies --install, -i Enable policies in agent CLI settings
98
104
  [names...] Specific policy names to enable
105
+ --cli claude|codex Agent CLI(s) to install for; space-separated
106
+ (e.g. --cli claude codex) or repeated.
107
+ Default: detect installed CLIs and prompt.
99
108
  --scope user|project|local Config scope to write to (default: user)
109
+ (Codex supports user|project only)
100
110
  --beta Include beta policies
101
111
  --custom, -c <path> Path to a JS file of custom policies
102
112
 
103
113
  policies --uninstall, -u Disable policies or remove hooks
104
114
  [names...] Specific policy names to disable
115
+ --cli claude|codex Agent CLI(s) to uninstall from
105
116
  --scope user|project|local|all Config scope to remove from (default: user)
106
117
  --beta Remove only beta policies
107
118
  --custom, -c Clear the customPoliciesPath from config
@@ -126,9 +137,12 @@ EXAMPLES
126
137
  failproofai policies
127
138
  failproofai policies --install
128
139
  failproofai policies --install block-sudo sanitize-api-keys --scope project
140
+ failproofai policies --install --cli codex --scope project
141
+ failproofai policies --install --cli claude codex
129
142
  failproofai policies --install --custom ./my-policies.js
130
143
  failproofai policies -i -c ./my-policies.js
131
144
  failproofai policies --uninstall block-sudo
145
+ failproofai policies --uninstall --cli codex
132
146
  failproofai policies --uninstall --custom
133
147
 
134
148
  LINKS
@@ -167,13 +181,19 @@ USAGE
167
181
 
168
182
  OPTIONS (install)
169
183
  [names...] Specific policy names to enable (omit for interactive)
184
+ --cli claude|codex Agent CLI(s) to install for; space-separated
185
+ (e.g. --cli claude codex) or repeated. Omit to
186
+ detect installed CLIs and prompt (or auto-pick
187
+ if only one is found).
170
188
  --scope user|project|local Config scope to write to (default: user)
189
+ (Codex supports user|project only)
171
190
  --beta Include beta policies
172
191
  --custom, -c <path> Path to a JS file of custom policies
173
192
  (skips interactive prompt; validates file first)
174
193
 
175
194
  OPTIONS (uninstall)
176
195
  [names...] Specific policy names to disable (omit to remove hooks)
196
+ --cli claude|codex Agent CLI(s) to uninstall from
177
197
  --scope user|project|local|all Config scope to remove from (default: user)
178
198
  --beta Remove only beta policies
179
199
  --custom, -c Clear the customPoliciesPath from config
@@ -182,9 +202,12 @@ EXAMPLES
182
202
  failproofai policies
183
203
  failproofai policies --install
184
204
  failproofai policies --install block-sudo sanitize-api-keys
205
+ failproofai policies --install --cli codex --scope project
206
+ failproofai policies --install --cli claude codex
185
207
  failproofai policies --install --custom ./my-policies.js
186
208
  failproofai policies -i -c ./my-policies.js
187
209
  failproofai policies --uninstall block-sudo
210
+ failproofai policies --uninstall --cli codex
188
211
  failproofai policies -u
189
212
  failproofai policies --uninstall --custom
190
213
  `.trimStart());
@@ -193,6 +216,7 @@ EXAMPLES
193
216
 
194
217
  if (isInstall) {
195
218
  const { installHooks } = await import("../src/hooks/manager");
219
+ const { resolveTargetClis } = await import("../src/hooks/install-prompt");
196
220
 
197
221
  const scopeIdx = subArgs.indexOf("--scope");
198
222
  const scope = scopeIdx >= 0 ? subArgs[scopeIdx + 1] : "user";
@@ -211,15 +235,41 @@ EXAMPLES
211
235
  throw new CliError("Missing path after --custom/-c\nUsage: --custom <path> (e.g. --custom ./my-policies.js)");
212
236
  }
213
237
 
238
+ // --cli accepts one or more space-separated values, optionally repeated:
239
+ // --cli claude codex
240
+ // --cli claude --cli codex
241
+ // Values are consumed greedily until the next flag or end of argv.
242
+ const VALID_CLIS = new Set(["claude", "codex"]);
243
+ const cliFlagValues = [];
244
+ const cliConsumedIdxs = new Set();
245
+ const cliFlagIdxs = subArgs.map((a, i) => (a === "--cli" ? i : -1)).filter((i) => i >= 0);
246
+ for (const idx of cliFlagIdxs) {
247
+ let consumed = 0;
248
+ for (let j = idx + 1; j < subArgs.length; j++) {
249
+ const v = subArgs[j];
250
+ if (v.startsWith("-")) break;
251
+ // Stop at the first non-CLI token so a policy name following --cli
252
+ // (e.g. `--cli claude block-sudo`) is not mis-consumed as a CLI.
253
+ if (!VALID_CLIS.has(v)) break;
254
+ cliFlagValues.push(v);
255
+ cliConsumedIdxs.add(j);
256
+ consumed++;
257
+ }
258
+ if (consumed === 0) {
259
+ throw new CliError("Missing value(s) for --cli. Usage: --cli claude codex (or any subset)");
260
+ }
261
+ }
262
+
214
263
  const includeBeta = subArgs.includes("--beta");
215
264
 
216
265
  // Collect positional policy names — args that don't start with - and aren't
217
- // values consumed by --scope or --custom/-c (tracked by index, not value,
266
+ // values consumed by --scope, --custom/-c, or --cli (tracked by index, not value,
218
267
  // so a policy named "user" isn't incorrectly dropped by the default scope).
219
268
  const consumedIdxs = new Set();
220
269
  if (scopeIdx >= 0) consumedIdxs.add(scopeIdx + 1);
221
270
  if (customIdx >= 0) consumedIdxs.add(customIdx + 1);
222
- const flags = new Set(["--install", "-i", "--scope", "--beta", "--custom", "-c"]);
271
+ for (const i of cliConsumedIdxs) consumedIdxs.add(i);
272
+ const flags = new Set(["--install", "-i", "--scope", "--beta", "--custom", "-c", "--cli"]);
223
273
  const unknownInstallFlag = subArgs.find((a) => a.startsWith("-") && !flags.has(a));
224
274
  if (unknownInstallFlag) {
225
275
  throw new CliError(`Unknown flag: ${unknownInstallFlag}\nRun \`failproofai policies --help\` for usage.`);
@@ -237,6 +287,8 @@ EXAMPLES
237
287
  : customPoliciesPath !== undefined ? []
238
288
  : undefined;
239
289
 
290
+ const cli = await resolveTargetClis(cliFlagValues.length > 0 ? cliFlagValues : undefined);
291
+
240
292
  await installHooks(
241
293
  policyNames,
242
294
  scope,
@@ -244,12 +296,15 @@ EXAMPLES
244
296
  includeBeta,
245
297
  undefined,
246
298
  customPoliciesPath,
299
+ false,
300
+ cli,
247
301
  );
248
302
  process.exit(0);
249
303
  }
250
304
 
251
305
  if (isUninstall) {
252
306
  const { removeHooks } = await import("../src/hooks/manager");
307
+ const { resolveTargetClis } = await import("../src/hooks/install-prompt");
253
308
 
254
309
  const scopeIdx = subArgs.indexOf("--scope");
255
310
  const scope = scopeIdx >= 0 ? subArgs[scopeIdx + 1] : "user";
@@ -260,12 +315,35 @@ EXAMPLES
260
315
  throw new CliError(`Invalid scope: ${scope}. Valid values: user, project, local, all`);
261
316
  }
262
317
 
318
+ // --cli accepts one or more space-separated values; same parser as install.
319
+ const VALID_CLIS = new Set(["claude", "codex"]);
320
+ const cliFlagValues = [];
321
+ const cliConsumedIdxs = new Set();
322
+ const cliFlagIdxs = subArgs.map((a, i) => (a === "--cli" ? i : -1)).filter((i) => i >= 0);
323
+ for (const idx of cliFlagIdxs) {
324
+ let consumed = 0;
325
+ for (let j = idx + 1; j < subArgs.length; j++) {
326
+ const v = subArgs[j];
327
+ if (v.startsWith("-")) break;
328
+ // Stop at the first non-CLI token so a policy name following --cli
329
+ // (e.g. `--cli claude block-sudo`) is not mis-consumed as a CLI.
330
+ if (!VALID_CLIS.has(v)) break;
331
+ cliFlagValues.push(v);
332
+ cliConsumedIdxs.add(j);
333
+ consumed++;
334
+ }
335
+ if (consumed === 0) {
336
+ throw new CliError("Missing value(s) for --cli. Usage: --cli claude codex (or any subset)");
337
+ }
338
+ }
339
+
263
340
  const betaOnly = subArgs.includes("--beta");
264
341
  const removeCustomHooks = subArgs.includes("--custom") || subArgs.includes("-c");
265
342
 
266
343
  const consumedIdxs = new Set();
267
344
  if (scopeIdx >= 0) consumedIdxs.add(scopeIdx + 1);
268
- const flags = new Set(["--uninstall", "-u", "--scope", "--beta", "--custom", "-c"]);
345
+ for (const i of cliConsumedIdxs) consumedIdxs.add(i);
346
+ const flags = new Set(["--uninstall", "-u", "--scope", "--beta", "--custom", "-c", "--cli"]);
269
347
  const unknownUninstallFlag = subArgs.find((a) => a.startsWith("-") && !flags.has(a));
270
348
  if (unknownUninstallFlag) {
271
349
  throw new CliError(`Unknown flag: ${unknownUninstallFlag}\nRun \`failproofai policies --help\` for usage.`);
@@ -275,11 +353,13 @@ EXAMPLES
275
353
  (a, idx) => !a.startsWith("-") && !consumedIdxs.has(idx)
276
354
  );
277
355
 
356
+ const cli = await resolveTargetClis(cliFlagValues.length > 0 ? cliFlagValues : undefined);
357
+
278
358
  await removeHooks(
279
359
  policyNames.length > 0 ? policyNames : undefined,
280
360
  scope,
281
361
  undefined,
282
- { betaOnly, removeCustomHooks },
362
+ { betaOnly, removeCustomHooks, cli },
283
363
  );
284
364
  process.exit(0);
285
365
  }