failproofai 1.0.10 → 1.0.11-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 (296) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/build-manifest.json +6 -6
  3. package/.next/standalone/.next/prerender-manifest.json +4 -4
  4. package/.next/standalone/.next/required-server-files.json +1 -1
  5. package/.next/standalone/.next/server/app/_global-error/page/build-manifest.json +3 -3
  6. package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
  7. package/.next/standalone/.next/server/app/_global-error/page.js +4 -4
  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.meta +8 -0
  12. package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
  13. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +6 -6
  14. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
  15. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  16. package/.next/standalone/.next/server/app/_not-found/page/build-manifest.json +3 -3
  17. package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  18. package/.next/standalone/.next/server/app/_not-found/page.js +4 -4
  19. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  20. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  21. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  22. package/.next/standalone/.next/server/app/_not-found.meta +8 -0
  23. package/.next/standalone/.next/server/app/_not-found.rsc +14 -14
  24. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +14 -14
  25. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +13 -13
  26. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  27. package/.next/standalone/.next/server/app/api/audit/invite/route.js +4 -4
  28. package/.next/standalone/.next/server/app/api/audit/invite/route.js.nft.json +1 -1
  29. package/.next/standalone/.next/server/app/api/audit/run/route.js +4 -4
  30. package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -1
  31. package/.next/standalone/.next/server/app/api/audit/status/route.js +1 -1
  32. package/.next/standalone/.next/server/app/api/audit/status/route.js.nft.json +1 -1
  33. package/.next/standalone/.next/server/app/api/auth/login-request/route.js +2 -2
  34. package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -1
  35. package/.next/standalone/.next/server/app/api/auth/login-verify/route.js +4 -4
  36. package/.next/standalone/.next/server/app/api/auth/login-verify/route.js.nft.json +1 -1
  37. package/.next/standalone/.next/server/app/api/auth/logout/route.js +3 -3
  38. package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
  39. package/.next/standalone/.next/server/app/api/auth/status/route.js +3 -3
  40. package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -1
  41. package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js +1 -1
  42. package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
  43. package/.next/standalone/.next/server/app/audit/page/build-manifest.json +3 -3
  44. package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +2 -2
  45. package/.next/standalone/.next/server/app/audit/page.js +4 -4
  46. package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -1
  47. package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
  48. package/.next/standalone/.next/server/app/index.html +1 -1
  49. package/.next/standalone/.next/server/app/index.meta +8 -0
  50. package/.next/standalone/.next/server/app/index.rsc +14 -14
  51. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +13 -13
  52. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +14 -14
  53. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  54. package/.next/standalone/.next/server/app/page/build-manifest.json +3 -3
  55. package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
  56. package/.next/standalone/.next/server/app/page.js +4 -4
  57. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  58. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  59. package/.next/standalone/.next/server/app/policies/page/build-manifest.json +3 -3
  60. package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +14 -14
  61. package/.next/standalone/.next/server/app/policies/page.js +8 -8
  62. package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
  63. package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
  64. package/.next/standalone/.next/server/app/project/[name]/page/build-manifest.json +3 -3
  65. package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
  66. package/.next/standalone/.next/server/app/project/[name]/page.js +5 -5
  67. package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
  68. package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
  69. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/build-manifest.json +3 -3
  70. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
  71. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
  72. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js +5 -5
  73. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
  74. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
  75. package/.next/standalone/.next/server/app/projects/page/build-manifest.json +3 -3
  76. package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
  77. package/.next/standalone/.next/server/app/projects/page.js +5 -5
  78. package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
  79. package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  80. package/.next/standalone/.next/server/app/settings/page/build-manifest.json +3 -3
  81. package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +8 -8
  82. package/.next/standalone/.next/server/app/settings/page.js +9 -9
  83. package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
  84. package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  85. package/.next/standalone/.next/server/chunks/{[externals]__0qxhecv._.js → [externals]__0d7i9ea._.js} +2 -2
  86. package/.next/standalone/.next/server/chunks/{[externals]__0sg9-3p._.js → [externals]__0hjaw70._.js} +1 -1
  87. package/.next/standalone/.next/server/chunks/[externals]__1_9ze9b._.js +3 -0
  88. package/.next/standalone/.next/server/chunks/[externals]__1oenfmn._.js +3 -0
  89. package/.next/standalone/.next/server/chunks/[root-of-the-server]__08dchfu._.js +1 -1
  90. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ga9hs7._.js +3 -0
  91. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0l3yhx4._.js +2 -2
  92. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0moxohc._.js +22 -0
  93. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0o07qi9._.js +1 -1
  94. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0z2ll-a._.js +3 -0
  95. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1adacul._.js +11 -11
  96. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1autwno._.js +3 -0
  97. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1v25n-6._.js +3 -0
  98. package/.next/standalone/.next/server/chunks/_09dz7xv._.js +1 -1
  99. package/.next/standalone/.next/server/chunks/_0tovk6q._.js +1 -1
  100. package/.next/standalone/.next/server/chunks/_0trp3yc._.js +1 -1
  101. package/.next/standalone/.next/server/chunks/_1ek68ln._.js +2 -2
  102. package/.next/standalone/.next/server/chunks/_1fz8m31._.js +1 -1
  103. package/.next/standalone/.next/server/chunks/_1jrv3hg._.js +3 -0
  104. package/.next/standalone/.next/server/chunks/_1nx8fim._.js +3 -0
  105. package/.next/standalone/.next/server/chunks/_1ogwigf._.js +1 -1
  106. package/.next/standalone/.next/server/chunks/{_1q5i8mb._.js → _1q27azx._.js} +2 -2
  107. package/.next/standalone/.next/server/chunks/lib_telemetry_ts_0dctyyw._.js +1 -1
  108. package/.next/standalone/.next/server/chunks/{node_modules_posthog-node_dist_entrypoints_index_node_mjs_0el6rg8._.js → node_modules_posthog-node_dist_entrypoints_index_node_mjs_0ol5pa3._.js} +2 -2
  109. package/.next/standalone/.next/server/chunks/{node_modules_posthog-node_dist_entrypoints_index_node_mjs_04op_ou._.js → node_modules_posthog-node_dist_entrypoints_index_node_mjs_1rqmk27._.js} +2 -2
  110. package/.next/standalone/.next/server/chunks/{node_modules_posthog-node_dist_entrypoints_index_node_mjs_0dr20uz._.js → node_modules_posthog-node_dist_entrypoints_index_node_mjs_1w7tiq4._.js} +2 -2
  111. package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
  112. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__04usis8._.js +2 -2
  113. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1-bm5zf._.js → [root-of-the-server]__0502lat._.js} +1 -1
  114. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0_gn5iz._.js +4 -0
  115. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0f765xr._.js +4 -0
  116. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__01bmjsj._.js → [root-of-the-server]__0h38gzz._.js} +1 -1
  117. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0hoaz1g._.js +4 -0
  118. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1ouobn4._.js → [root-of-the-server]__0mxmwtx._.js} +1 -1
  119. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__19evfi8._.js → [root-of-the-server]__0uescqv._.js} +1 -1
  120. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1484zv2._.js +3 -0
  121. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1mf3zp6._.js → [root-of-the-server]__19dutr7._.js} +4 -4
  122. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0oqrl71._.js → [root-of-the-server]__1_qv8oh._.js} +2 -2
  123. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1u6sn69._.js → [root-of-the-server]__1ab4ifb._.js} +1 -1
  124. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1fbrk56._.js +4 -0
  125. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1pprgri._.js +2 -2
  126. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1um4yxn._.js +4 -0
  127. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1wb4yt2._.js +4 -0
  128. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1y3n3cn._.js +4 -0
  129. package/.next/standalone/.next/server/chunks/ssr/_08x1r5t._.js +1 -1
  130. package/.next/standalone/.next/server/chunks/ssr/_0bqoto4._.js +1 -1
  131. package/.next/standalone/.next/server/chunks/ssr/{_16pa9ht._.js → _0lnpwk8._.js} +2 -2
  132. package/.next/standalone/.next/server/chunks/ssr/{_0yq5_3a._.js → _15y8myg._.js} +1 -1
  133. package/.next/standalone/.next/server/chunks/ssr/_1gb0ifp._.js +2 -2
  134. package/.next/standalone/.next/server/chunks/ssr/{_042cgl1._.js → _1o95rf0._.js} +2 -2
  135. package/.next/standalone/.next/server/chunks/ssr/{_1zopuov._.js → _1thr5rf._.js} +2 -2
  136. package/.next/standalone/.next/server/chunks/ssr/_next-internal_server_app_policies_page_actions_1sp2-yo.js +12 -14
  137. package/.next/standalone/.next/server/chunks/ssr/app_actions_get-scheduled-audit_ts_0ei9sni._.js +1 -1
  138. package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +1 -1
  139. package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
  140. package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +1 -1
  141. package/.next/standalone/.next/server/chunks/ssr/app_settings_02tf1h4._.js +1 -1
  142. package/.next/standalone/.next/server/chunks/ssr/node_modules_1hl81y4._.js +1 -1
  143. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_0nkkbfv._.js +6 -0
  144. package/.next/standalone/.next/server/chunks/ssr/src_hooks_fp-config_ts_04t589g._.js +1 -1
  145. package/.next/standalone/.next/server/chunks/ssr/src_hooks_fp-home_ts_0je3xkv._.js +1 -1
  146. package/.next/standalone/.next/server/middleware-build-manifest.js +6 -6
  147. package/.next/standalone/.next/server/middleware.js +1 -1
  148. package/.next/standalone/.next/server/pages/404.html +1 -1
  149. package/.next/standalone/.next/server/pages/500.html +1 -1
  150. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  151. package/.next/standalone/.next/server/server-reference-manifest.json +23 -23
  152. package/.next/standalone/.next/static/chunks/{03h3b-uomi7_d.js → 0pra9i676pym1.js} +1 -1
  153. package/.next/standalone/.next/static/chunks/{2kj826h1w9r47.js → 1-lpi0m-hc1kb.js} +1 -1
  154. package/.next/standalone/.next/static/chunks/{3ob2161ap37ul.js → 17yvyyblr_eb5.js} +1 -1
  155. package/.next/standalone/.next/static/chunks/{3nkc2jlgyygda.js → 1mylcr99gccyz.js} +1 -1
  156. package/.next/standalone/.next/static/chunks/{2j92xul6y24_v.js → 1wozchtn2etvh.js} +1 -1
  157. package/.next/standalone/.next/static/chunks/{3mjfvng11xnoo.js → 23thtelz1a-ur.js} +2 -2
  158. package/.next/standalone/.next/static/chunks/{1fqukzzowjflt.js → 2bc17tohgs4bs.js} +1 -1
  159. package/.next/standalone/.next/static/chunks/{3u1s8dsqiean5.js → 2xq-ejo8kti18.js} +1 -1
  160. package/.next/standalone/.next/static/chunks/3-_pth_c9n938.js +1 -0
  161. package/.next/standalone/.next/static/chunks/{3i8rg2fv9nd6e.js → 3n46e45atic-m.js} +1 -1
  162. package/.next/standalone/.next/static/chunks/{078dofaxvjgpd.js → 3q7sndqftqhw9.js} +1 -1
  163. package/.next/standalone/.next/static/chunks/{0542cuk_va8g1.js → 3sg07wnn969xq.js} +1 -1
  164. package/.next/standalone/.next/static/chunks/{turbopack-11dn2pegmg9_9.js → turbopack-1opxka4dtjbc5.js} +1 -1
  165. package/.next/standalone/app/actions/install-hooks-web.ts +10 -2
  166. package/.next/standalone/hermes-plugin/plugin.yaml +1 -1
  167. package/.next/standalone/node_modules/@next/env/package.json +1 -1
  168. package/.next/standalone/node_modules/next/dist/build/swc/index.js +1 -1
  169. package/.next/standalone/node_modules/next/dist/compiled/hash.js/sha256/256.js +1 -0
  170. package/.next/standalone/node_modules/next/dist/compiled/hash.js/sha256/package.json +1 -0
  171. package/.next/standalone/node_modules/next/dist/compiled/next-server/app-page-turbo-experimental.runtime.prod.js +17 -17
  172. package/.next/standalone/node_modules/next/dist/compiled/next-server/app-page-turbo.runtime.prod.js +18 -18
  173. package/.next/standalone/node_modules/next/dist/compiled/next-server/app-route-turbo.runtime.prod.js +3 -3
  174. package/.next/standalone/node_modules/next/dist/compiled/next-server/pages-turbo.runtime.prod.js +13 -13
  175. package/.next/standalone/node_modules/next/dist/lib/patch-incorrect-lockfile.js +3 -3
  176. package/.next/standalone/node_modules/next/dist/server/base-server.js +1 -2
  177. package/.next/standalone/node_modules/next/dist/server/config.js +1 -1
  178. package/.next/standalone/node_modules/next/dist/server/dev/hot-reloader-turbopack.js +2 -2
  179. package/.next/standalone/node_modules/next/dist/server/dev/hot-reloader-webpack.js +1 -1
  180. package/.next/standalone/node_modules/next/dist/server/image-optimizer.js +265 -53
  181. package/.next/standalone/node_modules/next/dist/server/lib/app-info-log.js +1 -1
  182. package/.next/standalone/node_modules/next/dist/server/lib/incremental-cache/file-system-cache.js +177 -19
  183. package/.next/standalone/node_modules/next/dist/server/lib/incremental-cache/index.js +36 -17
  184. package/.next/standalone/node_modules/next/dist/server/lib/incremental-cache/shared-cache-controls.external.js +14 -6
  185. package/.next/standalone/node_modules/next/dist/server/lib/match-next-data-pathname.js +3 -1
  186. package/.next/standalone/node_modules/next/dist/server/lib/node-fs-methods.js +14 -0
  187. package/.next/standalone/node_modules/next/dist/server/lib/route-cache-key.js +77 -0
  188. package/.next/standalone/node_modules/next/dist/server/lib/router-utils/block-cross-site-dev.js +9 -11
  189. package/.next/standalone/node_modules/next/dist/server/lib/start-server.js +1 -1
  190. package/.next/standalone/node_modules/next/dist/server/mcp/get-mcp-middleware.js +4 -2
  191. package/.next/standalone/node_modules/next/dist/server/next-server.js +7 -3
  192. package/.next/standalone/node_modules/next/dist/server/response-cache/index.js +32 -16
  193. package/.next/standalone/node_modules/next/dist/server/route-matcher-providers/app-page-route-matcher-provider.js +2 -2
  194. package/.next/standalone/node_modules/next/dist/server/route-modules/pages/pages-handler.js +6 -1
  195. package/.next/standalone/node_modules/next/dist/server/route-modules/route-module.js +9 -2
  196. package/.next/standalone/node_modules/next/dist/server/use-cache/use-cache-wrapper.js +30 -29
  197. package/.next/standalone/node_modules/next/dist/shared/lib/router/utils/app-paths.js +18 -1
  198. package/.next/standalone/node_modules/next/dist/telemetry/anonymous-meta.js +1 -1
  199. package/.next/standalone/node_modules/next/dist/telemetry/events/swc-load-failure.js +1 -1
  200. package/.next/standalone/node_modules/next/dist/telemetry/events/version.js +2 -2
  201. package/.next/standalone/node_modules/next/package.json +10 -10
  202. package/.next/standalone/package.json +14 -11
  203. package/.next/standalone/sdk/python/README.md +41 -0
  204. package/.next/standalone/sdk/python/docs/README.md +1 -0
  205. package/.next/standalone/sdk/python/docs/otel/README.md +36 -0
  206. package/.next/standalone/sdk/python/docs/otel/examples/agent_trace.py +30 -0
  207. package/.next/standalone/sdk/python/docs/otel/examples/quickstart.py +22 -0
  208. package/.next/standalone/sdk/python/failproofai_sdk/__init__.py +8 -0
  209. package/.next/standalone/sdk/python/failproofai_sdk/integrations/__init__.py +3 -0
  210. package/.next/standalone/sdk/python/failproofai_sdk/integrations/otel.py +189 -0
  211. package/.next/standalone/sdk/python/pyproject.toml +2 -1
  212. package/.next/standalone/sdk/python/tests/test_docs.py +16 -3
  213. package/.next/standalone/sdk/python/tests/test_integrations.py +1 -1
  214. package/.next/standalone/sdk/python/tests/test_otel.py +147 -0
  215. package/.next/standalone/sdk/python/tests/test_zero_dependencies.py +4 -1
  216. package/.next/standalone/sdk/python/uv.lock +258 -147
  217. package/.next/standalone/sdk/typescript/README.md +43 -0
  218. package/.next/standalone/sdk/typescript/integration/ai.test.ts +9 -2
  219. package/.next/standalone/sdk/typescript/package-lock.json +57 -5
  220. package/.next/standalone/sdk/typescript/package.json +2 -0
  221. package/.next/standalone/sdk/typescript/src/edge/index.ts +9 -0
  222. package/.next/standalone/sdk/typescript/src/index.ts +2 -0
  223. package/.next/standalone/sdk/typescript/src/integrations/index.ts +4 -1
  224. package/.next/standalone/sdk/typescript/src/integrations/otel.ts +204 -0
  225. package/.next/standalone/sdk/typescript/test/integrations.test.ts +1 -1
  226. package/.next/standalone/sdk/typescript/test/otel.test.ts +125 -0
  227. package/.next/standalone/server.js +1 -1
  228. package/bin/failproofai.mjs +653 -1077
  229. package/dist/cli.mjs +8781 -4050
  230. package/dist/worker.mjs +170 -62
  231. package/hermes-plugin/plugin.yaml +1 -1
  232. package/package.json +14 -11
  233. package/scripts/launch-facts.ts +157 -0
  234. package/scripts/launch-ready.ts +228 -0
  235. package/scripts/launch-screen.ts +202 -0
  236. package/scripts/launch.ts +106 -49
  237. package/scripts/skew-log-filter.ts +38 -0
  238. package/src/audit/cli-login.ts +39 -59
  239. package/src/audit/cli.ts +308 -228
  240. package/src/audit/index.ts +45 -2
  241. package/src/audit/schedule-cli.ts +83 -120
  242. package/src/audit/types.ts +31 -0
  243. package/src/hooks/agent-selection.ts +155 -0
  244. package/src/hooks/backfill-cli.ts +151 -137
  245. package/src/hooks/backfill-request.ts +149 -0
  246. package/src/hooks/cloud-connection.ts +1 -1
  247. package/src/hooks/cloud-enrollment-cli.ts +78 -28
  248. package/src/hooks/cloud-introspect.ts +3 -0
  249. package/src/hooks/collector-config.ts +10 -1
  250. package/src/hooks/config-status.ts +717 -0
  251. package/src/hooks/configure-wizard.ts +967 -988
  252. package/src/hooks/daemon-service.ts +16 -6
  253. package/src/hooks/did-you-mean.ts +185 -0
  254. package/src/hooks/flush-cli.ts +33 -7
  255. package/src/hooks/fp-config.ts +96 -0
  256. package/src/hooks/fp-home.ts +11 -0
  257. package/src/hooks/fp-reset.ts +102 -95
  258. package/src/hooks/handler.ts +4 -0
  259. package/src/hooks/harness-cli.ts +87 -138
  260. package/src/hooks/install-prompt.ts +38 -477
  261. package/src/hooks/integrations.ts +1 -1
  262. package/src/hooks/jev-cli.ts +183 -196
  263. package/src/hooks/manager.ts +554 -358
  264. package/src/hooks/onboarding-attempt.ts +11 -9
  265. package/src/hooks/otel-cli.ts +350 -0
  266. package/src/hooks/otel-output.ts +24 -0
  267. package/src/hooks/otel-writers.ts +215 -0
  268. package/src/hooks/pack-cli.ts +219 -204
  269. package/src/hooks/report-body.ts +50 -0
  270. package/src/hooks/safe-config-write.ts +4 -2
  271. package/src/hooks/session-pause-cli.ts +93 -73
  272. package/src/hooks/tui.ts +849 -389
  273. package/src/hooks/uninstall-cli.ts +136 -149
  274. package/src/hooks/untraced-note.ts +52 -0
  275. package/.next/standalone/.next/server/chunks/[externals]__19_pzeq._.js +0 -3
  276. package/.next/standalone/.next/server/chunks/[externals]__20kzpkf._.js +0 -3
  277. package/.next/standalone/.next/server/chunks/[root-of-the-server]__01eqny5._.js +0 -3
  278. package/.next/standalone/.next/server/chunks/[root-of-the-server]__05ja_05._.js +0 -3
  279. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0igxt32._.js +0 -3
  280. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0zyc_nm._.js +0 -3
  281. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1ttrwnd._.js +0 -22
  282. package/.next/standalone/.next/server/chunks/_0bs-v8p._.js +0 -3
  283. package/.next/standalone/.next/server/chunks/_185gyk9._.js +0 -3
  284. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__056wjo4._.js +0 -4
  285. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0n0xg95._.js +0 -4
  286. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0rwtwpm._.js +0 -4
  287. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0yrsbd_._.js +0 -3
  288. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__11mayhe._.js +0 -4
  289. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__15578wp._.js +0 -4
  290. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1m_svbe._.js +0 -4
  291. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1q4p5b8._.js +0 -4
  292. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_1n3w9lb._.js +0 -6
  293. package/.next/standalone/.next/static/chunks/1lyg_puttohbc.js +0 -1
  294. /package/.next/standalone/.next/static/{ECs8__hcNabYV58WfDh-3 → xtcpqBNBdjQVerPMkI2HI}/_buildManifest.js +0 -0
  295. /package/.next/standalone/.next/static/{ECs8__hcNabYV58WfDh-3 → xtcpqBNBdjQVerPMkI2HI}/_clientMiddlewareManifest.js +0 -0
  296. /package/.next/standalone/.next/static/{ECs8__hcNabYV58WfDh-3 → xtcpqBNBdjQVerPMkI2HI}/_ssgManifest.js +0 -0
package/scripts/launch.ts CHANGED
@@ -1,47 +1,89 @@
1
1
  /**
2
- * Shared launch logic for dev.ts and start.ts.
2
+ * Shared launch logic for dev.ts and start.ts, bare `failproofai`, and the
3
+ * dashboard hand-off at the end of `failproofai audit`.
3
4
  */
4
5
  import { spawn } from "child_process";
5
6
  import { realpathSync, existsSync } from "node:fs";
6
7
  import { resolve, dirname } from "node:path";
7
8
  import { fileURLToPath } from "node:url";
8
- import { createInterface } from "node:readline";
9
9
  import { parseScriptArgs } from "./parse-script-args";
10
10
  import { diagnoseShadow } from "./install-diagnosis.mjs";
11
- import { makeSkewLogFilter } from "./skew-log-filter";
12
- import { renderLaunchBanner } from "../src/hooks/tui";
11
+ import { colorsEnabled, screenKit } from "../src/hooks/tui";
13
12
  import { isLoopbackHostname, resolveDashboardHost } from "../lib/dashboard-host";
13
+ import { dashboardBrowseUrl, exposedBindWarning, launchFailureLines, launchScreenLines } from "./launch-screen";
14
+ import { gatherLaunchFacts } from "./launch-facts";
15
+ import { dashboardProbeHost, probeDashboardPort, watchDashboardStart } from "./launch-ready";
14
16
  import { version } from "../package.json";
15
17
 
16
- export function launch(mode: "dev" | "start"): void {
17
- const { loggingLevel, disableTelemetry, allowedDevOrigins, host, remainingArgs } = parseScriptArgs(process.argv.slice(2));
18
+ export interface LaunchOptions {
19
+ /**
20
+ * Print the launch screen. Off for `failproofai audit`, whose hand-off prints
21
+ * its own lines and the /audit address before the server starts.
22
+ */
23
+ screen?: boolean;
24
+ /**
25
+ * Draw the logomark above the screen, on a terminal. Off when the first-run
26
+ * setup wizard already drew it in this process.
27
+ */
28
+ logo?: boolean;
29
+ }
18
30
 
19
- // Branded splash — the same logomark + palette as the `configure` wizard, then
20
- // a tidy version/links column. Falls back to plain text off a TTY.
21
- for (const line of renderLaunchBanner(version)) console.log(line);
31
+ export function launch(mode: "dev" | "start", options: LaunchOptions = {}): void {
32
+ const { loggingLevel, disableTelemetry, allowedDevOrigins, host, remainingArgs } = parseScriptArgs(process.argv.slice(2));
33
+ const showScreen = options.screen !== false;
22
34
 
23
35
  // The dashboard has no authentication and can toggle policies and uninstall
24
36
  // hooks from every agent CLI, so it binds loopback unless someone asks
25
37
  // otherwise. It used to bind 0.0.0.0 unconditionally, which handed all of
26
38
  // that to every peer on the network.
27
39
  const bindHost = resolveDashboardHost(host, process.env.FAILPROOFAI_DASHBOARD_HOST);
28
- if (!isLoopbackHostname(bindHost)) {
29
- console.warn(
30
- `\n! Binding the dashboard to ${bindHost}, which is reachable from outside this machine.\n` +
31
- ` It has no authentication: anyone who can reach it can read your session\n` +
32
- ` transcripts, disable your policies, and uninstall failproofai's hooks.\n`,
33
- );
34
- }
40
+ const exposed = isLoopbackHostname(bindHost)
41
+ ? undefined
42
+ : { host: bindHost, fix: host !== undefined ? "--host 127.0.0.1" : "unset FAILPROOFAI_DASHBOARD_HOST" };
35
43
  // Read back by proxy.ts, which refuses any request whose Host is not one it
36
44
  // should be answering to — the layer that stops DNS rebinding, which a
37
45
  // loopback bind alone does not.
38
46
  process.env.FAILPROOFAI_DASHBOARD_HOST = bindHost;
39
47
 
48
+ // A routable bind is allowed, and said out loud. The launch screen carries
49
+ // that warning as its attention line; audit's hand-off has no screen, so it
50
+ // is said here, before anything listens.
51
+ if (exposed && !showScreen) {
52
+ const k = screenKit({ color: colorsEnabled(process.stderr) });
53
+ process.stderr.write(`\n${k.caution(exposedBindWarning(exposed.host))}\n ${k.cmd(exposed.fix)}\n\n`);
54
+ }
55
+
56
+ // `.next/standalone/server.js` does `process.chdir(__dirname)` on its first
57
+ // line, so by the time a server action runs, `process.cwd()` is the PACKAGE
58
+ // directory, not the directory the user launched from. Anything resolving
59
+ // project-scope paths from cwd would look inside the installed package and
60
+ // find nothing. So the real cwd is captured here, before the child starts,
61
+ // the same way FAILPROOFAI_PACKAGE_ROOT is threaded through, and the launch
62
+ // screen reads the project from the same place the dashboard will.
63
+ const launchCwd = process.env.FAILPROOFAI_LAUNCH_CWD ?? process.cwd();
64
+
65
+ const portIdx = remainingArgs.indexOf("--port");
66
+ const portFlag = portIdx >= 0 ? remainingArgs[portIdx + 1] : undefined;
67
+ // `next dev` serves on PORT, else 3000, unless --port is passed through.
68
+ const port = mode === "start" ? (portFlag ?? "8020") : (portFlag ?? process.env.PORT ?? "3000");
69
+
70
+ const printScreen = (live: boolean): void => {
71
+ const lines = launchScreenLines(
72
+ { url: dashboardBrowseUrl(bindHost, port), live, exposed, ...gatherLaunchFacts(launchCwd) },
73
+ {
74
+ color: colorsEnabled(process.stdout),
75
+ // Some pseudo-terminals report 0 columns; that is "unknown", not narrow.
76
+ cols: process.stdout.columns || undefined,
77
+ // Piped output is a log: no art in it.
78
+ logo: options.logo !== false && Boolean(process.stdout.isTTY),
79
+ },
80
+ );
81
+ process.stdout.write(`${lines.join("\n")}\n`);
82
+ };
83
+
40
84
  let cmd: string;
41
85
  let cmdArgs: string[];
42
86
  if (mode === "start") {
43
- const portIdx = remainingArgs.indexOf("--port");
44
- const port = portIdx >= 0 ? remainingArgs[portIdx + 1] : "8020";
45
87
  process.env.PORT = port;
46
88
  process.env.HOSTNAME = bindHost;
47
89
  cmd = "node";
@@ -100,52 +142,67 @@ export function launch(mode: "dev" | "start"): void {
100
142
  }
101
143
 
102
144
  // In `start` (the shipped standalone server) we pipe + filter the child's
103
- // output to drop the benign "Failed to find Server Action" deployment-skew
145
+ // output: to drop the benign "Failed to find Server Action" deployment-skew
104
146
  // block — a stale browser tab POSTing an old action ID after a rebuild, which
105
- // the client recovers from via Next's graceful 404 (see skew-log-filter.ts).
147
+ // the client recovers from via Next's graceful 404 (see skew-log-filter.ts) —
148
+ // and to learn when the server is listening, so the launch screen can say so.
106
149
  // `dev` keeps "inherit" so Next's interactive compile output is untouched.
107
- // FORCE_COLOR keeps the piped child's output colored despite the non-TTY pipe.
108
150
  const filterLogs = mode === "start";
109
151
 
152
+ // Dev never learns when its server is up, so its screen goes first, as the
153
+ // banner always did, and says it is starting.
154
+ if (!filterLogs && showScreen) printScreen(false);
155
+
110
156
  const nextProcess = spawn(cmd, cmdArgs, {
111
157
  stdio: filterLogs ? ["inherit", "pipe", "pipe"] : "inherit",
112
158
  env: {
113
159
  ...process.env,
114
- // `.next/standalone/server.js` does `process.chdir(__dirname)` on its
115
- // first line, so by the time a server action runs, `process.cwd()` is the
116
- // PACKAGE directory, not the directory the user launched from. Anything
117
- // resolving project-scope paths from cwd would look inside the installed
118
- // package and find nothing. Capture the real cwd here, before the child
119
- // starts, the same way FAILPROOFAI_PACKAGE_ROOT is threaded through.
120
- FAILPROOFAI_LAUNCH_CWD: process.env.FAILPROOFAI_LAUNCH_CWD ?? process.cwd(),
121
- ...(filterLogs ? { FORCE_COLOR: process.env.FORCE_COLOR ?? "1" } : {}),
160
+ FAILPROOFAI_LAUNCH_CWD: launchCwd,
161
+ // Keeps the piped child's output coloured despite the pipe, when this
162
+ // process is itself writing to a terminal. Not otherwise: piped output is
163
+ // a log file, and forced colour put escape codes in it.
164
+ ...(filterLogs && process.stdout.isTTY ? { FORCE_COLOR: process.env.FORCE_COLOR ?? "1" } : {}),
122
165
  ...(loggingLevel ? { FAILPROOFAI_LOG_LEVEL: loggingLevel } : {}),
123
166
  ...(disableTelemetry ? { FAILPROOFAI_TELEMETRY_DISABLED: "1" } : {}),
124
167
  ...(allowedDevOrigins ? { FAILPROOFAI_ALLOWED_DEV_ORIGINS: allowedDevOrigins.join(",") } : {}),
125
168
  },
126
169
  });
127
170
 
128
- if (filterLogs) {
129
- // One filter instance per stream — the skew block is multi-line and stateful.
130
- for (const [src, dest] of [
131
- [nextProcess.stdout, process.stdout],
132
- [nextProcess.stderr, process.stderr],
133
- ] as const) {
134
- if (!src) continue;
135
- const filter = makeSkewLogFilter();
136
- createInterface({ input: src }).on("line", (line) => {
137
- const out = filter(line);
138
- if (out !== null) dest.write(out + "\n");
139
- });
140
- }
171
+ if (!filterLogs) {
172
+ nextProcess.on("error", (error) => {
173
+ console.error("Error starting Next.js:", error);
174
+ process.exit(1);
175
+ });
176
+ nextProcess.on("exit", (code) => {
177
+ process.exit(code || 0);
178
+ });
179
+ return;
141
180
  }
142
181
 
143
- nextProcess.on("error", (error) => {
144
- console.error("Error starting Next.js:", error);
145
- process.exit(1);
146
- });
147
-
148
- nextProcess.on("exit", (code) => {
149
- process.exit(code || 0);
182
+ const failLine = (text: string): void => {
183
+ process.stderr.write(`${screenKit({ color: colorsEnabled(process.stderr) }).fail(text)}\n`);
184
+ };
185
+ watchDashboardStart({
186
+ child: nextProcess,
187
+ stdout: process.stdout,
188
+ stderr: process.stderr,
189
+ probe: () => probeDashboardPort(dashboardProbeHost(bindHost), Number(port)),
190
+ onSettled: (outcome) => {
191
+ if (outcome.kind === "failed") {
192
+ const lines = launchFailureLines(outcome, {
193
+ port,
194
+ portFromFlag: portFlag !== undefined,
195
+ color: colorsEnabled(process.stderr),
196
+ });
197
+ process.stderr.write(`${lines.join("\n")}\n`);
198
+ process.exit(outcome.code ?? 1);
199
+ return;
200
+ }
201
+ if (showScreen) printScreen(outcome.kind === "ready");
202
+ },
203
+ onExit: (code, error) => {
204
+ if (error) failLine(`The dashboard server failed: ${error.message}`);
205
+ process.exit(error ? 1 : code || 0);
206
+ },
150
207
  });
151
208
  }
@@ -44,3 +44,41 @@ export function makeSkewLogFilter(): (line: string) => string | null {
44
44
  return line;
45
45
  };
46
46
  }
47
+
48
+ /**
49
+ * Drops Next's own startup banner from the standalone server's stdout, and
50
+ * reports the moment the server is listening.
51
+ *
52
+ * The launch screen prints the dashboard's address itself once the server is
53
+ * up, so in `start` mode Next's banner would say it a second time, in another
54
+ * style:
55
+ *
56
+ * ▲ Next.js 16.3.6
57
+ * - Local: http://127.0.0.1:8020
58
+ * - Network: http://127.0.0.1:8020
59
+ * ✓ Ready in 0ms
60
+ *
61
+ * Next logs `Ready in` from its `listening` handler, straight after the banner,
62
+ * so that line doubles as the readiness signal (`onReady`). Only those four
63
+ * shapes are dropped, and only until the ready line; every other line, and
64
+ * every line after it, passes through verbatim. That is the skew filter's
65
+ * contract too, and the reason the two are separate: its test pins these exact
66
+ * lines passing through it.
67
+ *
68
+ * The child is coloured when failproofai runs on a terminal, so a line is
69
+ * matched with its SGR codes stripped and, when kept, emitted as it arrived.
70
+ */
71
+ export function makeNextStartupFilter(onReady?: () => void): (line: string) => string | null {
72
+ let listening = false;
73
+ return (line: string): string | null => {
74
+ if (listening) return line;
75
+ const plain = line.replace(/\x1B\[[0-9;]*m/g, "").trim();
76
+ if (/^(?:✓\s*)?Ready in\b/.test(plain)) {
77
+ listening = true;
78
+ onReady?.();
79
+ return null;
80
+ }
81
+ if (/^▲ Next\.js\b/.test(plain) || /^- (?:Local|Network):/.test(plain)) return null;
82
+ return line;
83
+ };
84
+ }
@@ -20,16 +20,7 @@ import {
20
20
  writeAuth,
21
21
  type StoredAuth,
22
22
  } from "../../lib/auth/auth-store";
23
- import {
24
- ANSI_RESET,
25
- BAR,
26
- colorsEnabled,
27
- intro,
28
- outro,
29
- promptText,
30
- step,
31
- stepOpen,
32
- } from "../hooks/tui";
23
+ import { INDENT, optsFor, paint, promptText, screenKit } from "../hooks/tui";
33
24
 
34
25
  const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
35
26
 
@@ -43,18 +34,6 @@ const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
43
34
  const CODE_MIN = 4;
44
35
  const CODE_MAX = 12;
45
36
 
46
- /**
47
- * The spine a prompt hangs off, so the two questions sit inside the same frame
48
- * `intro`/`outro` draw. Empty when colour is off or output is piped: the frame
49
- * is decoration, and a log file should not collect box-drawing characters.
50
- */
51
- function spine(): string {
52
- return colorsEnabled(process.stdout)
53
- ? `${ANSI_DIM_BAR}${BAR}${ANSI_RESET} `
54
- : "";
55
- }
56
- const ANSI_DIM_BAR = "\x1B[2m";
57
-
58
37
  /**
59
38
  * Codes are numeric (`auth/otp.rs` generates digits only), so anything else in
60
39
  * the field is packaging: "Your failproof code is 123456", a copied "123 456",
@@ -93,10 +72,9 @@ export interface SignedIn {
93
72
  /**
94
73
  * Whether a sign-in flow actually ran.
95
74
  *
96
- * The caller uses it to decide whether its confirmation continues an open frame
97
- * or stands on its own: the `│` spine means "a flow is happening", so printing
98
- * one under a command that answered instantly from the session file would be a
99
- * frame with no beginning.
75
+ * The caller uses it to decide whether its confirmation continues an open
76
+ * screen or opens its own: a sign-in has already printed the `Audit` header, so
77
+ * a second one under it would read as a second command.
100
78
  */
101
79
  export interface EnsureSignedIn {
102
80
  user: SignedIn;
@@ -199,35 +177,40 @@ export function invalidEmail(address: string): string | null {
199
177
  }
200
178
 
201
179
  /**
202
- * The two prompts, inside the frame `failproofai config` uses.
180
+ * The sign-in screen: `failproofai audit --schedule`'s two prompts.
203
181
  *
204
- * Same logo, same `│` spine, same `◆ / ◇` step glyphs, same pink `└` close —
205
- * because this is the same product asking, and a sign-in that looked like a
206
- * different tool would be the one moment the seam showed. It is also the only
207
- * moment this command asks for something personal, which is the moment worth
208
- * spending the frame on.
182
+ * In the language every other screen speaks — the `Audit` header, an
183
+ * UPPERCASE heading, a field per question, and a `✓` or `✕` line for each
184
+ * outcome — so a sign-in reads as the same product asking. It used to open
185
+ * with the full logomark inside `config`'s step spine, on the argument that
186
+ * the one personal question deserved the frame; the redesign keeps the mark to
187
+ * bare `failproofai` and `config` (LAUNCH-10), and the wordmark in the header
188
+ * is what every screen shares.
209
189
  *
210
190
  * Exported so a test can drive it without the caller.
211
191
  */
212
192
  export async function runLogin(preset?: string): Promise<SignedIn> {
213
- intro("scheduled audits need somewhere to send the report");
193
+ const k = screenKit(optsFor(process.stdout));
194
+ const say = (...lines: string[]) => process.stdout.write(`${lines.join("\n")}\n`);
195
+ say("", k.header("Audit"), "", k.head("Sign in"));
214
196
 
215
197
  let address: string;
216
198
  if (preset) {
217
199
  // Supplied on the command line, so the question is already answered — but
218
- // it is still SHOWN, as a settled step, because it is the address a code is
219
- // about to be sent to and the flag is exactly where a typo hides.
200
+ // it is still SHOWN, as the field it would have been typed into, because it
201
+ // is the address a code is about to be sent to and the flag is exactly
202
+ // where a typo hides.
220
203
  address = preset.trim().toLowerCase();
221
- step("your email", address);
204
+ say(`${INDENT}${"email".padEnd(10)}${paint(optsFor(process.stdout).color).pink("›")} ${address}`);
222
205
  } else {
223
206
  const email = await promptText({
224
- prefix: spine(),
225
- message: "your email",
207
+ field: true,
208
+ message: "email",
226
209
  hint: "you@yourdomain.com",
227
- validate: (v) => (EMAIL_RE.test(v.trim()) ? null : "that doesn't look like an email"),
210
+ validate: (v) => (EMAIL_RE.test(v.trim()) ? null : "That doesn't look like an email address."),
228
211
  });
229
212
  if (email === null) {
230
- outro("Cancelled — nothing was changed.", { ok: false });
213
+ say("Cancelled. Nothing was changed.");
231
214
  throw new LoginError("Cancelled.");
232
215
  }
233
216
  address = email.trim().toLowerCase();
@@ -237,65 +220,62 @@ export async function runLogin(preset?: string): Promise<SignedIn> {
237
220
  const sent = await requestLoginCode(address);
238
221
  expiresInMin = Math.max(1, Math.ceil(sent.expires_in / 60));
239
222
  } catch (err) {
240
- outro("Could not send a login code.", { ok: false });
223
+ say(k.fail("Could not send a login code."));
241
224
  throw new LoginError(describeAuthError(err, "Could not send a login code"));
242
225
  }
243
226
 
244
- // The address is echoed back on the settled step rather than left to memory:
245
- // a typo in it is the single most likely reason no code arrives, and this is
246
- // the last place it can be noticed before somebody starts waiting.
247
- step("code sent", `to ${address} · expires in ${expiresInMin} min`);
227
+ // The address is echoed back rather than left to memory: a typo in it is the
228
+ // single most likely reason no code arrives, and this is the last place it
229
+ // can be noticed before somebody starts waiting.
230
+ say(k.ok(`Sent a code to ${address}, valid for ${expiresInMin} minute${expiresInMin === 1 ? "" : "s"}.`));
248
231
 
249
232
  // Three attempts, matching the server's own per-code cap. Looping forever
250
233
  // would keep a person typing at a code the server stopped accepting after
251
234
  // the fifth try, and one attempt would punish a typo with a fresh email.
252
235
  const ATTEMPTS = 3;
253
236
  for (let attempt = 1; attempt <= ATTEMPTS; attempt += 1) {
254
- stepOpen(attempt === 1 ? "the code from that email" : "try that code again");
255
237
  const typed = await promptText({
256
- prefix: spine(),
238
+ field: true,
257
239
  message: "code",
258
240
  // Unmasked on purpose. A login code is single-use and expires in minutes,
259
241
  // so hiding it protects nothing and costs the one thing that matters at
260
242
  // this prompt: seeing your own typo before pressing enter.
261
243
  hint:
262
244
  attempt === 1
263
- ? "123456 · paste the whole line if you like"
245
+ ? "123456 · paste the whole line if you like"
264
246
  : `attempt ${attempt} of ${ATTEMPTS}`,
265
247
  validate: (v) => {
266
248
  // No digits at all is not a mistyped code, it is not a code — caught
267
249
  // here rather than spent as one of the server's five attempts.
268
- if (!/\d/.test(v)) return "a code is digits — paste the line from the email";
250
+ if (!/\d/.test(v)) return "A code is digits. Paste the line from the email.";
269
251
  const code = extractCode(v);
270
- if (code.length < CODE_MIN) return "that looks too short to be the code";
271
- if (code.length > CODE_MAX) return "that looks too long — paste just the code";
252
+ if (code.length < CODE_MIN) return "That looks too short to be the code.";
253
+ if (code.length > CODE_MAX) return "That looks too long. Paste just the code.";
272
254
  return null;
273
255
  },
274
256
  });
275
257
  if (typed === null) {
276
- outro("Cancelled — nothing was changed.", { ok: false });
258
+ say("Cancelled. Nothing was changed.");
277
259
  throw new LoginError("Cancelled.");
278
260
  }
279
261
 
280
262
  try {
281
263
  const tokens = await verifyLoginCode(address, extractCode(typed));
282
264
  writeAuth(authFromTokenResponse(tokens));
283
- step("signed in", tokens.user.email);
265
+ say(k.ok(`Signed in as ${tokens.user.email}.`));
284
266
  return { id: tokens.user.id, email: tokens.user.email };
285
267
  } catch (err) {
286
268
  const wrongCode = err instanceof AuthApiError && err.code === "invalid_code";
287
269
  if (wrongCode && attempt < ATTEMPTS) {
288
- step(
289
- "that code was wrong or expired",
290
- `${ATTEMPTS - attempt} more ${ATTEMPTS - attempt === 1 ? "try" : "tries"} before it asks for a new one`,
291
- );
270
+ // The tries left are on the next field's hint, `attempt 2 of 3`.
271
+ say(k.fail("That code was wrong or has expired."));
292
272
  continue;
293
273
  }
294
- outro("Could not verify that code.", { ok: false });
274
+ say(k.fail("Could not verify that code."));
295
275
  throw new LoginError(describeAuthError(err, "Could not verify that code"));
296
276
  }
297
277
  }
298
- outro("Too many wrong codes.", { ok: false });
278
+ say(k.fail("Too many wrong codes."));
299
279
  throw new LoginError("Too many wrong codes. Run the command again for a fresh one.");
300
280
  }
301
281