failproofai 1.0.7 → 1.0.8-beta.0

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 (271) 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 +8 -7
  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 +9 -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 -10
  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 +8 -7
  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 +6 -6
  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 +7 -6
  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 +52 -8
  63. package/.next/standalone/.next/server/app/settings/page.js +12 -7
  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]__1msfs-h._.js → [externals]__19_pzeq._.js} +1 -1
  67. package/.next/standalone/.next/server/chunks/{[externals]__1_bftcl._.js → [externals]__20kzpkf._.js} +1 -1
  68. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0o07qi9._.js +1 -1
  69. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1ttrwnd._.js +22 -0
  70. package/.next/standalone/.next/server/chunks/_09dz7xv._.js +21 -21
  71. package/.next/standalone/.next/server/chunks/_0tovk6q._.js +1 -1
  72. package/.next/standalone/.next/server/chunks/_0trp3yc._.js +1 -1
  73. package/.next/standalone/.next/server/chunks/_1ek68ln._.js +16 -16
  74. package/.next/standalone/.next/server/chunks/{_1c3k-8x._.js → _1q5i8mb._.js} +2 -2
  75. package/.next/standalone/.next/server/chunks/lib_16xa545._.js +3 -0
  76. package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
  77. package/.next/standalone/.next/server/chunks/src_hooks_1aveq0u._.js +5 -0
  78. package/.next/standalone/.next/server/chunks/src_hooks_1eem5a7._.js +3 -0
  79. package/.next/standalone/.next/server/chunks/src_hooks_custom-hooks-loader_ts_0lnb3n3._.js +4 -2
  80. package/.next/standalone/.next/server/chunks/ssr/[externals]__0ohnuzs._.js +3 -0
  81. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__01bmjsj._.js +3 -0
  82. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__04usis8._.js +4 -0
  83. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__056wjo4._.js +4 -0
  84. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__059yza8._.js +3 -0
  85. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__06pflha._.js +3 -0
  86. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0eip4_k._.js +22 -0
  87. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0n0xg95._.js +4 -0
  88. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0qcb0mg._.js +3 -0
  89. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0rwtwpm._.js +4 -0
  90. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0yrsbd_._.js +3 -0
  91. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__11mayhe._.js +4 -0
  92. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__12e7nhs._.js +3 -0
  93. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__13d-wb6._.js +3 -0
  94. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0bd3mje._.js → [root-of-the-server]__14o3ek1._.js} +2 -2
  95. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__15578wp._.js +4 -0
  96. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__19evfi8._.js +3 -0
  97. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1dinjii._.js +3 -0
  98. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1m_svbe._.js +4 -0
  99. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0cxe_2_._.js → [root-of-the-server]__1mf3zp6._.js} +3 -3
  100. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1pprgri._.js +4 -0
  101. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1q4p5b8._.js +4 -0
  102. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1qiz0e4._.js +3 -0
  103. package/.next/standalone/.next/server/chunks/ssr/_042cgl1._.js +3 -0
  104. package/.next/standalone/.next/server/chunks/ssr/_08x1r5t._.js +1 -1
  105. package/.next/standalone/.next/server/chunks/ssr/_0bqoto4._.js +3 -0
  106. package/.next/standalone/.next/server/chunks/ssr/{_166t73i._.js → _0o4xkpl._.js} +1 -1
  107. package/.next/standalone/.next/server/chunks/ssr/_0uyu3jf._.js +3 -0
  108. package/.next/standalone/.next/server/chunks/ssr/{_1-i_gzc._.js → _1-7sqrb._.js} +2 -2
  109. package/.next/standalone/.next/server/chunks/ssr/{_1es2j7i._.js → _1gb0ifp._.js} +5 -5
  110. package/.next/standalone/.next/server/chunks/ssr/{_1_qswah._.js → _1q46vxx._.js} +2 -2
  111. package/.next/standalone/.next/server/chunks/ssr/_1zopuov._.js +1 -1
  112. package/.next/standalone/.next/server/chunks/ssr/_next-internal_server_app_policies_page_actions_1sp2-yo.js +13 -13
  113. package/.next/standalone/.next/server/chunks/ssr/app_actions_get-scheduled-audit_ts_0ei9sni._.js +3 -0
  114. package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +1 -1
  115. package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
  116. package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +2 -2
  117. package/.next/standalone/.next/server/chunks/ssr/app_settings_02tf1h4._.js +3 -0
  118. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_0aiy-os._.js +1 -1
  119. package/.next/standalone/.next/server/chunks/ssr/{node_modules_next_dist_0drixxt._.js → node_modules_next_dist_0w6mzq5._.js} +4 -4
  120. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_18_d8l1._.js +151 -0
  121. package/.next/standalone/.next/server/chunks/ssr/src_hooks_0-q0umm._.js +3 -0
  122. package/.next/standalone/.next/server/chunks/ssr/src_hooks_06kzv9d._.js +12 -0
  123. package/.next/standalone/.next/server/chunks/ssr/src_hooks_0g194sy._.js +3 -0
  124. package/.next/standalone/.next/server/chunks/ssr/src_hooks_1cv9_c4._.js +4 -2
  125. package/.next/standalone/.next/server/chunks/ssr/src_hooks_1kx9e0d._.js +3 -0
  126. package/.next/standalone/.next/server/chunks/ssr/src_hooks_effective-reviewers_ts_1h4wtvo._.js +5 -0
  127. package/.next/standalone/.next/server/chunks/ssr/src_hooks_fp-config_ts_04t589g._.js +1 -1
  128. package/.next/standalone/.next/server/chunks/ssr/src_hooks_fp-home_ts_0je3xkv._.js +1 -1
  129. package/.next/standalone/.next/server/chunks/ssr/src_hooks_pack-cli_ts_0t7me65._.js +1 -1
  130. package/.next/standalone/.next/server/chunks/ssr/src_hooks_semantic_pack-policies_ts_0gh_bu_._.js +3 -0
  131. package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
  132. package/.next/standalone/.next/server/pages/404.html +1 -1
  133. package/.next/standalone/.next/server/pages/500.html +1 -1
  134. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  135. package/.next/standalone/.next/server/server-reference-manifest.json +67 -23
  136. package/.next/standalone/.next/static/chunks/078gnymqoh3r4.js +1 -0
  137. package/.next/standalone/.next/static/chunks/{2mdh397ghgnvv.js → 0ahfwmbkpgfw4.js} +1 -1
  138. package/.next/standalone/.next/static/chunks/0bhidk90e-07f.css +2 -0
  139. package/.next/standalone/.next/static/chunks/1bu2-nv59ed6i.js +1 -0
  140. package/.next/standalone/.next/static/chunks/{0o6qlkgubtoex.js → 1v_tp3hm8wyhe.js} +1 -1
  141. package/.next/standalone/.next/static/chunks/2a405_e1o26ol.js +1 -0
  142. package/.next/standalone/.next/static/chunks/2qv4hshejedtx.css +1 -0
  143. package/.next/standalone/.next/static/chunks/2vo7qbdbvnc0o.js +69 -0
  144. package/.next/standalone/.next/static/chunks/{13i7-9is-vhys.js → 2z7i-yg59w4pn.js} +1 -1
  145. package/.next/standalone/.next/static/chunks/36uhh9el_oz8e.js +1 -0
  146. package/.next/standalone/.next/static/chunks/{0__8a7m868fvf.js → 3bgot5v6f6s3c.js} +1 -1
  147. package/.next/standalone/.next/static/chunks/3o3f1ibfci0p7.js +6 -0
  148. package/.next/standalone/PROBE-FOLLOWUP.md +186 -0
  149. package/.next/standalone/app/actions/get-jev-config.ts +604 -0
  150. package/.next/standalone/app/actions/pack-actions.ts +12 -0
  151. package/.next/standalone/app/actions/update-jev-config.ts +569 -0
  152. package/.next/standalone/app/components/jev-notices.tsx +96 -0
  153. package/.next/standalone/app/policies/hooks-client.tsx +14 -3
  154. package/.next/standalone/app/settings/jev-panel.tsx +630 -0
  155. package/.next/standalone/app/settings/page.tsx +20 -1
  156. package/.next/standalone/app/settings/settings-client.tsx +27 -1
  157. package/.next/standalone/app/settings/settings.css +79 -0
  158. package/.next/standalone/fp-cloud-cli/CHANGELOG.md +22 -4
  159. package/.next/standalone/fp-cloud-cli/fp_cli/client.py +14 -1
  160. package/.next/standalone/fp-cloud-cli/fp_cli/commands/keys_cmds.py +17 -3
  161. package/.next/standalone/fp-cloud-cli/fp_cli/commands/policies_cmds.py +3 -0
  162. package/.next/standalone/fp-cloud-cli/fp_cli/permissions.py +22 -0
  163. package/.next/standalone/fp-cloud-cli/fp_cli/policy_check.py +169 -0
  164. package/.next/standalone/fp-cloud-cli/skill/references/commands.md +1 -1
  165. package/.next/standalone/fp-cloud-cli/tests/test_keys_queries.py +65 -0
  166. package/.next/standalone/fp-cloud-cli/tests/test_policy_check.py +61 -0
  167. package/.next/standalone/package.json +10 -10
  168. package/.next/standalone/sdk/python/CHANGELOG.md +7 -0
  169. package/.next/standalone/sdk/python/failproofai_sdk/_version.py +1 -1
  170. package/.next/standalone/sdk/typescript/scripts/release.mjs +30 -0
  171. package/.next/standalone/server.js +1 -1
  172. package/README.md +3 -2
  173. package/bin/failproofai.mjs +148 -4
  174. package/dist/cli.mjs +18537 -9492
  175. package/dist/index.js +19 -1
  176. package/dist/worker.mjs +10421 -3770
  177. package/package.json +10 -10
  178. package/pi-extension/index.ts +11 -0
  179. package/scripts/build-policy-pack.mjs +53 -2
  180. package/src/audit/features.ts +3 -2
  181. package/src/hooks/builtin-policies.ts +195 -8
  182. package/src/hooks/cloud-connection.ts +190 -1
  183. package/src/hooks/cloud-enrollment-cli.ts +57 -8
  184. package/src/hooks/cloud-introspect.ts +6 -0
  185. package/src/hooks/cloud-managed-policies.ts +22 -0
  186. package/src/hooks/configure-wizard.ts +26 -6
  187. package/src/hooks/custom-hooks-loader.ts +98 -10
  188. package/src/hooks/custom-hooks-registry.ts +45 -1
  189. package/src/hooks/effective-reviewers.ts +243 -0
  190. package/src/hooks/first-run-gate.ts +5 -0
  191. package/src/hooks/flush-cli.ts +35 -8
  192. package/src/hooks/fp-config.ts +266 -1
  193. package/src/hooks/fp-home.ts +23 -0
  194. package/src/hooks/fp-reset.ts +22 -4
  195. package/src/hooks/handler.ts +303 -7
  196. package/src/hooks/hook-activity-store.ts +118 -6
  197. package/src/hooks/hook-telemetry.ts +41 -0
  198. package/src/hooks/jev-activity.ts +385 -0
  199. package/src/hooks/jev-cli.ts +2172 -0
  200. package/src/hooks/jev-cloud-connection.ts +392 -0
  201. package/src/hooks/loader-utils.ts +6 -0
  202. package/src/hooks/manager.ts +45 -7
  203. package/src/hooks/pack-cli.ts +568 -37
  204. package/src/hooks/pack-failclosed.ts +3 -0
  205. package/src/hooks/pack-manifest.ts +489 -7
  206. package/src/hooks/pack-store.ts +194 -11
  207. package/src/hooks/policy-authority.ts +386 -0
  208. package/src/hooks/policy-catalog.ts +206 -0
  209. package/src/hooks/policy-evaluator.ts +963 -796
  210. package/src/hooks/policy-registry.ts +27 -1
  211. package/src/hooks/policy-reviewability.ts +258 -0
  212. package/src/hooks/policy-types.ts +128 -0
  213. package/src/hooks/semantic/combine.ts +581 -0
  214. package/src/hooks/semantic/compile.ts +176 -0
  215. package/src/hooks/semantic/decide.ts +408 -0
  216. package/src/hooks/semantic/envelope.ts +1255 -0
  217. package/src/hooks/semantic/evaluator.ts +556 -0
  218. package/src/hooks/semantic/facts.ts +298 -0
  219. package/src/hooks/semantic/intent.ts +1190 -0
  220. package/src/hooks/semantic/jev-client.ts +1155 -0
  221. package/src/hooks/semantic/jev-config.ts +1142 -0
  222. package/src/hooks/semantic/jev-review.ts +389 -0
  223. package/src/hooks/semantic/jev-stats.ts +289 -0
  224. package/src/hooks/semantic/jev-throttle.ts +427 -0
  225. package/src/hooks/semantic/pack-policies.ts +294 -0
  226. package/src/hooks/semantic/policies.ts +597 -0
  227. package/src/hooks/semantic/precondition-names.ts +60 -0
  228. package/src/hooks/semantic/preconditions.ts +58 -0
  229. package/src/hooks/semantic/redact.ts +2937 -0
  230. package/src/hooks/semantic/session-root.ts +116 -0
  231. package/src/hooks/semantic/types.ts +156 -0
  232. package/src/hooks/semver-precedence.ts +128 -0
  233. package/src/hooks/tui.ts +4 -0
  234. package/src/hooks/types.ts +1 -1
  235. package/src/hooks/worker-server.ts +121 -27
  236. package/src/index.ts +6 -0
  237. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0cuho4x._.js +0 -3
  238. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1_r2rbg._.js +0 -24
  239. package/.next/standalone/.next/server/chunks/src_hooks_0iu54mz._.js +0 -3
  240. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0-_ki57._.js +0 -4
  241. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__013jr2b._.js +0 -4
  242. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__01wy8d-._.js +0 -4
  243. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__02npjtd._.js +0 -4
  244. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0cg-bgc._.js +0 -5
  245. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0cpu_mj._.js +0 -3
  246. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0da85px._.js +0 -4
  247. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ftmoxc._.js +0 -4
  248. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0p-5p8u._.js +0 -4
  249. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0u3w0ll._.js +0 -22
  250. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__17d_ffl._.js +0 -3
  251. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__19d9tgz._.js +0 -5
  252. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1ctpynv._.js +0 -3
  253. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1jiwfsj._.js +0 -3
  254. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1p2otjt._.js +0 -4
  255. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1phc187._.js +0 -3
  256. package/.next/standalone/.next/server/chunks/ssr/_06imw3p._.js +0 -5
  257. package/.next/standalone/.next/server/chunks/ssr/_0h_douw._.js +0 -3
  258. package/.next/standalone/.next/server/chunks/ssr/_1u8-lu2._.js +0 -3
  259. package/.next/standalone/.next/server/chunks/ssr/app_settings_settings-client_tsx_20lq-mq._.js +0 -3
  260. package/.next/standalone/.next/server/chunks/ssr/src_hooks_builtin-policies_ts_09j2ndl._.js +0 -3
  261. package/.next/standalone/.next/static/chunks/094xgi4owxaqf.js +0 -1
  262. package/.next/standalone/.next/static/chunks/1rz20_pz828f3.js +0 -6
  263. package/.next/standalone/.next/static/chunks/2k9f4tyv04809.css +0 -1
  264. package/.next/standalone/.next/static/chunks/2klitrtzpaoe0.js +0 -1
  265. package/.next/standalone/.next/static/chunks/2rshywgeqsyzk.css +0 -2
  266. package/.next/standalone/.next/static/chunks/3pzx4chkhko9k.js +0 -1
  267. package/.next/standalone/.next/static/chunks/3rh5o7e16irrm.js +0 -69
  268. package/.next/standalone/.next/static/chunks/43ufqrz8qo3h-.js +0 -1
  269. /package/.next/standalone/.next/static/{PgeWCHmyVbjRznv2VO7KF → O_b5R1axf5cb4NxIXq2kS}/_buildManifest.js +0 -0
  270. /package/.next/standalone/.next/static/{PgeWCHmyVbjRznv2VO7KF → O_b5R1axf5cb4NxIXq2kS}/_clientMiddlewareManifest.js +0 -0
  271. /package/.next/standalone/.next/static/{PgeWCHmyVbjRznv2VO7KF → O_b5R1axf5cb4NxIXq2kS}/_ssgManifest.js +0 -0
@@ -0,0 +1,427 @@
1
+ /**
2
+ * Cache and rate limit in front of a Jev transport, so a burst of tool calls
3
+ * stays under the provider's limit instead of degrading silently.
4
+ *
5
+ * `throttleTransport(t, opts?)` returns a transport with the same contract as
6
+ * `t`. It adds two things and nothing else:
7
+ *
8
+ * - **An LRU cache** keyed by the SHA-256 of the full request (model, state
9
+ * and questions, byte for byte as serialized, plus an optional `scope`).
10
+ * The request is everything Jev sees — no clock, no randomness — so an
11
+ * identical request is an identical question, and its answer is reused for
12
+ * a short TTL. The TTL runs from when the answer was fetched; a hit never
13
+ * extends it. Only answers the evaluator accepts are stored (`readAnswers`:
14
+ * a probability in [0, 1] for every question asked, from a model it
15
+ * accepts), bounded by entry count and by size, and
16
+ * every hit hands back a fresh copy, so a caller mutating its response can
17
+ * never change what the next caller gets. A side effect worth having: within
18
+ * the TTL, retrying a denied call gets the same answer rather than a fresh
19
+ * draw from a model that is ~98% run-to-run stable.
20
+ * - **A token bucket** (default 5 req/s, burst 5; see `ThrottleOptions` for
21
+ * what those bound) on the calls that actually go upstream; cache hits are
22
+ * free. Over budget, it throws
23
+ * `JevError("rate-limited")` at once, so the evaluator degrades and the
24
+ * caller falls back to the regex result with a recorded reason — visibly,
25
+ * not silently. `maxWaitMs` lets a call wait briefly for the next token
26
+ * instead. A provider 429 empties the bucket as of when the 429 arrived
27
+ * (however long that round-trip took), so the calls right behind it fall
28
+ * back locally instead of spending more requests on a full window.
29
+ *
30
+ * It never throws on its own except for those two cases: an over-budget call,
31
+ * and a signal that is already aborted (or aborts while waiting for a token).
32
+ * Every error from the wrapped transport is rethrown unchanged — the same
33
+ * object — and never cached. Internal failures (a request that cannot be
34
+ * serialized, say) skip the cache; they never fail the call.
35
+ *
36
+ * **State is module-level.** The daemon's warm worker (`worker-server.ts`) is
37
+ * the only evaluator on a configured machine and lives for hours, so the
38
+ * process is the cache and the bucket is the process's upstream budget: a
39
+ * caller may build a new wrapper per hook event and every wrapper shares both.
40
+ * The worker serializes the registry part of `evaluateHookEvent` but hands the
41
+ * queue back while a two-tier review waits on Jev (`worker-server.ts`
42
+ * `release`), so several Jev calls can be in flight at once. The cache fills
43
+ * only when an answer arrives: identical requests in flight together each
44
+ * miss, each take a token and each go upstream (and are billed).
45
+ * ponytail: no in-flight de-duplication; add a single-flight map keyed by the
46
+ * digest if duplicate spend shows up (the joiner's abort must not cancel the
47
+ * leader, and a leader's own abort must not fail the joiner).
48
+ *
49
+ * **No on-disk cache**, deliberately. It would only help the one-shot
50
+ * in-process path, which on a configured machine does not exist (CLAUDE.md,
51
+ * "Enforcement routes through the daemon": only this repo's dogfood configs
52
+ * and not-yet-set-up machines evaluate in-process). And it would be a
53
+ * poisoning surface: every file under `~/.failproofai` is writable by the same
54
+ * user the agent runs as, and the request format is open source, so the agent
55
+ * being judged could compute the digest of the call it is about to make and
56
+ * pre-write an all-clear answer — clearing reviewable denies without Jev ever
57
+ * being asked. The worker's memory has no such surface. Signing the entries
58
+ * would not help: any key the hook can read, the agent can read too.
59
+ *
60
+ * **What a caller wiring this in must do** (T3), because the module cannot see
61
+ * any of it from here:
62
+ *
63
+ * - **Pass `scope`** naming where answers come from, e.g.
64
+ * `` `${route.via}|${route.endpoint}|${route.model}` `` from T1's route. The
65
+ * request alone does not say which provider, endpoint or model answered — a
66
+ * transport may send a model other than `request.model` — and the cache is
67
+ * process-wide, so without a scope a `jev.json` change in a long-lived
68
+ * worker serves the old provider's answers under the new one until they
69
+ * expire. The scope is only ever hashed into the key, never stored, so an
70
+ * endpoint carrying a credential in its query string is safe to pass. It
71
+ * cannot default to anything better: the transport's identity changes on
72
+ * every hook event (a new wrapper each time), which would turn the cache off.
73
+ * - **A hit is the original answer, `usage` included**, returned in ~0 ms.
74
+ * Anything that sums tokens or cost, or takes latency percentiles, must tell
75
+ * hits apart. `evaluateSemantic` never exposes the response, so wrap the
76
+ * throttled transport and ask {@link isCachedJevResponse}:
77
+ * `async (r, s) => { const res = await throttled(r, s); cached = isCachedJevResponse(res); return res; }`
78
+ * then record `inputTokens: null` (and flag the latency) when `cached`.
79
+ * - **Tests** that route through a throttled transport share this module's
80
+ * state across every file bun runs in one process: call
81
+ * `resetJevThrottle()` in `beforeEach`, or pass
82
+ * `{ cacheTtlMs: 0, ratePerSec: 1e6 }` where caching and limiting are not
83
+ * what is under test.
84
+ */
85
+ import { createHash } from "node:crypto";
86
+ import { JevError, readAnswers, type JevTransport } from "./jev-client";
87
+ import type { JevRequest, JevResponse } from "./types";
88
+
89
+ export interface ThrottleOptions {
90
+ /**
91
+ * Sustained upstream requests per second. Default 5, from the one Cloudflare
92
+ * figure there is: a replay against one key sustained ~6 calls/s before
93
+ * HTTP 429s took over (measured over the replay as a whole, not over any
94
+ * one-second window). Cloudflare publishes its Workers AI limits per
95
+ * minute (300/min for text generation by default, i.e. 5/s); whether
96
+ * `typesafe/jev` is under that default, and so which window a burst runs
97
+ * into, is unconfirmed (R4 or a live check). TypeSafe documents 1,200/min
98
+ * (20/s). Must be a positive finite number, else the default.
99
+ */
100
+ ratePerSec?: number;
101
+ /**
102
+ * Bucket capacity — how many calls may go out back to back. Default: one
103
+ * second's worth (`ratePerSec`, at least 1), so a handful of parallel tool
104
+ * calls after a pause are all judged. A bucket admits at most
105
+ * `burst + ratePerSec` calls in any one-second window (10 with the
106
+ * defaults) and `burst + 60 × ratePerSec` in any minute (305). Against a
107
+ * per-minute limit that is the sustained rate plus one burst; against a
108
+ * strict per-second one it could spend a few calls a provider refuses, and
109
+ * the first 429 then empties the bucket, so the loss stays at a few calls
110
+ * per burst. Pass `burst: 1` to cap any one second at `1 + ratePerSec`.
111
+ */
112
+ burst?: number;
113
+ /** How long a call may wait for the next token before it is rate-limited. Default 0: over budget fails at once. */
114
+ maxWaitMs?: number;
115
+ /** How long an answer is reused, from when it was fetched. Default 5 minutes. 0 disables the cache. */
116
+ cacheTtlMs?: number;
117
+ /** Most answers kept. Default 512. 0 disables the cache. */
118
+ cacheMaxEntries?: number;
119
+ /** Most characters of serialized answers kept (≈ bytes; answers are ASCII JSON). Default 4 MiB. 0 disables the cache. */
120
+ cacheMaxBytes?: number;
121
+ /**
122
+ * Mixed into the cache key (hashed, never stored): where the answers came
123
+ * from — provider, endpoint and the model actually sent, e.g.
124
+ * `` `${via}|${endpoint}|${model}` ``. Answers cached under one scope are
125
+ * never served under another. Default `""`, which every unscoped wrapper in
126
+ * the process shares: a real caller should always pass one (see the module
127
+ * doc).
128
+ */
129
+ scope?: string;
130
+ /** Monotonic clock in milliseconds. For tests; defaults to `performance.now()`. */
131
+ now?: () => number;
132
+ }
133
+
134
+ export const DEFAULT_THROTTLE = Object.freeze({
135
+ ratePerSec: 5,
136
+ maxWaitMs: 0,
137
+ cacheTtlMs: 5 * 60_000,
138
+ cacheMaxEntries: 512,
139
+ cacheMaxBytes: 4 * 1024 * 1024,
140
+ });
141
+
142
+ /** One answer bigger than this is never cached. A full request's answers are a few KB. */
143
+ export const MAX_CACHED_ENTRY_CHARS = 64 * 1024;
144
+
145
+ interface ResolvedOptions {
146
+ ratePerSec: number;
147
+ burst: number;
148
+ maxWaitMs: number;
149
+ cacheEnabled: boolean;
150
+ cacheTtlMs: number;
151
+ cacheMaxEntries: number;
152
+ cacheMaxBytes: number;
153
+ scope: string;
154
+ now: () => number;
155
+ }
156
+
157
+ const positive = (v: unknown, fallback: number): number =>
158
+ typeof v === "number" && Number.isFinite(v) && v > 0 ? v : fallback;
159
+ const nonNegative = (v: unknown, fallback: number): number =>
160
+ typeof v === "number" && Number.isFinite(v) && v >= 0 ? v : fallback;
161
+
162
+ function resolveOptions(opts: ThrottleOptions): ResolvedOptions {
163
+ const ratePerSec = positive(opts.ratePerSec, DEFAULT_THROTTLE.ratePerSec);
164
+ const cacheTtlMs = nonNegative(opts.cacheTtlMs, DEFAULT_THROTTLE.cacheTtlMs);
165
+ const cacheMaxEntries = Math.floor(nonNegative(opts.cacheMaxEntries, DEFAULT_THROTTLE.cacheMaxEntries));
166
+ const cacheMaxBytes = nonNegative(opts.cacheMaxBytes, DEFAULT_THROTTLE.cacheMaxBytes);
167
+ return {
168
+ ratePerSec,
169
+ burst: Math.max(1, positive(opts.burst, ratePerSec)),
170
+ maxWaitMs: nonNegative(opts.maxWaitMs, DEFAULT_THROTTLE.maxWaitMs),
171
+ cacheEnabled: cacheTtlMs > 0 && cacheMaxEntries > 0 && cacheMaxBytes > 0,
172
+ cacheTtlMs,
173
+ cacheMaxEntries,
174
+ cacheMaxBytes,
175
+ scope: typeof opts.scope === "string" ? opts.scope : "",
176
+ now: typeof opts.now === "function" ? opts.now : () => performance.now(),
177
+ };
178
+ }
179
+
180
+ // ── Module state (shared by every wrapper in the process) ────────────────────
181
+
182
+ interface Entry {
183
+ body: string;
184
+ expiresAt: number;
185
+ size: number;
186
+ }
187
+
188
+ const cache = new Map<string, Entry>();
189
+ let cacheChars = 0;
190
+ /** Tokens may go negative: a waiting call reserves the next one. NaN = not yet used. */
191
+ const bucket = { tokens: Number.NaN, last: Number.NaN };
192
+ const counters = { hits: 0, misses: 0, rateLimited: 0, upstreamErrors: 0, evictions: 0 };
193
+ /** Responses this module handed out from the cache; see {@link isCachedJevResponse}. */
194
+ let servedFromCache = new WeakSet<object>();
195
+
196
+ export interface JevThrottleStats {
197
+ /** Answers served from the cache. */
198
+ hits: number;
199
+ /** Lookups that found nothing (cache enabled only). */
200
+ misses: number;
201
+ /** Calls refused locally because the bucket was empty. */
202
+ rateLimited: number;
203
+ /** Errors the wrapped transport threw (passed through). */
204
+ upstreamErrors: number;
205
+ /** Entries dropped to stay within the size bounds (not counting expiry). */
206
+ evictions: number;
207
+ /** Answers currently cached. */
208
+ entries: number;
209
+ /** Characters currently cached. */
210
+ chars: number;
211
+ }
212
+
213
+ export function jevThrottleStats(): JevThrottleStats {
214
+ return { ...counters, entries: cache.size, chars: cacheChars };
215
+ }
216
+
217
+ /** Empties the cache and the bucket and zeroes the counters. */
218
+ export function resetJevThrottle(): void {
219
+ cache.clear();
220
+ cacheChars = 0;
221
+ bucket.tokens = Number.NaN;
222
+ bucket.last = Number.NaN;
223
+ counters.hits = 0;
224
+ counters.misses = 0;
225
+ counters.rateLimited = 0;
226
+ counters.upstreamErrors = 0;
227
+ counters.evictions = 0;
228
+ servedFromCache = new WeakSet<object>();
229
+ }
230
+
231
+ /**
232
+ * True when `response` came from the cache rather than the network — for a
233
+ * caller that wants to record it. A hit costs nothing and takes ~0 ms, but it
234
+ * still carries the original answer's `usage`: token and cost totals must
235
+ * skip it. Through `evaluateSemantic`, wrap the throttled transport to see
236
+ * the response (module doc).
237
+ */
238
+ export function isCachedJevResponse(response: unknown): boolean {
239
+ return typeof response === "object" && response !== null && servedFromCache.has(response);
240
+ }
241
+
242
+ // ── Cache ────────────────────────────────────────────────────────────────────
243
+
244
+ /**
245
+ * The cache key: SHA-256 over the scope and the full request exactly as
246
+ * serialized. Exported so a replay (R4) can measure hit rates with the same
247
+ * key the worker uses. Throws if the request cannot be serialized.
248
+ */
249
+ export function jevRequestDigest(request: JevRequest, scope = ""): string {
250
+ return createHash("sha256").update(scope).update("\0").update(JSON.stringify(request)).digest("hex");
251
+ }
252
+
253
+ function keyFor(cfg: ResolvedOptions, request: JevRequest): string | null {
254
+ if (!cfg.cacheEnabled) return null;
255
+ try {
256
+ return jevRequestDigest(request, cfg.scope);
257
+ } catch {
258
+ return null; // Unserializable: no cache for this call, never an error.
259
+ }
260
+ }
261
+
262
+ function dropEntry(key: string, entry: Entry): void {
263
+ cache.delete(key);
264
+ cacheChars -= entry.size;
265
+ }
266
+
267
+ function cacheGet(key: string, now: number): JevResponse | null {
268
+ const entry = cache.get(key);
269
+ if (!entry) return null;
270
+ if (now >= entry.expiresAt) {
271
+ dropEntry(key, entry);
272
+ return null;
273
+ }
274
+ // Most recently used goes last; eviction takes from the front.
275
+ cache.delete(key);
276
+ cache.set(key, entry);
277
+ try {
278
+ return JSON.parse(entry.body) as JevResponse;
279
+ } catch {
280
+ dropEntry(key, entry);
281
+ return null;
282
+ }
283
+ }
284
+
285
+ /**
286
+ * Only an answer the evaluator could use is worth keeping. The rule is the
287
+ * evaluator's own (`readAnswers`: a probability in [0, 1] for every question,
288
+ * and a model it accepts), not a copy of it, so the two cannot drift apart: a
289
+ * wrong-model answer the evaluator rejects is never pinned for the TTL.
290
+ */
291
+ function isUsableAnswer(request: JevRequest, response: JevResponse): boolean {
292
+ try {
293
+ readAnswers(request, response);
294
+ return true;
295
+ } catch {
296
+ return false;
297
+ }
298
+ }
299
+
300
+ function cachePut(cfg: ResolvedOptions, key: string, request: JevRequest, response: JevResponse, now: number): void {
301
+ if (!isUsableAnswer(request, response)) return;
302
+ let body: string;
303
+ try {
304
+ body = JSON.stringify(response);
305
+ } catch {
306
+ return;
307
+ }
308
+ const size = key.length + body.length;
309
+ if (size > MAX_CACHED_ENTRY_CHARS || size > cfg.cacheMaxBytes) return;
310
+ const prev = cache.get(key);
311
+ if (prev) dropEntry(key, prev);
312
+ cache.set(key, { body, expiresAt: now + cfg.cacheTtlMs, size });
313
+ cacheChars += size;
314
+ for (const [k, e] of cache) {
315
+ const expired = now >= e.expiresAt;
316
+ if (!expired && cache.size <= cfg.cacheMaxEntries && cacheChars <= cfg.cacheMaxBytes) break;
317
+ dropEntry(k, e);
318
+ if (!expired) counters.evictions++;
319
+ }
320
+ }
321
+
322
+ // ── Token bucket ─────────────────────────────────────────────────────────────
323
+
324
+ /** Error codes meaning the provider itself refused for rate: `http-429` from the HTTP layer, or a transport's own `rate-limited`. */
325
+ const PROVIDER_WINDOW_FULL = new Set(["http-429", "rate-limited"]);
326
+
327
+ function refill(cfg: ResolvedOptions, now: number): void {
328
+ if (!Number.isFinite(bucket.last) || !Number.isFinite(bucket.tokens)) {
329
+ bucket.tokens = cfg.burst;
330
+ bucket.last = now;
331
+ return;
332
+ }
333
+ const elapsed = Math.max(0, now - bucket.last);
334
+ bucket.last = now;
335
+ bucket.tokens = Math.min(cfg.burst, bucket.tokens + (elapsed * cfg.ratePerSec) / 1000);
336
+ }
337
+
338
+ function abortedError(signal: AbortSignal): JevError {
339
+ const name = (signal.reason as { name?: unknown } | undefined)?.name;
340
+ return name === "TimeoutError"
341
+ ? new JevError("timeout", "Jev did not answer in time")
342
+ : new JevError("aborted", "the Jev request was aborted");
343
+ }
344
+
345
+ function sleep(ms: number, signal: AbortSignal | undefined): Promise<void> {
346
+ return new Promise<void>((resolve, reject) => {
347
+ const onAbort = () => {
348
+ clearTimeout(timer);
349
+ reject(abortedError(signal as AbortSignal));
350
+ };
351
+ const timer = setTimeout(() => {
352
+ signal?.removeEventListener("abort", onAbort);
353
+ resolve();
354
+ }, ms);
355
+ signal?.addEventListener("abort", onAbort, { once: true });
356
+ });
357
+ }
358
+
359
+ /** Takes one token, waiting up to `maxWaitMs` for it, or throws `rate-limited`. */
360
+ async function acquire(cfg: ResolvedOptions, signal: AbortSignal | undefined): Promise<void> {
361
+ refill(cfg, cfg.now());
362
+ bucket.tokens -= 1;
363
+ if (bucket.tokens >= 0) return;
364
+ const waitMs = (-bucket.tokens / cfg.ratePerSec) * 1000;
365
+ if (waitMs > cfg.maxWaitMs) {
366
+ bucket.tokens += 1;
367
+ counters.rateLimited++;
368
+ throw new JevError(
369
+ "rate-limited",
370
+ `local Jev budget of ${cfg.ratePerSec} request(s)/s is spent; next slot in ${Math.ceil(waitMs)} ms`,
371
+ );
372
+ }
373
+ try {
374
+ await sleep(waitMs, signal);
375
+ } catch (err) {
376
+ bucket.tokens += 1; // The reserved slot was never used.
377
+ throw err;
378
+ }
379
+ }
380
+
381
+ // ── The wrapper ──────────────────────────────────────────────────────────────
382
+
383
+ /**
384
+ * `t` behind the shared cache and token bucket. `opts` is read once, here;
385
+ * every call through the returned transport uses it.
386
+ */
387
+ export function throttleTransport(t: JevTransport, opts?: ThrottleOptions | null): JevTransport {
388
+ const cfg = resolveOptions(opts ?? {});
389
+ return async (request, signal) => {
390
+ // The type says a signal is always passed; a caller that omits one still gets no throw from here.
391
+ if (signal?.aborted) throw abortedError(signal);
392
+
393
+ const key = keyFor(cfg, request);
394
+ if (key !== null) {
395
+ const hit = cacheGet(key, cfg.now());
396
+ if (hit) {
397
+ counters.hits++;
398
+ servedFromCache.add(hit);
399
+ return hit;
400
+ }
401
+ counters.misses++;
402
+ }
403
+
404
+ await acquire(cfg, signal);
405
+
406
+ let response: JevResponse;
407
+ try {
408
+ response = await t(request, signal);
409
+ } catch (err) {
410
+ counters.upstreamErrors++;
411
+ // The provider's window is full: the calls right behind this one fall
412
+ // back locally until the bucket refills, rather than each spending a
413
+ // request to learn the same thing. Refill to now first: the bucket was
414
+ // last stamped when this call was admitted, so without it the next
415
+ // refill would credit the whole round-trip (hundreds of ms against a
416
+ // real provider, i.e. one or more tokens) and undo the emptying.
417
+ if (err instanceof JevError && PROVIDER_WINDOW_FULL.has(err.code)) {
418
+ refill(cfg, cfg.now());
419
+ bucket.tokens = Math.min(bucket.tokens, 0);
420
+ }
421
+ throw err;
422
+ }
423
+
424
+ if (key !== null) cachePut(cfg, key, request, response, cfg.now());
425
+ return response;
426
+ };
427
+ }