failproofai 1.0.12-beta.2 → 1.0.13-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 (374) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/build-manifest.json +13 -13
  3. package/.next/standalone/.next/prerender-manifest.json +3 -3
  4. package/.next/standalone/.next/required-server-files.json +1 -1
  5. package/.next/standalone/.next/server/app/_global-error/page/build-manifest.json +2 -2
  6. package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
  7. package/.next/standalone/.next/server/app/_global-error/page.js +2 -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 +2 -2
  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 +2 -2
  14. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  15. package/.next/standalone/.next/server/app/_not-found/page/build-manifest.json +2 -2
  16. package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  17. package/.next/standalone/.next/server/app/_not-found/page.js +4 -3
  18. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  19. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  20. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  21. package/.next/standalone/.next/server/app/_not-found.rsc +3 -3
  22. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  23. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
  24. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  25. package/.next/standalone/.next/server/app/api/audit/invite/route.js +6 -5
  26. package/.next/standalone/.next/server/app/api/audit/invite/route.js.nft.json +1 -1
  27. package/.next/standalone/.next/server/app/api/audit/run/route.js +27 -26
  28. package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -1
  29. package/.next/standalone/.next/server/app/api/audit/status/route.js +4 -3
  30. package/.next/standalone/.next/server/app/api/audit/status/route.js.nft.json +1 -1
  31. package/.next/standalone/.next/server/app/api/auth/login-request/route.js +6 -5
  32. package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -1
  33. package/.next/standalone/.next/server/app/api/auth/login-verify/route.js +6 -5
  34. package/.next/standalone/.next/server/app/api/auth/login-verify/route.js.nft.json +1 -1
  35. package/.next/standalone/.next/server/app/api/auth/logout/route.js +6 -5
  36. package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
  37. package/.next/standalone/.next/server/app/api/auth/status/route.js +6 -5
  38. package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -1
  39. package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js +4 -3
  40. package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
  41. package/.next/standalone/.next/server/app/audit/page/build-manifest.json +2 -2
  42. package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +2 -2
  43. package/.next/standalone/.next/server/app/audit/page.js +7 -6
  44. package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -1
  45. package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
  46. package/.next/standalone/.next/server/app/index.html +1 -1
  47. package/.next/standalone/.next/server/app/index.rsc +3 -3
  48. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  49. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +3 -3
  50. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  51. package/.next/standalone/.next/server/app/page/build-manifest.json +2 -2
  52. package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
  53. package/.next/standalone/.next/server/app/page.js +6 -5
  54. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  55. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  56. package/.next/standalone/.next/server/app/policies/page/build-manifest.json +2 -2
  57. package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +14 -14
  58. package/.next/standalone/.next/server/app/policies/page.js +5 -4
  59. package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
  60. package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
  61. package/.next/standalone/.next/server/app/project/[name]/page/build-manifest.json +2 -2
  62. package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
  63. package/.next/standalone/.next/server/app/project/[name]/page.js +21 -20
  64. package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
  65. package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
  66. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/build-manifest.json +2 -2
  67. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
  68. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
  69. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js +10 -9
  70. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
  71. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
  72. package/.next/standalone/.next/server/app/projects/page/build-manifest.json +2 -2
  73. package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
  74. package/.next/standalone/.next/server/app/projects/page.js +7 -6
  75. package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
  76. package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  77. package/.next/standalone/.next/server/app/settings/page/build-manifest.json +2 -2
  78. package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +8 -8
  79. package/.next/standalone/.next/server/app/settings/page.js +6 -5
  80. package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
  81. package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  82. package/.next/standalone/.next/server/chunks/{[externals]__0vt9i6fqinjne._.js → [externals]__1h83uo-b1b6-2._.js} +1 -1
  83. package/.next/standalone/.next/server/chunks/[externals]__214wn4wh2x79y._.js +3 -0
  84. package/.next/standalone/.next/server/chunks/{[externals]__1rlxpymm37wel._.js → [root-of-the-server]__031qp1lkow_kc._.js} +2 -2
  85. package/.next/standalone/.next/server/chunks/[root-of-the-server]__038kwryp970nh._.js +3 -0
  86. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0_hsnj_a2mvl_._.js → [root-of-the-server]__03s1za0hn71yp._.js} +2 -2
  87. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0wg9dk8x8bnau._.js → [root-of-the-server]__07a0sa6fuw5_b._.js} +2 -2
  88. package/.next/standalone/.next/server/chunks/[root-of-the-server]__08atcie7jzswm._.js +3 -0
  89. package/.next/standalone/.next/server/chunks/[root-of-the-server]__08dchfudh2_4f._.js +1 -1
  90. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0car70pylmvor._.js +3 -0
  91. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0spt0kv8azrpl._.js +1 -1
  92. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__12kq3x-h7t7i1._.js → [root-of-the-server]__0yvyp5b7jmlc4._.js} +2 -2
  93. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__02vous7mpi2xm._.js → [root-of-the-server]__145vo_drnuvas._.js} +2 -2
  94. package/.next/standalone/.next/server/chunks/{[externals]__0h0p9dmv_e7r7._.js → [root-of-the-server]__1a2d0ewycsp6k._.js} +2 -2
  95. package/.next/standalone/.next/server/chunks/{[externals]__1_407huhlmj1m._.js → [root-of-the-server]__1am_1tz0o0aqz._.js} +2 -2
  96. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__03i5o4a840guz._.js → [root-of-the-server]__1gxfzuvpyw30j._.js} +1 -1
  97. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1j6kfp0vzu5rw._.js +3 -0
  98. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1l0ayum_hqqsw._.js +3 -0
  99. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1lh8c0mmhdrbj._.js +3 -0
  100. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1o9rznwc0w7og._.js +3 -0
  101. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0f_4g-vazrvxv._.js → [root-of-the-server]__1o_622x0fglpr._.js} +1 -1
  102. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1oclamblhzhrf._.js +68 -0
  103. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1v1-l-83czzsr._.js +63 -0
  104. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__1a5zkndjwlc13._.js → [root-of-the-server]__1wwi53kkqhnfi._.js} +1 -1
  105. package/.next/standalone/.next/server/chunks/{_1y590mjzpkbos._.js → _02sa8fcu9_9xo._.js} +2 -2
  106. package/.next/standalone/.next/server/chunks/_0tovk6q0miud6._.js +1 -1
  107. package/.next/standalone/.next/server/chunks/_0trp3ycqv17cl._.js +1 -1
  108. package/.next/standalone/.next/server/chunks/_1-2owkp-1_987._.js +1 -1
  109. package/.next/standalone/.next/server/chunks/_13ltj8a9z92o8._.js +1 -1
  110. package/.next/standalone/.next/server/chunks/_15k37au70vjvg._.js +1 -1
  111. package/.next/standalone/.next/server/chunks/_18rfu4__wjhwb._.js +1 -1
  112. package/.next/standalone/.next/server/chunks/_1ek68lnh2daur._.js +2 -2
  113. package/.next/standalone/.next/server/chunks/_1fz8m31sndkcu._.js +1 -1
  114. package/.next/standalone/.next/server/chunks/_1ogwigfb0163w._.js +1 -1
  115. package/.next/standalone/.next/server/chunks/_1vslkoe35wok6._.js +1 -1
  116. package/.next/standalone/.next/server/chunks/node_modules_@opentelemetry_api_build_esm_index_0oo58a7rymoxh.js +3 -0
  117. package/.next/standalone/.next/server/chunks/node_modules_@opentelemetry_api_build_esm_index_1jp9ij0_ddtgk.js +3 -0
  118. package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_01r25oigsgz07._.js +2 -2
  119. package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_09z9-p77cu37y._.js +2 -2
  120. package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4vkpxxu7._.js +1 -1
  121. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0ffu2-38y03ic._.js → [root-of-the-server]__021vebe-4il8s._.js} +1 -1
  122. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__075uro8t92s0_._.js +14 -0
  123. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__08ch3staq3ejw._.js +1 -1
  124. package/.next/standalone/.next/server/chunks/ssr/{[externals]__12qr51qgrrt6o._.js → [root-of-the-server]__097i34ct1o88x._.js} +2 -2
  125. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0alpzjn3450sr._.js +3 -0
  126. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0aup10z2o8zc1._.js +3 -0
  127. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0bigvy9xmv2ka._.js +1 -1
  128. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0bioghlkjf7s7._.js +3 -0
  129. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__01j58mdcdw0vn._.js → [root-of-the-server]__0ed1zh4scn7-k._.js} +1 -1
  130. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0naevg4bcoh54._.js → [root-of-the-server]__0evgy902m9h5e._.js} +2 -2
  131. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0h86bl2qf0k_o._.js +1 -1
  132. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__00l2u6j86cb8y._.js → [root-of-the-server]__0mhtkwwx1pxcq._.js} +2 -2
  133. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0nhm28v58ty9z._.js +3 -0
  134. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0pia5h3p8re4c._.js +1 -1
  135. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0vse4qi496ol-._.js +3 -0
  136. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__17r4zrwanhp6r._.js → [root-of-the-server]__0yb3u36xjy3b9._.js} +1 -1
  137. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0g8b0kyorya-t._.js → [root-of-the-server]__0ywj2u6ovfm_5._.js} +1 -1
  138. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1-ey9fgesfbc0._.js +1 -1
  139. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0zn1d4blhd3bu._.js → [root-of-the-server]__10v5cyxvj64j4._.js} +1 -1
  140. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__15usvs-ms-0hf._.js +1 -1
  141. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__16gb3_92zvk5x._.js +1 -1
  142. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__190xwrr5zrfi3._.js +3 -0
  143. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1avi2kypusyb_._.js +1 -1
  144. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1vx7o8ukefudh._.js → [root-of-the-server]__1guwlpkyurdn9._.js} +1 -1
  145. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1k96jctukf65_._.js +3 -0
  146. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1r7drlqli-ado._.js +1 -1
  147. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1sj-wn2jp6va5._.js +3 -0
  148. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1vofkb2oq7p7e._.js +1 -1
  149. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1s2-ck3k3rsoo._.js → [root-of-the-server]__20dt376-socef._.js} +1 -1
  150. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1lnfv02ucky7m._.js → [root-of-the-server]__2158020r_amn9._.js} +1 -1
  151. package/.next/standalone/.next/server/chunks/ssr/{_1fw0_nzkae5ao._.js → _0bc4f4quq6w47._.js} +2 -2
  152. package/.next/standalone/.next/server/chunks/ssr/_0bseae9u7g98r._.js +1 -1
  153. package/.next/standalone/.next/server/chunks/ssr/_0eoura3_9gjb-._.js +1 -1
  154. package/.next/standalone/.next/server/chunks/ssr/_0mouhaflye1ro._.js +1 -1
  155. package/.next/standalone/.next/server/chunks/ssr/_0ouu886szh6yj._.js +1 -1
  156. package/.next/standalone/.next/server/chunks/ssr/_0pedwblqdoh58._.js +1 -1
  157. package/.next/standalone/.next/server/chunks/ssr/_1_ozgifqv1ssi._.js +1 -1
  158. package/.next/standalone/.next/server/chunks/ssr/_1djqs9i27e4kg._.js +1 -1
  159. package/.next/standalone/.next/server/chunks/ssr/_20hn4gn87nsjc._.js +1 -1
  160. package/.next/standalone/.next/server/chunks/ssr/_next-internal_server_app_policies_page_actions_1sp2-yo5_vm5f.js +2 -2
  161. package/.next/standalone/.next/server/chunks/ssr/app_actions_get-scheduled-audit_ts_0ei9snixb5fd-._.js +1 -1
  162. package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47q0xq5w._.js +1 -1
  163. package/.next/standalone/.next/server/chunks/ssr/app_components_project-list_tsx_1ke6anr0vt64h._.js +1 -1
  164. package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x33jqb6._.js +1 -1
  165. package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpcz0uxur._.js +1 -1
  166. package/.next/standalone/.next/server/chunks/ssr/app_settings_02tf1h47jmhhd._.js +1 -1
  167. package/.next/standalone/.next/server/chunks/ssr/{node_modules_09s4n108bqreq._.js → node_modules_0ptcnmeaxvd_a._.js} +22 -2
  168. package/.next/standalone/.next/server/chunks/ssr/node_modules_@opentelemetry_api_build_esm_index_0ntwr8lzj6p2i.js +3 -0
  169. package/.next/standalone/.next/server/chunks/ssr/{node_modules_html-to-image_es_index_1fv03uigni8s5.js → node_modules_html-to-image_es_index_1jwgv0pf-gy96.js} +1 -1
  170. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_0bz67659f5z-3._.js +32 -0
  171. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_0janj0i6dqko7._.js +3 -3
  172. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_0ocrceo0c9psx._.js +32 -0
  173. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_1alv566ojmz5j._.js +32 -0
  174. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_1khq67j4vo9y4._.js +3 -0
  175. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_shared_lib_0ftnv26hg1lry._.js +3 -0
  176. package/.next/standalone/.next/server/chunks/ssr/node_modules_posthog-node_dist_entrypoints_index_node_mjs_0dagmbznysrc2._.js +1 -1
  177. package/.next/standalone/.next/server/chunks/ssr/node_modules_posthog-node_dist_entrypoints_index_node_mjs_11bnuznb72p7z._.js +2 -2
  178. package/.next/standalone/.next/server/chunks/ssr/package_json_[json]_cjs_013tntikdft59._.js +1 -1
  179. package/.next/standalone/.next/server/middleware-build-manifest.js +13 -13
  180. package/.next/standalone/.next/server/middleware.js +2 -2
  181. package/.next/standalone/.next/server/pages/404.html +1 -1
  182. package/.next/standalone/.next/server/pages/500.html +1 -1
  183. package/.next/standalone/.next/server/preview-props.json +3 -3
  184. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  185. package/.next/standalone/.next/server/server-reference-manifest.json +23 -23
  186. package/.next/standalone/.next/static/chunks/0cbom4-ijx_a_.js +1 -0
  187. package/.next/standalone/.next/static/chunks/0u5weo5jdn2s8.js +1 -0
  188. package/.next/standalone/.next/static/chunks/{1c_jf6g5wnslk.js → 18-icoqze51kl.js} +1 -1
  189. package/.next/standalone/.next/static/chunks/2d-u90dt4-8rd.js +6 -0
  190. package/.next/standalone/.next/static/chunks/2n-bzb7pxe7hu.js +1 -0
  191. package/.next/standalone/.next/static/chunks/{2o6d37j425uci.js → 2zc7lg-jq353g.js} +1 -1
  192. package/.next/standalone/.next/static/chunks/{0tbm3vjm62h-2.js → 33djjf12bhcsv.js} +1 -1
  193. package/.next/standalone/.next/static/chunks/{42xptz88mtq3x.js → 38u_i3j5funpi.js} +1 -1
  194. package/.next/standalone/.next/static/chunks/{20py8k1gd_i1m.js → 3symuj7t4js-c.js} +1 -1
  195. package/.next/standalone/.next/static/chunks/{0ay__-d2h1xb5.js → 3vzut6zpdrvtx.js} +1 -1
  196. package/.next/standalone/.next/static/chunks/{063al_q720fkj.js → 3xgxl1s_in776.js} +2 -2
  197. package/.next/standalone/SECURITY.md +20 -4
  198. package/.next/standalone/fp-cloud-cli/CHANGELOG.md +34 -1
  199. package/.next/standalone/fp-cloud-cli/README.md +120 -0
  200. package/.next/standalone/fp-cloud-cli/fp_cli/_version.py +1 -1
  201. package/.next/standalone/fp-cloud-cli/fp_cli/app.py +15 -1
  202. package/.next/standalone/fp-cloud-cli/fp_cli/client.py +198 -7
  203. package/.next/standalone/fp-cloud-cli/fp_cli/cloud_output.py +523 -0
  204. package/.next/standalone/fp-cloud-cli/fp_cli/commands/_cloud.py +45 -0
  205. package/.next/standalone/fp-cloud-cli/fp_cli/commands/_write.py +3 -1
  206. package/.next/standalone/fp-cloud-cli/fp_cli/commands/account_cmds.py +171 -0
  207. package/.next/standalone/fp-cloud-cli/fp_cli/commands/agent_cmds.py +80 -7
  208. package/.next/standalone/fp-cloud-cli/fp_cli/commands/alerts_cmds.py +23 -0
  209. package/.next/standalone/fp-cloud-cli/fp_cli/commands/audits_cmds.py +2 -0
  210. package/.next/standalone/fp-cloud-cli/fp_cli/commands/contracts_cmds.py +67 -0
  211. package/.next/standalone/fp-cloud-cli/fp_cli/commands/dashboards_cmds.py +159 -0
  212. package/.next/standalone/fp-cloud-cli/fp_cli/commands/evaluators_cmds.py +380 -0
  213. package/.next/standalone/fp-cloud-cli/fp_cli/commands/events_cmds.py +14 -1
  214. package/.next/standalone/fp-cloud-cli/fp_cli/commands/incidents_cmds.py +82 -6
  215. package/.next/standalone/fp-cloud-cli/fp_cli/commands/list_cmds.py +4 -1
  216. package/.next/standalone/fp-cloud-cli/fp_cli/commands/orgs_cmds.py +17 -0
  217. package/.next/standalone/fp-cloud-cli/fp_cli/commands/policies_cmds.py +143 -1
  218. package/.next/standalone/fp-cloud-cli/fp_cli/commands/queries_cmds.py +70 -0
  219. package/.next/standalone/fp-cloud-cli/fp_cli/commands/sentiment_cmds.py +49 -0
  220. package/.next/standalone/fp-cloud-cli/fp_cli/commands/sessions_cmds.py +95 -1
  221. package/.next/standalone/fp-cloud-cli/fp_cli/commands/settings_cmds.py +2 -0
  222. package/.next/standalone/fp-cloud-cli/fp_cli/commands/usage_cmds.py +21 -1
  223. package/.next/standalone/fp-cloud-cli/fp_cli/commands/users_cmds.py +14 -0
  224. package/.next/standalone/fp-cloud-cli/fp_cli/errors.py +3 -0
  225. package/.next/standalone/fp-cloud-cli/fp_cli/evaluator_spec.py +266 -0
  226. package/.next/standalone/fp-cloud-cli/fp_cli/output.py +187 -81
  227. package/.next/standalone/fp-cloud-cli/fp_cli/theme.py +21 -24
  228. package/.next/standalone/fp-cloud-cli/skill/SKILL.md +124 -23
  229. package/.next/standalone/fp-cloud-cli/skill/agents/openai.yaml +2 -1
  230. package/.next/standalone/fp-cloud-cli/skill/references/commands.md +168 -16
  231. package/.next/standalone/fp-cloud-cli/tests/fake_cloud_smoke.py +312 -0
  232. package/.next/standalone/fp-cloud-cli/tests/test_cloud_account.py +125 -0
  233. package/.next/standalone/fp-cloud-cli/tests/test_cloud_agent.py +253 -0
  234. package/.next/standalone/fp-cloud-cli/tests/test_cloud_human_views.py +287 -0
  235. package/.next/standalone/fp-cloud-cli/tests/test_cloud_observability.py +116 -0
  236. package/.next/standalone/fp-cloud-cli/tests/test_cloud_transport.py +141 -0
  237. package/.next/standalone/fp-cloud-cli/tests/test_commands.py +3 -3
  238. package/.next/standalone/fp-cloud-cli/tests/test_dashboards_agent.py +3 -3
  239. package/.next/standalone/fp-cloud-cli/tests/test_evaluator_authoring.py +449 -0
  240. package/.next/standalone/fp-cloud-cli/tests/test_facets.py +1 -1
  241. package/.next/standalone/fp-cloud-cli/tests/test_help_table_coverage.py +15 -0
  242. package/.next/standalone/fp-cloud-cli/tests/test_operator.py +1 -1
  243. package/.next/standalone/fp-cloud-cli/tests/test_orgs.py +1 -1
  244. package/.next/standalone/fp-cloud-cli/tests/test_output.py +37 -37
  245. package/.next/standalone/fp-cloud-cli/tests/test_round4_behaviour.py +144 -0
  246. package/.next/standalone/fp-cloud-cli/tests/test_screen_language.py +80 -0
  247. package/.next/standalone/fp-cloud-cli/tests/test_session_reevaluate.py +33 -0
  248. package/.next/standalone/fp-cloud-cli/tests/test_staging_parity.py +198 -0
  249. package/.next/standalone/fp-cloud-cli/tests/test_whoami.py +1 -1
  250. package/.next/standalone/fp-cloud-cli/uv.lock +4 -4
  251. package/.next/standalone/hermes-plugin/plugin.yaml +1 -1
  252. package/.next/standalone/node_modules/@next/env/package.json +1 -1
  253. package/.next/standalone/node_modules/next/dist/build/swc/index.js +1 -1
  254. package/.next/standalone/node_modules/next/dist/compiled/next-server/app-page-turbo-experimental.runtime.prod.js +24 -24
  255. package/.next/standalone/node_modules/next/dist/compiled/next-server/app-page-turbo.runtime.prod.js +26 -26
  256. package/.next/standalone/node_modules/next/dist/compiled/next-server/app-route-turbo.runtime.prod.js +3 -3
  257. package/.next/standalone/node_modules/next/dist/compiled/next-server/pages-turbo.runtime.prod.js +13 -13
  258. package/.next/standalone/node_modules/next/dist/lib/patch-incorrect-lockfile.js +3 -3
  259. package/.next/standalone/node_modules/next/dist/server/app-render/app-render.js +41 -40
  260. package/.next/standalone/node_modules/next/dist/server/app-render/async-local-storage.js +1 -1
  261. package/.next/standalone/node_modules/next/dist/server/app-render/dynamic-rendering-validation.js +814 -0
  262. package/.next/standalone/node_modules/next/dist/server/app-render/dynamic-rendering.js +1 -799
  263. package/.next/standalone/node_modules/next/dist/server/base-server.js +39 -5
  264. package/.next/standalone/node_modules/next/dist/server/config.js +1 -1
  265. package/.next/standalone/node_modules/next/dist/server/dev/hot-reloader-turbopack.js +2 -2
  266. package/.next/standalone/node_modules/next/dist/server/dev/hot-reloader-webpack.js +1 -1
  267. package/.next/standalone/node_modules/next/dist/server/lib/app-info-log.js +1 -1
  268. package/.next/standalone/node_modules/next/dist/server/lib/dedupe-fetch.js +4 -43
  269. package/.next/standalone/node_modules/next/dist/server/lib/patch-fetch-symbol.js +13 -0
  270. package/.next/standalone/node_modules/next/dist/server/lib/patch-fetch.js +3 -7
  271. package/.next/standalone/node_modules/next/dist/server/lib/router-server.js +3 -3
  272. package/.next/standalone/node_modules/next/dist/server/lib/router-utils/instrumentation-globals.external.js +77 -12
  273. package/.next/standalone/node_modules/next/dist/server/lib/start-server.js +1 -1
  274. package/.next/standalone/node_modules/next/dist/server/lib/trace/constants.js +12 -0
  275. package/.next/standalone/node_modules/next/dist/server/lib/trace/tracer.js +30 -14
  276. package/.next/standalone/node_modules/next/dist/server/next-server.js +10 -11
  277. package/.next/standalone/node_modules/next/dist/server/route-modules/pages/pages-handler.js +29 -23
  278. package/.next/standalone/node_modules/next/dist/server/route-modules/route-module.js +85 -8
  279. package/.next/standalone/node_modules/next/dist/server/use-cache/use-cache-wrapper.js +1 -1
  280. package/.next/standalone/node_modules/next/dist/server/web/adapter.js +124 -65
  281. package/.next/standalone/node_modules/next/dist/server/web/forward-trace-context.js +102 -0
  282. package/.next/standalone/node_modules/next/dist/telemetry/anonymous-meta.js +1 -1
  283. package/.next/standalone/node_modules/next/dist/telemetry/events/swc-load-failure.js +1 -1
  284. package/.next/standalone/node_modules/next/dist/telemetry/events/version.js +2 -2
  285. package/.next/standalone/node_modules/next/package.json +10 -10
  286. package/.next/standalone/node_modules/react/cjs/react.production.js +1 -1
  287. package/.next/standalone/node_modules/react/package.json +1 -1
  288. package/.next/standalone/node_modules/react-dom/cjs/react-dom-server-legacy.browser.production.js +1 -1
  289. package/.next/standalone/node_modules/react-dom/cjs/react-dom-server-legacy.node.production.js +1 -1
  290. package/.next/standalone/node_modules/react-dom/cjs/react-dom-server.browser.production.js +31 -27
  291. package/.next/standalone/node_modules/react-dom/cjs/react-dom-server.edge.production.js +33 -27
  292. package/.next/standalone/node_modules/react-dom/cjs/react-dom-server.node.production.js +38 -30
  293. package/.next/standalone/node_modules/react-dom/cjs/react-dom.production.js +1 -1
  294. package/.next/standalone/node_modules/react-dom/package.json +2 -2
  295. package/.next/standalone/package.json +10 -10
  296. package/.next/standalone/sdk/python/CHANGELOG.md +8 -4
  297. package/.next/standalone/sdk/python/failproofai_sdk/evaluator/source.py +2 -2
  298. package/.next/standalone/sdk/python/pyproject.toml +2 -7
  299. package/.next/standalone/sdk/python/skill/references/frameworks.md +0 -15
  300. package/.next/standalone/sdk/python/tests/test_docs.py +1 -4
  301. package/.next/standalone/sdk/python/tests/test_evaluator_source.py +1 -1
  302. package/.next/standalone/sdk/python/tests/test_packaging.py +4 -7
  303. package/.next/standalone/sdk/python/tests/test_zero_dependencies.py +2 -13
  304. package/.next/standalone/sdk/python/uv.lock +43 -905
  305. package/.next/standalone/sdk/typescript/CHANGELOG.md +52 -0
  306. package/.next/standalone/sdk/typescript/integration/fixtures/ai-5/package-lock.json +7 -7
  307. package/.next/standalone/sdk/typescript/integration/fixtures/ai-5/package.json +2 -2
  308. package/.next/standalone/sdk/typescript/integration/fixtures/ai-6/package-lock.json +7 -7
  309. package/.next/standalone/sdk/typescript/integration/fixtures/ai-6/package.json +1 -1
  310. package/.next/standalone/sdk/typescript/integration/fixtures/ai-7/package-lock.json +7 -7
  311. package/.next/standalone/sdk/typescript/integration/fixtures/ai-7/package.json +1 -1
  312. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-1/package-lock.json +4 -4
  313. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-1/package.json +1 -1
  314. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-dup-core/package-lock.json +4 -4
  315. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-dup-core/package.json +1 -1
  316. package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.11/package-lock.json +3 -3
  317. package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.11/package.json +3 -0
  318. package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.12/package-lock.json +4 -4
  319. package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.12/package.json +1 -1
  320. package/.next/standalone/sdk/typescript/integration/fixtures/mastra-0/package-lock.json +25 -25
  321. package/.next/standalone/sdk/typescript/integration/fixtures/mastra-0/package.json +1 -1
  322. package/.next/standalone/sdk/typescript/integration/fixtures/mastra-1/package-lock.json +34 -22
  323. package/.next/standalone/sdk/typescript/integration/fixtures/mastra-1/package.json +3 -2
  324. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/package-lock.json +10 -10
  325. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/package.json +1 -1
  326. package/.next/standalone/sdk/typescript/integration/fixtures/runtimes/deno-npm.ts +1 -1
  327. package/.next/standalone/sdk/typescript/integration/fixtures/runtimes/package-lock.json +7 -7
  328. package/.next/standalone/sdk/typescript/integration/fixtures/runtimes/package.json +1 -1
  329. package/.next/standalone/server.js +1 -1
  330. package/README.md +0 -6
  331. package/dist/cli.mjs +87 -38
  332. package/dist/worker.mjs +73 -28
  333. package/hermes-plugin/plugin.yaml +1 -1
  334. package/openclaw-plugin/daemon-client.js +254 -0
  335. package/openclaw-plugin/hooks.js +187 -0
  336. package/openclaw-plugin/index.js +17 -211
  337. package/package.json +10 -10
  338. package/scripts/sync-agent-cli-harnesses-prompt.md +26 -31
  339. package/src/hooks/agent-skill.ts +3 -0
  340. package/src/hooks/enforcement-capability.ts +1 -1
  341. package/src/hooks/fp-home.ts +1 -1
  342. package/src/hooks/handler.ts +22 -3
  343. package/src/hooks/integrations.ts +5 -2
  344. package/src/hooks/semantic/intent.ts +127 -24
  345. package/src/hooks/semantic/jev-review.ts +21 -2
  346. package/.next/standalone/.codex/hooks.json +0 -76
  347. package/.next/standalone/.cursor/hooks.json +0 -47
  348. package/.next/standalone/.factory/hooks.json +0 -112
  349. package/.next/standalone/.next/server/chunks/[externals]__1x24dzcbbq6-g._.js +0 -3
  350. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0__a_je8fsn65._.js +0 -3
  351. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0l-oi4gdtmlo5._.js +0 -3
  352. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0t9ufnv5hi2hq._.js +0 -327
  353. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1aaw59g-5uty7._.js +0 -322
  354. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1hqpg6vgmfexv._.js +0 -3
  355. package/.next/standalone/.next/server/chunks/ssr/[externals]__0ilfh9mfnzsth._.js +0 -3
  356. package/.next/standalone/.next/server/chunks/ssr/[externals]__0ohnuzsaozaca._.js +0 -3
  357. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0pwj2h2efe5f-._.js +0 -14
  358. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_0zuikgt2xho-v._.js +0 -271
  359. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_158jo-9mwvgad._.js +0 -291
  360. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_19r82zsxo2jj1._.js +0 -291
  361. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_1dupwucoqt5qm._.js +0 -3
  362. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_shared_lib_03w27x2kh17_8._.js +0 -23
  363. package/.next/standalone/.next/static/chunks/1my3-5p47t7r-.js +0 -1
  364. package/.next/standalone/.next/static/chunks/21hckpmsc4g70.js +0 -6
  365. package/.next/standalone/.next/static/chunks/2hmex93ppj1ke.js +0 -1
  366. package/.next/standalone/.next/static/chunks/40oworn_-x12p.js +0 -1
  367. package/.next/standalone/.opencode/opencode.json +0 -4
  368. package/.next/standalone/.opencode/plugins/failproofai.mjs +0 -210
  369. package/.next/standalone/.pi/settings.json +0 -5
  370. package/.next/standalone/node_modules/react/cjs/react.development.js +0 -1330
  371. package/scripts/dev-hook.mjs +0 -333
  372. /package/.next/standalone/.next/static/{LHCtFxVG0mdvd4lsXAOFC → 1n2dyfTQb0MDajeqlipJy}/_buildManifest.js +0 -0
  373. /package/.next/standalone/.next/static/{LHCtFxVG0mdvd4lsXAOFC → 1n2dyfTQb0MDajeqlipJy}/_clientMiddlewareManifest.js +0 -0
  374. /package/.next/standalone/.next/static/{LHCtFxVG0mdvd4lsXAOFC → 1n2dyfTQb0MDajeqlipJy}/_ssgManifest.js +0 -0
package/dist/worker.mjs CHANGED
@@ -1166,7 +1166,7 @@ function instruct(reason) {
1166
1166
  }
1167
1167
 
1168
1168
  // package.json
1169
- var version = "1.0.12-beta.2";
1169
+ var version = "1.0.13-beta.1";
1170
1170
  var init_package = () => {};
1171
1171
 
1172
1172
  // src/hooks/agent-targets.ts
@@ -15706,6 +15706,7 @@ __export(exports_intent, {
15706
15706
  cleanHumanTurn: () => cleanHumanTurn,
15707
15707
  cleanUserSaid: () => cleanUserSaid,
15708
15708
  humanMessageText: () => humanMessageText,
15709
+ intentProfileKey: () => intentProfileKey,
15709
15710
  lastAgentMessage: () => lastAgentMessage,
15710
15711
  looseIntentStoreDir: () => looseIntentStoreDir,
15711
15712
  pruneExpiredSessions: () => pruneExpiredSessions,
@@ -15725,13 +15726,27 @@ import {
15725
15726
  writeFileSync as writeFileSync8
15726
15727
  } from "node:fs";
15727
15728
  import { dirname as dirname10, resolve as resolve17 } from "node:path";
15729
+ function intentProfileKey(profile) {
15730
+ if (validAgentIdentity(profile.agent))
15731
+ return `${profile.agent.integration}.${profile.agent.instanceId}`;
15732
+ return isKnownCli(profile.cli) ? profile.cli : null;
15733
+ }
15734
+ function storeSlot(sessionId, profile) {
15735
+ if (profile === undefined)
15736
+ return { dir: sessionsDir(), file: resolve17(sessionsDir(), `${sessionId}.json`) };
15737
+ const key = intentProfileKey(profile);
15738
+ if (key === null || !PROFILE_DIR_RE.test(key))
15739
+ return null;
15740
+ const dir = resolve17(sessionsDir(), key);
15741
+ return { dir, file: resolve17(dir, `${sessionId}.json`) };
15742
+ }
15728
15743
  function modesAreMeaningful2() {
15729
15744
  return process.platform !== "win32";
15730
15745
  }
15731
- function storeDirChain() {
15746
+ function storeDirChain(innermost = sessionsDir()) {
15732
15747
  const home = resolve17(failproofaiHome());
15733
15748
  const chain = [];
15734
- let dir = sessionsDir();
15749
+ let dir = innermost;
15735
15750
  for (let i = 0;i < 8; i++) {
15736
15751
  chain.push(dir);
15737
15752
  if (dir === home)
@@ -15743,10 +15758,10 @@ function storeDirChain() {
15743
15758
  }
15744
15759
  return chain;
15745
15760
  }
15746
- function looseIntentStoreDir() {
15761
+ function looseIntentStoreDir(innermost) {
15747
15762
  if (!modesAreMeaningful2())
15748
15763
  return null;
15749
- for (const dir of storeDirChain()) {
15764
+ for (const dir of storeDirChain(innermost)) {
15750
15765
  let mode;
15751
15766
  try {
15752
15767
  mode = statSync20(dir).mode & 511;
@@ -15765,23 +15780,22 @@ function looseIntentStoreDir() {
15765
15780
  }
15766
15781
  return null;
15767
15782
  }
15768
- function readIntentFile(sessionId) {
15783
+ function readIntentFile(slot) {
15769
15784
  try {
15770
- const parsed = JSON.parse(readFileSync19(intentFile(sessionId), "utf8"));
15785
+ const parsed = JSON.parse(readFileSync19(slot.file, "utf8"));
15771
15786
  return Array.isArray(parsed?.prompts) ? parsed : { prompts: [] };
15772
15787
  } catch {
15773
15788
  return { prompts: [] };
15774
15789
  }
15775
15790
  }
15776
- function appendPrompt(sessionId, entry) {
15791
+ function appendPrompt(slot, entry) {
15777
15792
  try {
15778
- const file = readIntentFile(sessionId);
15793
+ const file = readIntentFile(slot);
15779
15794
  const last = file.prompts[file.prompts.length - 1];
15780
15795
  const kept = last && last.text === entry.text ? file.prompts.slice(0, -1) : file.prompts;
15781
15796
  file.prompts = [...kept, entry].slice(-MAX_RECORDED_PROMPTS);
15782
- const dir = sessionsDir();
15783
- mkdirSync9(dir, { recursive: true, mode: 448 });
15784
- const target = intentFile(sessionId);
15797
+ mkdirSync9(slot.dir, { recursive: true, mode: 448 });
15798
+ const target = slot.file;
15785
15799
  const isNew = !fileExists2(target);
15786
15800
  const tmp = `${target}.${process.pid}.tmp`;
15787
15801
  writeFileSync8(tmp, JSON.stringify(file), { mode: 384 });
@@ -15802,9 +15816,24 @@ function fileExists2(path) {
15802
15816
  }
15803
15817
  }
15804
15818
  function pruneExpiredSessions(now = Date.now()) {
15819
+ const root = sessionsDir();
15820
+ let removed = pruneDir(root, now);
15821
+ try {
15822
+ for (const name of readdirSync13(root)) {
15823
+ if (!PROFILE_DIR_RE.test(name))
15824
+ continue;
15825
+ const dir = resolve17(root, name);
15826
+ try {
15827
+ if (statSync20(dir).isDirectory())
15828
+ removed += pruneDir(dir, now);
15829
+ } catch {}
15830
+ }
15831
+ } catch {}
15832
+ return removed;
15833
+ }
15834
+ function pruneDir(dir, now) {
15805
15835
  let removed = 0;
15806
15836
  try {
15807
- const dir = sessionsDir();
15808
15837
  for (const name of readdirSync13(dir)) {
15809
15838
  if (!SESSION_FILE_RE3.test(name))
15810
15839
  continue;
@@ -15820,23 +15849,29 @@ function pruneExpiredSessions(now = Date.now()) {
15820
15849
  } catch {}
15821
15850
  return removed;
15822
15851
  }
15823
- function recordPrompt(sessionId, prompt, agent, now) {
15852
+ function recordPrompt(sessionId, profile, prompt, agent, now) {
15824
15853
  if (!SESSION_ID_RE2.test(sessionId))
15825
15854
  return false;
15826
15855
  if (prompt.trim().length === 0)
15827
15856
  return false;
15857
+ const slot = storeSlot(sessionId, profile);
15858
+ if (!slot)
15859
+ return false;
15828
15860
  try {
15829
- return appendPrompt(sessionId, { at: now, text: storable(prompt.trim()), agent: agent === null ? null : storable(agent) });
15861
+ return appendPrompt(slot, { at: now, text: storable(prompt.trim()), agent: agent === null ? null : storable(agent) });
15830
15862
  } catch {
15831
15863
  return false;
15832
15864
  }
15833
15865
  }
15834
- function livePrompts(sessionId, now) {
15866
+ function livePrompts(sessionId, now, profile) {
15835
15867
  if (!sessionId || !SESSION_ID_RE2.test(sessionId))
15836
15868
  return [];
15837
- if (looseIntentStoreDir() !== null)
15869
+ const slot = storeSlot(sessionId, profile);
15870
+ if (!slot)
15838
15871
  return [];
15839
- return readIntentFile(sessionId).prompts.filter((p) => typeof p?.text === "string" && typeof p.at === "number" && now - p.at <= INTENT_MAX_AGE_MS && p.at - now <= MAX_CLOCK_SKEW_MS);
15872
+ if (looseIntentStoreDir(slot.dir) !== null)
15873
+ return [];
15874
+ return readIntentFile(slot).prompts.filter((p) => typeof p?.text === "string" && typeof p.at === "number" && now - p.at <= INTENT_MAX_AGE_MS && p.at - now <= MAX_CLOCK_SKEW_MS);
15840
15875
  }
15841
15876
  function replaceTagBlocks(text, tag, replace, attributes = false) {
15842
15877
  const open = attributes ? `<${tag}` : `<${tag}>`;
@@ -16183,16 +16218,16 @@ function captureIntent(ev, now = Date.now()) {
16183
16218
  const cleaned = cleanHumanTurn(raw);
16184
16219
  if (cleaned === null)
16185
16220
  return;
16186
- recordPrompt(sessionId, cleaned, lastAgentMessage(ev.transcriptPath), now);
16221
+ recordPrompt(sessionId, ev.profile, cleaned, lastAgentMessage(ev.transcriptPath), now);
16187
16222
  } catch {}
16188
16223
  }
16189
- function readIntent(sessionId, now = Date.now()) {
16190
- const prompts = livePrompts(sessionId, now);
16224
+ function readIntent(sessionId, now = Date.now(), profile) {
16225
+ const prompts = livePrompts(sessionId, now, profile);
16191
16226
  const latest = prompts[prompts.length - 1];
16192
16227
  const agent = latest && typeof latest.agent === "string" && latest.agent.length > 0 ? latest.agent : null;
16193
16228
  return { userSaid: prompts.map((p) => p.text), agentLastMessage: agent };
16194
16229
  }
16195
- var MAX_RECORDED_PROMPTS = 5, INTENT_MAX_AGE_MS, MAX_CLOCK_SKEW_MS, SESSION_ID_RE2, sessionsDir = () => resolve17(semanticDir(), "sessions"), intentFile = (sessionId) => resolve17(sessionsDir(), `${sessionId}.json`), DIR_WRITABLE_BY_OTHERS3 = 18, SESSION_FILE_RE3, NON_HUMAN_PREFIXES, CONTINUATION_PREFIX = "This session is being continued from a previous conversation", IDE_MACHINE_OPENERS, IDE_AMBIGUOUS_OPENERS, IDE_REQUEST_HEADINGS, obj = (v) => v && typeof v === "object" && !Array.isArray(v) ? v : undefined, CLAUDE_MACHINE_SOURCES, claudeMachineTurn = (payload) => typeof payload.source === "string" && CLAUDE_MACHINE_SOURCES.has(payload.source), piMachineTurn = (payload) => payload.input_source === "extension" || payload.source === "extension", openclawMachineRun = (payload) => {
16230
+ var MAX_RECORDED_PROMPTS = 5, INTENT_MAX_AGE_MS, MAX_CLOCK_SKEW_MS, SESSION_ID_RE2, sessionsDir = () => resolve17(semanticDir(), "sessions"), PROFILE_DIR_RE, DIR_WRITABLE_BY_OTHERS3 = 18, SESSION_FILE_RE3, NON_HUMAN_PREFIXES, CONTINUATION_PREFIX = "This session is being continued from a previous conversation", IDE_MACHINE_OPENERS, IDE_AMBIGUOUS_OPENERS, IDE_REQUEST_HEADINGS, obj = (v) => v && typeof v === "object" && !Array.isArray(v) ? v : undefined, CLAUDE_MACHINE_SOURCES, claudeMachineTurn = (payload) => typeof payload.source === "string" && CLAUDE_MACHINE_SOURCES.has(payload.source), piMachineTurn = (payload) => payload.input_source === "extension" || payload.source === "extension", openclawMachineRun = (payload) => {
16196
16231
  const meta = obj(payload.openclaw);
16197
16232
  if (!meta)
16198
16233
  return false;
@@ -16208,9 +16243,11 @@ var MAX_RECORDED_PROMPTS = 5, INTENT_MAX_AGE_MS, MAX_CLOCK_SKEW_MS, SESSION_ID_R
16208
16243
  var init_intent = __esm(() => {
16209
16244
  init_fp_home();
16210
16245
  init_envelope();
16246
+ init_agent_targets();
16211
16247
  INTENT_MAX_AGE_MS = 6 * 60 * 60 * 1000;
16212
16248
  MAX_CLOCK_SKEW_MS = 5 * 60 * 1000;
16213
16249
  SESSION_ID_RE2 = /^[A-Za-z0-9._-]{1,128}$/;
16250
+ PROFILE_DIR_RE = /^[a-z]+(?:\.agt_[0-9a-f]{16,32})?$/;
16214
16251
  SESSION_FILE_RE3 = /^[A-Za-z0-9._-]{1,128}\.json(?:\.\d+\.tmp)?$/;
16215
16252
  NON_HUMAN_PREFIXES = [
16216
16253
  "<local-command-caveat>",
@@ -17939,7 +17976,10 @@ function startJevReview(cfg, call) {
17939
17976
  }
17940
17977
  let intent;
17941
17978
  try {
17942
- intent = intentReader.readIntent(call.sessionId);
17979
+ intent = intentReader.readIntent(call.sessionId, undefined, {
17980
+ cli: call.cli,
17981
+ agent: call.agent !== undefined ? call.agent : call.cloud?.agent ?? null
17982
+ });
17943
17983
  } catch {
17944
17984
  intent = { userSaid: [], agentLastMessage: null };
17945
17985
  }
@@ -18351,6 +18391,7 @@ async function startTwoTier(canonicalEventType, parsed, session, cli, opts, acti
18351
18391
  permissionMode: session.permissionMode,
18352
18392
  sessionId: session.sessionId,
18353
18393
  cli,
18394
+ agent,
18354
18395
  ...loaded.cloud ? { cloud: loaded.cloud } : {},
18355
18396
  ...activePause ? { localPaused: true } : {}
18356
18397
  });
@@ -18377,13 +18418,16 @@ function jevTelemetry(activity) {
18377
18418
  return {};
18378
18419
  }
18379
18420
  }
18380
- async function captureJevIntent(canonicalEventType, decision, parsed, session, cli, opts) {
18421
+ async function captureJevIntent(canonicalEventType, decision, parsed, session, cli, opts, agent) {
18381
18422
  if (canonicalEventType !== "UserPromptSubmit" || jevForcedOff(opts))
18382
18423
  return;
18383
18424
  try {
18384
- if (!cloudJevAsks(readCloudJevMode()) && !jevChecksInstalled())
18425
+ const cloudAsks = cloudJevAsks(readCloudJevMode());
18426
+ if (!cloudAsks && !jevChecksInstalled())
18427
+ return;
18428
+ if (cloudAsks && cloudJevAssignmentsFor(agent)?.length === 0 && !packJevChecksInstalled())
18385
18429
  return;
18386
- if (!await readJevConfig())
18430
+ if (!await readJevConfig(agent))
18387
18431
  return;
18388
18432
  if (decision === "deny") {
18389
18433
  await Promise.resolve().then(() => init_enforcement_capability());
@@ -18397,7 +18441,8 @@ async function captureJevIntent(canonicalEventType, decision, parsed, session, c
18397
18441
  transcriptPath: session.transcriptPath,
18398
18442
  cli,
18399
18443
  payload: parsed,
18400
- prompt: parsed.prompt
18444
+ prompt: parsed.prompt,
18445
+ profile: { cli, agent }
18401
18446
  };
18402
18447
  captureIntent(event);
18403
18448
  } catch (err) {
@@ -18663,7 +18708,7 @@ async function evaluateHookEvent(eventType, cli = "claude", stdinPayload, opts)
18663
18708
  }
18664
18709
  const durationMs = Math.round(performance.now() - startTime);
18665
18710
  hookLogInfo(`result=${result.decision} policy=${result.policyName ?? "none"} duration=${durationMs}ms`);
18666
- await captureJevIntent(canonicalEventType, result.decision, parsed, session, cli, opts);
18711
+ await captureJevIntent(canonicalEventType, result.decision, parsed, session, cli, opts, runtimeAgent);
18667
18712
  const matchedPolicies = matchedBeforeRelease ?? getPoliciesForEvent(canonicalEventType, parsed.tool_name).map((p) => p.name);
18668
18713
  const jevOrigin = result.policyName && result.twoTier?.decidedByJev ? result.twoTier.jevOrigin : undefined;
18669
18714
  const activityEntry = {
@@ -1,5 +1,5 @@
1
1
  name: failproofai
2
- version: 1.0.12-beta.2
2
+ version: 1.0.13-beta.1
3
3
  description: Real-time FailproofAI policy enforcement for Hermes
4
4
  manifest_version: 2
5
5
  api_version: 1
@@ -0,0 +1,254 @@
1
+ /**
2
+ * Asks failproofaid for a verdict over its owner-only Unix socket — the same
3
+ * `hook` request `failproofai --hook <event> --cli openclaw` sends to the
4
+ * daemon (crates/PROTOCOL.md), made from inside the gateway instead of from a
5
+ * process spawned per hook. The Hermes plugin (hermes-plugin/client.py) reaches
6
+ * the daemon the same way.
7
+ *
8
+ * Why not spawn the CLI: OpenClaw ≥ 2026.9.6 imports this plugin from a copy
9
+ * under ~/.openclaw/tmp/plugin-captures/…, and the copy holds only this
10
+ * directory's files. A CLI path derived from import.meta.url (`../dist/cli.mjs`)
11
+ * then points at nothing; the old shim read the spawn failure as "allow", so
12
+ * every tool call ran unchecked and no hook activity was recorded. The socket
13
+ * path depends only on the environment, never on where this file sits.
14
+ *
15
+ * Self-contained on purpose — node built-ins only, nothing imported from
16
+ * outside this directory — because the capture copies nothing else.
17
+ */
18
+ import { createConnection } from "node:net";
19
+ import { homedir } from "node:os";
20
+ import { resolve } from "node:path";
21
+
22
+ export const PROTOCOL_VERSION = 2;
23
+ // The daemon's frame limit (crates/fpai-ipc/src/framing.rs), both ways.
24
+ const MAX_FRAME_BYTES = 16 * 1024 * 1024;
25
+ // The payload limit the CLI applies to its stdin (handler.ts, read-stdin.ts).
26
+ // It bounds the RAW payload: the envelope carries it as an escaped JSON
27
+ // string plus routing fields, so it is larger, and only the frame limit
28
+ // applies to the envelope.
29
+ export const MAX_PAYLOAD_BYTES = 1_048_576;
30
+
31
+ // The CLI's daemon client budgets these separately for the reason it gives:
32
+ // connecting is the "is anything listening" probe, the response covers the
33
+ // whole evaluation. 250 ms matches the Hermes plugin; 30 s matches the
34
+ // daemon's own read timeout on its worker (worker.rs).
35
+ export const CONNECT_TIMEOUT_MS = 250;
36
+ export const RESPONSE_TIMEOUT_MS = 30_000;
37
+
38
+ const PROTOCOL_MISMATCH_MESSAGE =
39
+ "failproofaid is running a different protocol version than this plugin, so it cannot " +
40
+ "evaluate this call. Run `failproofai update` to update the daemon.";
41
+ const UNREACHABLE_MESSAGE =
42
+ "failproofaid could not be reached. This machine is configured to run hooks through it " +
43
+ "— check the daemon (see `failproofai config`) rather than retrying blindly.";
44
+
45
+ /** Mirrors `daemonSocket()` in src/hooks/fp-home.ts. */
46
+ export function daemonSocketPath(env = process.env, home = homedir()) {
47
+ return (
48
+ env.FAILPROOFAI_DAEMON_SOCKET ||
49
+ resolve(env.FAILPROOFAI_HOME || resolve(home, ".failproofai"), "run", "failproofaid.sock")
50
+ );
51
+ }
52
+
53
+ /**
54
+ * The gateway profile's openclaw.json — what the spawned CLI computed from the
55
+ * gateway's environment (`runtimeAgentSettingsPath("openclaw", …)` in
56
+ * src/hooks/agent-roster.ts). Sent explicitly: left out, the daemon's worker
57
+ * would resolve it from the DAEMON's environment and attribute a
58
+ * `--profile <name>` gateway to the default profile.
59
+ */
60
+ export function openclawAgentSettingsPath(env = process.env, home = homedir()) {
61
+ const config = env.OPENCLAW_CONFIG_PATH;
62
+ if (config?.trim()) return resolve(config);
63
+ const state = env.OPENCLAW_STATE_DIR || env.OPENCLAW_HOME;
64
+ if (state?.trim()) return resolve(state, "openclaw.json");
65
+ const profile = env.OPENCLAW_PROFILE?.trim();
66
+ if (profile && profile !== "default" && /^[A-Za-z0-9._-]{1,80}$/.test(profile) && !profile.startsWith(".")) {
67
+ return resolve(home, `.openclaw-${profile}`, "openclaw.json");
68
+ }
69
+ return resolve(home, ".openclaw", "openclaw.json");
70
+ }
71
+
72
+ function failed(failure, message) {
73
+ return { ok: false, failure, message };
74
+ }
75
+
76
+ /**
77
+ * Turn the daemon's reply into a flat `{permission, reason}` verdict. For
78
+ * OpenClaw the evaluator always exits 0 and prints either nothing (allow) or
79
+ * one JSON object, so anything else is an evaluation failure — never an allow.
80
+ */
81
+ function readHookResult(message) {
82
+ if (message === null || typeof message !== "object" || Array.isArray(message)) {
83
+ return failed("invalid", "failproofaid returned a non-object response");
84
+ }
85
+ if (message.protocolVersion !== PROTOCOL_VERSION) {
86
+ return failed("protocol-mismatch", PROTOCOL_MISMATCH_MESSAGE);
87
+ }
88
+ if (message.type === "error") {
89
+ const detail = typeof message.message === "string" && message.message ? message.message : "no detail";
90
+ return failed("evaluation", `failproofaid could not evaluate this call: ${detail}`);
91
+ }
92
+ if (message.type !== "hookResult") {
93
+ return failed("invalid", `failproofaid returned an unexpected ${JSON.stringify(message.type)} response`);
94
+ }
95
+ // The daemon always serializes all three (crates/fpai-ipc/src/envelope.rs);
96
+ // a frame missing one is not a hookResult, and must not read as an empty
97
+ // stdout — that is the allow.
98
+ if (
99
+ !Number.isInteger(message.exitCode) ||
100
+ typeof message.stdout !== "string" ||
101
+ typeof message.stderr !== "string"
102
+ ) {
103
+ return failed("invalid", "failproofaid returned an incomplete hookResult");
104
+ }
105
+ if (message.exitCode !== 0) {
106
+ return failed("evaluation", `failproofai exited ${String(message.exitCode)} without a verdict`);
107
+ }
108
+ const stdout = message.stdout.trim();
109
+ if (!stdout) return { ok: true, verdict: { permission: "allow" } };
110
+ let verdict;
111
+ try {
112
+ verdict = JSON.parse(stdout);
113
+ } catch {
114
+ return failed("invalid", "failproofai returned a verdict that is not JSON");
115
+ }
116
+ return isVerdict(verdict)
117
+ ? { ok: true, verdict }
118
+ : failed("invalid", "failproofai returned a malformed verdict");
119
+ }
120
+
121
+ const PERMISSIONS = new Set(["allow", "deny", "instruct"]);
122
+
123
+ /** The flat shape policy-evaluator.ts prints for `--cli openclaw`; unknown keys are ignored. */
124
+ function isVerdict(verdict) {
125
+ if (verdict === null || typeof verdict !== "object" || Array.isArray(verdict)) return false;
126
+ if (!PERMISSIONS.has(verdict.permission)) return false;
127
+ if (verdict.reason !== undefined && typeof verdict.reason !== "string") return false;
128
+ if (verdict.policyName !== undefined && typeof verdict.policyName !== "string") return false;
129
+ if (
130
+ verdict.policyNames !== undefined &&
131
+ !(Array.isArray(verdict.policyNames) && verdict.policyNames.every((name) => typeof name === "string"))
132
+ ) {
133
+ return false;
134
+ }
135
+ return true;
136
+ }
137
+
138
+ /**
139
+ * One request, one connection, one frame each way. Never rejects: resolves to
140
+ * `{ok: true, verdict}` (plus `oversized: true`, see below) or
141
+ * `{ok: false, failure, message}`.
142
+ *
143
+ * A payload over MAX_PAYLOAD_BYTES is sent as an empty stdin, exactly as the
144
+ * CLI discards an oversized stdin and evaluates an empty payload;
145
+ * `oversized: true` lets the caller say so instead of discarding it silently.
146
+ */
147
+ export function requestHookVerdict({
148
+ event,
149
+ payload,
150
+ cwd = "",
151
+ agentSettingsPath = "",
152
+ socketPath = daemonSocketPath(),
153
+ connectTimeoutMs = CONNECT_TIMEOUT_MS,
154
+ responseTimeoutMs = RESPONSE_TIMEOUT_MS,
155
+ }) {
156
+ return new Promise((done) => {
157
+ let body;
158
+ let oversized = false;
159
+ try {
160
+ let stdin = JSON.stringify(payload ?? {});
161
+ if (Buffer.byteLength(stdin, "utf8") > MAX_PAYLOAD_BYTES) {
162
+ stdin = "";
163
+ oversized = true;
164
+ }
165
+ body = Buffer.from(
166
+ JSON.stringify({
167
+ type: "hook",
168
+ protocolVersion: PROTOCOL_VERSION,
169
+ hookEvent: event,
170
+ cli: "openclaw",
171
+ stdin,
172
+ ...(typeof cwd === "string" && cwd ? { cwd } : {}),
173
+ agentSettingsPath: agentSettingsPath || "",
174
+ }),
175
+ "utf8",
176
+ );
177
+ } catch (err) {
178
+ done(failed("invalid", `could not encode the hook request: ${err?.message ?? String(err)}`));
179
+ return;
180
+ }
181
+ // Unreachable for a payload within MAX_PAYLOAD_BYTES (escaping at most
182
+ // sextuples it); kept so nothing over the daemon's limit is ever sent.
183
+ if (body.length > MAX_FRAME_BYTES) {
184
+ done(failed("invalid", "hook request exceeds the daemon's 16 MiB frame limit"));
185
+ return;
186
+ }
187
+
188
+ let settled = false;
189
+ let connected = false;
190
+ let received = Buffer.alloc(0);
191
+ let timer;
192
+ let socket;
193
+ const finish = (result) => {
194
+ if (settled) return;
195
+ settled = true;
196
+ clearTimeout(timer);
197
+ try { socket?.destroy(); } catch { /* already closed */ }
198
+ done(result);
199
+ };
200
+
201
+ try {
202
+ socket = createConnection(socketPath);
203
+ } catch {
204
+ finish(failed("unreachable", UNREACHABLE_MESSAGE));
205
+ return;
206
+ }
207
+ timer = setTimeout(() => finish(failed("unreachable", UNREACHABLE_MESSAGE)), connectTimeoutMs);
208
+
209
+ socket.on("connect", () => {
210
+ connected = true;
211
+ clearTimeout(timer);
212
+ timer = setTimeout(
213
+ () => finish(failed("timeout", `failproofaid did not answer within ${responseTimeoutMs} ms`)),
214
+ responseTimeoutMs,
215
+ );
216
+ const header = Buffer.alloc(4);
217
+ header.writeUInt32BE(body.length, 0);
218
+ socket.write(Buffer.concat([header, body]));
219
+ });
220
+ socket.on("data", (chunk) => {
221
+ received = Buffer.concat([received, chunk]);
222
+ if (received.length < 4) return;
223
+ const length = received.readUInt32BE(0);
224
+ if (length > MAX_FRAME_BYTES) {
225
+ finish(failed("invalid", "failproofaid response exceeds the 16 MiB limit"));
226
+ return;
227
+ }
228
+ if (received.length < 4 + length) return;
229
+ let message;
230
+ try {
231
+ message = JSON.parse(received.subarray(4, 4 + length).toString("utf8"));
232
+ } catch {
233
+ finish(failed("invalid", "failproofaid returned a response that is not JSON"));
234
+ return;
235
+ }
236
+ const result = readHookResult(message);
237
+ finish(result.ok && oversized ? { ...result, oversized: true } : result);
238
+ });
239
+ socket.on("error", (err) => {
240
+ finish(
241
+ connected
242
+ ? failed("evaluation", `failproofaid connection failed: ${err?.message ?? String(err)}`)
243
+ : failed("unreachable", UNREACHABLE_MESSAGE),
244
+ );
245
+ });
246
+ socket.on("close", () => {
247
+ finish(
248
+ connected
249
+ ? failed("evaluation", "failproofaid closed the connection before returning a verdict")
250
+ : failed("unreachable", UNREACHABLE_MESSAGE),
251
+ );
252
+ });
253
+ });
254
+ }
@@ -0,0 +1,187 @@
1
+ /**
2
+ * OpenClaw typed plugin hooks → failproofai verdicts.
3
+ *
4
+ * Kept apart from index.js (whose only job is `definePluginEntry`) so the
5
+ * hook wiring is importable without the `openclaw/plugin-sdk` package, which
6
+ * only resolves inside the gateway.
7
+ *
8
+ * Each hook sends a Claude-shaped payload (params→tool_input, toolName→
9
+ * tool_name, transcriptPath→transcript_path, stopHookActive→stop_hook_active,
10
+ * sessionKey→session_id) with the RAW event and tool names; the daemon's
11
+ * worker canonicalizes them via the OPENCLAW_* maps in src/hooks/types.ts
12
+ * (single source of truth — no inline maps here, unlike the OpenCode/Pi shims).
13
+ *
14
+ * When failproofaid cannot return a verdict the gates fail closed, as every
15
+ * other CLI does on a daemon-configured machine (bin/failproofai.mjs): a tool
16
+ * call or prompt is blocked with the reason, and the reason is logged. The
17
+ * turn-end gate is the exception — a revise cannot bring the daemon back, so
18
+ * forcing one would loop the turn instead of protecting anything.
19
+ */
20
+ import { createInstructRetryGate, mapBeforeToolVerdict } from "./instruct-retry-gate.js";
21
+ import { createWorkspaceContext } from "./workspace-context.js";
22
+ import { openclawAgentSettingsPath, requestHookVerdict } from "./daemon-client.js";
23
+
24
+ const sharedRetryGate = createInstructRetryGate();
25
+ const sharedWorkspace = createWorkspaceContext();
26
+
27
+ const OBSERVATION_EVENTS = [
28
+ "after_tool_call",
29
+ "session_start",
30
+ "session_end",
31
+ "subagent_ended",
32
+ "before_compaction",
33
+ ];
34
+
35
+ const HOOK_OPTIONS = { priority: 100, timeoutMs: 60_000 };
36
+
37
+ /** Claude-shaped stdin base. Extra keys are ignored by the evaluator's payload
38
+ * parser; they're forwarded for activity attribution. */
39
+ function baseMeta(payload, ctx, config, workspace) {
40
+ const p = payload || {};
41
+ const c = ctx || {};
42
+ return {
43
+ session_id: c.sessionId ?? p.sessionId ?? c.sessionKey ?? p.sessionKey,
44
+ cwd: workspace.resolveWorkspace(p, c, config) ?? process.cwd(),
45
+ transcript_path: p.transcriptPath,
46
+ stop_hook_active: p.stopHookActive === true,
47
+ openclaw: {
48
+ agentId: c.agentId,
49
+ sessionKey: c.sessionKey ?? p.sessionKey,
50
+ runId: c.runId ?? p.runId,
51
+ provider: p.provider,
52
+ model: p.model,
53
+ },
54
+ };
55
+ }
56
+
57
+ function defaultEvaluate(event, payload) {
58
+ return requestHookVerdict({
59
+ event,
60
+ payload,
61
+ cwd: payload.cwd,
62
+ agentSettingsPath: openclawAgentSettingsPath(),
63
+ });
64
+ }
65
+
66
+ function logFailure(api, event, message) {
67
+ const line = `[failproofai] ${event}: ${message}`;
68
+ try {
69
+ if (typeof api?.logger?.error === "function") {
70
+ api.logger.error(line);
71
+ return;
72
+ }
73
+ } catch { /* fall through to stderr */ }
74
+ process.stderr.write(`${line}\n`);
75
+ }
76
+
77
+ const blockedReason = (message) => `FailproofAI could not check this call, so it was blocked: ${message}`;
78
+
79
+ /**
80
+ * Register every hook on `api`. `evaluate(event, payload)` resolves to
81
+ * `{ok: true, verdict}` or `{ok: false, message}`; tests inject their own.
82
+ */
83
+ export function registerFailproofaiHooks(api, {
84
+ evaluate = defaultEvaluate,
85
+ retryGate = sharedRetryGate,
86
+ workspace = sharedWorkspace,
87
+ } = {}) {
88
+ const ask = async (event, payload) => {
89
+ let result;
90
+ try {
91
+ result = await evaluate(event, payload);
92
+ } catch (err) {
93
+ result = { ok: false, message: `the failproofai plugin failed: ${err?.message ?? String(err)}` };
94
+ }
95
+ if (!result?.ok) logFailure(api, event, result?.message ?? "no verdict");
96
+ // Same outcome as the CLI's oversized stdin (warn, evaluate an empty
97
+ // payload), and said out loud for the same reason it is there.
98
+ else if (result.oversized) {
99
+ logFailure(api, event, "payload exceeds 1 MiB, so it was evaluated as an empty payload");
100
+ }
101
+ return result ?? { ok: false, message: "no verdict" };
102
+ };
103
+
104
+ // before_tool_call → PreToolUse. Deny always blocks. Instruct blocks the
105
+ // first matching attempt only, using blockReason to give the model the
106
+ // instruction, then permits retries from that session/policy for 5 minutes.
107
+ api.on(
108
+ "before_tool_call",
109
+ async (payload, ctx) => {
110
+ const p = payload || {};
111
+ const result = await ask("before_tool_call", {
112
+ ...baseMeta(payload, ctx, api.config, workspace),
113
+ tool_name: p.toolName,
114
+ tool_input: p.params,
115
+ hook_event_name: "before_tool_call",
116
+ });
117
+ if (!result.ok) return { block: true, blockReason: blockedReason(result.message) };
118
+ return mapBeforeToolVerdict(result.verdict, payload, ctx, retryGate);
119
+ },
120
+ HOOK_OPTIONS,
121
+ );
122
+
123
+ // before_agent_run → UserPromptSubmit. Deny: return {outcome:"block", reason}.
124
+ api.on(
125
+ "before_agent_run",
126
+ async (payload, ctx) => {
127
+ const p = payload || {};
128
+ workspace.remember(payload, ctx);
129
+ const result = await ask("before_agent_run", {
130
+ ...baseMeta(payload, ctx, api.config, workspace),
131
+ prompt: p.prompt,
132
+ hook_event_name: "before_agent_run",
133
+ });
134
+ if (!result.ok) return { outcome: "block", reason: blockedReason(result.message) };
135
+ if (result.verdict.permission === "deny") {
136
+ return { outcome: "block", reason: result.verdict.reason || "Blocked by failproofai" };
137
+ }
138
+ return undefined;
139
+ },
140
+ HOOK_OPTIONS,
141
+ );
142
+
143
+ // before_agent_finalize → Stop. The real turn-end gate: a deny becomes a
144
+ // revise so the agent runs another pass. The evaluator supplies the
145
+ // MANDATORY ACTION wording; the payload's stop_hook_active guards the
146
+ // require-*-before-stop builtins against infinite loops.
147
+ api.on(
148
+ "before_agent_finalize",
149
+ async (payload, ctx) => {
150
+ const result = await ask("before_agent_finalize", {
151
+ ...baseMeta(payload, ctx, api.config, workspace),
152
+ hook_event_name: "before_agent_finalize",
153
+ });
154
+ if (result.ok && result.verdict.permission === "deny") {
155
+ return { action: "revise", reason: result.verdict.reason || "Action required by failproofai" };
156
+ }
157
+ return undefined;
158
+ },
159
+ HOOK_OPTIONS,
160
+ );
161
+
162
+ // Observation hooks — await so activity ordering is stable, ignore verdict.
163
+ // after_tool_call → PostToolUse; session_start/end → SessionStart/End;
164
+ // subagent_ended → SubagentStop (obs only); before_compaction → PreCompact.
165
+ for (const event of OBSERVATION_EVENTS) {
166
+ api.on(
167
+ event,
168
+ async (payload, ctx) => {
169
+ const p = payload || {};
170
+ await ask(event, {
171
+ ...baseMeta(payload, ctx, api.config, workspace),
172
+ tool_name: p.toolName,
173
+ tool_input: p.params,
174
+ tool_response: p.result,
175
+ reason: p.reason,
176
+ hook_event_name: event,
177
+ });
178
+ if (event === "session_end") {
179
+ retryGate.clear(payload, ctx);
180
+ workspace.clear(payload, ctx);
181
+ }
182
+ return undefined;
183
+ },
184
+ HOOK_OPTIONS,
185
+ );
186
+ }
187
+ }