failproofai 1.0.4-beta.8 → 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 (245) 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 +1 -1
  34. package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
  35. package/.next/standalone/.next/server/app/audit/page/build-manifest.json +2 -2
  36. package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +4 -37
  37. package/.next/standalone/.next/server/app/audit/page.js +2 -2
  38. package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -1
  39. package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
  40. package/.next/standalone/.next/server/app/index.html +1 -1
  41. package/.next/standalone/.next/server/app/index.rsc +14 -14
  42. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +13 -13
  43. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +14 -14
  44. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  45. package/.next/standalone/.next/server/app/page/build-manifest.json +2 -2
  46. package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
  47. package/.next/standalone/.next/server/app/page.js +2 -2
  48. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  49. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  50. package/.next/standalone/.next/server/app/policies/page/build-manifest.json +2 -2
  51. package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +14 -14
  52. package/.next/standalone/.next/server/app/policies/page.js +4 -4
  53. package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
  54. package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
  55. package/.next/standalone/.next/server/app/project/[name]/page/build-manifest.json +2 -2
  56. package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
  57. package/.next/standalone/.next/server/app/project/[name]/page.js +4 -4
  58. package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
  59. package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
  60. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/build-manifest.json +2 -2
  61. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
  62. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
  63. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js +5 -5
  64. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
  65. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
  66. package/.next/standalone/.next/server/app/projects/page/build-manifest.json +2 -2
  67. package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
  68. package/.next/standalone/.next/server/app/projects/page.js +3 -3
  69. package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
  70. package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  71. package/.next/standalone/.next/server/app/settings/page/build-manifest.json +2 -2
  72. package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +4 -15
  73. package/.next/standalone/.next/server/app/settings/page.js +4 -4
  74. package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
  75. package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  76. package/.next/standalone/.next/server/chunks/{[externals]__0hmcwgg._.js → [externals]__0-9ti7z._.js} +1 -1
  77. package/.next/standalone/.next/server/chunks/{[externals]__14b7cc6._.js → [externals]__0u3wrvq._.js} +1 -1
  78. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0-219ec._.js +3 -0
  79. package/.next/standalone/.next/server/chunks/[root-of-the-server]__04_h-a5._.js +3 -0
  80. package/.next/standalone/.next/server/chunks/[root-of-the-server]__08dchfu._.js +1 -1
  81. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0o07qi9._.js +1 -1
  82. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0rv7m0k._.js +1 -1
  83. package/.next/standalone/.next/server/chunks/[root-of-the-server]__17g9wh7._.js +1 -1
  84. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1le9jqc._.js +3 -0
  85. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1legmza._.js +1 -1
  86. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1p-qi2t._.js +5 -0
  87. package/.next/standalone/.next/server/chunks/_0tovk6q._.js +1 -1
  88. package/.next/standalone/.next/server/chunks/_0trp3yc._.js +1 -1
  89. package/.next/standalone/.next/server/chunks/{_1_eakl4._.js → _1-akg6w._.js} +2 -2
  90. package/.next/standalone/.next/server/chunks/_1ek68ln._.js +10 -10
  91. package/.next/standalone/.next/server/chunks/_1vslkoe._.js +1 -1
  92. package/.next/standalone/.next/server/chunks/lib_telemetry_ts_0dctyyw._.js +1 -1
  93. package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
  94. package/.next/standalone/.next/server/chunks/src_hooks_fp-home_ts_09kv0bn._.js +1 -1
  95. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__187jks6._.js → [root-of-the-server]__00-s7h8._.js} +1 -1
  96. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__013jr2b._.js +4 -0
  97. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__01wy8d-._.js +4 -0
  98. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__02npjtd._.js +4 -0
  99. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1fa1jd9._.js → [root-of-the-server]__09flfsx._.js} +2 -2
  100. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0da85px._.js +4 -0
  101. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ftmoxc._.js +4 -0
  102. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0kokc8z._.js → [root-of-the-server]__0n_lxhg._.js} +1 -1
  103. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0oa1lav._.js +1 -1
  104. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0p-5p8u._.js +4 -0
  105. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0s740oi._.js +6 -0
  106. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1kpd1za._.js → [root-of-the-server]__190won8._.js} +1 -1
  107. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1ctpynv._.js +3 -0
  108. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1nq7ivq._.js +3 -0
  109. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1p2otjt._.js +4 -0
  110. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__00y9ww2._.js → [root-of-the-server]__1sc84bb._.js} +2 -21
  111. package/.next/standalone/.next/server/chunks/ssr/_02yoeej._.js +3 -0
  112. package/.next/standalone/.next/server/chunks/ssr/{_00bqkhj._.js → _04rbnaq._.js} +2 -2
  113. package/.next/standalone/.next/server/chunks/ssr/_08x1r5t._.js +1 -1
  114. package/.next/standalone/.next/server/chunks/ssr/{_0s-77v5._.js → _0h_douw._.js} +1 -1
  115. package/.next/standalone/.next/server/chunks/ssr/_1_ozgif._.js +1 -1
  116. package/.next/standalone/.next/server/chunks/ssr/_1ddpc5g._.js +1 -1
  117. package/.next/standalone/.next/server/chunks/ssr/_1es2j7i._.js +14 -51
  118. package/.next/standalone/.next/server/chunks/ssr/{_14c6q09._.js → _1if9ixi._.js} +2 -21
  119. package/.next/standalone/.next/server/chunks/ssr/{_07t3jol._.js → _1u8-lu2._.js} +2 -2
  120. package/.next/standalone/.next/server/chunks/ssr/_1ylae7o._.js +3 -0
  121. package/.next/standalone/.next/server/chunks/ssr/_1zopuov._.js +3 -0
  122. package/.next/standalone/.next/server/chunks/ssr/_next-internal_server_app_policies_page_actions_1sp2-yo.js +2 -2
  123. package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +69 -1
  124. package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
  125. package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +1 -1
  126. package/.next/standalone/.next/server/chunks/ssr/app_settings_settings-client_tsx_20lq-mq._.js +1 -1
  127. package/.next/standalone/.next/server/chunks/ssr/lib_openclaw-projects_ts_0qxq3bp._.js +1 -1
  128. package/.next/standalone/.next/server/chunks/ssr/node_modules_13n822a._.js +1 -1
  129. package/.next/standalone/.next/server/chunks/ssr/node_modules_html-to-image_es_index_1ao30b1.js +3 -0
  130. package/.next/standalone/.next/server/chunks/ssr/src_hooks_builtin-policies_ts_09j2ndl._.js +1 -1
  131. package/.next/standalone/.next/server/chunks/ssr/src_hooks_fp-config_ts_04t589g._.js +1 -1
  132. package/.next/standalone/.next/server/chunks/ssr/src_hooks_fp-home_ts_0je3xkv._.js +1 -1
  133. package/.next/standalone/.next/server/middleware-build-manifest.js +5 -5
  134. package/.next/standalone/.next/server/pages/404.html +1 -1
  135. package/.next/standalone/.next/server/pages/500.html +1 -1
  136. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  137. package/.next/standalone/.next/server/server-reference-manifest.json +21 -65
  138. package/.next/standalone/.next/static/chunks/{1302duobnz07l.js → 0-tyrpwuc3lla.js} +1 -1
  139. package/.next/standalone/.next/static/chunks/0ca7octhod0g2.js +69 -0
  140. package/.next/standalone/.next/static/chunks/0u64yey446k4f.css +1 -0
  141. package/.next/standalone/.next/static/chunks/{2n85g-crgcx5j.js → 1j6o9min_6qa9.js} +1 -1
  142. package/.next/standalone/.next/static/chunks/27cl8h-c2w7cd.js +1 -0
  143. package/.next/standalone/.next/static/chunks/{0jpd8dv2vk930.css → 29-iqnp9v_axt.css} +1 -1
  144. package/.next/standalone/.next/static/chunks/{3uyhmm01g64k4.css → 2k9f4tyv04809.css} +0 -1
  145. package/.next/standalone/.next/static/chunks/{1chm9piluggc-.js → 2lwipmv5etc8m.js} +1 -1
  146. package/.next/standalone/.next/static/chunks/2pd16tn5qmx13.js +1 -0
  147. package/.next/standalone/.next/static/chunks/{2ukucf6g-kbs5.js → 2u8vh73tpw28_.js} +1 -1
  148. package/.next/standalone/.next/static/chunks/{1_x7pqemw5n_w.js → 31u94yukw9fz-.js} +1 -1
  149. package/.next/standalone/.next/static/chunks/{2mizt96igig1y.js → 3p9_8x5ezce-9.js} +1 -1
  150. package/.next/standalone/.next/static/chunks/3qfoeqhy5l10x.js +1 -0
  151. package/.next/standalone/.next/static/chunks/{0vm4wdx3w-2_w.js → 3tjji451hrgc0.js} +1 -1
  152. package/.next/standalone/.next/static/chunks/3zkg2s2vzxc3d.js +1 -0
  153. package/.next/standalone/.next/static/chunks/{turbopack-3s3c-u_u_l0u9.js → turbopack-3p73obe0xmrxm.js} +1 -1
  154. package/.next/standalone/.opencode/plugins/failproofai.mjs +27 -51
  155. package/.next/standalone/app/actions/get-scheduled-audit.ts +0 -5
  156. package/.next/standalone/app/actions/update-scheduled-audit.ts +57 -18
  157. package/.next/standalone/app/api/auth/status/route.ts +2 -3
  158. package/.next/standalone/app/audit/_components/audit-dashboard.tsx +34 -140
  159. package/.next/standalone/app/audit/_components/audit-poster.tsx +10 -29
  160. package/.next/standalone/app/audit/_components/come-back-better-section.tsx +1 -6
  161. package/.next/standalone/app/audit/_components/empty-state.tsx +1 -4
  162. package/.next/standalone/app/audit/_components/how-to-improve-section.tsx +5 -19
  163. package/.next/standalone/app/audit/_components/share-templates.ts +44 -110
  164. package/.next/standalone/app/audit/audit-styles.css +1 -132
  165. package/.next/standalone/app/settings/page.tsx +1 -1
  166. package/.next/standalone/app/settings/settings-client.tsx +45 -50
  167. package/.next/standalone/lib/auth/api-server-client.ts +5 -33
  168. package/.next/standalone/lib/claude-sessions.ts +27 -101
  169. package/.next/standalone/lib/codex-sessions.ts +4 -20
  170. package/.next/standalone/lib/copilot-sessions.ts +1 -32
  171. package/.next/standalone/lib/cursor-sessions.ts +5 -62
  172. package/.next/standalone/lib/download-session.ts +13 -58
  173. package/.next/standalone/lib/openclaw-projects.ts +18 -54
  174. package/.next/standalone/lib/openclaw-sessions.ts +17 -75
  175. package/.next/standalone/lib/sqlite-reader.ts +1 -78
  176. package/.next/standalone/package.json +9 -9
  177. package/.next/standalone/server.js +1 -1
  178. package/bin/failproofai.mjs +1 -1
  179. package/dist/cli.mjs +664 -2121
  180. package/dist/worker.mjs +105 -422
  181. package/lib/auth/api-server-client.ts +5 -33
  182. package/lib/claude-sessions.ts +27 -101
  183. package/lib/codex-sessions.ts +4 -20
  184. package/lib/copilot-sessions.ts +1 -32
  185. package/lib/cursor-sessions.ts +5 -62
  186. package/lib/download-session.ts +13 -58
  187. package/lib/openclaw-projects.ts +18 -54
  188. package/lib/openclaw-sessions.ts +17 -75
  189. package/lib/sqlite-reader.ts +1 -78
  190. package/package.json +9 -9
  191. package/pi-extension/index.ts +5 -50
  192. package/src/audit/cache.ts +0 -6
  193. package/src/audit/cli-adapters/claude.ts +0 -13
  194. package/src/audit/cli-login.ts +1 -4
  195. package/src/audit/cli.ts +7 -157
  196. package/src/audit/harm-report.ts +4 -111
  197. package/src/audit/index.ts +15 -286
  198. package/src/audit/machine-store.ts +9 -8
  199. package/src/audit/redact-example.ts +15 -324
  200. package/src/audit/report-harm.ts +37 -33
  201. package/src/audit/report.ts +3 -6
  202. package/src/audit/schedule-cli.ts +33 -54
  203. package/src/audit/scoring.ts +0 -49
  204. package/src/audit/types.ts +0 -52
  205. package/src/hooks/builtin-policies.ts +2 -67
  206. package/src/hooks/configure-wizard.ts +0 -55
  207. package/src/hooks/fp-config.ts +48 -83
  208. package/src/hooks/fp-home.ts +0 -27
  209. package/src/hooks/integrations.ts +14 -51
  210. package/src/hooks/uninstall-cli.ts +2 -17
  211. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0faqz9x._.js +0 -22
  212. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0zyc_nm._.js +0 -3
  213. package/.next/standalone/.next/server/chunks/[root-of-the-server]__112b4go._.js +0 -24
  214. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1l71g3y._.js +0 -22
  215. package/.next/standalone/.next/server/chunks/lib_openclaw-projects_ts_0gc-p24._.js +0 -3
  216. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0-4ja6q._.js +0 -4
  217. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__00cr3xu._.js +0 -4
  218. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__04px77e._.js +0 -4
  219. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0egr5s1._.js +0 -6
  220. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0i0l1di._.js +0 -4
  221. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0n2txhk._.js +0 -3
  222. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0r3c1_0._.js +0 -4
  223. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__17xnxlx._.js +0 -4
  224. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1ckpmkk._.js +0 -4
  225. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1kaotix._.js +0 -22
  226. package/.next/standalone/.next/server/chunks/ssr/_04ng_6x._.js +0 -3
  227. package/.next/standalone/.next/server/chunks/ssr/_0l2hi_d._.js +0 -3
  228. package/.next/standalone/.next/server/chunks/ssr/app_audit__components_rerun-button_tsx_0blihgw._.js +0 -3
  229. package/.next/standalone/.next/static/chunks/0igq884ziuv-8.js +0 -1
  230. package/.next/standalone/.next/static/chunks/349jkb79v5g6z.js +0 -1
  231. package/.next/standalone/.next/static/chunks/3a4gth64hwtwf.js +0 -1
  232. package/.next/standalone/app/actions/get-leaks.ts +0 -104
  233. package/.next/standalone/app/audit/_components/leak-section.tsx +0 -192
  234. package/.next/standalone/lib/openclaw-db.ts +0 -271
  235. package/lib/openclaw-db.ts +0 -271
  236. package/src/audit/desktop-notify.ts +0 -420
  237. package/src/audit/leak-fingerprint.ts +0 -198
  238. package/src/audit/leak-record.ts +0 -248
  239. package/src/audit/leak-scan.ts +0 -268
  240. package/src/audit/leak-store.ts +0 -220
  241. package/src/audit/macos-notifier.ts +0 -298
  242. package/src/hooks/notice.ts +0 -24
  243. /package/.next/standalone/.next/static/{DNhaAH8iPGH0tIuxee5_2 → dg8VQ7Ejlo0Qsh_x92oIt}/_buildManifest.js +0 -0
  244. /package/.next/standalone/.next/static/{DNhaAH8iPGH0tIuxee5_2 → dg8VQ7Ejlo0Qsh_x92oIt}/_clientMiddlewareManifest.js +0 -0
  245. /package/.next/standalone/.next/static/{DNhaAH8iPGH0tIuxee5_2 → dg8VQ7Ejlo0Qsh_x92oIt}/_ssgManifest.js +0 -0
@@ -1,104 +0,0 @@
1
- "use server";
2
-
3
- import {
4
- activeFindings,
5
- dismissFinding,
6
- readLeakRecord,
7
- } from "@/src/audit/leak-store";
8
- import { readConfig, updateConfig } from "@/src/hooks/fp-config";
9
-
10
- /**
11
- * One credential, flattened for the report table.
12
- *
13
- * A separate shape from `LeakFinding` on purpose: this crosses into a client
14
- * component, so it carries only what is drawn. The finding's raw sightings, its
15
- * rule and its salt stay on the server side of the boundary — not because any
16
- * of them is a secret (the record holds no secret by construction), but because
17
- * a display type that mirrors the storage type drifts into rendering whatever
18
- * gets added to storage next.
19
- */
20
- export interface LeakRow {
21
- id: string;
22
- /** WHAT — `ghp_••••••••4f2a`. Never the value; there is no value to send. */
23
- display: string;
24
- label: string;
25
- length: number;
26
- /** False means no console to revoke at — the advice changes completely. */
27
- attributed: boolean;
28
- /** The identifier it was assigned to, when there was one. */
29
- name: string | null;
30
- /** WHO — the harness whose transcript carried it. */
31
- cli: string;
32
- /** WHERE — home-shortened project path. */
33
- project: string;
34
- /** WHEN — ISO, formatted client-side so it lands in the reader's timezone. */
35
- lastSeen: string;
36
- firstSeen: string;
37
- /** HOW — "read from ~/…/.env". */
38
- mechanism: string;
39
- /** WHY IT MATTERS — an input the agent sent can be denied next time; a
40
- * result it received cannot be un-received. */
41
- direction: "input" | "result";
42
- occurrences: number;
43
- sessions: number;
44
- }
45
-
46
- export interface LeaksPayload {
47
- rows: LeakRow[];
48
- /** Whether this machine may raise a desktop notification. Drawn as a toggle
49
- * beside the table, because the table is where somebody decides the banner
50
- * was worth it or not. */
51
- notify: boolean;
52
- }
53
-
54
- export async function getLeaksAction(): Promise<LeaksPayload> {
55
- const findings = activeFindings(readLeakRecord());
56
- const rows: LeakRow[] = findings.map((f) => {
57
- // The most recent sighting: where the key is now, not where it debuted.
58
- const seen = f.sightings?.[f.sightings.length - 1];
59
- return {
60
- id: f.id,
61
- display: f.fingerprint?.display ?? "[credential]",
62
- label: f.fingerprint?.label ?? "secret",
63
- length: f.fingerprint?.length ?? 0,
64
- attributed: f.fingerprint?.attributed === true,
65
- name: f.name,
66
- cli: seen?.cli ?? "unknown",
67
- project: seen?.cwd ?? "unknown",
68
- lastSeen: f.lastSeen,
69
- firstSeen: f.firstSeen,
70
- mechanism: seen?.mechanism?.summary ?? "seen in a transcript",
71
- direction: seen?.mechanism?.direction ?? "result",
72
- occurrences: f.occurrences,
73
- sessions: new Set((f.sightings ?? []).map((s) => s.sessionId)).size,
74
- };
75
- });
76
- rows.sort((a, b) => Date.parse(b.lastSeen) - Date.parse(a.lastSeen));
77
- return { rows, notify: readConfig().audit.notify };
78
- }
79
-
80
- /**
81
- * Mark one finding as not-a-secret.
82
- *
83
- * The finding is RETAINED, not deleted — deleting it would let the next scan
84
- * rediscover the same value and alert again, which is the one outcome that
85
- * teaches a user the dismiss button does not work.
86
- */
87
- export async function dismissLeakAction(id: string): Promise<boolean> {
88
- return dismissFinding(id);
89
- }
90
-
91
- /**
92
- * Turn the desktop banner on or off.
93
- *
94
- * Writes the same `audit.notify` key `failproofai config` writes and the daemon's
95
- * audit child reads, so the dashboard and the CLI cannot disagree about it.
96
- */
97
- export async function setLeakNotifyAction(notify: boolean): Promise<boolean> {
98
- try {
99
- updateConfig({ audit: { notify } });
100
- return true;
101
- } catch {
102
- return false;
103
- }
104
- }
@@ -1,192 +0,0 @@
1
- "use client";
2
-
3
- /**
4
- * The leak report: every credential this machine found in its own transcripts.
5
- *
6
- * This is what replaced the persona poster and the five scored sections. The
7
- * old report answered "what kind of agent user are you"; this one answers the
8
- * only question a leaked key raises — what is it, where did it go, how did it
9
- * get there, and what do I do now.
10
- *
11
- * Each row is one DISTINCT credential, not one sighting: a key pasted into
12
- * forty commands is one thing to rotate, not forty. The count of exposures is a
13
- * column, which is the honest way to show forty without implying forty problems.
14
- */
15
- import { useCallback, useEffect, useState } from "react";
16
- import {
17
- dismissLeakAction,
18
- getLeaksAction,
19
- setLeakNotifyAction,
20
- type LeakRow,
21
- } from "@/app/actions/get-leaks";
22
-
23
- /** Rendered in the reader's timezone, which is why it is not done server-side. */
24
- function when(iso: string): string {
25
- const t = Date.parse(iso);
26
- if (!Number.isFinite(t)) return "unknown";
27
- const days = Math.floor((Date.now() - t) / 86_400_000);
28
- if (days <= 0) return "today";
29
- if (days === 1) return "yesterday";
30
- if (days < 30) return `${days}d ago`;
31
- return new Date(t).toLocaleDateString(undefined, { month: "short", day: "numeric" });
32
- }
33
-
34
- /**
35
- * What to actually do about this one.
36
- *
37
- * Two genuinely different situations, and conflating them is what makes
38
- * security advice useless. A recognised prefix means a console exists and the
39
- * key can be revoked there in a minute. An unattributed value — the majority,
40
- * per the pattern census — has no console at all: the only move is to find
41
- * where it came from, and the identifier name is usually the only clue.
42
- */
43
- function advice(row: LeakRow): string {
44
- if (row.attributed) return `rotate it in the ${row.label.replace(/ (API )?(key|token).*$/i, "")} console`;
45
- if (row.name) return `find what reads ${row.name}, then rotate it there`;
46
- return "trace it to its owner, then rotate it";
47
- }
48
-
49
- export function LeakSection() {
50
- const [rows, setRows] = useState<LeakRow[] | null>(null);
51
- const [notify, setNotify] = useState(true);
52
- const [busy, setBusy] = useState<string | null>(null);
53
-
54
- const load = useCallback(async () => {
55
- const payload = await getLeaksAction();
56
- setRows(payload.rows);
57
- setNotify(payload.notify);
58
- }, []);
59
-
60
- useEffect(() => {
61
- void load();
62
- }, [load]);
63
-
64
- const dismiss = useCallback(
65
- async (id: string) => {
66
- setBusy(id);
67
- try {
68
- // Optimism would be wrong here: a dismissal that did not persist means
69
- // the row comes back on the next load, and the user has to guess which
70
- // of the two states is real.
71
- if (await dismissLeakAction(id)) setRows((prev) => prev?.filter((r) => r.id !== id) ?? null);
72
- } finally {
73
- setBusy(null);
74
- }
75
- },
76
- [],
77
- );
78
-
79
- const toggleNotify = useCallback(async () => {
80
- const next = !notify;
81
- setNotify(next);
82
- if (!(await setLeakNotifyAction(next))) setNotify(!next);
83
- }, [notify]);
84
-
85
- if (rows === null) return null;
86
-
87
- return (
88
- <section className="audit-sec" data-screen-label="02 Leaks">
89
- <div className="audit-sec-head">
90
- <span className="audit-sec-eyebrow">
91
- <span className="ix">02</span>{"// credentials"}
92
- </span>
93
- <button
94
- type="button"
95
- className="cbb-toggle leak-notify"
96
- data-on={notify}
97
- onClick={toggleNotify}
98
- aria-label={notify ? "turn desktop notifications off" : "turn desktop notifications on"}
99
- title="desktop notification when a new credential is found"
100
- >
101
- <span className="cbb-toggle-knob" />
102
- </button>
103
- </div>
104
-
105
- {rows.length === 0 ? (
106
- <>
107
- <h2 className="audit-sec-title">no credentials found</h2>
108
- <div className="audit-sec-sub">
109
- {"// nothing in this machine's transcripts matched a known key format"}
110
- <br />
111
- {"// or a secret-named assignment."}
112
- </div>
113
- </>
114
- ) : (
115
- <>
116
- <h2 className="audit-sec-title">
117
- {rows.length} credential{rows.length === 1 ? "" : "s"} in your transcripts
118
- </h2>
119
- <div className="audit-sec-sub">
120
- {"// one row per distinct key — an exposure count is not a key count."}
121
- </div>
122
-
123
- <ul className="leak-list">
124
- {rows.map((row) => (
125
- <li key={row.id} className="leak-row" data-attributed={row.attributed}>
126
- <div className="leak-row-top">
127
- <code className="leak-key">{row.display}</code>
128
- <span className="leak-label">{row.label}</span>
129
- {row.name ? <span className="leak-name">{row.name}</span> : null}
130
- <button
131
- type="button"
132
- className="leak-dismiss"
133
- onClick={() => void dismiss(row.id)}
134
- disabled={busy === row.id}
135
- >
136
- not a secret
137
- </button>
138
- </div>
139
-
140
- {/* The 5W1H, as one sentence rather than a grid of labelled
141
- cells — a person reading a leak wants the story, and the
142
- grid version made every row look like a form to fill in. */}
143
- {/* The date is FIRST seen, not last. "When did this key get
144
- into a transcript" is the question a leak raises; "when did
145
- I last run a scan that noticed" is not. They also looked
146
- identical in practice — the record keeps the 500 most
147
- recently seen findings, so everything surviving the cap
148
- reported the same recent `lastSeen` and every row read
149
- "today", which is true and useless. */}
150
- <div className="leak-how">
151
- <span className="leak-verb">{row.mechanism}</span>
152
- {" in "}
153
- <span className="leak-where">{row.project}</span>
154
- {" via "}
155
- <span className="leak-who">{row.cli}</span>
156
- {" · leaked "}
157
- <span className="leak-when">{when(row.firstSeen)}</span>
158
- {row.firstSeen !== row.lastSeen ? (
159
- <>
160
- {" · last seen "}
161
- <span className="leak-when">{when(row.lastSeen)}</span>
162
- </>
163
- ) : null}
164
- </div>
165
-
166
- <div className="leak-foot">
167
- <span className="leak-meta">
168
- {row.occurrences} exposure{row.occurrences === 1 ? "" : "s"}
169
- {row.sessions > 1 ? ` · ${row.sessions} sessions` : ""}
170
- {" · "}
171
- {row.length} chars
172
- </span>
173
- {/* The direction is the difference between a leak a gate can
174
- stop next time and one it cannot. An input travelled OUT
175
- of the machine with the agent's request; a result came
176
- back INTO the transcript from a file or a command, where
177
- no PreToolUse hook can intercept it. */}
178
- <span className="leak-dir">
179
- {row.direction === "input"
180
- ? "sent by the agent — blockable at PreToolUse"
181
- : "returned to the agent — already in the transcript"}
182
- </span>
183
- <span className="leak-fix">{advice(row)}</span>
184
- </div>
185
- </li>
186
- ))}
187
- </ul>
188
- </>
189
- )}
190
- </section>
191
- );
192
- }
@@ -1,271 +0,0 @@
1
- /**
2
- * Read OpenClaw 2026.9.2+ transcripts from the per-agent SQLite databases at
3
- * `agents/<agentId>/agent/openclaw-agent.sqlite`.
4
- *
5
- * `event_json` is the exact logical JSONL record, so the dashboard can feed it
6
- * through the same parser and download format used by archived JSONL files.
7
- */
8
- import { existsSync } from "node:fs";
9
- import { join } from "node:path";
10
- import { openSqliteReadonly, type SqliteReader } from "./sqlite-reader";
11
-
12
- const DB_NAME = "openclaw-agent.sqlite";
13
-
14
- export interface OpenClawSqliteSession {
15
- sessionId: string;
16
- agentId: string;
17
- dbPath: string;
18
- transcriptPath: string;
19
- mtimeMs: number;
20
- sizeBytes: number;
21
- channel: string;
22
- label?: string;
23
- chatId?: string;
24
- chatType?: string;
25
- }
26
-
27
- export interface OpenClawSqliteTranscript {
28
- agentId: string;
29
- dbPath: string;
30
- filePath: string;
31
- rawLines: Record<string, unknown>[];
32
- eventJsonLines: string[];
33
- }
34
-
35
- interface WindowRow {
36
- session_id: string;
37
- session_key: string;
38
- updated_at: number;
39
- transcript_updated_at: number | null;
40
- ended_at: number | null;
41
- channel: string | null;
42
- chat_type: string | null;
43
- display_name: string | null;
44
- event_updated_at: number;
45
- size_bytes: number;
46
- }
47
-
48
- interface NodeRow {
49
- current_session_id: string;
50
- entry_json: string;
51
- label: string | null;
52
- display_name: string | null;
53
- }
54
-
55
- interface ConversationRow {
56
- session_id: string;
57
- channel: string;
58
- kind: string;
59
- peer_id: string;
60
- delivery_target: string;
61
- label: string | null;
62
- }
63
-
64
- interface EventRow {
65
- event_json: string;
66
- }
67
-
68
- interface SessionMeta {
69
- channel?: string;
70
- label?: string;
71
- chatId?: string;
72
- chatType?: string;
73
- }
74
-
75
- function str(value: unknown): string | undefined {
76
- return typeof value === "string" && value.length > 0 ? value : undefined;
77
- }
78
-
79
- function parseObject(value: string): Record<string, unknown> | undefined {
80
- try {
81
- const parsed: unknown = JSON.parse(value);
82
- return parsed && typeof parsed === "object" && !Array.isArray(parsed)
83
- ? (parsed as Record<string, unknown>)
84
- : undefined;
85
- } catch {
86
- return undefined;
87
- }
88
- }
89
-
90
- function syntheticPath(agentId: string, sessionId: string): string {
91
- return `openclaw-sqlite://${encodeURIComponent(agentId)}/${sessionId}`;
92
- }
93
-
94
- /** Existing per-agent SQLite databases, derived from the configured agents. */
95
- export function listOpenClawDatabases(
96
- home: string,
97
- agentIds: string[],
98
- ): Array<{ agentId: string; dbPath: string }> {
99
- const out: Array<{ agentId: string; dbPath: string }> = [];
100
- for (const agentId of agentIds) {
101
- const dbPath = join(home, "agents", agentId, "agent", DB_NAME);
102
- if (existsSync(dbPath)) out.push({ agentId, dbPath });
103
- }
104
- return out;
105
- }
106
-
107
- function readNodeMetadata(db: SqliteReader): Map<string, SessionMeta> {
108
- const out = new Map<string, SessionMeta>();
109
- let rows: NodeRow[];
110
- try {
111
- rows = db.query<NodeRow>(
112
- `SELECT current_session_id, entry_json, label, display_name
113
- FROM session_nodes`,
114
- );
115
- } catch {
116
- return out;
117
- }
118
- for (const row of rows) {
119
- const entry = parseObject(row.entry_json) ?? {};
120
- const origin =
121
- entry.origin &&
122
- typeof entry.origin === "object" &&
123
- !Array.isArray(entry.origin)
124
- ? (entry.origin as Record<string, unknown>)
125
- : {};
126
- out.set(row.current_session_id, {
127
- channel:
128
- str(entry.lastChannel) ?? str(origin.provider) ?? str(origin.surface),
129
- label:
130
- str(row.label) ??
131
- str(row.display_name) ??
132
- str(entry.displayName) ??
133
- str(origin.label),
134
- chatId: str(entry.lastTo) ?? str(origin.from),
135
- chatType: str(entry.chatType) ?? str(origin.chatType),
136
- });
137
- }
138
- return out;
139
- }
140
-
141
- function readConversationMetadata(db: SqliteReader): Map<string, SessionMeta> {
142
- const out = new Map<string, SessionMeta>();
143
- let rows: ConversationRow[];
144
- try {
145
- rows = db.query<ConversationRow>(
146
- `SELECT sc.session_id, c.channel, c.kind, c.peer_id,
147
- c.delivery_target, c.label
148
- FROM session_conversations sc
149
- JOIN conversations c ON c.conversation_id = sc.conversation_id
150
- ORDER BY CASE sc.role WHEN 'primary' THEN 0 ELSE 1 END, sc.last_seen_at DESC`,
151
- );
152
- } catch {
153
- return out;
154
- }
155
- for (const row of rows) {
156
- if (out.has(row.session_id)) continue;
157
- out.set(row.session_id, {
158
- channel: str(row.channel),
159
- label: str(row.label),
160
- chatId: str(row.delivery_target) ?? str(row.peer_id),
161
- chatType: str(row.kind),
162
- });
163
- }
164
- return out;
165
- }
166
-
167
- /** List every transcript-bearing session in all per-agent databases. */
168
- export async function listOpenClawSqliteSessions(
169
- home: string,
170
- agentIds: string[],
171
- ): Promise<OpenClawSqliteSession[]> {
172
- const sessions: OpenClawSqliteSession[] = [];
173
- for (const { agentId, dbPath } of listOpenClawDatabases(home, agentIds)) {
174
- const db = await openSqliteReadonly(dbPath);
175
- if (!db) continue;
176
- try {
177
- let rows: WindowRow[];
178
- try {
179
- rows = db.query<WindowRow>(
180
- `SELECT w.session_id, w.session_key, w.updated_at,
181
- w.transcript_updated_at, w.ended_at, w.channel,
182
- w.chat_type, w.display_name,
183
- COALESCE((SELECT MAX(e.created_at)
184
- FROM transcript_events e
185
- WHERE e.session_id = w.session_id), 0) AS event_updated_at,
186
- COALESCE((SELECT SUM(length(e.event_json) + 1)
187
- FROM transcript_events e
188
- WHERE e.session_id = w.session_id), 0) AS size_bytes
189
- FROM session_windows w
190
- WHERE EXISTS (SELECT 1 FROM transcript_events e
191
- WHERE e.session_id = w.session_id)`,
192
- );
193
- } catch {
194
- continue;
195
- }
196
-
197
- const nodes = readNodeMetadata(db);
198
- const conversations = readConversationMetadata(db);
199
- for (const row of rows) {
200
- const node = nodes.get(row.session_id);
201
- const conversation = conversations.get(row.session_id);
202
- sessions.push({
203
- sessionId: row.session_id,
204
- agentId,
205
- dbPath,
206
- transcriptPath: syntheticPath(agentId, row.session_id),
207
- mtimeMs: Math.max(
208
- Number(row.updated_at) || 0,
209
- Number(row.transcript_updated_at) || 0,
210
- Number(row.ended_at) || 0,
211
- Number(row.event_updated_at) || 0,
212
- ),
213
- sizeBytes: Number(row.size_bytes) || 0,
214
- channel:
215
- str(row.channel) ??
216
- conversation?.channel ??
217
- node?.channel ??
218
- "local",
219
- label: str(row.display_name) ?? conversation?.label ?? node?.label,
220
- chatId: conversation?.chatId ?? node?.chatId,
221
- chatType:
222
- str(row.chat_type) ?? conversation?.chatType ?? node?.chatType,
223
- });
224
- }
225
- } finally {
226
- db.close();
227
- }
228
- }
229
- return sessions;
230
- }
231
-
232
- /** Read one SQLite transcript by UUID. The first matching agent wins. */
233
- export async function readOpenClawSqliteTranscript(
234
- home: string,
235
- agentIds: string[],
236
- sessionId: string,
237
- ): Promise<OpenClawSqliteTranscript | null> {
238
- for (const { agentId, dbPath } of listOpenClawDatabases(home, agentIds)) {
239
- const db = await openSqliteReadonly(dbPath);
240
- if (!db) continue;
241
- try {
242
- let rows: EventRow[];
243
- try {
244
- rows = db.query<EventRow>(
245
- `SELECT event_json
246
- FROM transcript_events
247
- WHERE session_id = ?
248
- ORDER BY seq ASC`,
249
- [sessionId],
250
- );
251
- } catch {
252
- continue;
253
- }
254
- if (rows.length === 0) continue;
255
- const eventJsonLines = rows.map((row) => row.event_json);
256
- const rawLines = eventJsonLines
257
- .map(parseObject)
258
- .filter((line): line is Record<string, unknown> => line !== undefined);
259
- return {
260
- agentId,
261
- dbPath,
262
- filePath: syntheticPath(agentId, sessionId),
263
- rawLines,
264
- eventJsonLines,
265
- };
266
- } finally {
267
- db.close();
268
- }
269
- }
270
- return null;
271
- }