failproofai 0.0.13 → 0.0.14-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (310) hide show
  1. package/.next/standalone/.codex/hooks.json +6 -6
  2. package/.next/standalone/.cursor/hooks.json +6 -6
  3. package/.next/standalone/.factory/hooks.json +112 -0
  4. package/.next/standalone/.next/BUILD_ID +1 -1
  5. package/.next/standalone/.next/build-manifest.json +5 -5
  6. package/.next/standalone/.next/prerender-manifest.json +3 -3
  7. package/.next/standalone/.next/required-server-files.json +1 -1
  8. package/.next/standalone/.next/server/app/_global-error/page/build-manifest.json +2 -2
  9. package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
  10. package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
  11. package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  12. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  13. package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
  14. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +2 -2
  15. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
  16. package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +3 -3
  17. package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +3 -3
  18. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  19. package/.next/standalone/.next/server/app/_not-found/page/build-manifest.json +2 -2
  20. package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  21. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  22. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  23. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  24. package/.next/standalone/.next/server/app/_not-found.rsc +15 -15
  25. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +15 -15
  26. package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
  27. package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +10 -10
  28. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
  29. package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
  30. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  31. package/.next/standalone/.next/server/app/api/audit/invite/route.js.nft.json +1 -1
  32. package/.next/standalone/.next/server/app/api/audit/run/route.js +3 -3
  33. package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -1
  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.nft.json +1 -1
  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/reminder/route.js.nft.json +1 -1
  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 -1
  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 +2 -2
  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.nft.json +1 -1
  44. package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
  45. package/.next/standalone/.next/server/app/index.html +1 -1
  46. package/.next/standalone/.next/server/app/index.rsc +15 -15
  47. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  48. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +15 -15
  49. package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +4 -4
  50. package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +10 -10
  51. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  52. package/.next/standalone/.next/server/app/page/build-manifest.json +2 -2
  53. package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
  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 +2 -2
  57. package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +8 -8
  58. package/.next/standalone/.next/server/app/policies/page.js +1 -1
  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 +2 -2
  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 +3 -2
  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 +2 -2
  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 +5 -3
  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 +2 -2
  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 +1 -1
  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/chunks/[root-of-the-server]__0--lkk6._.js +3 -0
  78. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0-219ec._.js +3 -0
  79. package/.next/standalone/.next/server/chunks/[root-of-the-server]__04_h-a5._.js +3 -0
  80. package/.next/standalone/.next/server/chunks/[root-of-the-server]__06cuf1y._.js +3 -0
  81. package/.next/standalone/.next/server/chunks/[root-of-the-server]__08w4wmd._.js +3 -0
  82. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0g6bbuw._.js +3 -0
  83. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0jllheg._.js +3 -0
  84. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0jnjf2t._.js +3 -0
  85. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0q-v9z2._.js +1 -1
  86. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0q0qzx1._.js +3 -0
  87. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0q2nbsl._.js +3 -0
  88. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0rv7m0k._.js +1 -1
  89. package/.next/standalone/.next/server/chunks/[root-of-the-server]__16le-kd._.js +3 -0
  90. package/.next/standalone/.next/server/chunks/[root-of-the-server]__17g9wh7._.js +1 -1
  91. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1d9qen3._.js +3 -0
  92. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1ffkmds._.js +3 -0
  93. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1fwl2mz._.js +1 -1
  94. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1legmza._.js +1 -1
  95. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1mrihkj._.js +1 -1
  96. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1myjm-d._.js +1 -1
  97. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1qb590j._.js +3 -0
  98. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1qxztj-._.js +1 -1
  99. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1shcqgr._.js +3 -0
  100. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1xuedea._.js +3 -0
  101. package/.next/standalone/.next/server/chunks/{_1z062h5._.js → _1vslkoe._.js} +2 -2
  102. package/.next/standalone/.next/server/chunks/lib_factory-projects_ts_1eo_bk-._.js +3 -0
  103. package/.next/standalone/.next/server/chunks/lib_openclaw-projects_ts_0gc-p24._.js +3 -0
  104. package/.next/standalone/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_17k9e3w.js +24 -12
  105. package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_01r25oi._.js +1 -1
  106. package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_09z9-p7._.js +1 -1
  107. package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
  108. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__00cz9as._.js +3 -0
  109. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__015_i4t._.js +2 -2
  110. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__030k0c6._.js +3 -0
  111. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__03lv-pe._.js +2 -2
  112. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__042d3cd._.js +3 -0
  113. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__05r_17v._.js +3 -0
  114. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__09q1168._.js +3 -0
  115. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__108slqn._.js → [root-of-the-server]__0brjczq._.js} +2 -2
  116. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0e2l3c1._.js +3 -0
  117. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0hci7t3._.js +3 -0
  118. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0hdsupo._.js +2 -2
  119. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0p84xee._.js +3 -0
  120. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0qeuy9c._.js +2 -2
  121. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0s89hoe._.js +2 -2
  122. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__07iom4f._.js → [root-of-the-server]__0wp9w6i._.js} +2 -2
  123. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ynf7tx._.js +2 -2
  124. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__170799-._.js +12 -9
  125. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__17ai7sy._.js +4 -0
  126. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1d8omgc._.js +1 -1
  127. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1nq7ivq._.js +3 -0
  128. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1tkjqka._.js +2 -2
  129. package/.next/standalone/.next/server/chunks/ssr/_05whahf._.js +1 -1
  130. package/.next/standalone/.next/server/chunks/ssr/_0_9_ytf._.js +3 -0
  131. package/.next/standalone/.next/server/chunks/ssr/_11_p9y8._.js +1 -1
  132. package/.next/standalone/.next/server/chunks/ssr/{_0ul5rf_._.js → _1_ozgif._.js} +2 -2
  133. package/.next/standalone/.next/server/chunks/ssr/_1p0-leb._.js +1 -1
  134. package/.next/standalone/.next/server/chunks/ssr/app_087bt9w._.js +1 -1
  135. package/.next/standalone/.next/server/chunks/ssr/app_1fvisnp._.js +1 -1
  136. package/.next/standalone/.next/server/chunks/ssr/app_209u41o._.js +1 -1
  137. package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +2 -2
  138. package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
  139. package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +1 -1
  140. package/.next/standalone/.next/server/chunks/ssr/lib_0xkhw_v._.js +3 -0
  141. package/.next/standalone/.next/server/chunks/ssr/lib_antigravity-projects_ts_0_6zf11._.js +3 -0
  142. package/.next/standalone/.next/server/chunks/ssr/lib_devin-projects_ts_0a64qdy._.js +3 -0
  143. package/.next/standalone/.next/server/chunks/ssr/lib_factory-projects_ts_1uyaahq._.js +3 -0
  144. package/.next/standalone/.next/server/chunks/ssr/lib_goose-projects_ts_0zkscri._.js +3 -0
  145. package/.next/standalone/.next/server/chunks/ssr/lib_openclaw-projects_ts_0qxq3bp._.js +3 -0
  146. package/.next/standalone/.next/server/chunks/ssr/{node_modules_html-to-image_es_index_13p7zob.js → node_modules_html-to-image_es_index_12rjfea.js} +1 -1
  147. package/.next/standalone/.next/server/chunks/ssr/node_modules_posthog-node_dist_entrypoints_index_node_mjs_11bnuzn._.js +1 -1
  148. package/.next/standalone/.next/server/chunks/ssr/src_hooks_1ezd2jf._.js +1 -1
  149. package/.next/standalone/.next/server/chunks/ssr/src_hooks_1tnuifj._.js +1 -1
  150. package/.next/standalone/.next/server/middleware-build-manifest.js +5 -5
  151. package/.next/standalone/.next/server/pages/404.html +1 -1
  152. package/.next/standalone/.next/server/pages/500.html +1 -1
  153. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  154. package/.next/standalone/.next/server/server-reference-manifest.json +10 -10
  155. package/.next/standalone/.next/static/chunks/{13f1kmjea-0md.js → 02jcotghcxrbu.js} +1 -1
  156. package/.next/standalone/.next/static/chunks/{30ysv-_8jj052.js → 0d5lypu1zs21r.js} +1 -1
  157. package/.next/standalone/.next/static/chunks/0emg30_6svycu.js +1 -0
  158. package/.next/standalone/.next/static/chunks/0o9wpnze1ey8y.js +6 -0
  159. package/.next/standalone/.next/static/chunks/{05apzuand0c22.js → 1359o5785rmve.js} +2 -2
  160. package/.next/standalone/.next/static/chunks/20tuctw38jbgw.js +1 -0
  161. package/.next/standalone/.next/static/chunks/{0vc0eak148vo6.js → 2ldhnaweu9ew3.js} +1 -1
  162. package/.next/standalone/.next/static/chunks/{23c7v2svx90dp.js → 2vav_x0_336ds.js} +1 -1
  163. package/.next/standalone/.next/static/chunks/3-ogr79xqbw0h.js +1 -0
  164. package/.next/standalone/.next/static/chunks/36j05kb2x323i.css +2 -0
  165. package/.next/standalone/.next/static/chunks/3cg7x0joi2b98.js +1 -0
  166. package/.next/standalone/.next/static/chunks/{36wdtkgdf0zrd.js → 3k87p-tijud-4.js} +1 -1
  167. package/.next/standalone/.next/static/chunks/{2cejn75gug3j8.js → 3kmaqcp7rldad.js} +1 -1
  168. package/.next/standalone/.next/static/chunks/{turbopack-0vavqo2d-tlt3.js → turbopack-10hj8t5pf33tu.js} +1 -1
  169. package/.next/standalone/.opencode/plugins/failproofai.mjs +30 -11
  170. package/.next/standalone/app/api/audit/run/route.ts +2 -0
  171. package/.next/standalone/app/audit/_components/empty-state.tsx +1 -1
  172. package/.next/standalone/app/components/global-error-listeners.tsx +27 -0
  173. package/.next/standalone/app/globals.css +25 -1
  174. package/.next/standalone/app/policies/hooks-client.tsx +2 -4
  175. package/.next/standalone/app/project/[name]/page.tsx +30 -10
  176. package/.next/standalone/app/project/[name]/session/[sessionId]/page.tsx +71 -21
  177. package/.next/standalone/assets/logos/antigravity.svg +1 -0
  178. package/.next/standalone/assets/logos/devin.svg +1 -0
  179. package/.next/standalone/assets/logos/factory-dark.png +0 -0
  180. package/.next/standalone/assets/logos/factory-light.png +0 -0
  181. package/.next/standalone/assets/logos/goose-dark.svg +1 -0
  182. package/.next/standalone/assets/logos/goose-light.svg +1 -0
  183. package/.next/standalone/assets/logos/openclaw.svg +22 -0
  184. package/.next/standalone/ci/cli-integration/Dockerfile +47 -0
  185. package/.next/standalone/ci/cli-integration/README.md +69 -0
  186. package/.next/standalone/ci/cli-integration/canary-policies.mjs +45 -0
  187. package/.next/standalone/ci/cli-integration/capture-tokens.sh +48 -0
  188. package/.next/standalone/ci/cli-integration/inject-tokens.sh +44 -0
  189. package/.next/standalone/ci/cli-integration/install-clis.sh +91 -0
  190. package/.next/standalone/ci/cli-integration/probe-cli.sh +208 -0
  191. package/.next/standalone/ci/cli-integration/report.js +74 -0
  192. package/.next/standalone/ci/cli-integration/run.sh +107 -0
  193. package/.next/standalone/components/navbar.tsx +5 -11
  194. package/.next/standalone/components/reach-developers.tsx +2 -2
  195. package/.next/standalone/docker-hook-sync/Dockerfile +8 -4
  196. package/.next/standalone/lib/antigravity-projects.ts +224 -0
  197. package/.next/standalone/lib/antigravity-sessions.ts +283 -0
  198. package/.next/standalone/lib/cli-registry.ts +26 -6
  199. package/.next/standalone/lib/devin-projects.ts +141 -0
  200. package/.next/standalone/lib/devin-sessions.ts +343 -0
  201. package/.next/standalone/lib/download-session.ts +56 -5
  202. package/.next/standalone/lib/error-origin.ts +67 -0
  203. package/.next/standalone/lib/factory-projects.ts +109 -0
  204. package/.next/standalone/lib/factory-sessions.ts +312 -0
  205. package/.next/standalone/lib/goose-projects.ts +148 -0
  206. package/.next/standalone/lib/goose-sessions.ts +296 -0
  207. package/.next/standalone/lib/install-check.ts +231 -0
  208. package/.next/standalone/lib/openclaw-projects.ts +182 -0
  209. package/.next/standalone/lib/openclaw-sessions.ts +284 -0
  210. package/.next/standalone/lib/projects.ts +33 -9
  211. package/.next/standalone/lib/telemetry-sanitize.ts +43 -0
  212. package/.next/standalone/openclaw-plugin/index.js +223 -0
  213. package/.next/standalone/openclaw-plugin/openclaw.plugin.json +6 -0
  214. package/.next/standalone/openclaw-plugin/package.json +12 -0
  215. package/.next/standalone/package.json +2 -3
  216. package/.next/standalone/server.js +1 -1
  217. package/README.md +94 -62
  218. package/bin/failproofai.mjs +98 -30
  219. package/dist/cli.mjs +12499 -9243
  220. package/lib/antigravity-projects.ts +224 -0
  221. package/lib/antigravity-sessions.ts +283 -0
  222. package/lib/cli-registry.ts +26 -6
  223. package/lib/devin-projects.ts +141 -0
  224. package/lib/devin-sessions.ts +343 -0
  225. package/lib/download-session.ts +56 -5
  226. package/lib/error-origin.ts +67 -0
  227. package/lib/factory-projects.ts +109 -0
  228. package/lib/factory-sessions.ts +312 -0
  229. package/lib/goose-projects.ts +148 -0
  230. package/lib/goose-sessions.ts +296 -0
  231. package/lib/install-check.ts +231 -0
  232. package/lib/openclaw-projects.ts +182 -0
  233. package/lib/openclaw-sessions.ts +284 -0
  234. package/lib/projects.ts +33 -9
  235. package/lib/telemetry-sanitize.ts +43 -0
  236. package/openclaw-plugin/index.js +223 -0
  237. package/openclaw-plugin/openclaw.plugin.json +6 -0
  238. package/openclaw-plugin/package.json +12 -0
  239. package/package.json +2 -3
  240. package/scripts/dev-hook.mjs +292 -0
  241. package/scripts/install-diagnosis.mjs +5 -8
  242. package/scripts/install-telemetry.mjs +12 -4
  243. package/scripts/launch.ts +4 -8
  244. package/scripts/sync-agent-cli-harnesses-prompt.md +7 -10
  245. package/scripts/translate-docs/cli.ts +120 -53
  246. package/scripts/translate-docs/config.ts +57 -13
  247. package/scripts/translate-docs/mdx-translator.ts +177 -28
  248. package/scripts/translate-docs/mintlify-nav.ts +91 -10
  249. package/scripts/translate-docs/readme-translator.ts +13 -5
  250. package/scripts/translate-docs/translator.ts +38 -2
  251. package/scripts/translate-docs/types.ts +3 -0
  252. package/scripts/validate-mdx.ts +12 -4
  253. package/src/audit/cli-adapters/antigravity.ts +87 -0
  254. package/src/audit/cli-adapters/devin.ts +53 -0
  255. package/src/audit/cli-adapters/factory.ts +75 -0
  256. package/src/audit/cli-adapters/goose.ts +53 -0
  257. package/src/audit/cli-adapters/index.ts +30 -6
  258. package/src/audit/cli-adapters/openclaw.ts +56 -0
  259. package/src/audit/cli.ts +83 -8
  260. package/src/audit/report.ts +1 -1
  261. package/src/audit/types.ts +1 -1
  262. package/src/hooks/builtin-policies.ts +5 -5
  263. package/src/hooks/configure-wizard.ts +356 -0
  264. package/src/hooks/handler.ts +283 -218
  265. package/src/hooks/hook-telemetry.ts +43 -3
  266. package/src/hooks/install-prompt.ts +92 -173
  267. package/src/hooks/integrations.ts +739 -138
  268. package/src/hooks/manager.ts +46 -2
  269. package/src/hooks/policy-evaluator.ts +301 -121
  270. package/src/hooks/policy-presets.ts +71 -0
  271. package/src/hooks/resolve-cwd.ts +1 -1
  272. package/src/hooks/resolve-permission-mode.ts +1 -5
  273. package/src/hooks/resolve-transcript-path.ts +25 -7
  274. package/src/hooks/tool-name-canonicalize.ts +36 -3
  275. package/src/hooks/tui.ts +578 -0
  276. package/src/hooks/types.ts +447 -109
  277. package/.next/standalone/.gemini/settings.json +0 -147
  278. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0cag8qd._.js +0 -3
  279. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0cefjd9._.js +0 -3
  280. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ekj92q._.js +0 -3
  281. package/.next/standalone/.next/server/chunks/[root-of-the-server]__12v-lma._.js +0 -3
  282. package/.next/standalone/.next/server/chunks/[root-of-the-server]__136y39g._.js +0 -3
  283. package/.next/standalone/.next/server/chunks/[root-of-the-server]__13h8pzr._.js +0 -3
  284. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1hgv_75._.js +0 -3
  285. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__04bqvos._.js +0 -3
  286. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0dqgs96._.js +0 -3
  287. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0q5rfxg._.js +0 -3
  288. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0qukut7._.js +0 -4
  289. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1ql-mch._.js +0 -3
  290. package/.next/standalone/.next/server/chunks/ssr/_11v0g3z._.js +0 -3
  291. package/.next/standalone/.next/server/chunks/ssr/lib_gemini-projects_ts_1c7bgx-._.js +0 -3
  292. package/.next/standalone/.next/static/chunks/0fa7j157kg9_d.js +0 -1
  293. package/.next/standalone/.next/static/chunks/0nrah-qv6smeg.js +0 -6
  294. package/.next/standalone/.next/static/chunks/0wtagd8a5gwq-.js +0 -1
  295. package/.next/standalone/.next/static/chunks/1c8i78p7t1i-5.js +0 -1
  296. package/.next/standalone/.next/static/chunks/25qr0e6ez0ei0.js +0 -1
  297. package/.next/standalone/.next/static/chunks/25s52un3k_wht.css +0 -2
  298. package/.next/standalone/assets/logos/gemini-dark.svg +0 -13
  299. package/.next/standalone/assets/logos/gemini-light.svg +0 -13
  300. package/.next/standalone/lib/gemini-projects.ts +0 -243
  301. package/.next/standalone/lib/gemini-sessions.ts +0 -365
  302. package/lib/gemini-projects.ts +0 -243
  303. package/lib/gemini-sessions.ts +0 -365
  304. package/scripts/postinstall.mjs +0 -243
  305. package/scripts/preuninstall.mjs +0 -131
  306. package/src/audit/cli-adapters/gemini.ts +0 -51
  307. package/src/hooks/first-run-nudge.ts +0 -146
  308. /package/.next/standalone/.next/static/{kmzdjTLVs6LqsfyOaUf69 → LkN-JjmhKGmL-WklH7WVi}/_buildManifest.js +0 -0
  309. /package/.next/standalone/.next/static/{kmzdjTLVs6LqsfyOaUf69 → LkN-JjmhKGmL-WklH7WVi}/_clientMiddlewareManifest.js +0 -0
  310. /package/.next/standalone/.next/static/{kmzdjTLVs6LqsfyOaUf69 → LkN-JjmhKGmL-WklH7WVi}/_ssgManifest.js +0 -0
@@ -1,243 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * postinstall script for the failproofai package.
4
- *
5
- * 1. Warns if hooks config exists but hooks are missing from Claude Code settings.
6
- * 2. Tracks a package_installed telemetry event.
7
- *
8
- * No external dependencies — Node.js built-ins only.
9
- */
10
- import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
11
- import { resolve } from "node:path";
12
- import { platform, arch, release, homedir, hostname } from "node:os";
13
- import { createHmac } from "node:crypto";
14
- import { trackInstallEvent } from "./install-telemetry.mjs";
15
- import { diagnoseShadow } from "./install-diagnosis.mjs";
16
-
17
- // Skip when running in development context (e.g. `bun install` in the source repo).
18
- // INIT_CWD is set by npm/bun to the directory where install was invoked; it differs
19
- // from process.cwd() only when we are being installed as a dependency by someone else.
20
- if (!process.env.INIT_CWD || process.env.INIT_CWD === process.cwd()) process.exit(0);
21
-
22
- // Verify server.js exists — fail the install early if the dashboard build is missing.
23
- const serverJsPath = resolve(process.cwd(), ".next", "standalone", "server.js");
24
- if (!existsSync(serverJsPath)) {
25
- console.error(
26
- `\n[failproofai] Error: server.js not found at:\n ${serverJsPath}\n\n` +
27
- ` The package may not have been built correctly.\n` +
28
- ` Try reinstalling: npm install -g failproofai@latest\n`
29
- );
30
- // Await so the event lands before process.exit(1) kills the in-flight fetch —
31
- // a failed install is exactly the signal we most want and would otherwise lose.
32
- await trackInstallEvent("package_install_failed", {
33
- reason: "server_js_missing",
34
- platform: platform(),
35
- arch: arch(),
36
- node_version: process.versions.node,
37
- }).catch(() => {});
38
- process.exit(1);
39
- }
40
-
41
- // Detect when an older `failproofai` is shadowing this fresh install on PATH —
42
- // classic case is a leftover `bun link` from a prior dev session, or a
43
- // `bun install -g` whose ~/.bun/bin sorts ahead of npm's prefix. Without this
44
- // warning the user only finds out later via a confusing runtime error from
45
- // scripts/launch.ts pointing at the *old* install's missing build output.
46
- try {
47
- let selfVersion = null;
48
- try {
49
- selfVersion = JSON.parse(readFileSync(resolve(process.cwd(), "package.json"), "utf8")).version ?? null;
50
- } catch {}
51
- const diag = diagnoseShadow({ selfPackageRoot: process.cwd(), selfVersion });
52
- if (diag.shadowed) {
53
- console.warn(
54
- `\n[failproofai] Warning: another failproofai install is earlier on your PATH.\n` +
55
- ` Just installed: ${diag.selfPackageRoot}` + (diag.selfVersion ? ` (v${diag.selfVersion})` : "") + `\n` +
56
- ` PATH resolves : ${diag.pathFirstPath}` + (diag.pathFirstVersion ? ` (v${diag.pathFirstVersion})` : "") + `\n\n` +
57
- ` Your shell will run the older copy. Remove the shadow with:\n` +
58
- ` ${diag.recommendation}\n`
59
- );
60
- }
61
- } catch {
62
- // Diagnosis is best-effort — never fail the install over a warning.
63
- }
64
-
65
- const FAILPROOFAI_HOOK_MARKER = "__failproofai_hook__";
66
- const NAMESPACE = "failproofai-telemetry-v1";
67
-
68
- function hashToId(raw) {
69
- return createHmac("sha256", NAMESPACE).update(raw).digest("hex");
70
- }
71
-
72
- /**
73
- * Returns the current hooks configuration state.
74
- * @returns {{ configured: boolean, registered: boolean, policyCount: number }}
75
- */
76
- function checkHooks() {
77
- const hooksConfigPath = resolve(homedir(), ".failproofai", "policies-config.json");
78
- if (!existsSync(hooksConfigPath)) {
79
- return { configured: false, registered: false, policyCount: 0 };
80
- }
81
-
82
- let config;
83
- try {
84
- config = JSON.parse(readFileSync(hooksConfigPath, "utf8"));
85
- } catch {
86
- return { configured: false, registered: false, policyCount: 0 };
87
- }
88
-
89
- if (!Array.isArray(config.enabledPolicies) || config.enabledPolicies.length === 0) {
90
- return { configured: false, registered: false, policyCount: 0 };
91
- }
92
-
93
- const policyCount = config.enabledPolicies.length;
94
-
95
- // Check if Claude Code settings have failproofai hooks
96
- const settingsPath = resolve(homedir(), ".claude", "settings.json");
97
- if (!existsSync(settingsPath)) {
98
- printHooksWarning();
99
- return { configured: true, registered: false, policyCount };
100
- }
101
-
102
- let settings;
103
- try {
104
- settings = JSON.parse(readFileSync(settingsPath, "utf8"));
105
- } catch {
106
- printHooksWarning();
107
- return { configured: true, registered: false, policyCount };
108
- }
109
-
110
- if (!settings.hooks) {
111
- printHooksWarning();
112
- return { configured: true, registered: false, policyCount };
113
- }
114
-
115
- // Walk settings.hooks looking for failproofai entries
116
- for (const matchers of Object.values(settings.hooks)) {
117
- if (!Array.isArray(matchers)) continue;
118
- for (const matcher of matchers) {
119
- if (!matcher.hooks) continue;
120
- if (matcher.hooks.some((h) => h[FAILPROOFAI_HOOK_MARKER] === true)) {
121
- return { configured: true, registered: true, policyCount };
122
- }
123
- }
124
- }
125
-
126
- printHooksWarning();
127
- return { configured: true, registered: false, policyCount };
128
- }
129
-
130
- function printHooksWarning() {
131
- console.log(
132
- `\n[failproofai] Warning: hooks config exists with enabled policies, but hooks are not registered in Claude Code settings.\n` +
133
- ` To re-register hooks, run:\n` +
134
- ` failproofai policies --uninstall && failproofai policies --install\n`
135
- );
136
- }
137
-
138
- let hooksResult = { configured: false, registered: false, policyCount: 0 };
139
- try {
140
- hooksResult = checkHooks();
141
- } catch {
142
- // Non-critical — don't fail the install
143
- }
144
-
145
- if (!hooksResult.configured && !hooksResult.registered) {
146
- console.log(
147
- `\n[failproofai] Installed. Next steps:\n` +
148
- ` 1. Run \`failproofai policies --install\` to enable safety policies.\n` +
149
- ` 2. Run \`failproofai\` to open the dashboard (or just \`failproofai\` to start now — it'll offer to set up policies for you).\n` +
150
- ` Disable first-run prompt: FAILPROOFAI_NO_FIRST_RUN=1\n`
151
- );
152
- }
153
-
154
- // First-run + version_changed detection. The presence of ~/.failproofai/last-version
155
- // is a stable signal: written on every postinstall, absent before the first one.
156
- // Cannot piggy-back on instance-id because most users hit Tier 2 (OS machine ID)
157
- // and never create that file.
158
- //
159
- // Semver comparison: a release (no prerelease tag) is greater than the same
160
- // version with a prerelease tag (semver §11). Inside the prerelease, numeric
161
- // identifiers are lower than non-numeric ones of the same length.
162
- function compareSemver(a, b) {
163
- const parse = (v) => {
164
- const m = /^(\d+)\.(\d+)\.(\d+)(?:-(.+))?$/.exec(v);
165
- if (!m) return null;
166
- return { nums: [Number(m[1]), Number(m[2]), Number(m[3])], pre: m[4] ?? null };
167
- };
168
- const pa = parse(a);
169
- const pb = parse(b);
170
- if (!pa || !pb) return a < b ? -1 : a > b ? 1 : 0;
171
- for (let i = 0; i < 3; i++) {
172
- if (pa.nums[i] !== pb.nums[i]) return pa.nums[i] < pb.nums[i] ? -1 : 1;
173
- }
174
- if (pa.pre === null && pb.pre === null) return 0;
175
- if (pa.pre === null) return 1;
176
- if (pb.pre === null) return -1;
177
- const ax = pa.pre.split(/[.-]/);
178
- const bx = pb.pre.split(/[.-]/);
179
- for (let i = 0; i < Math.max(ax.length, bx.length); i++) {
180
- const ai = ax[i], bi = bx[i];
181
- if (ai === undefined) return -1;
182
- if (bi === undefined) return 1;
183
- const aNum = /^\d+$/.test(ai), bNum = /^\d+$/.test(bi);
184
- if (aNum && bNum) {
185
- const d = Number(ai) - Number(bi);
186
- if (d !== 0) return d < 0 ? -1 : 1;
187
- } else if (aNum) {
188
- return -1;
189
- } else if (bNum) {
190
- return 1;
191
- } else if (ai !== bi) {
192
- return ai < bi ? -1 : 1;
193
- }
194
- }
195
- return 0;
196
- }
197
-
198
- const currentVersion = process.env.npm_package_version ?? "unknown";
199
- const lastVersionFile = resolve(homedir(), ".failproofai", "last-version");
200
- let previousVersion = null;
201
- try {
202
- if (existsSync(lastVersionFile)) {
203
- previousVersion = readFileSync(lastVersionFile, "utf8").trim() || null;
204
- }
205
- } catch {}
206
-
207
- if (previousVersion === null) {
208
- trackInstallEvent("first_install", {
209
- platform: platform(),
210
- arch: arch(),
211
- os_release: release(),
212
- node_version: process.versions.node,
213
- // `version` is carried automatically as `failproofai_version` — no explicit dup.
214
- }).catch(() => {});
215
- } else {
216
- // Same version is a reinstall — still worth tracking; users hitting `npm install -g`
217
- // repeatedly is itself signal. Drop the `!==` guard so cmp===0 reaches the event.
218
- const cmp = compareSemver(previousVersion, currentVersion);
219
- trackInstallEvent("version_changed", {
220
- from_version: previousVersion,
221
- to_version: currentVersion,
222
- direction: cmp < 0 ? "upgrade" : cmp > 0 ? "downgrade" : "reinstall",
223
- platform: platform(),
224
- arch: arch(),
225
- }).catch(() => {});
226
- }
227
-
228
- try {
229
- mkdirSync(resolve(homedir(), ".failproofai"), { recursive: true });
230
- writeFileSync(lastVersionFile, currentVersion, "utf8");
231
- } catch {}
232
-
233
- // Telemetry (best-effort, fire-and-forget)
234
- trackInstallEvent("package_installed", {
235
- platform: platform(),
236
- arch: arch(),
237
- os_release: release(),
238
- node_version: process.versions.node,
239
- hostname_hash: hashToId(hostname()),
240
- hooks_configured: hooksResult.configured,
241
- hooks_registered: hooksResult.registered,
242
- enabled_policy_count: hooksResult.policyCount,
243
- }).catch(() => {});
@@ -1,131 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * preuninstall script for the failproofai package.
4
- *
5
- * Removes failproofai hook entries from all reachable Claude Code settings files:
6
- * - ~/.claude/settings.json (user scope — always attempted)
7
- * - {cwd}/.claude/settings.json (project scope — if it exists)
8
- * - {cwd}/.claude/settings.local.json (local scope — if it exists)
9
- *
10
- * Does NOT delete ~/.failproofai/ (preserves cache, hooks-config, instance-id).
11
- *
12
- * Never exits non-zero — uninstall must not be blocked by cleanup failures.
13
- * No external dependencies — Node.js built-ins only.
14
- */
15
- import { readFileSync, writeFileSync, existsSync } from "node:fs";
16
- import { resolve } from "node:path";
17
- import { homedir, platform, arch } from "node:os";
18
- import { trackInstallEvent } from "./install-telemetry.mjs";
19
-
20
- // Skip when running in development context (same guard as postinstall.mjs).
21
- if (process.env.INIT_CWD && process.env.INIT_CWD === process.cwd()) process.exit(0);
22
-
23
- const FAILPROOFAI_HOOK_MARKER = "__failproofai_hook__";
24
-
25
- /**
26
- * Remove all failproofai-marked hook entries from a single settings file.
27
- * Returns the number of hook entries removed.
28
- * Writes the file only when at least one hook was removed.
29
- */
30
- function removeHooksFromFile(settingsPath) {
31
- if (!existsSync(settingsPath)) return 0;
32
-
33
- let settings;
34
- try {
35
- settings = JSON.parse(readFileSync(settingsPath, "utf8"));
36
- } catch {
37
- return 0; // Corrupt or unreadable — nothing to do
38
- }
39
-
40
- if (!settings?.hooks) return 0;
41
-
42
- let hooksRemoved = 0;
43
-
44
- for (const eventType of Object.keys(settings.hooks)) {
45
- const matchers = settings.hooks[eventType];
46
- if (!Array.isArray(matchers)) continue;
47
-
48
- for (let i = matchers.length - 1; i >= 0; i--) {
49
- const matcher = matchers[i];
50
- if (!matcher.hooks) continue;
51
-
52
- const before = matcher.hooks.length;
53
- matcher.hooks = matcher.hooks.filter((h) => {
54
- if (h[FAILPROOFAI_HOOK_MARKER] === true) return false; // marked entry
55
- // Fallback for legacy installs that predate the marker
56
- const cmd = typeof h.command === "string" ? h.command : "";
57
- if (cmd.includes("failproofai") && cmd.includes("--hook")) return false;
58
- return true;
59
- });
60
- hooksRemoved += before - matcher.hooks.length;
61
-
62
- // Remove now-empty matchers
63
- if (matcher.hooks.length === 0) {
64
- matchers.splice(i, 1);
65
- }
66
- }
67
-
68
- // Remove now-empty event type arrays
69
- if (matchers.length === 0) {
70
- delete settings.hooks[eventType];
71
- }
72
- }
73
-
74
- // Remove now-empty hooks object
75
- if (Object.keys(settings.hooks).length === 0) {
76
- delete settings.hooks;
77
- }
78
-
79
- if (hooksRemoved > 0) {
80
- try {
81
- writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf8");
82
- } catch {
83
- // Best-effort — don't block uninstall
84
- }
85
- }
86
-
87
- return hooksRemoved;
88
- }
89
-
90
- let totalRemoved = 0;
91
-
92
- try {
93
- const home = homedir();
94
- const projectCwd = process.cwd();
95
-
96
- // Build list of settings files to clean, deduped in case cwd === home
97
- const candidates = [
98
- resolve(home, ".claude", "settings.json"), // user scope
99
- resolve(projectCwd, ".claude", "settings.json"), // project scope
100
- resolve(projectCwd, ".claude", "settings.local.json"), // local scope
101
- ];
102
- const seen = new Set();
103
- const settingsPaths = candidates.filter((p) => {
104
- if (seen.has(p)) return false;
105
- seen.add(p);
106
- return true;
107
- });
108
-
109
- for (const settingsPath of settingsPaths) {
110
- const removed = removeHooksFromFile(settingsPath);
111
- if (removed > 0) {
112
- console.log(`[failproofai] Removed ${removed} hook(s) from ${settingsPath}.`);
113
- totalRemoved += removed;
114
- }
115
- }
116
-
117
- if (totalRemoved === 0) {
118
- console.log("[failproofai] No hook entries found to remove.");
119
- }
120
- } catch {
121
- // Never block uninstall
122
- }
123
-
124
- // Telemetry — best-effort, awaited so the process stays alive long enough to send
125
- try {
126
- await trackInstallEvent("package_uninstalled", {
127
- platform: platform(),
128
- arch: arch(),
129
- hooks_removed: totalRemoved,
130
- });
131
- } catch {}
@@ -1,51 +0,0 @@
1
- /**
2
- * Gemini CLI transcript adapter.
3
- */
4
- import { statSync } from "node:fs";
5
- import { getGeminiProjects, getGeminiSessionsByEncodedName } from "../../../lib/gemini-projects";
6
- import { getGeminiSessionLog } from "../../../lib/gemini-sessions";
7
- import type { NormalizedToolEvent, TranscriptMetadata } from "../types";
8
- import type { ListOpts } from "./claude";
9
- import { logEntriesToEvents } from "./shared";
10
-
11
- export async function listGeminiTranscriptMetadata(
12
- opts: ListOpts = {},
13
- ): Promise<TranscriptMetadata[]> {
14
- const projectFilter = opts.projects ? new Set(opts.projects) : null;
15
- const sinceMs = opts.sinceMs ?? 0;
16
- const out: TranscriptMetadata[] = [];
17
-
18
- const projects = await getGeminiProjects();
19
- for (const project of projects) {
20
- const { cwd, sessions } = await getGeminiSessionsByEncodedName(project.name);
21
- const effectiveCwd = cwd ?? "";
22
- if (projectFilter && !projectFilter.has(effectiveCwd)) continue;
23
- for (const s of sessions) {
24
- const mtimeMs = s.lastModified.getTime();
25
- if (mtimeMs < sinceMs) continue;
26
- let sizeBytes = 0;
27
- try { sizeBytes = statSync(s.path).size; } catch { /* unreadable */ }
28
- if (!s.sessionId) continue;
29
- out.push({
30
- cli: "gemini",
31
- projectName: project.name,
32
- sessionId: s.sessionId,
33
- transcriptPath: s.path,
34
- mtimeMs,
35
- sizeBytes,
36
- });
37
- }
38
- }
39
- return out;
40
- }
41
-
42
- export async function streamGeminiEvents(meta: TranscriptMetadata): Promise<NormalizedToolEvent[]> {
43
- const log = await getGeminiSessionLog(meta.sessionId);
44
- if (!log) return [];
45
- return logEntriesToEvents(log.entries, {
46
- cli: "gemini",
47
- sessionId: meta.sessionId,
48
- transcriptPath: meta.transcriptPath,
49
- cwd: log.cwd ?? "",
50
- });
51
- }
@@ -1,146 +0,0 @@
1
- /**
2
- * First-run nudge for `failproofai` (no-args invocation).
3
- *
4
- * Fires when a user runs the bare CLI without having installed any policies on
5
- * any detected agent CLI. PostHog data showed only ~10% of npm-installed users
6
- * ran `failproofai policies --install`; this prompt closes the awareness gap
7
- * by offering to run that install inline.
8
- *
9
- * The hooks themselves are the sentinel — if any are installed for any
10
- * detected CLI, we never prompt again. No separate state file needed.
11
- *
12
- * Honors `FAILPROOFAI_NO_FIRST_RUN=1` for opt-out, falls back to a short
13
- * stderr hint in non-TTY contexts (CI, piped invocations).
14
- */
15
- import * as readline from "node:readline";
16
-
17
- import { detectInstalledClis, getIntegration } from "./integrations";
18
- import { installHooks } from "./manager";
19
- import { trackHookEvent } from "./hook-telemetry";
20
- import { getInstanceId } from "../../lib/telemetry-id";
21
- import type { IntegrationType } from "./types";
22
-
23
- type TTYIn = NodeJS.ReadableStream & { isTTY?: boolean };
24
- type TTYOut = NodeJS.WritableStream & { isTTY?: boolean };
25
-
26
- export interface FirstRunNudgeOptions {
27
- stdin?: TTYIn;
28
- stdout?: TTYOut;
29
- }
30
-
31
- async function emit(event: string, props: Record<string, unknown>): Promise<void> {
32
- try {
33
- await trackHookEvent(getInstanceId(), event, props);
34
- } catch {
35
- // Telemetry must never break first-run UX.
36
- }
37
- }
38
-
39
- function anyHooksInstalled(detected: IntegrationType[]): boolean {
40
- for (const id of detected) {
41
- const integration = getIntegration(id);
42
- for (const scope of integration.scopes) {
43
- try {
44
- if (integration.hooksInstalledInSettings(scope)) return true;
45
- } catch {
46
- // A broken settings file shouldn't suppress the nudge.
47
- }
48
- }
49
- }
50
- return false;
51
- }
52
-
53
- function clisLabel(detected: IntegrationType[]): string {
54
- return detected.map((id) => getIntegration(id).displayName).join(", ");
55
- }
56
-
57
- async function promptYesNo(
58
- stdin: TTYIn,
59
- stdout: TTYOut,
60
- ): Promise<"yes" | "no" | "sigint"> {
61
- return new Promise((resolve) => {
62
- const rl = readline.createInterface({ input: stdin, output: stdout });
63
- let settled = false;
64
- const finish = (answer: "yes" | "no" | "sigint") => {
65
- if (settled) return;
66
- settled = true;
67
- rl.close();
68
- resolve(answer);
69
- };
70
- rl.on("SIGINT", () => finish("sigint"));
71
- rl.question("Install policies now? [Y/n] ", (raw) => {
72
- const a = (raw ?? "").trim().toLowerCase();
73
- if (a === "" || a === "y" || a === "yes") finish("yes");
74
- else finish("no");
75
- });
76
- });
77
- }
78
-
79
- export async function maybeRunFirstRunNudge(opts: FirstRunNudgeOptions = {}): Promise<void> {
80
- if (process.env.FAILPROOFAI_NO_FIRST_RUN === "1") return;
81
-
82
- const stdin: TTYIn = opts.stdin ?? process.stdin;
83
- const stdout: TTYOut = opts.stdout ?? process.stdout;
84
-
85
- let detected: IntegrationType[];
86
- try {
87
- detected = detectInstalledClis();
88
- } catch {
89
- return;
90
- }
91
- if (detected.length === 0) return;
92
-
93
- if (anyHooksInstalled(detected)) return;
94
-
95
- const detectedProps = { detected_clis: detected, detected_count: detected.length };
96
-
97
- if (!stdin.isTTY || !stdout.isTTY) {
98
- stdout.write(
99
- `\n[failproofai] No policies are installed. Run \`failproofai policies --install\` to set them up.\n` +
100
- `[failproofai] Launching dashboard…\n\n`,
101
- );
102
- await emit("first_run_nudge_skipped_noninteractive", detectedProps);
103
- return;
104
- }
105
-
106
- stdout.write(
107
- `\n┌─ Failproof AI — first-run setup ────────────────────────────────────\n` +
108
- `│ Detected agent CLI(s): ${clisLabel(detected)}\n` +
109
- `│ Policies block unsafe actions (sudo, rm -rf /, secret leaks, …)\n` +
110
- `│ before your agent runs them. Nothing is installed yet.\n` +
111
- `└──────────────────────────────────────────────────────────────────────\n\n` +
112
- ` Disable this prompt anytime: FAILPROOFAI_NO_FIRST_RUN=1\n\n`,
113
- );
114
-
115
- await emit("first_run_nudge_shown", detectedProps);
116
-
117
- const answer = await promptYesNo(stdin, stdout);
118
-
119
- if (answer === "sigint") {
120
- await emit("first_run_nudge_declined", { ...detectedProps, reason: "sigint" });
121
- process.exit(130);
122
- }
123
-
124
- if (answer === "no") {
125
- await emit("first_run_nudge_declined", { ...detectedProps, reason: "user_no" });
126
- return;
127
- }
128
-
129
- await emit("first_run_nudge_accepted", {
130
- ...detectedProps,
131
- target_scope: "user",
132
- source: "first-run-nudge",
133
- });
134
-
135
- await installHooks(
136
- undefined,
137
- "user",
138
- undefined,
139
- false,
140
- "first-run-nudge",
141
- undefined,
142
- false,
143
- detected,
144
- );
145
- process.exit(0);
146
- }