failproofai 1.0.7-beta.2 → 1.0.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 (252) 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 +4 -4
  4. package/.next/standalone/.next/required-server-files.json +1 -1
  5. package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
  6. package/.next/standalone/.next/server/app/_global-error/page.js +4 -4
  7. package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
  8. package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  9. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  10. package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
  11. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +6 -6
  12. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
  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 +4 -4
  16. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  17. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  18. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  19. package/.next/standalone/.next/server/app/_not-found.rsc +15 -15
  20. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +15 -15
  21. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +14 -14
  22. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  23. package/.next/standalone/.next/server/app/api/audit/invite/route.js.nft.json +1 -1
  24. package/.next/standalone/.next/server/app/api/audit/run/route.js +7 -8
  25. package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -1
  26. package/.next/standalone/.next/server/app/api/audit/status/route.js.nft.json +1 -1
  27. package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -1
  28. package/.next/standalone/.next/server/app/api/auth/login-verify/route.js.nft.json +1 -1
  29. package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
  30. package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -1
  31. package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
  32. package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +2 -2
  33. package/.next/standalone/.next/server/app/audit/page.js +5 -7
  34. package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -1
  35. package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
  36. package/.next/standalone/.next/server/app/index.html +1 -1
  37. package/.next/standalone/.next/server/app/index.rsc +15 -15
  38. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +14 -14
  39. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +15 -15
  40. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  41. package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
  42. package/.next/standalone/.next/server/app/page.js +6 -6
  43. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  44. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  45. package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +14 -14
  46. package/.next/standalone/.next/server/app/policies/page.js +11 -13
  47. package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
  48. package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
  49. package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
  50. package/.next/standalone/.next/server/app/project/[name]/page.js +7 -8
  51. package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
  52. package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
  53. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
  54. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
  55. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js +7 -7
  56. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
  57. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
  58. package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
  59. package/.next/standalone/.next/server/app/projects/page.js +6 -7
  60. package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
  61. package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  62. package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +8 -41
  63. package/.next/standalone/.next/server/app/settings/page.js +9 -12
  64. package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
  65. package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  66. package/.next/standalone/.next/server/chunks/{[externals]__1j-zsg5._.js → [externals]__1_bftcl._.js} +1 -1
  67. package/.next/standalone/.next/server/chunks/{[externals]__19_pzeq._.js → [externals]__1msfs-h._.js} +1 -1
  68. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0l3yhx4._.js +2 -2
  69. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0o07qi9._.js +1 -1
  70. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__1bf34x4._.js → [root-of-the-server]__1_r2rbg._.js} +7 -5
  71. package/.next/standalone/.next/server/chunks/_09dz7xv._.js +21 -21
  72. package/.next/standalone/.next/server/chunks/_0tovk6q._.js +1 -1
  73. package/.next/standalone/.next/server/chunks/_0trp3yc._.js +1 -1
  74. package/.next/standalone/.next/server/chunks/{_1q5i8mb._.js → _1c3k-8x._.js} +2 -2
  75. package/.next/standalone/.next/server/chunks/_1ek68ln._.js +16 -16
  76. package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
  77. package/.next/standalone/.next/server/chunks/src_hooks_0iu54mz._.js +3 -0
  78. package/.next/standalone/.next/server/chunks/src_hooks_custom-hooks-loader_ts_0lnb3n3._.js +2 -4
  79. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0-_ki57._.js +4 -0
  80. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__013jr2b._.js +4 -0
  81. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__01wy8d-._.js +4 -0
  82. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__02npjtd._.js +4 -0
  83. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0l44ual._.js → [root-of-the-server]__0bd3mje._.js} +2 -2
  84. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0cg-bgc._.js +5 -0
  85. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0cpu_mj._.js +3 -0
  86. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1mf3zp6._.js → [root-of-the-server]__0cxe_2_._.js} +3 -3
  87. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0da85px._.js +4 -0
  88. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ftmoxc._.js +4 -0
  89. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0p-5p8u._.js +4 -0
  90. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0u3w0ll._.js +22 -0
  91. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__17d_ffl._.js +3 -0
  92. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__19d9tgz._.js +5 -0
  93. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1ctpynv._.js +3 -0
  94. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1jiwfsj._.js +3 -0
  95. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1p2otjt._.js +4 -0
  96. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1phc187._.js +3 -0
  97. package/.next/standalone/.next/server/chunks/ssr/_06imw3p._.js +5 -0
  98. package/.next/standalone/.next/server/chunks/ssr/_08x1r5t._.js +1 -1
  99. package/.next/standalone/.next/server/chunks/ssr/{_1w_5l7t._.js → _0h_douw._.js} +1 -1
  100. package/.next/standalone/.next/server/chunks/ssr/{_1mel6y1._.js → _1-i_gzc._.js} +2 -2
  101. package/.next/standalone/.next/server/chunks/ssr/{_1v-jvrv._.js → _166t73i._.js} +1 -1
  102. package/.next/standalone/.next/server/chunks/ssr/{_1q46vxx._.js → _1_qswah._.js} +2 -2
  103. package/.next/standalone/.next/server/chunks/ssr/{_1gb0ifp._.js → _1es2j7i._.js} +5 -5
  104. package/.next/standalone/.next/server/chunks/ssr/_1u8-lu2._.js +3 -0
  105. package/.next/standalone/.next/server/chunks/ssr/_1zopuov._.js +1 -1
  106. package/.next/standalone/.next/server/chunks/ssr/_next-internal_server_app_policies_page_actions_1sp2-yo.js +2 -2
  107. package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +1 -1
  108. package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
  109. package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +2 -2
  110. package/.next/standalone/.next/server/chunks/ssr/app_settings_settings-client_tsx_20lq-mq._.js +3 -0
  111. package/.next/standalone/.next/server/chunks/ssr/{node_modules_next_dist_0w6mzq5._.js → node_modules_next_dist_0drixxt._.js} +4 -4
  112. package/.next/standalone/.next/server/chunks/ssr/src_hooks_1cv9_c4._.js +10 -0
  113. package/.next/standalone/.next/server/chunks/ssr/src_hooks_builtin-policies_ts_09j2ndl._.js +1 -1
  114. package/.next/standalone/.next/server/chunks/ssr/src_hooks_fp-home_ts_0je3xkv._.js +1 -1
  115. package/.next/standalone/.next/server/chunks/ssr/src_hooks_pack-cli_ts_0t7me65._.js +1 -1
  116. package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
  117. package/.next/standalone/.next/server/pages/404.html +1 -1
  118. package/.next/standalone/.next/server/pages/500.html +1 -1
  119. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  120. package/.next/standalone/.next/server/server-reference-manifest.json +23 -56
  121. package/.next/standalone/.next/static/chunks/094xgi4owxaqf.js +1 -0
  122. package/.next/standalone/.next/static/chunks/{129ag2bw93bdh.js → 0__8a7m868fvf.js} +1 -1
  123. package/.next/standalone/.next/static/chunks/{3ugmd_7dyn0id.js → 0o6qlkgubtoex.js} +1 -1
  124. package/.next/standalone/.next/static/chunks/{0fqd7m_u81mi5.js → 13i7-9is-vhys.js} +1 -1
  125. package/.next/standalone/.next/static/chunks/1rz20_pz828f3.js +6 -0
  126. package/.next/standalone/.next/static/chunks/2k9f4tyv04809.css +1 -0
  127. package/.next/standalone/.next/static/chunks/{2_pltstd8-xgs.js → 2klitrtzpaoe0.js} +1 -1
  128. package/.next/standalone/.next/static/chunks/{3brze37td_wnc.js → 2mdh397ghgnvv.js} +1 -1
  129. package/.next/standalone/.next/static/chunks/2rshywgeqsyzk.css +2 -0
  130. package/.next/standalone/.next/static/chunks/3pzx4chkhko9k.js +1 -0
  131. package/.next/standalone/.next/static/chunks/3rh5o7e16irrm.js +69 -0
  132. package/.next/standalone/.next/static/chunks/{1qd741hzlmjbo.js → 43ufqrz8qo3h-.js} +1 -1
  133. package/.next/standalone/SECURITY.md +53 -0
  134. package/.next/standalone/app/actions/pack-actions.ts +0 -12
  135. package/.next/standalone/app/policies/hooks-client.tsx +0 -9
  136. package/.next/standalone/app/settings/page.tsx +1 -20
  137. package/.next/standalone/app/settings/settings-client.tsx +1 -27
  138. package/.next/standalone/app/settings/settings.css +0 -79
  139. package/.next/standalone/package.json +10 -10
  140. package/.next/standalone/sdk/typescript/CHANGELOG.md +15 -1
  141. package/.next/standalone/sdk/typescript/integration/fixtures/ai-4/package-lock.json +10 -30
  142. package/.next/standalone/sdk/typescript/integration/fixtures/ai-4/package.json +3 -0
  143. package/.next/standalone/sdk/typescript/integration/fixtures/ai-5/package-lock.json +4 -16
  144. package/.next/standalone/sdk/typescript/integration/fixtures/ai-5/package.json +3 -0
  145. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-0.3/package-lock.json +13 -132
  146. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-0.3/package.json +4 -0
  147. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-dup-core/package-lock.json +4 -142
  148. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-dup-core/package.json +4 -0
  149. package/.next/standalone/sdk/typescript/integration/fixtures/mastra-0/package-lock.json +1396 -1016
  150. package/.next/standalone/sdk/typescript/integration/fixtures/mastra-0/package.json +9 -0
  151. package/.next/standalone/server.js +1 -1
  152. package/README.md +2 -2
  153. package/bin/failproofai.mjs +2 -115
  154. package/dist/cli.mjs +6543 -13872
  155. package/dist/index.js +1 -19
  156. package/dist/worker.mjs +2022 -8055
  157. package/package.json +10 -10
  158. package/pi-extension/index.ts +0 -11
  159. package/scripts/build-policy-pack.mjs +2 -53
  160. package/src/audit/features.ts +2 -3
  161. package/src/hooks/builtin-policies.ts +8 -177
  162. package/src/hooks/cloud-enrollment-cli.ts +1 -1
  163. package/src/hooks/cloud-managed-policies.ts +0 -22
  164. package/src/hooks/custom-hooks-loader.ts +7 -45
  165. package/src/hooks/custom-hooks-registry.ts +1 -45
  166. package/src/hooks/first-run-gate.ts +0 -5
  167. package/src/hooks/fp-home.ts +0 -23
  168. package/src/hooks/handler.ts +6 -265
  169. package/src/hooks/hook-activity-store.ts +1 -105
  170. package/src/hooks/hook-telemetry.ts +0 -41
  171. package/src/hooks/loader-utils.ts +0 -6
  172. package/src/hooks/manager.ts +1 -1
  173. package/src/hooks/pack-cli.ts +19 -412
  174. package/src/hooks/pack-manifest.ts +7 -479
  175. package/src/hooks/pack-store.ts +11 -157
  176. package/src/hooks/policy-catalog.ts +0 -204
  177. package/src/hooks/policy-evaluator.ts +796 -940
  178. package/src/hooks/policy-registry.ts +0 -25
  179. package/src/hooks/policy-types.ts +0 -126
  180. package/src/hooks/types.ts +1 -1
  181. package/src/hooks/worker-server.ts +26 -119
  182. package/src/index.ts +0 -6
  183. package/.next/standalone/.next/server/chunks/src_hooks_01frwmb._.js +0 -5
  184. package/.next/standalone/.next/server/chunks/src_hooks_18qtd42._.js +0 -3
  185. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__01bmjsj._.js +0 -3
  186. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__04usis8._.js +0 -4
  187. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__056wjo4._.js +0 -4
  188. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__059yza8._.js +0 -3
  189. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0eip4_k._.js +0 -22
  190. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0n0xg95._.js +0 -4
  191. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0qcb0mg._.js +0 -3
  192. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0qxnccm._.js +0 -5
  193. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0rwtwpm._.js +0 -4
  194. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0s_yomn._.js +0 -4
  195. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0soxz2z._.js +0 -3
  196. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0yrsbd_._.js +0 -3
  197. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__11mayhe._.js +0 -4
  198. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__13d-wb6._.js +0 -3
  199. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1dinjii._.js +0 -3
  200. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1pprgri._.js +0 -4
  201. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1q4p5b8._.js +0 -4
  202. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1qiz0e4._.js +0 -3
  203. package/.next/standalone/.next/server/chunks/ssr/_042cgl1._.js +0 -3
  204. package/.next/standalone/.next/server/chunks/ssr/_0bqoto4._.js +0 -3
  205. package/.next/standalone/.next/server/chunks/ssr/_0uyu3jf._.js +0 -3
  206. package/.next/standalone/.next/server/chunks/ssr/_1feuvhb._.js +0 -5
  207. package/.next/standalone/.next/server/chunks/ssr/app_actions_get-scheduled-audit_ts_0ei9sni._.js +0 -3
  208. package/.next/standalone/.next/server/chunks/ssr/app_settings_02tf1h4._.js +0 -3
  209. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_18_d8l1._.js +0 -151
  210. package/.next/standalone/.next/server/chunks/ssr/src_hooks_095a_79._.js +0 -5
  211. package/.next/standalone/.next/server/chunks/ssr/src_hooks_15t8kqj._.js +0 -3
  212. package/.next/standalone/.next/server/chunks/ssr/src_hooks_18k8rl0._.js +0 -12
  213. package/.next/standalone/.next/server/chunks/ssr/src_hooks_1fm2w5z._.js +0 -3
  214. package/.next/standalone/.next/server/chunks/ssr/src_hooks_1j0zy3v._.js +0 -3
  215. package/.next/standalone/.next/static/chunks/043j99m8ykg__.css +0 -2
  216. package/.next/standalone/.next/static/chunks/2c8j9l6j_b1ci.js +0 -1
  217. package/.next/standalone/.next/static/chunks/2qv4hshejedtx.css +0 -1
  218. package/.next/standalone/.next/static/chunks/3-k569wzcli8q.js +0 -1
  219. package/.next/standalone/.next/static/chunks/3otmypm6j_xfo.js +0 -6
  220. package/.next/standalone/.next/static/chunks/3yxro_r2_o9ad.js +0 -69
  221. package/.next/standalone/PROBE-FOLLOWUP.md +0 -186
  222. package/.next/standalone/app/actions/get-jev-config.ts +0 -424
  223. package/.next/standalone/app/actions/update-jev-config.ts +0 -420
  224. package/.next/standalone/app/components/jev-notices.tsx +0 -96
  225. package/.next/standalone/app/settings/jev-panel.tsx +0 -473
  226. package/src/hooks/effective-reviewers.ts +0 -79
  227. package/src/hooks/jev-activity.ts +0 -385
  228. package/src/hooks/jev-cli.ts +0 -1249
  229. package/src/hooks/policy-authority.ts +0 -333
  230. package/src/hooks/policy-reviewability.ts +0 -229
  231. package/src/hooks/semantic/combine.ts +0 -541
  232. package/src/hooks/semantic/compile.ts +0 -176
  233. package/src/hooks/semantic/decide.ts +0 -392
  234. package/src/hooks/semantic/envelope.ts +0 -1296
  235. package/src/hooks/semantic/evaluator.ts +0 -547
  236. package/src/hooks/semantic/facts.ts +0 -292
  237. package/src/hooks/semantic/intent.ts +0 -1190
  238. package/src/hooks/semantic/jev-client.ts +0 -643
  239. package/src/hooks/semantic/jev-config.ts +0 -594
  240. package/src/hooks/semantic/jev-review.ts +0 -374
  241. package/src/hooks/semantic/jev-stats.ts +0 -289
  242. package/src/hooks/semantic/jev-throttle.ts +0 -421
  243. package/src/hooks/semantic/pack-policies.ts +0 -251
  244. package/src/hooks/semantic/policies.ts +0 -596
  245. package/src/hooks/semantic/precondition-names.ts +0 -60
  246. package/src/hooks/semantic/preconditions.ts +0 -58
  247. package/src/hooks/semantic/redact.ts +0 -2910
  248. package/src/hooks/semantic/types.ts +0 -145
  249. package/src/hooks/semver-precedence.ts +0 -128
  250. /package/.next/standalone/.next/static/{gbEOjBgZAxF2UIUwZVHNu → PgeWCHmyVbjRznv2VO7KF}/_buildManifest.js +0 -0
  251. /package/.next/standalone/.next/static/{gbEOjBgZAxF2UIUwZVHNu → PgeWCHmyVbjRznv2VO7KF}/_clientMiddlewareManifest.js +0 -0
  252. /package/.next/standalone/.next/static/{gbEOjBgZAxF2UIUwZVHNu → PgeWCHmyVbjRznv2VO7KF}/_ssgManifest.js +0 -0
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "failproofai",
3
- "version": "1.0.7-beta.2",
4
- "description": "Observability and enforcement for AI agent harnesses. 40 built-in policies hooked into 12 of them — Claude Code, Codex, Cursor, Hermes, OpenClaw and more — blocking the tool call before it runs. Local dashboard included, no account needed.",
3
+ "version": "1.0.7",
4
+ "description": "Observability and enforcement for AI agent harnesses. 39 built-in policies hooked into 12 of them — Claude Code, Codex, Cursor, Hermes, OpenClaw and more — blocking the tool call before it runs. Local dashboard included, no account needed.",
5
5
  "bin": {
6
6
  "failproofai": "./dist/cli.mjs",
7
7
  "failproofaid": "./bin/failproofaid-shim.mjs"
@@ -122,15 +122,15 @@
122
122
  "browserslist": "4.28.8"
123
123
  },
124
124
  "optionalDependencies": {
125
- "@failproofai/failproofaid-linux-x64": "1.0.7-beta.2",
126
- "@failproofai/failproofaid-linux-arm64": "1.0.7-beta.2",
127
- "@failproofai/failproofaid-darwin-x64": "1.0.7-beta.2",
128
- "@failproofai/failproofaid-darwin-arm64": "1.0.7-beta.2"
125
+ "@failproofai/failproofaid-linux-x64": "1.0.7",
126
+ "@failproofai/failproofaid-linux-arm64": "1.0.7",
127
+ "@failproofai/failproofaid-darwin-x64": "1.0.7",
128
+ "@failproofai/failproofaid-darwin-arm64": "1.0.7"
129
129
  },
130
130
  "failproofaidBinaries": {
131
- "linux-x64": "5362ab6a4cfb23d1eee598aac67aedd9e43351e62724ee1c6b40c4fc8021c08f",
132
- "linux-arm64": "f14a2548b41e14ad32b7fdd03a27ffe7160da1046e422e1f651099371b0d27e5",
133
- "darwin-x64": "14189cade04f17cf5278bd8061a5ec0c2a2381aa21944ae0d05e8c35b98c2816",
134
- "darwin-arm64": "4ba9f5c321894d953407efa3404f0deec07dccfd7db7bc2511bb35226816b583"
131
+ "linux-x64": "65acfcabaa4dda6d37d2958d4100c366a85f17c68d2250de6126e2717ca773e6",
132
+ "linux-arm64": "cece883f87d53034003be8f0f293aa89bd0e69306d6032e17b3eb91f230b3ce2",
133
+ "darwin-x64": "565aa3d560a05dd76e2eb843ddbad593d2d8df94c963bdeb1c7e2a8a3816d0c5",
134
+ "darwin-arm64": "2b41601b53e77a31439e92d8be9be6b9872e3d4ad7e8664ff89cd2be4ed6c44d"
135
135
  }
136
136
  }
@@ -404,17 +404,6 @@ export default function failproofaiBridge(pi: PiExtensionApi) {
404
404
  session_id: resolveSessionId(e.sessionId, resolveCwd(e.cwd)),
405
405
  cwd: resolveCwd(e.cwd),
406
406
  hook_event_name: "UserPromptSubmit",
407
- // "interactive" | "rpc" | "extension": which channel the input came
408
- // through, and the only mark Pi gives about who wrote the prompt. It
409
- // names the channel, not the author — `pi -p "<text>"` reports
410
- // `interactive` exactly as a person typing does — so the Jev evaluator
411
- // uses it only in the direction it is reliable in (`piMachineTurn`,
412
- // src/hooks/semantic/intent.ts): `extension`, another extension's
413
- // `sendUserMessage()` whose text can be model-written or repo-derived,
414
- // is refused, while `interactive`, `rpc` and an absent value are all
415
- // recorded as the human's request. Policies read it too, and a later Pi
416
- // build may say more here.
417
- input_source: e.source,
418
407
  });
419
408
  if (decision.block) {
420
409
  console.error(`[failproofai] prompt blocked: ${decision.reason ?? "blocked by policy"}`);
@@ -31,24 +31,6 @@
31
31
  * that stops an agent disabling failproofai, it ships compiled in, and
32
32
  * `pack-manifest.ts` REFUSES any pack that declares `alwaysOn`. A pack containing
33
33
  * it would be rejected by our own loader — correctly.
34
- *
35
- * **Every policy states its authority** — whether Jev may clear its verdict —
36
- * as the registry would resolve it (`manifestAuthority`), not as a copy of
37
- * whatever the catalog happened to spell. A machine running this pack reads
38
- * authority from the MANIFEST, so a field left off here is a policy that is
39
- * silently hard everywhere it is installed. The entry passes the same fields to
40
- * `customPolicies.add`, so a manifest rebuilt from the entry (`failproofai
41
- * publish`) says the same thing.
42
- *
43
- * **It emits no `semantic` array, deliberately.** A pack that declares one
44
- * REPLACES this build's compiled-in semantic set wholesale
45
- * (`semantic/pack-policies.ts`), and this pack is the dress rehearsal for the
46
- * regex floor leaving the package — not for Jev's question set leaving it. So
47
- * the 39 builtins travel and the 16 semantic policies stay compiled in, which
48
- * also keeps `manifestAuthority` below judging `reviewedBy` against the right
49
- * list: the builtin reviewer names, which is what a machine installing this pack
50
- * will still be running. The separate `FailproofAI/jev-policies` pack is where
51
- * the semantic half ships, and it declares its own `minCliVersion`.
52
34
  */
53
35
  import { execFileSync } from "node:child_process";
54
36
  import { createHash } from "node:crypto";
@@ -58,7 +40,6 @@ import { fileURLToPath } from "node:url";
58
40
  // The one place the pack's id is decided. Imported rather than restated — see
59
41
  // PACK_ID below for what restating it cost.
60
42
  import { CORE_SOURCE } from "../src/hooks/pack-store.ts";
61
- import { manifestAuthority } from "../src/hooks/policy-authority.ts";
62
43
 
63
44
  const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "..");
64
45
  // `--out <dir>` lets the conformance test generate into a temp directory rather
@@ -114,23 +95,6 @@ for (const policy of BUILTIN_POLICIES) {
114
95
  defaultEnabled: policy.defaultEnabled === true,
115
96
  match: policy.match,
116
97
  fn: policy.fn,
117
- // The parameter schema. It has to be registered here as well as written
118
- // into the manifest this script builds, because there are TWO manifest
119
- // producers for this pack and they have to agree: this script builds one
120
- // from POLICY_CATALOG, and the publish command rebuilds one by importing
121
- // the entry and reading back what it registered. A field the entry does
122
- // not register is a field the second producer cannot know about.
123
- //
124
- // params is the one that fails silently STRICTER. Registration reads a
125
- // pack policy's schema from the manifest, so an absent schema means the
126
- // policy sees empty params: block-sudo's allowPatterns, and block-rm-rf's
127
- // and block-read-outside-cwd's allowPaths, stop applying -- taking the
128
- // user's own configured values with them. No backticks in this comment:
129
- // see the note above entrySource.
130
- ...(policy.params !== undefined ? { params: policy.params } : {}),
131
- // Whether Jev may clear it; see the note on authority at the top.
132
- ...(policy.authority !== undefined ? { authority: policy.authority } : {}),
133
- ...(policy.reviewedBy !== undefined ? { reviewedBy: policy.reviewedBy } : {}),
134
98
  });
135
99
  }
136
100
  `;
@@ -156,20 +120,7 @@ try {
156
120
  // validates these with the loader's own rules, so a shape the loader would
157
121
  // refuse fails this build rather than shipping.
158
122
  const { POLICY_CATALOG } = await import(join(ROOT, "src/hooks/policy-catalog.ts"));
159
- const policies = POLICY_CATALOG.filter((p) => !p.alwaysOn).map((p) => {
160
- // Throws on a declaration the registry would quietly downgrade: in the
161
- // catalog that is a typo or a renamed semantic policy, and publishing it
162
- // would turn a reviewed decision into an unannounced hard one. The fields
163
- // come from the same call, so the check cannot be skipped without the
164
- // manifest losing its authority too.
165
- const resolved = manifestAuthority(p);
166
- // Spread first so every field keeps its catalog position; only the two
167
- // authority fields are replaced by their resolved values.
168
- const entry = { ...p, authority: resolved.authority };
169
- if (resolved.reviewedBy) entry.reviewedBy = resolved.reviewedBy;
170
- else delete entry.reviewedBy;
171
- return entry;
172
- });
123
+ const policies = POLICY_CATALOG.filter((p) => !p.alwaysOn).map((p) => ({ ...p }));
173
124
 
174
125
  const manifest = JSON.stringify(
175
126
  { id: PACK_ID, version, effect: "enforce", policies },
@@ -187,10 +138,8 @@ writeFileSync(
187
138
  );
188
139
 
189
140
  const omitted = POLICY_CATALOG.filter((p) => p.alwaysOn).map((p) => p.name);
190
- const reviewable = policies.filter((p) => p.authority === "reviewable").length;
191
141
  console.log(
192
- `[policy-pack] ${PACK_ID}@${version} — ${policies.length} policies ` +
193
- `(${reviewable} reviewable by Jev, ${policies.length - reviewable} hard), ` +
142
+ `[policy-pack] ${PACK_ID}@${version} — ${policies.length} policies, ` +
194
143
  `${(entryBytes.length / 1024).toFixed(1)} KB entry` +
195
144
  (omitted.length ? `; omitted alwaysOn: ${omitted.join(", ")}` : ""),
196
145
  );
@@ -69,13 +69,13 @@ export const ARCHITECT_CAUTION_SIGNALS = new Set(["reread-after-edit", "redundan
69
69
 
70
70
  /**
71
71
  * Mapping from policy/detector short-name → which archetype its hits feed,
72
- * and how heavily (intensity within the cluster). Every one of the 40 builtin
72
+ * and how heavily (intensity within the cluster). Every one of the 39 builtin
73
73
  * policies and 8 audit-only detectors maps exactly once — no overlaps, full
74
74
  * coverage. Weights express *severity within* a persona; cross-persona
75
75
  * fairness is handled later by lift normalisation, not by these numbers.
76
76
  */
77
77
  export const SIGNAL_MAP: Record<string, { archetype: ArchetypeKey; weight: number }> = {
78
- // ── cowboy ── destructive / forceful / bypasses guardrails (21) ───────────
78
+ // ── cowboy ── destructive / forceful / bypasses guardrails (20) ───────────
79
79
  "block-rm-rf": { archetype: "cowboy", weight: 2.0 },
80
80
  "block-failproofai-commands":{ archetype: "cowboy", weight: 2.0 },
81
81
  "block-sudo": { archetype: "cowboy", weight: 1.5 },
@@ -88,7 +88,6 @@ export const SIGNAL_MAP: Record<string, { archetype: ArchetypeKey; weight: numbe
88
88
  "git-commit-no-verify": { archetype: "cowboy", weight: 1.5 },
89
89
  "warn-git-amend": { archetype: "cowboy", weight: 0.8 },
90
90
  "warn-git-stash-drop": { archetype: "cowboy", weight: 1.0 },
91
- "warn-git-clean": { archetype: "cowboy", weight: 1.0 },
92
91
  "warn-all-files-staged": { archetype: "cowboy", weight: 0.6 },
93
92
  "block-kubectl": { archetype: "cowboy", weight: 1.5 },
94
93
  "block-terraform": { archetype: "cowboy", weight: 1.5 },
@@ -623,15 +623,8 @@ const GIT_DESTRUCTIVE_SUBCOMMANDS = new Set([
623
623
  */
624
624
  const GIT_FLAGS_WITH_OPERANDS = new Set(["-C", "-c", "--git-dir", "--work-tree", "--namespace", "--exec-path"]);
625
625
 
626
- /**
627
- * Where the `git` subcommand sits in `args`, with git's own global options
628
- * walked off first, or `-1` when there is no subcommand at all.
629
- *
630
- * The index rather than the value, because a caller that wants to read the
631
- * SUBCOMMAND's flags (`warnGitClean`) needs to know where they start, and
632
- * `args.indexOf("clean")` would land on a `-C clean` operand instead.
633
- */
634
- function gitSubcommandIndex(args: string[]): number {
626
+ /** The `git` subcommand, with git's own global options walked off first. */
627
+ function gitSubcommand(args: string[]): string | undefined {
635
628
  for (let i = 0; i < args.length; i++) {
636
629
  const arg = args[i];
637
630
  if (GIT_FLAGS_WITH_OPERANDS.has(arg)) {
@@ -639,15 +632,9 @@ function gitSubcommandIndex(args: string[]): number {
639
632
  continue;
640
633
  }
641
634
  if (arg.startsWith("-")) continue;
642
- return i;
635
+ return arg;
643
636
  }
644
- return -1;
645
- }
646
-
647
- /** The `git` subcommand, with git's own global options walked off first. */
648
- function gitSubcommand(args: string[]): string | undefined {
649
- const i = gitSubcommandIndex(args);
650
- return i < 0 ? undefined : args[i];
637
+ return undefined;
651
638
  }
652
639
 
653
640
  /**
@@ -1392,48 +1379,6 @@ const GIT_AMEND_RE = /\bgit\s+commit\b.*--amend\b/;
1392
1379
  // warnGitStashDrop
1393
1380
  const GIT_STASH_DROP_RE = /\bgit\s+stash\s+(?:drop|clear)\b/;
1394
1381
 
1395
- // warnGitClean
1396
- /**
1397
- * `git`, however the command line spells it. Same shape as {@link RM_CMD_RE}:
1398
- * an absolute path to the binary does not change what it does.
1399
- */
1400
- const GIT_CMD_RE = /^(?:\/\S*\/)?git$/;
1401
-
1402
- /** A short-flag cluster: `-f`, `-fdx`, `-xdf`. */
1403
- const SHORT_FLAG_CLUSTER_RE = /^-[A-Za-z]+$/;
1404
-
1405
- /**
1406
- * `clean.requireForce=false`, the config that makes `git clean` delete with no
1407
- * `-f` at all — and settable per invocation as `git -c
1408
- * clean.requireForce=false clean -xd`. Reading the subcommand's flags alone
1409
- * would call that "no force, no warning" on the one spelling that needs none.
1410
- */
1411
- const GIT_CLEAN_FORCE_WAIVED_RE = /^clean\.requireforce=(?:false|0|no|off)$/i;
1412
-
1413
- /**
1414
- * The default `destructiveFlags`, and why the condition is these three letters
1415
- * rather than "any `git clean`".
1416
- *
1417
- * `git clean` deletes nothing without `-f` / `--force` (or the config above),
1418
- * and `-n` / `--dry-run` only prints — so force is the precondition and
1419
- * dry-run is the exemption. What force ALONE removes is untracked files in the
1420
- * current directory: the narrowest spelling, and the one people mean when they
1421
- * tidy up. These are the letters that widen the blast radius past that:
1422
- *
1423
- * - `-x` also removes IGNORED files — `.env`, local config, editor state,
1424
- * scratch work. That is the data that genuinely cannot be rebuilt by running
1425
- * a command, and it is what makes `git clean -fdx` the severe spelling.
1426
- * - `-X` removes ONLY ignored files: the same loss, tracked tree untouched.
1427
- * - `-d` also removes untracked DIRECTORIES — whole new subtrees git has never
1428
- * had a copy of.
1429
- *
1430
- * A bare `git clean -f` is deliberately absent. It has the smallest radius and
1431
- * by far the most traffic, and a guard that fires on the ordinary spelling is
1432
- * one people switch off — which would cost them the `-fdx` warning too. Add
1433
- * `"f"` to `destructiveFlags` to opt into it.
1434
- */
1435
- const GIT_CLEAN_DESTRUCTIVE_FLAGS = ["d", "x", "X"];
1436
-
1437
1382
  // warnAllFilesStaged
1438
1383
  const GIT_ADD_ALL_RE = /\bgit\s+add\s+(?:-A\b|--all\b|\.(?:\s|$|;|&&|\|\|))/;
1439
1384
 
@@ -2270,29 +2215,17 @@ const READ_LIKE_CMDS =
2270
2215
  * separator characters that appear in compound argv tokens (':' for Docker
2271
2216
  * volume mounts and PATH-like lists, '=' for env var assignments) so that a
2272
2217
  * suffix like '/dashboard.mdx' in 'docs/STAR/dashboard.mdx' or '/docs' in
2273
- * '-v HOST_DIR:/docs' is not misread as a standalone absolute path. '/' is in
2274
- * that list too, so a match cannot START on the second slash of a protocol
2275
- * separator: 'http://localhost:3000/x' used to yield '/localhost:3000/x'.
2276
- * A match that starts on the FIRST slash is untouched, so '//etc/passwd' —
2277
- * a real, working spelling of /etc/passwd — is still extracted and still
2278
- * resolves to /etc/passwd.
2279
- *
2280
- * Runs of slashes with nothing else ('//', '///') are dropped: those are a
2281
- * line-comment marker, not a directory. They used to resolve to the filesystem
2282
- * root, which denied any read-like command carrying a '// …' comment — a
2283
- * heredoc writing a TypeScript file into the project, say. A lone '/' is the
2284
- * root and is kept.
2218
+ * '-v HOST_DIR:/docs' is not misread as a standalone absolute path.
2285
2219
  */
2286
2220
  function extractAbsolutePaths(command: string): string[] {
2287
2221
  const paths: string[] = [];
2288
- const pathRe = /(?<![a-zA-Z0-9_.\-~\\*?:=/])(?:~\/[^\s;|&"'()\[\]{}]*|~(?=\s|$|[;|&"'()\[\]{}])|\/[^\s;|&"'()\[\]{}]*)/g;
2222
+ const pathRe = /(?<![a-zA-Z0-9_.\-~\\*?:=])(?:~\/[^\s;|&"'()\[\]{}]*|~(?=\s|$|[;|&"'()\[\]{}])|\/[^\s;|&"'()\[\]{}]*)/g;
2289
2223
 
2290
2224
  function addPaths(s: string): void {
2291
2225
  pathRe.lastIndex = 0;
2292
2226
  let m: RegExpExecArray | null;
2293
2227
  while ((m = pathRe.exec(s)) !== null) {
2294
2228
  let p = m[0];
2295
- if (/^\/{2,}$/.test(p)) continue; // a `//` comment marker, not the root
2296
2229
  if (p === "~") p = homedir();
2297
2230
  else if (p.startsWith("~/")) p = join(homedir(), p.slice(2));
2298
2231
  paths.push(p);
@@ -2583,101 +2516,6 @@ function warnGitStashDrop(ctx: PolicyContext): PolicyResult {
2583
2516
  return allow();
2584
2517
  }
2585
2518
 
2586
- /** What one `git clean` argument list asks for. */
2587
- interface GitCleanFlags {
2588
- force: boolean;
2589
- dryRun: boolean;
2590
- /** Short-flag letters, with `--force` counted as `f` so widening works either way. */
2591
- letters: Set<string>;
2592
- }
2593
-
2594
- /**
2595
- * Read `git clean`'s own options: clusters (`-fdx`) and the two long forms
2596
- * that matter (`--force`, `--dry-run`).
2597
- *
2598
- * Everything after `--` is a pathspec, not a flag — `git clean -n -- -fdx`
2599
- * asks about a file literally called `-fdx` and deletes nothing.
2600
- */
2601
- function readGitCleanFlags(args: string[]): GitCleanFlags {
2602
- const letters = new Set<string>();
2603
- let force = false;
2604
- let dryRun = false;
2605
- let sawEndOfOptions = false;
2606
- for (const token of args) {
2607
- if (token === "--") {
2608
- sawEndOfOptions = true;
2609
- continue;
2610
- }
2611
- if (sawEndOfOptions) continue;
2612
- if (token === "--force") {
2613
- force = true;
2614
- continue;
2615
- }
2616
- if (token === "--dry-run") {
2617
- dryRun = true;
2618
- continue;
2619
- }
2620
- if (token.startsWith("--")) continue;
2621
- if (!SHORT_FLAG_CLUSTER_RE.test(token)) continue;
2622
- for (const letter of token.slice(1)) {
2623
- if (letter === "f") force = true;
2624
- if (letter === "n") dryRun = true;
2625
- letters.add(letter);
2626
- }
2627
- }
2628
- if (force) letters.add("f");
2629
- return { force, dryRun, letters };
2630
- }
2631
-
2632
- /** True when git's own `-c key=value` options waive `clean.requireForce`. */
2633
- function gitCleanForceWaived(globalOptions: string[]): boolean {
2634
- for (let i = 0; i < globalOptions.length; i++) {
2635
- const token = globalOptions[i];
2636
- const value =
2637
- token === "-c" ? globalOptions[i + 1] : token.startsWith("-c") ? token.slice(2) : undefined;
2638
- if (value !== undefined && GIT_CLEAN_FORCE_WAIVED_RE.test(value)) return true;
2639
- }
2640
- return false;
2641
- }
2642
-
2643
- /**
2644
- * The gap this closes: `git clean -fdx` was caught by NEITHER tier — no regex
2645
- * builtin matched the string at all, and the semantic check that covers
2646
- * unrecoverable deletion cannot fire on it. See the note on the catalog entry
2647
- * for the measurement and for why this policy is `hard`.
2648
- */
2649
- function warnGitClean(ctx: PolicyContext): PolicyResult {
2650
- if (ctx.toolName !== "Bash") return allow();
2651
- const destructiveFlags = ((ctx.params?.destructiveFlags ?? GIT_CLEAN_DESTRUCTIVE_FLAGS) as string[]);
2652
- if (destructiveFlags.length === 0) return allow();
2653
-
2654
- for (const segment of shellSegments(getCommand(ctx))) {
2655
- const tokens = parseArgvTokens(segment);
2656
- // `findIndex`, not `tokens[0]`, so an env prefix (`GIT_DIR=x git clean …`)
2657
- // and an absolute binary path both still resolve to the git invocation.
2658
- const gitIdx = tokens.findIndex((t) => GIT_CMD_RE.test(t));
2659
- if (gitIdx < 0) continue;
2660
- const args = tokens.slice(gitIdx + 1);
2661
- const subIdx = gitSubcommandIndex(args);
2662
- if (subIdx < 0 || args[subIdx] !== "clean") continue;
2663
-
2664
- const flags = readGitCleanFlags(args.slice(subIdx + 1));
2665
- // `-n` / `--dry-run` prints what would go and removes nothing, whatever
2666
- // else is on the line — the safe inspection form, never a warning.
2667
- if (flags.dryRun) continue;
2668
- if (!flags.force && !gitCleanForceWaived(args.slice(0, subIdx))) continue;
2669
- if (!destructiveFlags.some((f) => flags.letters.has(f))) continue;
2670
-
2671
- return instruct(
2672
- "STOP: This command deletes untracked files from the working tree (git clean). Git has no copy of " +
2673
- "untracked or ignored files, so nothing it removes can be recovered: -d takes whole untracked " +
2674
- "directories, and -x / -X also take .gitignore'd files such as .env, local config and scratch work. " +
2675
- "Re-run it with --dry-run and confirm the exact paths with the user before executing.",
2676
- );
2677
- }
2678
- return allow();
2679
- }
2680
-
2681
2519
  function warnAllFilesStaged(ctx: PolicyContext): PolicyResult {
2682
2520
  if (ctx.toolName !== "Bash") return allow();
2683
2521
  const cmd = getCommand(ctx);
@@ -3240,7 +3078,7 @@ function requireCiGreenBeforeStop(ctx: PolicyContext): PolicyResult {
3240
3078
  * Each value is the identical hoisted function object, never a wrapper. Two
3241
3079
  * things depend on that and neither fails loudly: `audit/cache.ts` hashes
3242
3080
  * `fn.toString()` into the audit cache's `engineVersion`, so wrapping every
3243
- * entry would collapse 40 distinct hashes into one and freeze the key — stale
3081
+ * entry would collapse 39 distinct hashes into one and freeze the key — stale
3244
3082
  * audit results would then be served for the full 30-day TTL with no symptom;
3245
3083
  * and `gitBranchCache` is module-scoped, so a per-call factory would silently
3246
3084
  * reset it on every hook event.
@@ -3271,7 +3109,6 @@ const POLICY_IMPLEMENTATIONS: Record<string, PolicyFunction> = {
3271
3109
  "block-work-on-main": blockWorkOnMain,
3272
3110
  "warn-git-amend": warnGitAmend,
3273
3111
  "warn-git-stash-drop": warnGitStashDrop,
3274
- "warn-git-clean": warnGitClean,
3275
3112
  "warn-all-files-staged": warnAllFilesStaged,
3276
3113
  "warn-destructive-sql": warnDestructiveSql,
3277
3114
  "warn-schema-alteration": warnSchemaAlteration,
@@ -3341,13 +3178,7 @@ export function registerBuiltinPolicies(enabledNames: string[]): void {
3341
3178
  // A guard against the agent disabling failproofai that any of those can
3342
3179
  // switch off is not a guard.
3343
3180
  if (policy.alwaysOn || enabledSet.has(normalizePolicyName(policy.name))) {
3344
- // `alwaysOn` travels with the declaration so the self-protection guard
3345
- // resolves to hard even if its catalog entry ever said otherwise.
3346
- registerPolicy(policy.name, policy.description, policy.fn, policy.match, 0, policy.params, {
3347
- authority: policy.authority,
3348
- reviewedBy: policy.reviewedBy,
3349
- alwaysOn: policy.alwaysOn,
3350
- });
3181
+ registerPolicy(policy.name, policy.description, policy.fn, policy.match, 0, policy.params);
3351
3182
  }
3352
3183
  }
3353
3184
  }
@@ -377,7 +377,7 @@ export function versionStatusLines(): string[] {
377
377
  const daemon = recorded?.daemon ?? "not installed";
378
378
  return [
379
379
  `CLI ${cliVersion} · daemon ${daemon}${skew ? " (STALE)" : ""} · layout ${recorded?.layout ?? "-"}`,
380
- ...(skew ? [" Run `failproofai update` to update the daemon."] : []),
380
+ ...(skew ? [" Run `failproofai config` to update the daemon."] : []),
381
381
  ];
382
382
  }
383
383
 
@@ -8,8 +8,6 @@ import { createHash } from "node:crypto";
8
8
  import { existsSync, readFileSync, realpathSync, rmSync } from "node:fs";
9
9
  import { isAbsolute, relative, resolve } from "node:path";
10
10
  import { cloudPoliciesDir } from "./fp-home";
11
- import { authorityFieldsOf } from "./policy-authority";
12
- import type { PolicyAuthority } from "./policy-types";
13
11
 
14
12
  /**
15
13
  * Active-manifest schema versions this reader accepts.
@@ -46,19 +44,6 @@ export interface CloudManagedPolicyArtifact {
46
44
  sha256: string;
47
45
  path: string;
48
46
  deployment: number;
49
- /**
50
- * Whether Jev may clear this policy's verdict once it is configured, as the
51
- * ASSIGNMENT declares it — code inside the artifact cannot grant itself this.
52
- * Absent means `hard`, which is what keeps Jev from weakening central
53
- * enforcement by default: a cloud policy is only ever reviewable because
54
- * whoever deployed it said so. Applies to every hook the artifact registers.
55
- *
56
- * Read and validated here; the daemon has to carry it into `active.json`
57
- * (`ActivePolicy` in `cloud_policies.rs`) before a deployment can set it.
58
- */
59
- authority?: PolicyAuthority;
60
- /** The semantic policies that must all be asked and none answer `deny`; see `authority`. */
61
- reviewedBy?: string[];
62
47
  }
63
48
 
64
49
  interface ActiveManifest {
@@ -70,8 +55,6 @@ interface ActiveManifest {
70
55
  effect?: string;
71
56
  sha256: string;
72
57
  path: string;
73
- authority?: unknown;
74
- reviewedBy?: unknown;
75
58
  }>;
76
59
  }
77
60
 
@@ -223,11 +206,6 @@ export function readActiveCloudManagedPolicies(): CloudManagedPolicyArtifact[] {
223
206
  sha256: policy.sha256,
224
207
  path,
225
208
  deployment: manifest.deployment,
226
- // Unlike `effect`, a malformed authority is dropped rather than refused:
227
- // dropping it makes this policy `hard`, the default that keeps enforcing,
228
- // while refusing would take the whole deployment down over an optional
229
- // field. Absent stays absent.
230
- ...authorityFieldsOf(policy as unknown as Record<string, unknown>),
231
209
  };
232
210
  });
233
211
  }
@@ -33,7 +33,6 @@ import type { CustomHook, PolicyCatalogEntry } from "./policy-types";
33
33
  import type { CloudManagedPolicyArtifact } from "./cloud-managed-policies";
34
34
  import type { ResolvedPack } from "./pack-manifest";
35
35
  import { customPoliciesDir, shimsDir } from "./fp-home";
36
- import { warnAuthority, withMergedAuthority } from "./policy-authority";
37
36
 
38
37
  const LOADING_KEY = "__FAILPROOFAI_LOADING_HOOKS__";
39
38
 
@@ -449,19 +448,9 @@ export async function loadAllCustomHooks(
449
448
  `cloud-managed policies ${existing.id} and ${policy.id} have identical source, so they share ` +
450
449
  `one artifact and load as one policy; enforcing it if either asks to enforce`,
451
450
  );
452
- // Authority resolves toward HARD, for the same reason: reviewable only if
453
- // every assignment behind these bytes says so. Keeping one record's
454
- // declaration let the order of active.json decide, so a team's reviewable
455
- // assignment could clear what an org-wide hard one enforces.
456
- const winner = existing.effect !== "enforce" && policy.effect === "enforce" ? policy : existing;
457
- const { merged, overruled } = withMergedAuthority(winner, [existing, policy]);
458
- if (overruled) {
459
- warnAuthority(
460
- `cloud-managed policies ${existing.id} and ${policy.id} share one artifact and do not all declare it ` +
461
- `reviewable, so it stays hard`,
462
- );
451
+ if (existing.effect !== "enforce" && policy.effect === "enforce") {
452
+ cloudManagedByPath.set(key, policy);
463
453
  }
464
- cloudManagedByPath.set(key, merged);
465
454
  }
466
455
 
467
456
  // Installed packs, keyed by artifact path — the same content-addressing, and
@@ -493,34 +482,14 @@ export async function loadAllCustomHooks(
493
482
  *
494
483
  * Winner precedence on a name both declare, because the merged record carries
495
484
  * the winner's id and version and there is no merging two different defaults.
496
- *
497
- * Except AUTHORITY, which resolves toward hard like the effect resolves toward
498
- * enforce (`withMergedAuthority`): a name is reviewable only if every pack
499
- * behind the artifact declares it reviewable. A pack whose manifest does not
500
- * list the name at all counts as hard — its copy of the artifact registers
501
- * the policy all the same, undeclared, and an undeclared pack policy is hard.
502
- * Winner precedence here would let one pack's manifest make another pack's
503
- * policy reviewable, which is the one thing a manifest may never do.
504
485
  */
505
486
  const unionCatalog = (
506
487
  winner: PolicyCatalogEntry[],
507
488
  other: PolicyCatalogEntry[],
508
- ): { policies: PolicyCatalogEntry[]; overruled: string[] } => {
509
- /** Names a pack asked to be reviewable and did not get, for the warning. */
510
- const overruled: string[] = [];
511
- const harden = (entry: PolicyCatalogEntry, peer: PolicyCatalogEntry | undefined) => {
512
- const r = withMergedAuthority(entry, [entry, peer ?? {}]);
513
- if (r.overruled) overruled.push(entry.name);
514
- return r.merged;
515
- };
516
- return {
517
- policies: [
518
- ...winner.map((w) => harden(w, other.find((p) => p.name === w.name))),
519
- ...other.filter((p) => !winner.some((w) => w.name === p.name)).map((p) => harden(p, undefined)),
520
- ],
521
- overruled,
522
- };
523
- };
489
+ ): PolicyCatalogEntry[] => [
490
+ ...winner,
491
+ ...other.filter((p) => !winner.some((w) => w.name === p.name)),
492
+ ];
524
493
 
525
494
  const packByPath = new Map<string, ResolvedPack>();
526
495
  /**
@@ -566,19 +535,12 @@ export async function loadAllCustomHooks(
566
535
  // being intersected away.
567
536
  const winner = existing.effect !== "enforce" && pack.effect === "enforce" ? pack : existing;
568
537
  const other = winner === existing ? pack : existing;
569
- const catalog = unionCatalog(winner.policies, other.policies);
570
538
  packByPath.set(key, {
571
539
  ...winner,
572
- policies: catalog.policies,
540
+ policies: unionCatalog(winner.policies, other.policies),
573
541
  enabled: unionSelection(winner.enabled, other.enabled),
574
542
  clis: unionSelection(winner.clis, other.clis),
575
543
  });
576
- if (catalog.overruled.length > 0) {
577
- warnAuthority(
578
- `packs ${existing.id} and ${pack.id} share one artifact and do not all declare ` +
579
- `${catalog.overruled.join(", ")} reviewable, so ${catalog.overruled.length === 1 ? "it stays" : "they stay"} hard`,
580
- );
581
- }
582
544
  }
583
545
 
584
546
  // 1. Explicit custom policy paths. Accept a string for callers/configs using
@@ -4,14 +4,9 @@
4
4
  * from 'failproofai') and the hook handler (which reads from this file) share the
5
5
  * same in-process state when running within the same Node.js process.
6
6
  */
7
- import type { CustomHook, SemanticPolicyDeclaration } from "./policy-types";
7
+ import type { CustomHook } from "./policy-types";
8
8
 
9
9
  const REGISTRY_KEY = "__failproofai_custom_hooks__";
10
- /**
11
- * Beside the hook registry, on the same key namespace and cleared by the same
12
- * call — the two are one registration pass and a build step reads both.
13
- */
14
- const SEMANTIC_KEY = "__failproofai_semantic_policies__";
15
10
 
16
11
  function getRegistry(): CustomHook[] {
17
12
  const g = globalThis as Record<string, unknown>;
@@ -19,56 +14,17 @@ function getRegistry(): CustomHook[] {
19
14
  return g[REGISTRY_KEY] as CustomHook[];
20
15
  }
21
16
 
22
- function getSemanticRegistry(): SemanticPolicyDeclaration[] {
23
- const g = globalThis as Record<string, unknown>;
24
- if (!Array.isArray(g[SEMANTIC_KEY])) g[SEMANTIC_KEY] = [];
25
- return g[SEMANTIC_KEY] as SemanticPolicyDeclaration[];
26
- }
27
-
28
17
  export const customPolicies = {
29
18
  add(hook: CustomHook): void {
30
19
  getRegistry().push(hook);
31
20
  },
32
21
  };
33
22
 
34
- /**
35
- * Register a semantic (Jev) policy — a question set for the classifier, read by
36
- * `failproofai publish` and emitted as the pack manifest's `semantic` array.
37
- *
38
- * A SEPARATE namespace from `customPolicies`, deliberately, rather than a
39
- * `customPolicies.addSemantic`. A semantic policy has no `fn` and no `match`,
40
- * and nothing about it ever executes on a user's machine: what installs is the
41
- * declaration in the manifest, and the artifact's call here matters only at
42
- * build time. Putting it behind the object whose entries return
43
- * `allow()`/`deny()` invites exactly the shape confusion the manifest parser
44
- * would then have to catch — a function on a semantic entry, a probe list on a
45
- * regex one — and both mistakes would be silent until somebody read a manifest.
46
- *
47
- * Nothing is validated here. `parsePackSemanticPolicy` in `pack-manifest.ts`
48
- * owns every rule, and it is applied at BUILD time (where the author can still
49
- * fix it) and again at load time (where the bytes may have come from anywhere).
50
- * Validating a third time in the setter would be a third copy of the rules.
51
- */
52
- export const semanticPolicies = {
53
- add(policy: SemanticPolicyDeclaration): void {
54
- getSemanticRegistry().push(policy);
55
- },
56
- };
57
-
58
23
  export function getCustomHooks(): CustomHook[] {
59
24
  return getRegistry();
60
25
  }
61
26
 
62
- export function getSemanticRegistrations(): SemanticPolicyDeclaration[] {
63
- return getSemanticRegistry();
64
- }
65
-
66
27
  export function clearCustomHooks(): void {
67
28
  const g = globalThis as Record<string, unknown>;
68
29
  g[REGISTRY_KEY] = [];
69
- // Both maps, on one call. A loader that cleared only the hooks would carry
70
- // one entry file's semantic policies into the next file's build — and since
71
- // the semantic half is read after the load rather than during it, the extras
72
- // would be published under the wrong pack with nothing to notice.
73
- g[SEMANTIC_KEY] = [];
74
30
  }
@@ -35,11 +35,6 @@ export const FIRST_RUN_EXEMPT_SUBCOMMANDS: readonly string[] = [
35
35
  // Same reason: a backfill is an explicit instruction about an already-set-up
36
36
  // machine, and interrupting it to offer setup answers a question nobody asked.
37
37
  "backfill",
38
- // `jev setup` is configuration in its own right, and `jev status` / `test` /
39
- // `remove` inspect or undo it. It is also the command most likely to be
40
- // scripted with a key on stdin — a wizard in front of it would read that key
41
- // as the answer to its first question.
42
- "jev",
43
38
  ];
44
39
 
45
40
  export function shouldOfferFirstRun(args: readonly string[]): boolean {