failproofai 1.0.11 → 1.0.12-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 (342) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/build-manifest.json +23 -23
  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/build-manifest.json +3 -3
  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 -2
  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 +3 -3
  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 +3 -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 +5 -6
  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 +24 -24
  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 +2 -2
  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 +4 -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 -7
  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 -7
  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 +5 -6
  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 +2 -2
  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 +3 -3
  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 +4 -4
  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 +3 -3
  52. package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
  53. package/.next/standalone/.next/server/app/page.js +2 -2
  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 +3 -3
  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 +7 -7
  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 +3 -3
  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 +7 -7
  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 +3 -3
  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 +8 -8
  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 +3 -3
  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 +3 -3
  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 +3 -3
  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 +10 -10
  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]__0qkp92tjfvw8r._.js → [externals]__0vt9i6fqinjne._.js} +1 -1
  83. package/.next/standalone/.next/server/chunks/[externals]__1x24dzcbbq6-g._.js +3 -0
  84. package/.next/standalone/.next/server/chunks/[root-of-the-server]__02vous7mpi2xm._.js +3 -0
  85. package/.next/standalone/.next/server/chunks/[root-of-the-server]__03i5o4a840guz._.js +3 -0
  86. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0__a_je8fsn65._.js +3 -0
  87. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0_hsnj_a2mvl_._.js +3 -0
  88. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__1izwqj_ij_9x_._.js → [root-of-the-server]__0f_4g-vazrvxv._.js} +1 -1
  89. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0l-oi4gdtmlo5._.js +3 -0
  90. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0swiyzbmvja2d._.js → [root-of-the-server]__0t9ufnv5hi2hq._.js} +5 -5
  91. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0wg9dk8x8bnau._.js +3 -0
  92. package/.next/standalone/.next/server/chunks/[root-of-the-server]__12kq3x-h7t7i1._.js +3 -0
  93. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1a5zkndjwlc13._.js +3 -0
  94. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__1r7kbfkiw2xmu._.js → [root-of-the-server]__1aaw59g-5uty7._.js} +12 -12
  95. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1hqpg6vgmfexv._.js +3 -0
  96. package/.next/standalone/.next/server/chunks/_09dz7xva4ce_2._.js +1 -1
  97. package/.next/standalone/.next/server/chunks/_0hf5q4xzyg40j._.js +1 -1
  98. package/.next/standalone/.next/server/chunks/_0tovk6q0miud6._.js +1 -1
  99. package/.next/standalone/.next/server/chunks/_0trp3ycqv17cl._.js +1 -1
  100. package/.next/standalone/.next/server/chunks/_19011-u44143j._.js +1 -1
  101. package/.next/standalone/.next/server/chunks/_1ek68lnh2daur._.js +1 -1
  102. package/.next/standalone/.next/server/chunks/_1vslkoe35wok6._.js +1 -1
  103. package/.next/standalone/.next/server/chunks/{_1ixl-kxq_ctsa._.js → _1y590mjzpkbos._.js} +2 -2
  104. package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4vkpxxu7._.js +1 -1
  105. package/.next/standalone/.next/server/chunks/src_hooks_0_em82s16zfym._.js +5 -0
  106. package/.next/standalone/.next/server/chunks/src_hooks_builtin-policies_ts_1yq5ybgx1v98e._.js +3 -0
  107. package/.next/standalone/.next/server/chunks/src_hooks_custom-hooks-loader_ts_0lnb3n3h94wnn._.js +1 -1
  108. package/.next/standalone/.next/server/chunks/src_hooks_daemon-client_ts_0il_yu1zc0291._.js +1 -1
  109. package/.next/standalone/.next/server/chunks/src_hooks_fp-home_ts_09kv0bn_4twyh._.js +1 -1
  110. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__01j58mdcdw0vn._.js +3 -0
  111. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0588st-tpiuia._.js +3 -0
  112. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__08ch3staq3ejw._.js +1 -1
  113. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0_a8z2ldp2v3n._.js +3 -0
  114. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0vcyntk4snf0f._.js → [root-of-the-server]__0b78b0j8iyv6l._.js} +1 -1
  115. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0bigvy9xmv2ka._.js +1 -1
  116. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ffu2-38y03ic._.js +3 -0
  117. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0g8b0kyorya-t._.js +3 -0
  118. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0h86bl2qf0k_o._.js +1 -1
  119. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1_xbg2kx30wp-._.js → [root-of-the-server]__0naevg4bcoh54._.js} +1 -1
  120. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0pia5h3p8re4c._.js +1 -1
  121. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__075uro8t92s0_._.js → [root-of-the-server]__0pwj2h2efe5f-._.js} +3 -3
  122. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0zn1d4blhd3bu._.js +3 -0
  123. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1-ey9fgesfbc0._.js +1 -1
  124. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__15usvs-ms-0hf._.js +1 -1
  125. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__16gb3_92zvk5x._.js +1 -1
  126. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__17r4zrwanhp6r._.js +3 -0
  127. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1avi2kypusyb_._.js +1 -1
  128. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1lnfv02ucky7m._.js +3 -0
  129. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1mc9-zlnh656_._.js +3 -0
  130. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1r7drlqli-ado._.js +1 -1
  131. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1s2-ck3k3rsoo._.js +3 -0
  132. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1l1qgu5mfapkh._.js → [root-of-the-server]__1vx7o8ukefudh._.js} +1 -1
  133. package/.next/standalone/.next/server/chunks/ssr/_0eoura3_9gjb-._.js +1 -1
  134. package/.next/standalone/.next/server/chunks/ssr/_0pedwblqdoh58._.js +1 -1
  135. package/.next/standalone/.next/server/chunks/ssr/_128ebxr83nk6g._.js +3 -0
  136. package/.next/standalone/.next/server/chunks/ssr/_1_ozgifqv1ssi._.js +1 -1
  137. package/.next/standalone/.next/server/chunks/ssr/{_1gb0ifpkowwub._.js → _1a3tubds7s7ow._.js} +10 -9
  138. package/.next/standalone/.next/server/chunks/ssr/_1djqs9i27e4kg._.js +1 -1
  139. package/.next/standalone/.next/server/chunks/ssr/_next-internal_server_app_policies_page_actions_1sp2-yo5_vm5f.js +2 -2
  140. package/.next/standalone/.next/server/chunks/ssr/app_actions_get-scheduled-audit_ts_0ei9snixb5fd-._.js +1 -1
  141. package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47q0xq5w._.js +1 -1
  142. package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x33jqb6._.js +1 -1
  143. package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpcz0uxur._.js +1 -1
  144. package/.next/standalone/.next/server/chunks/ssr/app_settings_02tf1h47jmhhd._.js +1 -1
  145. package/.next/standalone/.next/server/chunks/ssr/{node_modules_html-to-image_es_index_1f_ymmaonkksc.js → node_modules_html-to-image_es_index_1i8oid1gc7s1f.js} +1 -1
  146. package/.next/standalone/.next/server/chunks/ssr/package_json_[json]_cjs_013tntikdft59._.js +1 -1
  147. package/.next/standalone/.next/server/chunks/ssr/src_hooks_06kzv9ddabn3_._.js +1 -1
  148. package/.next/standalone/.next/server/chunks/ssr/src_hooks_0agdmptetetdt._.js +5 -0
  149. package/.next/standalone/.next/server/chunks/ssr/src_hooks_0mdwgjisv4fub._.js +5 -0
  150. package/.next/standalone/.next/server/chunks/ssr/src_hooks_1cv9_c4l1tzrm._.js +1 -1
  151. package/.next/standalone/.next/server/chunks/ssr/src_hooks_daemon-client_ts_0k41_i7jg6ndv._.js +1 -1
  152. package/.next/standalone/.next/server/chunks/ssr/src_hooks_pack-cli_ts_0t7me658zqmh_._.js +1 -1
  153. package/.next/standalone/.next/server/middleware-build-manifest.js +23 -23
  154. package/.next/standalone/.next/server/middleware.js +2 -2
  155. package/.next/standalone/.next/server/pages/404.html +1 -1
  156. package/.next/standalone/.next/server/pages/500.html +1 -1
  157. package/.next/standalone/.next/server/preview-props.json +3 -3
  158. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  159. package/.next/standalone/.next/server/server-reference-manifest.json +23 -23
  160. package/.next/standalone/.next/static/chunks/{0frxv4_m-m2u5.js → 063al_q720fkj.js} +1 -1
  161. package/.next/standalone/.next/static/chunks/0_zfad4co-t2z.js +1 -0
  162. package/.next/standalone/.next/static/chunks/0jutamwqz8pg5.js +1 -0
  163. package/.next/standalone/.next/static/chunks/114hbolvrv94e.js +1 -0
  164. package/.next/standalone/.next/static/chunks/{37stoe-_yd852.js → 18433qz-8njv3.js} +1 -1
  165. package/.next/standalone/.next/static/chunks/{1kwj8uqxuv85t.js → 1b32-afqacaen.js} +1 -1
  166. package/.next/standalone/.next/static/chunks/{44a7k2_62qc-9.js → 1p-hsi58i-6h0.js} +2 -2
  167. package/.next/standalone/.next/static/chunks/{302llgh97ce6w.js → 2-tf6_7u623kd.js} +1 -1
  168. package/.next/standalone/.next/static/chunks/{1_c0dc7zqj1n7.js → 24w3x2da9sk49.js} +1 -1
  169. package/.next/standalone/.next/static/chunks/2tjfp9dirxnku.js +1 -0
  170. package/.next/standalone/.next/static/chunks/{16z6_d7sp61jm.js → 3-pku9qwv1yfu.js} +1 -1
  171. package/.next/standalone/.next/static/chunks/{15rm15u5a6dua.js → 42e8zab314654.js} +1 -1
  172. package/.next/standalone/fp-cloud-cli/CHANGELOG.md +41 -0
  173. package/.next/standalone/fp-cloud-cli/README.md +42 -1
  174. package/.next/standalone/fp-cloud-cli/fp_cli/client.py +117 -12
  175. package/.next/standalone/fp-cloud-cli/fp_cli/commands/fleet_cmds.py +285 -19
  176. package/.next/standalone/fp-cloud-cli/fp_cli/commands/policies_cmds.py +84 -18
  177. package/.next/standalone/fp-cloud-cli/fp_cli/enforcement.py +170 -6
  178. package/.next/standalone/fp-cloud-cli/fp_cli/models.py +89 -6
  179. package/.next/standalone/fp-cloud-cli/fp_cli/output.py +259 -21
  180. package/.next/standalone/fp-cloud-cli/fp_cli/policy_check.py +8 -5
  181. package/.next/standalone/fp-cloud-cli/skill/SKILL.md +2 -2
  182. package/.next/standalone/fp-cloud-cli/skill/references/commands.md +17 -9
  183. package/.next/standalone/fp-cloud-cli/tests/test_cloud_jev.py +692 -0
  184. package/.next/standalone/fp-cloud-cli/tests/test_enforcement_logic.py +46 -0
  185. package/.next/standalone/fp-cloud-cli/tests/test_output.py +23 -0
  186. package/.next/standalone/fp-cloud-cli/uv.lock +6 -6
  187. package/.next/standalone/hermes-plugin/README.md +6 -4
  188. package/.next/standalone/hermes-plugin/__init__.py +16 -0
  189. package/.next/standalone/hermes-plugin/client.py +5 -1
  190. package/.next/standalone/hermes-plugin/plugin.yaml +1 -1
  191. package/.next/standalone/node_modules/@next/env/package.json +1 -1
  192. package/.next/standalone/node_modules/@opentelemetry/api/build/src/api/context.js +72 -0
  193. package/.next/standalone/node_modules/@opentelemetry/api/build/src/api/diag.js +84 -0
  194. package/.next/standalone/node_modules/@opentelemetry/api/build/src/api/metrics.js +50 -0
  195. package/.next/standalone/node_modules/@opentelemetry/api/build/src/api/propagation.js +80 -0
  196. package/.next/standalone/node_modules/@opentelemetry/api/build/src/api/trace.js +70 -0
  197. package/.next/standalone/node_modules/@opentelemetry/api/build/src/baggage/context-helpers.js +52 -0
  198. package/.next/standalone/node_modules/@opentelemetry/api/build/src/baggage/internal/baggage-impl.js +44 -0
  199. package/.next/standalone/node_modules/@opentelemetry/api/build/src/baggage/internal/symbol.js +12 -0
  200. package/.next/standalone/node_modules/@opentelemetry/api/build/src/baggage/utils.js +41 -0
  201. package/.next/standalone/node_modules/@opentelemetry/api/build/src/context/NoopContextManager.js +27 -0
  202. package/.next/standalone/node_modules/@opentelemetry/api/build/src/context/context.js +52 -0
  203. package/.next/standalone/node_modules/@opentelemetry/api/build/src/context-api.js +16 -0
  204. package/.next/standalone/node_modules/@opentelemetry/api/build/src/diag/ComponentLogger.js +47 -0
  205. package/.next/standalone/node_modules/@opentelemetry/api/build/src/diag/consoleLogger.js +73 -0
  206. package/.next/standalone/node_modules/@opentelemetry/api/build/src/diag/internal/logLevelLogger.js +34 -0
  207. package/.next/standalone/node_modules/@opentelemetry/api/build/src/diag/types.js +33 -0
  208. package/.next/standalone/node_modules/@opentelemetry/api/build/src/diag-api.js +20 -0
  209. package/.next/standalone/node_modules/@opentelemetry/api/build/src/index.js +71 -0
  210. package/.next/standalone/node_modules/@opentelemetry/api/build/src/internal/global-utils.js +60 -0
  211. package/.next/standalone/node_modules/@opentelemetry/api/build/src/internal/semver.js +111 -0
  212. package/.next/standalone/node_modules/@opentelemetry/api/build/src/metrics/Metric.js +18 -0
  213. package/.next/standalone/node_modules/@opentelemetry/api/build/src/metrics/NoopMeter.js +118 -0
  214. package/.next/standalone/node_modules/@opentelemetry/api/build/src/metrics/NoopMeterProvider.js +20 -0
  215. package/.next/standalone/node_modules/@opentelemetry/api/build/src/metrics-api.js +17 -0
  216. package/.next/standalone/node_modules/@opentelemetry/api/build/src/propagation/NoopTextMapPropagator.js +23 -0
  217. package/.next/standalone/node_modules/@opentelemetry/api/build/src/propagation/TextMapPropagator.js +36 -0
  218. package/.next/standalone/node_modules/@opentelemetry/api/build/src/propagation-api.js +17 -0
  219. package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/NonRecordingSpan.js +58 -0
  220. package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/NoopTracer.js +68 -0
  221. package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/NoopTracerProvider.js +21 -0
  222. package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/ProxyTracer.js +46 -0
  223. package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/ProxyTracerProvider.js +46 -0
  224. package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/SamplingResult.js +33 -0
  225. package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/context-utils.js +71 -0
  226. package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/internal/tracestate-impl.js +94 -0
  227. package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/internal/tracestate-validators.js +35 -0
  228. package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/internal/utils.js +16 -0
  229. package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/invalid-span-constants.js +25 -0
  230. package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/span_kind.js +38 -0
  231. package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/spancontext-utils.js +66 -0
  232. package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/status.js +29 -0
  233. package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/trace_flags.js +18 -0
  234. package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace-api.js +17 -0
  235. package/.next/standalone/node_modules/@opentelemetry/api/build/src/version.js +10 -0
  236. package/.next/standalone/node_modules/@opentelemetry/api/package.json +96 -0
  237. package/.next/standalone/node_modules/next/dist/build/swc/index.js +1 -1
  238. package/.next/standalone/node_modules/next/dist/compiled/next-server/app-page-turbo-experimental.runtime.prod.js +2 -2
  239. package/.next/standalone/node_modules/next/dist/compiled/next-server/app-page-turbo.runtime.prod.js +2 -2
  240. package/.next/standalone/node_modules/next/dist/compiled/next-server/app-route-turbo.runtime.prod.js +1 -1
  241. package/.next/standalone/node_modules/next/dist/lib/patch-incorrect-lockfile.js +3 -3
  242. package/.next/standalone/node_modules/next/dist/server/app-render/async-local-storage.js +1 -1
  243. package/.next/standalone/node_modules/next/dist/server/config.js +1 -1
  244. package/.next/standalone/node_modules/next/dist/server/dev/hot-reloader-turbopack.js +2 -2
  245. package/.next/standalone/node_modules/next/dist/server/dev/hot-reloader-webpack.js +1 -1
  246. package/.next/standalone/node_modules/next/dist/server/lib/app-info-log.js +1 -1
  247. package/.next/standalone/node_modules/next/dist/server/lib/generate-agent-files.js +3 -3
  248. package/.next/standalone/node_modules/next/dist/server/lib/router-server.js +1 -1
  249. package/.next/standalone/node_modules/next/dist/server/lib/start-server.js +1 -1
  250. package/.next/standalone/node_modules/next/dist/server/lib/trace/tracer.js +1 -1
  251. package/.next/standalone/node_modules/next/dist/server/typescript/rules/config.js +2 -2
  252. package/.next/standalone/node_modules/next/dist/server/use-cache/use-cache-wrapper.js +1 -1
  253. package/.next/standalone/node_modules/next/dist/telemetry/anonymous-meta.js +1 -1
  254. package/.next/standalone/node_modules/next/dist/telemetry/events/swc-load-failure.js +1 -1
  255. package/.next/standalone/node_modules/next/dist/telemetry/events/version.js +2 -2
  256. package/.next/standalone/node_modules/next/package.json +11 -11
  257. package/.next/standalone/package.json +11 -11
  258. package/.next/standalone/sdk/python/CHANGELOG.md +7 -0
  259. package/.next/standalone/sdk/python/failproofai_sdk/_version.py +1 -1
  260. package/.next/standalone/sdk/python/pyproject.toml +19 -0
  261. package/.next/standalone/sdk/python/uv.lock +520 -301
  262. package/.next/standalone/sdk/typescript/CHANGELOG.md +13 -0
  263. package/.next/standalone/sdk/typescript/integration/fixtures/mastra-1/package-lock.json +4 -13
  264. package/.next/standalone/sdk/typescript/integration/fixtures/mastra-1/package.json +2 -1
  265. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/package-lock.json +4 -13
  266. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/package.json +3 -0
  267. package/.next/standalone/sdk/typescript/package-lock.json +178 -162
  268. package/.next/standalone/sdk/typescript/package.json +1 -1
  269. package/.next/standalone/sdk/typescript/src/version.ts +1 -1
  270. package/.next/standalone/server.js +1 -1
  271. package/bin/failproofai.mjs +17 -1
  272. package/dist/cli.mjs +2866 -1124
  273. package/dist/worker.mjs +1450 -145
  274. package/hermes-plugin/README.md +6 -4
  275. package/hermes-plugin/__init__.py +16 -0
  276. package/hermes-plugin/client.py +5 -1
  277. package/hermes-plugin/plugin.yaml +1 -1
  278. package/package.json +11 -11
  279. package/src/hooks/agent-roster.ts +172 -0
  280. package/src/hooks/agent-targets.ts +60 -0
  281. package/src/hooks/cloud-connection.ts +97 -27
  282. package/src/hooks/cloud-enrollment-cli.ts +7 -4
  283. package/src/hooks/cloud-managed-policies.ts +380 -20
  284. package/src/hooks/cloud-policy-errors.ts +481 -0
  285. package/src/hooks/config-status.ts +1 -1
  286. package/src/hooks/custom-hooks-loader.ts +26 -3
  287. package/src/hooks/daemon-client.ts +9 -4
  288. package/src/hooks/daemon-service.ts +2 -1
  289. package/src/hooks/effective-reviewers.ts +22 -1
  290. package/src/hooks/fp-home.ts +6 -0
  291. package/src/hooks/handler.ts +235 -18
  292. package/src/hooks/health-probe.ts +15 -0
  293. package/src/hooks/integrations.ts +18 -11
  294. package/src/hooks/jev-cli.ts +197 -0
  295. package/src/hooks/jev-cloud-connection.ts +92 -0
  296. package/src/hooks/manager.ts +122 -16
  297. package/src/hooks/pack-failclosed.ts +2 -0
  298. package/src/hooks/pack-manifest.ts +8 -1
  299. package/src/hooks/policy-evaluator.ts +5 -1
  300. package/src/hooks/policy-registry.ts +3 -2
  301. package/src/hooks/policy-reviewability.ts +21 -5
  302. package/src/hooks/semantic/cloud-jev-health.ts +227 -0
  303. package/src/hooks/semantic/cloud-jev.ts +677 -0
  304. package/src/hooks/semantic/jev-client.ts +18 -1
  305. package/src/hooks/semantic/jev-config.ts +173 -3
  306. package/src/hooks/semantic/jev-review.ts +129 -10
  307. package/src/hooks/semantic/pack-policies.ts +2 -1
  308. package/src/hooks/semantic/types.ts +8 -0
  309. package/src/hooks/session-pause-cli.ts +1 -1
  310. package/src/hooks/worker-server.ts +5 -1
  311. package/.next/standalone/.next/server/chunks/[externals]__0hjaw70fchx66._.js +0 -3
  312. package/.next/standalone/.next/server/chunks/[root-of-the-server]__07l68zv0hqdiu._.js +0 -3
  313. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0car70pylmvor._.js +0 -3
  314. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0u3i025_setk_._.js +0 -3
  315. package/.next/standalone/.next/server/chunks/[root-of-the-server]__10a2f6s636yc7._.js +0 -3
  316. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1qt5u58xrcuk6._.js +0 -3
  317. package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_077n_4ip5__fu._.js +0 -3
  318. package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_0mqvvxcn6v0op._.js +0 -3
  319. package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_0pb7ds5g0vzgn._.js +0 -3
  320. package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_1gasm5xkeqmm3._.js +0 -3
  321. package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_1q1heqmkhh8l4._.js +0 -3
  322. package/.next/standalone/.next/server/chunks/src_hooks_1aveq0uhs2t1b._.js +0 -5
  323. package/.next/standalone/.next/server/chunks/src_hooks_1eem5a7cyqlb2._.js +0 -3
  324. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0888k4s6spfmh._.js +0 -3
  325. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0_bflu046ep5j._.js +0 -3
  326. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0_lbstb5x2t15._.js +0 -3
  327. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0fdwgktjfhedo._.js +0 -3
  328. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0s4deza787asx._.js +0 -3
  329. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__18qe-hu0gwqm4._.js +0 -3
  330. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1_p_9xe520fex._.js +0 -3
  331. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1fmhm8_s9i4re._.js +0 -3
  332. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1g76awtnmimd1._.js +0 -3
  333. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1pczevlpk5lxh._.js +0 -3
  334. package/.next/standalone/.next/server/chunks/ssr/_0dc-of_bn0cim._.js +0 -3
  335. package/.next/standalone/.next/server/chunks/ssr/src_hooks_effective-reviewers_ts_1h4wtvo55j16x._.js +0 -5
  336. package/.next/standalone/.next/static/chunks/0m-tv1y6ghhtk.js +0 -1
  337. package/.next/standalone/.next/static/chunks/0ol2gj4ntfn56.js +0 -1
  338. package/.next/standalone/.next/static/chunks/3hj5_7i3nw4zj.js +0 -1
  339. package/.next/standalone/.next/static/chunks/3iyoapeoq_hup.js +0 -1
  340. /package/.next/standalone/.next/static/{kEFP3ybXwZdriNEQmWwlH → xq8UgF5yFxty1VWxY2hyn}/_buildManifest.js +0 -0
  341. /package/.next/standalone/.next/static/{kEFP3ybXwZdriNEQmWwlH → xq8UgF5yFxty1VWxY2hyn}/_clientMiddlewareManifest.js +0 -0
  342. /package/.next/standalone/.next/static/{kEFP3ybXwZdriNEQmWwlH → xq8UgF5yFxty1VWxY2hyn}/_ssgManifest.js +0 -0
@@ -1,4 +1,4 @@
1
- """The fleet: fleet list / show / deploy / diff / history / rollback / rename.
1
+ """The fleet: fleet list / show / deploy / jev-mode / diff / history / rollback / rename.
2
2
 
3
3
  What each machine is TOLD to enforce. Authoring the policies is `fp policies`;
4
4
  what they actually did is `fp guardrails`.
@@ -26,14 +26,18 @@ from .. import output
26
26
  from .._context import GLOBALS_EPILOG, AppState, deny_in_key_mode, require_auth
27
27
  from .. import _click_compat as click # the Click Typer is running; see _click_compat
28
28
  from ..enforcement import (
29
+ JEV_MODES,
29
30
  RefError,
30
31
  RefUsageError,
31
32
  check_race,
32
33
  disabled_ids,
34
+ jev_mode_after,
33
35
  latest_versions,
34
36
  plan_deploy,
37
+ version_kinds,
35
38
  )
36
- from ..errors import ApiError, NotFoundError
39
+ from ..errors import ApiError, AuthError, FpCliError, NotFoundError
40
+ from ..models import PolicyRef
37
41
  from . import _write
38
42
 
39
43
  _KEY_MODE_REASON = (
@@ -62,6 +66,8 @@ def fleet_list(ctx: typer.Context) -> None:
62
66
  `intended` is the generation deployed, `applied` is the one the machine last
63
67
  collected, and `seen` is when it last reported anything — a machine can be
64
68
  in sync and dead, or alive and behind, and those are different problems.
69
+ `state` reads `N errors` when the machine reported policies it could not
70
+ apply (`fp fleet show <machine>` lists them).
65
71
 
66
72
  A machine appears from its very first check-in, including the poll that
67
73
  finds nothing deployed — that is exactly the machine you are usually looking
@@ -101,10 +107,22 @@ def fleet_show(
101
107
  machine can be told to run a policy and not yet have it; the policy list
102
108
  alone cannot tell you which, and that is usually the question.
103
109
 
110
+ Shows the Jev mode FailproofAI Cloud sets on the machine (`local` when it
111
+ sets none) and the policy errors the machine last reported: a policy it
112
+ could not load, a Jev mode it cannot act on (`jev_unconfigured`: its key
113
+ does not carry Jev; `transcripts_disabled`: it was connected with
114
+ `--no-transcripts`), FailproofAI Cloud Jev refusing or failing its calls
115
+ (`jev_rate_limited`: over the organization's Jev rate limit;
116
+ `jev_unavailable`: it skips a failing Cloud Jev for a minute at a time), an
117
+ installed pack's check left out for the question budget (`jev_budget`) or
118
+ because an organization Cloud check has its name (`jev_name_clash`).
119
+ Anything listed there is not enforcing, whatever the deployment says.
120
+
104
121
  Needs `policies:read`. With `--json`: `{machine, deployment}` — the machine
105
- record (including `appliedDeployment`, `drifted`, `lastSeen` and both label
106
- fields, with raw timestamps) and the deployment, or `deployment: null` when
107
- nothing is deployed.
122
+ record (including `appliedDeployment`, `drifted`, `lastSeen`, both label
123
+ fields, `jevMode` and `policyErrors`/`policyErrorsAt` when reported, with raw
124
+ timestamps) and the deployment, or `deployment: null` when nothing is
125
+ deployed.
108
126
 
109
127
  Example:
110
128
 
@@ -129,7 +147,8 @@ def fleet_show(
129
147
  "deployment": dep.to_dict() if dep else None,
130
148
  })
131
149
  return
132
- output.render_machine_policies(machine_id, dep, machine)
150
+ output.render_machine_policies(machine_id, dep, machine,
151
+ agent_labels=api.agent_labels(cctx, machine_id))
133
152
 
134
153
 
135
154
  def fleet_deploy(
@@ -137,17 +156,34 @@ def fleet_deploy(
137
156
  machine_id: str = typer.Argument(..., help="Machine id."),
138
157
  add: Optional[List[str]] = typer.Option(
139
158
  None, "--add",
140
- help="Add or update a policy: `id`, `id@version`, `id:effect` or `id@version:effect`.",
159
+ help="Add or update a policy: `id`, `id@version`, `id:effect` or `id@version:effect`. "
160
+ "`observe` on a `both` policy observes its JavaScript and withholds its Jev checks.",
141
161
  ),
142
162
  remove: Optional[List[str]] = typer.Option(None, "--remove", help="Remove a policy by id."),
143
163
  replace: Optional[List[str]] = typer.Option(
144
164
  None, "--set",
145
165
  help="REPLACE the whole set with exactly these. Cannot be combined with --add/--remove.",
146
166
  ),
167
+ targets: Optional[List[str]] = typer.Option(
168
+ None, "--target",
169
+ help="Scope one assigned policy: POLICY=INTEGRATION or POLICY=INTEGRATION/agt_ID. Repeat to OR selectors.",
170
+ ),
171
+ all_agents: Optional[List[str]] = typer.Option(
172
+ None, "--all-agents",
173
+ help="Clear one policy's targeting back to every agent on this machine.",
174
+ ),
147
175
  create: bool = typer.Option(
148
176
  False, "--create",
149
177
  help="Allow deploying to a machine id that has not checked in yet (pre-staging).",
150
178
  ),
179
+ jev_mode: Optional[str] = typer.Option(
180
+ None, "--jev-mode",
181
+ help="Set the machine's Jev mode from FailproofAI Cloud: off, observe, enforce (Jev's "
182
+ "checks BLOCK calls as well as clearing what they review) — or local to stop "
183
+ "overriding the machine's own. Jev checks run on FailproofAI Cloud; nothing is "
184
+ "installed on the machine. Machine-wide: installed packs' checks too. "
185
+ "Omitted: unchanged.",
186
+ ),
151
187
  yes: bool = typer.Option(False, "--yes", "-y", help="Skip the confirmation prompt. The prompt only appears on an interactive terminal: under --json, or with stdin redirected, this command proceeds without asking."),
152
188
  ) -> None:
153
189
  """Change what a machine enforces, showing the full resulting set first.
@@ -159,6 +195,24 @@ def fleet_deploy(
159
195
 
160
196
  `--set` replaces everything — the only way to drop policies you do not name.
161
197
 
198
+ Any kind deploys the same way. Jev checks run on FailproofAI Cloud; nothing
199
+ is installed on the machine: a `both` policy sends the machine its
200
+ JavaScript, and the machine asks FailproofAI Cloud about each checked tool
201
+ call while its Jev mode is `observe` or `enforce`. An effect applies to
202
+ JavaScript only — an `observe` `both` policy observes its JavaScript and its
203
+ Jev checks are not asked — and a `jev` policy is watched through the Jev
204
+ MODE instead: `--jev-mode observe` asks Jev and logs what it says while the
205
+ regex policies decide; `enforce` lets Jev's checks BLOCK calls (every `jev`
206
+ policy's deny checks) as well as clear the regex verdicts they review; `off`
207
+ stops Jev on the machine; `local` hands the choice back to the machine. The
208
+ mode is the MACHINE's: it also governs the checks of any pack installed
209
+ there, and it overrides the machine's own mode and `jev.json`, a local
210
+ `off` included. Without `--jev-mode` it is left as it is.
211
+
212
+ `--jev-mode` with no change to the set changes ONLY the mode (the same as
213
+ `fp fleet jev-mode`): the policy set — disabled policies' assignments
214
+ included — is not read back and rewritten.
215
+
162
216
  **Concurrency.** The write is a full replace with no server-side lock, so the
163
217
  CLI records the generation it read and refuses if the result is not exactly
164
218
  one higher: that means somebody else deployed in between and a replace does
@@ -170,17 +224,19 @@ def fleet_deploy(
170
224
  * `fp fleet deploy ci-runner-01 --add no-force-push`
171
225
  * `fp fleet deploy ci-runner-01 --add prod-guard@1:observe --remove old-rule`
172
226
  * `fp fleet deploy ci-runner-01 --set no-force-push --set no-secret-echo`
227
+ * `fp fleet deploy ci-runner-01 --add prod-db-intent --jev-mode observe`
228
+ * `fp fleet deploy ci-runner-01 --jev-mode local`
173
229
  """
174
230
  state: AppState = ctx.obj
175
231
  deny_in_key_mode(state, "fleet deploy", _KEY_MODE_REASON)
176
232
  cctx = require_auth(state)
177
233
 
178
- if not add and not remove and replace is None:
234
+ if not add and not remove and replace is None and jev_mode is None and not targets and not all_agents:
179
235
  # Exit 2 for the same reason `--set` with `--add` is: no flag
180
236
  # combination was given that this command can act on. Both are the
181
237
  # caller's command line, not the server's answer.
182
238
  raise click.UsageError(
183
- "nothing to do — pass --add, --remove, or --set. "
239
+ "nothing to do — pass --add, --remove, --set, --target, --all-agents, or --jev-mode. "
184
240
  "`fp fleet show <machine>` prints the current set."
185
241
  )
186
242
 
@@ -212,6 +268,11 @@ def fleet_deploy(
212
268
  replace=replace,
213
269
  latest=latest,
214
270
  disabled=disabled_ids(published),
271
+ jev_mode=jev_mode,
272
+ current_jev_mode=current.jev_mode if current else None,
273
+ kinds=version_kinds(published),
274
+ targets=targets or (),
275
+ all_agents=all_agents or (),
215
276
  )
216
277
  except RefUsageError as exc:
217
278
  # Exit 2, like every other bad flag value in this CLI (`--since`,
@@ -237,6 +298,16 @@ def fleet_deploy(
237
298
  output.deployment_unchanged(machine_id)
238
299
  return
239
300
 
301
+ # The mode alone: its own route, which never touches the policy set. A
302
+ # deploy is a full replace of the set the CLI read, and that set leaves out
303
+ # disabled policies' assignments — so a mode change sent as a deploy deleted
304
+ # them, and reverted anything changed since the read (CONTRACT C9.1). A
305
+ # machine with no deployment yet has nothing to lose and no mode to change:
306
+ # its first deploy, carrying the mode, is how it gets one.
307
+ if plan.jev_mode is not None and not plan.set_changes and current is not None:
308
+ _apply_jev_modes(state, cctx, [(machine_id, current.jev_mode)], plan.jev_mode, yes=yes, plan=plan)
309
+ return
310
+
240
311
  if not output.is_json():
241
312
  output.render_deploy_plan(plan)
242
313
  dropped = len(plan.removed)
@@ -252,7 +323,7 @@ def fleet_deploy(
252
323
  output.print_cancelled()
253
324
  return
254
325
 
255
- result = api.deploy_policies(cctx, machine_id, plan.result)
326
+ result = api.deploy_policies(cctx, machine_id, plan.result, jev_mode=jev_mode)
256
327
  check_race(plan.base, result.deployment)
257
328
 
258
329
  if output.is_json():
@@ -265,6 +336,176 @@ def fleet_deploy(
265
336
  output.deployment_applied(machine_id, result.deployment, len(result.policies))
266
337
 
267
338
 
339
+ def _jev_mode_consequence(mode: str, count: int) -> str:
340
+ what = f"{count} machine{'s' if count != 1 else ''}"
341
+ tail = {
342
+ "enforce": "; in enforce Jev's deny checks BLOCK calls, and it covers installed packs' checks too",
343
+ "observe": "; in observe Jev only records what it would have decided",
344
+ "off": "; Jev stops on them, a local jev.json included",
345
+ "local": "; each machine's own jev.json decides again",
346
+ }.get(mode, "")
347
+ return f"this sets the Jev mode to {mode} on {what} and leaves their policy sets untouched{tail}"
348
+
349
+
350
+ def _apply_jev_modes(
351
+ state: AppState,
352
+ cctx,
353
+ targets: List[tuple],
354
+ mode: str,
355
+ *,
356
+ yes: bool,
357
+ plan=None,
358
+ ) -> None:
359
+ """Set `mode` on each `(machine_id, current_mode)`, through the mode-only route.
360
+
361
+ Shared by `fleet jev-mode` and `fleet deploy --jev-mode` with no set change.
362
+ A machine already on `mode` is left alone; one that fails is reported and
363
+ the rest still go ahead (exit 1 at the end, naming them).
364
+ """
365
+ after = jev_mode_after(mode)
366
+ rows = [
367
+ {"machineId": mid, "from": cur or "local", "to": after or "local", "changed": (cur or None) != after}
368
+ for mid, cur in targets
369
+ ]
370
+ todo = [r for r in rows if r["changed"]]
371
+ if not todo:
372
+ if output.is_json():
373
+ out = {"mode": mode, "machines": rows, "applied": False}
374
+ if plan is not None:
375
+ out = {"plan": plan.to_dict(), "deployment": None, "applied": False}
376
+ output.emit_json(out)
377
+ return
378
+ output.jev_mode_unchanged([r["machineId"] for r in rows], mode)
379
+ return
380
+
381
+ if not output.is_json():
382
+ output.render_jev_mode_plan(rows)
383
+ if not _write.confirm_destructive(
384
+ state, "change the Jev mode on",
385
+ todo[0]["machineId"] if len(todo) == 1 else f"{len(todo)} machines",
386
+ consequence=_jev_mode_consequence(mode, len(todo)),
387
+ assume_yes=yes,
388
+ ):
389
+ if output.is_json():
390
+ output.emit_json({"cancelled": True, "applied": False, "machines": rows})
391
+ else:
392
+ output.print_cancelled()
393
+ return
394
+
395
+ failed = []
396
+ last = None
397
+ for row in todo:
398
+ try:
399
+ result, changed = api.set_jev_mode(cctx, row["machineId"], mode)
400
+ except AuthError:
401
+ raise
402
+ except FpCliError as exc:
403
+ # One machine's refusal (a 404, a 403, a 422) is that machine's;
404
+ # the rest still go ahead, and the exit code says it was not all.
405
+ row["error"] = exc.format_message() if hasattr(exc, "format_message") else str(exc)
406
+ failed.append(row["machineId"])
407
+ continue
408
+ last = result
409
+ row["deployment"] = result.deployment
410
+ row["changed"] = changed
411
+
412
+ if output.is_json():
413
+ if plan is not None:
414
+ output.emit_json({
415
+ "plan": plan.to_dict(),
416
+ "deployment": last.to_dict() if last is not None else None,
417
+ "applied": last is not None,
418
+ "jevModeOnly": True,
419
+ })
420
+ else:
421
+ output.emit_json({"mode": mode, "machines": rows, "applied": not failed})
422
+ else:
423
+ output.jev_mode_applied(rows)
424
+ if failed:
425
+ raise ApiError(
426
+ f"the Jev mode could not be changed on {', '.join(failed)}"
427
+ + ("" if len(failed) == len(todo) else " — the other machines were changed"),
428
+ )
429
+
430
+
431
+ def fleet_jev_mode(
432
+ ctx: typer.Context,
433
+ args: Optional[List[str]] = typer.Argument(
434
+ None, metavar="[MACHINE]... MODE",
435
+ help="The machines, then the mode: off, observe, enforce or local. With --all, just the mode.",
436
+ ),
437
+ all_machines: bool = typer.Option(
438
+ False, "--all", help="Every machine that has a deployment (machines with none are skipped).",
439
+ ),
440
+ yes: bool = typer.Option(False, "--yes", "-y", help="Skip the confirmation prompt. The prompt only appears on an interactive terminal: under --json, or with stdin redirected, this command proceeds without asking."),
441
+ ) -> None:
442
+ """Set the Jev mode FailproofAI Cloud gives machines, and nothing else.
443
+
444
+ `off`, `observe` or `enforce` override each machine's own mode and
445
+ `jev.json`, a local `off` included; `local` hands the choice back to the
446
+ machine. Jev checks run on FailproofAI Cloud; nothing is installed on the
447
+ machine: under `observe` or `enforce` it sends each checked tool call to
448
+ FailproofAI Cloud. `observe` asks Jev and records what it says while the
449
+ regex policies decide. `enforce` lets Jev's checks BLOCK calls — every `jev`
450
+ policy's deny checks — as well as clear the regex verdicts they review. The
451
+ mode is the machine's: it also governs the checks of every pack installed
452
+ there. A machine connected with `--no-transcripts` never asks, and reports
453
+ `transcripts_disabled`.
454
+
455
+ Only the mode changes: each machine's policy set, disabled policies'
456
+ assignments included, is left exactly as it is, and a machine already on
457
+ the mode is skipped. Each change is a new generation in `fp fleet history`.
458
+ A machine with no deployment has no mode to change — `fp fleet deploy
459
+ <machine> --jev-mode <mode>` gives it its first deployment with one.
460
+
461
+ Needs `policies:write`. With `--json`: `{mode, applied, machines:[{machineId,
462
+ from, to, changed, deployment?, error?}]}`.
463
+
464
+ Examples:
465
+
466
+ * `fp fleet jev-mode ci-runner-01 observe`
467
+ * `fp fleet jev-mode ci-runner-01 ci-runner-02 enforce`
468
+ * `fp fleet jev-mode --all local`
469
+ """
470
+ state: AppState = ctx.obj
471
+ deny_in_key_mode(state, "fleet jev-mode", _KEY_MODE_REASON)
472
+ words = list(args or [])
473
+ if not words:
474
+ raise click.UsageError("pass the mode: off, observe, enforce or local")
475
+ mode, machine_ids = words[-1], list(dict.fromkeys(words[:-1]))
476
+ if mode not in JEV_MODES:
477
+ raise click.UsageError(f"{mode!r} is not a Jev mode — one of {', '.join(JEV_MODES)}")
478
+ if all_machines and machine_ids:
479
+ raise click.UsageError("--all sets every machine; do not name machines as well")
480
+ if not all_machines and not machine_ids:
481
+ raise click.UsageError("name at least one machine, or pass --all")
482
+ cctx = require_auth(state)
483
+
484
+ deployments = {d.machine_id: d for d in api.list_deployments(cctx)}
485
+ if all_machines:
486
+ targets = [(mid, deployments[mid].jev_mode) for mid in sorted(deployments)]
487
+ else:
488
+ known = {m.machine_id for m in api.list_machines(cctx)} | set(deployments)
489
+ unknown = [mid for mid in machine_ids if mid not in known]
490
+ if unknown:
491
+ raise NotFoundError(f"no machine {', '.join(repr(u) for u in unknown)} has checked in")
492
+ bare = [mid for mid in machine_ids if mid not in deployments]
493
+ if bare:
494
+ raise ApiError(
495
+ f"{', '.join(bare)} {'has' if len(bare) == 1 else 'have'} no deployment, so there is no Jev "
496
+ "mode to change",
497
+ hint=f"`fp fleet deploy <machine> --jev-mode {mode}` gives a machine its first deployment with the mode",
498
+ )
499
+ targets = [(mid, deployments[mid].jev_mode) for mid in machine_ids]
500
+ if not targets:
501
+ if output.is_json():
502
+ output.emit_json({"mode": mode, "machines": [], "applied": False})
503
+ else:
504
+ output.info("no machine has a deployment yet — nothing to set")
505
+ return
506
+ _apply_jev_modes(state, cctx, targets, mode, yes=yes)
507
+
508
+
268
509
  def fleet_diff(
269
510
  ctx: typer.Context,
270
511
  machine_id: Optional[str] = typer.Argument(None, help="Machine id. Omit for the whole fleet."),
@@ -314,8 +555,11 @@ def fleet_history(
314
555
  """List a machine's deployment generations, newest first.
315
556
 
316
557
  A reissue — the server rewriting a deployment because a policy was disabled
317
- — appears as an ordinary entry. Needs `policies:read`. With `--json`:
318
- `{machineId, history:[{deployment, policies, updatedAt}]}`.
558
+ — appears as an ordinary entry, and so does a Jev mode change. Each
559
+ generation shows the Jev mode FailproofAI Cloud set with it (`local` when it
560
+ set none), which is the mode a rollback to it restores. Needs
561
+ `policies:read`. With `--json`: `{machineId, history:[{deployment, policies,
562
+ updatedAt, jevMode}]}`.
319
563
 
320
564
  Example:
321
565
 
@@ -329,7 +573,8 @@ def fleet_history(
329
573
  if output.is_json():
330
574
  output.emit_json({"machineId": machine_id, "history": entries})
331
575
  return
332
- output.render_deployment_history(machine_id, entries)
576
+ output.render_deployment_history(machine_id, entries,
577
+ agent_labels=api.agent_labels(cctx, machine_id))
333
578
 
334
579
 
335
580
  def fleet_rollback(
@@ -344,8 +589,12 @@ def fleet_rollback(
344
589
  counter, so history stays append-only. A generation containing a policy that
345
590
  has since been disabled or deleted cannot be reinstated; the server says so.
346
591
 
347
- Needs `policies:write`. With `--json`: the resulting deployment, or
348
- `{"cancelled": true}` if you decline.
592
+ It restores that generation's Jev mode too, `local` included: the prompt
593
+ and the result say `jev mode <now> → <then>` when that changes it.
594
+
595
+ Needs `policies:write`. With `--json`: the resulting deployment plus
596
+ `jevModeBefore` (the mode it replaced), or `{"cancelled": true}` if you
597
+ decline.
349
598
 
350
599
  Example:
351
600
 
@@ -356,9 +605,22 @@ def fleet_rollback(
356
605
  cctx = require_auth(state)
357
606
  _require_machine(cctx, machine_id)
358
607
  current = api.get_deployment(cctx, machine_id)
608
+ # The mode that generation carried comes back with it, NULL (`local`)
609
+ # included — a rollback past an `--jev-mode off` turns enforcement back on.
610
+ # Read it first, so the prompt says so rather than the fleet finding out.
611
+ target = next(
612
+ (e for e in api.deployment_history(cctx, machine_id) if e.get("deployment") == deployment), None)
613
+ mode_before = (current.jev_mode if current else None) or "local"
614
+ mode_target = (target.get("jevMode") or "local") if target is not None else None
615
+ consequence = "this REPLACES the machine's current set with the one from that generation"
616
+ if target is not None:
617
+ refs = [PolicyRef.from_dict(ref).label for ref in (target.get("policies") or [])]
618
+ consequence += "; assignments: " + ("; ".join(refs) if refs else "no policies")
619
+ if mode_target is not None and mode_target != mode_before:
620
+ consequence += f", and its Jev mode: jev mode {mode_before} → {mode_target}"
359
621
  if not _write.confirm_destructive(
360
622
  state, f"reinstate deployment #{deployment} on", machine_id,
361
- consequence="this REPLACES the machine's current set with the one from that generation",
623
+ consequence=consequence,
362
624
  assume_yes=yes,
363
625
  ):
364
626
  if output.is_json():
@@ -369,9 +631,12 @@ def fleet_rollback(
369
631
  result = api.rollback_deployment(cctx, machine_id, deployment)
370
632
  check_race(current.deployment if current else None, result.deployment)
371
633
  if output.is_json():
372
- output.emit_json(result.to_dict())
634
+ output.emit_json({**result.to_dict(), "jevModeBefore": mode_before})
373
635
  return
374
- output.deployment_rolled_back(machine_id, deployment, result.deployment)
636
+ output.deployment_rolled_back(
637
+ machine_id, deployment, result.deployment,
638
+ jev_from=mode_before, jev_to=result.jev_mode or "local",
639
+ )
375
640
 
376
641
 
377
642
  def fleet_rename(
@@ -404,11 +669,12 @@ def register(app: typer.Typer) -> None:
404
669
  no_args_is_help=True,
405
670
  rich_markup_mode="markdown",
406
671
  context_settings={"help_option_names": ["-h", "--help"]},
407
- help="The fleet and what each machine enforces (list / show / deploy / diff / history / rollback / rename).",
672
+ help="The fleet and what each machine enforces (list / show / deploy / jev-mode / diff / history / rollback / rename).",
408
673
  )
409
674
  fleet_app.command("list", epilog=GLOBALS_EPILOG)(fleet_list)
410
675
  fleet_app.command("show", epilog=GLOBALS_EPILOG)(fleet_show)
411
676
  fleet_app.command("deploy", epilog=GLOBALS_EPILOG)(fleet_deploy)
677
+ fleet_app.command("jev-mode", epilog=GLOBALS_EPILOG)(fleet_jev_mode)
412
678
  fleet_app.command("diff", epilog=GLOBALS_EPILOG)(fleet_diff)
413
679
  fleet_app.command("history", epilog=GLOBALS_EPILOG)(fleet_history)
414
680
  fleet_app.command("rollback", epilog=GLOBALS_EPILOG)(fleet_rollback)
@@ -10,6 +10,7 @@ single most surprising thing here, so every success path says so.
10
10
  """
11
11
  from __future__ import annotations
12
12
 
13
+ import json
13
14
  from typing import Optional
14
15
 
15
16
  import typer
@@ -18,8 +19,8 @@ from .. import client as api
18
19
  from .. import output, theme
19
20
  from .._context import GLOBALS_EPILOG, AppState, deny_in_key_mode, require_auth
20
21
  from .. import _click_compat as click # the Click Typer is running; see _click_compat
21
- from ..enforcement import RefError, RefUsageError, read_source
22
- from ..policy_check import check_syntax, run_policy
22
+ from ..enforcement import RefError, RefUsageError, parse_semantic, read_source, resolve_kind
23
+ from ..policy_check import SyntaxResult, check_syntax, run_policy
23
24
  from ..errors import ApiError, NotFoundError
24
25
  from . import _write
25
26
 
@@ -36,11 +37,15 @@ _KEY_MODE_REASON = (
36
37
  def policies_list(ctx: typer.Context) -> None:
37
38
  """List every published policy version, newest of each policy first.
38
39
 
39
- Shows `policy · version · state · description`, one row per VERSION —
40
+ Shows `policy · version · kind · state · description`, one row per VERSION —
40
41
  versions are immutable and every one stays addressable, so a policy
41
42
  published three times is three rows. The title counts distinct policies and
42
43
  captions the version total, the way the dashboard's library does.
43
44
 
45
+ `kind` is `regex` (JavaScript), `jev` (Jev checks only) or `both`
46
+ (JavaScript its own Jev checks may clear); a `jev`/`both` row names its
47
+ checks and the characters they take of a machine's Jev question budget.
48
+
44
49
  `state` is active, disabled (kept but not enforced) or archived (deleted;
45
50
  machines already carrying it keep it until redeployed). Needs
46
51
  `policies:read`. With `--json`: the server's policy list verbatim — also
@@ -64,9 +69,11 @@ def policies_show(
64
69
  ctx: typer.Context,
65
70
  policy_id: str = typer.Argument(..., help="Policy id."),
66
71
  ) -> None:
67
- """Show one policy, including its full source.
72
+ """Show one policy, including its full source and its Jev checks.
68
73
 
69
- Needs `policies:read`. With `--json`: the policy object with `source`.
74
+ Needs `policies:read`. With `--json`: the policy object with `source`,
75
+ `kind`, and for `jev`/`both` its `semantic` declarations, `semanticSha256`
76
+ and the server-derived `authority`/`reviewedBy`.
70
77
 
71
78
  Example:
72
79
 
@@ -96,6 +103,8 @@ def policies_show(
96
103
  source_bytes=len((match.source or "").encode("utf-8")))
97
104
  if match.source:
98
105
  output.info(match.source)
106
+ if match.semantic:
107
+ output.info(json.dumps(match.semantic, indent=2))
99
108
 
100
109
 
101
110
  def policies_publish(
@@ -103,7 +112,19 @@ def policies_publish(
103
112
  policy_id: str = typer.Argument(..., help="Policy id (letters, numbers, '.', '_', '-')."),
104
113
  source: Optional[str] = typer.Argument(
105
114
  None,
106
- help="Path to the policy source, @path, or - for stdin. Omit to paste it.",
115
+ help="Path to the JavaScript source, @path, or - for stdin. Omit to paste it. Same as --source.",
116
+ ),
117
+ kind: Optional[str] = typer.Option(
118
+ None, "--kind",
119
+ help="regex (JavaScript), jev (Jev checks only) or both (JavaScript its own Jev checks may "
120
+ "clear). Default: follows from what you give — --semantic alone is jev, with source both.",
121
+ ),
122
+ source_opt: Optional[str] = typer.Option(
123
+ None, "--source", help="The JavaScript source: a path, @path, or - for stdin.",
124
+ ),
125
+ semantic_path: Optional[str] = typer.Option(
126
+ None, "--semantic",
127
+ help="A JSON file holding the Jev declarations (a JSON array): a path, @path, or - for stdin.",
107
128
  ),
108
129
  description: str = typer.Option("", "--description", help="One-line description."),
109
130
  no_verify: bool = typer.Option(
@@ -112,13 +133,29 @@ def policies_publish(
112
133
  ) -> None:
113
134
  """Publish a policy — mints a NEW VERSION; it never edits one in place.
114
135
 
115
- The source is parse-checked with node before it is sent. Nothing downstream
116
- does this: the server validates the id and a size ceiling, and a broken
117
- policy otherwise fails on the machine at enforcement time. `--no-verify`
118
- skips it; a host without node publishes with a warning rather than a block.
119
- Jev fields a cloud policy never reads (`semanticPolicies.add`, `authority:
120
- "reviewable"`) are refused regardless — ship those in a pack with
121
- `failproofai publish`.
136
+ A policy has a **kind**:
137
+
138
+ * `regex` — JavaScript (`--source`, or the positional source): what publish
139
+ has always done, and the default.
140
+ * `jev` — Jev checks only (`--semantic checks.json`): a JSON array of Jev
141
+ declarations, each `{name, title, appliesTo, mode, userCanOverride,
142
+ probes:[{id, instructions, criteria:{true,false}}], guidance, ...}` —
143
+ exactly a failproofai pack manifest's semantic entry. No JavaScript.
144
+ * `both` — the two together. FailproofAI Cloud makes the JavaScript's
145
+ verdict reviewable by exactly its own checks, and deploys them as one.
146
+
147
+ Jev checks run on FailproofAI Cloud; nothing is installed on the machine.
148
+ A machine gets a `both` policy's JavaScript, and asks FailproofAI Cloud
149
+ about each checked tool call while its Jev mode is `observe` or `enforce`.
150
+
151
+ The JavaScript is parse-checked with node before it is sent. Nothing
152
+ downstream does this: the server validates the id and a size ceiling, and a
153
+ broken policy otherwise fails on the machine at enforcement time.
154
+ `--no-verify` skips it; a host without node publishes with a warning rather
155
+ than a block. Jev fields in the JavaScript (`semanticPolicies.add`,
156
+ `authority: "reviewable"`) are refused regardless — put Jev checks in
157
+ `--semantic`. The server checks each declaration (limits, reserved
158
+ FailproofAI names, names unique in the org) and says which one it refused.
122
159
 
123
160
  Source can come from a path, `@path`, a pipe, `-`, or an interactive paste
124
161
  when you give none and stdin is a terminal.
@@ -134,21 +171,42 @@ def policies_publish(
134
171
  * `fp policies publish no-force-push ./rule.mjs`
135
172
  * `cat rule.mjs | fp policies publish no-force-push`
136
173
  * `fp policies publish no-force-push -` — read stdin explicitly
174
+ * `fp policies publish prod-db-intent --kind jev --semantic ./checks.json`
175
+ * `fp policies publish no-prod-db --kind both --source ./rule.mjs --semantic ./checks.json`
137
176
  """
138
177
  state: AppState = ctx.obj
139
178
  deny_in_key_mode(state, "policies publish", _KEY_MODE_REASON)
140
179
  cctx = require_auth(state)
141
180
 
181
+ if source is not None and source_opt is not None:
182
+ raise click.UsageError("give the JavaScript source once — positionally or with --source, not both")
183
+ source = source if source is not None else source_opt
184
+ if source == "-" and semantic_path == "-":
185
+ raise click.UsageError("only one of the JavaScript source and --semantic can come from stdin")
186
+
187
+ # Whether JavaScript is coming is decided WITHOUT reading stdin: a Jev-only
188
+ # publish must not sit waiting for a paste nobody is going to give.
189
+ wants_source = source is not None or kind in ("regex", "both") or (kind is None and semantic_path is None)
190
+ try:
191
+ resolved_kind = resolve_kind(kind, has_source=wants_source, has_semantic=semantic_path is not None)
192
+ except RefUsageError as exc:
193
+ raise click.UsageError(str(exc))
194
+
142
195
  def _paste_prompt() -> None:
143
196
  output.hint("paste the policy source, then press Ctrl-D")
144
197
 
198
+ text: Optional[str] = None
199
+ semantic = None
145
200
  try:
146
- text = read_source(source, prompt=_paste_prompt)
201
+ if semantic_path is not None:
202
+ semantic = parse_semantic(read_source(semantic_path, isatty=False))
203
+ if wants_source:
204
+ text = read_source(source, prompt=_paste_prompt)
147
205
  except RefUsageError as exc:
148
206
  raise click.UsageError(str(exc))
149
207
  except RefError as exc:
150
208
  raise ApiError(str(exc))
151
- if not text.strip():
209
+ if wants_source and not (text or "").strip():
152
210
  raise ApiError("policy source is empty — nothing to publish")
153
211
 
154
212
  # Nothing downstream parses this. The server checks the id and a size
@@ -156,7 +214,9 @@ def policies_publish(
156
214
  # place for a syntax error to surface. `--no-verify` exists because a
157
215
  # machine without node should still be able to publish, not because
158
216
  # skipping is ever a good idea.
159
- if not no_verify:
217
+ syn = SyntaxResult(ok=True, checked=False,
218
+ message="not checked" if text else "no JavaScript source")
219
+ if text and not no_verify:
160
220
  syn = check_syntax(text)
161
221
  if not syn.ok:
162
222
  raise ApiError(
@@ -167,7 +227,13 @@ def policies_publish(
167
227
  if not syn.checked and not output.is_json():
168
228
  output.warn(syn.message)
169
229
 
170
- created = api.publish_policy(cctx, policy_id, text, description)
230
+ created = api.publish_policy(
231
+ cctx, policy_id, text, description,
232
+ # Sent only when it says something the server's default does not, so a
233
+ # plain JavaScript publish is the same request it has always been.
234
+ kind=None if resolved_kind == "regex" and kind is None else resolved_kind,
235
+ semantic=semantic,
236
+ )
171
237
 
172
238
  # Which machines already carry this policy, and at which version. Publishing
173
239
  # deploys nothing, so this is the one thing the card must not guess at: it
@@ -191,7 +257,7 @@ def policies_publish(
191
257
  output.emit_json({**created.to_dict(), "carriers": carriers, "syntax": syn.to_dict()})
192
258
  return
193
259
  output.render_policy_published(created, carriers=carriers,
194
- source_bytes=len(text.encode("utf-8")))
260
+ source_bytes=len((text or "").encode("utf-8")))
195
261
 
196
262
 
197
263
  def policies_enable(