failproofai 1.0.4-beta.7 → 1.0.4

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 (221) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/build-manifest.json +5 -5
  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 +2 -2
  6. package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
  7. package/.next/standalone/.next/server/app/_global-error/page.js +2 -2
  8. package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
  9. package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  10. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  11. package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
  12. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +6 -6
  13. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
  14. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  15. package/.next/standalone/.next/server/app/_not-found/page/build-manifest.json +2 -2
  16. package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  17. package/.next/standalone/.next/server/app/_not-found/page.js +2 -2
  18. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  19. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  20. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  21. package/.next/standalone/.next/server/app/_not-found.rsc +14 -14
  22. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +14 -14
  23. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +13 -13
  24. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  25. package/.next/standalone/.next/server/app/api/audit/invite/route.js.nft.json +1 -1
  26. package/.next/standalone/.next/server/app/api/audit/run/route.js +4 -4
  27. package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -1
  28. package/.next/standalone/.next/server/app/api/audit/status/route.js.nft.json +1 -1
  29. package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -1
  30. package/.next/standalone/.next/server/app/api/auth/login-verify/route.js.nft.json +1 -1
  31. package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
  32. package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -1
  33. package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
  34. package/.next/standalone/.next/server/app/audit/page/build-manifest.json +2 -2
  35. package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +4 -37
  36. package/.next/standalone/.next/server/app/audit/page.js +2 -2
  37. package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -1
  38. package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
  39. package/.next/standalone/.next/server/app/index.html +1 -1
  40. package/.next/standalone/.next/server/app/index.rsc +14 -14
  41. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +13 -13
  42. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +14 -14
  43. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  44. package/.next/standalone/.next/server/app/page/build-manifest.json +2 -2
  45. package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
  46. package/.next/standalone/.next/server/app/page.js +2 -2
  47. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  48. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  49. package/.next/standalone/.next/server/app/policies/page/build-manifest.json +2 -2
  50. package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +14 -14
  51. package/.next/standalone/.next/server/app/policies/page.js +4 -4
  52. package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
  53. package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
  54. package/.next/standalone/.next/server/app/project/[name]/page/build-manifest.json +2 -2
  55. package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
  56. package/.next/standalone/.next/server/app/project/[name]/page.js +3 -3
  57. package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
  58. package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
  59. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/build-manifest.json +2 -2
  60. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
  61. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
  62. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js +4 -4
  63. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
  64. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
  65. package/.next/standalone/.next/server/app/projects/page/build-manifest.json +2 -2
  66. package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
  67. package/.next/standalone/.next/server/app/projects/page.js +3 -3
  68. package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
  69. package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  70. package/.next/standalone/.next/server/app/settings/page/build-manifest.json +2 -2
  71. package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +4 -15
  72. package/.next/standalone/.next/server/app/settings/page.js +4 -4
  73. package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
  74. package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  75. package/.next/standalone/.next/server/chunks/{[externals]__0v1hz15._.js → [externals]__0-9ti7z._.js} +1 -1
  76. package/.next/standalone/.next/server/chunks/{[externals]__1nb206a._.js → [externals]__0u3wrvq._.js} +1 -1
  77. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0o07qi9._.js +1 -1
  78. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0rv7m0k._.js +1 -1
  79. package/.next/standalone/.next/server/chunks/[root-of-the-server]__17g9wh7._.js +1 -1
  80. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1legmza._.js +1 -1
  81. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1p-qi2t._.js +1 -1
  82. package/.next/standalone/.next/server/chunks/_0tovk6q._.js +1 -1
  83. package/.next/standalone/.next/server/chunks/_0trp3yc._.js +1 -1
  84. package/.next/standalone/.next/server/chunks/{_0otft92._.js → _1-akg6w._.js} +2 -2
  85. package/.next/standalone/.next/server/chunks/_1ek68ln._.js +10 -10
  86. package/.next/standalone/.next/server/chunks/_1vslkoe._.js +1 -1
  87. package/.next/standalone/.next/server/chunks/lib_telemetry_ts_0dctyyw._.js +1 -1
  88. package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
  89. package/.next/standalone/.next/server/chunks/src_hooks_fp-home_ts_09kv0bn._.js +1 -1
  90. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1fvfw59._.js → [root-of-the-server]__00-s7h8._.js} +1 -1
  91. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__013jr2b._.js +4 -0
  92. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__01wy8d-._.js +4 -0
  93. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__02npjtd._.js +4 -0
  94. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__12hbpha._.js → [root-of-the-server]__09flfsx._.js} +2 -2
  95. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0da85px._.js +4 -0
  96. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ftmoxc._.js +4 -0
  97. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0kokc8z._.js → [root-of-the-server]__0n_lxhg._.js} +1 -1
  98. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0oa1lav._.js +1 -1
  99. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0p-5p8u._.js +4 -0
  100. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0s740oi._.js +6 -0
  101. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0dxf928._.js → [root-of-the-server]__190won8._.js} +1 -1
  102. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0n2txhk._.js → [root-of-the-server]__1ctpynv._.js} +1 -1
  103. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1p2otjt._.js +4 -0
  104. package/.next/standalone/.next/server/chunks/ssr/_02yoeej._.js +3 -0
  105. package/.next/standalone/.next/server/chunks/ssr/{_0a0zlpr._.js → _04rbnaq._.js} +2 -2
  106. package/.next/standalone/.next/server/chunks/ssr/_08x1r5t._.js +1 -1
  107. package/.next/standalone/.next/server/chunks/ssr/{_0s-77v5._.js → _0h_douw._.js} +1 -1
  108. package/.next/standalone/.next/server/chunks/ssr/_1_ozgif._.js +1 -1
  109. package/.next/standalone/.next/server/chunks/ssr/_1ddpc5g._.js +1 -1
  110. package/.next/standalone/.next/server/chunks/ssr/_1es2j7i._.js +14 -51
  111. package/.next/standalone/.next/server/chunks/ssr/{_07t3jol._.js → _1u8-lu2._.js} +2 -2
  112. package/.next/standalone/.next/server/chunks/ssr/_1ylae7o._.js +3 -0
  113. package/.next/standalone/.next/server/chunks/ssr/_1zopuov._.js +3 -0
  114. package/.next/standalone/.next/server/chunks/ssr/_next-internal_server_app_policies_page_actions_1sp2-yo.js +2 -2
  115. package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +69 -1
  116. package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
  117. package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +1 -1
  118. package/.next/standalone/.next/server/chunks/ssr/app_settings_settings-client_tsx_20lq-mq._.js +1 -1
  119. package/.next/standalone/.next/server/chunks/ssr/node_modules_13n822a._.js +1 -1
  120. package/.next/standalone/.next/server/chunks/ssr/node_modules_html-to-image_es_index_1ao30b1.js +3 -0
  121. package/.next/standalone/.next/server/chunks/ssr/src_hooks_builtin-policies_ts_09j2ndl._.js +1 -1
  122. package/.next/standalone/.next/server/chunks/ssr/src_hooks_fp-config_ts_04t589g._.js +1 -1
  123. package/.next/standalone/.next/server/chunks/ssr/src_hooks_fp-home_ts_0je3xkv._.js +1 -1
  124. package/.next/standalone/.next/server/middleware-build-manifest.js +5 -5
  125. package/.next/standalone/.next/server/pages/404.html +1 -1
  126. package/.next/standalone/.next/server/pages/500.html +1 -1
  127. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  128. package/.next/standalone/.next/server/server-reference-manifest.json +21 -65
  129. package/.next/standalone/.next/static/chunks/{0f1pznnc7zlub.js → 0-tyrpwuc3lla.js} +1 -1
  130. package/.next/standalone/.next/static/chunks/0ca7octhod0g2.js +69 -0
  131. package/.next/standalone/.next/static/chunks/0u64yey446k4f.css +1 -0
  132. package/.next/standalone/.next/static/chunks/{1csubx9gwhsf6.js → 1j6o9min_6qa9.js} +1 -1
  133. package/.next/standalone/.next/static/chunks/27cl8h-c2w7cd.js +1 -0
  134. package/.next/standalone/.next/static/chunks/{0jpd8dv2vk930.css → 29-iqnp9v_axt.css} +1 -1
  135. package/.next/standalone/.next/static/chunks/{3uyhmm01g64k4.css → 2k9f4tyv04809.css} +0 -1
  136. package/.next/standalone/.next/static/chunks/{0t6ea7d3bkmdv.js → 2lwipmv5etc8m.js} +1 -1
  137. package/.next/standalone/.next/static/chunks/2pd16tn5qmx13.js +1 -0
  138. package/.next/standalone/.next/static/chunks/{0ntdfr2552x-h.js → 2u8vh73tpw28_.js} +1 -1
  139. package/.next/standalone/.next/static/chunks/{15uon66hpwbgg.js → 31u94yukw9fz-.js} +1 -1
  140. package/.next/standalone/.next/static/chunks/{2pwfrn6_mw-1u.js → 3p9_8x5ezce-9.js} +1 -1
  141. package/.next/standalone/.next/static/chunks/3qfoeqhy5l10x.js +1 -0
  142. package/.next/standalone/.next/static/chunks/{083fk73jtv9a0.js → 3tjji451hrgc0.js} +1 -1
  143. package/.next/standalone/.next/static/chunks/3zkg2s2vzxc3d.js +1 -0
  144. package/.next/standalone/.next/static/chunks/{turbopack-3s3c-u_u_l0u9.js → turbopack-3p73obe0xmrxm.js} +1 -1
  145. package/.next/standalone/.opencode/plugins/failproofai.mjs +27 -51
  146. package/.next/standalone/app/actions/get-scheduled-audit.ts +0 -5
  147. package/.next/standalone/app/actions/update-scheduled-audit.ts +57 -18
  148. package/.next/standalone/app/api/auth/status/route.ts +2 -3
  149. package/.next/standalone/app/audit/_components/audit-dashboard.tsx +34 -140
  150. package/.next/standalone/app/audit/_components/audit-poster.tsx +10 -29
  151. package/.next/standalone/app/audit/_components/come-back-better-section.tsx +1 -6
  152. package/.next/standalone/app/audit/_components/empty-state.tsx +1 -4
  153. package/.next/standalone/app/audit/_components/how-to-improve-section.tsx +5 -19
  154. package/.next/standalone/app/audit/_components/share-templates.ts +44 -110
  155. package/.next/standalone/app/audit/audit-styles.css +1 -132
  156. package/.next/standalone/app/settings/page.tsx +1 -1
  157. package/.next/standalone/app/settings/settings-client.tsx +45 -50
  158. package/.next/standalone/lib/auth/api-server-client.ts +5 -33
  159. package/.next/standalone/lib/claude-sessions.ts +27 -101
  160. package/.next/standalone/lib/codex-sessions.ts +4 -20
  161. package/.next/standalone/lib/copilot-sessions.ts +1 -32
  162. package/.next/standalone/lib/cursor-sessions.ts +5 -62
  163. package/.next/standalone/lib/sqlite-reader.ts +1 -78
  164. package/.next/standalone/package.json +9 -9
  165. package/.next/standalone/server.js +1 -1
  166. package/bin/failproofai.mjs +1 -1
  167. package/dist/cli.mjs +500 -1762
  168. package/dist/worker.mjs +16 -138
  169. package/lib/auth/api-server-client.ts +5 -33
  170. package/lib/claude-sessions.ts +27 -101
  171. package/lib/codex-sessions.ts +4 -20
  172. package/lib/copilot-sessions.ts +1 -32
  173. package/lib/cursor-sessions.ts +5 -62
  174. package/lib/sqlite-reader.ts +1 -78
  175. package/package.json +9 -9
  176. package/pi-extension/index.ts +5 -50
  177. package/src/audit/cache.ts +0 -6
  178. package/src/audit/cli-adapters/claude.ts +0 -13
  179. package/src/audit/cli-login.ts +1 -4
  180. package/src/audit/cli.ts +7 -157
  181. package/src/audit/harm-report.ts +4 -111
  182. package/src/audit/index.ts +15 -286
  183. package/src/audit/machine-store.ts +9 -8
  184. package/src/audit/redact-example.ts +15 -324
  185. package/src/audit/report-harm.ts +37 -33
  186. package/src/audit/report.ts +3 -6
  187. package/src/audit/schedule-cli.ts +33 -54
  188. package/src/audit/scoring.ts +0 -49
  189. package/src/audit/types.ts +0 -52
  190. package/src/hooks/builtin-policies.ts +2 -67
  191. package/src/hooks/configure-wizard.ts +0 -55
  192. package/src/hooks/fp-config.ts +48 -83
  193. package/src/hooks/fp-home.ts +0 -27
  194. package/src/hooks/integrations.ts +14 -51
  195. package/src/hooks/uninstall-cli.ts +2 -17
  196. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0-4ja6q._.js +0 -4
  197. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__00cr3xu._.js +0 -4
  198. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__04px77e._.js +0 -4
  199. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0egr5s1._.js +0 -6
  200. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0i0l1di._.js +0 -4
  201. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0r3c1_0._.js +0 -4
  202. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__17xnxlx._.js +0 -4
  203. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1ckpmkk._.js +0 -4
  204. package/.next/standalone/.next/server/chunks/ssr/_04ng_6x._.js +0 -3
  205. package/.next/standalone/.next/server/chunks/ssr/_0l2hi_d._.js +0 -3
  206. package/.next/standalone/.next/server/chunks/ssr/app_audit__components_rerun-button_tsx_0blihgw._.js +0 -3
  207. package/.next/standalone/.next/static/chunks/0divvxng208xo.js +0 -1
  208. package/.next/standalone/.next/static/chunks/27du9n7ssja7l.js +0 -1
  209. package/.next/standalone/.next/static/chunks/2h_pcb1y8_jde.js +0 -1
  210. package/.next/standalone/app/actions/get-leaks.ts +0 -104
  211. package/.next/standalone/app/audit/_components/leak-section.tsx +0 -192
  212. package/src/audit/desktop-notify.ts +0 -420
  213. package/src/audit/leak-fingerprint.ts +0 -198
  214. package/src/audit/leak-record.ts +0 -248
  215. package/src/audit/leak-scan.ts +0 -268
  216. package/src/audit/leak-store.ts +0 -220
  217. package/src/audit/macos-notifier.ts +0 -298
  218. package/src/hooks/notice.ts +0 -24
  219. /package/.next/standalone/.next/static/{YiPsVpjrc-pEQoN7XvhZ0 → dg8VQ7Ejlo0Qsh_x92oIt}/_buildManifest.js +0 -0
  220. /package/.next/standalone/.next/static/{YiPsVpjrc-pEQoN7XvhZ0 → dg8VQ7Ejlo0Qsh_x92oIt}/_clientMiddlewareManifest.js +0 -0
  221. /package/.next/standalone/.next/static/{YiPsVpjrc-pEQoN7XvhZ0 → dg8VQ7Ejlo0Qsh_x92oIt}/_ssgManifest.js +0 -0
package/dist/cli.mjs CHANGED
@@ -29,7 +29,7 @@ var __esm = (fn, res, err) => () => {
29
29
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
30
30
 
31
31
  // package.json
32
- var version2 = "1.0.4-beta.7", package_default;
32
+ var version2 = "1.0.4", package_default;
33
33
  var init_package = __esm(() => {
34
34
  package_default = {
35
35
  name: "failproofai",
@@ -154,16 +154,16 @@ var init_package = __esm(() => {
154
154
  browserslist: "4.28.8"
155
155
  },
156
156
  optionalDependencies: {
157
- "@failproofai/failproofaid-linux-x64": "1.0.4-beta.7",
158
- "@failproofai/failproofaid-linux-arm64": "1.0.4-beta.7",
159
- "@failproofai/failproofaid-darwin-x64": "1.0.4-beta.7",
160
- "@failproofai/failproofaid-darwin-arm64": "1.0.4-beta.7"
157
+ "@failproofai/failproofaid-linux-x64": "1.0.4",
158
+ "@failproofai/failproofaid-linux-arm64": "1.0.4",
159
+ "@failproofai/failproofaid-darwin-x64": "1.0.4",
160
+ "@failproofai/failproofaid-darwin-arm64": "1.0.4"
161
161
  },
162
162
  failproofaidBinaries: {
163
- "linux-x64": "e59735a8f94cd8ac697b2bd67aafdd8d76a8394d53db229876980cc13a18f07e",
164
- "linux-arm64": "b9ce50dd2f79b55f4f7112add265a776a4a6d002c2a56f971e666fbb796f3906",
165
- "darwin-x64": "b46efc8ec33945a5cc26b7bb288fb87cea65b5983bd83094b5e607d53b8eda4c",
166
- "darwin-arm64": "a8cc6112cee5ca8a7d517900e9ce32118855135980f22979fa0ff7aa6f68d954"
163
+ "linux-x64": "cca1d41ff951784ba084bf2d72cfad0fe8d988f8226e0e7a4538b1fb8d76a5bd",
164
+ "linux-arm64": "55e9c1e2864cbf6057fd0c27e4bc573ca8fba2cd35d480a3db3a55d398e7bec0",
165
+ "darwin-x64": "2a46ec77d2cac14a036f35e832f92f16895239814a5f10f02121f3c313e70574",
166
+ "darwin-arm64": "a0e7ccc6fe24e1017592637192ba8a26c9d05ca839c98bc72a983094c863b39b"
167
167
  }
168
168
  };
169
169
  });
@@ -206,7 +206,7 @@ function retiredLayoutPaths() {
206
206
  legacy.localPoliciesDir()
207
207
  ];
208
208
  }
209
- var LAYOUT_VERSION = 4, at = (...parts) => resolve(failproofaiHome(), ...parts), atHome = (home, ...parts) => home ? resolve(failproofaiHome(home), ...parts) : at(...parts), versionFile = (home) => atHome(home, "VERSION"), configFile = (home) => atHome(home, "config.json"), credentialsFile = (home) => atHome(home, "credentials.json"), binDir = (home) => atHome(home, "bin"), policiesDir = (home) => atHome(home, "policies"), customPoliciesDir, globalPolicyConfigFile = (home) => atHome(home, "policies-config.json"), cloudPoliciesDir = (home) => resolve(policiesDir(home), "cloud-policies"), packsDir = (home) => resolve(policiesDir(home), "packs"), packsInstalledFile = (home) => resolve(packsDir(home), "installed.json"), cursorsDir = (source, home) => source ? resolve(atHome(home, "cursors"), source) : atHome(home, "cursors"), customAgentsDir = (home) => atHome(home, "custom-agents"), auditDir = (home) => atHome(home, "audit"), auditDashboardFile = (home) => resolve(auditDir(home), "dashboard.json"), auditCacheDir = (home) => resolve(auditDir(home), "cache"), auditSessionFile = (home) => resolve(auditDir(home), "session.json"), auditMachineFile = (home) => resolve(auditDir(home), "machine.json"), auditLeaksFile = (home) => resolve(auditDir(home), "leaks.json"), auditLeakIdentityFile = (home) => resolve(auditDir(home), "leak-identity.json"), fpcliDir = (home) => atHome(home, "fpcli"), fpcliAuthFile = (home) => resolve(fpcliDir(home), "cli-auth.json"), hookActivityDir = (home) => atHome(home, "hook-activity"), runDir = (home) => atHome(home, "run"), daemonSocket = () => process.env.FAILPROOFAI_DAEMON_SOCKET || resolve(runDir(), "failproofaid.sock"), auditLockFile = (home) => resolve(runDir(home), "audit.lock"), stateDir = (home) => atHome(home, "state"), shimsDir = (home) => resolve(stateDir(home), "shims"), spoolDir = (home) => resolve(stateDir(home), "spool"), failedDir = (home) => resolve(stateDir(home), "failed"), collectorHealthFile = (home) => resolve(stateDir(home), "collector-health.json"), sessionPauseDir = () => resolve(stateDir(), "sessions"), auditScheduleFile = (home) => resolve(auditDir(home), "schedule.json"), telemetryIdFile = (home) => resolve(stateDir(home), "telemetry-id"), launcherMarker = (home) => resolve(stateDir(home), "launcher-configured"), onboardingAttemptFile = (home) => resolve(stateDir(home), "onboarding-attempt.json"), lastVersionFile = (home) => resolve(stateDir(home), "last-version"), onboardingLockFile = (home) => resolve(stateDir(home), "onboarding.lock"), codexSessionPathsFile = (home) => resolve(stateDir(home), "codex-session-paths.json"), logsDir = (home) => atHome(home, "logs"), migrationsDir = (home) => atHome(home, "migrations"), migrationLedgerFile = (home) => resolve(migrationsDir(home), "applied.json"), migrationBackupDir = (layout, home) => resolve(migrationsDir(home), `backup-layout${layout}`), HOME_CLASSES, legacy;
209
+ var LAYOUT_VERSION = 4, at = (...parts) => resolve(failproofaiHome(), ...parts), atHome = (home, ...parts) => home ? resolve(failproofaiHome(home), ...parts) : at(...parts), versionFile = (home) => atHome(home, "VERSION"), configFile = (home) => atHome(home, "config.json"), credentialsFile = (home) => atHome(home, "credentials.json"), binDir = (home) => atHome(home, "bin"), policiesDir = (home) => atHome(home, "policies"), customPoliciesDir, globalPolicyConfigFile = (home) => atHome(home, "policies-config.json"), cloudPoliciesDir = (home) => resolve(policiesDir(home), "cloud-policies"), packsDir = (home) => resolve(policiesDir(home), "packs"), packsInstalledFile = (home) => resolve(packsDir(home), "installed.json"), cursorsDir = (source, home) => source ? resolve(atHome(home, "cursors"), source) : atHome(home, "cursors"), customAgentsDir = (home) => atHome(home, "custom-agents"), auditDir = (home) => atHome(home, "audit"), auditDashboardFile = (home) => resolve(auditDir(home), "dashboard.json"), auditCacheDir = (home) => resolve(auditDir(home), "cache"), auditSessionFile = (home) => resolve(auditDir(home), "session.json"), auditMachineFile = (home) => resolve(auditDir(home), "machine.json"), fpcliDir = (home) => atHome(home, "fpcli"), fpcliAuthFile = (home) => resolve(fpcliDir(home), "cli-auth.json"), hookActivityDir = (home) => atHome(home, "hook-activity"), runDir = (home) => atHome(home, "run"), daemonSocket = () => process.env.FAILPROOFAI_DAEMON_SOCKET || resolve(runDir(), "failproofaid.sock"), auditLockFile = (home) => resolve(runDir(home), "audit.lock"), stateDir = (home) => atHome(home, "state"), shimsDir = (home) => resolve(stateDir(home), "shims"), spoolDir = (home) => resolve(stateDir(home), "spool"), failedDir = (home) => resolve(stateDir(home), "failed"), collectorHealthFile = (home) => resolve(stateDir(home), "collector-health.json"), sessionPauseDir = () => resolve(stateDir(), "sessions"), auditScheduleFile = (home) => resolve(auditDir(home), "schedule.json"), telemetryIdFile = (home) => resolve(stateDir(home), "telemetry-id"), launcherMarker = (home) => resolve(stateDir(home), "launcher-configured"), onboardingAttemptFile = (home) => resolve(stateDir(home), "onboarding-attempt.json"), lastVersionFile = (home) => resolve(stateDir(home), "last-version"), onboardingLockFile = (home) => resolve(stateDir(home), "onboarding.lock"), codexSessionPathsFile = (home) => resolve(stateDir(home), "codex-session-paths.json"), logsDir = (home) => atHome(home, "logs"), migrationsDir = (home) => atHome(home, "migrations"), migrationLedgerFile = (home) => resolve(migrationsDir(home), "applied.json"), migrationBackupDir = (layout, home) => resolve(migrationsDir(home), `backup-layout${layout}`), HOME_CLASSES, legacy;
210
210
  var init_fp_home = __esm(() => {
211
211
  customPoliciesDir = policiesDir;
212
212
  HOME_CLASSES = [
@@ -228,10 +228,8 @@ var init_fp_home = __esm(() => {
228
228
  { path: versionFile, class: "identity" },
229
229
  { path: migrationsDir, class: "identity" },
230
230
  { path: auditMachineFile, class: "identity" },
231
- { path: auditLeakIdentityFile, class: "identity" },
232
231
  { path: auditDashboardFile, class: "derived" },
233
232
  { path: auditCacheDir, class: "derived" },
234
- { path: auditLeaksFile, class: "derived" },
235
233
  { path: auditScheduleFile, class: "derived" },
236
234
  { path: collectorHealthFile, class: "derived" },
237
235
  { path: codexSessionPathsFile, class: "derived" },
@@ -396,8 +394,7 @@ function projectConfig(parsed) {
396
394
  const daemon = parsed.daemon ?? {};
397
395
  const collector = parsed.collector ?? {};
398
396
  const telemetry = parsed.telemetry ?? {};
399
- const auditPresent = !!parsed.audit && typeof parsed.audit === "object" && !Array.isArray(parsed.audit);
400
- const audit = auditPresent ? parsed.audit : {};
397
+ const audit = parsed.audit ?? {};
401
398
  return {
402
399
  mode: mode === "cloud" ? "cloud" : "oss",
403
400
  daemon: { configured: daemon.configured === true },
@@ -412,8 +409,7 @@ function projectConfig(parsed) {
412
409
  },
413
410
  telemetry: { enabled: telemetry.enabled !== false },
414
411
  audit: {
415
- auto: auditPresent && audit.auto !== false,
416
- notify: audit.notify !== false,
412
+ auto: audit.auto === true,
417
413
  intervalDays: readIntervalDays(audit.interval_days),
418
414
  reportsConsentedAt: typeof audit.reports_consented_at === "number" && Number.isFinite(audit.reports_consented_at) ? audit.reports_consented_at : undefined
419
415
  }
@@ -467,7 +463,6 @@ function writeConfig(config, raw) {
467
463
  ...config.telemetry.enabled ? {} : { telemetry: { enabled: false } },
468
464
  audit: {
469
465
  auto: config.audit.auto,
470
- notify: config.audit.notify,
471
466
  interval_days: config.audit.intervalDays,
472
467
  ...config.audit.reportsConsentedAt === undefined ? {} : { reports_consented_at: config.audit.reportsConsentedAt }
473
468
  }
@@ -602,7 +597,7 @@ var init_fp_config = __esm(() => {
602
597
  environment: "local"
603
598
  },
604
599
  telemetry: { enabled: true },
605
- audit: { auto: false, notify: true, intervalDays: DEFAULT_AUDIT_INTERVAL_DAYS }
600
+ audit: { auto: false, intervalDays: DEFAULT_AUDIT_INTERVAL_DAYS }
606
601
  };
607
602
  OWNED_CONFIG_KEYS = [
608
603
  ["mode", "kind"],
@@ -616,7 +611,6 @@ var init_fp_config = __esm(() => {
616
611
  ["collector", "sources", "*", "extra_paths"],
617
612
  ["telemetry", "enabled"],
618
613
  ["audit", "auto"],
619
- ["audit", "notify"],
620
614
  ["audit", "interval_days"],
621
615
  ["audit", "reports_consented_at"]
622
616
  ];
@@ -3870,39 +3864,15 @@ var init_builtin_policies = __esm(() => {
3870
3864
  SHELL_METACHAR_RE = /[;&<>`$()\\]/;
3871
3865
  JWT_RE = /eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}/;
3872
3866
  API_KEY_PATTERNS = [
3873
- [/sk-ant-api03-[A-Za-z0-9\-_]{20,}/, "Anthropic API key"],
3874
- [/sk-ant-oat01-[A-Za-z0-9\-_]{20,}/, "Anthropic OAuth token"],
3875
3867
  [/sk-ant-[A-Za-z0-9\-_]{20,}/, "Anthropic API key"],
3876
3868
  [/sk-proj-[A-Za-z0-9\-_]{20,}/, "OpenAI project API key"],
3877
- [/(?<!\w)sk-svcacct-[A-Za-z0-9\-_]{20,}/, "OpenAI service-account key"],
3878
- [/(?<!\w)sk-admin-[A-Za-z0-9\-_]{20,}/, "OpenAI admin key"],
3879
- [/sk-or-v1-[A-Za-z0-9\-_]{20,}/, "OpenRouter API key"],
3880
- [/sk-[A-Za-z0-9]{20,}/, "OpenAI-compatible key (issuer unknown)"],
3881
- [/github_pat_[A-Za-z0-9_]{82}/, "GitHub fine-grained token"],
3869
+ [/sk-[A-Za-z0-9]{20,}/, "OpenAI API key"],
3882
3870
  [/ghp_[A-Za-z0-9]{36}/, "GitHub personal access token"],
3883
- [/gho_[A-Za-z0-9]{36}/, "GitHub OAuth token"],
3884
- [/ghu_[A-Za-z0-9]{36}/, "GitHub user-to-server token"],
3885
- [/ghs_[A-Za-z0-9]{36}/, "GitHub server-to-server token"],
3886
- [/ghr_[A-Za-z0-9]{36}/, "GitHub refresh token"],
3887
- [/glpat-[A-Za-z0-9\-_]{20,}/, "GitLab personal access token"],
3871
+ [/github_pat_[A-Za-z0-9_]{82}/, "GitHub fine-grained token"],
3888
3872
  [/AKIA[A-Z0-9]{16}/, "AWS access key ID"],
3889
- [/ASIA[A-Z0-9]{16}/, "AWS temporary access key ID"],
3890
3873
  [/sk_live_[A-Za-z0-9]{24,}/, "Stripe live secret key"],
3891
3874
  [/sk_test_[A-Za-z0-9]{24,}/, "Stripe test secret key"],
3892
- [/rk_live_[A-Za-z0-9]{24,}/, "Stripe restricted key"],
3893
- [/AIza[0-9A-Za-z\-_]{35}/, "Google API key"],
3894
- [/\d{8,10}:[A-Za-z0-9_-]{35}/, "Telegram bot token"],
3895
- [/xox[baprs]-[A-Za-z0-9-]{10,}/, "Slack token"],
3896
- [/xapp-[0-9]-[A-Za-z0-9-]{10,}/, "Slack app-level token"],
3897
- [/hf_[A-Za-z0-9]{30,}/, "Hugging Face token"],
3898
- [/gsk_[A-Za-z0-9]{40,}/, "Groq API key"],
3899
- [/r8_[A-Za-z0-9]{30,}/, "Replicate token"],
3900
- [/xai-[A-Za-z0-9]{40,}/, "xAI API key"],
3901
- [/npm_[A-Za-z0-9]{36}/, "npm access token"],
3902
- [/dop_v1_[a-f0-9]{64}/, "DigitalOcean token"],
3903
- [/shpat_[a-fA-F0-9]{32}/, "Shopify access token"],
3904
- [/sb_secret_[A-Za-z0-9\-_]{20,}/, "Supabase secret key"],
3905
- [/sbp_[a-f0-9]{40}/, "Supabase personal token"]
3875
+ [/AIza[0-9A-Za-z\-_]{35}/, "Google API key"]
3906
3876
  ];
3907
3877
  CONNECTION_STRING_RE = /(?:postgresql|postgres|mysql|mongodb(?:\+srv)?|redis|amqps?|smtps?):\/\/[^@\s]+@/;
3908
3878
  PRIVATE_KEY_RE = /-----BEGIN (?:[A-Z]+ )?PRIVATE KEY-----/;
@@ -11682,7 +11652,7 @@ function buildOpenCodePluginShim(binaryPath, scope) {
11682
11652
  // Re-generate via: failproofai policies --install --cli opencode
11683
11653
  // Plugin shim that bridges OpenCode's plugin API to the failproofai binary.
11684
11654
  // See: https://opencode.ai/docs/plugins/
11685
- import { spawn } from "node:child_process";
11655
+ import { spawnSync } from "node:child_process";
11686
11656
 
11687
11657
  // Map opencode bus-event types → canonical failproofai event names.
11688
11658
  // (The binary sees PascalCase — the binary's --cli=opencode flag is for
@@ -11745,52 +11715,18 @@ function canonicalizeToolInput(canonicalToolName, args) {
11745
11715
  const FAILPROOFAI_BIN = ${escapedBin};
11746
11716
  const USE_NPX = ${useNpx};
11747
11717
 
11748
- /**
11749
- * Run failproofai for one event WITHOUT blocking opencode's event loop.
11750
- *
11751
- * This was spawnSync, and opencode loads the plugin in-process in the TUI —
11752
- * so every hook froze rendering and input for the subprocess's full duration,
11753
- * with a 60s ceiling. The verdicts are unchanged: every caller already awaits
11754
- * applyDecision, so the deny still lands before the tool runs. What changes
11755
- * is that the wait is now a promise rather than a blocked thread, and the TUI
11756
- * keeps painting while it happens.
11757
- *
11758
- * Fail-open on spawn error, and on the timeout — a policy that never ran must
11759
- * not read as a deny.
11760
- */
11761
- async function runFailproofai(eventName, payload, directory) {
11718
+ function runFailproofai(eventName, payload, directory) {
11762
11719
  const cmd = USE_NPX ? "npx" : FAILPROOFAI_BIN;
11763
11720
  const args = USE_NPX
11764
11721
  ? ["-y", "failproofai", "--hook", eventName, "--cli", "opencode"]
11765
11722
  : ["--hook", eventName, "--cli", "opencode"];
11766
- return await new Promise((resolveRun) => {
11767
- let child;
11768
- try {
11769
- child = spawn(cmd, args, { cwd: directory });
11770
- } catch {
11771
- resolveRun({ exitCode: 0, stdout: "", stderr: "" });
11772
- return;
11773
- }
11774
- let stdout = "";
11775
- let stderr = "";
11776
- let settled = false;
11777
- const finish = (exitCode) => {
11778
- if (settled) return;
11779
- settled = true;
11780
- clearTimeout(timer);
11781
- resolveRun({ exitCode, stdout, stderr });
11782
- };
11783
- const timer = setTimeout(() => {
11784
- try { child.kill("SIGKILL"); } catch { /* already gone */ }
11785
- finish(0);
11786
- }, 60_000);
11787
- child.stdout.on("data", (d) => { stdout += d; });
11788
- child.stderr.on("data", (d) => { stderr += d; });
11789
- child.on("error", () => finish(0));
11790
- child.on("close", (code) => finish(code ?? 0));
11791
- child.stdin.on("error", () => {});
11792
- child.stdin.end(JSON.stringify(payload));
11723
+ const r = spawnSync(cmd, args, {
11724
+ input: JSON.stringify(payload),
11725
+ encoding: "utf8",
11726
+ timeout: 60_000,
11727
+ cwd: directory,
11793
11728
  });
11729
+ return { exitCode: r.status ?? 0, stdout: r.stdout ?? "", stderr: r.stderr ?? "" };
11794
11730
  }
11795
11731
 
11796
11732
  async function applyDecision(result, ctx, eventName) {
@@ -11855,7 +11791,7 @@ export default async function failproofaiPlugin({ client, directory }) {
11855
11791
  }
11856
11792
  }
11857
11793
  if (!prompt) prompt = (info.text || info.content || props.text || "").toString();
11858
- const r = await runFailproofai("UserPromptSubmit", {
11794
+ const r = runFailproofai("UserPromptSubmit", {
11859
11795
  session_id: sessionID, cwd: directory, hook_event_name: "UserPromptSubmit", prompt,
11860
11796
  }, directory);
11861
11797
  await applyDecision(r, { client, sessionID }, "UserPromptSubmit");
@@ -11865,11 +11801,8 @@ export default async function failproofaiPlugin({ client, directory }) {
11865
11801
  const claudeEvent = BUS_EVENT_MAP[event.type];
11866
11802
  if (!claudeEvent) return;
11867
11803
  const props = event.properties || {};
11868
- const info = props.info || props.session || {};
11869
-
11870
- const sessionID = info.id || info.sessionID || info.sessionId || info.session_id ||
11871
- props.sessionID || props.sessionId || props.session_id || props.id;
11872
- const r = await runFailproofai(claudeEvent, {
11804
+ const sessionID = props.sessionID || (props.session && props.session.id) || props.id;
11805
+ const r = runFailproofai(claudeEvent, {
11873
11806
  session_id: sessionID, cwd: directory, hook_event_name: claudeEvent,
11874
11807
  }, directory);
11875
11808
  await applyDecision(r, { client, sessionID }, claudeEvent);
@@ -11878,7 +11811,7 @@ export default async function failproofaiPlugin({ client, directory }) {
11878
11811
  // First-class PreToolUse hook. Note: tool args live on output.args (mutable).
11879
11812
  "tool.execute.before": async (input, output) => {
11880
11813
  const canonicalTool = canonicalizeTool(input.tool);
11881
- const r = await runFailproofai("PreToolUse", {
11814
+ const r = runFailproofai("PreToolUse", {
11882
11815
  session_id: input.sessionID,
11883
11816
  cwd: directory,
11884
11817
  tool_name: canonicalTool,
@@ -11891,7 +11824,7 @@ export default async function failproofaiPlugin({ client, directory }) {
11891
11824
  // First-class PostToolUse hook. Note: tool args live on input.args here.
11892
11825
  "tool.execute.after": async (input, output) => {
11893
11826
  const canonicalTool = canonicalizeTool(input.tool);
11894
- const r = await runFailproofai("PostToolUse", {
11827
+ const r = runFailproofai("PostToolUse", {
11895
11828
  session_id: input.sessionID,
11896
11829
  cwd: directory,
11897
11830
  tool_name: canonicalTool,
@@ -11905,7 +11838,7 @@ export default async function failproofaiPlugin({ client, directory }) {
11905
11838
  // Cleaner deny UX for prompted tools — mutate output.status instead of throwing.
11906
11839
  "permission.ask": async (input, output) => {
11907
11840
  const canonicalTool = canonicalizeTool(input.tool);
11908
- const r = await runFailproofai("PermissionRequest", {
11841
+ const r = runFailproofai("PermissionRequest", {
11909
11842
  session_id: input.sessionID,
11910
11843
  cwd: directory,
11911
11844
  tool_name: canonicalTool || input.command || "permission",
@@ -17177,21 +17110,8 @@ var init_cursor_projects = __esm(() => {
17177
17110
  // lib/sqlite-reader.ts
17178
17111
  import { existsSync as existsSync11, readFileSync as readFileSync8 } from "node:fs";
17179
17112
  import initSqlJs from "sql.js/dist/sql-asm.js";
17180
- function silenceSqliteExperimentalWarning() {
17181
- if (warningPatched)
17182
- return;
17183
- warningPatched = true;
17184
- const original = process.emitWarning.bind(process);
17185
- process.emitWarning = (warning, ...rest) => {
17186
- const text = typeof warning === "string" ? warning : String(warning?.message ?? "");
17187
- if (text.includes("SQLite is an experimental feature"))
17188
- return;
17189
- return original(warning, ...rest);
17190
- };
17191
- }
17192
17113
  async function tryNodeSqlite(dbPath) {
17193
17114
  try {
17194
- silenceSqliteExperimentalWarning();
17195
17115
  const mod = await import("node:sqlite");
17196
17116
  const db = new mod.DatabaseSync(dbPath, { readOnly: true });
17197
17117
  return {
@@ -17212,21 +17132,10 @@ function loadSqlJs() {
17212
17132
  sqlPromise = initSqlJs();
17213
17133
  return sqlPromise;
17214
17134
  }
17215
- function clearWalFlag(bytes) {
17216
- if (bytes.length < 20)
17217
- return bytes;
17218
- if (bytes.toString("latin1", 0, 16) !== SQLITE_MAGIC)
17219
- return bytes;
17220
- if (bytes[18] === 1 && bytes[19] === 1)
17221
- return bytes;
17222
- bytes[18] = 1;
17223
- bytes[19] = 1;
17224
- return bytes;
17225
- }
17226
17135
  async function trySqlJs(dbPath) {
17227
17136
  try {
17228
17137
  const SQL = await loadSqlJs();
17229
- const db = new SQL.Database(clearWalFlag(readFileSync8(dbPath)));
17138
+ const db = new SQL.Database(readFileSync8(dbPath));
17230
17139
  return {
17231
17140
  query(sql, params) {
17232
17141
  const stmt = db.prepare(sql);
@@ -17254,7 +17163,7 @@ async function openSqliteReadonly(dbPath) {
17254
17163
  return null;
17255
17164
  return await tryNodeSqlite(dbPath) ?? await trySqlJs(dbPath);
17256
17165
  }
17257
- var warningPatched = false, sqlPromise = null, SQLITE_MAGIC = "SQLite format 3\x00";
17166
+ var sqlPromise = null;
17258
17167
  var init_sqlite_reader = () => {};
17259
17168
 
17260
17169
  // lib/opencode-db.ts
@@ -20005,15 +19914,6 @@ function joinTexts(blocks, wantedType) {
20005
19914
  return blocks.filter((b) => b?.type === wantedType && typeof b.text === "string").map((b) => b.text).join(`
20006
19915
  `);
20007
19916
  }
20008
- function toolOutputText(output) {
20009
- if (typeof output === "string")
20010
- return output;
20011
- if (Array.isArray(output)) {
20012
- return output.filter((block) => !!block && typeof block === "object").map((block) => typeof block.text === "string" ? block.text : "").filter(Boolean).join(`
20013
- `);
20014
- }
20015
- return output === undefined ? "" : JSON.stringify(output);
20016
- }
20017
19917
  async function parseCodexLog(fileContent, source = "session") {
20018
19918
  const lines = fileContent.split(`
20019
19919
  `).filter((line) => line.trim() !== "");
@@ -20090,11 +19990,10 @@ async function parseCodexLog(fileContent, source = "session") {
20090
19990
  });
20091
19991
  continue;
20092
19992
  }
20093
- if (subType === "function_call" || subType === "custom_tool_call") {
19993
+ if (subType === "function_call") {
20094
19994
  const callId = payload.call_id;
20095
19995
  const name = payload.name ?? "function_call";
20096
- const encodedInput = payload.arguments ?? payload.input;
20097
- const input = safeJsonParse4(encodedInput);
19996
+ const input = safeJsonParse4(payload.arguments);
20098
19997
  const toolUse = {
20099
19998
  type: "tool_use",
20100
19999
  id: callId ?? `${timestamp}-${name}`,
@@ -20113,7 +20012,7 @@ async function parseCodexLog(fileContent, source = "session") {
20113
20012
  }
20114
20013
  continue;
20115
20014
  }
20116
- if (subType === "function_call_output" || subType === "custom_tool_call_output") {
20015
+ if (subType === "function_call_output") {
20117
20016
  const callId = payload.call_id;
20118
20017
  const block = callId ? toolUseById.get(callId) : undefined;
20119
20018
  if (block) {
@@ -20122,7 +20021,7 @@ async function parseCodexLog(fileContent, source = "session") {
20122
20021
  block.result = {
20123
20022
  timestamp,
20124
20023
  timestampFormatted: formatTimestamp(date),
20125
- content: toolOutputText(payload.output),
20024
+ content: typeof payload.output === "string" ? payload.output : JSON.stringify(payload.output),
20126
20025
  durationMs: duration,
20127
20026
  durationFormatted: formatDuration(duration)
20128
20027
  };
@@ -20317,8 +20216,6 @@ async function parseCopilotLog(fileContent, source = "session") {
20317
20216
  const rawLines = [];
20318
20217
  const toolUseById = new Map;
20319
20218
  const toolUseStartMs = new Map;
20320
- let mostRecentToolUse;
20321
- let mostRecentToolUseStartMs = 0;
20322
20219
  let cwd;
20323
20220
  let seenSessionStart = false;
20324
20221
  for (let i = 0;i < lines.length; i++) {
@@ -20414,24 +20311,8 @@ async function parseCopilotLog(fileContent, source = "session") {
20414
20311
  toolUseById.set(callId, toolUse);
20415
20312
  toolUseStartMs.set(callId, date.getTime());
20416
20313
  }
20417
- mostRecentToolUse = toolUse;
20418
- mostRecentToolUseStartMs = date.getTime();
20419
20314
  continue;
20420
20315
  }
20421
- if (recType === "hook.start" && data.hookType === "postToolUse" && mostRecentToolUse) {
20422
- const input = data.input ?? {};
20423
- const hookResult = input.toolResult ?? {};
20424
- const hookContent = hookResult.textResultForLlm ?? hookResult.sessionLog;
20425
- if (typeof hookContent === "string" && hookContent.length > 0) {
20426
- mostRecentToolUse.result = {
20427
- timestamp,
20428
- timestampFormatted: formatTimestamp(date),
20429
- content: hookContent,
20430
- durationMs: Math.max(0, date.getTime() - mostRecentToolUseStartMs),
20431
- durationFormatted: formatDuration(Math.max(0, date.getTime() - mostRecentToolUseStartMs))
20432
- };
20433
- }
20434
- }
20435
20316
  if (recType === "tool.execution_complete") {
20436
20317
  const callId = data.toolCallId;
20437
20318
  const block = callId ? toolUseById.get(callId) : undefined;
@@ -20441,8 +20322,7 @@ async function parseCopilotLog(fileContent, source = "session") {
20441
20322
  const telemetry = data.toolTelemetry ?? {};
20442
20323
  const reportedMs = telemetry.metrics?.commandTimeMs ?? telemetry.metrics?.durationMs ?? null;
20443
20324
  const durationMs = typeof reportedMs === "number" && reportedMs >= 0 ? reportedMs : Math.max(0, date.getTime() - startMs);
20444
- const completionContent = result.detailedContent ?? result.content ?? "";
20445
- const content = block.result?.content || completionContent;
20325
+ const content = result.detailedContent ?? result.content ?? "";
20446
20326
  block.result = {
20447
20327
  timestamp,
20448
20328
  timestampFormatted: formatTimestamp(date),
@@ -20566,27 +20446,8 @@ async function parseCursorLog(fileContent, source = "session") {
20566
20446
  if (!raw.type && raw.role && raw.message?.content) {
20567
20447
  const synthDate = new Date(SYNTH_T0 + i);
20568
20448
  const synthTs = synthDate.toISOString();
20569
- const messageContent = raw.message.content;
20570
- const textParts = messageContent.filter((c) => c?.type === "text" && typeof c.text === "string").map((c) => c.text).join("");
20449
+ const textParts = raw.message.content.filter((c) => c?.type === "text" && typeof c.text === "string").map((c) => c.text).join("");
20571
20450
  if (raw.role === "user") {
20572
- let attachedResult = false;
20573
- for (const block of messageContent) {
20574
- if (block?.type !== "tool_result")
20575
- continue;
20576
- const callId = typeof block.tool_use_id === "string" ? block.tool_use_id : undefined;
20577
- const toolUse = callId ? toolUseById.get(callId) : undefined;
20578
- if (!toolUse)
20579
- continue;
20580
- const durationMs = Math.max(0, synthDate.getTime() - (toolUseStartMs.get(callId) ?? synthDate.getTime()));
20581
- toolUse.result = {
20582
- timestamp: synthTs,
20583
- timestampFormatted: formatTimestamp(synthDate),
20584
- content: typeof block.content === "string" ? block.content : block.content == null ? "" : JSON.stringify(block.content),
20585
- durationMs,
20586
- durationFormatted: formatDuration(durationMs)
20587
- };
20588
- attachedResult = true;
20589
- }
20590
20451
  const queryMatch = /<user_query>\s*([\s\S]*?)\s*<\/user_query>/.exec(textParts);
20591
20452
  const text = queryMatch ? queryMatch[1] : textParts;
20592
20453
  if (text) {
@@ -20595,35 +20456,11 @@ async function parseCursorLog(fileContent, source = "session") {
20595
20456
  ...baseEntry(rawCopy, synthTs, synthDate, source),
20596
20457
  message: { role: "user", content: text }
20597
20458
  });
20598
- } else if (!attachedResult) {
20599
- entries.push({
20600
- type: "system",
20601
- ...baseEntry(rawCopy, synthTs, synthDate, source),
20602
- raw: rawCopy
20603
- });
20604
20459
  }
20605
20460
  continue;
20606
20461
  }
20607
20462
  if (raw.role === "assistant") {
20608
- const blocks = [];
20609
- if (textParts)
20610
- blocks.push({ type: "text", text: textParts });
20611
- for (let j = 0;j < messageContent.length; j++) {
20612
- const contentBlock = messageContent[j];
20613
- if (contentBlock?.type !== "tool_use")
20614
- continue;
20615
- const name = typeof contentBlock.name === "string" ? contentBlock.name : "tool";
20616
- const id = typeof contentBlock.id === "string" && contentBlock.id ? contentBlock.id : `cursor-${i}-${name}-${j}`;
20617
- const toolUse = {
20618
- type: "tool_use",
20619
- id,
20620
- name,
20621
- input: contentBlock.input && typeof contentBlock.input === "object" ? contentBlock.input : {}
20622
- };
20623
- blocks.push(toolUse);
20624
- toolUseById.set(id, toolUse);
20625
- toolUseStartMs.set(id, synthDate.getTime());
20626
- }
20463
+ const blocks = textParts ? [{ type: "text", text: textParts }] : [];
20627
20464
  if (blocks.length === 0) {
20628
20465
  entries.push({
20629
20466
  type: "system",
@@ -25112,232 +24949,6 @@ var init_manager = __esm(() => {
25112
24949
  VALID_POLICY_NAMES = new Set(BUILTIN_POLICIES.map((p) => p.name));
25113
24950
  });
25114
24951
 
25115
- // src/audit/leak-fingerprint.ts
25116
- function matchPublicPrefix(value) {
25117
- for (const entry of PUBLIC_PREFIXES) {
25118
- if (value.startsWith(entry[0]))
25119
- return entry;
25120
- }
25121
- return null;
25122
- }
25123
- function fingerprintSecret(value, fallbackLabel = "secret") {
25124
- const length = value.length;
25125
- const matched = matchPublicPrefix(value);
25126
- if (!matched) {
25127
- return {
25128
- display: `[${length}-char ${fallbackLabel}]`,
25129
- label: fallbackLabel,
25130
- length,
25131
- attributed: false
25132
- };
25133
- }
25134
- const [prefix, label] = matched;
25135
- const bodyLength = length - prefix.length;
25136
- const run = MASK_CHAR.repeat(Math.max(1, Math.min(MAX_MASK_RUN, bodyLength)));
25137
- if (length >= MIN_LEN_FOR_TAIL && bodyLength > TAIL_CHARS * 2) {
25138
- return {
25139
- display: `${prefix}${run}${value.slice(-TAIL_CHARS)}`,
25140
- label,
25141
- length,
25142
- attributed: true
25143
- };
25144
- }
25145
- return { display: `${prefix}${run}`, label, length, attributed: true };
25146
- }
25147
- function isFindingId(id) {
25148
- return /^[0-9a-f]{16}$/.test(id);
25149
- }
25150
- function fingerprintId(value, machineSalt) {
25151
- const { createHmac } = __require("node:crypto");
25152
- return createHmac("sha256", machineSalt).update(value).digest("hex").slice(0, 16);
25153
- }
25154
- var MASK_CHAR = "•", MAX_MASK_RUN = 8, MIN_LEN_FOR_TAIL = 24, TAIL_CHARS = 4, PUBLIC_PREFIXES;
25155
- var init_leak_fingerprint = __esm(() => {
25156
- PUBLIC_PREFIXES = [
25157
- ["sk-ant-api03-", "Anthropic API key"],
25158
- ["sk-ant-oat01-", "Anthropic OAuth token"],
25159
- ["sk-ant-", "Anthropic key"],
25160
- ["sk-proj-", "OpenAI project key"],
25161
- ["sk-svcacct-", "OpenAI service-account key"],
25162
- ["sk-admin-", "OpenAI admin key"],
25163
- ["sk-or-v1-", "OpenRouter key"],
25164
- ["github_pat_", "GitHub fine-grained token"],
25165
- ["ghp_", "GitHub personal access token"],
25166
- ["gho_", "GitHub OAuth token"],
25167
- ["ghu_", "GitHub user-to-server token"],
25168
- ["ghs_", "GitHub server-to-server token"],
25169
- ["ghr_", "GitHub refresh token"],
25170
- ["glpat-", "GitLab personal access token"],
25171
- ["xoxb-", "Slack bot token"],
25172
- ["xoxp-", "Slack user token"],
25173
- ["xapp-", "Slack app-level token"],
25174
- ["sk_live_", "Stripe live secret key"],
25175
- ["sk_test_", "Stripe test secret key"],
25176
- ["rk_live_", "Stripe restricted key"],
25177
- ["AKIA", "AWS access key ID"],
25178
- ["ASIA", "AWS temporary access key ID"],
25179
- ["AIza", "Google API key"],
25180
- ["hf_", "Hugging Face token"],
25181
- ["gsk_", "Groq API key"],
25182
- ["r8_", "Replicate token"],
25183
- ["xai-", "xAI key"],
25184
- ["npm_", "npm access token"],
25185
- ["dop_v1_", "DigitalOcean token"],
25186
- ["shpat_", "Shopify access token"],
25187
- ["sbp_", "Supabase token"]
25188
- ];
25189
- });
25190
-
25191
- // src/audit/macos-notifier.ts
25192
- import { execFileSync as execFileSync3 } from "node:child_process";
25193
- import { chmodSync as chmodSync5, existsSync as existsSync26, mkdirSync as mkdirSync17, readdirSync as readdirSync16, renameSync as renameSync8, rmSync as rmSync9, writeFileSync as writeFileSync15 } from "node:fs";
25194
- import { homedir as homedir24 } from "node:os";
25195
- import { resolve as resolve22 } from "node:path";
25196
- function macNotifierAppPath(home) {
25197
- return resolve22(runDir(home), "..", "bin", "FailproofAI Notifier.app");
25198
- }
25199
- function macNotifierRunnerPath(home) {
25200
- return resolve22(runDir(home), "..", "bin", "failproofai-notifier.zsh");
25201
- }
25202
- function macNotifierPlistPath() {
25203
- return resolve22(homedir24(), "Library", "LaunchAgents", `${MAC_NOTIFIER_LABEL}.plist`);
25204
- }
25205
- function escapeXml2(s) {
25206
- return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
25207
- }
25208
- function notifierScript(home) {
25209
- const dir = macNotifyDir(home);
25210
- const quotedDir = `'${dir.replace(/'/g, `'\\''`)}'`;
25211
- return `#!/bin/zsh
25212
- set -u
25213
- setopt NULL_GLOB
25214
-
25215
- drop_dir=${quotedDir}
25216
-
25217
- for entry_path in "$drop_dir"/*; do
25218
- [ -f "$entry_path" ] || continue
25219
- note_title=$(/usr/bin/sed -n '1p' "$entry_path")
25220
- note_body=$(/usr/bin/sed -n '2,$p' "$entry_path" | /usr/bin/tr '\\n' ' ')
25221
- /bin/rm -f "$entry_path"
25222
- [ -n "$note_title" ] || continue
25223
- /usr/bin/osascript - "$note_title" "$note_body" <<'APPLESCRIPT'
25224
- on run argv
25225
- display notification (item 2 of argv) with title (item 1 of argv)
25226
- end run
25227
- APPLESCRIPT
25228
- done
25229
- `;
25230
- }
25231
- function notifierPlistContents(runnerPath, watchDir) {
25232
- return `<?xml version="1.0" encoding="UTF-8"?>
25233
- <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
25234
- <plist version="1.0">
25235
- <dict>
25236
- <key>Label</key>
25237
- <string>${escapeXml2(MAC_NOTIFIER_LABEL)}</string>
25238
- <key>ProgramArguments</key>
25239
- <array>
25240
- <string>${escapeXml2(runnerPath)}</string>
25241
- </array>
25242
- <!-- Started only when something is queued, and it exits when the queue is
25243
- empty. RunAtLoad would fire it once at login with nothing to say. -->
25244
- <key>WatchPaths</key>
25245
- <array>
25246
- <string>${escapeXml2(watchDir)}</string>
25247
- </array>
25248
- <key>RunAtLoad</key>
25249
- <false/>
25250
- <!-- Not a service: it does one pass and exits, and launchd must not treat
25251
- that as a crash to restart. -->
25252
- <key>KeepAlive</key>
25253
- <false/>
25254
- <key>ProcessType</key>
25255
- <string>Interactive</string>
25256
- </dict>
25257
- </plist>
25258
- `;
25259
- }
25260
- function run(cmd, args) {
25261
- execFileSync3(cmd, args, { stdio: "ignore", timeout: 20000 });
25262
- }
25263
- function installMacNotifier(home) {
25264
- if (process.platform !== "darwin")
25265
- return { installed: false, reason: "not macOS" };
25266
- try {
25267
- const runner = macNotifierRunnerPath(home);
25268
- const watch = macNotifyDir(home);
25269
- mkdirSync17(watch, { recursive: true, mode: 448 });
25270
- mkdirSync17(resolve22(runner, ".."), { recursive: true });
25271
- writeFileSync15(runner, notifierScript(home), { mode: 448 });
25272
- chmodSync5(runner, 448);
25273
- rmSync9(macNotifierAppPath(home), { recursive: true, force: true });
25274
- mkdirSync17(resolve22(macNotifierPlistPath(), ".."), { recursive: true });
25275
- writeFileSync15(macNotifierPlistPath(), notifierPlistContents(runner, watch), { mode: 420 });
25276
- const target = `gui/${process.getuid?.() ?? 0}`;
25277
- try {
25278
- run("launchctl", ["bootout", `${target}/${MAC_NOTIFIER_LABEL}`]);
25279
- } catch {}
25280
- run("launchctl", ["bootstrap", target, macNotifierPlistPath()]);
25281
- return { installed: true };
25282
- } catch (err) {
25283
- return { installed: false, reason: err instanceof Error ? err.message : String(err) };
25284
- }
25285
- }
25286
- function uninstallMacNotifier(home) {
25287
- if (process.platform !== "darwin")
25288
- return;
25289
- try {
25290
- run("launchctl", ["bootout", `gui/${process.getuid?.() ?? 0}/${MAC_NOTIFIER_LABEL}`]);
25291
- } catch {}
25292
- rmSync9(macNotifierPlistPath(), { force: true });
25293
- rmSync9(macNotifierAppPath(home), { recursive: true, force: true });
25294
- rmSync9(macNotifierRunnerPath(home), { force: true });
25295
- rmSync9(macNotifyDir(home), { recursive: true, force: true });
25296
- }
25297
- function queueMacNotification(id, title, body, home) {
25298
- if (!isFindingId(id))
25299
- return false;
25300
- const dir = macNotifyDir(home);
25301
- const tmp = resolve22(dir, "..", `notify-${id}.tmp`);
25302
- try {
25303
- mkdirSync17(dir, { recursive: true, mode: 448 });
25304
- const payload = `${title.replace(/\s+/g, " ")}
25305
- ${body.replace(/\s+/g, " ")}
25306
- `;
25307
- writeFileSync15(tmp, payload, { mode: 384 });
25308
- renameSync8(tmp, resolve22(dir, id));
25309
- return true;
25310
- } catch {
25311
- try {
25312
- rmSync9(tmp, { force: true });
25313
- } catch {}
25314
- return false;
25315
- }
25316
- }
25317
- function macNotifierInstalled(home) {
25318
- return existsSync26(macNotifierPlistPath()) && existsSync26(macNotifierRunnerPath(home));
25319
- }
25320
- function pruneMacNotifyQueue(home, maxAgeMs = 7 * 86400000) {
25321
- try {
25322
- const dir = macNotifyDir(home);
25323
- if (!existsSync26(dir))
25324
- return;
25325
- const { statSync } = __require("node:fs");
25326
- for (const name of readdirSync16(dir)) {
25327
- const path = resolve22(dir, name);
25328
- try {
25329
- if (Date.now() - statSync(path).mtimeMs > maxAgeMs)
25330
- rmSync9(path, { force: true });
25331
- } catch {}
25332
- }
25333
- } catch {}
25334
- }
25335
- var MAC_NOTIFIER_LABEL = "ai.failproof.notifier", macNotifyDir = (home) => resolve22(runDir(home), "notify");
25336
- var init_macos_notifier = __esm(() => {
25337
- init_fp_home();
25338
- init_leak_fingerprint();
25339
- });
25340
-
25341
24952
  // lib/fetch-with-timeout.ts
25342
24953
  function fetchWithTimeout(input, init = {}, timeoutMs = DEFAULT_FETCH_TIMEOUT_MS) {
25343
24954
  const timeoutSignal = AbortSignal.timeout(timeoutMs);
@@ -25354,7 +24965,7 @@ var DEFAULT_FETCH_TIMEOUT_MS = 15000;
25354
24965
 
25355
24966
  // src/hooks/cloud-enrollment.ts
25356
24967
  import { randomUUID as randomUUID3 } from "node:crypto";
25357
- import { existsSync as existsSync27, readFileSync as readFileSync22, rmSync as rmSync10 } from "node:fs";
24968
+ import { existsSync as existsSync26, readFileSync as readFileSync22, rmSync as rmSync9 } from "node:fs";
25358
24969
  import { hostname as hostname4 } from "node:os";
25359
24970
  function cloudCredentialPath() {
25360
24971
  return process.env.FAILPROOFAI_CLOUD_CREDENTIALS ?? credentialsFile();
@@ -25393,7 +25004,7 @@ function readCloudCredentials() {
25393
25004
  if (!usingJsonOverride())
25394
25005
  return readCredentials().cloud ?? null;
25395
25006
  const path = cloudCredentialPath();
25396
- if (!existsSync27(path))
25007
+ if (!existsSync26(path))
25397
25008
  return null;
25398
25009
  try {
25399
25010
  const raw = JSON.parse(readFileSync22(path, "utf8"));
@@ -25435,10 +25046,10 @@ function resolveMachineLabel(explicit) {
25435
25046
  function clearCloudCredentials() {
25436
25047
  if (usingJsonOverride()) {
25437
25048
  const path = cloudCredentialPath();
25438
- if (!existsSync27(path))
25049
+ if (!existsSync26(path))
25439
25050
  return false;
25440
25051
  try {
25441
- rmSync10(path);
25052
+ rmSync9(path);
25442
25053
  return true;
25443
25054
  } catch {
25444
25055
  return false;
@@ -25686,14 +25297,14 @@ var init_cloud_connection = __esm(() => {
25686
25297
  });
25687
25298
 
25688
25299
  // src/hooks/setup-state.ts
25689
- import { existsSync as existsSync28, realpathSync as realpathSync2, statSync as statSync17 } from "node:fs";
25690
- import { dirname as dirname14, resolve as resolve23 } from "node:path";
25691
- import { homedir as homedir25 } from "node:os";
25692
- function globalConfigPath(home = homedir25()) {
25300
+ import { existsSync as existsSync27, realpathSync as realpathSync2, statSync as statSync17 } from "node:fs";
25301
+ import { dirname as dirname14, resolve as resolve22 } from "node:path";
25302
+ import { homedir as homedir24 } from "node:os";
25303
+ function globalConfigPath(home = homedir24()) {
25693
25304
  return globalPolicyConfigFile(home);
25694
25305
  }
25695
25306
  function projectConfigPath(projectRoot) {
25696
- return resolve23(projectRoot, ".failproofai", "policies-config.json");
25307
+ return resolve22(projectRoot, ".failproofai", "policies-config.json");
25697
25308
  }
25698
25309
  function legacyMarkerPath(home) {
25699
25310
  return launcherMarker(home);
@@ -25705,18 +25316,18 @@ function isDir(path) {
25705
25316
  return false;
25706
25317
  }
25707
25318
  }
25708
- function findProjectRoot(start, home = homedir25()) {
25319
+ function findProjectRoot(start, home = homedir24()) {
25709
25320
  const resolvedHome = realResolve(home);
25710
25321
  let dir = realResolve(start);
25711
25322
  while (dir !== resolvedHome) {
25712
- if (isDir(resolve23(dir, ".failproofai")))
25323
+ if (isDir(resolve22(dir, ".failproofai")))
25713
25324
  return dir;
25714
25325
  const parent = dirname14(dir);
25715
25326
  if (parent === dir)
25716
25327
  break;
25717
25328
  dir = parent;
25718
25329
  }
25719
- return resolve23(start);
25330
+ return resolve22(start);
25720
25331
  }
25721
25332
  function hasGlobalHooksInstalled() {
25722
25333
  for (const id of INTEGRATION_TYPES) {
@@ -25728,14 +25339,14 @@ function hasGlobalHooksInstalled() {
25728
25339
  return false;
25729
25340
  }
25730
25341
  function realResolve(path) {
25731
- const lexical = resolve23(path);
25342
+ const lexical = resolve22(path);
25732
25343
  try {
25733
25344
  return realpathSync2(lexical);
25734
25345
  } catch {
25735
25346
  return lexical;
25736
25347
  }
25737
25348
  }
25738
- function detectSetupState(cwd = process.cwd(), home = homedir25()) {
25349
+ function detectSetupState(cwd = process.cwd(), home = homedir24()) {
25739
25350
  const resolvedCwd = realResolve(cwd);
25740
25351
  const resolvedHome = realResolve(home);
25741
25352
  const projectRoot = findProjectRoot(resolvedCwd, resolvedHome);
@@ -25743,10 +25354,10 @@ function detectSetupState(cwd = process.cwd(), home = homedir25()) {
25743
25354
  cwd: resolvedCwd,
25744
25355
  home: resolvedHome,
25745
25356
  projectRoot,
25746
- hasGlobalConfig: existsSync28(globalConfigPath(resolvedHome)),
25747
- hasProjectConfig: projectRoot !== resolvedHome && existsSync28(projectConfigPath(projectRoot)),
25357
+ hasGlobalConfig: existsSync27(globalConfigPath(resolvedHome)),
25358
+ hasProjectConfig: projectRoot !== resolvedHome && existsSync27(projectConfigPath(projectRoot)),
25748
25359
  hasGlobalHooks: hasGlobalHooksInstalled(),
25749
- hasLegacyMarker: existsSync28(legacyMarkerPath(resolvedHome)),
25360
+ hasLegacyMarker: existsSync27(legacyMarkerPath(resolvedHome)),
25750
25361
  inHomeDir: resolvedCwd === resolvedHome
25751
25362
  };
25752
25363
  }
@@ -25763,11 +25374,11 @@ var init_setup_state = __esm(() => {
25763
25374
  });
25764
25375
 
25765
25376
  // src/hooks/onboarding-attempt.ts
25766
- import { existsSync as existsSync29, mkdirSync as mkdirSync18, readFileSync as readFileSync23, rmSync as rmSync11, writeFileSync as writeFileSync16 } from "node:fs";
25377
+ import { existsSync as existsSync28, mkdirSync as mkdirSync17, readFileSync as readFileSync23, rmSync as rmSync10, writeFileSync as writeFileSync15 } from "node:fs";
25767
25378
  import { dirname as dirname15 } from "node:path";
25768
25379
  function readOnboardingAttempt() {
25769
25380
  const path = onboardingAttemptFile();
25770
- if (!existsSync29(path))
25381
+ if (!existsSync28(path))
25771
25382
  return null;
25772
25383
  try {
25773
25384
  const raw = JSON.parse(readFileSync23(path, "utf8"));
@@ -25789,7 +25400,7 @@ function readOnboardingAttempt() {
25789
25400
  function recordOnboardingAttempt(reason, cliVersion, daemonStatus, now = Date.now()) {
25790
25401
  try {
25791
25402
  const path = onboardingAttemptFile();
25792
- mkdirSync18(dirname15(path), { recursive: true });
25403
+ mkdirSync17(dirname15(path), { recursive: true });
25793
25404
  const record = {
25794
25405
  schemaVersion: SCHEMA_VERSION3,
25795
25406
  reason,
@@ -25797,12 +25408,12 @@ function recordOnboardingAttempt(reason, cliVersion, daemonStatus, now = Date.no
25797
25408
  daemonStatus,
25798
25409
  at: now
25799
25410
  };
25800
- writeFileSync16(path, JSON.stringify(record, null, 2), "utf8");
25411
+ writeFileSync15(path, JSON.stringify(record, null, 2), "utf8");
25801
25412
  } catch {}
25802
25413
  }
25803
25414
  function clearOnboardingAttempt() {
25804
25415
  try {
25805
- rmSync11(onboardingAttemptFile(), { force: true });
25416
+ rmSync10(onboardingAttemptFile(), { force: true });
25806
25417
  } catch {}
25807
25418
  }
25808
25419
  function blockerCleared(attempt, probe) {
@@ -25844,9 +25455,9 @@ var init_onboarding_attempt = __esm(() => {
25844
25455
  });
25845
25456
 
25846
25457
  // src/hooks/onboarding-lock.ts
25847
- import { mkdirSync as mkdirSync19, readFileSync as readFileSync24, rmSync as rmSync12, writeFileSync as writeFileSync17 } from "node:fs";
25848
- import { homedir as homedir26 } from "node:os";
25849
- function onboardingLockPath(home = homedir26()) {
25458
+ import { mkdirSync as mkdirSync18, readFileSync as readFileSync24, rmSync as rmSync11, writeFileSync as writeFileSync16 } from "node:fs";
25459
+ import { homedir as homedir25 } from "node:os";
25460
+ function onboardingLockPath(home = homedir25()) {
25850
25461
  return onboardingLockFile(home);
25851
25462
  }
25852
25463
  function processAlive(pid) {
@@ -25869,15 +25480,15 @@ function readLock(path) {
25869
25480
  return null;
25870
25481
  }
25871
25482
  }
25872
- function acquireOnboardingLock(home = homedir26()) {
25483
+ function acquireOnboardingLock(home = homedir25()) {
25873
25484
  const path = onboardingLockPath(home);
25874
25485
  try {
25875
25486
  const held = readLock(path);
25876
25487
  if (held && held.pid !== process.pid && processAlive(held.pid))
25877
25488
  return null;
25878
- mkdirSync19(stateDir(home), { recursive: true });
25489
+ mkdirSync18(stateDir(home), { recursive: true });
25879
25490
  const body = { pid: process.pid, startedAt: Date.now() };
25880
- writeFileSync17(path, JSON.stringify(body), "utf8");
25491
+ writeFileSync16(path, JSON.stringify(body), "utf8");
25881
25492
  let released = false;
25882
25493
  return {
25883
25494
  release() {
@@ -25887,7 +25498,7 @@ function acquireOnboardingLock(home = homedir26()) {
25887
25498
  try {
25888
25499
  const current = readLock(path);
25889
25500
  if (!current || current.pid === process.pid)
25890
- rmSync12(path, { force: true });
25501
+ rmSync11(path, { force: true });
25891
25502
  } catch {}
25892
25503
  }
25893
25504
  };
@@ -25900,7 +25511,7 @@ var init_onboarding_lock = __esm(() => {
25900
25511
  });
25901
25512
 
25902
25513
  // lib/claude-sessions.ts
25903
- import { readdirSync as readdirSync17, statSync as statSync18, existsSync as existsSync30 } from "node:fs";
25514
+ import { readdirSync as readdirSync16, statSync as statSync18, existsSync as existsSync29 } from "node:fs";
25904
25515
  import { join as join32, basename as basename6 } from "node:path";
25905
25516
  function getClaudeProjectsRoot() {
25906
25517
  return getClaudeProjectsPath();
@@ -25909,7 +25520,7 @@ function listClaudeProjects() {
25909
25520
  const root = getClaudeProjectsRoot();
25910
25521
  let entries;
25911
25522
  try {
25912
- entries = readdirSync17(root, { withFileTypes: true });
25523
+ entries = readdirSync16(root, { withFileTypes: true });
25913
25524
  } catch {
25914
25525
  return [];
25915
25526
  }
@@ -25919,45 +25530,11 @@ function listClaudeProjects() {
25919
25530
  path: join32(root, e.name)
25920
25531
  }));
25921
25532
  }
25922
- function collectSubagentTranscripts(dir, relPrefix, project, out, depth) {
25923
- if (depth > MAX_SUBAGENT_DEPTH)
25924
- return;
25925
- let entries;
25926
- try {
25927
- entries = readdirSync17(dir, { withFileTypes: true });
25928
- } catch {
25929
- return;
25930
- }
25931
- for (const entry of entries) {
25932
- if (entry.isSymbolicLink())
25933
- continue;
25934
- if (entry.isDirectory()) {
25935
- collectSubagentTranscripts(join32(dir, entry.name), relPrefix ? `${relPrefix}__${entry.name}` : entry.name, project, out, depth + 1);
25936
- continue;
25937
- }
25938
- if (!entry.isFile() || !entry.name.endsWith(".jsonl"))
25939
- continue;
25940
- const stem = entry.name.slice(0, -".jsonl".length);
25941
- const transcriptPath = join32(dir, entry.name);
25942
- try {
25943
- const s = statSync18(transcriptPath);
25944
- out.push({
25945
- projectName: project.name,
25946
- cwd: project.cwd,
25947
- sessionId: relPrefix ? `${relPrefix}__${stem}` : stem,
25948
- transcriptPath,
25949
- mtimeMs: s.mtimeMs,
25950
- sizeBytes: s.size,
25951
- isSubagent: true
25952
- });
25953
- } catch {}
25954
- }
25955
- }
25956
25533
  function listClaudeTranscripts(project) {
25957
25534
  const out = [];
25958
25535
  let entries;
25959
25536
  try {
25960
- entries = readdirSync17(project.path, { withFileTypes: true });
25537
+ entries = readdirSync16(project.path, { withFileTypes: true });
25961
25538
  } catch {
25962
25539
  return out;
25963
25540
  }
@@ -25981,14 +25558,37 @@ function listClaudeTranscripts(project) {
25981
25558
  } catch {}
25982
25559
  } else if (entry.isDirectory() && UUID_RE2.test(entry.name)) {
25983
25560
  const subDir = join32(project.path, entry.name, "subagents");
25984
- if (!existsSync30(subDir))
25561
+ if (!existsSync29(subDir))
25985
25562
  continue;
25986
- collectSubagentTranscripts(subDir, entry.name, project, out, 0);
25563
+ let subEntries;
25564
+ try {
25565
+ subEntries = readdirSync16(subDir, { withFileTypes: true });
25566
+ } catch {
25567
+ continue;
25568
+ }
25569
+ for (const sub of subEntries) {
25570
+ if (!sub.isFile() || !sub.name.endsWith(".jsonl"))
25571
+ continue;
25572
+ const agentId = sub.name.slice(0, -".jsonl".length);
25573
+ const transcriptPath = join32(subDir, sub.name);
25574
+ try {
25575
+ const s = statSync18(transcriptPath);
25576
+ out.push({
25577
+ projectName: project.name,
25578
+ cwd: project.cwd,
25579
+ sessionId: agentId,
25580
+ transcriptPath,
25581
+ mtimeMs: s.mtimeMs,
25582
+ sizeBytes: s.size,
25583
+ isSubagent: true
25584
+ });
25585
+ } catch {}
25586
+ }
25987
25587
  }
25988
25588
  }
25989
25589
  return out;
25990
25590
  }
25991
- var UUID_RE2, MAX_SUBAGENT_DEPTH = 5;
25591
+ var UUID_RE2;
25992
25592
  var init_claude_sessions = __esm(() => {
25993
25593
  init_paths();
25994
25594
  UUID_RE2 = /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/i;
@@ -26047,7 +25647,6 @@ var init_shared = __esm(() => {
26047
25647
 
26048
25648
  // src/audit/cli-adapters/claude.ts
26049
25649
  import { readFile as readFile15, open as open2 } from "node:fs/promises";
26050
- import { readFileSync as readFileSync25 } from "node:fs";
26051
25650
  async function listClaudeTranscriptMetadata(opts = {}) {
26052
25651
  const projectFilter = opts.projects ? new Set(opts.projects) : null;
26053
25652
  const sinceMs = opts.sinceMs ?? 0;
@@ -26064,22 +25663,13 @@ async function listClaudeTranscriptMetadata(opts = {}) {
26064
25663
  for (const t of transcripts) {
26065
25664
  if (t.mtimeMs < sinceMs)
26066
25665
  continue;
26067
- let sessionDescription;
26068
- if (t.isSubagent) {
26069
- try {
26070
- const meta = JSON.parse(readFileSync25(t.transcriptPath.replace(/\.jsonl$/, ".meta.json"), "utf8"));
26071
- if (typeof meta.description === "string")
26072
- sessionDescription = meta.description;
26073
- } catch {}
26074
- }
26075
25666
  out.push({
26076
25667
  cli: "claude",
26077
25668
  projectName: project.name,
26078
25669
  sessionId: t.sessionId,
26079
25670
  transcriptPath: t.transcriptPath,
26080
25671
  mtimeMs: t.mtimeMs,
26081
- sizeBytes: t.sizeBytes,
26082
- sessionDescription
25672
+ sizeBytes: t.sizeBytes
26083
25673
  });
26084
25674
  }
26085
25675
  }
@@ -27309,420 +26899,9 @@ var init_features = __esm(() => {
27309
26899
  })();
27310
26900
  });
27311
26901
 
27312
- // src/audit/leak-scan.ts
27313
- function unquote(v) {
27314
- return v.startsWith('"') && v.endsWith('"') || v.startsWith("'") && v.endsWith("'") ? v.slice(1, -1) : v;
27315
- }
27316
- function isDocsLiteral(value) {
27317
- const { createHash } = __require("node:crypto");
27318
- return DOCS_LITERALS.has(createHash("sha256").update(value).digest("hex"));
27319
- }
27320
- function isSelfOutput(text) {
27321
- return SELF_OUTPUT_MARKERS.some((m) => text.includes(m));
27322
- }
27323
- function literalPrefixOf(source) {
27324
- let out = "";
27325
- for (let i = 0;i < source.length; i++) {
27326
- const c = source[i];
27327
- if (c === "\\") {
27328
- const next = source[i + 1];
27329
- if (next === undefined)
27330
- break;
27331
- if (/[dwsSDWbB]/.test(next))
27332
- break;
27333
- out += next;
27334
- i++;
27335
- continue;
27336
- }
27337
- if ("[](){}|?*+^$.".includes(c))
27338
- break;
27339
- out += c;
27340
- }
27341
- return out.length >= 2 ? out : null;
27342
- }
27343
- function applicablePatterns(text) {
27344
- return GATED_PATTERNS.filter(([, , gate]) => gate === null || text.includes(gate));
27345
- }
27346
- function findSecrets(text) {
27347
- if (!text)
27348
- return [];
27349
- if (isSelfOutput(text))
27350
- return [];
27351
- const byValue = new Map;
27352
- for (const [pattern, label] of applicablePatterns(text)) {
27353
- const re = new RegExp(pattern.source, pattern.flags.includes("g") ? pattern.flags : pattern.flags + "g");
27354
- for (const m of text.matchAll(re)) {
27355
- const value = m[0];
27356
- if (isDocsLiteral(value))
27357
- continue;
27358
- if (!byValue.has(value))
27359
- byValue.set(value, { value, name: null, rule: label, shaped: true });
27360
- }
27361
- }
27362
- for (const m of text.matchAll(ASSIGNMENT_RE)) {
27363
- const name = m[2];
27364
- const value = unquote(m[4]);
27365
- const existing = byValue.get(value);
27366
- if (existing)
27367
- existing.name ??= name;
27368
- }
27369
- return [...byValue.values()];
27370
- }
27371
- function flattenToolInput(input, depth = 0) {
27372
- if (depth > 6 || input == null)
27373
- return "";
27374
- if (typeof input === "string")
27375
- return input;
27376
- if (typeof input === "number" || typeof input === "boolean")
27377
- return String(input);
27378
- if (Array.isArray(input))
27379
- return input.map((v) => flattenToolInput(v, depth + 1)).join(`
27380
- `);
27381
- if (typeof input === "object") {
27382
- return Object.entries(input).map(([k, v]) => `${k}=${flattenToolInput(v, depth + 1)}`).join(`
27383
- `);
27384
- }
27385
- return "";
27386
- }
27387
- var LEAK_SCAN_VERSION = 6, ASSIGNMENT_RE, DOCS_LITERALS, SELF_OUTPUT_MARKERS, GATED_PATTERNS;
27388
- var init_leak_scan = __esm(() => {
27389
- init_builtin_policies();
27390
- ASSIGNMENT_RE = /(["']?)\b([A-Za-z_][A-Za-z0-9_]{0,127})\1([ \t]*(?::(?!\/\/)|=)[ \t]*)("[^"]*"|'[^']*'|[^\s;|&"']+)/g;
27391
- DOCS_LITERALS = new Set([
27392
- "1a5d44a2dca19669d72edf4c4f1c27c4c1ca4b4408fbb17f6ce4ad452d78ddb3",
27393
- "78314b11be2e581549ac1c4f616563fad3fdf0c3b71678f6e2299182080e0598",
27394
- "cb20d34a7adda2f5d2043836051e242fd4c2b233e02c80c91fe9d5af9b100574",
27395
- "3543c50b0cb9cea8e55eb1f529b79f043cb250d485fde7b66cabbb5183add7da",
27396
- "1fae28c1b317300acfd90078c973567c8159015822b0c8b81508a5ec40517d20",
27397
- "23219833092a3136d7ad178ccb62ebd6ac8cba54ff24c2cfcd37b84aba9e95cf",
27398
- "872db7f4419592e397ef45230f910e06b48c36ed9970cf1f9e4fb896e69f129c",
27399
- "78a08441f4314f0a2833cfe58c62e555a162264206982cda39f6804f5048f570",
27400
- "2cafc0970149a84f3b9e62eaf169f36f59907a3b3e31f7b82e68c69cd27f7326",
27401
- "b363ade84d56c43bebbc9339b4971e340e3f13f7f8d45580b53373d2763e9e33"
27402
- ]);
27403
- SELF_OUTPUT_MARKERS = [
27404
- "[REDACTED:",
27405
- "[redacted:",
27406
- "failproofai audit",
27407
- "assigned secret]"
27408
- ];
27409
- GATED_PATTERNS = SECRET_PATTERNS.map(([re, label]) => [re, label, literalPrefixOf(re.source)]);
27410
- });
27411
-
27412
- // src/audit/leak-record.ts
27413
- function upsertFinding(record, incoming) {
27414
- const { sighting, ...rest } = incoming;
27415
- const existing = record.findings.find((f) => f.id === rest.id);
27416
- if (!existing) {
27417
- record.findings.push({
27418
- ...rest,
27419
- firstSeen: sighting.at,
27420
- lastSeen: sighting.at,
27421
- occurrences: 1,
27422
- sightings: [sighting]
27423
- });
27424
- return { record, isNew: true };
27425
- }
27426
- const seen = existing.sightings.some((s) => s.sessionId === sighting.sessionId && s.at === sighting.at && s.mechanism.direction === sighting.mechanism.direction && s.mechanism.summary === sighting.mechanism.summary);
27427
- if (seen)
27428
- return { record, isNew: false };
27429
- existing.occurrences += 1;
27430
- if (sighting.at > existing.lastSeen)
27431
- existing.lastSeen = sighting.at;
27432
- if (sighting.at < existing.firstSeen)
27433
- existing.firstSeen = sighting.at;
27434
- existing.sightings.push(sighting);
27435
- existing.sightings.sort((a, b) => a.at.localeCompare(b.at));
27436
- if (existing.sightings.length > MAX_SIGHTINGS) {
27437
- existing.sightings.splice(1, existing.sightings.length - MAX_SIGHTINGS);
27438
- }
27439
- return { record, isNew: false };
27440
- }
27441
- function pruneRecord(record, nowMs) {
27442
- const cutoff = new Date(nowMs - FINDING_TTL_DAYS * 86400000).toISOString();
27443
- const live = record.findings.filter((f) => !f.lastSeen || !Number.isFinite(Date.parse(f.lastSeen)) || f.lastSeen >= cutoff);
27444
- live.sort((a, b) => a.lastSeen < b.lastSeen ? 1 : a.lastSeen > b.lastSeen ? -1 : 0);
27445
- record.findings = live.slice(0, MAX_FINDINGS);
27446
- return record;
27447
- }
27448
- function emptyRecord(salt, nowIso) {
27449
- return {
27450
- schemaVersion: LEAK_RECORD_SCHEMA_VERSION,
27451
- salt,
27452
- updatedAt: nowIso,
27453
- findings: []
27454
- };
27455
- }
27456
- function describeMechanism(toolName, direction, shortPath) {
27457
- const where = shortPath ? ` ${shortPath}` : "";
27458
- let summary;
27459
- if (direction === "result") {
27460
- summary = shortPath ? `appeared in the output of reading${where}` : "appeared in tool output";
27461
- } else {
27462
- switch (toolName) {
27463
- case "Read":
27464
- summary = `read from${where || " a file"}`;
27465
- break;
27466
- case "Write":
27467
- summary = `written to${where || " a file"}`;
27468
- break;
27469
- case "Edit":
27470
- case "NotebookEdit":
27471
- summary = `edited into${where || " a file"}`;
27472
- break;
27473
- case "Bash":
27474
- summary = "passed in a shell command";
27475
- break;
27476
- default:
27477
- summary = `sent to the ${toolName} tool`;
27478
- }
27479
- }
27480
- return { summary, toolName, direction };
27481
- }
27482
- var MAX_SIGHTINGS = 5, FINDING_TTL_DAYS = 90, MAX_FINDINGS = 500, LEAK_RECORD_SCHEMA_VERSION = 1;
27483
-
27484
- // src/audit/leak-store.ts
27485
- import { randomBytes as randomBytes2 } from "node:crypto";
27486
- import { existsSync as existsSync31, mkdirSync as mkdirSync20, readFileSync as readFileSync26 } from "node:fs";
27487
- import { dirname as dirname16 } from "node:path";
27488
- function readJson(path) {
27489
- try {
27490
- if (!existsSync31(path))
27491
- return null;
27492
- return JSON.parse(readFileSync26(path, "utf8"));
27493
- } catch {
27494
- return null;
27495
- }
27496
- }
27497
- function readLeakIdentity(home) {
27498
- const existing = readJson(auditLeakIdentityFile(home));
27499
- if (existing && typeof existing.salt === "string" && existing.salt.length >= 32) {
27500
- return {
27501
- salt: existing.salt,
27502
- dismissed: existing.dismissed ?? []
27503
- };
27504
- }
27505
- const minted = { salt: randomBytes2(32).toString("hex"), dismissed: [] };
27506
- writeLeakIdentity(minted, home);
27507
- return minted;
27508
- }
27509
- function writeLeakIdentity(identity, home) {
27510
- const path = auditLeakIdentityFile(home);
27511
- try {
27512
- mkdirSync20(dirname16(path), { recursive: true });
27513
- writeJsonAtomically(path, identity, { mode: FILE_MODE });
27514
- return true;
27515
- } catch {
27516
- return false;
27517
- }
27518
- }
27519
- function sanitizeFinding(raw) {
27520
- if (!raw || typeof raw !== "object" || Array.isArray(raw))
27521
- return null;
27522
- const f = raw;
27523
- if (typeof f.id !== "string" || !isFindingId(f.id))
27524
- return null;
27525
- const fp = f.fingerprint;
27526
- if (!fp || typeof fp !== "object" || typeof fp.display !== "string" || typeof fp.label !== "string") {
27527
- return null;
27528
- }
27529
- const sightings = Array.isArray(f.sightings) ? f.sightings.filter((s) => {
27530
- if (!s || typeof s !== "object")
27531
- return false;
27532
- const m = s.mechanism;
27533
- return !!m && typeof m === "object" && typeof m.summary === "string";
27534
- }) : [];
27535
- return {
27536
- ...f,
27537
- fingerprint: {
27538
- display: fp.display,
27539
- label: fp.label,
27540
- length: typeof fp.length === "number" && Number.isFinite(fp.length) ? fp.length : 0,
27541
- attributed: fp.attributed === true
27542
- },
27543
- name: typeof f.name === "string" ? f.name : null,
27544
- firstSeen: typeof f.firstSeen === "string" ? f.firstSeen : "",
27545
- lastSeen: typeof f.lastSeen === "string" ? f.lastSeen : "",
27546
- occurrences: typeof f.occurrences === "number" && Number.isFinite(f.occurrences) ? f.occurrences : sightings.length,
27547
- sightings
27548
- };
27549
- }
27550
- function readLeakRecord(home) {
27551
- const identity = readLeakIdentity(home);
27552
- const raw = readJson(auditLeaksFile(home));
27553
- if (!raw || raw.schemaVersion !== LEAK_RECORD_SCHEMA_VERSION || !Array.isArray(raw.findings)) {
27554
- return emptyRecord(identity.salt, new Date().toISOString());
27555
- }
27556
- const findings = raw.findings.map(sanitizeFinding).filter((f) => f !== null);
27557
- return { ...raw, findings, salt: identity.salt };
27558
- }
27559
- function writeLeakRecord(record, home, nowMs = Date.now()) {
27560
- const path = auditLeaksFile(home);
27561
- try {
27562
- mkdirSync20(dirname16(path), { recursive: true });
27563
- const pruned = pruneRecord(record, nowMs);
27564
- pruned.updatedAt = new Date(nowMs).toISOString();
27565
- writeJsonAtomically(path, pruned, { mode: FILE_MODE });
27566
- return true;
27567
- } catch {
27568
- return false;
27569
- }
27570
- }
27571
- function activeFindings(record, home) {
27572
- const dismissed = new Set(readLeakIdentity(home).dismissed);
27573
- return record.findings.filter((f) => !dismissed.has(f.id)).sort((a, b) => a.lastSeen < b.lastSeen ? 1 : a.lastSeen > b.lastSeen ? -1 : 0);
27574
- }
27575
- var FILE_MODE = 384;
27576
- var init_leak_store = __esm(() => {
27577
- init_fp_home();
27578
- init_atomic_write();
27579
- init_leak_fingerprint();
27580
- });
27581
-
27582
- // src/audit/redact-example.ts
27583
- import { homedir as homedir27 } from "node:os";
27584
- function maskTruncatedSecret(input) {
27585
- for (const [pattern, label] of SECRET_PREFIXES) {
27586
- if (pattern.test(input)) {
27587
- return input.replace(pattern, `[REDACTED: ${label}]`);
27588
- }
27589
- }
27590
- return input;
27591
- }
27592
- function identifierComponents(name) {
27593
- return name.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1_$2").toUpperCase().split(/[_\-.]+/).filter(Boolean);
27594
- }
27595
- function isPublishedByDesign(name) {
27596
- const components = identifierComponents(name);
27597
- if (components.length === 0)
27598
- return false;
27599
- const upper = components.join("_");
27600
- for (const prefix of CLIENT_BUNDLE_PREFIXES) {
27601
- if (upper === prefix || upper.startsWith(prefix + "_"))
27602
- return true;
27603
- }
27604
- return PUBLISHED_MARKERS.test(upper);
27605
- }
27606
- function isSecretName(name) {
27607
- if (isPublishedByDesign(name))
27608
- return false;
27609
- const upper = name.toUpperCase();
27610
- if (SECRET_NAME_SUBSTRINGS.some((word) => upper.includes(word)))
27611
- return true;
27612
- const components = identifierComponents(name);
27613
- if (components.some((part) => SECRET_NAME_COMPONENTS.includes(part)))
27614
- return true;
27615
- return components.length > 1 && components.some((part) => COMPOUND_ONLY_COMPONENTS.includes(part));
27616
- }
27617
- function maskAssignedSecrets(input) {
27618
- let out = input.replace(ASSIGNMENT_RE2, (match, quote, name, separator, value) => {
27619
- if (!isSecretName(name))
27620
- return match;
27621
- if (value.startsWith("[REDACTED"))
27622
- return match;
27623
- return `${quote}${name}${quote}${separator}[REDACTED: assigned secret]`;
27624
- });
27625
- out = out.replace(URL_CREDENTIALS_RE, "$1[REDACTED: URL credentials]@");
27626
- out = out.replace(BASIC_AUTH_FLAG_RE, "$1[REDACTED: basic auth]");
27627
- return out;
27628
- }
27629
- function maskSecrets(input) {
27630
- let out = input;
27631
- for (const [pattern, label] of SECRET_PATTERNS) {
27632
- const global = new RegExp(pattern.source, pattern.flags.includes("g") ? pattern.flags : `${pattern.flags}g`);
27633
- out = out.replace(global, `[REDACTED: ${label}]`);
27634
- }
27635
- return out;
27636
- }
27637
- function shortenPaths(input, home = homedir27()) {
27638
- const homeRoot = home.replace(/\/+$/, "");
27639
- return input.replace(ABSOLUTE_PATH_RE, (match, offset, whole) => {
27640
- if (PUBLIC_PATH_ROOTS.some((root) => match.startsWith(root)))
27641
- return match;
27642
- if (offset > 0 && whole[offset - 1] === "/" && /[a-z][a-z0-9+.\-]*:$/i.test(whole.slice(0, offset - 1))) {
27643
- const urlSegments = match.split("/").filter(Boolean);
27644
- if (urlSegments.length <= 1)
27645
- return match;
27646
- const host = urlSegments[0];
27647
- const leaf = urlSegments[urlSegments.length - 1];
27648
- const elided = urlSegments.length > 2 ? "/…" : "";
27649
- return `/${host}${elided}/${leaf}${match.endsWith("/") ? "/" : ""}`;
27650
- }
27651
- const trailingSlash = match.endsWith("/");
27652
- const segments = match.split("/").filter(Boolean);
27653
- if (segments.length === 0)
27654
- return match;
27655
- const basename = segments[segments.length - 1];
27656
- const kept = segments.slice(Math.max(0, segments.length - 1 - KEPT_PARENT_SEGMENTS), segments.length - 1);
27657
- const matchRoot = match.replace(/\/+$/, "");
27658
- const underHome = homeRoot.length > 0 && (matchRoot === homeRoot || matchRoot.startsWith(`${homeRoot}/`));
27659
- if (matchRoot === homeRoot && homeRoot.length > 0) {
27660
- return trailingSlash ? "~/" : "~";
27661
- }
27662
- const root = underHome ? "~" : "";
27663
- const middle = segments.length - kept.length - 1 > 0 ? "/…" : "";
27664
- const tail = [...kept, basename].join("/");
27665
- return `${root}${middle}/${tail}${trailingSlash ? "/" : ""}`;
27666
- });
27667
- }
27668
- function maskSecretsOnly(input) {
27669
- return maskAssignedSecrets(maskTruncatedSecret(maskSecrets(input)));
27670
- }
27671
- function redactExample(input, home = homedir27()) {
27672
- const masked = maskSecretsOnly(input);
27673
- const shortened = shortenPaths(masked, home);
27674
- const collapsed = shortened.replace(/\s+/g, " ").trim();
27675
- return collapsed.length > REDACTED_EXAMPLE_MAX_CHARS ? `${collapsed.slice(0, REDACTED_EXAMPLE_MAX_CHARS - 1)}…` : collapsed;
27676
- }
27677
- var REDACTED_EXAMPLE_MAX_CHARS = 160, KEPT_PARENT_SEGMENTS = 0, ABSOLUTE_PATH_RE, PUBLIC_PATH_ROOTS, SECRET_PREFIXES, SECRET_NAME_SUBSTRINGS, SECRET_NAME_COMPONENTS, COMPOUND_ONLY_COMPONENTS, ASSIGNMENT_RE2, URL_CREDENTIALS_RE, BASIC_AUTH_FLAG_RE, CLIENT_BUNDLE_PREFIXES, PUBLISHED_MARKERS;
27678
- var init_redact_example = __esm(() => {
27679
- init_builtin_policies();
27680
- ABSOLUTE_PATH_RE = /(?:\/[\w.\-@+]+){2,}\/?/g;
27681
- PUBLIC_PATH_ROOTS = ["/dev/", "/proc/", "/sys/"];
27682
- SECRET_PREFIXES = [
27683
- [/(?<!\w)(?:Authorization:\s*)?Bearer\s+\S*$/i, "bearer token"],
27684
- [/(?<!\w)sk-ant-\S*$/, "Anthropic API key"],
27685
- [/(?<!\w)sk-proj-\S*$/, "OpenAI project API key"],
27686
- [/(?<!\w)sk-\S*$/, "OpenAI API key"],
27687
- [/(?<!\w)ghp_\S*$/, "GitHub personal access token"],
27688
- [/(?<!\w)github_pat_\S*$/, "GitHub fine-grained token"],
27689
- [/(?<!\w)AKIA\S*$/, "AWS access key ID"],
27690
- [/(?<!\w)sk_live_\S*$/, "Stripe live secret key"],
27691
- [/(?<!\w)sk_test_\S*$/, "Stripe test secret key"],
27692
- [/(?<!\w)AIza\S*$/, "Google API key"],
27693
- [/-----BEGIN\s[A-Z ]*$/, "private key"]
27694
- ];
27695
- SECRET_NAME_SUBSTRINGS = [
27696
- "TOKEN",
27697
- "SECRET",
27698
- "PASSWORD",
27699
- "PASSWD",
27700
- "PASSPHRASE",
27701
- "CREDENTIAL",
27702
- "APIKEY",
27703
- "PRIVATEKEY"
27704
- ];
27705
- SECRET_NAME_COMPONENTS = ["PASS", "AUTH", "PAT", "SIG", "SIGNATURE", "COOKIE"];
27706
- COMPOUND_ONLY_COMPONENTS = ["PWD", "KEY"];
27707
- ASSIGNMENT_RE2 = /(["']?)\b([A-Za-z_][A-Za-z0-9_]{0,127})\1([ \t]*(?::(?!\/\/)|=)[ \t]*)("[^"]*"|'[^']*'|[^\s;|&"']+)/g;
27708
- URL_CREDENTIALS_RE = /([a-z][a-z0-9+.\-]{0,31}:\/\/)[^\s/:@]{1,256}:[^\s/@]{1,256}@/gi;
27709
- BASIC_AUTH_FLAG_RE = /((?:^|\s)(?:-u|--user)[\s=])\S+:\S+/g;
27710
- CLIENT_BUNDLE_PREFIXES = [
27711
- "NEXT_PUBLIC",
27712
- "VITE",
27713
- "REACT_APP",
27714
- "EXPO_PUBLIC",
27715
- "NUXT_PUBLIC",
27716
- "GATSBY",
27717
- "STORYBOOK",
27718
- "PUBLIC"
27719
- ];
27720
- PUBLISHED_MARKERS = /PUBLISHABLE|(^|_)PUBLIC_KEY$|(^|_)ANON_KEY$/;
27721
- });
27722
-
27723
26902
  // src/audit/cache.ts
27724
26903
  import { createHash as createHash8 } from "node:crypto";
27725
- import { existsSync as existsSync32, mkdirSync as mkdirSync21, readFileSync as readFileSync27, writeFileSync as writeFileSync18, chmodSync as chmodSync6, openSync, readSync, closeSync } from "node:fs";
26904
+ import { existsSync as existsSync30, mkdirSync as mkdirSync19, readFileSync as readFileSync25, writeFileSync as writeFileSync17, chmodSync as chmodSync5, openSync, readSync, closeSync } from "node:fs";
27726
26905
  import { join as join33 } from "node:path";
27727
26906
  function getEngineVersion() {
27728
26907
  if (cachedEngineVersion)
@@ -27783,10 +26962,10 @@ function readCachedTranscript(transcriptPath, mtimeMs, sizeBytes) {
27783
26962
  if (sizeBytes === 0)
27784
26963
  return null;
27785
26964
  const cachePath = getCachePathFor(transcriptPath);
27786
- if (!existsSync32(cachePath))
26965
+ if (!existsSync30(cachePath))
27787
26966
  return null;
27788
26967
  try {
27789
- const raw = readFileSync27(cachePath, "utf-8");
26968
+ const raw = readFileSync25(cachePath, "utf-8");
27790
26969
  const entry = JSON.parse(raw);
27791
26970
  if (entry.schemaVersion !== CACHE_SCHEMA_VERSION)
27792
26971
  return null;
@@ -27794,8 +26973,6 @@ function readCachedTranscript(transcriptPath, mtimeMs, sizeBytes) {
27794
26973
  return null;
27795
26974
  if (entry.detectorVersion !== getDetectorVersion())
27796
26975
  return null;
27797
- if (entry.leakScanVersion !== LEAK_SCAN_VERSION)
27798
- return null;
27799
26976
  if (!Number.isFinite(entry.cachedAt) || Date.now() - entry.cachedAt > CACHE_TTL_MS)
27800
26977
  return null;
27801
26978
  if (!entry.result)
@@ -27827,7 +27004,7 @@ function writeCachedTranscriptResult(transcriptPath, mtimeMs, sizeBytes, result,
27827
27004
  return;
27828
27005
  const cachePath = getCachePathFor(transcriptPath);
27829
27006
  try {
27830
- mkdirSync21(auditCacheDir(), { recursive: true });
27007
+ mkdirSync19(auditCacheDir(), { recursive: true });
27831
27008
  const entry = {
27832
27009
  schemaVersion: CACHE_SCHEMA_VERSION,
27833
27010
  cachedAt: Date.now(),
@@ -27835,7 +27012,6 @@ function writeCachedTranscriptResult(transcriptPath, mtimeMs, sizeBytes, result,
27835
27012
  sizeBytes,
27836
27013
  engineVersion: getEngineVersion(),
27837
27014
  detectorVersion: getDetectorVersion(),
27838
- leakScanVersion: LEAK_SCAN_VERSION,
27839
27015
  result
27840
27016
  };
27841
27017
  if (resume && resume.bytesScanned > 0) {
@@ -27846,9 +27022,9 @@ function writeCachedTranscriptResult(transcriptPath, mtimeMs, sizeBytes, result,
27846
27022
  entry.detectorState = encodeDetectorState(resume.detectorState);
27847
27023
  }
27848
27024
  }
27849
- writeFileSync18(cachePath, JSON.stringify(entry), { encoding: "utf-8", mode: 384 });
27025
+ writeFileSync17(cachePath, JSON.stringify(entry), { encoding: "utf-8", mode: 384 });
27850
27026
  try {
27851
- chmodSync6(cachePath, 384);
27027
+ chmodSync5(cachePath, 384);
27852
27028
  } catch {}
27853
27029
  } catch {}
27854
27030
  }
@@ -27856,7 +27032,6 @@ var cachedEngineVersion = null, cachedDetectorVersion = null, CACHE_SCHEMA_VERSI
27856
27032
  var init_cache = __esm(() => {
27857
27033
  init_builtin_policies();
27858
27034
  init_detectors();
27859
- init_leak_scan();
27860
27035
  init_fp_home();
27861
27036
  CACHE_TTL_MS = 30 * 24 * 60 * 60000;
27862
27037
  });
@@ -27925,30 +27100,6 @@ var init_replay = __esm(() => {
27925
27100
  });
27926
27101
 
27927
27102
  // src/audit/index.ts
27928
- class ByteGate {
27929
- budget;
27930
- inFlight = 0;
27931
- waiting = [];
27932
- constructor(budget) {
27933
- this.budget = budget;
27934
- }
27935
- async acquire(bytes) {
27936
- const want = Math.max(0, bytes);
27937
- while (this.inFlight > 0 && this.inFlight + want > this.budget) {
27938
- await new Promise((resolve) => this.waiting.push(resolve));
27939
- }
27940
- this.inFlight += want;
27941
- }
27942
- release(bytes) {
27943
- this.inFlight -= Math.max(0, bytes);
27944
- if (this.inFlight < 0)
27945
- this.inFlight = 0;
27946
- const waiters = this.waiting;
27947
- this.waiting = [];
27948
- for (const wake of waiters)
27949
- wake();
27950
- }
27951
- }
27952
27103
  function shortPolicyName(name) {
27953
27104
  const slash = name.indexOf("/");
27954
27105
  return slash >= 0 ? name.slice(slash + 1) : name;
@@ -27990,27 +27141,6 @@ function parseSinceOpt(since) {
27990
27141
  return t;
27991
27142
  throw new Error(`Invalid --since value: "${since}" (expected e.g. "7d", "30d", or "2026-04-01")`);
27992
27143
  }
27993
- function isCredentialResearchSession(events, sessionDescription) {
27994
- if (sessionDescription && CREDENTIAL_RESEARCH_PURPOSE.test(sessionDescription))
27995
- return true;
27996
- const matched = new Set;
27997
- let evidenceEvents = 0;
27998
- for (const event of events) {
27999
- const intent = flattenToolInput(event.toolInput);
28000
- let eventMatched = false;
28001
- for (let i = 0;i < CREDENTIAL_RESEARCH_MARKERS.length; i++) {
28002
- if (CREDENTIAL_RESEARCH_MARKERS[i].test(intent)) {
28003
- matched.add(i);
28004
- eventMatched = true;
28005
- }
28006
- }
28007
- if (eventMatched)
28008
- evidenceEvents++;
28009
- if (matched.size >= 2 || evidenceEvents >= 3)
28010
- return true;
28011
- }
28012
- return false;
28013
- }
28014
27144
  async function scanOneTranscript(meta, resume) {
28015
27145
  const empty = {
28016
27146
  transcriptPath: meta.transcriptPath,
@@ -28051,10 +27181,13 @@ async function scanOneTranscript(meta, resume) {
28051
27181
  const result = empty;
28052
27182
  result.eventsScanned = events.length;
28053
27183
  result.cwd = result.cwd || events[0].cwd || "";
28054
- const suppressLeakScan = isCredentialResearchSession(events, meta.sessionDescription);
28055
- if (suppressLeakScan)
28056
- result.leakScanSuppressed = "credential-research";
28057
27184
  for (const event of events) {
27185
+ for (const detector of AUDIT_DETECTORS) {
27186
+ const hit = detector.detect(event, sessionState);
27187
+ if (!hit)
27188
+ continue;
27189
+ recordHit(result, detector.name, event.timestamp, event.cwd, truncateExample(hit.example));
27190
+ }
28058
27191
  let replayHits;
28059
27192
  try {
28060
27193
  replayHits = await replayEvent(event);
@@ -28065,77 +27198,9 @@ async function scanOneTranscript(meta, resume) {
28065
27198
  const example = formatPolicyExample(hit.policyName, event);
28066
27199
  recordHit(result, hit.policyName, event.timestamp, event.cwd, truncateExample(example));
28067
27200
  }
28068
- if (!suppressLeakScan)
28069
- recordLeaks(result, event);
28070
27201
  }
28071
27202
  return { result, bytesScanned, detectorState: sessionState, resumed };
28072
27203
  }
28073
- function recordLeaks(result, event) {
28074
- const salt = leakSalt();
28075
- if (!salt)
28076
- return;
28077
- const filePath = event.toolInput.file_path;
28078
- const shortPath = typeof filePath === "string" ? shortenPaths(filePath) : null;
28079
- const scan = (text, direction) => {
28080
- for (const match of findSecrets(text)) {
28081
- (result.leaks ??= []).push({
28082
- id: fingerprintId(match.value, salt),
28083
- fingerprint: fingerprintSecret(match.value, match.rule),
28084
- name: match.name,
28085
- rule: match.rule,
28086
- shaped: match.shaped,
28087
- timestamp: event.timestamp,
28088
- cwd: event.cwd,
28089
- toolName: event.toolName,
28090
- direction,
28091
- path: shortPath
28092
- });
28093
- }
28094
- };
28095
- scan(flattenToolInput(event.toolInput), "input");
28096
- if (event.toolResultText !== undefined)
28097
- scan(event.toolResultText, "result");
28098
- }
28099
- function leakSalt() {
28100
- if (cachedSalt === undefined) {
28101
- try {
28102
- cachedSalt = readLeakIdentity().salt;
28103
- } catch {
28104
- cachedSalt = null;
28105
- }
28106
- }
28107
- return cachedSalt;
28108
- }
28109
- function persistLeaks(perTranscript, replaceExisting) {
28110
- const fresh = [];
28111
- try {
28112
- const previous = readLeakRecord();
28113
- const previousIds = new Set(previous.findings.map((f) => f.id));
28114
- const record = replaceExisting ? emptyRecord(previous.salt, new Date().toISOString()) : previous;
28115
- for (const t of perTranscript) {
28116
- for (const leak of t.leaks ?? []) {
28117
- const { isNew } = upsertFinding(record, {
28118
- id: leak.id,
28119
- fingerprint: leak.fingerprint,
28120
- name: leak.name,
28121
- rule: leak.rule,
28122
- confidence: leak.shaped ? "doc-verified" : "name-only",
28123
- sighting: {
28124
- cli: t.cli,
28125
- sessionId: t.sessionId,
28126
- cwd: shortenPaths(leak.cwd),
28127
- at: leak.timestamp,
28128
- mechanism: describeMechanism(leak.toolName, leak.direction, leak.path)
28129
- }
28130
- });
28131
- if (isNew && !previousIds.has(leak.id))
28132
- fresh.push(leak.id);
28133
- }
28134
- }
28135
- writeLeakRecord(record);
28136
- } catch {}
28137
- return fresh;
28138
- }
28139
27204
  function formatPolicyExample(_policyName, event) {
28140
27205
  if (event.toolName === "Bash") {
28141
27206
  const command = event.toolInput.command;
@@ -28158,12 +27223,6 @@ function mergeIncremental(cached, tail) {
28158
27223
  examplesByName: {},
28159
27224
  rangeByName: { ...cached.rangeByName }
28160
27225
  };
28161
- if (cached.leakScanSuppressed || tail.leakScanSuppressed) {
28162
- out.leakScanSuppressed = "credential-research";
28163
- out.leaks = [];
28164
- } else {
28165
- out.leaks = [...cached.leaks ?? [], ...tail.leaks ?? []];
28166
- }
28167
27226
  for (const [name, list] of Object.entries(cached.examplesByName)) {
28168
27227
  out.examplesByName[name] = [...list];
28169
27228
  }
@@ -28287,19 +27346,16 @@ async function runAuditInner(opts, startedAt) {
28287
27346
  }
28288
27347
  } catch {}
28289
27348
  const allTranscripts = [];
28290
- let discoveryErrors = 0;
28291
27349
  for (const cli of clis) {
28292
27350
  const adapter = ADAPTERS[cli];
28293
27351
  let list;
28294
27352
  try {
28295
27353
  list = await adapter.listTranscripts({ projects: opts.projects, sinceMs });
28296
27354
  } catch {
28297
- discoveryErrors++;
28298
27355
  continue;
28299
27356
  }
28300
27357
  allTranscripts.push(...list);
28301
27358
  }
28302
- const gate = new ByteGate(TRANSCRIPT_BYTE_BUDGET);
28303
27359
  let skipped = 0;
28304
27360
  let errors = 0;
28305
27361
  const tasks = allTranscripts.map((meta) => async () => {
@@ -28312,7 +27368,6 @@ async function runAuditInner(opts, startedAt) {
28312
27368
  resume = found?.kind === "resume" ? { fromByte: found.fromByte, detectorState: found.detectorState } : undefined;
28313
27369
  cachedPrefix = found?.kind === "resume" ? found.result : null;
28314
27370
  }
28315
- await gate.acquire(meta.sizeBytes);
28316
27371
  try {
28317
27372
  const scan = await scanOneTranscript(meta, resume);
28318
27373
  const fresh = cachedPrefix && scan.resumed ? mergeIncremental(cachedPrefix, scan.result) : scan.result;
@@ -28335,8 +27390,6 @@ async function runAuditInner(opts, startedAt) {
28335
27390
  examplesByName: {},
28336
27391
  rangeByName: {}
28337
27392
  };
28338
- } finally {
28339
- gate.release(meta.sizeBytes);
28340
27393
  }
28341
27394
  });
28342
27395
  const settled = await batchAll(tasks, TRANSCRIPT_CONCURRENCY);
@@ -28363,13 +27416,8 @@ async function runAuditInner(opts, startedAt) {
28363
27416
  projectsScannedSet.add(t.cwd);
28364
27417
  eventsScanned += t.eventsScanned ?? 0;
28365
27418
  }
28366
- const coversAllHistory = opts.clis === undefined && opts.projects === undefined && opts.since === undefined && discoveryErrors === 0 && errors === 0 && skipped === 0;
28367
- const newFindingIds = persistLeaks(perTranscript, coversAllHistory);
28368
- const leakIds = [...new Set(perTranscript.flatMap((t) => (t.leaks ?? []).map((leak) => leak.id)))];
28369
27419
  const auditResult = {
28370
27420
  version: 2,
28371
- leakIds,
28372
- newLeakIds: newFindingIds,
28373
27421
  scannedAt: new Date(startedAt).toISOString(),
28374
27422
  scope: {
28375
27423
  cli: clis,
@@ -28393,7 +27441,7 @@ async function runAuditInner(opts, startedAt) {
28393
27441
  };
28394
27442
  return auditResult;
28395
27443
  }
28396
- var TRANSCRIPT_CONCURRENCY = 8, TRANSCRIPT_BYTE_BUDGET, CREDENTIAL_RESEARCH_MARKERS, CREDENTIAL_RESEARCH_PURPOSE, cachedSalt;
27444
+ var TRANSCRIPT_CONCURRENCY = 8;
28397
27445
  var init_audit = __esm(() => {
28398
27446
  init_builtin_policies();
28399
27447
  init_hooks_config();
@@ -28402,33 +27450,20 @@ var init_audit = __esm(() => {
28402
27450
  init_cli_adapters();
28403
27451
  init_detectors();
28404
27452
  init_features();
28405
- init_leak_scan();
28406
- init_leak_fingerprint();
28407
- init_leak_store();
28408
- init_redact_example();
28409
27453
  init_cache();
28410
27454
  init_replay();
28411
27455
  init_types2();
28412
- TRANSCRIPT_BYTE_BUDGET = 48 * 1024 * 1024;
28413
- CREDENTIAL_RESEARCH_MARKERS = [
28414
- /\b(?:secret|credential)[-_ ](?:scanner|detection|detector|pattern|regex|corpus)\b/i,
28415
- /\b(?:trufflehog|trufflesecurity|gitleaks|detect-secrets|secret-detection-rules)\b/i,
28416
- /\b(?:SECRET_PATTERNS|findSecrets|isDocsLiteral|leak-scan)\b/,
28417
- /\b(?:fixture|placeholder|synthetic|sample) (?:api )?(?:key|token|secret|credential)s?\b/i,
28418
- /\b(?:grep|rg|ripgrep|scan|hunt|search)\b[^\n]{0,240}\b(?:secret|credential|token)s?\b/i
28419
- ];
28420
- CREDENTIAL_RESEARCH_PURPOSE = /\b(?:hunt|scan|search|research|test)(?:ing)?\b[^\n]{0,80}\b(?:secret|credential|token)s?\b|\b(?:secret|credential|token)s?\b[^\n]{0,80}\b(?:scanner|detector|detection|research|fixtures?|corpus)\b/i;
28421
27456
  });
28422
27457
 
28423
27458
  // src/audit/audit-lock.ts
28424
27459
  import {
28425
27460
  closeSync as closeSync2,
28426
27461
  linkSync,
28427
- mkdirSync as mkdirSync22,
27462
+ mkdirSync as mkdirSync20,
28428
27463
  openSync as openSync2,
28429
- readFileSync as readFileSync28,
27464
+ readFileSync as readFileSync26,
28430
27465
  unlinkSync as unlinkSync4,
28431
- writeFileSync as writeFileSync19,
27466
+ writeFileSync as writeFileSync18,
28432
27467
  writeSync
28433
27468
  } from "node:fs";
28434
27469
  function acquireAuditLock(source, now = Date.now()) {
@@ -28487,7 +27522,7 @@ function handleFor(path, info) {
28487
27522
  }
28488
27523
  function readLock2(path) {
28489
27524
  try {
28490
- const parsed = JSON.parse(readFileSync28(path, "utf8"));
27525
+ const parsed = JSON.parse(readFileSync26(path, "utf8"));
28491
27526
  if (typeof parsed?.pid !== "number" || typeof parsed?.startedAt !== "number")
28492
27527
  return null;
28493
27528
  return {
@@ -28503,7 +27538,7 @@ function writeLockExclusive(path, info) {
28503
27538
  const body = JSON.stringify(info);
28504
27539
  const staging = `${path}.${process.pid}.tmp`;
28505
27540
  try {
28506
- writeFileSync19(staging, body, { mode: 384 });
27541
+ writeFileSync18(staging, body, { mode: 384 });
28507
27542
  } catch {
28508
27543
  return false;
28509
27544
  }
@@ -28537,8 +27572,8 @@ function createThenWrite(path, body) {
28537
27572
  }
28538
27573
  }
28539
27574
  function ensureRunDir() {
28540
- mkdirSync22(failproofaiHome(), { recursive: true });
28541
- mkdirSync22(runDir(), { recursive: true, mode: 448 });
27575
+ mkdirSync20(failproofaiHome(), { recursive: true });
27576
+ mkdirSync20(runDir(), { recursive: true, mode: 448 });
28542
27577
  }
28543
27578
  var AUDIT_LOCK_MAX_AGE_MS;
28544
27579
  var init_audit_lock = __esm(() => {
@@ -28547,7 +27582,7 @@ var init_audit_lock = __esm(() => {
28547
27582
  });
28548
27583
 
28549
27584
  // src/audit/dashboard-cache.ts
28550
- import { existsSync as existsSync33, readFileSync as readFileSync29 } from "node:fs";
27585
+ import { existsSync as existsSync31, readFileSync as readFileSync27 } from "node:fs";
28551
27586
  function getCachePath() {
28552
27587
  return auditDashboardFile();
28553
27588
  }
@@ -28567,10 +27602,10 @@ function writeDashboardCache(params, result) {
28567
27602
  }
28568
27603
  function readDashboardCacheMeta() {
28569
27604
  const cachePath = getCachePath();
28570
- if (!existsSync33(cachePath))
27605
+ if (!existsSync31(cachePath))
28571
27606
  return null;
28572
27607
  try {
28573
- const raw = readFileSync29(cachePath, "utf-8");
27608
+ const raw = readFileSync27(cachePath, "utf-8");
28574
27609
  const entry = JSON.parse(raw);
28575
27610
  if (!entry || entry.schemaVersion !== DASHBOARD_CACHE_SCHEMA_VERSION || typeof entry.cachedAt !== "string" || Number.isNaN(new Date(entry.cachedAt).getTime()))
28576
27611
  return null;
@@ -28794,18 +27829,18 @@ var init_api_server_client = __esm(() => {
28794
27829
  });
28795
27830
 
28796
27831
  // lib/auth/auth-store.ts
28797
- import { existsSync as existsSync34, readFileSync as readFileSync30, readdirSync as readdirSync18, rmSync as rmSync13 } from "node:fs";
28798
- import { join as join34, resolve as resolve24 } from "node:path";
27832
+ import { existsSync as existsSync32, readFileSync as readFileSync28, readdirSync as readdirSync17, rmSync as rmSync12 } from "node:fs";
27833
+ import { join as join34, resolve as resolve23 } from "node:path";
28799
27834
  function getAuthFilePath() {
28800
27835
  const override = process.env.FAILPROOFAI_AUTH_DIR;
28801
27836
  return override ? join34(override, "session.json") : auditSessionFile();
28802
27837
  }
28803
27838
  function readAuth() {
28804
27839
  const p = getAuthFilePath();
28805
- if (!existsSync34(p))
27840
+ if (!existsSync32(p))
28806
27841
  return null;
28807
27842
  try {
28808
- const raw = readFileSync30(p, "utf-8");
27843
+ const raw = readFileSync28(p, "utf-8");
28809
27844
  const parsed = JSON.parse(raw);
28810
27845
  if (typeof parsed.access_token !== "string" || typeof parsed.refresh_token !== "string" || typeof parsed.access_expires_at !== "number" || typeof parsed.user !== "object" || !parsed.user || typeof parsed.user.id !== "string" || typeof parsed.user.email !== "string") {
28811
27846
  return null;
@@ -28829,18 +27864,18 @@ function writeAuth(auth) {
28829
27864
  }
28830
27865
  function deleteAuth() {
28831
27866
  const p = getAuthFilePath();
28832
- if (existsSync34(p))
28833
- rmSync13(p, { force: true });
27867
+ if (existsSync32(p))
27868
+ rmSync12(p, { force: true });
28834
27869
  try {
28835
27870
  const root = migrationsDir();
28836
- if (!existsSync34(root))
27871
+ if (!existsSync32(root))
28837
27872
  return;
28838
- for (const entry of readdirSync18(root)) {
27873
+ for (const entry of readdirSync17(root)) {
28839
27874
  if (!entry.startsWith("backup-layout"))
28840
27875
  continue;
28841
- const copy = resolve24(root, entry, "auth.json");
28842
- if (existsSync34(copy))
28843
- rmSync13(copy, { force: true });
27876
+ const copy = resolve23(root, entry, "auth.json");
27877
+ if (existsSync32(copy))
27878
+ rmSync12(copy, { force: true });
28844
27879
  }
28845
27880
  } catch {}
28846
27881
  }
@@ -28900,6 +27935,112 @@ var init_auth_store = __esm(() => {
28900
27935
  inFlightRefreshes = new Map;
28901
27936
  });
28902
27937
 
27938
+ // src/audit/redact-example.ts
27939
+ import { homedir as homedir26 } from "node:os";
27940
+ function maskTruncatedSecret(input) {
27941
+ for (const [pattern, label] of SECRET_PREFIXES) {
27942
+ if (pattern.test(input)) {
27943
+ return input.replace(pattern, `[REDACTED: ${label}]`);
27944
+ }
27945
+ }
27946
+ return input;
27947
+ }
27948
+ function isSecretName(name) {
27949
+ const upper = name.toUpperCase();
27950
+ if (SECRET_NAME_SUBSTRINGS.some((word) => upper.includes(word)))
27951
+ return true;
27952
+ return upper.split("_").some((part) => SECRET_NAME_COMPONENTS.includes(part));
27953
+ }
27954
+ function maskAssignedSecrets(input) {
27955
+ let out = input.replace(ASSIGNMENT_RE, (match, name, value) => {
27956
+ if (!isSecretName(name))
27957
+ return match;
27958
+ if (value.startsWith("[REDACTED"))
27959
+ return match;
27960
+ return `${name}=[REDACTED: assigned secret]`;
27961
+ });
27962
+ out = out.replace(URL_CREDENTIALS_RE, "$1[REDACTED: URL credentials]@");
27963
+ out = out.replace(BASIC_AUTH_FLAG_RE, "$1[REDACTED: basic auth]");
27964
+ return out;
27965
+ }
27966
+ function maskSecrets(input) {
27967
+ let out = input;
27968
+ for (const [pattern, label] of SECRET_PATTERNS) {
27969
+ const global = new RegExp(pattern.source, pattern.flags.includes("g") ? pattern.flags : `${pattern.flags}g`);
27970
+ out = out.replace(global, `[REDACTED: ${label}]`);
27971
+ }
27972
+ return out;
27973
+ }
27974
+ function shortenPaths(input, home = homedir26()) {
27975
+ const homeRoot = home.replace(/\/+$/, "");
27976
+ return input.replace(ABSOLUTE_PATH_RE, (match, offset, whole) => {
27977
+ if (PUBLIC_PATH_ROOTS.some((root) => match.startsWith(root)))
27978
+ return match;
27979
+ if (offset > 0 && whole[offset - 1] === "/" && /[a-z][a-z0-9+.\-]*:$/i.test(whole.slice(0, offset - 1))) {
27980
+ const urlSegments = match.split("/").filter(Boolean);
27981
+ if (urlSegments.length <= 1)
27982
+ return match;
27983
+ const host = urlSegments[0];
27984
+ const leaf = urlSegments[urlSegments.length - 1];
27985
+ const elided = urlSegments.length > 2 ? "/…" : "";
27986
+ return `/${host}${elided}/${leaf}${match.endsWith("/") ? "/" : ""}`;
27987
+ }
27988
+ const trailingSlash = match.endsWith("/");
27989
+ const segments = match.split("/").filter(Boolean);
27990
+ if (segments.length === 0)
27991
+ return match;
27992
+ const basename = segments[segments.length - 1];
27993
+ const kept = segments.slice(Math.max(0, segments.length - 1 - KEPT_PARENT_SEGMENTS), segments.length - 1);
27994
+ const matchRoot = match.replace(/\/+$/, "");
27995
+ const underHome = homeRoot.length > 0 && (matchRoot === homeRoot || matchRoot.startsWith(`${homeRoot}/`));
27996
+ if (matchRoot === homeRoot && homeRoot.length > 0) {
27997
+ return trailingSlash ? "~/" : "~";
27998
+ }
27999
+ const root = underHome ? "~" : "";
28000
+ const middle = segments.length - kept.length - 1 > 0 ? "/…" : "";
28001
+ const tail = [...kept, basename].join("/");
28002
+ return `${root}${middle}/${tail}${trailingSlash ? "/" : ""}`;
28003
+ });
28004
+ }
28005
+ function redactExample(input, home = homedir26()) {
28006
+ const masked = maskAssignedSecrets(maskTruncatedSecret(maskSecrets(input)));
28007
+ const shortened = shortenPaths(masked, home);
28008
+ const collapsed = shortened.replace(/\s+/g, " ").trim();
28009
+ return collapsed.length > REDACTED_EXAMPLE_MAX_CHARS ? `${collapsed.slice(0, REDACTED_EXAMPLE_MAX_CHARS - 1)}…` : collapsed;
28010
+ }
28011
+ var REDACTED_EXAMPLE_MAX_CHARS = 160, KEPT_PARENT_SEGMENTS = 0, ABSOLUTE_PATH_RE, PUBLIC_PATH_ROOTS, SECRET_PREFIXES, SECRET_NAME_SUBSTRINGS, SECRET_NAME_COMPONENTS, ASSIGNMENT_RE, URL_CREDENTIALS_RE, BASIC_AUTH_FLAG_RE;
28012
+ var init_redact_example = __esm(() => {
28013
+ init_builtin_policies();
28014
+ ABSOLUTE_PATH_RE = /(?:\/[\w.\-@+]+){2,}\/?/g;
28015
+ PUBLIC_PATH_ROOTS = ["/dev/", "/proc/", "/sys/"];
28016
+ SECRET_PREFIXES = [
28017
+ [/(?<!\w)(?:Authorization:\s*)?Bearer\s+\S*$/i, "bearer token"],
28018
+ [/(?<!\w)sk-ant-\S*$/, "Anthropic API key"],
28019
+ [/(?<!\w)sk-proj-\S*$/, "OpenAI project API key"],
28020
+ [/(?<!\w)sk-\S*$/, "OpenAI API key"],
28021
+ [/(?<!\w)ghp_\S*$/, "GitHub personal access token"],
28022
+ [/(?<!\w)github_pat_\S*$/, "GitHub fine-grained token"],
28023
+ [/(?<!\w)AKIA\S*$/, "AWS access key ID"],
28024
+ [/(?<!\w)sk_live_\S*$/, "Stripe live secret key"],
28025
+ [/(?<!\w)sk_test_\S*$/, "Stripe test secret key"],
28026
+ [/(?<!\w)AIza\S*$/, "Google API key"],
28027
+ [/-----BEGIN\s[A-Z ]*$/, "private key"]
28028
+ ];
28029
+ SECRET_NAME_SUBSTRINGS = [
28030
+ "TOKEN",
28031
+ "SECRET",
28032
+ "PASSWORD",
28033
+ "PASSWD",
28034
+ "CREDENTIAL",
28035
+ "APIKEY",
28036
+ "PRIVATEKEY"
28037
+ ];
28038
+ SECRET_NAME_COMPONENTS = ["KEY", "PASS", "AUTH", "PAT", "SIG", "SIGNATURE", "SESSION", "COOKIE"];
28039
+ ASSIGNMENT_RE = /\b([A-Za-z_][A-Za-z0-9_]*)=("[^"]*"|'[^']*'|[^\s;|&"']+)/g;
28040
+ URL_CREDENTIALS_RE = /([a-z][a-z0-9+.\-]*:\/\/)[^\s/:@]+:[^\s/@]+@/gi;
28041
+ BASIC_AUTH_FLAG_RE = /((?:^|\s)(?:-u|--user)[\s=])\S+:\S+/g;
28042
+ });
28043
+
28903
28044
  // src/audit/harm-report.ts
28904
28045
  function shortName2(name) {
28905
28046
  const slash = name.indexOf("/");
@@ -28962,41 +28103,7 @@ function selectHarmful(result, from, to, opts = {}) {
28962
28103
  out.sort((a, b) => b.hits - a.hits);
28963
28104
  return out;
28964
28105
  }
28965
- function selectLeaks(findings, from, to) {
28966
- const lo = from.getTime();
28967
- const hi = to.getTime();
28968
- const out = [];
28969
- for (const f of findings) {
28970
- if (f.dismissedAt)
28971
- continue;
28972
- const last = ts(f.lastSeen);
28973
- if (last !== null && (last < lo || last > hi))
28974
- continue;
28975
- const seen = f.sightings?.reduce((latest, candidate) => {
28976
- if (!latest)
28977
- return candidate;
28978
- return (ts(candidate.at) ?? 0) >= (ts(latest.at) ?? 0) ? candidate : latest;
28979
- }, undefined);
28980
- out.push({
28981
- id: f.id,
28982
- display: f.fingerprint?.display ?? "[credential]",
28983
- label: f.fingerprint?.label ?? "secret",
28984
- length: f.fingerprint?.length ?? 0,
28985
- attributed: f.fingerprint?.attributed === true,
28986
- name: f.name,
28987
- confidence: f.confidence,
28988
- first_seen: f.firstSeen,
28989
- last_seen: f.lastSeen,
28990
- occurrences: f.occurrences,
28991
- cli: seen?.cli ?? "unknown",
28992
- project: seen?.cwd ?? "unknown",
28993
- mechanism: seen?.mechanism?.summary ?? "seen in a transcript",
28994
- direction: seen?.mechanism?.direction ?? "result"
28995
- });
28996
- }
28997
- return out.sort((a, b) => (ts(b.last_seen) ?? 0) - (ts(a.last_seen) ?? 0));
28998
- }
28999
- function buildHarmReport(result, lastReportedAt, intervalDays, leakFindings = []) {
28106
+ function buildHarmReport(result, lastReportedAt, intervalDays) {
29000
28107
  const to = new Date(Date.parse(result.scannedAt));
29001
28108
  const windowTo = Number.isFinite(to.getTime()) ? to : new Date;
29002
28109
  const watermark = ts(lastReportedAt);
@@ -29007,8 +28114,7 @@ function buildHarmReport(result, lastReportedAt, intervalDays, leakFindings = []
29007
28114
  return {
29008
28115
  window_from: from.toISOString(),
29009
28116
  window_to: windowTo.toISOString(),
29010
- harmful: selectHarmful(result, from, windowTo, { includeUnplaceable: isFirstReport }),
29011
- leaks: selectLeaks(leakFindings, from, windowTo).slice(0, 1)
28117
+ harmful: selectHarmful(result, from, windowTo, { includeUnplaceable: isFirstReport })
29012
28118
  };
29013
28119
  }
29014
28120
  var HARMFUL_SEVERITIES, ALSO_HARMFUL;
@@ -29019,15 +28125,15 @@ var init_harm_report = __esm(() => {
29019
28125
  });
29020
28126
 
29021
28127
  // src/audit/machine-store.ts
29022
- import { existsSync as existsSync35, readFileSync as readFileSync31, rmSync as rmSync14 } from "node:fs";
28128
+ import { existsSync as existsSync33, readFileSync as readFileSync29, rmSync as rmSync13 } from "node:fs";
29023
28129
  import { hostname as hostname5 } from "node:os";
29024
28130
  import { randomUUID as randomUUID4 } from "node:crypto";
29025
28131
  function readMachineIdentity(home) {
29026
28132
  const path = auditMachineFile(home);
29027
- if (!existsSync35(path))
28133
+ if (!existsSync33(path))
29028
28134
  return null;
29029
28135
  try {
29030
- const parsed = JSON.parse(readFileSync31(path, "utf8"));
28136
+ const parsed = JSON.parse(readFileSync29(path, "utf8"));
29031
28137
  if (typeof parsed.machine_id !== "string" || !parsed.machine_id)
29032
28138
  return null;
29033
28139
  return {
@@ -29073,20 +28179,20 @@ var init_machine_store = __esm(() => {
29073
28179
  // src/audit/report-harm.ts
29074
28180
  async function reportHarm(result) {
29075
28181
  let auto = false;
28182
+ let consentedAt;
29076
28183
  let intervalDays = 7;
29077
28184
  try {
29078
28185
  const config = readConfig();
29079
28186
  auto = config.audit.auto;
28187
+ consentedAt = config.audit.reportsConsentedAt;
29080
28188
  intervalDays = config.audit.intervalDays;
29081
28189
  } catch {
29082
28190
  return { kind: "disabled" };
29083
28191
  }
29084
28192
  if (!auto)
29085
28193
  return { kind: "disabled" };
29086
- const prior = readMachineIdentity();
29087
- const report = buildHarmReport(result, prior?.last_reported_at, intervalDays, activeFindings(readLeakRecord()));
29088
- if (report.leaks.length === 0)
29089
- return { kind: "no-leak" };
28194
+ if (consentedAt === undefined)
28195
+ return { kind: "consent-required" };
29090
28196
  const auth = await getValidAccessToken();
29091
28197
  if (!auth) {
29092
28198
  return { kind: "signed-out" };
@@ -29097,6 +28203,8 @@ async function reportHarm(result) {
29097
28203
  } catch (err) {
29098
28204
  return { kind: "failed", error: err instanceof Error ? err.message : String(err) };
29099
28205
  }
28206
+ const report = buildHarmReport(result, identity.last_reported_at, intervalDays);
28207
+ const hits = report.harmful.reduce((n, p) => n + p.hits, 0);
29100
28208
  try {
29101
28209
  const res = await submitAuditReport(auth.access_token, {
29102
28210
  machine_id: identity.machine_id,
@@ -29104,13 +28212,12 @@ async function reportHarm(result) {
29104
28212
  platform: process.platform,
29105
28213
  window_from: report.window_from,
29106
28214
  window_to: report.window_to,
29107
- harmful: report.harmful,
29108
- leaks: report.leaks
28215
+ harmful: report.harmful
29109
28216
  });
29110
28217
  try {
29111
28218
  recordReportWatermark(res.next_window_from);
29112
28219
  } catch {}
29113
- return res.emailed ? { kind: "sent", leaks: report.leaks.length } : { kind: "held", leaks: report.leaks.length, reason: res.reason ?? "not_sent" };
28220
+ return res.emailed ? { kind: "sent", hits } : { kind: "held", hits, reason: res.reason ?? "not_sent" };
29114
28221
  } catch (err) {
29115
28222
  const error = err instanceof AuthApiError ? `${err.code}: ${err.message}` : err instanceof Error ? err.message : String(err);
29116
28223
  return { kind: "failed", error };
@@ -29119,16 +28226,17 @@ async function reportHarm(result) {
29119
28226
  function describeOutcome2(outcome) {
29120
28227
  switch (outcome.kind) {
29121
28228
  case "disabled":
29122
- case "no-leak":
29123
28229
  return null;
28230
+ case "consent-required":
28231
+ return "failproofai: scheduled scans are on, but emailing what they find needs a fresh opt-in — run `failproofai audit --schedule` (or visit /settings) to turn digests on";
29124
28232
  case "signed-out":
29125
- return "failproofai: a credential exposure was found, but no email is configured — run `failproofai audit --schedule --email you@example.com`";
28233
+ return "failproofai: emailed reports are on but this machine is signed out — run `failproofai audit --schedule` or visit /settings to resume them";
29126
28234
  case "sent":
29127
- return "failproofai: emailed the most recent credential exposure";
28235
+ return `failproofai: emailed a harm digest (${outcome.hits} finding${outcome.hits === 1 ? "" : "s"})`;
29128
28236
  case "held":
29129
- return `failproofai: credential exposure reported, no email (${outcome.reason})`;
28237
+ return `failproofai: ${outcome.hits} finding${outcome.hits === 1 ? "" : "s"} reported, no email (${outcome.reason})`;
29130
28238
  case "failed":
29131
- return `failproofai: could not send the credential alert: ${outcome.error}`;
28239
+ return `failproofai: could not send the harm report: ${outcome.error}`;
29132
28240
  }
29133
28241
  }
29134
28242
  var init_report_harm = __esm(() => {
@@ -29136,281 +28244,9 @@ var init_report_harm = __esm(() => {
29136
28244
  init_api_server_client();
29137
28245
  init_fp_config();
29138
28246
  init_harm_report();
29139
- init_leak_store();
29140
28247
  init_machine_store();
29141
28248
  });
29142
28249
 
29143
- // src/audit/desktop-notify.ts
29144
- import { connect } from "node:net";
29145
-
29146
- class Marshal {
29147
- chunks = [];
29148
- len = 0;
29149
- align(n) {
29150
- const pad = (n - this.len % n) % n;
29151
- if (pad)
29152
- this.raw(Buffer.alloc(pad));
29153
- }
29154
- raw(b) {
29155
- this.chunks.push(b);
29156
- this.len += b.length;
29157
- }
29158
- byte(v) {
29159
- this.raw(Buffer.from([v]));
29160
- }
29161
- u32(v) {
29162
- this.align(4);
29163
- const b = Buffer.alloc(4);
29164
- b.writeUInt32LE(v, 0);
29165
- this.raw(b);
29166
- }
29167
- i32(v) {
29168
- this.align(4);
29169
- const b = Buffer.alloc(4);
29170
- b.writeInt32LE(v, 0);
29171
- this.raw(b);
29172
- }
29173
- str(v) {
29174
- const b = Buffer.from(v, "utf8");
29175
- this.u32(b.length);
29176
- this.raw(b);
29177
- this.byte(0);
29178
- }
29179
- sig(v) {
29180
- const b = Buffer.from(v, "utf8");
29181
- this.byte(b.length);
29182
- this.raw(b);
29183
- this.byte(0);
29184
- }
29185
- get length() {
29186
- return this.len;
29187
- }
29188
- buffer() {
29189
- return Buffer.concat(this.chunks);
29190
- }
29191
- }
29192
- function headerFields(fields) {
29193
- const m = new Marshal;
29194
- for (const [code, signature, value] of fields) {
29195
- m.align(8);
29196
- m.byte(code);
29197
- m.sig(signature);
29198
- if (signature === "g")
29199
- m.sig(value);
29200
- else
29201
- m.str(value);
29202
- }
29203
- return { data: m.buffer(), declaredLength: m.length };
29204
- }
29205
- function methodCall(serial, fields, body) {
29206
- const { data, declaredLength } = headerFields(fields);
29207
- const head = new Marshal;
29208
- head.raw(Buffer.from([108, 1, 0, 1]));
29209
- head.u32(body.length);
29210
- head.u32(serial);
29211
- head.u32(declaredLength);
29212
- head.raw(data);
29213
- head.align(8);
29214
- return Buffer.concat([head.buffer(), body]);
29215
- }
29216
- function notifyBody(app, replacesId, summary, body) {
29217
- const m = new Marshal;
29218
- m.str(app);
29219
- m.u32(replacesId);
29220
- m.str("");
29221
- m.str(summary);
29222
- m.str(body);
29223
- m.u32(0);
29224
- m.u32(0);
29225
- m.align(8);
29226
- m.i32(-1);
29227
- return m.buffer();
29228
- }
29229
- function readMessage(buf) {
29230
- if (buf.length < 16)
29231
- return null;
29232
- const bodyLength = buf.readUInt32LE(4);
29233
- const fieldsLength = buf.readUInt32LE(12);
29234
- const bodyStart = 16 + fieldsLength + (8 - fieldsLength % 8) % 8;
29235
- const total = bodyStart + bodyLength;
29236
- if (buf.length < total)
29237
- return null;
29238
- let replySerial = null;
29239
- let errorName = null;
29240
- let i = 16;
29241
- const end = 16 + fieldsLength;
29242
- while (i < end) {
29243
- i += (8 - (i - 16) % 8) % 8;
29244
- if (i + 4 > end)
29245
- break;
29246
- const code = buf[i];
29247
- const sigLen = buf[i + 1];
29248
- const sig = buf.toString("latin1", i + 2, i + 2 + sigLen);
29249
- i += 2 + sigLen + 1;
29250
- if (sig === "u") {
29251
- i += (4 - (i - 16) % 4) % 4;
29252
- if (i + 4 > end)
29253
- break;
29254
- if (code === 5)
29255
- replySerial = buf.readUInt32LE(i);
29256
- i += 4;
29257
- } else if (sig === "s" || sig === "o") {
29258
- i += (4 - (i - 16) % 4) % 4;
29259
- if (i + 4 > end)
29260
- break;
29261
- const len = buf.readUInt32LE(i);
29262
- if (i + 4 + len > end)
29263
- break;
29264
- if (code === 4)
29265
- errorName = buf.toString("utf8", i + 4, i + 4 + len);
29266
- i += 4 + len + 1;
29267
- } else if (sig === "g") {
29268
- const len = buf[i];
29269
- i += 1 + len + 1;
29270
- } else {
29271
- break;
29272
- }
29273
- }
29274
- return { type: buf[1], replySerial, errorName, bodyStart, bodyLength, total };
29275
- }
29276
- function resolveBusPath(env) {
29277
- const declared = env.DBUS_SESSION_BUS_ADDRESS;
29278
- if (declared) {
29279
- for (const part of declared.split(";")) {
29280
- const m = /^unix:(?:.*,)?path=([^,]+)/.exec(part.trim());
29281
- if (m)
29282
- return m[1];
29283
- }
29284
- }
29285
- const uid = typeof process.getuid === "function" ? process.getuid() : -1;
29286
- return uid >= 0 ? `/run/user/${uid}/bus` : null;
29287
- }
29288
- function notifyDesktop(summary, body, replacesId = 0, opts = {}) {
29289
- return new Promise((resolvePromise) => {
29290
- if (process.platform !== "linux" && !opts.socketPath) {
29291
- resolvePromise({ ok: false, reason: "error", detail: "linux only" });
29292
- return;
29293
- }
29294
- const uid = typeof process.getuid === "function" ? process.getuid() : -1;
29295
- const path = opts.socketPath ?? resolveBusPath(process.env);
29296
- if (!path || uid < 0) {
29297
- resolvePromise({ ok: false, reason: "no-session", detail: "no bus address" });
29298
- return;
29299
- }
29300
- let settled = false;
29301
- const done = (o) => {
29302
- if (settled)
29303
- return;
29304
- settled = true;
29305
- clearTimeout(timer);
29306
- try {
29307
- sock.destroy();
29308
- } catch {}
29309
- resolvePromise(o);
29310
- };
29311
- const timer = setTimeout(() => done({ ok: false, reason: "timeout", detail: `${TIMEOUT_MS}ms` }), TIMEOUT_MS);
29312
- let sock;
29313
- try {
29314
- sock = connect(path);
29315
- } catch (err) {
29316
- done({ ok: false, reason: "no-session", detail: String(err) });
29317
- return;
29318
- }
29319
- let stage = "auth";
29320
- let buf = Buffer.alloc(0);
29321
- sock.on("error", (err) => {
29322
- done({
29323
- ok: false,
29324
- reason: err.code === "ENOENT" || err.code === "ECONNREFUSED" ? "no-session" : "error",
29325
- detail: err.code ?? String(err)
29326
- });
29327
- });
29328
- sock.on("close", () => {
29329
- done({ ok: false, reason: "refused", detail: `bus closed the connection during ${stage}` });
29330
- });
29331
- sock.on("connect", () => {
29332
- const hexUid = Buffer.from(String(uid), "utf8").toString("hex");
29333
- sock.write(Buffer.concat([Buffer.from([0]), Buffer.from(`AUTH EXTERNAL ${hexUid}\r
29334
- `, "utf8")]));
29335
- });
29336
- sock.on("data", (chunk) => {
29337
- buf = Buffer.concat([buf, chunk]);
29338
- if (stage === "auth") {
29339
- const text = buf.toString("latin1");
29340
- const nl = text.indexOf(`\r
29341
- `);
29342
- if (nl === -1)
29343
- return;
29344
- if (!text.startsWith("OK")) {
29345
- done({ ok: false, reason: "refused", detail: text.slice(0, nl).trim().slice(0, 80) });
29346
- return;
29347
- }
29348
- buf = buf.subarray(nl + 2);
29349
- stage = "hello";
29350
- sock.write(Buffer.from(`BEGIN\r
29351
- `, "utf8"));
29352
- sock.write(methodCall(1, HELLO_FIELDS, Buffer.alloc(0)));
29353
- }
29354
- for (;; ) {
29355
- const msg = readMessage(buf);
29356
- if (!msg)
29357
- return;
29358
- const frame = buf.subarray(0, msg.total);
29359
- buf = buf.subarray(msg.total);
29360
- if (msg.type === 4 || msg.type === 1)
29361
- continue;
29362
- if (stage === "hello") {
29363
- if (msg.type === 3) {
29364
- done({ ok: false, reason: "refused", detail: msg.errorName ?? "Hello failed" });
29365
- return;
29366
- }
29367
- if (msg.replySerial !== 1)
29368
- continue;
29369
- stage = "notify";
29370
- sock.write(methodCall(2, NOTIFY_FIELDS, notifyBody("failproofai", replacesId, summary, body)));
29371
- continue;
29372
- }
29373
- if (msg.replySerial !== 2)
29374
- continue;
29375
- if (msg.type === 3) {
29376
- const name = msg.errorName ?? "";
29377
- const noServer = name.includes("ServiceUnknown") || name.includes("NameHasNoOwner");
29378
- done({ ok: false, reason: noServer ? "no-server" : "error", detail: name || "error" });
29379
- return;
29380
- }
29381
- const id = msg.bodyLength >= 4 && frame.length >= msg.bodyStart + 4 ? frame.readUInt32LE(msg.bodyStart) : 0;
29382
- done({ ok: true, id });
29383
- return;
29384
- }
29385
- });
29386
- });
29387
- }
29388
- var TIMEOUT_MS = 2000, HELLO_FIELDS, NOTIFY_FIELDS;
29389
- var init_desktop_notify = __esm(() => {
29390
- HELLO_FIELDS = [
29391
- [1, "o", "/org/freedesktop/DBus"],
29392
- [6, "s", "org.freedesktop.DBus"],
29393
- [2, "s", "org.freedesktop.DBus"],
29394
- [3, "s", "Hello"]
29395
- ];
29396
- NOTIFY_FIELDS = [
29397
- [1, "o", "/org/freedesktop/Notifications"],
29398
- [6, "s", "org.freedesktop.Notifications"],
29399
- [2, "s", "org.freedesktop.Notifications"],
29400
- [3, "s", "Notify"],
29401
- [8, "g", "susssasa{sv}i"]
29402
- ];
29403
- });
29404
-
29405
- // src/hooks/notice.ts
29406
- function desktopLeakNotice(email = "held") {
29407
- const followUp = email === "sent" ? "A masked alert was also sent to your email." : email === "missing" ? "Add email alerts with: failproofai audit --schedule --email you@example.com" : email === "failed" ? "Email delivery failed this time; the local result is still available." : "Email was not sent for this run.";
29408
- return {
29409
- title: "failproofai audit needs review",
29410
- body: "Possible credential exposure was found in your agent transcripts. " + `Run failproofai audit to verify the matches and rotate anything real. ${followUp}`
29411
- };
29412
- }
29413
-
29414
28250
  // src/audit/cli.ts
29415
28251
  function colorOn() {
29416
28252
  if (process.env.NO_COLOR && process.env.NO_COLOR !== "")
@@ -29601,10 +28437,6 @@ var init_cli = __esm(() => {
29601
28437
  init_telemetry_sanitize();
29602
28438
  init_open_browser();
29603
28439
  init_report_harm();
29604
- init_desktop_notify();
29605
- init_macos_notifier();
29606
- init_fp_config();
29607
- init_auth_store();
29608
28440
  init_tui();
29609
28441
  init_package();
29610
28442
  AUDIT_STAGES = [
@@ -29623,16 +28455,16 @@ var init_cli = __esm(() => {
29623
28455
  });
29624
28456
 
29625
28457
  // src/hooks/configure-wizard.ts
29626
- import { existsSync as existsSync36, mkdirSync as mkdirSync23, writeFileSync as writeFileSync20, readFileSync as readFileSync32 } from "node:fs";
29627
- import { homedir as homedir28 } from "node:os";
29628
- import { dirname as dirname17, resolve as resolve25, sep as sep5 } from "node:path";
28458
+ import { existsSync as existsSync34, mkdirSync as mkdirSync21, writeFileSync as writeFileSync19, readFileSync as readFileSync30 } from "node:fs";
28459
+ import { homedir as homedir27 } from "node:os";
28460
+ import { dirname as dirname16, resolve as resolve24, sep as sep5 } from "node:path";
29629
28461
  async function emit(event, props) {
29630
28462
  try {
29631
28463
  await trackHookEvent2(getInstanceId2(), event, props);
29632
28464
  } catch {}
29633
28465
  }
29634
28466
  function homeify(p) {
29635
- const home = homedir28();
28467
+ const home = homedir27();
29636
28468
  if (p === home)
29637
28469
  return "~";
29638
28470
  if (p.startsWith(home + sep5))
@@ -29648,8 +28480,8 @@ function setCustomPoliciesEnabled(scope, cwd, enabled) {
29648
28480
  const path = getConfigPathForScope(scope, cwd);
29649
28481
  let config = {};
29650
28482
  try {
29651
- if (existsSync36(path))
29652
- config = JSON.parse(readFileSync32(path, "utf8"));
28483
+ if (existsSync34(path))
28484
+ config = JSON.parse(readFileSync30(path, "utf8"));
29653
28485
  } catch {
29654
28486
  return;
29655
28487
  }
@@ -29658,7 +28490,7 @@ function setCustomPoliciesEnabled(scope, cwd, enabled) {
29658
28490
  else
29659
28491
  config.customPoliciesEnabled = false;
29660
28492
  try {
29661
- writeFileSync20(path, JSON.stringify(config, null, 2) + `
28493
+ writeFileSync19(path, JSON.stringify(config, null, 2) + `
29662
28494
  `, "utf8");
29663
28495
  } catch {}
29664
28496
  }
@@ -29689,7 +28521,7 @@ function describeCustomPolicies(cwd) {
29689
28521
  const scopes = [];
29690
28522
  let fileCount = 0;
29691
28523
  const dirs = [
29692
- { dir: resolve25(cwd, ".failproofai", "policies"), label: "project" },
28524
+ { dir: resolve24(cwd, ".failproofai", "policies"), label: "project" },
29693
28525
  { dir: customPoliciesDir(), label: "global" }
29694
28526
  ];
29695
28527
  for (const { dir, label } of dirs) {
@@ -29700,7 +28532,7 @@ function describeCustomPolicies(cwd) {
29700
28532
  fileCount += found.length;
29701
28533
  }
29702
28534
  for (const name of findSkippedPolicyFiles(dir)) {
29703
- warnings.push(`! ${homeify(resolve25(dir, name))} is NOT loaded — rename to ` + `${name.replace(/\.(js|mjs|ts)$/, "-policies.$1")}`);
28535
+ warnings.push(`! ${homeify(resolve24(dir, name))} is NOT loaded — rename to ` + `${name.replace(/\.(js|mjs|ts)$/, "-policies.$1")}`);
29704
28536
  }
29705
28537
  }
29706
28538
  return { active, warnings, fileCount, scopes };
@@ -29793,8 +28625,8 @@ function firstRunMarkerPath() {
29793
28625
  }
29794
28626
  function markLauncherSeen() {
29795
28627
  try {
29796
- mkdirSync23(dirname17(firstRunMarkerPath()), { recursive: true });
29797
- writeFileSync20(firstRunMarkerPath(), "1", "utf8");
28628
+ mkdirSync21(dirname16(firstRunMarkerPath()), { recursive: true });
28629
+ writeFileSync19(firstRunMarkerPath(), "1", "utf8");
29798
28630
  } catch {}
29799
28631
  }
29800
28632
  function retryProbe() {
@@ -29872,8 +28704,6 @@ async function runConfigureWizard(io = {}, answers = {}) {
29872
28704
  const cwd = process.cwd();
29873
28705
  const unattended = !stdin.isTTY || !stdout.isTTY;
29874
28706
  const preAnswered = Boolean(answers.token);
29875
- const initialAudit = readConfigRaw().raw.audit;
29876
- const hadExplicitAuditAuto = !!initialAudit && typeof initialAudit === "object" && !Array.isArray(initialAudit) && typeof initialAudit.auto === "boolean";
29877
28707
  if (typeof process.getuid === "function" && process.getuid() === 0 && process.env.SUDO_USER) {
29878
28708
  stdout.write(`Run failproofai config as ${process.env.SUDO_USER}, not under sudo.
29879
28709
  ` + `Everything it configures is per-user — hooks, policies and the daemon's own
@@ -30196,21 +29026,7 @@ Hooks keep enforcing; scheduled audits stay off until it is.
30196
29026
  }
30197
29027
  if (daemonInstalled) {
30198
29028
  setDaemonConfigured(true, version2);
30199
- if (!hadExplicitAuditAuto) {
30200
- try {
30201
- updateConfig({ audit: { auto: true } });
30202
- } catch {}
30203
- }
30204
29029
  pruneOldDaemonBinaries();
30205
- const notifier = installMacNotifier();
30206
- if (process.platform === "darwin" && !notifier.installed) {
30207
- hookLogWarn(`macOS notification helper was not installed: ${notifier.reason ?? "unknown error"}`);
30208
- stdout.write(`
30209
- System notifications could not be installed. Scheduled scans and email alerts
30210
- still work; re-run \`failproofai config\` after checking the local LaunchAgent.
30211
-
30212
- `);
30213
- }
30214
29030
  }
30215
29031
  const applied = emit("configure_applied", {
30216
29032
  target,
@@ -30288,7 +29104,6 @@ var init_configure_wizard = __esm(() => {
30288
29104
  init_hook_telemetry2();
30289
29105
  init_telemetry_id2();
30290
29106
  init_daemon_service();
30291
- init_macos_notifier();
30292
29107
  init_hook_logger();
30293
29108
  init_cloud_enrollment();
30294
29109
  init_cloud_connection();
@@ -30298,22 +29113,21 @@ var init_configure_wizard = __esm(() => {
30298
29113
  init_package();
30299
29114
  init_onboarding_attempt();
30300
29115
  init_onboarding_lock();
30301
- init_fp_config();
30302
29116
  POLICY_LIST_INDENT = " ".repeat(15);
30303
29117
  });
30304
29118
 
30305
29119
  // src/hooks/flush-cli.ts
30306
- import { existsSync as existsSync37, mkdirSync as mkdirSync24, writeFileSync as writeFileSync21, readdirSync as readdirSync19 } from "node:fs";
30307
- import { dirname as dirname18, join as join35 } from "node:path";
29120
+ import { existsSync as existsSync35, mkdirSync as mkdirSync22, writeFileSync as writeFileSync20, readdirSync as readdirSync18 } from "node:fs";
29121
+ import { dirname as dirname17, join as join35 } from "node:path";
30308
29122
  function flushRequestPath2(home) {
30309
29123
  return join35(failproofaiHome(home), "state", "flush-request.json");
30310
29124
  }
30311
29125
  function spoolDirs2(home) {
30312
29126
  const root = spoolDir(home);
30313
- if (!existsSync37(root))
29127
+ if (!existsSync35(root))
30314
29128
  return [];
30315
29129
  try {
30316
- return readdirSync19(root, { withFileTypes: true }).filter((e) => e.isDirectory() && e.name !== "failed").map((e) => join35(root, e.name));
29130
+ return readdirSync18(root, { withFileTypes: true }).filter((e) => e.isDirectory() && e.name !== "failed").map((e) => join35(root, e.name));
30317
29131
  } catch {
30318
29132
  return [];
30319
29133
  }
@@ -30322,7 +29136,7 @@ function pendingBatches2(home) {
30322
29136
  let n = 0;
30323
29137
  for (const dir of spoolDirs2(home)) {
30324
29138
  try {
30325
- n += readdirSync19(dir).filter((f) => f.endsWith(".jsonl")).length;
29139
+ n += readdirSync18(dir).filter((f) => f.endsWith(".jsonl")).length;
30326
29140
  } catch {}
30327
29141
  }
30328
29142
  return n;
@@ -30379,8 +29193,8 @@ async function runFlushCommand2(opts = {}) {
30379
29193
  return { exitCode: 0, pending: 0, lines: ["Nothing spooled — everything already delivered."] };
30380
29194
  }
30381
29195
  const path = flushRequestPath2(home);
30382
- mkdirSync24(dirname18(path), { recursive: true });
30383
- writeFileSync21(path, `${JSON.stringify({ requestedAtMs: Date.now() }, null, 2)}
29196
+ mkdirSync22(dirname17(path), { recursive: true });
29197
+ writeFileSync20(path, `${JSON.stringify({ requestedAtMs: Date.now() }, null, 2)}
30384
29198
  `, {
30385
29199
  mode: 384
30386
29200
  });
@@ -30411,8 +29225,8 @@ var init_flush_cli2 = __esm(() => {
30411
29225
  });
30412
29226
 
30413
29227
  // src/hooks/backfill-cli.ts
30414
- import { existsSync as existsSync38, mkdirSync as mkdirSync25, writeFileSync as writeFileSync22, readdirSync as readdirSync20, statSync as statSync23 } from "node:fs";
30415
- import { dirname as dirname19, join as join36 } from "node:path";
29228
+ import { existsSync as existsSync36, mkdirSync as mkdirSync23, writeFileSync as writeFileSync21, readdirSync as readdirSync19, statSync as statSync23 } from "node:fs";
29229
+ import { dirname as dirname18, join as join36 } from "node:path";
30416
29230
  function backfillRequestPath(home) {
30417
29231
  return join36(failproofaiHome(home), "state", "backfill-request.json");
30418
29232
  }
@@ -30420,7 +29234,7 @@ function surveySessions(sinceMs, homeDir) {
30420
29234
  const out = [];
30421
29235
  for (const { cli, dir } of SESSION_DIRS) {
30422
29236
  const root = join36(homeDir, dir);
30423
- if (!existsSync38(root))
29237
+ if (!existsSync36(root))
30424
29238
  continue;
30425
29239
  let files = 0;
30426
29240
  let newest = 0;
@@ -30429,7 +29243,7 @@ function surveySessions(sinceMs, homeDir) {
30429
29243
  return;
30430
29244
  let entries;
30431
29245
  try {
30432
- entries = readdirSync20(d, { withFileTypes: true });
29246
+ entries = readdirSync19(d, { withFileTypes: true });
30433
29247
  } catch {
30434
29248
  return;
30435
29249
  }
@@ -30458,7 +29272,7 @@ function runBackfillCommand(opts = {}) {
30458
29272
  const now = opts.now ?? Date.now();
30459
29273
  const sinceMs = opts.sinceMs ?? now - DEFAULT_BACKFILL_DAYS * 24 * 60 * 60 * 1000;
30460
29274
  const home = failproofaiHome();
30461
- if (!existsSync38(home)) {
29275
+ if (!existsSync36(home)) {
30462
29276
  return {
30463
29277
  exitCode: 1,
30464
29278
  lines: [`No failproofai home at ${home}. Run \`failproofai config\` first.`]
@@ -30490,7 +29304,7 @@ function runBackfillCommand(opts = {}) {
30490
29304
  ]
30491
29305
  };
30492
29306
  }
30493
- const found = surveySessions(sinceMs, dirname19(home));
29307
+ const found = surveySessions(sinceMs, dirname18(home));
30494
29308
  const totalFiles = found.reduce((n, f) => n + f.files, 0);
30495
29309
  const sinceLabel = new Date(sinceMs).toISOString().slice(0, 10);
30496
29310
  const lines = [
@@ -30513,8 +29327,8 @@ function runBackfillCommand(opts = {}) {
30513
29327
  }
30514
29328
  try {
30515
29329
  const path = backfillRequestPath();
30516
- mkdirSync25(dirname19(path), { recursive: true });
30517
- writeFileSync22(path, `${JSON.stringify({ sinceMs, requestedAtMs: now }, null, 2)}
29330
+ mkdirSync23(dirname18(path), { recursive: true });
29331
+ writeFileSync21(path, `${JSON.stringify({ sinceMs, requestedAtMs: now }, null, 2)}
30518
29332
  `, {
30519
29333
  mode: 384
30520
29334
  });
@@ -30556,8 +29370,8 @@ var init_backfill_cli = __esm(() => {
30556
29370
  });
30557
29371
 
30558
29372
  // src/hooks/harness-cli.ts
30559
- import { homedir as homedir29 } from "node:os";
30560
- import { resolve as resolve26 } from "node:path";
29373
+ import { homedir as homedir28 } from "node:os";
29374
+ import { resolve as resolve25 } from "node:path";
30561
29375
  function unknownHarness(name) {
30562
29376
  return fail([
30563
29377
  `Unknown harness: ${name}`,
@@ -30600,8 +29414,8 @@ function comparableLabel(raw) {
30600
29414
  return raw.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
30601
29415
  }
30602
29416
  function comparablePath(raw) {
30603
- const home = homedir29();
30604
- const expanded = raw === "~" ? home : raw.startsWith("~/") ? resolve26(home, raw.slice(2)) : raw;
29417
+ const home = homedir28();
29418
+ const expanded = raw === "~" ? home : raw.startsWith("~/") ? resolve25(home, raw.slice(2)) : raw;
30605
29419
  return expanded.replace(/\/+$/, "");
30606
29420
  }
30607
29421
  function effectiveLabel(entry) {
@@ -30789,7 +29603,7 @@ var init_harness_cli = __esm(() => {
30789
29603
  });
30790
29604
 
30791
29605
  // src/hooks/fp-config.ts
30792
- import { chmodSync as chmodSync7, existsSync as existsSync39, mkdirSync as mkdirSync26, readFileSync as readFileSync33, statSync as statSync24, writeFileSync as writeFileSync23 } from "node:fs";
29606
+ import { chmodSync as chmodSync6, existsSync as existsSync37, mkdirSync as mkdirSync24, readFileSync as readFileSync31, statSync as statSync24, writeFileSync as writeFileSync22 } from "node:fs";
30793
29607
  function detectLayout2() {
30794
29608
  const raw = readVersionFile2();
30795
29609
  if (raw) {
@@ -30797,17 +29611,17 @@ function detectLayout2() {
30797
29611
  return { kind: "current", version: raw };
30798
29612
  return raw.layout > LAYOUT_VERSION ? { kind: "future", found: raw.layout } : { kind: "stale", found: raw.layout };
30799
29613
  }
30800
- if (existsSync39(configFile())) {
29614
+ if (existsSync37(configFile())) {
30801
29615
  const layoutThreePositions = [
30802
29616
  legacy.authJson(),
30803
29617
  legacy.nextAudit(),
30804
29618
  legacy.auditSchedule()
30805
29619
  ];
30806
- if (layoutThreePositions.some((p) => existsSync39(p)))
29620
+ if (layoutThreePositions.some((p) => existsSync37(p)))
30807
29621
  return { kind: "stale", found: 3 };
30808
29622
  return { kind: "current", version: { layout: LAYOUT_VERSION, cli: "" }, inferred: true };
30809
29623
  }
30810
- if (existsSync39(legacy.configToml()))
29624
+ if (existsSync37(legacy.configToml()))
30811
29625
  return { kind: "stale", found: 2 };
30812
29626
  const layoutOneMarkers = [
30813
29627
  legacy.policyConfig(),
@@ -30818,7 +29632,7 @@ function detectLayout2() {
30818
29632
  legacy.ingestCredentials(),
30819
29633
  legacy.auditDashboard()
30820
29634
  ];
30821
- return layoutOneMarkers.some((p) => existsSync39(p)) ? { kind: "stale", found: 1 } : { kind: "absent" };
29635
+ return layoutOneMarkers.some((p) => existsSync37(p)) ? { kind: "stale", found: 1 } : { kind: "absent" };
30822
29636
  }
30823
29637
  function readLegacyTomlVersion2(text) {
30824
29638
  const layout = Number(/^\s*layout\s*=\s*(\d+)\s*$/m.exec(text)?.[1]);
@@ -30830,7 +29644,7 @@ function readLegacyTomlVersion2(text) {
30830
29644
  function readVersionFile2() {
30831
29645
  let text;
30832
29646
  try {
30833
- text = readFileSync33(versionFile(), "utf8");
29647
+ text = readFileSync31(versionFile(), "utf8");
30834
29648
  } catch {
30835
29649
  return null;
30836
29650
  }
@@ -30859,16 +29673,16 @@ var init_fp_home2 = () => {};
30859
29673
 
30860
29674
  // src/hooks/migrations.ts
30861
29675
  import {
30862
- chmodSync as chmodSync8,
29676
+ chmodSync as chmodSync7,
30863
29677
  copyFileSync as copyFileSync3,
30864
- existsSync as existsSync40,
30865
- mkdirSync as mkdirSync27,
30866
- readFileSync as readFileSync34,
30867
- renameSync as renameSync9,
30868
- rmSync as rmSync15,
30869
- writeFileSync as writeFileSync24
29678
+ existsSync as existsSync38,
29679
+ mkdirSync as mkdirSync25,
29680
+ readFileSync as readFileSync32,
29681
+ renameSync as renameSync8,
29682
+ rmSync as rmSync14,
29683
+ writeFileSync as writeFileSync23
30870
29684
  } from "node:fs";
30871
- import { basename as basename7, dirname as dirname20, join as join37, resolve as resolve27 } from "node:path";
29685
+ import { basename as basename7, dirname as dirname19, join as join37, resolve as resolve26 } from "node:path";
30872
29686
  function migrateToLayout42() {
30873
29687
  const moves = [
30874
29688
  { from: legacy.authJson(), to: auditSessionFile() },
@@ -30884,33 +29698,33 @@ function migrateToLayout42() {
30884
29698
  }
30885
29699
  const migrated = [];
30886
29700
  for (const { from, to } of moves) {
30887
- if (!existsSync40(from))
29701
+ if (!existsSync38(from))
30888
29702
  continue;
30889
- if (existsSync40(to)) {
30890
- rmSync15(from, { force: true });
29703
+ if (existsSync38(to)) {
29704
+ rmSync14(from, { force: true });
30891
29705
  continue;
30892
29706
  }
30893
- mkdirSync27(dirname20(to), { recursive: true });
29707
+ mkdirSync25(dirname19(to), { recursive: true });
30894
29708
  try {
30895
- renameSync9(from, to);
29709
+ renameSync8(from, to);
30896
29710
  } catch {
30897
29711
  try {
30898
29712
  copyFileSync3(from, to);
30899
29713
  } catch (err) {
30900
29714
  try {
30901
- rmSync15(to, { force: true });
29715
+ rmSync14(to, { force: true });
30902
29716
  } catch {}
30903
29717
  throw err;
30904
29718
  }
30905
- rmSync15(from, { force: true });
29719
+ rmSync14(from, { force: true });
30906
29720
  }
30907
29721
  migrated.push(`${basename7(from)} → audit/${basename7(to)}`);
30908
29722
  }
30909
29723
  for (const secret of [auditSessionFile()]) {
30910
- if (!existsSync40(secret))
29724
+ if (!existsSync38(secret))
30911
29725
  continue;
30912
29726
  try {
30913
- chmodSync8(secret, 384);
29727
+ chmodSync7(secret, 384);
30914
29728
  } catch {}
30915
29729
  }
30916
29730
  writeVersionFile({ layout: 4 });
@@ -30933,7 +29747,7 @@ function planMigration2(from, registry = MIGRATIONS2) {
30933
29747
  }
30934
29748
  function readLedger2() {
30935
29749
  try {
30936
- const parsed = JSON.parse(readFileSync34(migrationLedgerFile(), "utf8"));
29750
+ const parsed = JSON.parse(readFileSync32(migrationLedgerFile(), "utf8"));
30937
29751
  return Array.isArray(parsed) ? parsed : [];
30938
29752
  } catch {
30939
29753
  return [];
@@ -30941,9 +29755,9 @@ function readLedger2() {
30941
29755
  }
30942
29756
  function appendLedger2(entry) {
30943
29757
  try {
30944
- mkdirSync27(migrationsDir(), { recursive: true });
29758
+ mkdirSync25(migrationsDir(), { recursive: true });
30945
29759
  const all = [...readLedger2(), entry];
30946
- writeFileSync24(migrationLedgerFile(), `${JSON.stringify(all, null, 2)}
29760
+ writeFileSync23(migrationLedgerFile(), `${JSON.stringify(all, null, 2)}
30947
29761
  `, "utf8");
30948
29762
  } catch {}
30949
29763
  }
@@ -30955,12 +29769,12 @@ function pruneMigratedCredentials2(from) {
30955
29769
  for (let layout = from;layout < LAYOUT_VERSION; layout++) {
30956
29770
  for (const { as, landsAt } of PRUNED_AFTER_SUCCESS2) {
30957
29771
  try {
30958
- if (!existsSync40(landsAt()))
29772
+ if (!existsSync38(landsAt()))
30959
29773
  continue;
30960
- const copy = resolve27(migrationBackupDir(layout), as);
30961
- if (!existsSync40(copy))
29774
+ const copy = resolve26(migrationBackupDir(layout), as);
29775
+ if (!existsSync38(copy))
30962
29776
  continue;
30963
- rmSync15(copy, { force: true });
29777
+ rmSync14(copy, { force: true });
30964
29778
  pruned.push(as);
30965
29779
  } catch {}
30966
29780
  }
@@ -30971,7 +29785,7 @@ function filesToBackUp2() {
30971
29785
  const seen = new Map;
30972
29786
  for (const f of [...BACKED_UP2, ...BACKED_UP_LEGACY2]) {
30973
29787
  const path = f.at();
30974
- if (existsSync40(path))
29788
+ if (existsSync38(path))
30975
29789
  seen.set(path, backupNameOf2(f));
30976
29790
  }
30977
29791
  return [...seen].map(([path, as]) => ({ path, as }));
@@ -30980,14 +29794,14 @@ function backupBeforeMigrating2(from) {
30980
29794
  const dir = migrationBackupDir(from);
30981
29795
  const saved = [];
30982
29796
  try {
30983
- rmSync15(dir, { recursive: true, force: true });
30984
- mkdirSync27(dir, { recursive: true });
29797
+ rmSync14(dir, { recursive: true, force: true });
29798
+ mkdirSync25(dir, { recursive: true });
30985
29799
  } catch {
30986
29800
  return [];
30987
29801
  }
30988
29802
  for (const { path: source, as } of filesToBackUp2()) {
30989
29803
  try {
30990
- copyFileSync3(source, resolve27(dir, as));
29804
+ copyFileSync3(source, resolve26(dir, as));
30991
29805
  saved.push(as);
30992
29806
  } catch {}
30993
29807
  }
@@ -31125,17 +29939,17 @@ var init_migrations2 = __esm(() => {
31125
29939
 
31126
29940
  // src/hooks/daemon-service.ts
31127
29941
  import {
31128
- existsSync as existsSync41,
31129
- mkdirSync as mkdirSync28,
29942
+ existsSync as existsSync39,
29943
+ mkdirSync as mkdirSync26,
31130
29944
  mkdtempSync as mkdtempSync2,
31131
- readFileSync as readFileSync35,
31132
- writeFileSync as writeFileSync25,
29945
+ readFileSync as readFileSync33,
29946
+ writeFileSync as writeFileSync24,
31133
29947
  unlinkSync as unlinkSync5,
31134
- rmSync as rmSync16
29948
+ rmSync as rmSync15
31135
29949
  } from "node:fs";
31136
- import { homedir as homedir30, tmpdir as tmpdir3, userInfo as userInfo2 } from "node:os";
31137
- import { resolve as resolve28 } from "node:path";
31138
- import { execFileSync as execFileSync4 } from "node:child_process";
29950
+ import { homedir as homedir29, tmpdir as tmpdir3, userInfo as userInfo2 } from "node:os";
29951
+ import { resolve as resolve27 } from "node:path";
29952
+ import { execFileSync as execFileSync3 } from "node:child_process";
31139
29953
  function isDaemonSupportedPlatform2() {
31140
29954
  return process.platform === "linux" || process.platform === "darwin";
31141
29955
  }
@@ -31150,13 +29964,13 @@ function resolveFailproofaidBinaryPath2() {
31150
29964
  if (process.env.FAILPROOFAI_DAEMON_BINARY)
31151
29965
  return process.env.FAILPROOFAI_DAEMON_BINARY;
31152
29966
  const downloaded = installedBinaryPath();
31153
- if (existsSync41(downloaded))
29967
+ if (existsSync39(downloaded))
31154
29968
  return downloaded;
31155
29969
  const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT;
31156
29970
  if (packageRoot) {
31157
29971
  for (const profile of ["release", "debug"]) {
31158
- const candidate = resolve28(packageRoot, "target", profile, "failproofaid");
31159
- if (existsSync41(candidate))
29972
+ const candidate = resolve27(packageRoot, "target", profile, "failproofaid");
29973
+ if (existsSync39(candidate))
31160
29974
  return candidate;
31161
29975
  }
31162
29976
  }
@@ -31186,8 +30000,8 @@ function resolveWorkerCommand2() {
31186
30000
  const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT;
31187
30001
  if (!packageRoot)
31188
30002
  return null;
31189
- const workerScript = resolve28(packageRoot, "dist", "worker.mjs");
31190
- if (!existsSync41(workerScript))
30003
+ const workerScript = resolve27(packageRoot, "dist", "worker.mjs");
30004
+ if (!existsSync39(workerScript))
31191
30005
  return null;
31192
30006
  return `${shellQuote2(process.execPath)} ${shellQuote2(workerScript)}`;
31193
30007
  }
@@ -31197,8 +30011,8 @@ function resolveCliCommand2() {
31197
30011
  const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT;
31198
30012
  if (!packageRoot)
31199
30013
  return null;
31200
- const cliScript = resolve28(packageRoot, "dist", "cli.mjs");
31201
- if (!existsSync41(cliScript))
30014
+ const cliScript = resolve27(packageRoot, "dist", "cli.mjs");
30015
+ if (!existsSync39(cliScript))
31202
30016
  return null;
31203
30017
  return `${shellQuote2(process.execPath)} ${shellQuote2(cliScript)}`;
31204
30018
  }
@@ -31211,8 +30025,8 @@ function workerScriptPath2() {
31211
30025
  const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT;
31212
30026
  if (!packageRoot)
31213
30027
  return null;
31214
- const workerScript = resolve28(packageRoot, "dist", "worker.mjs");
31215
- return existsSync41(workerScript) ? workerScript : null;
30028
+ const workerScript = resolve27(packageRoot, "dist", "worker.mjs");
30029
+ return existsSync39(workerScript) ? workerScript : null;
31216
30030
  }
31217
30031
  function assertUnitSafe2(value, field) {
31218
30032
  if (UNIT_UNSAFE_RE2.test(value)) {
@@ -31238,10 +30052,10 @@ function systemdUnitDir2() {
31238
30052
  return process.env.FAILPROOFAI_SYSTEMD_DIR || "/etc/systemd/system";
31239
30053
  }
31240
30054
  function systemdUnitPath2(user = serviceUser2()) {
31241
- return resolve28(systemdUnitDir2(), systemdUnitName2(user));
30055
+ return resolve27(systemdUnitDir2(), systemdUnitName2(user));
31242
30056
  }
31243
30057
  function legacySystemdUserUnitPath2() {
31244
- return resolve28(homedir30(), ".config", "systemd", "user", "failproofaid.service");
30058
+ return resolve27(homedir29(), ".config", "systemd", "user", "failproofaid.service");
31245
30059
  }
31246
30060
  function launchdLabel2(user = serviceUser2()) {
31247
30061
  return `ai.failproof.failproofaid.${user}`;
@@ -31250,7 +30064,7 @@ function launchdPlistPath2(user = serviceUser2()) {
31250
30064
  return `/Library/LaunchDaemons/${launchdLabel2(user)}.plist`;
31251
30065
  }
31252
30066
  function legacyLaunchAgentPlistPath2() {
31253
- return resolve28(homedir30(), "Library", "LaunchAgents", "ai.failproof.failproofaid.plist");
30067
+ return resolve27(homedir29(), "Library", "LaunchAgents", "ai.failproof.failproofaid.plist");
31254
30068
  }
31255
30069
  function legacySharedLaunchDaemonPath2() {
31256
30070
  return "/Library/LaunchDaemons/ai.failproof.failproofaid.plist";
@@ -31266,7 +30080,7 @@ function primeElevation2() {
31266
30080
  if (canElevate2())
31267
30081
  return true;
31268
30082
  try {
31269
- execFileSync4("sudo", ["-v"], { stdio: "inherit", timeout: SUDO_PROMPT_TIMEOUT_MS2 });
30083
+ execFileSync3("sudo", ["-v"], { stdio: "inherit", timeout: SUDO_PROMPT_TIMEOUT_MS2 });
31270
30084
  return canElevate2();
31271
30085
  } catch {
31272
30086
  return false;
@@ -31276,7 +30090,7 @@ function canElevate2() {
31276
30090
  if (typeof process.getuid === "function" && process.getuid() === 0)
31277
30091
  return true;
31278
30092
  try {
31279
- execFileSync4("sudo", ["-n", "true"], { stdio: "ignore", timeout: SERVICE_CMD_TIMEOUT_MS2 });
30093
+ execFileSync3("sudo", ["-n", "true"], { stdio: "ignore", timeout: SERVICE_CMD_TIMEOUT_MS2 });
31280
30094
  return true;
31281
30095
  } catch {
31282
30096
  return false;
@@ -31285,42 +30099,42 @@ function canElevate2() {
31285
30099
  function runPrivileged2(command, args) {
31286
30100
  const root = typeof process.getuid === "function" && process.getuid() === 0;
31287
30101
  const [cmd, argv] = root ? [command, args] : ["sudo", ["-n", command, ...args]];
31288
- execFileSync4(cmd, argv, { stdio: "ignore", timeout: SERVICE_CMD_TIMEOUT_MS2 });
30102
+ execFileSync3(cmd, argv, { stdio: "ignore", timeout: SERVICE_CMD_TIMEOUT_MS2 });
31289
30103
  }
31290
30104
  function writePrivilegedFile2(destination, contents, mode = "0644") {
31291
- const stagingDir = mkdtempSync2(resolve28(tmpdir3(), "failproofaid-stage-"));
31292
- const staging = resolve28(stagingDir, "service-definition");
30105
+ const stagingDir = mkdtempSync2(resolve27(tmpdir3(), "failproofaid-stage-"));
30106
+ const staging = resolve27(stagingDir, "service-definition");
31293
30107
  try {
31294
- writeFileSync25(staging, contents, "utf8");
30108
+ writeFileSync24(staging, contents, "utf8");
31295
30109
  runPrivileged2("install", ["-m", mode, staging, destination]);
31296
30110
  } finally {
31297
- rmSync16(stagingDir, { recursive: true, force: true });
30111
+ rmSync15(stagingDir, { recursive: true, force: true });
31298
30112
  }
31299
30113
  }
31300
30114
  function removeLegacyUserService2() {
31301
30115
  try {
31302
30116
  if (process.platform === "linux") {
31303
30117
  const legacy = legacySystemdUserUnitPath2();
31304
- if (!existsSync41(legacy))
30118
+ if (!existsSync39(legacy))
31305
30119
  return;
31306
30120
  try {
31307
- execFileSync4("systemctl", ["--user", "disable", "--now", "failproofaid.service"], {
30121
+ execFileSync3("systemctl", ["--user", "disable", "--now", "failproofaid.service"], {
31308
30122
  stdio: "ignore",
31309
30123
  timeout: SERVICE_CMD_TIMEOUT_MS2
31310
30124
  });
31311
30125
  } catch {}
31312
30126
  unlinkSync5(legacy);
31313
30127
  try {
31314
- execFileSync4("systemctl", ["--user", "daemon-reload"], {
30128
+ execFileSync3("systemctl", ["--user", "daemon-reload"], {
31315
30129
  stdio: "ignore",
31316
30130
  timeout: SERVICE_CMD_TIMEOUT_MS2
31317
30131
  });
31318
30132
  } catch {}
31319
30133
  } else {
31320
30134
  const legacyAgent = legacyLaunchAgentPlistPath2();
31321
- if (existsSync41(legacyAgent)) {
30135
+ if (existsSync39(legacyAgent)) {
31322
30136
  try {
31323
- execFileSync4("launchctl", ["unload", "-w", legacyAgent], {
30137
+ execFileSync3("launchctl", ["unload", "-w", legacyAgent], {
31324
30138
  stdio: "ignore",
31325
30139
  timeout: SERVICE_CMD_TIMEOUT_MS2
31326
30140
  });
@@ -31328,7 +30142,7 @@ function removeLegacyUserService2() {
31328
30142
  unlinkSync5(legacyAgent);
31329
30143
  }
31330
30144
  const legacyDaemon = legacySharedLaunchDaemonPath2();
31331
- if (existsSync41(legacyDaemon)) {
30145
+ if (existsSync39(legacyDaemon)) {
31332
30146
  try {
31333
30147
  runPrivileged2("launchctl", ["unload", "-w", legacyDaemon]);
31334
30148
  } catch {}
@@ -31344,8 +30158,8 @@ function systemdUnitContents2(binaryPath, workerCmd, cliCmd = null) {
31344
30158
  `).join("");
31345
30159
  const user = assertUnitSafe2(serviceUser2(), "User");
31346
30160
  assertUnitSafe2(binaryPath, "ExecStart");
31347
- assertUnitSafe2(homedir30(), "HOME");
31348
- const conditionPaths = [binaryPath, workerScriptPath2()].filter((p) => typeof p === "string" && existsSync41(p));
30161
+ assertUnitSafe2(homedir29(), "HOME");
30162
+ const conditionPaths = [binaryPath, workerScriptPath2()].filter((p) => typeof p === "string" && existsSync39(p));
31349
30163
  const conditionLines = conditionPaths.map((p) => `ConditionPathExists=${assertUnitSafe2(p, "ConditionPathExists")}
31350
30164
  `).join("");
31351
30165
  return `[Unit]
@@ -31358,7 +30172,7 @@ User=${user}
31358
30172
  # Set explicitly rather than relying on systemd deriving it from User=:
31359
30173
  # failproofaid stores per-user state and refuses to start without HOME, so this
31360
30174
  # required variable is not left to a version-dependent default.
31361
- Environment="HOME=${homedir30()}"
30175
+ Environment="HOME=${homedir29()}"
31362
30176
  ${envLines}ExecStart=${binaryPath}
31363
30177
  Restart=on-failure
31364
30178
  RestartSec=2
@@ -31370,7 +30184,7 @@ RestartSec=2
31370
30184
  WantedBy=multi-user.target
31371
30185
  `;
31372
30186
  }
31373
- function escapeXml3(s) {
30187
+ function escapeXml2(s) {
31374
30188
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
31375
30189
  }
31376
30190
  function launchdPlistContents2(binaryPath, logDir, workerCmd, cliCmd = null) {
@@ -31378,7 +30192,7 @@ function launchdPlistContents2(binaryPath, logDir, workerCmd, cliCmd = null) {
31378
30192
  const envBlock = env.length ? ` <key>EnvironmentVariables</key>
31379
30193
  <dict>
31380
30194
  ${env.map(([key, value]) => ` <key>${key}</key>
31381
- <string>${escapeXml3(value)}</string>`).join(`
30195
+ <string>${escapeXml2(value)}</string>`).join(`
31382
30196
  `)}
31383
30197
  </dict>
31384
30198
  ` : "";
@@ -31387,10 +30201,10 @@ ${env.map(([key, value]) => ` <key>${key}</key>
31387
30201
  <plist version="1.0">
31388
30202
  <dict>
31389
30203
  <key>Label</key>
31390
- <string>${escapeXml3(launchdLabel2())}</string>
30204
+ <string>${escapeXml2(launchdLabel2())}</string>
31391
30205
  <key>ProgramArguments</key>
31392
30206
  <array>
31393
- <string>${escapeXml3(binaryPath)}</string>
30207
+ <string>${escapeXml2(binaryPath)}</string>
31394
30208
  </array>
31395
30209
  <key>RunAtLoad</key>
31396
30210
  <true/>
@@ -31401,11 +30215,11 @@ ${env.map(([key, value]) => ` <key>${key}</key>
31401
30215
  system, executed as the one user whose home, socket and lock it
31402
30216
  is allowed to touch. -->
31403
30217
  <key>UserName</key>
31404
- <string>${escapeXml3(serviceUser2())}</string>
30218
+ <string>${escapeXml2(serviceUser2())}</string>
31405
30219
  ${envBlock} <key>StandardOutPath</key>
31406
- <string>${escapeXml3(resolve28(logDir, "failproofaid.log"))}</string>
30220
+ <string>${escapeXml2(resolve27(logDir, "failproofaid.log"))}</string>
31407
30221
  <key>StandardErrorPath</key>
31408
- <string>${escapeXml3(resolve28(logDir, "failproofaid.err.log"))}</string>
30222
+ <string>${escapeXml2(resolve27(logDir, "failproofaid.err.log"))}</string>
31409
30223
  </dict>
31410
30224
  </plist>
31411
30225
  `;
@@ -31451,7 +30265,7 @@ async function installDaemonService2() {
31451
30265
  } else {
31452
30266
  const plistPath = launchdPlistPath2();
31453
30267
  const logDir = logsDir();
31454
- mkdirSync28(logDir, { recursive: true });
30268
+ mkdirSync26(logDir, { recursive: true });
31455
30269
  try {
31456
30270
  runPrivileged2("launchctl", ["unload", plistPath]);
31457
30271
  } catch {}
@@ -31538,7 +30352,7 @@ async function refreshDaemonToCliVersion(deps = {}) {
31538
30352
  }
31539
30353
  function inactiveLinuxStatus2() {
31540
30354
  try {
31541
- return interpretConditionResult2(execFileSync4("systemctl", ["show", systemdUnitName2(), "--property=ConditionResult", "--value"], { stdio: ["ignore", "pipe", "ignore"], timeout: SERVICE_CMD_TIMEOUT_MS2 }).toString());
30355
+ return interpretConditionResult2(execFileSync3("systemctl", ["show", systemdUnitName2(), "--property=ConditionResult", "--value"], { stdio: ["ignore", "pipe", "ignore"], timeout: SERVICE_CMD_TIMEOUT_MS2 }).toString());
31542
30356
  } catch {
31543
30357
  return "stopped";
31544
30358
  }
@@ -31550,10 +30364,10 @@ function daemonServiceStatus2() {
31550
30364
  if (!isDaemonSupportedPlatform2())
31551
30365
  return "unsupported-platform";
31552
30366
  if (process.platform === "linux") {
31553
- if (!existsSync41(systemdUnitPath2()))
30367
+ if (!existsSync39(systemdUnitPath2()))
31554
30368
  return "not-installed";
31555
30369
  try {
31556
- const out = execFileSync4("systemctl", ["is-active", systemdUnitName2()], {
30370
+ const out = execFileSync3("systemctl", ["is-active", systemdUnitName2()], {
31557
30371
  stdio: ["ignore", "pipe", "ignore"],
31558
30372
  timeout: SERVICE_CMD_TIMEOUT_MS2
31559
30373
  }).toString().trim();
@@ -31563,17 +30377,17 @@ function daemonServiceStatus2() {
31563
30377
  }
31564
30378
  }
31565
30379
  const plistPath = launchdPlistPath2();
31566
- if (!existsSync41(plistPath))
30380
+ if (!existsSync39(plistPath))
31567
30381
  return "not-installed";
31568
30382
  try {
31569
30383
  const root = typeof process.getuid === "function" && process.getuid() === 0;
31570
30384
  if (!root && !canElevate2())
31571
30385
  return "unknown";
31572
30386
  const args = ["print", `system/${launchdLabel2()}`];
31573
- const out = root ? execFileSync4("launchctl", args, {
30387
+ const out = root ? execFileSync3("launchctl", args, {
31574
30388
  stdio: ["ignore", "pipe", "ignore"],
31575
30389
  timeout: SERVICE_CMD_TIMEOUT_MS2
31576
- }).toString() : execFileSync4("sudo", ["-n", "launchctl", ...args], {
30390
+ }).toString() : execFileSync3("sudo", ["-n", "launchctl", ...args], {
31577
30391
  stdio: ["ignore", "pipe", "ignore"],
31578
30392
  timeout: SERVICE_CMD_TIMEOUT_MS2
31579
30393
  }).toString();
@@ -31593,7 +30407,7 @@ var init_daemon_service2 = __esm(() => {
31593
30407
  });
31594
30408
 
31595
30409
  // src/hooks/uninstall-cli.ts
31596
- import { existsSync as existsSync42, rmSync as rmSync17 } from "node:fs";
30410
+ import { existsSync as existsSync40, rmSync as rmSync16 } from "node:fs";
31597
30411
  function survey(cwd) {
31598
30412
  const clis = [];
31599
30413
  for (const id of listInstallableIds()) {
@@ -31614,9 +30428,9 @@ function survey(cwd) {
31614
30428
  return {
31615
30429
  clis,
31616
30430
  servicePath,
31617
- serviceInstalled: !!servicePath && existsSync42(servicePath),
30431
+ serviceInstalled: !!servicePath && existsSync40(servicePath),
31618
30432
  daemonConfigured,
31619
- homeExists: existsSync42(failproofaiHome())
30433
+ homeExists: existsSync40(failproofaiHome())
31620
30434
  };
31621
30435
  }
31622
30436
  async function runUninstallCommand(opts = {}) {
@@ -31645,7 +30459,6 @@ async function runUninstallCommand(opts = {}) {
31645
30459
  if (found.daemonConfigured) {
31646
30460
  plan.push(` • stop requiring the daemon (policies go back to evaluating in-process)`);
31647
30461
  }
31648
- let removeDaemon = opts.purge === true;
31649
30462
  if (found.serviceInstalled) {
31650
30463
  plan.push(opts.purge || opts.yes ? ` • stop, disable and delete the service at ${found.servicePath} — needs sudo` : ` • ask whether to remove the service at ${found.servicePath} (kept unless you say so)`);
31651
30464
  }
@@ -31705,7 +30518,7 @@ async function runUninstallCommand(opts = {}) {
31705
30518
  }
31706
30519
  }
31707
30520
  if (found.serviceInstalled) {
31708
- removeDaemon = opts.purge || opts.yes ? true : await opts.confirmDaemon?.() ?? false;
30521
+ const removeDaemon = opts.purge || opts.yes ? true : await opts.confirmDaemon?.() ?? false;
31709
30522
  if (!removeDaemon) {
31710
30523
  lines.push(`• kept the daemon service at ${found.servicePath}`, ` Remove it later with: failproofai uninstall --purge`);
31711
30524
  } else {
@@ -31715,7 +30528,7 @@ async function runUninstallCommand(opts = {}) {
31715
30528
  } catch {}
31716
30529
  try {
31717
30530
  await uninstallDaemonService();
31718
- if (found.servicePath && existsSync42(found.servicePath)) {
30531
+ if (found.servicePath && existsSync40(found.servicePath)) {
31719
30532
  failures.push(`the service at ${found.servicePath} is still there (most often: no sudo). ` + `Remove it with the commands below.`);
31720
30533
  } else {
31721
30534
  lines.push(`✓ stopped and removed the daemon service`);
@@ -31725,12 +30538,9 @@ async function runUninstallCommand(opts = {}) {
31725
30538
  }
31726
30539
  }
31727
30540
  }
31728
- if (opts.purge || removeDaemon) {
31729
- uninstallMacNotifier();
31730
- }
31731
30541
  if (opts.purge && found.homeExists) {
31732
30542
  try {
31733
- rmSync17(failproofaiHome(), { recursive: true, force: true });
30543
+ rmSync16(failproofaiHome(), { recursive: true, force: true });
31734
30544
  purged = true;
31735
30545
  lines.push(`✓ deleted ${failproofaiHome()}`);
31736
30546
  } catch (err) {
@@ -31741,7 +30551,7 @@ async function runUninstallCommand(opts = {}) {
31741
30551
  lines.push(``, `Not everything could be removed:`);
31742
30552
  for (const f of failures)
31743
30553
  lines.push(` ✗ ${f}`);
31744
- if (found.servicePath && existsSync42(found.servicePath)) {
30554
+ if (found.servicePath && existsSync40(found.servicePath)) {
31745
30555
  lines.push(``, `To remove the service by hand:`, ...manualServiceRemoval(found.servicePath), ``, `(\`${daemonStatusCommand()}\` shows its current state.)`);
31746
30556
  }
31747
30557
  return { exitCode: 1, lines, planLines, purged };
@@ -31769,15 +30579,14 @@ var init_uninstall_cli = __esm(() => {
31769
30579
  init_daemon_service();
31770
30580
  init_integrations();
31771
30581
  init_manager();
31772
- init_macos_notifier();
31773
30582
  });
31774
30583
 
31775
30584
  // src/hooks/pack-cli.ts
31776
- import { execFileSync as execFileSync5 } from "node:child_process";
31777
- import { homedir as homedir31, tmpdir as tmpdir4 } from "node:os";
30585
+ import { execFileSync as execFileSync4 } from "node:child_process";
30586
+ import { homedir as homedir30, tmpdir as tmpdir4 } from "node:os";
31778
30587
  import { createHash as createHash9 } from "node:crypto";
31779
- import { copyFileSync as copyFileSync4, existsSync as existsSync43, mkdirSync as mkdirSync29, mkdtempSync as mkdtempSync3, readFileSync as readFileSync36, readdirSync as readdirSync21, realpathSync as realpathSync3, rmSync as rmSync18, statSync as statSync25, writeFileSync as writeFileSync26 } from "node:fs";
31780
- import { basename as basename8, dirname as dirname21, isAbsolute as isAbsolute4, join as join38, relative as relative5, resolve as resolve29, sep as sep6 } from "node:path";
30588
+ import { copyFileSync as copyFileSync4, existsSync as existsSync41, mkdirSync as mkdirSync27, mkdtempSync as mkdtempSync3, readFileSync as readFileSync34, readdirSync as readdirSync20, realpathSync as realpathSync3, rmSync as rmSync17, statSync as statSync25, writeFileSync as writeFileSync25 } from "node:fs";
30589
+ import { basename as basename8, dirname as dirname20, isAbsolute as isAbsolute4, join as join38, relative as relative5, resolve as resolve28, sep as sep6 } from "node:path";
31781
30590
  function parseList(rest, flag) {
31782
30591
  const idx = rest.findIndex((a) => a === flag || a.startsWith(`${flag}=`));
31783
30592
  if (idx === -1)
@@ -31877,7 +30686,7 @@ async function build(rest) {
31877
30686
  const version = flag("version");
31878
30687
  const commit = flag("commit");
31879
30688
  const effect = flag("effect") ?? "enforce";
31880
- const outDir = resolve29(flag("out") ?? "dist-pack");
30689
+ const outDir = resolve28(flag("out") ?? "dist-pack");
31881
30690
  if (!entry || !id || !version) {
31882
30691
  return fail2([
31883
30692
  "Usage: failproofai publish <entry.mjs> --repo <owner>/<repo> --version <version>",
@@ -31890,10 +30699,10 @@ async function build(rest) {
31890
30699
  } catch (err) {
31891
30700
  return fail2([err instanceof Error ? err.message : String(err)]);
31892
30701
  }
31893
- const entryPath = resolve29(entry);
31894
- if (!existsSync43(entryPath))
30702
+ const entryPath = resolve28(entry);
30703
+ if (!existsSync41(entryPath))
31895
30704
  return fail2([`No such file: ${entryPath}`]);
31896
- const source = readFileSync36(entryPath, "utf8");
30705
+ const source = readFileSync34(entryPath, "utf8");
31897
30706
  const localImport = /(?:^|\n)\s*(?:import|export)[^;\n]*from\s+["'](\.[^"']*)["']/.exec(source);
31898
30707
  if (localImport) {
31899
30708
  return fail2([
@@ -31949,14 +30758,14 @@ async function build(rest) {
31949
30758
  policies
31950
30759
  }, null, 2) + `
31951
30760
  `;
31952
- mkdirSync29(outDir, { recursive: true });
31953
- const manifestPath = resolve29(outDir, PACK_MANIFEST_ASSET);
31954
- const entryOut = resolve29(outDir, PACK_ENTRY_ASSET);
31955
- writeFileSync26(manifestPath, manifest, "utf8");
30761
+ mkdirSync27(outDir, { recursive: true });
30762
+ const manifestPath = resolve28(outDir, PACK_MANIFEST_ASSET);
30763
+ const entryOut = resolve28(outDir, PACK_ENTRY_ASSET);
30764
+ writeFileSync25(manifestPath, manifest, "utf8");
31956
30765
  copyFileSync4(entryPath, entryOut);
31957
30766
  const sha = (bytes) => createHash9("sha256").update(bytes).digest("hex");
31958
- writeFileSync26(resolve29(outDir, PACK_CHECKSUMS_ASSET), `${sha(manifest)} ${PACK_MANIFEST_ASSET}
31959
- ${sha(readFileSync36(entryOut))} ${PACK_ENTRY_ASSET}
30767
+ writeFileSync25(resolve28(outDir, PACK_CHECKSUMS_ASSET), `${sha(manifest)} ${PACK_MANIFEST_ASSET}
30768
+ ${sha(readFileSync34(entryOut))} ${PACK_ENTRY_ASSET}
31960
30769
  `, "utf8");
31961
30770
  const on = policies.filter((p) => p.defaultEnabled).length;
31962
30771
  return ok2([
@@ -32085,12 +30894,12 @@ async function scaffold(target) {
32085
30894
  return ok2(["Nothing written."]);
32086
30895
  chosen = answer.trim();
32087
30896
  }
32088
- const path = resolve29(withPolicyExtension(chosen ?? "my-policies"));
32089
- if (existsSync43(path)) {
30897
+ const path = resolve28(withPolicyExtension(chosen ?? "my-policies"));
30898
+ if (existsSync41(path)) {
32090
30899
  return fail2([`${path} already exists — name a different file, or edit that one.`]);
32091
30900
  }
32092
- mkdirSync29(resolve29(path, ".."), { recursive: true });
32093
- writeFileSync26(path, `import { customPolicies, allow, deny } from "failproofai";
30901
+ mkdirSync27(resolve28(path, ".."), { recursive: true });
30902
+ writeFileSync25(path, `import { customPolicies, allow, deny } from "failproofai";
32094
30903
 
32095
30904
  // One file, no relative imports: only this entry is digest-pinned, so a pack
32096
30905
  // that imported siblings could not honestly claim to be verified.
@@ -32126,8 +30935,8 @@ customPolicies.add({
32126
30935
  }
32127
30936
  function inferRepo(entryPath) {
32128
30937
  try {
32129
- const url = execFileSync5("git", ["remote", "get-url", "origin"], {
32130
- cwd: resolve29(entryPath, ".."),
30938
+ const url = execFileSync4("git", ["remote", "get-url", "origin"], {
30939
+ cwd: resolve28(entryPath, ".."),
32131
30940
  encoding: "utf8",
32132
30941
  stdio: ["ignore", "pipe", "ignore"],
32133
30942
  timeout: 5000
@@ -32139,10 +30948,10 @@ function inferRepo(entryPath) {
32139
30948
  }
32140
30949
  }
32141
30950
  function inferCommit(entryPath, outDir, sources) {
32142
- const cwd = resolve29(entryPath, "..");
30951
+ const cwd = resolve28(entryPath, "..");
32143
30952
  const raw = (args) => {
32144
30953
  try {
32145
- return execFileSync5("git", args, {
30954
+ return execFileSync4("git", args, {
32146
30955
  cwd,
32147
30956
  encoding: "utf8",
32148
30957
  stdio: ["ignore", "pipe", "ignore"],
@@ -32194,9 +31003,9 @@ function realOrSelf(path) {
32194
31003
  }
32195
31004
  }
32196
31005
  function sourcesInHead(git, raw, sources) {
32197
- const paths = sources.map((f) => realOrSelf(resolve29(f)));
31006
+ const paths = sources.map((f) => realOrSelf(resolve28(f)));
32198
31007
  const shown = git(["rev-parse", "--show-toplevel"]);
32199
- const top = shown === null ? null : realOrSelf(resolve29(shown));
31008
+ const top = shown === null ? null : realOrSelf(resolve28(shown));
32200
31009
  const missing = [];
32201
31010
  for (const path of paths) {
32202
31011
  const rel = top ? relative5(top, path) : null;
@@ -32220,7 +31029,7 @@ function sourcesInHead(git, raw, sources) {
32220
31029
  ]);
32221
31030
  if (status === null)
32222
31031
  return { ok: false, offending: paths, why: "modified" };
32223
- const dirty = porcelainEntries(status).flatMap((entry) => [entry.path, entry.from].filter(Boolean).map((path) => resolve29(top ?? ".", path)));
31032
+ const dirty = porcelainEntries(status).flatMap((entry) => [entry.path, entry.from].filter(Boolean).map((path) => resolve28(top ?? ".", path)));
32224
31033
  if (dirty.length > 0)
32225
31034
  return { ok: false, offending: dirty, why: "modified" };
32226
31035
  return { ok: true };
@@ -32228,22 +31037,22 @@ function sourcesInHead(git, raw, sources) {
32228
31037
  function skipOutDir(git, entryPath, outDir) {
32229
31038
  if (!outDir)
32230
31039
  return [];
32231
- const out = resolve29(outDir);
32232
- if (resolve29(entryPath).startsWith(out + sep6))
31040
+ const out = resolve28(outDir);
31041
+ if (resolve28(entryPath).startsWith(out + sep6))
32233
31042
  return [];
32234
31043
  const top = git(["rev-parse", "--show-toplevel"]);
32235
31044
  if (!top)
32236
31045
  return [];
32237
- const rel = relative5(resolve29(top), out);
31046
+ const rel = relative5(resolve28(top), out);
32238
31047
  if (!rel || rel.startsWith("..") || isAbsolute4(rel))
32239
31048
  return [];
32240
31049
  return ["--", ":(top)", `:(exclude,literal,top)${rel.split(sep6).join("/")}`];
32241
31050
  }
32242
31051
  function inferTaggedVersion(entryPath, sources) {
32243
- const cwd = resolve29(entryPath, "..");
31052
+ const cwd = resolve28(entryPath, "..");
32244
31053
  const raw = (args) => {
32245
31054
  try {
32246
- return execFileSync5("git", args, {
31055
+ return execFileSync4("git", args, {
32247
31056
  cwd,
32248
31057
  encoding: "utf8",
32249
31058
  stdio: ["ignore", "pipe", "ignore"],
@@ -32270,7 +31079,7 @@ function inferTaggedVersion(entryPath, sources) {
32270
31079
  function findEntry(dir) {
32271
31080
  let names;
32272
31081
  try {
32273
- names = readdirSync21(dir);
31082
+ names = readdirSync20(dir);
32274
31083
  } catch {
32275
31084
  return [];
32276
31085
  }
@@ -32278,11 +31087,11 @@ function findEntry(dir) {
32278
31087
  for (const name of names) {
32279
31088
  if (!/\.(mjs|js|ts)$/.test(name))
32280
31089
  continue;
32281
- const full = resolve29(dir, name);
31090
+ const full = resolve28(dir, name);
32282
31091
  try {
32283
31092
  if (statSync25(full).size > 512 * 1024)
32284
31093
  continue;
32285
- const text = readFileSync36(full, "utf8");
31094
+ const text = readFileSync34(full, "utf8");
32286
31095
  if (/from\s+["']failproofai["']/.test(text) && /customPolicies\s*\.\s*add\s*\(/.test(text)) {
32287
31096
  found.push(full);
32288
31097
  }
@@ -32293,7 +31102,7 @@ function findEntry(dir) {
32293
31102
  return found.sort();
32294
31103
  }
32295
31104
  function withLocalImports(sources) {
32296
- const seen = new Set(sources.map((f) => resolve29(f)));
31105
+ const seen = new Set(sources.map((f) => resolve28(f)));
32297
31106
  const queue = [...seen];
32298
31107
  while (queue.length > 0 && seen.size < 500) {
32299
31108
  const file = queue.shift();
@@ -32301,13 +31110,13 @@ function withLocalImports(sources) {
32301
31110
  try {
32302
31111
  if (statSync25(file).size > 512 * 1024)
32303
31112
  continue;
32304
- text = readFileSync36(file, "utf8");
31113
+ text = readFileSync34(file, "utf8");
32305
31114
  } catch {
32306
31115
  continue;
32307
31116
  }
32308
31117
  for (const re of LOCAL_IMPORT_RES) {
32309
31118
  for (const match of text.matchAll(re)) {
32310
- const base = resolve29(dirname21(file), match[1]);
31119
+ const base = resolve28(dirname20(file), match[1]);
32311
31120
  for (const ext of LOCAL_IMPORT_EXTENSIONS) {
32312
31121
  const candidate = base + ext;
32313
31122
  if (seen.has(candidate))
@@ -32328,10 +31137,10 @@ function withLocalImports(sources) {
32328
31137
  return [...seen];
32329
31138
  }
32330
31139
  function settleGitState(entryPath, provenance, packFiles, id, outDir) {
32331
- const cwd = resolve29(entryPath, "..");
31140
+ const cwd = resolve28(entryPath, "..");
32332
31141
  const raw = (args) => {
32333
31142
  try {
32334
- return execFileSync5("git", args, {
31143
+ return execFileSync4("git", args, {
32335
31144
  cwd,
32336
31145
  encoding: "utf8",
32337
31146
  stdio: ["ignore", "pipe", "pipe"],
@@ -32403,11 +31212,11 @@ function settleGitState(entryPath, provenance, packFiles, id, outDir) {
32403
31212
  if (root === null || status === null)
32404
31213
  return null;
32405
31214
  const entries = porcelainEntries(status);
32406
- const dirty = entries.map((entry) => resolve29(root, entry.path));
32407
- const renamedFrom = entries.filter((entry) => entry.from).map((entry) => resolve29(root, entry.from));
31215
+ const dirty = entries.map((entry) => resolve28(root, entry.path));
31216
+ const renamedFrom = entries.filter((entry) => entry.from).map((entry) => resolve28(root, entry.from));
32408
31217
  if (dirty.length === 0)
32409
31218
  return null;
32410
- const mine = new Set(packFiles.map((f) => resolve29(f)));
31219
+ const mine = new Set(packFiles.map((f) => resolve28(f)));
32411
31220
  const foreign = dirty.filter((path) => !mine.has(path));
32412
31221
  const toStage = [...dirty, ...renamedFrom];
32413
31222
  if (foreign.length > 0) {
@@ -32524,7 +31333,7 @@ async function ensureRepo(owner, name, id, token, sourceDir) {
32524
31333
  function pushExistingHistory(dir, owner, name, token) {
32525
31334
  const git = (args, env) => {
32526
31335
  try {
32527
- return execFileSync5("git", args, {
31336
+ return execFileSync4("git", args, {
32528
31337
  cwd: dir,
32529
31338
  encoding: "utf8",
32530
31339
  stdio: ["ignore", "pipe", "ignore"],
@@ -32540,7 +31349,7 @@ function pushExistingHistory(dir, owner, name, token) {
32540
31349
  return false;
32541
31350
  const askpass = join38(mkdtempSync3(join38(tmpdir4(), "fpai-askpass-")), "askpass.sh");
32542
31351
  try {
32543
- writeFileSync26(askpass, `#!/bin/sh
31352
+ writeFileSync25(askpass, `#!/bin/sh
32544
31353
  case "$1" in
32545
31354
  *Username*) echo x-access-token ;;
32546
31355
  *) echo "$FPAI_GH_TOKEN" ;;
@@ -32560,7 +31369,7 @@ esac
32560
31369
  return true;
32561
31370
  } finally {
32562
31371
  try {
32563
- rmSync18(dirname21(askpass), { recursive: true, force: true });
31372
+ rmSync17(dirname20(askpass), { recursive: true, force: true });
32564
31373
  } catch {}
32565
31374
  }
32566
31375
  }
@@ -32584,14 +31393,14 @@ failproofai policies add ${owner}/${name}
32584
31393
  function findBun() {
32585
31394
  const candidates = [
32586
31395
  "bun",
32587
- process.env.BUN_INSTALL ? resolve29(process.env.BUN_INSTALL, "bin", "bun") : null,
32588
- resolve29(homedir31(), ".bun", "bin", "bun"),
31396
+ process.env.BUN_INSTALL ? resolve28(process.env.BUN_INSTALL, "bin", "bun") : null,
31397
+ resolve28(homedir30(), ".bun", "bin", "bun"),
32589
31398
  "/opt/homebrew/bin/bun",
32590
31399
  "/usr/local/bin/bun"
32591
31400
  ].filter((c) => c !== null);
32592
31401
  for (const candidate of candidates) {
32593
31402
  try {
32594
- execFileSync5(candidate, ["--version"], { stdio: "ignore", timeout: 5000 });
31403
+ execFileSync4(candidate, ["--version"], { stdio: "ignore", timeout: 5000 });
32595
31404
  return candidate;
32596
31405
  } catch {
32597
31406
  continue;
@@ -32611,14 +31420,14 @@ function bundleEntry(sources, outDir) {
32611
31420
  ]
32612
31421
  };
32613
31422
  }
32614
- mkdirSync29(outDir, { recursive: true });
32615
- const entry = resolve29(outDir, ".entry.generated.mjs");
32616
- writeFileSync26(entry, sources.map((f) => `import ${JSON.stringify(f.startsWith("/") ? f : resolve29(f))};`).join(`
31423
+ mkdirSync27(outDir, { recursive: true });
31424
+ const entry = resolve28(outDir, ".entry.generated.mjs");
31425
+ writeFileSync25(entry, sources.map((f) => `import ${JSON.stringify(f.startsWith("/") ? f : resolve28(f))};`).join(`
32617
31426
  `) + `
32618
31427
  `, "utf8");
32619
- const bundled = resolve29(outDir, ".bundled.mjs");
31428
+ const bundled = resolve28(outDir, ".bundled.mjs");
32620
31429
  try {
32621
- execFileSync5(bun, [
31430
+ execFileSync4(bun, [
32622
31431
  "build",
32623
31432
  "--target=node",
32624
31433
  "--format=esm",
@@ -32648,7 +31457,7 @@ function githubToken() {
32648
31457
  if (fromEnv)
32649
31458
  return fromEnv.trim();
32650
31459
  try {
32651
- const out = execFileSync5("gh", ["auth", "token"], {
31460
+ const out = execFileSync4("gh", ["auth", "token"], {
32652
31461
  encoding: "utf8",
32653
31462
  stdio: ["ignore", "pipe", "ignore"],
32654
31463
  timeout: 5000
@@ -32734,7 +31543,7 @@ async function publish(rest) {
32734
31543
  `);
32735
31544
  const token = githubToken();
32736
31545
  const login = token ? await credentialLogin(token) : null;
32737
- const folder = basename8(resolve29(entry, ".."));
31546
+ const folder = basename8(resolve28(entry, ".."));
32738
31547
  const answered = await askWhereToPublish(`${login ?? "your-account"}/${folder}`, { stdin: process.stdin, stdout: process.stdout });
32739
31548
  if (answered === null)
32740
31549
  return ok2(["Nothing was published."]);
@@ -32745,7 +31554,7 @@ async function publish(rest) {
32745
31554
  let versionFromSha = false;
32746
31555
  const dryRun = rest.includes("--dry-run") || !repo;
32747
31556
  const allowPrivate = rest.includes("--allow-private");
32748
- const id = flag("id") ?? repo ?? (dryRun && entry ? `local/${basename8(resolve29(entry, ".."))}` : undefined);
31557
+ const id = flag("id") ?? repo ?? (dryRun && entry ? `local/${basename8(resolve28(entry, ".."))}` : undefined);
32749
31558
  const [owner, name] = (repo ?? "/").split("/");
32750
31559
  if (repo && (!owner || !name || repo.split("/").length !== 2)) {
32751
31560
  return fail2([`--repo must be <owner>/<repo>, got ${JSON.stringify(repo)}`]);
@@ -32764,7 +31573,7 @@ async function publish(rest) {
32764
31573
  "With no --repo it writes the three release assets and stops."
32765
31574
  ]);
32766
31575
  }
32767
- const outDirEarly = resolve29(flag("out") ?? "dist-pack");
31576
+ const outDirEarly = resolve28(flag("out") ?? "dist-pack");
32768
31577
  let provenance = entry ? inferCommit(entry, outDirEarly, bundledSources) : null;
32769
31578
  const gitLines = [];
32770
31579
  if (!version && entry && interactive) {
@@ -32804,7 +31613,7 @@ async function publish(rest) {
32804
31613
  "It needs write access to releases on that repository, and nothing else."
32805
31614
  ]);
32806
31615
  }
32807
- const ensured = await ensureRepo(owner, name, id, token, resolve29(entry, ".."));
31616
+ const ensured = await ensureRepo(owner, name, id, token, resolve28(entry, ".."));
32808
31617
  if ("error" in ensured)
32809
31618
  return fail2(ensured.error);
32810
31619
  created = ensured.created;
@@ -32824,7 +31633,7 @@ async function publish(rest) {
32824
31633
  }
32825
31634
  const tag = flag("tag") ?? version;
32826
31635
  let entryToBuild = entry;
32827
- const needsBundle = discovered.length > 1 || /(?:^|\n)\s*(?:import|export)[^;\n]*from\s+["']\.[^"']*["']/.test(readFileSync36(entry, "utf8"));
31636
+ const needsBundle = discovered.length > 1 || /(?:^|\n)\s*(?:import|export)[^;\n]*from\s+["']\.[^"']*["']/.test(readFileSync34(entry, "utf8"));
32828
31637
  if (needsBundle) {
32829
31638
  const sources = discovered.length > 1 ? discovered : [entry];
32830
31639
  const bundled = bundleEntry(sources, outDirEarly);
@@ -32903,7 +31712,7 @@ async function publish(rest) {
32903
31712
  if (prior) {
32904
31713
  await gh(`${GITHUB_API2}/repos/${owner}/${name}/releases/assets/${prior.id}`, auth, { method: "DELETE" });
32905
31714
  }
32906
- const bytes = readFileSync36(resolve29(outDir, asset));
31715
+ const bytes = readFileSync34(resolve28(outDir, asset));
32907
31716
  const upload = await gh(`${GITHUB_UPLOADS2}/repos/${owner}/${name}/releases/${releaseId}/assets?name=${encodeURIComponent(asset)}`, auth, {
32908
31717
  method: "POST",
32909
31718
  contentType: asset.endsWith(".json") ? "application/json" : "application/octet-stream",
@@ -33584,8 +32393,8 @@ var init_install_prompt = __esm(() => {
33584
32393
 
33585
32394
  // src/hooks/manager.ts
33586
32395
  import { execSync as execSync7 } from "node:child_process";
33587
- import { existsSync as existsSync44 } from "node:fs";
33588
- import { resolve as resolve30, basename as basename9 } from "node:path";
32396
+ import { existsSync as existsSync42 } from "node:fs";
32397
+ import { resolve as resolve29, basename as basename9 } from "node:path";
33589
32398
  import { platform as platform4, arch as arch4, release as release3, hostname as hostname6 } from "node:os";
33590
32399
  function getSettingsPath2(scope, cwd) {
33591
32400
  return claudeCode.getSettingsPath(scope, cwd);
@@ -33804,9 +32613,9 @@ async function installHooksImpl2(policyNames, scope = "user", cwd, includeBeta =
33804
32613
  delete configToWrite.customPoliciesPath;
33805
32614
  delete configToWrite.customPoliciesPaths;
33806
32615
  } else if (customPoliciesPath && (typeof customPoliciesPath === "string" || customPoliciesPath.length > 0)) {
33807
- const incoming = (typeof customPoliciesPath === "string" ? [customPoliciesPath] : customPoliciesPath).map((path) => resolve30(path));
33808
- const carried = (previousConfig.customPoliciesPaths ?? (previousConfig.customPoliciesPath ? [previousConfig.customPoliciesPath] : [])).map((path) => resolve30(path)).filter((path) => {
33809
- if (existsSync44(path))
32616
+ const incoming = (typeof customPoliciesPath === "string" ? [customPoliciesPath] : customPoliciesPath).map((path) => resolve29(path));
32617
+ const carried = (previousConfig.customPoliciesPaths ?? (previousConfig.customPoliciesPath ? [previousConfig.customPoliciesPath] : [])).map((path) => resolve29(path)).filter((path) => {
32618
+ if (existsSync42(path))
33810
32619
  return true;
33811
32620
  console.log(`Dropping custom policies path (file no longer exists): ${path}`);
33812
32621
  return false;
@@ -34029,7 +32838,7 @@ async function removeHooks2(policyNames, scope = "user", cwd, opts) {
34029
32838
  const scopesToRemove = scope === "all" ? [...integration.scopes] : integration.scopes.includes(scope) ? [scope] : [];
34030
32839
  for (const s of scopesToRemove) {
34031
32840
  const settingsPaths = settingsPathsFor(integration, s, cwd);
34032
- const existing = settingsPaths.filter((p) => existsSync44(p));
32841
+ const existing = settingsPaths.filter((p) => existsSync42(p));
34033
32842
  if (existing.length === 0) {
34034
32843
  if (scope !== "all" && selectedClis.length === 1) {
34035
32844
  console.log("No settings file found. Nothing to remove.");
@@ -34173,9 +32982,9 @@ async function listHooks(cwd) {
34173
32982
  if (explicitPaths.length > 0) {
34174
32983
  groups.push(rule("Custom Policies", opts));
34175
32984
  for (const path of explicitPaths) {
34176
- const absPath = resolve30(findProjectConfigDir(cwd ?? process.cwd()), path);
32985
+ const absPath = resolve29(findProjectConfigDir(cwd ?? process.cwd()), path);
34177
32986
  groups.push(note(absPath, opts));
34178
- if (!existsSync44(absPath)) {
32987
+ if (!existsSync42(absPath)) {
34179
32988
  groups.push(warning([`file not found: ${absPath}`], opts));
34180
32989
  continue;
34181
32990
  }
@@ -34195,7 +33004,7 @@ async function listHooks(cwd) {
34195
33004
  }
34196
33005
  }
34197
33006
  const base = findProjectConfigDir(cwd ?? process.cwd());
34198
- const projectDir = resolve30(base, ".failproofai", "policies");
33007
+ const projectDir = resolve29(base, ".failproofai", "policies");
34199
33008
  const userDir = customPoliciesDir();
34200
33009
  const sameDir = userDir === projectDir;
34201
33010
  const conventionDirs = [
@@ -34307,11 +33116,11 @@ var init_manager2 = __esm(() => {
34307
33116
  });
34308
33117
 
34309
33118
  // src/audit/audit-schedule.ts
34310
- import { readFileSync as readFileSync37 } from "node:fs";
33119
+ import { readFileSync as readFileSync35 } from "node:fs";
34311
33120
  function readAuditSchedule(home) {
34312
33121
  let raw;
34313
33122
  try {
34314
- raw = readFileSync37(auditScheduleFile(home), "utf8");
33123
+ raw = readFileSync35(auditScheduleFile(home), "utf8");
34315
33124
  } catch {
34316
33125
  return null;
34317
33126
  }
@@ -34375,9 +33184,7 @@ async function ensureSignedIn(preset) {
34375
33184
  }
34376
33185
  if (!canPrompt()) {
34377
33186
  throw new LoginError(`Signing in needs an interactive terminal, and this one is not.
34378
- ` + "Run `failproofai audit --schedule` from a shell you are sitting at,\n" + `or sign in from the dashboard — both write the same session file.
34379
- ` + `
34380
- ` + "`--email` does not avoid this: it fills in the address so you are not\n" + "asked for it, but a one-time code is still sent there for you to paste.");
33187
+ ` + "Run `failproofai audit --schedule` from a shell you are sitting at,\n" + "or sign in from the dashboard — both write the same session file.");
34381
33188
  }
34382
33189
  return { user: await runLogin(preset), prompted: true };
34383
33190
  }
@@ -34501,20 +33308,21 @@ async function runScheduleOn(daysArg, emailArg) {
34501
33308
  if (bad)
34502
33309
  throw new ScheduleCliError(bad);
34503
33310
  }
34504
- const signedIn = emailArg === undefined ? { user: readAuth()?.user ?? null, prompted: false } : await ensureSignedIn(emailArg);
33311
+ const { user, prompted } = await ensureSignedIn(emailArg);
34505
33312
  const next = updateConfig({
34506
33313
  audit: {
34507
33314
  auto: true,
33315
+ reportsConsentedAt: Date.now(),
34508
33316
  ...days !== undefined ? { intervalDays: days } : {}
34509
33317
  }
34510
33318
  });
34511
33319
  const interval = next.audit.intervalDays;
34512
33320
  const summary = [
34513
- `every ${interval} day${interval === 1 ? "" : "s"} · desktop notification on leaks`,
34514
- signedIn.user ? `masked leak alerts also go to ${signedIn.user.email}` : "email is optional · add it with --email you@example.com",
34515
- "email contains only the most recent masked credential exposure"
33321
+ `every ${interval} day${interval === 1 ? "" : "s"} · reports to ${user.email}`,
33322
+ "you only hear from it when a scan finds something harmful",
33323
+ "each report sends: finding counts, redacted example commands, this machine's name"
34516
33324
  ];
34517
- if (signedIn.prompted) {
33325
+ if (prompted) {
34518
33326
  step("scheduled audits are on", summary);
34519
33327
  } else {
34520
33328
  process.stdout.write(`
@@ -34523,7 +33331,7 @@ ${green("✓")} ${bold("scheduled audits are on")}
34523
33331
  `).join(""));
34524
33332
  }
34525
33333
  warnIfDaemonWontRun();
34526
- if (signedIn.prompted) {
33334
+ if (prompted) {
34527
33335
  outro("failproofai audit --status · when the next scan is due");
34528
33336
  } else {
34529
33337
  process.stdout.write(dim(`
@@ -34569,13 +33377,14 @@ function runScheduleStatus() {
34569
33377
  on ? `${green("on")}${dim(` every ${config.audit.intervalDays} days`)}` : dim("off")
34570
33378
  ]);
34571
33379
  const live = auth && auth.refresh_expires_at * 1000 > Date.now() ? auth : null;
34572
- detail.push([
34573
- "leak notifications",
34574
- config.audit.notify ? green("on") : dim("off (failproofai audit --notify)")
34575
- ]);
34576
33380
  detail.push(["reports to", live ? live.user.email : dim("— signed out")]);
34577
33381
  if (on && !live) {
34578
- detail.push(["", pink("scans and desktop alerts continue; email alerts are paused")]);
33382
+ detail.push(["", pink("scans continue; digests are paused until you sign in")]);
33383
+ } else if (on && config.audit.reportsConsentedAt === undefined) {
33384
+ detail.push([
33385
+ "",
33386
+ pink("scans continue; digests need a fresh opt-in — run `--schedule` to turn them on")
33387
+ ]);
34579
33388
  }
34580
33389
  detail.push(["daemon", describeDaemon(daemon)]);
34581
33390
  if (sched?.nextDueAtMs != null && on) {
@@ -34659,22 +33468,6 @@ function agoPhrase(ms) {
34659
33468
  return `${m}m ago`;
34660
33469
  return "just now";
34661
33470
  }
34662
- function runNotifyToggle(enable) {
34663
- try {
34664
- updateConfig({ audit: { notify: enable } });
34665
- } catch (err) {
34666
- process.stderr.write(`Could not update the setting: ${err instanceof Error ? err.message : String(err)}
34667
- `);
34668
- process.exit(1);
34669
- }
34670
- process.stdout.write(enable ? `
34671
- ${green("on")} leak notifications — this machine will tell you when a scan finds a credential.
34672
-
34673
- ` : `
34674
- ${dim("off")} leak notifications — scans continue, and findings still appear in ` + `\`failproofai audit\` and the emailed digest.
34675
-
34676
- `);
34677
- }
34678
33471
  var MIN_DAYS = 1, MAX_DAYS = 90, ScheduleCliError, styled = () => colorsEnabled(process.stdout), wrap3 = (open, s) => styled() ? `${open}${s}${ANSI_RESET}` : s, pink = (s) => wrap3(brandAnsi("pink"), s), green = (s) => wrap3(brandAnsi("guide"), s), dim = (s) => wrap3(ANSI_DIM, s), bold = (s) => wrap3(ANSI_BOLD, s);
34679
33472
  var init_schedule_cli = __esm(() => {
34680
33473
  init_fp_config();
@@ -34690,14 +33483,14 @@ var init_schedule_cli = __esm(() => {
34690
33483
  });
34691
33484
 
34692
33485
  // scripts/parse-script-args.ts
34693
- import { resolve as resolve31 } from "path";
33486
+ import { resolve as resolve30 } from "path";
34694
33487
  function parseStringFlag(flagName, errorLabel, inlineValue, args, index, options) {
34695
33488
  const raw = inlineValue ?? args[index + 1];
34696
33489
  if (raw === undefined || inlineValue === null && raw.startsWith("-")) {
34697
33490
  console.error(`Error: ${flagName} requires ${errorLabel}`);
34698
33491
  process.exit(1);
34699
33492
  }
34700
- const value = options?.resolve ? resolve31(raw) : raw;
33493
+ const value = options?.resolve ? resolve30(raw) : raw;
34701
33494
  return { value, spliceCount: inlineValue !== null ? 1 : 2 };
34702
33495
  }
34703
33496
  function parseScriptArgs(argv) {
@@ -34753,26 +33546,26 @@ function parseScriptArgs(argv) {
34753
33546
  var init_parse_script_args = () => {};
34754
33547
 
34755
33548
  // scripts/install-diagnosis.mjs
34756
- import { existsSync as existsSync45, readFileSync as readFileSync38, realpathSync as realpathSync4 } from "node:fs";
34757
- import { dirname as dirname22, resolve as resolve32 } from "node:path";
34758
- import { homedir as homedir32, platform as platform5 } from "node:os";
33549
+ import { existsSync as existsSync43, readFileSync as readFileSync36, realpathSync as realpathSync4 } from "node:fs";
33550
+ import { dirname as dirname21, resolve as resolve31 } from "node:path";
33551
+ import { homedir as homedir31, platform as platform5 } from "node:os";
34759
33552
  import { spawnSync } from "node:child_process";
34760
33553
  function findPackageRoot(start) {
34761
33554
  try {
34762
33555
  let dir = realpathSync4(start);
34763
- if (existsSync45(dir) && !existsSync45(resolve32(dir, "package.json"))) {
34764
- dir = dirname22(dir);
33556
+ if (existsSync43(dir) && !existsSync43(resolve31(dir, "package.json"))) {
33557
+ dir = dirname21(dir);
34765
33558
  }
34766
33559
  while (true) {
34767
- const pkgPath = resolve32(dir, "package.json");
34768
- if (existsSync45(pkgPath)) {
33560
+ const pkgPath = resolve31(dir, "package.json");
33561
+ if (existsSync43(pkgPath)) {
34769
33562
  try {
34770
- const pkg = JSON.parse(readFileSync38(pkgPath, "utf8"));
33563
+ const pkg = JSON.parse(readFileSync36(pkgPath, "utf8"));
34771
33564
  if (pkg.name === PKG_NAME)
34772
33565
  return dir;
34773
33566
  } catch {}
34774
33567
  }
34775
- const parent = dirname22(dir);
33568
+ const parent = dirname21(dir);
34776
33569
  if (parent === dir)
34777
33570
  return null;
34778
33571
  dir = parent;
@@ -34785,7 +33578,7 @@ function readPackageVersion(packageRoot) {
34785
33578
  if (!packageRoot)
34786
33579
  return null;
34787
33580
  try {
34788
- const pkg = JSON.parse(readFileSync38(resolve32(packageRoot, "package.json"), "utf8"));
33581
+ const pkg = JSON.parse(readFileSync36(resolve31(packageRoot, "package.json"), "utf8"));
34789
33582
  return typeof pkg.version === "string" ? pkg.version : null;
34790
33583
  } catch {
34791
33584
  return null;
@@ -34811,16 +33604,16 @@ function locateNpmGlobal() {
34811
33604
  const root = (res.stdout || "").trim();
34812
33605
  if (!root)
34813
33606
  return null;
34814
- const candidate = resolve32(root, PKG_NAME);
34815
- return existsSync45(resolve32(candidate, "package.json")) ? candidate : null;
33607
+ const candidate = resolve31(root, PKG_NAME);
33608
+ return existsSync43(resolve31(candidate, "package.json")) ? candidate : null;
34816
33609
  } catch {
34817
33610
  return null;
34818
33611
  }
34819
33612
  }
34820
33613
  function locateBunGlobal() {
34821
33614
  try {
34822
- const candidate = resolve32(homedir32(), ".bun", "install", "global", "node_modules", PKG_NAME);
34823
- return existsSync45(resolve32(candidate, "package.json")) ? candidate : null;
33615
+ const candidate = resolve31(homedir31(), ".bun", "install", "global", "node_modules", PKG_NAME);
33616
+ return existsSync43(resolve31(candidate, "package.json")) ? candidate : null;
34824
33617
  } catch {
34825
33618
  return null;
34826
33619
  }
@@ -34828,8 +33621,8 @@ function locateBunGlobal() {
34828
33621
  function buildRecommendation(pathFirstBin) {
34829
33622
  if (!pathFirstBin)
34830
33623
  return null;
34831
- const bunBinPrefix = resolve32(homedir32(), ".bun", "bin") + "/";
34832
- const bunGlobalPrefix = resolve32(homedir32(), ".bun", "install", "global") + "/";
33624
+ const bunBinPrefix = resolve31(homedir31(), ".bun", "bin") + "/";
33625
+ const bunGlobalPrefix = resolve31(homedir31(), ".bun", "install", "global") + "/";
34833
33626
  const isBun = pathFirstBin.startsWith(bunBinPrefix) || pathFirstBin.startsWith(bunGlobalPrefix);
34834
33627
  if (isBun) {
34835
33628
  return `rm -f ~/.bun/bin/${PKG_NAME} && rm -rf ~/.bun/install/global/node_modules/${PKG_NAME}`;
@@ -34923,8 +33716,8 @@ var init_dashboard_host = __esm(() => {
34923
33716
 
34924
33717
  // scripts/launch.ts
34925
33718
  import { spawn as spawn2 } from "child_process";
34926
- import { realpathSync as realpathSync5, existsSync as existsSync46 } from "node:fs";
34927
- import { resolve as resolve33, dirname as dirname23 } from "node:path";
33719
+ import { realpathSync as realpathSync5, existsSync as existsSync44 } from "node:fs";
33720
+ import { resolve as resolve32, dirname as dirname22 } from "node:path";
34928
33721
  import { fileURLToPath as fileURLToPath2 } from "node:url";
34929
33722
  import { createInterface } from "node:readline";
34930
33723
  function launch(mode) {
@@ -34948,9 +33741,9 @@ function launch(mode) {
34948
33741
  process.env.PORT = port;
34949
33742
  process.env.HOSTNAME = bindHost;
34950
33743
  cmd = "node";
34951
- const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT ?? resolve33(dirname23(realpathSync5(fileURLToPath2(import.meta.url))), "..");
34952
- const serverJsPath = resolve33(packageRoot, ".next/standalone/server.js");
34953
- if (!existsSync46(serverJsPath)) {
33744
+ const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT ?? resolve32(dirname22(realpathSync5(fileURLToPath2(import.meta.url))), "..");
33745
+ const serverJsPath = resolve32(packageRoot, ".next/standalone/server.js");
33746
+ if (!existsSync44(serverJsPath)) {
34954
33747
  let shadowMessage = null;
34955
33748
  try {
34956
33749
  const diag = diagnoseShadow({ selfPackageRoot: packageRoot, selfVersion: version2 });
@@ -35033,27 +33826,21 @@ function helpText() {
35033
33826
  const lines = helpScreen({
35034
33827
  command: "audit",
35035
33828
  version: version2,
35036
- tagline: "find credentials your agents leaked into their own transcripts",
33829
+ tagline: "review your agent CLIs for risky and wasteful patterns",
35037
33830
  sections: [
35038
33831
  {
35039
33832
  label: "usage",
35040
33833
  entries: [
35041
- ["(bare)", `Scan your session history for leaked keys, then open http://localhost:${DASHBOARD_PORT}/audit`],
35042
- ["--schedule [days]", "Scan on a timer and notify you on this machine. Default 7 days, range 1-90. No account required."],
35043
- ["--email <address>", "With --schedule, add email alerts for the most recent masked credential leak. A sign-in code is emailed to you."],
33834
+ ["(bare)", `Scan your session history, then open http://localhost:${DASHBOARD_PORT}/audit`],
33835
+ ["--schedule [days]", "Scan on a timer and email the findings. Default 7 days, range 1-90. Signs you in the first time."],
33836
+ ["--email <address>", "With --schedule, skips the sign-in prompt."],
35044
33837
  ["--no-schedule", "Stop the timer. Leaves you signed in."],
35045
- ["--notify", "Show a desktop notification when a scan finds a credential. On by default."],
35046
- ["--no-notify", "Stop desktop notifications. Scheduled scans and optional email alerts are unaffected."],
35047
33838
  ["--status", "Whether scheduling is on, where reports go, the daemon's state, and when the next scan is due."],
35048
33839
  ["-h, --help", "Show this help."]
35049
33840
  ]
35050
33841
  }
35051
33842
  ],
35052
- footer: [
35053
- "Every scan runs on this machine. Leak alerts appear as desktop system",
35054
- "notifications, never inside agent sessions. If you add email, only the",
35055
- "newest masked credential exposure and its metadata leave the machine."
35056
- ]
33843
+ footer: ["Everything runs on this machine; only a scheduled digest ever leaves it."]
35057
33844
  }, helpOptsFor(process.stdout));
35058
33845
  return ["", ...lines, ""].join(`
35059
33846
  `) + `
@@ -35202,40 +33989,6 @@ function heldByLine(held) {
35202
33989
  const ageS = Math.max(0, Math.round((Date.now() - held.startedAt) / 1000));
35203
33990
  return `another audit is already running (pid ${held.pid}, started by ${held.source} ${ageS}s ago)`;
35204
33991
  }
35205
- async function announceLeaksOnDesktop(result, report) {
35206
- try {
35207
- await announceLeaksOrThrow(result, report);
35208
- } catch (err) {
35209
- process.stderr.write(`failproofai: could not announce a leak on the desktop: ` + `${err instanceof Error ? err.message : String(err)}
35210
- `);
35211
- }
35212
- }
35213
- async function announceLeaksOrThrow(result, report) {
35214
- const ids = result.leakIds ?? result.newLeakIds ?? [];
35215
- if (ids.length === 0)
35216
- return;
35217
- if (!readConfig().audit.notify)
35218
- return;
35219
- const n = ids.length === 1 ? "a possible credential exposure" : `${ids.length} possible credential exposures`;
35220
- const emailState = report.kind === "sent" ? "sent" : report.kind === "signed-out" || !readAuth() ? "missing" : report.kind === "failed" ? "failed" : "held";
35221
- const { title, body } = desktopLeakNotice(emailState);
35222
- if (process.platform === "darwin") {
35223
- pruneMacNotifyQueue();
35224
- if (!queueMacNotification(ids[0], title, body)) {
35225
- process.stderr.write(`failproofai: found ${n} but could not queue a notification
35226
- `);
35227
- } else if (!macNotifierInstalled()) {
35228
- process.stderr.write(`failproofai: found ${n}; the notifier is not installed, so nothing will show it ` + `(run \`failproofai config\`)
35229
- `);
35230
- }
35231
- return;
35232
- }
35233
- const outcome = await notifyDesktop(title, body, 0);
35234
- if (!outcome.ok) {
35235
- process.stderr.write(`failproofai: found ${n} but could not raise a desktop notification (${outcome.reason})
35236
- `);
35237
- }
35238
- }
35239
33992
  async function runScheduledAudit() {
35240
33993
  const attempt = acquireAuditLock("scheduled");
35241
33994
  if (!attempt.ok) {
@@ -35268,7 +34021,6 @@ async function runScheduledAudit() {
35268
34021
  process.stdout.write(`failproofai: audit complete — ${num2(result.eventsScanned)} tool calls across ` + `${num2(result.transcripts.scanned)} sessions, ${num2(result.totals.hits)} hits
35269
34022
  `);
35270
34023
  const outcome = await reportHarm(result);
35271
- await announceLeaksOnDesktop(result, outcome);
35272
34024
  const line = describeOutcome2(outcome);
35273
34025
  if (line) {
35274
34026
  const stream = outcome.kind === "sent" ? process.stdout : process.stderr;
@@ -35299,16 +34051,6 @@ async function runAuditCli(args) {
35299
34051
  runScheduleStatus();
35300
34052
  process.exit(0);
35301
34053
  }
35302
- for (const [flag, enable] of [["--notify", true], ["--no-notify", false]]) {
35303
- if (args.includes(flag)) {
35304
- const extra = args.find((a) => a !== flag);
35305
- if (extra)
35306
- die(`\`audit ${flag}\` takes no other arguments (got: ${extra}).`);
35307
- await Promise.resolve().then(() => init_schedule_cli());
35308
- runNotifyToggle(enable);
35309
- process.exit(0);
35310
- }
35311
- }
35312
34054
  if (args.includes("--no-schedule")) {
35313
34055
  const extra = args.find((a) => a !== "--no-schedule");
35314
34056
  if (extra)
@@ -35424,10 +34166,6 @@ var init_cli2 = __esm(() => {
35424
34166
  init_telemetry_sanitize();
35425
34167
  init_open_browser();
35426
34168
  init_report_harm();
35427
- init_desktop_notify();
35428
- init_macos_notifier();
35429
- init_fp_config();
35430
- init_auth_store();
35431
34169
  init_tui();
35432
34170
  init_package();
35433
34171
  AUDIT_STAGES2 = [
@@ -35760,8 +34498,8 @@ var init_session_pause_cli = __esm(() => {
35760
34498
 
35761
34499
  // scripts/launch.ts
35762
34500
  import { spawn as spawn3 } from "child_process";
35763
- import { realpathSync as realpathSync6, existsSync as existsSync47 } from "node:fs";
35764
- import { resolve as resolve34, dirname as dirname24 } from "node:path";
34501
+ import { realpathSync as realpathSync6, existsSync as existsSync45 } from "node:fs";
34502
+ import { resolve as resolve33, dirname as dirname23 } from "node:path";
35765
34503
  import { fileURLToPath as fileURLToPath3 } from "node:url";
35766
34504
  import { createInterface as createInterface2 } from "node:readline";
35767
34505
  function launch2(mode) {
@@ -35785,9 +34523,9 @@ function launch2(mode) {
35785
34523
  process.env.PORT = port;
35786
34524
  process.env.HOSTNAME = bindHost;
35787
34525
  cmd = "node";
35788
- const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT ?? resolve34(dirname24(realpathSync6(fileURLToPath3(import.meta.url))), "..");
35789
- const serverJsPath = resolve34(packageRoot, ".next/standalone/server.js");
35790
- if (!existsSync47(serverJsPath)) {
34526
+ const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT ?? resolve33(dirname23(realpathSync6(fileURLToPath3(import.meta.url))), "..");
34527
+ const serverJsPath = resolve33(packageRoot, ".next/standalone/server.js");
34528
+ if (!existsSync45(serverJsPath)) {
35791
34529
  let shadowMessage = null;
35792
34530
  try {
35793
34531
  const diag = diagnoseShadow({ selfPackageRoot: packageRoot, selfVersion: version2 });
@@ -35884,17 +34622,17 @@ var init_cli_error2 = __esm(() => {
35884
34622
 
35885
34623
  // bin/failproofai.mjs
35886
34624
  import { realpathSync as realpathSync7 } from "fs";
35887
- import { dirname as dirname25, resolve as resolve35 } from "path";
34625
+ import { dirname as dirname24, resolve as resolve34 } from "path";
35888
34626
  import { fileURLToPath as fileURLToPath4 } from "url";
35889
34627
  // package.json
35890
- var version = "1.0.4-beta.7";
34628
+ var version = "1.0.4";
35891
34629
 
35892
34630
  // bin/failproofai.mjs
35893
34631
  if (!process.env.FAILPROOFAI_PACKAGE_ROOT) {
35894
- process.env.FAILPROOFAI_PACKAGE_ROOT = resolve35(dirname25(realpathSync7(fileURLToPath4(import.meta.url))), "..");
34632
+ process.env.FAILPROOFAI_PACKAGE_ROOT = resolve34(dirname24(realpathSync7(fileURLToPath4(import.meta.url))), "..");
35895
34633
  }
35896
34634
  if (!process.env.FAILPROOFAI_DIST_PATH) {
35897
- process.env.FAILPROOFAI_DIST_PATH = resolve35(dirname25(realpathSync7(fileURLToPath4(import.meta.url))), "..", "dist");
34635
+ process.env.FAILPROOFAI_DIST_PATH = resolve34(dirname24(realpathSync7(fileURLToPath4(import.meta.url))), "..", "dist");
35898
34636
  }
35899
34637
  var args = process.argv.slice(2);
35900
34638
  if (args[0] === "p" || args[0] === "policy")
@@ -36132,7 +34870,7 @@ Run \`failproofai help\` for usage.`);
36132
34870
  label: "see what it caught",
36133
34871
  entries: [
36134
34872
  ["(no args)", "Open the policy dashboard on localhost:8020"],
36135
- ["audit", "Find credentials your agents leaked, and get told about it"],
34873
+ ["audit", "Scan your agents' history, then open the audit view"],
36136
34874
  ["config --status", "Cloud connection, daemon version, pause state"]
36137
34875
  ]
36138
34876
  },