failproofai 1.0.7 → 1.0.8

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 (268) 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 +3 -3
  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]__02npjtd._.js → [root-of-the-server]__056wjo4._.js} +3 -3
  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]__0p-5p8u._.js → [root-of-the-server]__0n0xg95._.js} +3 -3
  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]__013jr2b._.js → [root-of-the-server]__0rwtwpm._.js} +3 -3
  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]__0da85px._.js → [root-of-the-server]__11mayhe._.js} +3 -3
  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]__13t1zkw._.js +3 -0
  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]__0ftmoxc._.js → [root-of-the-server]__1pprgri._.js} +3 -3
  101. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1p2otjt._.js → [root-of-the-server]__1q4p5b8._.js} +3 -3
  102. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1qiz0e4._.js +3 -0
  103. package/.next/standalone/.next/server/chunks/ssr/{_166t73i._.js → _0-vcssj._.js} +1 -1
  104. package/.next/standalone/.next/server/chunks/ssr/_042cgl1._.js +3 -0
  105. package/.next/standalone/.next/server/chunks/ssr/_08x1r5t._.js +1 -1
  106. package/.next/standalone/.next/server/chunks/ssr/_0bqoto4._.js +3 -0
  107. package/.next/standalone/.next/server/chunks/ssr/_0uyu3jf._.js +3 -0
  108. package/.next/standalone/.next/server/chunks/ssr/_13kfn90._.js +23 -0
  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_dist_0drixxt._.js → node_modules_next_dist_0w6mzq5._.js} +4 -4
  119. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_18_d8l1._.js +151 -0
  120. package/.next/standalone/.next/server/chunks/ssr/src_hooks_0-q0umm._.js +3 -0
  121. package/.next/standalone/.next/server/chunks/ssr/src_hooks_06kzv9d._.js +12 -0
  122. package/.next/standalone/.next/server/chunks/ssr/src_hooks_0g194sy._.js +3 -0
  123. package/.next/standalone/.next/server/chunks/ssr/src_hooks_1cv9_c4._.js +4 -2
  124. package/.next/standalone/.next/server/chunks/ssr/src_hooks_1kx9e0d._.js +3 -0
  125. package/.next/standalone/.next/server/chunks/ssr/src_hooks_effective-reviewers_ts_1h4wtvo._.js +5 -0
  126. package/.next/standalone/.next/server/chunks/ssr/src_hooks_fp-config_ts_04t589g._.js +1 -1
  127. package/.next/standalone/.next/server/chunks/ssr/src_hooks_fp-home_ts_0je3xkv._.js +1 -1
  128. package/.next/standalone/.next/server/chunks/ssr/src_hooks_pack-cli_ts_0t7me65._.js +1 -1
  129. package/.next/standalone/.next/server/chunks/ssr/src_hooks_semantic_pack-policies_ts_0gh_bu_._.js +3 -0
  130. package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
  131. package/.next/standalone/.next/server/pages/404.html +1 -1
  132. package/.next/standalone/.next/server/pages/500.html +1 -1
  133. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  134. package/.next/standalone/.next/server/server-reference-manifest.json +67 -23
  135. package/.next/standalone/.next/static/chunks/06dnzbolj00mc.js +6 -0
  136. package/.next/standalone/.next/static/chunks/0bhidk90e-07f.css +2 -0
  137. package/.next/standalone/.next/static/chunks/{2mdh397ghgnvv.js → 0m-9d6yn9hx4j.js} +1 -1
  138. package/.next/standalone/.next/static/chunks/{0__8a7m868fvf.js → 0wbjy0zo-m7is.js} +1 -1
  139. package/.next/standalone/.next/static/chunks/16f3fa-lx38hk.js +1 -0
  140. package/.next/standalone/.next/static/chunks/{0o6qlkgubtoex.js → 21uv-uusw329x.js} +1 -1
  141. package/.next/standalone/.next/static/chunks/2g2tki08kdhie.js +1 -0
  142. package/.next/standalone/.next/static/chunks/2qdpj67x6ifk_.js +69 -0
  143. package/.next/standalone/.next/static/chunks/2qv4hshejedtx.css +1 -0
  144. package/.next/standalone/.next/static/chunks/3-nbtkhg9y-1j.js +1 -0
  145. package/.next/standalone/.next/static/chunks/355km0ihuqo1p.js +1 -0
  146. package/.next/standalone/.next/static/chunks/{13i7-9is-vhys.js → 3c3qbmosdjl6w.js} +1 -1
  147. package/.next/standalone/PROBE-FOLLOWUP.md +186 -0
  148. package/.next/standalone/app/actions/get-jev-config.ts +604 -0
  149. package/.next/standalone/app/actions/pack-actions.ts +12 -0
  150. package/.next/standalone/app/actions/update-jev-config.ts +569 -0
  151. package/.next/standalone/app/components/jev-notices.tsx +96 -0
  152. package/.next/standalone/app/policies/hooks-client.tsx +14 -3
  153. package/.next/standalone/app/settings/jev-panel.tsx +630 -0
  154. package/.next/standalone/app/settings/page.tsx +20 -1
  155. package/.next/standalone/app/settings/settings-client.tsx +27 -1
  156. package/.next/standalone/app/settings/settings.css +79 -0
  157. package/.next/standalone/fp-cloud-cli/CHANGELOG.md +22 -4
  158. package/.next/standalone/fp-cloud-cli/fp_cli/client.py +14 -1
  159. package/.next/standalone/fp-cloud-cli/fp_cli/commands/keys_cmds.py +17 -3
  160. package/.next/standalone/fp-cloud-cli/fp_cli/commands/policies_cmds.py +3 -0
  161. package/.next/standalone/fp-cloud-cli/fp_cli/permissions.py +22 -0
  162. package/.next/standalone/fp-cloud-cli/fp_cli/policy_check.py +169 -0
  163. package/.next/standalone/fp-cloud-cli/skill/references/commands.md +1 -1
  164. package/.next/standalone/fp-cloud-cli/tests/test_keys_queries.py +65 -0
  165. package/.next/standalone/fp-cloud-cli/tests/test_policy_check.py +61 -0
  166. package/.next/standalone/package.json +10 -10
  167. package/.next/standalone/sdk/python/CHANGELOG.md +7 -0
  168. package/.next/standalone/sdk/python/failproofai_sdk/_version.py +1 -1
  169. package/.next/standalone/sdk/typescript/CHANGELOG.md +18 -1
  170. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/package-lock.json +0 -274
  171. package/.next/standalone/sdk/typescript/scripts/release.mjs +30 -0
  172. package/.next/standalone/server.js +1 -1
  173. package/README.md +3 -2
  174. package/bin/failproofai.mjs +148 -4
  175. package/dist/cli.mjs +18599 -9478
  176. package/dist/index.js +19 -1
  177. package/dist/worker.mjs +10500 -3773
  178. package/package.json +10 -10
  179. package/pi-extension/index.ts +11 -0
  180. package/scripts/build-policy-pack.mjs +53 -2
  181. package/src/audit/features.ts +3 -2
  182. package/src/hooks/builtin-policies.ts +195 -8
  183. package/src/hooks/cloud-connection.ts +190 -1
  184. package/src/hooks/cloud-enrollment-cli.ts +57 -8
  185. package/src/hooks/cloud-introspect.ts +6 -0
  186. package/src/hooks/cloud-managed-policies.ts +22 -0
  187. package/src/hooks/configure-wizard.ts +26 -6
  188. package/src/hooks/custom-hooks-loader.ts +98 -10
  189. package/src/hooks/custom-hooks-registry.ts +45 -1
  190. package/src/hooks/effective-reviewers.ts +243 -0
  191. package/src/hooks/first-run-gate.ts +5 -0
  192. package/src/hooks/flush-cli.ts +35 -8
  193. package/src/hooks/fp-config.ts +266 -1
  194. package/src/hooks/fp-home.ts +23 -0
  195. package/src/hooks/fp-reset.ts +22 -4
  196. package/src/hooks/handler.ts +303 -7
  197. package/src/hooks/hook-activity-store.ts +118 -6
  198. package/src/hooks/hook-telemetry.ts +41 -0
  199. package/src/hooks/jev-activity.ts +385 -0
  200. package/src/hooks/jev-cli.ts +2172 -0
  201. package/src/hooks/jev-cloud-connection.ts +392 -0
  202. package/src/hooks/loader-utils.ts +6 -0
  203. package/src/hooks/manager.ts +45 -7
  204. package/src/hooks/pack-cli.ts +568 -37
  205. package/src/hooks/pack-failclosed.ts +3 -0
  206. package/src/hooks/pack-manifest.ts +489 -7
  207. package/src/hooks/pack-store.ts +194 -11
  208. package/src/hooks/policy-authority.ts +386 -0
  209. package/src/hooks/policy-catalog.ts +206 -0
  210. package/src/hooks/policy-evaluator.ts +963 -796
  211. package/src/hooks/policy-registry.ts +27 -1
  212. package/src/hooks/policy-reviewability.ts +258 -0
  213. package/src/hooks/policy-types.ts +128 -0
  214. package/src/hooks/semantic/combine.ts +581 -0
  215. package/src/hooks/semantic/compile.ts +176 -0
  216. package/src/hooks/semantic/decide.ts +513 -0
  217. package/src/hooks/semantic/envelope.ts +1255 -0
  218. package/src/hooks/semantic/evaluator.ts +556 -0
  219. package/src/hooks/semantic/facts.ts +387 -0
  220. package/src/hooks/semantic/intent.ts +1190 -0
  221. package/src/hooks/semantic/jev-client.ts +1155 -0
  222. package/src/hooks/semantic/jev-config.ts +1142 -0
  223. package/src/hooks/semantic/jev-review.ts +389 -0
  224. package/src/hooks/semantic/jev-stats.ts +289 -0
  225. package/src/hooks/semantic/jev-throttle.ts +427 -0
  226. package/src/hooks/semantic/pack-policies.ts +294 -0
  227. package/src/hooks/semantic/policies.ts +597 -0
  228. package/src/hooks/semantic/precondition-names.ts +60 -0
  229. package/src/hooks/semantic/preconditions.ts +58 -0
  230. package/src/hooks/semantic/redact.ts +2937 -0
  231. package/src/hooks/semantic/session-root.ts +116 -0
  232. package/src/hooks/semantic/types.ts +162 -0
  233. package/src/hooks/semver-precedence.ts +128 -0
  234. package/src/hooks/tui.ts +4 -0
  235. package/src/hooks/types.ts +1 -1
  236. package/src/hooks/worker-server.ts +121 -27
  237. package/src/index.ts +6 -0
  238. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0cuho4x._.js +0 -3
  239. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1_r2rbg._.js +0 -24
  240. package/.next/standalone/.next/server/chunks/src_hooks_0iu54mz._.js +0 -3
  241. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0-_ki57._.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]__0bd3mje._.js +0 -3
  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]__0u3w0ll._.js +0 -22
  247. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__17d_ffl._.js +0 -3
  248. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__19d9tgz._.js +0 -5
  249. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1ctpynv._.js +0 -3
  250. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1jiwfsj._.js +0 -3
  251. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1phc187._.js +0 -3
  252. package/.next/standalone/.next/server/chunks/ssr/_06imw3p._.js +0 -5
  253. package/.next/standalone/.next/server/chunks/ssr/_0h_douw._.js +0 -3
  254. package/.next/standalone/.next/server/chunks/ssr/_1-i_gzc._.js +0 -23
  255. package/.next/standalone/.next/server/chunks/ssr/_1u8-lu2._.js +0 -3
  256. package/.next/standalone/.next/server/chunks/ssr/app_settings_settings-client_tsx_20lq-mq._.js +0 -3
  257. package/.next/standalone/.next/server/chunks/ssr/src_hooks_builtin-policies_ts_09j2ndl._.js +0 -3
  258. package/.next/standalone/.next/static/chunks/094xgi4owxaqf.js +0 -1
  259. package/.next/standalone/.next/static/chunks/1rz20_pz828f3.js +0 -6
  260. package/.next/standalone/.next/static/chunks/2k9f4tyv04809.css +0 -1
  261. package/.next/standalone/.next/static/chunks/2klitrtzpaoe0.js +0 -1
  262. package/.next/standalone/.next/static/chunks/2rshywgeqsyzk.css +0 -2
  263. package/.next/standalone/.next/static/chunks/3pzx4chkhko9k.js +0 -1
  264. package/.next/standalone/.next/static/chunks/3rh5o7e16irrm.js +0 -69
  265. package/.next/standalone/.next/static/chunks/43ufqrz8qo3h-.js +0 -1
  266. /package/.next/standalone/.next/static/{PgeWCHmyVbjRznv2VO7KF → 5yKM8NoTOpUI0MoQl8eo5}/_buildManifest.js +0 -0
  267. /package/.next/standalone/.next/static/{PgeWCHmyVbjRznv2VO7KF → 5yKM8NoTOpUI0MoQl8eo5}/_clientMiddlewareManifest.js +0 -0
  268. /package/.next/standalone/.next/static/{PgeWCHmyVbjRznv2VO7KF → 5yKM8NoTOpUI0MoQl8eo5}/_ssgManifest.js +0 -0
@@ -35,14 +35,23 @@ import {
35
35
  writeCloudCredentials,
36
36
  type CloudCredentials,
37
37
  } from "./cloud-enrollment";
38
- import { updateConfig, readCredentials, writeCredentials } from "./fp-config";
38
+ import { credentialsFile } from "./fp-home";
39
+ import {
40
+ clearJevCloudCredential,
41
+ updateConfig,
42
+ readCredentials,
43
+ writeCredentials,
44
+ writeJevCloudCredential,
45
+ } from "./fp-config";
39
46
  import {
40
47
  introspectKey,
41
48
  hasPermission,
42
49
  describeOrg,
43
50
  PERMISSION_EVENTS,
51
+ PERMISSION_JEV,
44
52
  PERMISSION_POLICIES,
45
53
  } from "./cloud-introspect";
54
+ import type { CloudJevConfigWrite } from "./jev-cloud-connection";
46
55
  import {
47
56
  ingestPath,
48
57
  validateIngestKey,
@@ -139,12 +148,50 @@ export interface CapabilityOutcome {
139
148
  export interface ConnectOutcome {
140
149
  policy: CapabilityOutcome & { policyCount?: number; deployment?: number };
141
150
  ingest: CapabilityOutcome;
151
+ /**
152
+ * Jev through FailproofAI Cloud. Absent when nothing connected, and when the
153
+ * server has no introspect endpoint to say whether the key carries it.
154
+ */
155
+ jev?: JevConnectOutcome;
142
156
  /** Which organisation the key belongs to. Absent on a pre-introspect server. */
143
157
  org?: { id?: string; slug?: string; name?: string };
144
158
  /** True when at least one capability was configured. */
145
159
  anyConfigured: boolean;
146
160
  }
147
161
 
162
+ export interface JevConnectOutcome {
163
+ /** The key carries `jev:evaluate`, and it was stored for Jev. */
164
+ ok: boolean;
165
+ reason?: string;
166
+ /** What became of `jev.json`. Present when `ok`, unless `optIn`. */
167
+ config?: CloudJevConfigWrite;
168
+ /**
169
+ * `ok`, but Jev was deliberately NOT switched on: the connection opted out
170
+ * of transcripts (`sessions !== true`), and there is no `jev.json`. The key
171
+ * is stored; `jev setup --provider failproofai` switches Jev on.
172
+ */
173
+ optIn?: true;
174
+ /**
175
+ * A `--no-transcripts` connection found a `jev.json` already in place that
176
+ * keeps Jev running through FailproofAI Cloud, in this mode. It is left
177
+ * alone like any existing file (never overwritten), but a connection that
178
+ * asked for decisions only is told that Jev still sends more than that.
179
+ */
180
+ stillOn?: "shadow" | "enforce";
181
+ /**
182
+ * Introspect gave no answer about this key's permissions — the server could
183
+ * not be asked (`unreachable`) or predates the endpoint (`unsupported`) — so
184
+ * whether it carries `jev:evaluate` is unknown, and the Jev slot was:
185
+ *
186
+ * - `kept`: it already held THIS key for THIS origin, and was left as it
187
+ * was — the machine's connection is the same one it belongs to;
188
+ * - `cleared`: it held another key or origin — the previous connection's,
189
+ * possibly another org's budget — and was removed;
190
+ * - `none`: there was no slot, and there still is none.
191
+ */
192
+ unconfirmed?: "kept" | "cleared" | "none";
193
+ }
194
+
148
195
  /**
149
196
  * Verify both capabilities, then write only what actually works.
150
197
  *
@@ -282,9 +329,146 @@ writeCloudCredentials(creds);
282
329
  });
283
330
  }
284
331
 
332
+ // ── Jev, last ─────────────────────────────────────────────────────────────
333
+ //
334
+ // Only from introspect's answer. `jev:evaluate` spends the org's budget on
335
+ // every gated tool call, so it is never inferred from a probe succeeding the
336
+ // way the other two capabilities are on a server without introspect — and a
337
+ // machine that connected to nothing gets nothing.
338
+ //
339
+ // There is no Jev-only path: the server refuses a key that carries
340
+ // `jev:evaluate` without `events:add` and `policies:pull`, so a key that gets
341
+ // here with Jev has already configured the other two.
342
+ if (outcome.anyConfigured) {
343
+ if (known && hasPermission(known, PERMISSION_JEV)) {
344
+ // The ORIGIN the key was verified against. `jev-config.ts` sends the key
345
+ // only to a base URL on this origin, so a jev.json pointing anywhere else
346
+ // cannot borrow it.
347
+ writeJevCloudCredential({ url: new URL(input.url).origin, key: input.token });
348
+ // Loaded here and nowhere earlier: a connect whose key does not carry Jev
349
+ // pulls in none of the Jev modules.
350
+ const { cloudJevRunningMode, existingJevConfig, writeCloudJevConfigIfAbsent } = await import("./jev-cloud-connection");
351
+ if (input.sessions === true) {
352
+ outcome.jev = { ok: true, config: writeCloudJevConfigIfAbsent(input.url) };
353
+ } else {
354
+ // `--no-transcripts` never switches Jev on (the user's decision). Jev
355
+ // sends each checked tool call and the recent prompt to FailproofAI
356
+ // Cloud, and someone who just asked for decisions only has not asked
357
+ // for that. The key is stored all the same, so opting in later is one
358
+ // command with no key to paste; jev.json is not written. One that is
359
+ // already there is somebody's decision and is reported as ever — and
360
+ // when it keeps Jev on through FailproofAI Cloud, that is said too, or
361
+ // "Decisions only." would be the last word while Jev keeps sending.
362
+ const existing = existingJevConfig(input.url);
363
+ const stillOn = existing ? cloudJevRunningMode() : null;
364
+ outcome.jev = existing
365
+ ? { ok: true, config: existing, ...(stillOn ? { stillOn } : {}) }
366
+ : { ok: true, optIn: true };
367
+ }
368
+ } else if (known) {
369
+ // Introspect ANSWERED, and the key does not carry Jev. This connection
370
+ // replaces the last one, and the last key's Jev slot describes a
371
+ // connection this machine no longer has — possibly another org's budget.
372
+ // Dropped, so Jev never spends on a key it was not just handed. (A Cloud
373
+ // jev.json then reads `key-lacks-jev`: off, and said.)
374
+ clearJevCloudCredential();
375
+ outcome.jev = { ok: false, reason: missing(PERMISSION_JEV) };
376
+ } else {
377
+ // No answer about this key: a 502 or a network blip on introspect
378
+ // (`unreachable`), or a server with no introspect at all (`unsupported`).
379
+ // Neither says the key LACKS Jev, so neither is a reason to switch Jev
380
+ // off — a reconnect during a transient outage used to do exactly that,
381
+ // silently.
382
+ //
383
+ // But neither says it HAS Jev, and the slot is only ever spent against.
384
+ // So it is kept only when it already holds this very key for this very
385
+ // origin: then the connection just verified IS the one it belongs to,
386
+ // and keeping it changes nothing about whose budget Jev spends. A slot
387
+ // holding any other key or origin is the previous connection's, and the
388
+ // machine is not connected with that key any more — the rule above,
389
+ // which wins whenever the answer is not "yes".
390
+ //
391
+ // `unsupported` is decided the same way, and conservatively: a server
392
+ // that predates introspect predates the Jev route too, so a kept slot
393
+ // there can only fall back with `http-404` — never spend — and clearing
394
+ // it would turn Jev off on no evidence. It gets no line when there was
395
+ // no slot, because on such a server there is nothing to say about Jev.
396
+ const previous = readCredentials().jev;
397
+ if (!previous) {
398
+ if (identity.kind === "unreachable") outcome.jev = { ok: false, unconfirmed: "none" };
399
+ } else if (previous.key === input.token && previous.url === new URL(input.url).origin) {
400
+ outcome.jev = { ok: false, unconfirmed: "kept" };
401
+ } else {
402
+ clearJevCloudCredential();
403
+ outcome.jev = { ok: false, unconfirmed: "cleared" };
404
+ }
405
+ }
406
+ }
407
+
285
408
  return outcome;
286
409
  }
287
410
 
411
+ /**
412
+ * The Jev line(s) for `describeOutcome`: whether FailproofAI Cloud runs Jev for
413
+ * this machine now, and — the one case worth a second line — why an existing
414
+ * `jev.json` was not touched.
415
+ */
416
+ function jevLines(outcome: ConnectOutcome): string[] {
417
+ const jev = outcome.jev;
418
+ if (!jev) return [];
419
+ if (jev.unconfirmed === "cleared") {
420
+ return [
421
+ " Jev could not confirm this key's Jev permission, and the Jev key stored before was a different one, so it was removed: Jev through FailproofAI Cloud is off. Run `failproofai config --token <key>` again to retry.",
422
+ ];
423
+ }
424
+ if (jev.unconfirmed) return [" Jev could not confirm the key's Jev permission; left as it was."];
425
+ if (!jev.ok) {
426
+ return [` Jev not through FailproofAI Cloud: ${jev.reason ?? `that key does not carry \`${PERMISSION_JEV}\``}.`];
427
+ }
428
+ if (jev.optIn) {
429
+ // One line, and nothing that reads as "on": this connection asked for
430
+ // decisions only, and Jev would send more than that.
431
+ return [
432
+ " Jev available on this key, not switched on (--no-transcripts): it sends each checked tool call and the recent prompt to FailproofAI Cloud for evaluation. To switch it on: `failproofai jev setup --provider failproofai`.",
433
+ ];
434
+ }
435
+ const config = jev.config;
436
+ if (!config || config.status === "written") {
437
+ // Plain http (loopback only) is accepted in shadow mode and nowhere else, so
438
+ // the enforce command would be refused there, by the CLI and the dashboard.
439
+ const plainHttp = config?.status === "written" && new URL(config.baseUrl).protocol === "http:";
440
+ return [
441
+ ` Jev on through FailproofAI Cloud, in shadow mode: logged, not enforced (${config?.path ?? "jev.json"}).`,
442
+ plainHttp
443
+ ? " Enforce needs an https FailproofAI Cloud URL: reconnect with `failproofai config --token <key> --url https://…`. Over plain http Jev stays in shadow mode."
444
+ : " Enforce it with `failproofai jev setup --mode enforce`, or from the dashboard.",
445
+ ];
446
+ }
447
+ if (config.status === "kept") {
448
+ const lines = [` Jev key stored; ${config.path} already exists and was left as configured.`];
449
+ if (config.otherOrigin) {
450
+ lines.push(
451
+ config.jevOff?.why === "off"
452
+ ? ` It points at ${config.otherOrigin} and has Jev switched off (mode off), so Jev is off. To point it here and turn it on: \`failproofai jev setup --provider failproofai --mode shadow\`.`
453
+ : ` It points at ${config.otherOrigin}, so Jev stays off until you run \`failproofai jev setup --provider failproofai\`.`,
454
+ );
455
+ } else if (config.jevOff?.why === "refused") {
456
+ lines.push(
457
+ ` It was refused (${config.jevOff.problem}), so Jev is off. ${config.jevOff.fix ? `Fix: \`${config.jevOff.fix}\`.` : "Write a valid one: `failproofai jev setup --provider failproofai`."}`,
458
+ );
459
+ } else if (config.jevOff?.why === "off") {
460
+ lines.push(" It has Jev switched off (mode off), so Jev is off. To turn it on: `failproofai jev setup --mode shadow`.");
461
+ }
462
+ if (jev.stillOn) {
463
+ lines.push(
464
+ ` Jev is still on through FailproofAI Cloud (${jev.stillOn} mode): it sends each checked tool call and the recent prompt to FailproofAI Cloud. To switch it off: \`failproofai jev setup --mode off\`.`,
465
+ );
466
+ }
467
+ return lines;
468
+ }
469
+ return [` Jev key stored, but Jev was not turned on: ${config.problem}.`];
470
+ }
471
+
288
472
  /**
289
473
  * How to describe the outcome to someone at a terminal.
290
474
  *
@@ -311,6 +495,7 @@ export function describeOutcome(outcome: ConnectOutcome, machineId: string, url:
311
495
  const n = outcome.policy.policyCount ?? 0;
312
496
  lines.push(` Policy ${n} polic${n === 1 ? "y" : "ies"} assigned (deployment ${outcome.policy.deployment ?? 0}).`);
313
497
  lines.push(` Dashboard hook activity will be sent to ${ingestUrlFor(url)}.`);
498
+ lines.push(...jevLines(outcome));
314
499
  return lines;
315
500
  }
316
501
 
@@ -322,6 +507,7 @@ export function describeOutcome(outcome: ConnectOutcome, machineId: string, url:
322
507
  lines.push("");
323
508
  lines.push(" Enforcement works. Nothing will appear in the dashboard until this");
324
509
  lines.push(" key also carries `events:add`, or you re-run --connect with one that does.");
510
+ lines.push(...jevLines(outcome));
325
511
  return lines;
326
512
  }
327
513
 
@@ -332,6 +518,7 @@ export function describeOutcome(outcome: ConnectOutcome, machineId: string, url:
332
518
  lines.push("");
333
519
  lines.push(" This machine keeps enforcing its LOCAL policies and will report what");
334
520
  lines.push(" they decide, but will not receive centrally-managed ones.");
521
+ lines.push(...jevLines(outcome));
335
522
  return lines;
336
523
  }
337
524
 
@@ -346,6 +533,8 @@ export function configuredPaths(outcome: ConnectOutcome): string[] {
346
533
  const paths: string[] = [];
347
534
  if (outcome.policy.ok) paths.push(cloudCredentialPath());
348
535
  if (outcome.ingest.ok) paths.push(ingestPath());
536
+ // The Jev slot is always in credentials.json, never behind the JSON override.
537
+ if (outcome.jev?.ok) paths.push(credentialsFile());
349
538
  // Deduplicated because layout 2 consolidated both credentials into
350
539
  // `credentials.toml`, so the two capabilities now name the SAME file and the
351
540
  // closing note read "stored in <path> and <path>" — the same path, twice.
@@ -20,9 +20,13 @@ import {
20
20
  daemonVersionSkew,
21
21
  } from "./daemon-service";
22
22
  import { clearActiveCloudManagedPolicies } from "./cloud-managed-policies";
23
- import { optsFor, rows as kitRows, stack, warning } from "./tui";
23
+ import { TOKEN_ON_ARGV, optsFor, rows as kitRows, stack, warning } from "./tui";
24
24
  import { deliveryHealth, deliveryHealthLine } from "./delivery-health";
25
- import { readVersionFile, readCredentials } from "./fp-config";
25
+ import { clearJevCloudCredential, readVersionFile, readCredentials } from "./fp-config";
26
+ // A CLI command's import, never the hook path's: `jev-cloud-connection` reaches
27
+ // `semantic/jev-config`, which a machine without jev.json must not load while
28
+ // evaluating a tool call. `config --disconnect` is not that.
29
+ import { removeCloudJevConfig } from "./jev-cloud-connection";
26
30
  import { version as cliVersion } from "../../package.json";
27
31
  import { daemonSocketPresent } from "./daemon-client";
28
32
  import {
@@ -174,16 +178,26 @@ function daemonWarning(status: ReturnType<typeof daemonServiceStatus>): string[]
174
178
  ];
175
179
  }
176
180
 
181
+ /**
182
+ * What `config --token` (and `config --connect … --token`) ends with, connected
183
+ * or not: every Jev remedy sends people to that spelling, and the key is in
184
+ * history either way. `jev setup --token` says the same first line.
185
+ */
186
+ export const CONFIG_TOKEN_HISTORY_WARNING = [
187
+ TOKEN_ON_ARGV,
188
+ "Next time, run `failproofai config` with the key in FAILPROOFAI_CLOUD_TOKEN (from a secret store, or `read -rs`) instead of --token — and rotate this one if it matters.",
189
+ ];
190
+
177
191
  export async function runConnectCommand(opts: ConnectOptions): Promise<CommandResult> {
178
192
  if (!opts.url) return { exitCode: 1, lines: ["--connect needs a URL, e.g. --connect https://be.failproof.ai"] };
179
193
  if (!opts.token) {
180
194
  return {
181
195
  exitCode: 1,
182
196
  lines: [
183
- "--connect needs a machine token: --token <key>",
197
+ "--connect needs this machine's key: set FAILPROOFAI_CLOUD_TOKEN (preferred), or pass --token <key>.",
184
198
  "",
185
- "Create an API key carrying only the `policies:pull` permission for this",
186
- "machine. Do not use an admin key.",
199
+ "Create it with the \"machine\" preset on the dashboard's Keys page",
200
+ "(events:add, policies:pull, jev:evaluate). Do not use an admin key.",
187
201
  ],
188
202
  };
189
203
  }
@@ -324,6 +338,13 @@ export function runDisconnectCommand(): CommandResult {
324
338
  // leave the machine still shipping activity to a cloud the user believes
325
339
  // they have left — the one outcome nobody expects from this command.
326
340
  const removedIngest = clearIngestCredential();
341
+ // And spending: the Jev key goes with the rest, so no tool call after this
342
+ // one is charged to an org this machine has left. The Cloud's own jev.json
343
+ // goes too — it names a route that now has no key — unless it is switched
344
+ // off, the owner's opt-out that must outlive a reconnect; a BYOK one stays,
345
+ // because it never depended on the Cloud and is not the Cloud's to delete.
346
+ const removedJevKey = clearJevCloudCredential();
347
+ const jevConfig = removeCloudJevConfig();
327
348
  // Stop ENFORCING them too, not merely refreshing them. Clearing the
328
349
  // credential ends the daemon's polling; every artifact already on disk stayed
329
350
  // referenced by `active.json` and kept being loaded on every tool call — so a
@@ -337,8 +358,35 @@ export function runDisconnectCommand(): CommandResult {
337
358
  // machine is provably silent instead of silent-by-happenstance.
338
359
  updateConfig({ mode: "oss" });
339
360
 
340
- if (!removed && !existing && !hadIngest && !stoppedManaged) {
341
- return { exitCode: 0, lines: ["This machine is not connected to FailproofAI Cloud."] };
361
+ const jevLines =
362
+ jevConfig.status === "removed"
363
+ ? [` Jev through FailproofAI Cloud is off: removed ${jevConfig.path}. Hooks run the regex policies.`]
364
+ : jevConfig.status === "error"
365
+ ? [
366
+ removedJevKey
367
+ ? ` ! The FailproofAI Cloud key for Jev is gone, so Jev is off — but ${jevConfig.problem}.`
368
+ : ` ! ${jevConfig.problem}.`,
369
+ ...(jevConfig.setAside ? [` To put it back: mv ${jevConfig.setAside} ${jevConfig.path}`] : []),
370
+ ]
371
+ : jevConfig.status === "kept-off"
372
+ ? [` Jev stays switched off: ${jevConfig.path} (mode off) was kept, so connecting again leaves it off.`]
373
+ : jevConfig.status === "kept" && jevConfig.provider !== null
374
+ ? [` ${jevConfig.path} (provider ${jevConfig.provider}) is your own Jev setup and was left in place.`]
375
+ : jevConfig.status === "set-aside"
376
+ ? [
377
+ ` ! ${jevConfig.path} was being checked when another jev.json was written in its place. Nothing was deleted: the new one is at ${jevConfig.path},`,
378
+ ` and the one that was there (provider ${jevConfig.provider ?? "unreadable"}, not FailproofAI Cloud's) is kept at ${jevConfig.setAside}.`,
379
+ ]
380
+ : removedJevKey
381
+ ? [" Jev through FailproofAI Cloud is off: its key was removed."]
382
+ : [];
383
+
384
+ if (!removed && !existing && !hadIngest && !stoppedManaged && !removedJevKey && jevConfig.status !== "removed") {
385
+ // Nothing was connected — but the jev.json check ran all the same, and a
386
+ // file it could not put back where it was (a bring-your-own-key setup,
387
+ // moved aside) is not nothing: left unsaid, that Jev is simply gone.
388
+ const unsettled = jevConfig.status === "error" || jevConfig.status === "set-aside";
389
+ return { exitCode: 0, lines: ["This machine is not connected to FailproofAI Cloud.", ...(unsettled ? jevLines : [])] };
342
390
  }
343
391
 
344
392
  const lines = [
@@ -348,6 +396,7 @@ export function runDisconnectCommand(): CommandResult {
348
396
  ? " Cloud-managed policies stop being enforced and stop being refreshed.\n" +
349
397
  " Local builtin, custom and convention policies are unaffected."
350
398
  : " Local builtin, custom and convention policies are unaffected.",
399
+ ...jevLines,
351
400
  ];
352
401
  if (removedIngest) {
353
402
  // Named honestly. The collector manager starts once for the daemon's
@@ -377,7 +426,7 @@ export function versionStatusLines(): string[] {
377
426
  const daemon = recorded?.daemon ?? "not installed";
378
427
  return [
379
428
  `CLI ${cliVersion} · daemon ${daemon}${skew ? " (STALE)" : ""} · layout ${recorded?.layout ?? "-"}`,
380
- ...(skew ? [" Run `failproofai config` to update the daemon."] : []),
429
+ ...(skew ? [" Run `failproofai update` to update the daemon."] : []),
381
430
  ];
382
431
  }
383
432
 
@@ -135,6 +135,12 @@ export async function introspectKey(
135
135
  /** The permission each capability needs. Named so the messages can quote them. */
136
136
  export const PERMISSION_EVENTS = "events:add";
137
137
  export const PERMISSION_POLICIES = "policies:pull";
138
+ /**
139
+ * Jev through FailproofAI Cloud, charged to the key's org. The server refuses a
140
+ * key that carries it without both of the above, so a key with it always
141
+ * connects for policy and reporting too — there is no Jev-only connection.
142
+ */
143
+ export const PERMISSION_JEV = "jev:evaluate";
138
144
 
139
145
  export function hasPermission(identity: KeyIdentity, permission: string): boolean {
140
146
  return identity.permissions.includes(permission);
@@ -8,6 +8,8 @@ import { createHash } from "node:crypto";
8
8
  import { existsSync, readFileSync, realpathSync, rmSync } from "node:fs";
9
9
  import { isAbsolute, relative, resolve } from "node:path";
10
10
  import { cloudPoliciesDir } from "./fp-home";
11
+ import { authorityFieldsOf } from "./policy-authority";
12
+ import type { PolicyAuthority } from "./policy-types";
11
13
 
12
14
  /**
13
15
  * Active-manifest schema versions this reader accepts.
@@ -44,6 +46,19 @@ export interface CloudManagedPolicyArtifact {
44
46
  sha256: string;
45
47
  path: string;
46
48
  deployment: number;
49
+ /**
50
+ * Whether Jev may clear this policy's verdict once it is configured, as the
51
+ * ASSIGNMENT declares it — code inside the artifact cannot grant itself this.
52
+ * Absent means `hard`, which is what keeps Jev from weakening central
53
+ * enforcement by default: a cloud policy is only ever reviewable because
54
+ * whoever deployed it said so. Applies to every hook the artifact registers.
55
+ *
56
+ * Read and validated here; the daemon has to carry it into `active.json`
57
+ * (`ActivePolicy` in `cloud_policies.rs`) before a deployment can set it.
58
+ */
59
+ authority?: PolicyAuthority;
60
+ /** The semantic policies that must all be asked and none answer `deny`; see `authority`. */
61
+ reviewedBy?: string[];
47
62
  }
48
63
 
49
64
  interface ActiveManifest {
@@ -55,6 +70,8 @@ interface ActiveManifest {
55
70
  effect?: string;
56
71
  sha256: string;
57
72
  path: string;
73
+ authority?: unknown;
74
+ reviewedBy?: unknown;
58
75
  }>;
59
76
  }
60
77
 
@@ -206,6 +223,11 @@ export function readActiveCloudManagedPolicies(): CloudManagedPolicyArtifact[] {
206
223
  sha256: policy.sha256,
207
224
  path,
208
225
  deployment: manifest.deployment,
226
+ // Unlike `effect`, a malformed authority is dropped rather than refused:
227
+ // dropping it makes this policy `hard`, the default that keeps enforcing,
228
+ // while refusing would take the whole deployment down over an optional
229
+ // field. Absent stays absent.
230
+ ...authorityFieldsOf(policy as unknown as Record<string, unknown>),
209
231
  };
210
232
  });
211
233
  }
@@ -1178,7 +1178,18 @@ export async function runConfigureWizard(
1178
1178
  // did — it is not a trusted back door. http stays loopback-only, so a
1179
1179
  // bearer token still cannot be exported onto the wire in clear by
1180
1180
  // setting a variable.
1181
- const override = process.env.FAILPROOFAI_CLOUD_URL?.trim();
1181
+ //
1182
+ // `--url` comes first. It was read into `answers.url` and then only
1183
+ // ever used as a CONDITION above, never as the URL, so
1184
+ // `config --token <key> --url <X>` connected to the env value or the
1185
+ // hosted default and ignored X — reporting a machine somewhere its
1186
+ // operator had explicitly said not to. The CLI fills `answers.url` from
1187
+ // `--url`, falling back to FAILPROOFAI_CLOUD_URL, so the source named
1188
+ // on screen is whichever of the two the value actually is.
1189
+ const envOverride = process.env.FAILPROOFAI_CLOUD_URL?.trim();
1190
+ const flagOverride = answers.url?.trim();
1191
+ const override = flagOverride || envOverride;
1192
+ const source = flagOverride && flagOverride !== envOverride ? "--url" : "FAILPROOFAI_CLOUD_URL";
1182
1193
  if (override) {
1183
1194
  const validated = validateCloudUrl(cloudBaseFor(override));
1184
1195
  if (!validated.ok) {
@@ -1186,7 +1197,7 @@ export async function runConfigureWizard(
1186
1197
  // wants THAT endpoint, and quietly reporting a machine to the
1187
1198
  // hosted service instead is the one outcome they did not ask for.
1188
1199
  stdout.write(
1189
- `\nFAILPROOFAI_CLOUD_URL is set to "${override}", which cannot be used: ` +
1200
+ `\n${source === "--url" ? "--url is" : "FAILPROOFAI_CLOUD_URL is set to"} "${override}", which cannot be used: ` +
1190
1201
  `${validated.reason}\n`,
1191
1202
  );
1192
1203
  return cancel();
@@ -1196,7 +1207,7 @@ export async function runConfigureWizard(
1196
1207
  // matters and a machine reporting somewhere unexpected is exactly the
1197
1208
  // thing nobody notices until they go looking for data that is not
1198
1209
  // there.
1199
- stdout.write(`\nUsing ${url} (from FAILPROOFAI_CLOUD_URL).\n`);
1210
+ stdout.write(`\nUsing ${url} (from ${source}).\n`);
1200
1211
  } else {
1201
1212
  url = cloudBaseFor(DEFAULT_INGEST_URL);
1202
1213
  }
@@ -1507,9 +1518,13 @@ export async function runConfigureWizard(
1507
1518
  token: connect.token,
1508
1519
  machineId: connect.machineId,
1509
1520
  machineLabel: connect.machineLabel,
1510
- // Both streams, as disclosed at the connect question. This is the one
1511
- // place that decision becomes a written setting.
1512
- sessions: true,
1521
+ // Both streams, as disclosed at the connect question, unless the run
1522
+ // said `--no-transcripts`. This is the one place that decision becomes
1523
+ // a written setting — and it used to be a literal `true`, so the flag
1524
+ // was parsed, carried here in `answers`, and silently ignored: a fleet
1525
+ // that asked for decisions only shipped every prompt, file and command
1526
+ // output. The separate `--connect` path always honoured it.
1527
+ sessions: answers.noTranscripts !== true,
1513
1528
  });
1514
1529
  connected = outcome.anyConfigured;
1515
1530
  // Show the human label with the id in parentheses when they differ.
@@ -1520,6 +1535,11 @@ export async function runConfigureWizard(
1520
1535
  for (const line of describeOutcome(outcome, shownAs, connect.url)) {
1521
1536
  stdout.write(`${line}\n`);
1522
1537
  }
1538
+ // Said when it took effect, as `--connect` says it: the default carries
1539
+ // prompts and file contents, so the opt-out is worth confirming.
1540
+ if (outcome.ingest.ok && answers.noTranscripts === true) {
1541
+ stdout.write(" Session transcripts are NOT being sent (--no-transcripts). Decisions only.\n");
1542
+ }
1523
1543
  // Never the key, the URL, or the count — only that it happened and which
1524
1544
  // capabilities the server actually granted.
1525
1545
  void emit("configure_connect", {