failproofai 1.0.11-beta.4 → 1.0.12-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (300) 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 +3 -3
  4. package/.next/standalone/.next/required-server-files.json +1 -1
  5. package/.next/standalone/.next/server/app/_global-error/page/build-manifest.json +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 +9 -9
  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 +3 -3
  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 +3 -3
  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]__0-ha5ydqq0mws._.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]__0jz5xqu-p_lfc._.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]__1ey11fel2q2qw._.js +1 -1
  96. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1hqpg6vgmfexv._.js +3 -0
  97. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1ztigqa01tigq._.js +1 -1
  98. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__1izwqj_ij_9x_._.js → [root-of-the-server]__20xe05hm5u8_1._.js} +1 -1
  99. package/.next/standalone/.next/server/chunks/{_1ixl-kxq_ctsa._.js → _0kc-piux3hady._.js} +2 -2
  100. package/.next/standalone/.next/server/chunks/_0tovk6q0miud6._.js +1 -1
  101. package/.next/standalone/.next/server/chunks/_0trp3ycqv17cl._.js +1 -1
  102. package/.next/standalone/.next/server/chunks/_1vslkoe35wok6._.js +1 -1
  103. package/.next/standalone/.next/server/chunks/lib_11qmqmccehybz._.js +1 -1
  104. package/.next/standalone/.next/server/chunks/lib_1sezqnatvr8j-._.js +1 -1
  105. package/.next/standalone/.next/server/chunks/lib_antigravity-projects_ts_0hdx6fkrln72c._.js +1 -1
  106. package/.next/standalone/.next/server/chunks/lib_codex-projects_ts_0di6zenec7h7n._.js +1 -1
  107. package/.next/standalone/.next/server/chunks/lib_copilot-projects_ts_00-tojoja20ke._.js +1 -1
  108. package/.next/standalone/.next/server/chunks/lib_cursor-projects_ts_1carno5mv3ix_._.js +1 -1
  109. package/.next/standalone/.next/server/chunks/lib_factory-projects_ts_1eo_bk-vm4wdz._.js +1 -1
  110. package/.next/standalone/.next/server/chunks/lib_hermes-projects_ts_0h9ny-woruqft._.js +1 -1
  111. package/.next/standalone/.next/server/chunks/lib_log-entries_ts_0e1mnh5npsol1._.js +1 -1
  112. package/.next/standalone/.next/server/chunks/lib_openclaw-projects_ts_0gc-p24z7gzy8._.js +1 -1
  113. package/.next/standalone/.next/server/chunks/lib_opencode-projects_ts_1r-bu98cz4660._.js +1 -1
  114. package/.next/standalone/.next/server/chunks/lib_pi-projects_ts_1_cy5lfxd21kv._.js +1 -1
  115. package/.next/standalone/.next/server/chunks/lib_projects_ts_01v279z8xccq4._.js +1 -1
  116. package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4vkpxxu7._.js +1 -1
  117. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__01j58mdcdw0vn._.js +3 -0
  118. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__08ch3staq3ejw._.js +1 -1
  119. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0_a8z2ldp2v3n._.js +3 -0
  120. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0bigvy9xmv2ka._.js +1 -1
  121. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ffu2-38y03ic._.js +3 -0
  122. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0g8b0kyorya-t._.js +3 -0
  123. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0h86bl2qf0k_o._.js +1 -1
  124. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0pia5h3p8re4c._.js +1 -1
  125. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__075uro8t92s0_._.js → [root-of-the-server]__0pwj2h2efe5f-._.js} +3 -3
  126. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0b28bm2e-y0rp._.js → [root-of-the-server]__0ts0fg5yih1c1._.js} +2 -2
  127. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0zn1d4blhd3bu._.js +3 -0
  128. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1-ey9fgesfbc0._.js +1 -1
  129. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__15usvs-ms-0hf._.js +1 -1
  130. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__16gb3_92zvk5x._.js +1 -1
  131. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__17r4zrwanhp6r._.js +3 -0
  132. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1avi2kypusyb_._.js +1 -1
  133. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1lnfv02ucky7m._.js +3 -0
  134. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1mc9-zlnh656_._.js +3 -0
  135. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1r7drlqli-ado._.js +1 -1
  136. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1s2-ck3k3rsoo._.js +3 -0
  137. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1l1qgu5mfapkh._.js → [root-of-the-server]__1vx7o8ukefudh._.js} +1 -1
  138. package/.next/standalone/.next/server/chunks/ssr/_0eoura3_9gjb-._.js +1 -1
  139. package/.next/standalone/.next/server/chunks/ssr/_0pedwblqdoh58._.js +1 -1
  140. package/.next/standalone/.next/server/chunks/ssr/_1_ozgifqv1ssi._.js +1 -1
  141. package/.next/standalone/.next/server/chunks/ssr/_1djqs9i27e4kg._.js +1 -1
  142. package/.next/standalone/.next/server/chunks/ssr/{_16u8ppjzw0upc._.js → _1ve8y151ua7qx._.js} +2 -2
  143. package/.next/standalone/.next/server/chunks/ssr/_next-internal_server_app_policies_page_actions_1sp2-yo5_vm5f.js +2 -2
  144. package/.next/standalone/.next/server/chunks/ssr/app_actions_get-scheduled-audit_ts_0ei9snixb5fd-._.js +1 -1
  145. package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47q0xq5w._.js +1 -1
  146. package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x33jqb6._.js +1 -1
  147. package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpcz0uxur._.js +1 -1
  148. package/.next/standalone/.next/server/chunks/ssr/app_settings_02tf1h47jmhhd._.js +1 -1
  149. package/.next/standalone/.next/server/chunks/ssr/{node_modules_html-to-image_es_index_0_zbgw5i5c7_a.js → node_modules_html-to-image_es_index_00jxj8foxqz5t.js} +1 -1
  150. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_0janj0i6dqko7._.js +2 -2
  151. package/.next/standalone/.next/server/chunks/ssr/package_json_[json]_cjs_013tntikdft59._.js +1 -1
  152. package/.next/standalone/.next/server/middleware-build-manifest.js +23 -23
  153. package/.next/standalone/.next/server/middleware.js +2 -2
  154. package/.next/standalone/.next/server/pages/404.html +1 -1
  155. package/.next/standalone/.next/server/pages/500.html +1 -1
  156. package/.next/standalone/.next/server/preview-props.json +3 -3
  157. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  158. package/.next/standalone/.next/server/server-reference-manifest.json +23 -23
  159. package/.next/standalone/.next/static/chunks/{0frxv4_m-m2u5.js → 063al_q720fkj.js} +1 -1
  160. package/.next/standalone/.next/static/chunks/{3c5k3z60x6vuh.js → 0a-ccsp3xmypz.js} +1 -1
  161. package/.next/standalone/.next/static/chunks/{2ly73y3n0ddxn.js → 0pjxnp927y7_j.js} +1 -1
  162. package/.next/standalone/.next/static/chunks/{0ii1av6gw3_74.js → 13jv-xvabeb62.js} +1 -1
  163. package/.next/standalone/.next/static/chunks/2ank2u3apy8m6.js +1 -0
  164. package/.next/standalone/.next/static/chunks/{14prk7fu_3vzm.js → 2meqb9kygrncb.js} +1 -1
  165. package/.next/standalone/.next/static/chunks/2ohktp_-lkv3x.js +1 -0
  166. package/.next/standalone/.next/static/chunks/2py0eldhwz8ay.js +1 -0
  167. package/.next/standalone/.next/static/chunks/{3yxhw5uqrh1rq.js → 2qz5piiir-qqm.js} +1 -1
  168. package/.next/standalone/.next/static/chunks/2tjfp9dirxnku.js +1 -0
  169. package/.next/standalone/.next/static/chunks/{2_2xem_wwddgy.js → 2znt1784j9gd9.js} +1 -1
  170. package/.next/standalone/.next/static/chunks/3tn1bzk094e8e.js +1 -0
  171. package/.next/standalone/fp-cloud-cli/uv.lock +6 -6
  172. package/.next/standalone/hermes-plugin/plugin.yaml +1 -1
  173. package/.next/standalone/node_modules/@next/env/package.json +1 -1
  174. package/.next/standalone/node_modules/@opentelemetry/api/build/src/api/context.js +72 -0
  175. package/.next/standalone/node_modules/@opentelemetry/api/build/src/api/diag.js +84 -0
  176. package/.next/standalone/node_modules/@opentelemetry/api/build/src/api/metrics.js +50 -0
  177. package/.next/standalone/node_modules/@opentelemetry/api/build/src/api/propagation.js +80 -0
  178. package/.next/standalone/node_modules/@opentelemetry/api/build/src/api/trace.js +70 -0
  179. package/.next/standalone/node_modules/@opentelemetry/api/build/src/baggage/context-helpers.js +52 -0
  180. package/.next/standalone/node_modules/@opentelemetry/api/build/src/baggage/internal/baggage-impl.js +44 -0
  181. package/.next/standalone/node_modules/@opentelemetry/api/build/src/baggage/internal/symbol.js +12 -0
  182. package/.next/standalone/node_modules/@opentelemetry/api/build/src/baggage/utils.js +41 -0
  183. package/.next/standalone/node_modules/@opentelemetry/api/build/src/context/NoopContextManager.js +27 -0
  184. package/.next/standalone/node_modules/@opentelemetry/api/build/src/context/context.js +52 -0
  185. package/.next/standalone/node_modules/@opentelemetry/api/build/src/context-api.js +16 -0
  186. package/.next/standalone/node_modules/@opentelemetry/api/build/src/diag/ComponentLogger.js +47 -0
  187. package/.next/standalone/node_modules/@opentelemetry/api/build/src/diag/consoleLogger.js +73 -0
  188. package/.next/standalone/node_modules/@opentelemetry/api/build/src/diag/internal/logLevelLogger.js +34 -0
  189. package/.next/standalone/node_modules/@opentelemetry/api/build/src/diag/types.js +33 -0
  190. package/.next/standalone/node_modules/@opentelemetry/api/build/src/diag-api.js +20 -0
  191. package/.next/standalone/node_modules/@opentelemetry/api/build/src/index.js +71 -0
  192. package/.next/standalone/node_modules/@opentelemetry/api/build/src/internal/global-utils.js +60 -0
  193. package/.next/standalone/node_modules/@opentelemetry/api/build/src/internal/semver.js +111 -0
  194. package/.next/standalone/node_modules/@opentelemetry/api/build/src/metrics/Metric.js +18 -0
  195. package/.next/standalone/node_modules/@opentelemetry/api/build/src/metrics/NoopMeter.js +118 -0
  196. package/.next/standalone/node_modules/@opentelemetry/api/build/src/metrics/NoopMeterProvider.js +20 -0
  197. package/.next/standalone/node_modules/@opentelemetry/api/build/src/metrics-api.js +17 -0
  198. package/.next/standalone/node_modules/@opentelemetry/api/build/src/propagation/NoopTextMapPropagator.js +23 -0
  199. package/.next/standalone/node_modules/@opentelemetry/api/build/src/propagation/TextMapPropagator.js +36 -0
  200. package/.next/standalone/node_modules/@opentelemetry/api/build/src/propagation-api.js +17 -0
  201. package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/NonRecordingSpan.js +58 -0
  202. package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/NoopTracer.js +68 -0
  203. package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/NoopTracerProvider.js +21 -0
  204. package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/ProxyTracer.js +46 -0
  205. package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/ProxyTracerProvider.js +46 -0
  206. package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/SamplingResult.js +33 -0
  207. package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/context-utils.js +71 -0
  208. package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/internal/tracestate-impl.js +94 -0
  209. package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/internal/tracestate-validators.js +35 -0
  210. package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/internal/utils.js +16 -0
  211. package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/invalid-span-constants.js +25 -0
  212. package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/span_kind.js +38 -0
  213. package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/spancontext-utils.js +66 -0
  214. package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/status.js +29 -0
  215. package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/trace_flags.js +18 -0
  216. package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace-api.js +17 -0
  217. package/.next/standalone/node_modules/@opentelemetry/api/build/src/version.js +10 -0
  218. package/.next/standalone/node_modules/@opentelemetry/api/package.json +96 -0
  219. package/.next/standalone/node_modules/next/dist/build/swc/index.js +1 -1
  220. package/.next/standalone/node_modules/next/dist/compiled/next-server/app-page-turbo-experimental.runtime.prod.js +2 -2
  221. package/.next/standalone/node_modules/next/dist/compiled/next-server/app-page-turbo.runtime.prod.js +2 -2
  222. package/.next/standalone/node_modules/next/dist/compiled/next-server/app-route-turbo.runtime.prod.js +1 -1
  223. package/.next/standalone/node_modules/next/dist/lib/patch-incorrect-lockfile.js +3 -3
  224. package/.next/standalone/node_modules/next/dist/server/app-render/async-local-storage.js +1 -1
  225. package/.next/standalone/node_modules/next/dist/server/config.js +1 -1
  226. package/.next/standalone/node_modules/next/dist/server/dev/hot-reloader-turbopack.js +2 -2
  227. package/.next/standalone/node_modules/next/dist/server/dev/hot-reloader-webpack.js +1 -1
  228. package/.next/standalone/node_modules/next/dist/server/lib/app-info-log.js +1 -1
  229. package/.next/standalone/node_modules/next/dist/server/lib/generate-agent-files.js +3 -3
  230. package/.next/standalone/node_modules/next/dist/server/lib/router-server.js +1 -1
  231. package/.next/standalone/node_modules/next/dist/server/lib/start-server.js +1 -1
  232. package/.next/standalone/node_modules/next/dist/server/lib/trace/tracer.js +1 -1
  233. package/.next/standalone/node_modules/next/dist/server/typescript/rules/config.js +2 -2
  234. package/.next/standalone/node_modules/next/dist/server/use-cache/use-cache-wrapper.js +1 -1
  235. package/.next/standalone/node_modules/next/dist/telemetry/anonymous-meta.js +1 -1
  236. package/.next/standalone/node_modules/next/dist/telemetry/events/swc-load-failure.js +1 -1
  237. package/.next/standalone/node_modules/next/dist/telemetry/events/version.js +2 -2
  238. package/.next/standalone/node_modules/next/package.json +11 -11
  239. package/.next/standalone/package.json +11 -11
  240. package/.next/standalone/sdk/python/CHANGELOG.md +22 -3
  241. package/.next/standalone/sdk/python/failproofai_sdk/_redact.py +3 -5
  242. package/.next/standalone/sdk/python/failproofai_sdk/_resolver.py +13 -2
  243. package/.next/standalone/sdk/python/failproofai_sdk/_version.py +1 -1
  244. package/.next/standalone/sdk/python/failproofai_sdk/integrations/otel.py +3 -1
  245. package/.next/standalone/sdk/python/pyproject.toml +19 -0
  246. package/.next/standalone/sdk/python/tests/test_otel.py +25 -0
  247. package/.next/standalone/sdk/python/uv.lock +520 -301
  248. package/.next/standalone/sdk/typescript/CHANGELOG.md +39 -1
  249. package/.next/standalone/sdk/typescript/integration/fixtures/mastra-0/package-lock.json +3 -3
  250. package/.next/standalone/sdk/typescript/integration/fixtures/mastra-1/package-lock.json +4 -13
  251. package/.next/standalone/sdk/typescript/integration/fixtures/mastra-1/package.json +2 -1
  252. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/package-lock.json +166 -175
  253. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/package.json +4 -1
  254. package/.next/standalone/sdk/typescript/package-lock.json +178 -162
  255. package/.next/standalone/sdk/typescript/package.json +1 -1
  256. package/.next/standalone/sdk/typescript/src/integrations/otel.ts +2 -1
  257. package/.next/standalone/sdk/typescript/src/resolver.ts +2 -1
  258. package/.next/standalone/sdk/typescript/src/version.ts +1 -1
  259. package/.next/standalone/sdk/typescript/test/otel.test.ts +25 -0
  260. package/.next/standalone/server.js +1 -1
  261. package/dist/cli.mjs +658 -85
  262. package/dist/worker.mjs +1 -1
  263. package/hermes-plugin/plugin.yaml +1 -1
  264. package/package.json +11 -11
  265. package/src/audit/open-browser.ts +19 -1
  266. package/src/hooks/cloud-connection.ts +4 -1
  267. package/src/hooks/cloud-introspect.ts +5 -2
  268. package/src/hooks/cloud-login.ts +245 -0
  269. package/src/hooks/configure-wizard.ts +311 -15
  270. package/src/hooks/otel-cli.ts +16 -6
  271. package/src/hooks/otel-writers.ts +13 -0
  272. package/src/hooks/tui.ts +271 -0
  273. package/.next/standalone/.next/server/chunks/[externals]__0hjaw70fchx66._.js +0 -3
  274. package/.next/standalone/.next/server/chunks/[root-of-the-server]__07l68zv0hqdiu._.js +0 -3
  275. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0car70pylmvor._.js +0 -3
  276. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0u3i025_setk_._.js +0 -3
  277. package/.next/standalone/.next/server/chunks/[root-of-the-server]__10a2f6s636yc7._.js +0 -3
  278. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1qt5u58xrcuk6._.js +0 -3
  279. package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_077n_4ip5__fu._.js +0 -3
  280. package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_0mqvvxcn6v0op._.js +0 -3
  281. package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_0pb7ds5g0vzgn._.js +0 -3
  282. package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_1gasm5xkeqmm3._.js +0 -3
  283. package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_1q1heqmkhh8l4._.js +0 -3
  284. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0888k4s6spfmh._.js +0 -3
  285. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0_bflu046ep5j._.js +0 -3
  286. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0fdwgktjfhedo._.js +0 -3
  287. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0s4deza787asx._.js +0 -3
  288. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__18qe-hu0gwqm4._.js +0 -3
  289. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1_p_9xe520fex._.js +0 -3
  290. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1fmhm8_s9i4re._.js +0 -3
  291. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1g76awtnmimd1._.js +0 -3
  292. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1pczevlpk5lxh._.js +0 -3
  293. package/.next/standalone/.next/static/chunks/01c3z7b9td1j-.js +0 -1
  294. package/.next/standalone/.next/static/chunks/08-yz-9n_9j-u.js +0 -1
  295. package/.next/standalone/.next/static/chunks/0m-tv1y6ghhtk.js +0 -1
  296. package/.next/standalone/.next/static/chunks/2q25h0pqaw62i.js +0 -1
  297. package/.next/standalone/.next/static/chunks/2sbmeexp-ixmd.js +0 -1
  298. /package/.next/standalone/.next/static/{ZxaJShYHqvP19gYm49Rao → SNr7o_-G4kNBQTR-iLZMM}/_buildManifest.js +0 -0
  299. /package/.next/standalone/.next/static/{ZxaJShYHqvP19gYm49Rao → SNr7o_-G4kNBQTR-iLZMM}/_clientMiddlewareManifest.js +0 -0
  300. /package/.next/standalone/.next/static/{ZxaJShYHqvP19gYm49Rao → SNr7o_-G4kNBQTR-iLZMM}/_ssgManifest.js +0 -0
@@ -30,20 +30,26 @@ import { dirname, resolve, sep } from "node:path";
30
30
  import { CORE_SOURCE } from "./pack-store";
31
31
 
32
32
  import {
33
+ BACK,
33
34
  collapseAfter,
34
35
  colorsEnabled,
35
36
  multiSelect,
36
37
  OPEN_SOURCE,
37
38
  optsFor,
38
39
  paint,
40
+ promptBrowserLogin,
39
41
  promptCloudKey,
40
42
  screenKit,
43
+ selectOne,
41
44
  type CloudKeyAnswer,
42
45
  type MultiChoice,
43
46
  type OpenSource,
47
+ type SelectChoice,
44
48
  type TTYIn,
45
49
  type TTYOut,
46
50
  } from "./tui";
51
+ import { claimLogin, machineOs, pollLogin, startLogin, type LoginOrg } from "./cloud-login";
52
+ import { canOpenBrowser, openUrl } from "../audit/open-browser";
47
53
  import {
48
54
  DEFAULT_INGEST_URL,
49
55
  readIngestCredential,
@@ -998,6 +1004,190 @@ export async function runConfigureWizard(
998
1004
  stdout,
999
1005
  });
1000
1006
 
1007
+ // A key typed after picking "Paste an API key" from the menu. Same field as
1008
+ // above minus the saved key, which the menu already offered as "keep"; Tab is
1009
+ // the way back to the menu, so it never means open source here.
1010
+ const askKey = (): Promise<CloudKeyAnswer | OpenSource | null> =>
1011
+ promptCloudKey({
1012
+ message: "Connect to cloud",
1013
+ meta: source ? `${host} · from ${source}` : host,
1014
+ tabHint: "go back",
1015
+ emptyError: "Paste a key, or press tab to go back.",
1016
+ check: async (key) => {
1017
+ if (!url) return { ok: false, line: badUrl ?? "No usable endpoint." };
1018
+ const r = await checkCloudKey(url, key);
1019
+ if (r.ok) {
1020
+ typedOrg = r.org;
1021
+ return { ok: true, line: r.note };
1022
+ }
1023
+ return { ok: false, line: r.refused ? `That key was refused: ${r.reason}.` : `Couldn't check the key: ${r.reason}.` };
1024
+ },
1025
+ collapsed: (answer) => (answer === OPEN_SOURCE ? [] : [...cloudLines(planFor(answer)), ""]),
1026
+ stdin,
1027
+ stdout,
1028
+ });
1029
+
1030
+ // The browser login. Resolves the approval, BACK for the menu of other
1031
+ // options (Tab / Esc, or a cloud that cannot do this), or null when the person
1032
+ // cancelled the whole run.
1033
+ type Approval = Extract<CloudPlan, { kind: "login" }>;
1034
+ // Set once the cloud says it has no browser login; the menu then drops it.
1035
+ let loginUnsupported = false;
1036
+ const askLogin = (endpoint: string): Promise<{ value: Approval } | typeof BACK | null> => {
1037
+ let pollSecret = "";
1038
+ return promptBrowserLogin<Approval>({
1039
+ message: "Connect to cloud",
1040
+ meta: source ? `${host} · from ${source}` : host,
1041
+ machineLabel,
1042
+ start: async () => {
1043
+ const r = await startLogin(endpoint, { label: machineLabel, os: machineOs(), cliVersion });
1044
+ if (r.kind === "ok") {
1045
+ pollSecret = r.pollSecret;
1046
+ void emit("configure_cloud_login", { step: "started" });
1047
+ return { ok: true, url: r.verificationUrl, expiresIn: r.expiresIn, interval: r.interval };
1048
+ }
1049
+ if (r.kind === "unsupported") {
1050
+ void emit("configure_cloud_login", { step: "unsupported" });
1051
+ loginUnsupported = true;
1052
+ return { ok: false, retryable: false, line: `${host} doesn't support logging in from here yet.` };
1053
+ }
1054
+ return {
1055
+ ok: false,
1056
+ retryable: true,
1057
+ line: r.kind === "refused" ? `Couldn't start the login: ${r.reason}.` : `Couldn't reach ${host}: ${r.reason}.`,
1058
+ };
1059
+ },
1060
+ poll: async () => {
1061
+ const p = await pollLogin(endpoint, pollSecret);
1062
+ switch (p.kind) {
1063
+ case "approved":
1064
+ void emit("configure_cloud_login", { step: "approved" });
1065
+ return {
1066
+ state: "approved",
1067
+ value: {
1068
+ kind: "login",
1069
+ pollSecret,
1070
+ org: p.org,
1071
+ approvedBy: p.approvedBy,
1072
+ keyName: p.keyName,
1073
+ permissions: p.permissions,
1074
+ },
1075
+ };
1076
+ case "pending":
1077
+ return { state: "pending", interval: p.interval };
1078
+ case "slow_down":
1079
+ return { state: "slow_down" };
1080
+ case "denied":
1081
+ void emit("configure_cloud_login", { step: "denied" });
1082
+ return { state: "denied" };
1083
+ case "unreachable":
1084
+ return { state: "unreachable", line: p.reason };
1085
+ // Expired, already claimed, or swept: in every case this link is done.
1086
+ default:
1087
+ return { state: "expired" };
1088
+ }
1089
+ },
1090
+ open: (link) => {
1091
+ if (!canOpenBrowser()) return false;
1092
+ openUrl(link);
1093
+ return true;
1094
+ },
1095
+ collapsed: (plan) => [...cloudLines(plan), ""],
1096
+ stdin,
1097
+ stdout,
1098
+ });
1099
+ };
1100
+
1101
+ // The interactive CONNECT step. A machine with no connection, or whose saved
1102
+ // key is refused, starts the browser login straight away — Tab or Esc there
1103
+ // opens the other options. A machine that is connected with a working key gets
1104
+ // the menu, "keep" first, so re-running config never opens a browser by itself.
1105
+ const chooseConnection = async (): Promise<CloudPlan | null> => {
1106
+ const verdict =
1107
+ saved && !saved.splitKeys
1108
+ ? await transient("Checking your saved key…", () => checkCloudKey(saved.url, saved.token))
1109
+ : null;
1110
+ const savedBroken = verdict !== null && !verdict.ok && verdict.refused;
1111
+ const keptPlan: CloudPlan =
1112
+ verdict && verdict.ok
1113
+ ? { kind: "kept", how: "saved", verified: true }
1114
+ : verdict && !verdict.refused
1115
+ ? { kind: "kept", how: "saved", verified: false }
1116
+ : { kind: "kept", how: "skip", verified: false };
1117
+ const keepHint = !saved
1118
+ ? ""
1119
+ : saved.splitKeys
1120
+ ? "leave both keys as they are"
1121
+ : verdict?.ok
1122
+ ? `${verdict.org ?? saved.org ?? hostOf(saved.url)} · key ${maskToken(saved.token)}`
1123
+ : savedBroken
1124
+ ? "its key no longer works"
1125
+ : "its key couldn't be checked just now";
1126
+
1127
+ type Pick = "login" | "key" | "oss" | "keep";
1128
+ const login: SelectChoice<Pick> = {
1129
+ label: saved ? "Log in again" : "Log in to FailproofAI Cloud",
1130
+ value: "login",
1131
+ hint: savedBroken
1132
+ ? "recommended · your saved key no longer works"
1133
+ : saved
1134
+ ? "opens your browser and makes a new key"
1135
+ : "recommended · opens your browser",
1136
+ };
1137
+ const key: SelectChoice<Pick> = { label: "Paste an API key", value: "key", hint: "one you already have" };
1138
+ const oss: SelectChoice<Pick> = { label: "Use open source", value: "oss", hint: "skip the cloud" };
1139
+ const keep: SelectChoice<Pick> = { label: "Keep current connection", value: "keep", hint: keepHint };
1140
+ // No initial-cursor option on selectOne: the default is whatever is first.
1141
+ const choices = !saved ? [login, key, oss] : savedBroken ? [login, key, keep] : [keep, login, key];
1142
+ const leftLogin = (result: Awaited<ReturnType<typeof askLogin>>): CloudPlan | null | typeof BACK => {
1143
+ if (result === null || result === BACK) {
1144
+ if (result === BACK && loginUnsupported) {
1145
+ write([kit.caution(`${host} doesn't support logging in from here yet. Paste an API key instead.`), ""]);
1146
+ }
1147
+ return result;
1148
+ }
1149
+ return result.value;
1150
+ };
1151
+
1152
+ if (url && (!saved || savedBroken)) {
1153
+ if (savedBroken && verdict && !verdict.ok) {
1154
+ write([kit.caution(`Your saved key no longer works: ${verdict.reason}. Logging in again.`)]);
1155
+ }
1156
+ void emit("configure_cloud_choice", { choice: "login", connected: Boolean(saved), auto: true });
1157
+ const first = leftLogin(await askLogin(url));
1158
+ if (first !== BACK) return first;
1159
+ }
1160
+
1161
+ for (;;) {
1162
+ const pick = await selectOne<Pick>({
1163
+ message: "Connect to cloud",
1164
+ meta: source ? `${host} · from ${source}` : host,
1165
+ choices: loginUnsupported ? choices.filter((c) => c.value !== "login") : choices,
1166
+ collapsed: (p) =>
1167
+ p === "keep" ? [...cloudLines(keptPlan), ""] : p === "oss" ? [...cloudLines({ kind: "oss" }), ""] : [],
1168
+ stdin,
1169
+ stdout,
1170
+ });
1171
+ if (pick === null) return null;
1172
+ void emit("configure_cloud_choice", { choice: pick, connected: Boolean(saved) });
1173
+ if (pick === "keep") return keptPlan;
1174
+ if (pick === "oss") return { kind: "oss" };
1175
+ if (pick === "key") {
1176
+ const answer = await askKey();
1177
+ if (answer === null) return null;
1178
+ if (answer === OPEN_SOURCE) continue;
1179
+ return planFor(answer);
1180
+ }
1181
+ if (!url) {
1182
+ write([kit.fail(badUrl ?? "No usable endpoint."), ""]);
1183
+ continue;
1184
+ }
1185
+ const result = leftLogin(await askLogin(url));
1186
+ if (result === BACK) continue;
1187
+ return result;
1188
+ }
1189
+ };
1190
+
1001
1191
  let cloud: CloudPlan;
1002
1192
  if (answers.oss) {
1003
1193
  cloud = saved ? { kind: "kept", how: "skip", verified: false } : { kind: "oss" };
@@ -1032,11 +1222,12 @@ export async function runConfigureWizard(
1032
1222
  cloud = saved ? { kind: "kept", how: "skip", verified: false } : { kind: "oss" };
1033
1223
  write([...cloudLines(cloud), ""]);
1034
1224
  } else {
1035
- // Said above the field, which stays usable for Tab and a saved key.
1225
+ // Said above the menu, which stays usable for keeping a saved key and for
1226
+ // open source, neither of which sends anything anywhere.
1036
1227
  if (badUrl) write([kit.fail(badUrl)]);
1037
- const answer = await askCloud();
1038
- if (answer === null) return cancel();
1039
- cloud = planFor(answer);
1228
+ const chosen = await chooseConnection();
1229
+ if (chosen === null) return cancel();
1230
+ cloud = chosen;
1040
1231
  }
1041
1232
 
1042
1233
  // ── AGENTS ──────────────────────────────────────────────────────────────────
@@ -1049,8 +1240,10 @@ export async function runConfigureWizard(
1049
1240
  // Whether the daemon will be collecting once this run ends: a key is already
1050
1241
  // on disk, or this run writes one. Removal copy and the backfill request both
1051
1242
  // depend on it.
1052
- const collectingAfter = cloud.kind === "connect" || readIngestCredential() !== null;
1053
- const sessionsOn = cloud.kind === "connect" ? answers.noTranscripts !== true : fp.collector.sessions === true;
1243
+ // A browser login connects exactly like a pasted key, one step later.
1244
+ const connecting = cloud.kind === "connect" || cloud.kind === "login";
1245
+ const collectingAfter = connecting || readIngestCredential() !== null;
1246
+ const sessionsOn = connecting ? answers.noTranscripts !== true : fp.collector.sessions === true;
1054
1247
 
1055
1248
  let selected: IntegrationType[];
1056
1249
  if (answers.agents && answers.agents.length > 0) {
@@ -1105,6 +1298,37 @@ export async function runConfigureWizard(
1105
1298
  // 5. The connection last.
1106
1299
  const done: string[] = [];
1107
1300
  let daemonInstalled = daemonAlreadyRunning;
1301
+ // The `sudo -v` at the top cached root for sudo's timeout — five minutes by
1302
+ // default on macOS, fifteen on most Linux. A browser login, or simply a slow
1303
+ // agents screen, can outlast it, and the install below runs `sudo -n`, which
1304
+ // would then fail AFTER the person did everything else. Ask once more instead.
1305
+ // The stale-unit refresh runs `sudo -n` too, so it is asked for the same way —
1306
+ // but, as at the top, losing root there costs the scheduled audit, not setup.
1307
+ // Unattended runs never primed anything, so there is nothing to have expired.
1308
+ if ((daemonWanted || daemonUnitStale) && !unattended) {
1309
+ let stillRoot = false;
1310
+ try {
1311
+ stillRoot = canElevate();
1312
+ } catch {
1313
+ stillRoot = false;
1314
+ }
1315
+ if (!stillRoot && daemonWanted) {
1316
+ if (!elevate("Your sudo session expired while you were away. Installing failproofaid needs root again.")) {
1317
+ write([
1318
+ kit.fail("Couldn't get root, so setup stopped before changing anything."),
1319
+ ` Re-run once you can use sudo: ${kit.cmd("failproofai config")}`,
1320
+ ]);
1321
+ void emit("configure_aborted", { reason: "needs_root" });
1322
+ return { applied: false, abort: "needs_root" };
1323
+ }
1324
+ } else if (
1325
+ !stillRoot &&
1326
+ !elevate("Your sudo session expired while you were away. Refreshing failproofaid's service definition needs root again.")
1327
+ ) {
1328
+ done.push(kit.caution("No root, so its service definition stays as it is. Scheduled audits stay off until it is refreshed."));
1329
+ daemonUnitStale = false;
1330
+ }
1331
+ }
1108
1332
  if (daemonWanted) {
1109
1333
  // A unit that is running but cannot answer is torn down before it is
1110
1334
  // rebuilt: it holds the singleton flock the replacement needs, so
@@ -1214,7 +1438,7 @@ export async function runConfigureWizard(
1214
1438
  pruneOldDaemonBinaries();
1215
1439
  }
1216
1440
 
1217
- const connectedAfterPlan = cloud.kind === "connect" || cloud.kind === "kept";
1441
+ const connectedAfterPlan = connecting || cloud.kind === "kept";
1218
1442
  // Telemetry runs concurrently with the rest of apply (never rejects,
1219
1443
  // 5s-bounded) and is awaited before returning. `cli` carries the selected
1220
1444
  // agent ids, as it always has (and as hooks_installed does): a fixed list of
@@ -1225,7 +1449,7 @@ export async function runConfigureWizard(
1225
1449
  cli: selected,
1226
1450
  cli_count: selected.length,
1227
1451
  policy_count: (readScopedHooksConfig("user", cwd).enabledPolicies ?? []).length,
1228
- connected: cloud.kind === "connect",
1452
+ connected: connecting,
1229
1453
  mode: connectedAfterPlan ? "cloud" : "oss",
1230
1454
  agents_selected: selected.length,
1231
1455
  agents_detected: plan.detected.size,
@@ -1273,8 +1497,36 @@ export async function runConfigureWizard(
1273
1497
  // a key on disk doing nothing. `connectToCloud` re-verifies each capability
1274
1498
  // and writes only what works.
1275
1499
  let connected = false;
1276
- if (cloud.kind === "connect" && url) {
1277
- const token = cloud.token;
1500
+ // A browser login has an approval, not a key: claim it NOW, with the daemon
1501
+ // in, so a run that stopped earlier left nothing minted anywhere. The claim
1502
+ // is single-use — the server mints the key and hands it over exactly once.
1503
+ let token: string | null = cloud.kind === "connect" ? cloud.token : null;
1504
+ let orgLabel: string | undefined = cloud.kind === "connect" ? cloud.org : undefined;
1505
+ let mintedName: string | undefined;
1506
+ if (cloud.kind === "login" && url) {
1507
+ const claimed = await transient("Creating this machine's key…", () => claimLogin(url, cloud.pollSecret));
1508
+ void emit("configure_cloud_login", { step: "claimed", ok: claimed.kind === "ok", reason: claimed.kind });
1509
+ if (claimed.kind === "ok") {
1510
+ token = claimed.key;
1511
+ orgLabel = loginOrgLabel(claimed.org);
1512
+ mintedName = claimed.keyName;
1513
+ } else {
1514
+ hookLogWarn(`cloud login could not be completed: ${claimed.kind}`);
1515
+ done.push(
1516
+ kit.caution(
1517
+ claimed.kind === "expired"
1518
+ ? "The login took too long to finish, so no key was created. Everything else was applied."
1519
+ : claimed.kind === "revoked"
1520
+ ? "Whoever approved the login can no longer create keys in that org, so no key was created."
1521
+ : claimed.kind === "unreachable"
1522
+ ? `Couldn't reach ${host} to create the key (${claimed.reason}); everything else was applied.`
1523
+ : `The key couldn't be created: ${claimed.reason}. Everything else was applied.`,
1524
+ "failproofai config",
1525
+ ),
1526
+ );
1527
+ }
1528
+ }
1529
+ if (token && url) {
1278
1530
  try {
1279
1531
  const outcome = await transient("Connecting…", () =>
1280
1532
  connectToCloud({
@@ -1288,7 +1540,12 @@ export async function runConfigureWizard(
1288
1540
  );
1289
1541
  connected = outcome.anyConfigured;
1290
1542
  done.push(...(outcome.changes ?? []));
1291
- done.push(...connectDoneLines(kit, outcome, host, cloud.org));
1543
+ done.push(...connectDoneLines(kit, outcome, host, orgLabel));
1544
+ // Logging in again makes a NEW key; the one this machine held keeps
1545
+ // working until someone revokes it. Said here, where it is still useful.
1546
+ if (cloud.kind === "login" && saved && connected) {
1547
+ done.push(` Your previous key for this machine still works until you revoke it on ${host}'s keys page.`);
1548
+ }
1292
1549
  if (outcome.ingest.ok && answers.noTranscripts === true) {
1293
1550
  done.push(" Decisions only: session transcripts are not sent (--no-transcripts).");
1294
1551
  }
@@ -1298,12 +1555,22 @@ export async function runConfigureWizard(
1298
1555
  hookLogWarn(`cloud connection was not written: ${err instanceof Error ? err.message : String(err)}`);
1299
1556
  done.push(kit.caution("Couldn't connect; everything else was applied.", "failproofai config"));
1300
1557
  }
1558
+ // The claim spent the approval and the key exists, but nothing here uses
1559
+ // it: say which one, so it can be revoked rather than left live.
1560
+ if (cloud.kind === "login" && !connected) {
1561
+ done.push(` The key ${mintedName ? `"${mintedName}" ` : ""}was created but isn't in use here; revoke it on ${host}'s keys page.`);
1562
+ }
1301
1563
  } else if (cloud.kind === "kept" && cloud.how === "saved" && fp.mode !== "cloud") {
1302
1564
  // A home migrated from layout 1 carries keys but no mode, and would read
1303
1565
  // as open source everywhere that asks.
1304
1566
  updateConfig({ mode: "cloud" });
1305
1567
  }
1306
1568
 
1569
+ // Logging in again on a connected machine, with no key at the end of it,
1570
+ // changed nothing about the connection: the previous one is still there.
1571
+ const keptOld = cloud.kind === "login" && !token && saved !== undefined;
1572
+ if (keptOld) done.push(" This machine keeps its previous connection.");
1573
+
1307
1574
  await applied;
1308
1575
  // Only now — a completed apply — is the launcher considered "seen", so
1309
1576
  // first-run onboarding stops offering itself on every command.
@@ -1321,7 +1588,7 @@ export async function runConfigureWizard(
1321
1588
  done,
1322
1589
  cwd,
1323
1590
  agents: selected.length,
1324
- connected: connected || cloud.kind === "kept",
1591
+ connected: connected || cloud.kind === "kept" || keptOld,
1325
1592
  codexTrust,
1326
1593
  }),
1327
1594
  );
@@ -1334,7 +1601,7 @@ export async function runConfigureWizard(
1334
1601
  policies,
1335
1602
  daemonInstalled,
1336
1603
  connected,
1337
- mode: connected || cloud.kind === "kept" ? "cloud" : "oss",
1604
+ mode: connected || cloud.kind === "kept" || keptOld ? "cloud" : "oss",
1338
1605
  agents: { selected, added, removed },
1339
1606
  };
1340
1607
  }
@@ -1345,7 +1612,19 @@ export async function runConfigureWizard(
1345
1612
  type CloudPlan =
1346
1613
  | { kind: "oss" }
1347
1614
  | { kind: "kept"; how: "skip" | "saved"; verified: boolean }
1348
- | { kind: "connect"; token: string; org?: string; note?: string };
1615
+ | { kind: "connect"; token: string; org?: string; note?: string }
1616
+ /**
1617
+ * Approved in the browser, not yet claimed. The key does not exist until
1618
+ * apply claims it — after the daemon is in — so a run that stops before then
1619
+ * leaves no key behind anywhere.
1620
+ */
1621
+ | { kind: "login"; pollSecret: string; org: LoginOrg; approvedBy?: string; keyName?: string; permissions: string[] };
1622
+
1623
+ /** "Acme (acme)", or whichever half the server sent. */
1624
+ function loginOrgLabel(org: LoginOrg): string {
1625
+ if (org.name && org.slug) return `${org.name} (${org.slug})`;
1626
+ return org.name ?? org.slug ?? "your org";
1627
+ }
1349
1628
 
1350
1629
  /**
1351
1630
  * The connection already on this machine, from either credential: the policy
@@ -1394,7 +1673,15 @@ export function resolveCloudUrl(
1394
1673
  const env = process.env.FAILPROOFAI_CLOUD_URL?.trim();
1395
1674
  const fromFlag = flag?.trim();
1396
1675
  const override = fromFlag || env;
1397
- if (!override) return { ok: true, url: existing ?? cloudBaseFor(DEFAULT_INGEST_URL) };
1676
+ if (!override) {
1677
+ if (!existing) return { ok: true, url: cloudBaseFor(DEFAULT_INGEST_URL) };
1678
+ // Checked like a typed one: login sends its secret and receives a key here
1679
+ // before anything else would, and the file it came from can be edited.
1680
+ const saved = validateCloudUrl(existing);
1681
+ return saved.ok
1682
+ ? { ok: true, url: existing }
1683
+ : { ok: false, message: `the saved cloud address "${existing}" cannot be used: ${saved.reason}` };
1684
+ }
1398
1685
  const source = fromFlag && fromFlag !== env ? "--url" : "FAILPROOFAI_CLOUD_URL";
1399
1686
  const validated = validateCloudUrl(cloudBaseFor(override));
1400
1687
  if (!validated.ok) {
@@ -1477,6 +1764,15 @@ export function cloudCollapsedLines(
1477
1764
  kit.ok(plan.org ? `Key accepted for ${plan.org} on ${at.host}` : `Key accepted by ${at.host}`),
1478
1765
  ...(plan.note ? [kit.caution(plan.note)] : []),
1479
1766
  ];
1767
+ case "login":
1768
+ // Who approved it is said out loud: a link someone else approved into
1769
+ // THEIR org would otherwise connect this machine there unnoticed.
1770
+ return [
1771
+ head,
1772
+ kit.ok(
1773
+ `Logged in${plan.approvedBy ? ` as ${plan.approvedBy}` : ""} · ${loginOrgLabel(plan.org)} on ${at.host}`,
1774
+ ),
1775
+ ];
1480
1776
  }
1481
1777
  }
1482
1778
 
@@ -12,10 +12,11 @@ import { collectorHealthFile, configFile, otelAgentStateFile, otlpHealthFile } f
12
12
  import { writeConfigFileAtomic } from "./safe-config-write";
13
13
  import { agentSessionsEnabled } from "./collector-config";
14
14
  import { introspectKey } from "./cloud-introspect";
15
+ import { validateCloudUrl } from "./cloud-enrollment";
15
16
  import { readJsonFile } from "./integrations";
16
17
  import { selectOne } from "./tui";
17
18
  import {
18
- AGENT_LABELS, OTEL_AGENTS, agentConfigPath, agentOtelWrites, editAgentConfig,
19
+ AGENT_LABELS, OTEL_AGENTS, agentConfigPath, agentOtelWrites, editAgentConfig, otlpDestination, cloudOtlpBase,
19
20
  getSetting, parseAgentConfig, vscodeInstalled,
20
21
  type JsonObject, type OtelAgent, type SettingWrite,
21
22
  } from "./otel-writers";
@@ -91,8 +92,13 @@ function credential(): { key: string; origin: string } {
91
92
  const ingest = readCredentials().ingest;
92
93
  const key = process.env.FAILPROOFAI_INGEST_KEY || ingest?.key;
93
94
  if (!key) throw new Error("No Cloud API key configured. Run `failproofai config` first.");
94
- const url = new URL(process.env.FAILPROOFAI_INGEST_URL || ingest?.url || "https://app.befailproof.ai");
95
- if (!["https:", "http:"].includes(url.protocol) || url.username || url.password) throw new Error("Invalid Cloud ingest URL.");
95
+ const raw = process.env.FAILPROOFAI_INGEST_URL || ingest?.url || "https://app.befailproof.ai";
96
+ // Every caller sends or prints this key for the origin: the same rule as
97
+ // Cloud enrollment, https or loopback http only, so it never travels in clear.
98
+ const checked = validateCloudUrl(raw);
99
+ if (!checked.ok) throw new Error(`Invalid Cloud ingest URL: ${checked.reason}`);
100
+ const url = new URL(raw);
101
+ if (url.username || url.password) throw new Error("Invalid Cloud ingest URL.");
96
102
  return { key, origin: url.origin };
97
103
  }
98
104
  function backupOnce(path: string, original: string | null): void {
@@ -185,7 +191,7 @@ async function enableAgent(agent: OtelAgent, yes: boolean, localFlag: boolean, c
185
191
  const local = localFlag || agent === "copilot";
186
192
  const port = readConfig().collector.otlp?.port ?? 4318;
187
193
  if (!Number.isInteger(port) || port < 1 || port > 65535) throw new Error("collector.otlp.port must be between 1 and 65535.");
188
- const destination = local ? `http://127.0.0.1:${port}` : origin;
194
+ const destination = otlpDestination(origin, local, port);
189
195
  const original = existsSync(file) ? readFileSync(file, "utf8") : null;
190
196
  const parsed = parseAgentConfig(original ?? "", agent);
191
197
  const oldState = existing ? privateState(agent) : null;
@@ -303,8 +309,12 @@ async function status(options: OtelOptions): Promise<OtelResult> {
303
309
  try {
304
310
  const state = privateState(agent);
305
311
  const original = parseAgentConfig(state.original ?? "", agent);
312
+ const { key, origin } = credential();
313
+ // Cloud's address is recomputed, so settings written for an older
314
+ // address (or another Cloud) read as "not managed" until re-enabled.
315
+ const expectedDestination = record.local ? record.destination : cloudOtlpBase(origin);
306
316
  const expected = parseAgentConfig(editAgentConfig(state.original ?? "", agent,
307
- agentOtelWrites(agent, record.destination, credential().key, record.local, record.content, original)), agent);
317
+ agentOtelWrites(agent, expectedDestination, key, record.local, record.content, original)), agent);
308
318
  managed = record.keys.every(k => JSON.stringify(getSetting(parsed, k.path)) === JSON.stringify(getSetting(expected, k.path)));
309
319
  } catch { /* Missing recovery state or key. */ }
310
320
  }
@@ -339,7 +349,7 @@ export async function runOtelCommand(args: string[], options: OtelOptions = {}):
339
349
  const consumed = rest.filter((_, i) => i !== index && i !== index + 1 || index < 0).filter(x => x !== "--local");
340
350
  if (consumed.length) throw new Error("env takes only --service <name> and --local.");
341
351
  const local = rest.includes("--local");
342
- const endpoint = local ? `http://127.0.0.1:${readConfig().collector.otlp?.port ?? 4318}` : origin;
352
+ const endpoint = otlpDestination(origin, local, readConfig().collector.otlp?.port ?? 4318);
343
353
  const quote = (s: string) => `'${s.replace(/'/g, "'\\''")}'`;
344
354
  const values = {
345
355
  OTEL_EXPORTER_OTLP_ENDPOINT: endpoint, OTEL_EXPORTER_OTLP_PROTOCOL: "http/protobuf",
@@ -186,6 +186,19 @@ export function editAgentConfig(text: string, agent: OtelAgent, writes: SettingW
186
186
  return next;
187
187
  }
188
188
 
189
+ /**
190
+ * FailproofAI Cloud's OTLP base URL. Exporters append `/v1/<signal>` to it, as
191
+ * the OTLP spec says. The local relay is plain `http://127.0.0.1:<port>`.
192
+ */
193
+ export function cloudOtlpBase(origin: string): string {
194
+ return `${origin.replace(/\/+$/, "")}/otel`;
195
+ }
196
+
197
+ /** Where an agent's exporter points: the local relay, or Cloud's OTLP base. */
198
+ export function otlpDestination(origin: string, local: boolean, port: number): string {
199
+ return local ? `http://127.0.0.1:${port}` : cloudOtlpBase(origin);
200
+ }
201
+
189
202
  export function agentOtelWrites(agent: OtelAgent, endpoint: string, key: string, local: boolean, content: boolean, config: JsonObject = {}): SettingWrite[] {
190
203
  const auth = local ? {} : { Authorization: `Bearer ${key}` };
191
204
  const env: JsonObject = {