failproofai 1.0.4-beta.2 → 1.0.4-beta.6

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 (176) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/build-manifest.json +3 -3
  3. package/.next/standalone/.next/prerender-manifest.json +3 -3
  4. package/.next/standalone/.next/required-server-files.json +1 -1
  5. package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
  6. package/.next/standalone/.next/server/app/_global-error/page.js +2 -2
  7. package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
  8. package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  9. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  10. package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
  11. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +6 -6
  12. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
  13. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  14. package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  15. package/.next/standalone/.next/server/app/_not-found/page.js +2 -2
  16. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  17. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  18. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  19. package/.next/standalone/.next/server/app/_not-found.rsc +14 -14
  20. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +14 -14
  21. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +13 -13
  22. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  23. package/.next/standalone/.next/server/app/api/audit/invite/route.js.nft.json +1 -1
  24. package/.next/standalone/.next/server/app/api/audit/run/route.js +1 -1
  25. package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -1
  26. package/.next/standalone/.next/server/app/api/audit/status/route.js.nft.json +1 -1
  27. package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -1
  28. package/.next/standalone/.next/server/app/api/auth/login-verify/route.js.nft.json +1 -1
  29. package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
  30. package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -1
  31. package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
  32. package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +5 -5
  33. package/.next/standalone/.next/server/app/audit/page.js +3 -3
  34. package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -1
  35. package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
  36. package/.next/standalone/.next/server/app/index.html +1 -1
  37. package/.next/standalone/.next/server/app/index.rsc +14 -14
  38. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +13 -13
  39. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +14 -14
  40. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  41. package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
  42. package/.next/standalone/.next/server/app/page.js +2 -2
  43. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  44. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  45. package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +14 -14
  46. package/.next/standalone/.next/server/app/policies/page.js +4 -4
  47. package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
  48. package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
  49. package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
  50. package/.next/standalone/.next/server/app/project/[name]/page.js +3 -3
  51. package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
  52. package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
  53. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
  54. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
  55. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js +4 -4
  56. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
  57. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
  58. package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
  59. package/.next/standalone/.next/server/app/projects/page.js +3 -3
  60. package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
  61. package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  62. package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +4 -4
  63. package/.next/standalone/.next/server/app/settings/page.js +2 -2
  64. package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
  65. package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  66. package/.next/standalone/.next/server/chunks/{[externals]__1lh7m5d._.js → [externals]__0v1hz15._.js} +1 -1
  67. package/.next/standalone/.next/server/chunks/{[externals]__1rqkg_y._.js → [externals]__1nb206a._.js} +1 -1
  68. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0o07qi9._.js +1 -1
  69. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0rv7m0k._.js +1 -1
  70. package/.next/standalone/.next/server/chunks/[root-of-the-server]__17g9wh7._.js +1 -1
  71. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1legmza._.js +1 -1
  72. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1p-qi2t._.js +1 -1
  73. package/.next/standalone/.next/server/chunks/{_08w6xzm._.js → _0otft92._.js} +2 -2
  74. package/.next/standalone/.next/server/chunks/_0tovk6q._.js +1 -1
  75. package/.next/standalone/.next/server/chunks/_0trp3yc._.js +1 -1
  76. package/.next/standalone/.next/server/chunks/_1ek68ln._.js +4 -4
  77. package/.next/standalone/.next/server/chunks/_1vslkoe._.js +1 -1
  78. package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
  79. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0p-5p8u._.js → [root-of-the-server]__0-4ja6q._.js} +3 -3
  80. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1p2otjt._.js → [root-of-the-server]__00cr3xu._.js} +3 -3
  81. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__013jr2b._.js → [root-of-the-server]__04px77e._.js} +3 -3
  82. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__190won8._.js → [root-of-the-server]__0dxf928._.js} +1 -1
  83. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0s740oi._.js → [root-of-the-server]__0egr5s1._.js} +3 -3
  84. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__01wy8d-._.js → [root-of-the-server]__0i0l1di._.js} +3 -3
  85. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0n_lxhg._.js → [root-of-the-server]__0kokc8z._.js} +1 -1
  86. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1ctpynv._.js → [root-of-the-server]__0n2txhk._.js} +1 -1
  87. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0oa1lav._.js +1 -1
  88. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__02npjtd._.js → [root-of-the-server]__0r3c1_0._.js} +3 -3
  89. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0ftmoxc._.js → [root-of-the-server]__17xnxlx._.js} +3 -3
  90. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0da85px._.js → [root-of-the-server]__1ckpmkk._.js} +3 -3
  91. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__00-s7h8._.js → [root-of-the-server]__1fvfw59._.js} +1 -1
  92. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1ui5ur8._.js +3 -0
  93. package/.next/standalone/.next/server/chunks/ssr/_02b3i98._.js +23 -0
  94. package/.next/standalone/.next/server/chunks/ssr/{_0oq1dh6._.js → _04ng_6x._.js} +2 -2
  95. package/.next/standalone/.next/server/chunks/ssr/{_1u8-lu2._.js → _07t3jol._.js} +2 -2
  96. package/.next/standalone/.next/server/chunks/ssr/_08x1r5t._.js +1 -1
  97. package/.next/standalone/.next/server/chunks/ssr/{_0h_douw._.js → _0s-77v5._.js} +1 -1
  98. package/.next/standalone/.next/server/chunks/ssr/_1_ozgif._.js +1 -1
  99. package/.next/standalone/.next/server/chunks/ssr/_1ddpc5g._.js +1 -1
  100. package/.next/standalone/.next/server/chunks/ssr/_1es2j7i._.js +4 -1
  101. package/.next/standalone/.next/server/chunks/ssr/_next-internal_server_app_policies_page_actions_1sp2-yo.js +2 -2
  102. package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +1 -1
  103. package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
  104. package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +1 -1
  105. package/.next/standalone/.next/server/chunks/ssr/app_settings_settings-client_tsx_20lq-mq._.js +1 -1
  106. package/.next/standalone/.next/server/chunks/ssr/src_hooks_fp-home_ts_0je3xkv._.js +1 -1
  107. package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
  108. package/.next/standalone/.next/server/pages/404.html +1 -1
  109. package/.next/standalone/.next/server/pages/500.html +1 -1
  110. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  111. package/.next/standalone/.next/server/server-reference-manifest.json +22 -22
  112. package/.next/standalone/.next/static/chunks/{1pb1oztsbwcss.js → 07c6l1lq5_69b.js} +1 -1
  113. package/.next/standalone/.next/static/chunks/{0o-hh5_turzlz.css → 0jpd8dv2vk930.css} +1 -1
  114. package/.next/standalone/.next/static/chunks/{32spub4wqjem-.js → 12bsgz8czvcnn.js} +1 -1
  115. package/.next/standalone/.next/static/chunks/{3m4upvybtrexd.js → 1gn08w2pgqh09.js} +1 -1
  116. package/.next/standalone/.next/static/chunks/{010bv1w6j171t.js → 1xgq22tri86an.js} +1 -1
  117. package/.next/standalone/.next/static/chunks/{2aquitk72k2op.js → 20xkiqzvfkuvm.js} +1 -1
  118. package/.next/standalone/.next/static/chunks/{2bi_1y0a_smt7.js → 2a84ug32tzik2.js} +1 -1
  119. package/.next/standalone/.next/static/chunks/{2ej3b8gk5ittu.js → 32m2ryfankf_2.js} +1 -1
  120. package/.next/standalone/.next/static/chunks/3ioub_lpen-sq.js +1 -0
  121. package/.next/standalone/.next/static/chunks/{0wz8yftk18ts2.js → 3jxd133cw2vm3.js} +1 -1
  122. package/.next/standalone/.next/static/chunks/44ncu88eq6z71.js +1 -0
  123. package/.next/standalone/app/actions/get-leaks.ts +5 -1
  124. package/.next/standalone/app/actions/update-scheduled-audit.ts +4 -56
  125. package/.next/standalone/app/api/auth/status/route.ts +3 -2
  126. package/.next/standalone/app/audit/_components/audit-dashboard.tsx +29 -2
  127. package/.next/standalone/app/audit/_components/leak-section.tsx +15 -2
  128. package/.next/standalone/app/audit/audit-styles.css +18 -0
  129. package/.next/standalone/app/settings/page.tsx +1 -1
  130. package/.next/standalone/app/settings/settings-client.tsx +13 -39
  131. package/.next/standalone/lib/auth/api-server-client.ts +6 -6
  132. package/.next/standalone/lib/codex-sessions.ts +20 -4
  133. package/.next/standalone/lib/copilot-sessions.ts +32 -1
  134. package/.next/standalone/lib/cursor-sessions.ts +62 -5
  135. package/.next/standalone/lib/sqlite-reader.ts +78 -1
  136. package/.next/standalone/package.json +10 -10
  137. package/.next/standalone/server.js +1 -1
  138. package/bin/failproofai.mjs +1 -1
  139. package/dist/cli.mjs +1191 -1130
  140. package/dist/worker.mjs +198 -359
  141. package/lib/auth/api-server-client.ts +6 -6
  142. package/lib/codex-sessions.ts +20 -4
  143. package/lib/copilot-sessions.ts +32 -1
  144. package/lib/cursor-sessions.ts +62 -5
  145. package/lib/sqlite-reader.ts +78 -1
  146. package/package.json +10 -10
  147. package/pi-extension/index.ts +11 -4
  148. package/src/audit/cache.ts +6 -0
  149. package/src/audit/cli-adapters/claude.ts +13 -0
  150. package/src/audit/cli-login.ts +4 -1
  151. package/src/audit/cli.ts +67 -51
  152. package/src/audit/harm-report.ts +12 -6
  153. package/src/audit/index.ts +151 -8
  154. package/src/audit/leak-fingerprint.ts +2 -4
  155. package/src/audit/leak-record.ts +13 -9
  156. package/src/audit/leak-scan.ts +20 -44
  157. package/src/audit/leak-store.ts +5 -2
  158. package/src/audit/machine-store.ts +8 -9
  159. package/src/audit/macos-notifier.ts +2 -2
  160. package/src/audit/redact-example.ts +62 -5
  161. package/src/audit/report-harm.ts +31 -46
  162. package/src/audit/schedule-cli.ts +17 -33
  163. package/src/audit/types.ts +11 -0
  164. package/src/hooks/configure-wizard.ts +28 -0
  165. package/src/hooks/fp-config.ts +29 -54
  166. package/src/hooks/handler.ts +1 -59
  167. package/src/hooks/integrations.ts +4 -1
  168. package/src/hooks/notice.ts +23 -154
  169. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0rgu2r3._.js +0 -3
  170. package/.next/standalone/.next/server/chunks/ssr/_0-oij9d._.js +0 -23
  171. package/.next/standalone/.next/static/chunks/04r6ch8uf_n8m.js +0 -1
  172. package/.next/standalone/.next/static/chunks/0zebh1n9jkfbt.js +0 -1
  173. package/src/audit/leak-notice.ts +0 -161
  174. /package/.next/standalone/.next/static/{aKNv4Kmv98Xpwns0Xa-C- → aeM365dNTtUZOZvNkX8ba}/_buildManifest.js +0 -0
  175. /package/.next/standalone/.next/static/{aKNv4Kmv98Xpwns0Xa-C- → aeM365dNTtUZOZvNkX8ba}/_clientMiddlewareManifest.js +0 -0
  176. /package/.next/standalone/.next/static/{aKNv4Kmv98Xpwns0Xa-C- → aeM365dNTtUZOZvNkX8ba}/_ssgManifest.js +0 -0
@@ -308,22 +308,15 @@ export interface FpConfig {
308
308
  };
309
309
  audit: {
310
310
  /**
311
- * Scan this machine on a schedule, and mail a digest when a scan finds
312
- * something harmful.
311
+ * Scan this machine on a schedule. Delivery is deliberately separate:
312
+ * desktop notifications are controlled by `notify`, while a verified local
313
+ * email identity adds email alerts without changing the timer.
313
314
  *
314
- * ONE switch, not two. An earlier revision split this into `auto` (scan
315
- * locally, no account) and `email_enabled` (mail me, sign in), and the two
316
- * could only ever disagree — a machine scanning on a timer with nothing to
317
- * report it to is a feature that looks on and does nothing visible. The
318
- * reason to put a scan on a timer is to be TOLD, so scheduling and mailing
319
- * are the same decision and take the same switch.
320
- *
321
- * A signed-out machine with this on is therefore a real, expected state
322
- * rather than a contradiction: it keeps scanning and keeps its local
323
- * dashboard current, and the UI says "signed out" until somebody signs back
324
- * in. Auth gates SETTING it up, never the machine's ongoing work — a
325
- * refresh token expiring must not silently switch off a background feature
326
- * somebody configured months ago.
315
+ * A signed-out machine with this on is therefore the normal local-only
316
+ * state rather than a contradiction: it keeps scanning, keeps its local
317
+ * dashboard current, and raises desktop notifications for credential leaks.
318
+ * A refresh token expiring must not silently switch off a background
319
+ * security feature.
327
320
  *
328
321
  * ON for a configured machine that has never stated an opinion, OFF for
329
322
  * every machine we could not read an opinion from — which is not the same
@@ -345,9 +338,9 @@ export interface FpConfig {
345
338
  * agree, or the settings page describes a machine that is doing something
346
339
  * else.
347
340
  *
348
- * Turning it on sends NOTHING on its own: the digest is gated on
349
- * `reportsConsentedAt` below, not on this switch, so a machine that flips
350
- * on at upgrade scans locally and mails nobody.
341
+ * Turning it on sends nothing remotely on its own. Email requires a valid
342
+ * identity in `audit/session.json`; without one, scans and notifications
343
+ * remain fully local.
351
344
  */
352
345
  auto: boolean;
353
346
  /**
@@ -358,40 +351,22 @@ export interface FpConfig {
358
351
  * wants the scan and not the banner is a coherent person, and without this
359
352
  * their only way to stop the banner is to stop the scan.
360
353
  *
361
- * ON by default, and the direction is the point: this fires at most once
362
- * per distinct credential ever (`leak-notice.ts` claims each finding with
363
- * an O_EXCL marker), so the volume it can reach is bounded by how many
364
- * secrets are actually leaking. A silent default would make the common
365
- * case — a user who never opens the dashboard and never gave an email —
366
- * a machine that finds the key and tells nobody.
354
+ * ON by default. Every scheduled scan that still sees a leak may notify,
355
+ * which keeps a credential that remains exposed from disappearing after
356
+ * its first alert. A silent default would make the common case — a user who
357
+ * never opens the dashboard and never gave an email — a machine that finds
358
+ * the key and tells nobody.
367
359
  *
368
- * It does NOT silence the in-CLI notice. That one appears inside a session
369
- * the user is already driving, costs two lines, and is the only channel
370
- * left when there is no desktop to notify — a headless box, a container, an
371
- * SSH session. Turning off every channel at once is not an option this
372
- * offers, because the resulting state is indistinguishable from broken.
360
+ * On a headless box, container or SSH-only session there may be no desktop
361
+ * server to receive the banner. The scheduled scan still completes and
362
+ * records its result; notification failure never changes the scan outcome.
373
363
  */
374
364
  notify: boolean;
375
365
  /**
376
- * When this machine's owner agreed that a scheduled scan may send what it
377
- * finds off the box, as epoch ms. Absent means they never did.
378
- *
379
- * This does NOT reintroduce the second switch the comment above rejects,
380
- * and it is never drawn as one. `auto` is what a person sets; this is a
381
- * record of the disclosure they were shown when they set it. The two cannot
382
- * drift, because every path that turns `auto` on stamps this in the same
383
- * call and nothing stamps it alone.
384
- *
385
- * It exists because `auto` CHANGED MEANING. Through 1.0.0 it meant "scan
386
- * this machine on a timer" and nothing more — no account, no network, and
387
- * the toggle that wrote it said as much in as many words. Harm digests gave
388
- * the same stored bit a second job: uploading redacted transcript excerpts
389
- * to the api-server and mailing them. Without a separate record, every
390
- * machine that opted into the old meaning would have started sending on
391
- * upgrade, having agreed to nothing of the kind, with the only notice a
392
- * line in the journal. Gating on the stamp rather than the switch is what
393
- * keeps that upgrade silent in the safe direction: those machines keep
394
- * scanning locally and send nothing until somebody opts in again.
366
+ * Legacy migration marker from the earlier harm-digest consent model.
367
+ * Retained when reading and writing old configs so upgrades are lossless,
368
+ * but it no longer gates scheduling or credential-alert email. A verified
369
+ * email identity is now the delivery opt-in.
395
370
  */
396
371
  reportsConsentedAt?: number;
397
372
  /** Days between scheduled runs. Wall clock, so it survives suspend. */
@@ -587,8 +562,8 @@ export function projectConfig(parsed: Record<string, unknown>): FpConfig {
587
562
  // question is only whether to speak.
588
563
  notify: audit.notify !== false,
589
564
  intervalDays: readIntervalDays(audit.interval_days),
590
- // A finite number or nothing. A garbage value reads as absent, which is
591
- // the direction that sends nothing.
565
+ // Preserve the legacy marker when it is valid; current behavior does
566
+ // not consult it.
592
567
  reportsConsentedAt:
593
568
  typeof audit.reports_consented_at === "number" &&
594
569
  Number.isFinite(audit.reports_consented_at)
@@ -738,7 +713,8 @@ export function writeConfig(config: FpConfig, raw?: Record<string, unknown>): vo
738
713
  ...(config.telemetry.enabled ? {} : { telemetry: { enabled: false } }),
739
714
  // Written ALWAYS, unlike telemetry directly above — the two are opposites
740
715
  // on purpose. Telemetry ships on and is deliberately not advertised;
741
- // the scheduled audit ships off and is meant to be FOUND, and a switch
716
+ // the scheduled audit is configured during setup and is meant to be FOUND,
717
+ // and a switch
742
718
  // nobody can see is the same as a switch that does not exist. Emitting both
743
719
  // keys unconditionally also makes "a user's setting survives a rewrite"
744
720
  // total rather than conditional.
@@ -749,9 +725,8 @@ export function writeConfig(config: FpConfig, raw?: Record<string, unknown>): vo
749
725
  // exists to be found by somebody the banner annoyed.
750
726
  notify: config.audit.notify,
751
727
  interval_days: config.audit.intervalDays,
752
- // Written only once there IS consent, so an untouched machine's config
753
- // does not grow a key implying it was asked. It is in
754
- // `OWNED_CONFIG_KEYS`, so omitting it here really removes it.
728
+ // Preserve the legacy consent marker when present. It is not used by the
729
+ // current local-schedule + optional-email model.
755
730
  ...(config.audit.reportsConsentedAt === undefined
756
731
  ? {}
757
732
  : { reports_consented_at: config.audit.reportsConsentedAt }),
@@ -35,8 +35,6 @@ import { loadAllCustomHooks } from "./custom-hooks-loader";
35
35
  import type { CustomHook } from "./policy-types";
36
36
  import { persistHookActivity } from "./hook-activity-store";
37
37
  import { deliveryHealth, deliveryHealthLine } from "./delivery-health";
38
- import { shapeNotice, canDeliverNotice, leakNoticeText } from "./notice";
39
- import { pendingLeakNotice, markLeakNoticeDelivered } from "../audit/leak-notice";
40
38
  import { trackHookEvent, flushHookTelemetry } from "./hook-telemetry";
41
39
  import { resolveCwd } from "./resolve-cwd";
42
40
  import { resolvePermissionMode } from "./resolve-permission-mode";
@@ -106,48 +104,6 @@ export interface HookEventOutcome {
106
104
  stderr: string;
107
105
  }
108
106
 
109
- /**
110
- * Merge a pending leak notice into an outcome, once.
111
- *
112
- * Anchored on Stop wherever the host renders there, and SessionStart only where
113
- * it does not: Stop fires once per turn, AFTER the answer, so it never
114
- * interrupts what the user was reading — and at session open the background
115
- * scan may not have produced the finding yet.
116
- *
117
- * Every failure is swallowed. A courtesy message must never be the reason a
118
- * hook misbehaves, and the finding is on disk either way.
119
- */
120
- function attachLeakNotice(
121
- eventType: string,
122
- cli: IntegrationType | undefined,
123
- outcome: HookEventOutcome,
124
- ): HookEventOutcome {
125
- try {
126
- if (!canDeliverNotice(cli)) return outcome;
127
- // canDeliverNotice() above already proved cli is set; narrow for the call.
128
- if (!cli) return outcome;
129
- const canonical = canonicalizeEventType(eventType, cli);
130
- if (canonical !== "Stop" && canonical !== "SessionStart") return outcome;
131
-
132
- const pending = pendingLeakNotice();
133
- if (pending.count === 0) return outcome;
134
-
135
- const shaped = shapeNotice(cli, leakNoticeText(pending.count), outcome.stdout);
136
- if (shaped.stdout === outcome.stdout && !shaped.stderr) return outcome;
137
-
138
- // Claimed only once the notice is actually on the stream, so a crash
139
- // between the two re-notifies rather than silently swallowing the alert.
140
- markLeakNoticeDelivered(pending.ids);
141
- return {
142
- exitCode: outcome.exitCode,
143
- stdout: shaped.stdout,
144
- stderr: outcome.stderr + shaped.stderr,
145
- };
146
- } catch {
147
- return outcome;
148
- }
149
- }
150
-
151
107
  export interface EvaluateHookEventOptions {
152
108
  /**
153
109
  * Await pending telemetry POSTs before returning. Defaults to `true`,
@@ -801,21 +757,7 @@ export async function evaluateHookEvent(
801
757
  }
802
758
  }
803
759
 
804
- // Attach a pending leak notice, if this event is one that can carry it.
805
- //
806
- // Emitted HERE rather than in `handleHookEvent`, which is what fixes the
807
- // bug this replaced: `bin/failproofai.mjs`'s `isDaemonConfigured()` branch
808
- // writes `result.stdout`/`result.stderr` and EXITS INSIDE THAT BRANCH — it
809
- // never falls through to `handleHookEvent`. Setup requires the daemon, so
810
- // the previous notice was dead code on every configured machine, and had
811
- // been since it shipped. Both paths return this object, so producing the
812
- // notice here reaches both with no change to either caller.
813
- const withNotice = attachLeakNotice(eventType, cli, {
814
- exitCode: result.exitCode,
815
- stdout: result.stdout,
816
- stderr: result.stderr,
817
- });
818
- return withNotice;
760
+ return { exitCode: result.exitCode, stdout: result.stdout, stderr: result.stderr };
819
761
  } finally {
820
762
  if (opts?.awaitTelemetryFlush ?? true) {
821
763
  // Await any un-awaited (`void trackHookEvent(...)`) events fired during
@@ -1011,7 +1011,10 @@ export default async function failproofaiPlugin({ client, directory }) {
1011
1011
  const claudeEvent = BUS_EVENT_MAP[event.type];
1012
1012
  if (!claudeEvent) return;
1013
1013
  const props = event.properties || {};
1014
- const sessionID = props.sessionID || (props.session && props.session.id) || props.id;
1014
+ const info = props.info || props.session || {};
1015
+
1016
+ const sessionID = info.id || info.sessionID || info.sessionId || info.session_id ||
1017
+ props.sessionID || props.sessionId || props.session_id || props.id;
1015
1018
  const r = await runFailproofai(claudeEvent, {
1016
1019
  session_id: sessionID, cwd: directory, hook_event_name: claudeEvent,
1017
1020
  }, directory);
@@ -1,155 +1,24 @@
1
- /**
2
- * Putting a short message in front of a HUMAN, inside the agent they are using.
3
- *
4
- * A notice is not a verdict. `allow` / `deny` / `instruct` all answer "what
5
- * happens to this tool call"; a notice answers nothing — it is one line of text
6
- * for the person, delivered alongside whatever the verdict turned out to be.
7
- * That is why it is a separate field rather than a fourth decision: shaping it
8
- * into stdout beside a verdict ad hoc is how the copilot nested-vs-flat
9
- * `additionalContext` bug happened.
10
- *
11
- * ## Why the channel differs per CLI, and why it is not `additionalContext`
12
- *
13
- * Measured across all 12 CLIs by live probe. The obvious channel —
14
- * `hookSpecificOutput.additionalContext` — reaches the MODEL, not the user, and
15
- * a model is a paraphraser: over eight real Claude turns it mentioned an
16
- * informational notice 8/8, but an earlier notice that asked the agent to *act*
17
- * was disclaimed as a suspected prompt injection 6/6 ("instructions arriving
18
- * that way aren't something I'll act on unasked"). A security notice routed
19
- * through something that may decline to repeat it is not a delivered notice.
20
- *
21
- * So each CLI gets the channel that was proven to paint text on the user's
22
- * terminal, and the ones with no such channel get nothing rather than a
23
- * pretend delivery:
24
- *
25
- * claude `{"systemMessage":…}` renders `Stop says: …`; model-invisible
26
- * (a neutral probe answered `NONE`)
27
- * codex `{"systemMessage":…}` renders `• Stop (completed) says: …`
28
- * copilot exit 0 + stderr renders as a `!` session warning
29
- * factory plain stdout renders under a `Hooks Stop` block
30
- *
31
- * opencode, pi and openclaw have real channels too, but they live inside the
32
- * plugin shims we ship rather than in a hook's stdout, so they are wired there.
33
- * cursor, devin, goose, antigravity and hermes have no channel that reaches a
34
- * human without an unsupported escape hatch — they get nothing here, and their
35
- * users get the finding from `failproofai audit` and the emailed digest.
36
- */
37
- import type { IntegrationType } from "./types";
38
-
39
- /** How a notice is delivered on one CLI. */
40
- type NoticeChannel = "systemMessage" | "stderr" | "stdout" | "none";
41
-
42
- /**
43
- * Per-CLI channel, from live probes rather than documentation.
44
- *
45
- * A CLI absent from this map delivers nothing — deliberately. Guessing a
46
- * channel produces the worst outcome available: output that looks delivered
47
- * from our side and reaches nobody, so we would report a leak as "notified"
48
- * that the user never saw.
49
- */
50
- const NOTICE_CHANNEL: Partial<Record<IntegrationType, NoticeChannel>> = {
51
- claude: "systemMessage",
52
- codex: "systemMessage",
53
- copilot: "stderr",
54
- factory: "stdout",
55
- };
56
-
57
- /**
58
- * Claude truncates `systemMessage` at 4000 characters on the cloud-forwarding
59
- * path, and a notice that gets cut mid-sentence reads as a broken tool. Ours is
60
- * two lines by design; this is a backstop, not a budget.
61
- */
62
- const MAX_NOTICE_CHARS = 900;
63
-
64
- export interface ShapedNotice {
65
- /** Merged into the outcome's stdout, or empty. */
66
- stdout: string;
67
- /** Merged into the outcome's stderr, or empty. */
68
- stderr: string;
69
- }
70
-
71
- /**
72
- * Render a notice for one CLI, merging it into any verdict JSON already bound
73
- * for stdout.
74
- *
75
- * `existingStdout` matters: a Stop-gate deny already emits a JSON object on
76
- * several CLIs, and emitting a second object would produce two JSON documents
77
- * on one stream — which every host parses as a syntax error and drops, taking
78
- * the deny with it. So the notice is merged INTO that object when there is one.
79
- */
80
- export function shapeNotice(
81
- cli: IntegrationType | undefined,
82
- notice: string,
83
- existingStdout = "",
84
- ): ShapedNotice {
85
- const empty: ShapedNotice = { stdout: existingStdout, stderr: "" };
86
- if (!notice.trim() || !cli) return empty;
87
-
88
- const channel = NOTICE_CHANNEL[cli] ?? "none";
89
- const text = notice.length > MAX_NOTICE_CHARS
90
- ? notice.slice(0, MAX_NOTICE_CHARS - 1) + "…"
91
- : notice;
92
-
93
- switch (channel) {
94
- case "systemMessage": {
95
- // Merge into the verdict object when one exists, so the stream stays a
96
- // single JSON document.
97
- if (existingStdout.trim().startsWith("{")) {
98
- try {
99
- const parsed = JSON.parse(existingStdout) as Record<string, unknown>;
100
- parsed.systemMessage = text;
101
- return { stdout: JSON.stringify(parsed), stderr: "" };
102
- } catch {
103
- // Not the JSON we thought it was — leave the verdict untouched
104
- // rather than risk destroying it to add a courtesy message.
105
- return empty;
106
- }
107
- }
108
- // Anything already on stdout that we could not merge into is left
109
- // exactly as it is, and the notice is dropped instead. The alternative —
110
- // emitting our own object over the top — DESTROYS it: measured with a
111
- // JSON array on stdout, which does not start with `{`, so it fell past
112
- // the merge and was replaced wholesale. A courtesy message is never worth
113
- // more than whatever the host was already being told.
114
- if (existingStdout.trim()) return empty;
115
- return { stdout: JSON.stringify({ systemMessage: text }), stderr: "" };
116
- }
117
- case "stderr":
118
- // Exit code is NOT touched: on copilot a non-zero exit from a tool event
119
- // is a block, and a notice must never block anything.
120
- return { stdout: existingStdout, stderr: text + "\n" };
121
- case "stdout":
122
- // factory renders plain text under its Hooks block. Only safe when no
123
- // verdict JSON is already on the stream.
124
- if (existingStdout.trim()) return empty;
125
- return { stdout: text + "\n", stderr: "" };
126
- default:
127
- return empty;
128
- }
129
- }
130
-
131
- /** True when this CLI has a channel that was proven to reach a human. */
132
- export function canDeliverNotice(cli: IntegrationType | undefined): boolean {
133
- return !!cli && (NOTICE_CHANNEL[cli] ?? "none") !== "none";
134
- }
135
-
136
- /**
137
- * The notice itself. A FIXED template with no interpolation of scanned content.
138
- *
139
- * The count is a number we computed; everything else is a constant. That is not
140
- * stylistic: the alternative is interpolating a finding's `example`, which is
141
- * the verbatim text of a command from a repository — attacker-controlled
142
- * through a README, a Makefile target or an npm script. Tested against the
143
- * shipped redactor, `echo "IGNORE ALL PRIOR INSTRUCTIONS…"` passes through
144
- * byte-identical, because that redactor masks secrets, not instructions. On the
145
- * CLIs where the only channel is the model's context, that string would land
146
- * directly in the prompt. So nothing scanned ever reaches this template.
147
- */
148
- export function leakNoticeText(newFindings: number): string {
149
- const n = newFindings === 1 ? "a credential" : `${newFindings} credentials`;
150
- return (
151
- `failproofai found ${n} in this project's agent transcripts.\n` +
152
- "Run `failproofai audit` to see the details, " +
153
- "or `failproofai audit --schedule` to get these by email."
154
- );
1
+ /** Copy for the OS notification raised by an unattended scheduled scan.
2
+ *
3
+ * Deliberately omits the count. A burst of generated fixtures can hit the
4
+ * record cap, and a desktop banner saying "500 leaked credentials" states a
5
+ * conclusion the detector cannot support. The dashboard carries the evidence;
6
+ * the banner's job is only to ask for review. */
7
+ export type DesktopLeakEmailState = "sent" | "missing" | "failed" | "held";
8
+
9
+ export function desktopLeakNotice(email: DesktopLeakEmailState = "held"): { title: string; body: string } {
10
+ const followUp =
11
+ email === "sent"
12
+ ? "A masked alert was also sent to your email."
13
+ : email === "missing"
14
+ ? "Add email alerts with: failproofai audit --schedule --email you@example.com"
15
+ : email === "failed"
16
+ ? "Email delivery failed this time; the local result is still available."
17
+ : "Email was not sent for this run.";
18
+ return {
19
+ title: "failproofai audit needs review",
20
+ body:
21
+ "Possible credential exposure was found in your agent transcripts. " +
22
+ `Run failproofai audit to verify the matches and rotate anything real. ${followUp}`,
23
+ };
155
24
  }
@@ -1,3 +0,0 @@
1
- module.exports=[18622,(a,b,c)=>{b.exports=a.x("next/dist/compiled/next-server/app-page-turbo.runtime.prod.js",()=>require("next/dist/compiled/next-server/app-page-turbo.runtime.prod.js"))},20635,(a,b,c)=>{b.exports=a.x("next/dist/server/app-render/action-async-storage.external.js",()=>require("next/dist/server/app-render/action-async-storage.external.js"))},24725,(a,b,c)=>{b.exports=a.x("next/dist/server/app-render/after-task-async-storage.external.js",()=>require("next/dist/server/app-render/after-task-async-storage.external.js"))},43285,(a,b,c)=>{b.exports=a.x("next/dist/server/app-render/dynamic-access-async-storage.external.js",()=>require("next/dist/server/app-render/dynamic-access-async-storage.external.js"))},56704,(a,b,c)=>{b.exports=a.x("next/dist/server/app-render/work-async-storage.external.js",()=>require("next/dist/server/app-render/work-async-storage.external.js"))},32319,(a,b,c)=>{b.exports=a.x("next/dist/server/app-render/work-unit-async-storage.external.js",()=>require("next/dist/server/app-render/work-unit-async-storage.external.js"))},59043,(a,b,c)=>{b.exports=a.x("next/dist/server/runtime-reacts.external.js",()=>require("next/dist/server/runtime-reacts.external.js"))},1355,a=>{"use strict";var b=a.i(5050);let c=(0,b.createServerReference)("000ae5b9f039195740b0697383b66ef36475abe12d",b.callServer,void 0,b.findSourceMapURL,"getTelemetryConfig");a.s(["getTelemetryConfig",0,c])},3171,a=>{"use strict";var b=a.i(87924),c=a.i(72131),d=a.i(1355),e=a.i(66036);a.s(["default",0,function({error:a,reset:f}){return(0,c.useEffect)(()=>{(0,d.getTelemetryConfig)().then(b=>{(0,e.setClientTelemetryConfig)(b),(0,e.captureClientEvent)("client_error",{error_message:a.message,error_name:a.name,error_digest:a.digest,boundary:"global"})}).catch(()=>{})},[a]),(0,b.jsx)("html",{children:(0,b.jsx)("body",{children:(0,b.jsx)("main",{style:{minHeight:"100vh",display:"flex",alignItems:"center",justifyContent:"center",background:"#031035",color:"#f8fafc",fontFamily:"system-ui, sans-serif"},children:(0,b.jsxs)("div",{style:{textAlign:"center",padding:"2rem",border:"1px solid rgba(239,68,68,0.4)",borderRadius:"0.5rem",maxWidth:"500px"},children:[(0,b.jsx)("h2",{style:{color:"#ef4444",marginBottom:"0.5rem",fontSize:"1.25rem"},children:"Something went wrong"}),(0,b.jsx)("p",{style:{color:"#94a3b8",marginBottom:"1.5rem"},children:a.message||"An unexpected error occurred."}),(0,b.jsx)("button",{onClick:f,style:{padding:"0.5rem 1.25rem",background:"#3b82f6",color:"white",border:"none",borderRadius:"0.375rem",cursor:"pointer",fontSize:"0.875rem"},children:"Try again"})]})})})})}])},66036,a=>{"use strict";a.s(["captureClientEvent",0,function(a,b){},"setClientTelemetryConfig",0,function(a){}])},46058,(a,b,c)=>{"use strict";function d(a){if("function"!=typeof WeakMap)return null;var b=new WeakMap,c=new WeakMap;return(d=function(a){return a?c:b})(a)}c._=function(a,b){if(!b&&a&&a.__esModule)return a;if(null===a||"object"!=typeof a&&"function"!=typeof a)return{default:a};var c=d(b);if(c&&c.has(a))return c.get(a);var e={__proto__:null},f=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var g in a)if("default"!==g&&Object.prototype.hasOwnProperty.call(a,g)){var h=f?Object.getOwnPropertyDescriptor(a,g):null;h&&(h.get||h.set)?Object.defineProperty(e,g,h):e[g]=a[g]}return e.default=a,c&&c.set(a,e),e}},5050,(a,b,c)=>{"use strict";Object.defineProperty(c,"__esModule",{value:!0});var d={callServer:function(){return f.callServer},createServerReference:function(){return h.createServerReference},findSourceMapURL:function(){return g.findSourceMapURL}};for(var e in d)Object.defineProperty(c,e,{enumerable:!0,get:d[e]});let f=a.r(20611),g=a.r(1722),h=a.r(38783)},20611,(a,b,c)=>{"use strict";Object.defineProperty(c,"__esModule",{value:!0}),Object.defineProperty(c,"callServer",{enumerable:!0,get:function(){return g}});let d=a.r(72131),e=a.r(88347),f=a.r(90841);async function g(a,b){return new Promise((c,g)=>{(0,d.startTransition)(()=>{(0,f.dispatchAppRouterAction)({type:e.ACTION_SERVER_ACTION,actionId:a,actionArgs:b,resolve:c,reject:g})})})}("function"==typeof c.default||"object"==typeof c.default&&null!==c.default)&&void 0===c.default.__esModule&&(Object.defineProperty(c.default,"__esModule",{value:!0}),Object.assign(c.default,c),b.exports=c.default)},1722,(a,b,c)=>{"use strict";let d;Object.defineProperty(c,"__esModule",{value:!0}),Object.defineProperty(c,"findSourceMapURL",{enumerable:!0,get:function(){return d}});("function"==typeof c.default||"object"==typeof c.default&&null!==c.default)&&void 0===c.default.__esModule&&(Object.defineProperty(c.default,"__esModule",{value:!0}),Object.assign(c.default,c),b.exports=c.default)},88347,(a,b,c)=>{"use strict";Object.defineProperty(c,"__esModule",{value:!0});var d,e,f={ACTION_HMR_REFRESH:function(){return l},ACTION_NAVIGATE:function(){return i},ACTION_REFRESH:function(){return h},ACTION_RESTORE:function(){return j},ACTION_SERVER_ACTION:function(){return m},ACTION_SERVER_PATCH:function(){return k},PrefetchKind:function(){return n},ScrollBehavior:function(){return o}};for(var g in f)Object.defineProperty(c,g,{enumerable:!0,get:f[g]});let h="refresh",i="navigate",j="restore",k="server-patch",l="hmr-refresh",m="server-action";var n=((d={}).AUTO="auto",d.FULL="full",d),o=((e={})[e.Default=0]="Default",e[e.NoScroll=1]="NoScroll",e);("function"==typeof c.default||"object"==typeof c.default&&null!==c.default)&&void 0===c.default.__esModule&&(Object.defineProperty(c.default,"__esModule",{value:!0}),Object.assign(c.default,c),b.exports=c.default)},90841,(a,b,c)=>{"use strict";Object.defineProperty(c,"__esModule",{value:!0});var d={dispatchAppRouterAction:function(){return i},dispatchGestureState:function(){return j},refreshOnInstantNavigationUnlock:function(){return h},useActionQueue:function(){return k}};for(var e in d)Object.defineProperty(c,e,{enumerable:!0,get:d[e]});let f=a.r(46058)._(a.r(72131)),g=a.r(67009);a.r(88347);function h(){}function i(a){!0;throw Object.defineProperty(Error("Internal Next.js error: Router action dispatched before initialization."),"__NEXT_ERROR_CODE",{value:"E668",enumerable:!1,configurable:!0})}function j(a){!0;throw Object.defineProperty(Error("Internal Next.js error: Router action dispatched before initialization."),"__NEXT_ERROR_CODE",{value:"E668",enumerable:!1,configurable:!0})}function k(a){let[b,c]=f.default.useState(a.state),[d,e]=(0,f.useOptimistic)(b),h=(0,f.useMemo)(()=>d,[d]);return(0,g.isThenable)(h)?(0,f.use)(h):h}("function"==typeof c.default||"object"==typeof c.default&&null!==c.default)&&void 0===c.default.__esModule&&(Object.defineProperty(c.default,"__esModule",{value:!0}),Object.assign(c.default,c),b.exports=c.default)},42602,(a,b,c)=>{"use strict";b.exports=a.r(18622)},9270,(a,b,c)=>{"use strict";b.exports=a.r(42602).vendored.contexts.AppRouterContext},36313,(a,b,c)=>{"use strict";b.exports=a.r(42602).vendored.contexts.HooksClientContext},18341,(a,b,c)=>{"use strict";b.exports=a.r(42602).vendored.contexts.ServerInsertedHtml},35112,(a,b,c)=>{"use strict";b.exports=a.r(42602).vendored["react-ssr"].ReactDOM},87924,(a,b,c)=>{"use strict";b.exports=a.r(42602).vendored["react-ssr"].ReactJsxRuntime},38783,(a,b,c)=>{"use strict";b.exports=a.r(42602).vendored["react-ssr"].ReactServerDOMTurbopackClient},72131,(a,b,c)=>{"use strict";b.exports=a.r(42602).vendored["react-ssr"].React},67009,(a,b,c)=>{"use strict";function d(a){return null!==a&&"object"==typeof a&&"then"in a&&"function"==typeof a.then}Object.defineProperty(c,"__esModule",{value:!0}),Object.defineProperty(c,"isThenable",{enumerable:!0,get:function(){return d}})}];
2
-
3
- //# sourceMappingURL=%5Broot-of-the-server%5D__0rgu2r3._.js.map
@@ -1,23 +0,0 @@
1
- module.exports=[1355,a=>{"use strict";var b=a.i(5050);let c=(0,b.createServerReference)("000ae5b9f039195740b0697383b66ef36475abe12d",b.callServer,void 0,b.findSourceMapURL,"getTelemetryConfig");a.s(["getTelemetryConfig",0,c])},18952,a=>{"use strict";var b=a.i(87924),c=a.i(72131);let d=[],e=0,f=new Set;function g(){for(let a of f)a()}function h(a){return f.add(a),()=>f.delete(a)}function i(){return d}function j({message:a}){let[d,e]=(0,c.useState)(!1);return(0,c.useEffect)(()=>{requestAnimationFrame(()=>e(!0));let a=setTimeout(()=>e(!1),2e3);return()=>clearTimeout(a)},[]),(0,b.jsx)("div",{className:`bg-card border border-border text-foreground text-sm px-4 py-2 rounded-lg shadow-lg transition-opacity duration-300 ${d?"opacity-100":"opacity-0"}`,children:a})}a.s(["Toaster",0,function(){let a=(0,c.useSyncExternalStore)(h,i,i);return(0,b.jsx)("div",{className:"fixed bottom-4 right-4 z-50 flex flex-col gap-2",children:a.map(a=>(0,b.jsx)(j,{message:a.message},a.id))})},"toast",0,function(a){let b=e++;d=[...d,{id:b,message:a}],g(),setTimeout(()=>{d=d.filter(a=>a.id!==b),g()},2500)}])},10765,a=>{"use strict";var b=a.i(87924),c=a.i(72131),d=a.i(50944),e=a.i(1355),f=a.i(66036);let g=(0,c.createContext)(void 0);a.s(["PostHogProvider",0,function({children:a}){let h=(0,d.usePathname)(),i=(0,c.useRef)(null),j=(0,c.useRef)(!1);(0,c.useEffect)(()=>{let a=!1;return(0,e.getTelemetryConfig)().then(b=>{a||((0,f.setClientTelemetryConfig)(b),j.current=!0,(0,f.captureClientEvent)("$pageview"),i.current=window.location.pathname)}),()=>{a=!0}},[]),(0,c.useEffect)(()=>{j.current&&i.current!==h&&(i.current=h,(0,f.captureClientEvent)("$pageview"))},[h]);let k=c.default.useCallback((a,b)=>{(0,f.captureClientEvent)(a,b)},[]);return(0,b.jsx)(g.Provider,{value:{capture:k},children:a})},"usePostHog",0,function(){let a=(0,c.useContext)(g);if(void 0===a)throw Error("usePostHog must be used within a PostHogProvider");return a}])},66036,a=>{"use strict";a.s(["captureClientEvent",0,function(a,b){},"setClientTelemetryConfig",0,function(a){}])},46058,(a,b,c)=>{"use strict";function d(a){if("function"!=typeof WeakMap)return null;var b=new WeakMap,c=new WeakMap;return(d=function(a){return a?c:b})(a)}c._=function(a,b){if(!b&&a&&a.__esModule)return a;if(null===a||"object"!=typeof a&&"function"!=typeof a)return{default:a};var c=d(b);if(c&&c.has(a))return c.get(a);var e={__proto__:null},f=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var g in a)if("default"!==g&&Object.prototype.hasOwnProperty.call(a,g)){var h=f?Object.getOwnPropertyDescriptor(a,g):null;h&&(h.get||h.set)?Object.defineProperty(e,g,h):e[g]=a[g]}return e.default=a,c&&c.set(a,e),e}},5050,(a,b,c)=>{"use strict";Object.defineProperty(c,"__esModule",{value:!0});var d={callServer:function(){return f.callServer},createServerReference:function(){return h.createServerReference},findSourceMapURL:function(){return g.findSourceMapURL}};for(var e in d)Object.defineProperty(c,e,{enumerable:!0,get:d[e]});let f=a.r(20611),g=a.r(1722),h=a.r(38783)},20611,(a,b,c)=>{"use strict";Object.defineProperty(c,"__esModule",{value:!0}),Object.defineProperty(c,"callServer",{enumerable:!0,get:function(){return g}});let d=a.r(72131),e=a.r(88347),f=a.r(90841);async function g(a,b){return new Promise((c,g)=>{(0,d.startTransition)(()=>{(0,f.dispatchAppRouterAction)({type:e.ACTION_SERVER_ACTION,actionId:a,actionArgs:b,resolve:c,reject:g})})})}("function"==typeof c.default||"object"==typeof c.default&&null!==c.default)&&void 0===c.default.__esModule&&(Object.defineProperty(c.default,"__esModule",{value:!0}),Object.assign(c.default,c),b.exports=c.default)},1722,(a,b,c)=>{"use strict";let d;Object.defineProperty(c,"__esModule",{value:!0}),Object.defineProperty(c,"findSourceMapURL",{enumerable:!0,get:function(){return d}});("function"==typeof c.default||"object"==typeof c.default&&null!==c.default)&&void 0===c.default.__esModule&&(Object.defineProperty(c.default,"__esModule",{value:!0}),Object.assign(c.default,c),b.exports=c.default)},88347,(a,b,c)=>{"use strict";Object.defineProperty(c,"__esModule",{value:!0});var d,e,f={ACTION_HMR_REFRESH:function(){return l},ACTION_NAVIGATE:function(){return i},ACTION_REFRESH:function(){return h},ACTION_RESTORE:function(){return j},ACTION_SERVER_ACTION:function(){return m},ACTION_SERVER_PATCH:function(){return k},PrefetchKind:function(){return n},ScrollBehavior:function(){return o}};for(var g in f)Object.defineProperty(c,g,{enumerable:!0,get:f[g]});let h="refresh",i="navigate",j="restore",k="server-patch",l="hmr-refresh",m="server-action";var n=((d={}).AUTO="auto",d.FULL="full",d),o=((e={})[e.Default=0]="Default",e[e.NoScroll=1]="NoScroll",e);("function"==typeof c.default||"object"==typeof c.default&&null!==c.default)&&void 0===c.default.__esModule&&(Object.defineProperty(c.default,"__esModule",{value:!0}),Object.assign(c.default,c),b.exports=c.default)},90841,(a,b,c)=>{"use strict";Object.defineProperty(c,"__esModule",{value:!0});var d={dispatchAppRouterAction:function(){return i},dispatchGestureState:function(){return j},refreshOnInstantNavigationUnlock:function(){return h},useActionQueue:function(){return k}};for(var e in d)Object.defineProperty(c,e,{enumerable:!0,get:d[e]});let f=a.r(46058)._(a.r(72131)),g=a.r(67009);a.r(88347);function h(){}function i(a){!0;throw Object.defineProperty(Error("Internal Next.js error: Router action dispatched before initialization."),"__NEXT_ERROR_CODE",{value:"E668",enumerable:!1,configurable:!0})}function j(a){!0;throw Object.defineProperty(Error("Internal Next.js error: Router action dispatched before initialization."),"__NEXT_ERROR_CODE",{value:"E668",enumerable:!1,configurable:!0})}function k(a){let[b,c]=f.default.useState(a.state),[d,e]=(0,f.useOptimistic)(b),h=(0,f.useMemo)(()=>d,[d]);return(0,g.isThenable)(h)?(0,f.use)(h):h}("function"==typeof c.default||"object"==typeof c.default&&null!==c.default)&&void 0===c.default.__esModule&&(Object.defineProperty(c.default,"__esModule",{value:!0}),Object.assign(c.default,c),b.exports=c.default)},14827,(a,b,c)=>{"use strict";Object.defineProperty(c,"__esModule",{value:!0});var d={createLinkPrefetchPartialError:function(){return g},createUnrenderedSegmentError:function(){return f}};for(var e in d)Object.defineProperty(c,e,{enumerable:!0,get:d[e]});function f(a,b){let c=`Route "${a}": Could not validate that a segment in your UI has instant navigation.`;if(b.length>0){let a=1===b.length?"Dropped segment":"Dropped segments";c+=`
2
-
3
- This segment was dropped from rendering. Issues that would prevent instant navigation will go undetected.
4
-
5
- ${a}:
6
- ${b.map(a=>` ${a}`).join("\n")}
7
-
8
- Ways to fix this:
9
- - [render] Render the dropped segment
10
- - [ignore] Set \`export const instant = false\` to opt the dropped segment out of instant-navigation validation
11
-
12
- Learn more: https://nextjs.org/docs/messages/instant-unrendered-segment`}return Object.defineProperty(Error(c),"__NEXT_ERROR_CODE",{value:"E1286",enumerable:!1,configurable:!0})}function g(a){return Object.defineProperty(Error(`Next.js encountered dynamic data during prefetching for "${a}".
13
-
14
- This will lead to slower, more expensive prefetches.
15
-
16
- Ways to fix this:
17
- - [upgrade] Opt into Partial Prefetching by exporting \`const prefetch = 'partial'\` from the page or layout, or by setting \`partialPrefetching: true\` in next.config to opt the whole app in
18
- - [disable] Remove \`prefetch={true}\` from the <Link> to use the default prefetch
19
- - [ignore] Set \`export const instant = false\` to opt the route out of instant-navigation validation
20
-
21
- Learn more: https://nextjs.org/docs/messages/instant-link-prefetch-partial`),"__NEXT_ERROR_CODE",{value:"E1435",enumerable:!1,configurable:!0})}},88644,(a,b,c)=>{"use strict";Object.defineProperty(c,"__esModule",{value:!0}),Object.defineProperty(c,"InvariantError",{enumerable:!0,get:function(){return d}});class d extends Error{constructor(a,b){super(`Invariant: ${a.endsWith(".")?a:a+"."} This is a bug in Next.js.`,b),Object.defineProperty(this,"__NEXT_ERROR_CODE",{value:"E1179",enumerable:!1,configurable:!0}),this.name="InvariantError"}}},67009,(a,b,c)=>{"use strict";function d(a){return null!==a&&"object"==typeof a&&"then"in a&&"function"==typeof a.then}Object.defineProperty(c,"__esModule",{value:!0}),Object.defineProperty(c,"isThenable",{enumerable:!0,get:function(){return d}})},41997,(a,b,c)=>{"use strict";Object.defineProperty(c,"__esModule",{value:!0});var d={BailoutToCSRError:function(){return g},isBailoutToCSRError:function(){return h}};for(var e in d)Object.defineProperty(c,e,{enumerable:!0,get:d[e]});let f="BAILOUT_TO_CLIENT_SIDE_RENDERING";class g extends Error{constructor(a){super(`Bail out to client-side rendering: ${a}`),this.reason=a,this.digest=f}}function h(a){return"object"==typeof a&&null!==a&&"digest"in a&&a.digest===f}},54427,(a,b,c)=>{"use strict";function d(){let a,b,c=new Promise((c,d)=>{a=c,b=d});return{resolve:a,reject:b,promise:c}}Object.defineProperty(c,"__esModule",{value:!0}),Object.defineProperty(c,"createPromiseWithResolvers",{enumerable:!0,get:function(){return d}})},39118,(a,b,c)=>{"use strict";Object.defineProperty(c,"__esModule",{value:!0});var d={DEFAULT_SEGMENT_KEY:function(){return l},NOT_FOUND_SEGMENT_KEY:function(){return m},PAGE_SEGMENT_KEY:function(){return k},addSearchParamsIfPageSegment:function(){return i},computeSelectedLayoutSegment:function(){return j},getSegmentValue:function(){return f},getSelectedLayoutSegmentPath:function(){return function a(b,c,d=!0,e=[]){let g;if(d)g=b[1][c];else{let a=b[1];g=a.children??Object.values(a)[0]}if(!g)return e;let h=f(g[0]);return!h||h.startsWith(k)?e:(e.push(h),a(g,c,!1,e))}},isGroupSegment:function(){return g},isParallelRouteSegment:function(){return h}};for(var e in d)Object.defineProperty(c,e,{enumerable:!0,get:d[e]});function f(a){return Array.isArray(a)?a[1]:a}function g(a){return"("===a[0]&&a.endsWith(")")}function h(a){return a.startsWith("@")&&"@children"!==a}function i(a,b){if(a.includes(k)){let a=JSON.stringify(b);return"{}"!==a?k+"?"+a:k}return a}function j(a,b){if(!a||0===a.length)return null;let c="children"===b?a[0]:a[a.length-1];return c===l?null:c}let k="__PAGE__",l="__DEFAULT__",m="/_not-found"}];
22
-
23
- //# sourceMappingURL=_0-oij9d._.js.map
@@ -1 +0,0 @@
1
- (globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,86616,29054,e=>{"use strict";function t(e,a={},s=15e3){let n=AbortSignal.timeout(s),i=a.signal?AbortSignal.any([a.signal,n]):n;return fetch(e,{...a,signal:i})}function a(e){if(null===e||"object"!=typeof e)return!1;let t=e.name;return"AbortError"===t||"TimeoutError"===t}e.s(["fetchWithTimeout",0,t,"isAbortError",0,a],29054);class s extends Error{kind;constructor(e,t){super(t),this.kind=e,this.name="RerunError"}}async function n(e){try{let a=await t("/api/audit/run",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({cli:e.cli.length>0?e.cli:void 0,since:"all"===e.since?void 0:e.since,noCache:!!e.noCache||void 0})});if(!a.ok&&409!==a.status){let e=await a.text().catch(()=>"");throw console.error("audit run failed:",a.status,e),new s("post_failed",`audit run failed (${a.status})`)}}catch(e){if(e instanceof s)throw e;throw console.error("audit run request failed:",e),new s(a(e)?"timeout":"network","audit run request failed")}let n=0;for(;;){await new Promise(e=>setTimeout(e,1e3));let e=null;try{let a=await t("/api/audit/status",{cache:"no-store"});a.ok&&(e=await a.json())}catch{}if(null===e){if(++n>=10)throw new s("network","audit status poll lost the server");continue}if(n=0,!e.running){if(e.error)throw new s("post_failed",e.error);return}}}e.s(["RerunError",0,s,"triggerRun",0,n],86616)},93237,e=>{"use strict";var t=e.i(43476),a=e.i(71645),s=e.i(95187);let n=(0,s.createServerReference)("00fba8e3afdca9169f059ee29f0a079b25dadd01d6",s.callServer,void 0,s.findSourceMapURL,"getScheduledAuditAction"),i=(0,s.createServerReference)("40c02d8b68c2c311ae947c910df0ffa7b94933324e",s.callServer,void 0,s.findSourceMapURL,"setAutoAuditAction"),r=(0,s.createServerReference)("409282b29dd0a877370c6bdc276c47c030e8308dce",s.callServer,void 0,s.findSourceMapURL,"setAuditIntervalAction");var l=e.i(86616),o=e.i(12344),c=e.i(29054);let d=/^[^\s@]+@[^\s@]+\.[^\s@]+$/;function u(e){if((0,c.isAbortError)(e))return"request timed out. check your network and try again.";let t=e instanceof Error?e.message:String(e);return`network error: ${t}`}function h({open:e,headline:s="where to route the reminder?",subhead:n="we'll send a one-time code to confirm.",onClose:i,onAuthed:r,source:l="unknown"}){let{capture:m}=(0,o.usePostHog)(),[f,b]=(0,a.useState)({kind:"email",error:null}),[p,x]=(0,a.useState)(!1),v=(0,a.useRef)(!1),g=(0,a.useRef)(null),y=(0,a.useRef)(null);(0,a.useEffect)(()=>{e&&(b({kind:"email",error:null}),x(!1),v.current=!1,m("audit_auth_dialog_opened",{source:l}))},[m,e,l]);let w=(0,a.useRef)(!1);(0,a.useEffect)(()=>{if(e){w.current=!0;return}w.current&&!v.current&&m("audit_auth_dialog_dismissed",{source:l,step:f.kind}),w.current=!1},[m,e,l,f.kind]),(0,a.useEffect)(()=>{if(!e)return;let t=setTimeout(()=>{"email"===f.kind?g.current?.focus():"code"===f.kind&&y.current?.focus()},50);return()=>clearTimeout(t)},[e,f.kind]),(0,a.useEffect)(()=>{if(!e)return;let t=e=>{"Escape"!==e.key||p||i()};return window.addEventListener("keydown",t),()=>window.removeEventListener("keydown",t)},[e,p,i]);let j="code"===f.kind&&f.resendIn>0;(0,a.useEffect)(()=>{if(!j)return;let e=setInterval(()=>{b(e=>"code"===e.kind?{...e,resendIn:Math.max(0,e.resendIn-1)}:e)},1e3);return()=>clearInterval(e)},[j]);let k=(0,a.useCallback)(async(e,t={})=>{let{isResend:a=!1}=t,s=e=>{a?b(t=>"code"===t.kind?{...t,error:e}:t):b({kind:"email",error:e})};x(!0);try{let t=await (0,c.fetchWithTimeout)("/api/auth/login-request",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({email:e})}),a=await t.json().catch(()=>({}));if(!t.ok){let e=a.message??"could not send code.";"rate_limited"===a.code&&void 0!==a.retry_after_secs?e=`too many tries. wait ${a.retry_after_secs}s and try again.`:"upstream_unreachable"===a.code&&(e="api-server unreachable. check your network."),s(e);return}b({kind:"code",email:e,error:null,expiresIn:a.expires_in??600,resendIn:a.resend_available_in??30})}catch(e){s(u(e))}finally{x(!1)}},[]),N=(0,a.useCallback)(async(e,t)=>{x(!0);try{let a=await (0,c.fetchWithTimeout)("/api/auth/login-verify",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({email:e,code:t})}),s=await a.json().catch(()=>({}));if(!a.ok||!s.authenticated||!s.user){let e=s.message??"invalid code.";"invalid_code"===s.code&&(e="wrong code, or it expired. try again."),b(t=>"code"===t.kind?{...t,error:e}:t);return}v.current=!0,m("audit_auth_dialog_succeeded",{source:l}),b({kind:"done",user:s.user}),r(s.user)}catch(t){let e=u(t);b(t=>"code"===t.kind?{...t,error:e}:t)}finally{x(!1)}},[m,r,l]),S=(0,a.useCallback)(async e=>{if(e.preventDefault(),p||"email"!==f.kind)return;let t=String(new FormData(e.currentTarget).get("email")??"").trim().toLowerCase();d.test(t)?await k(t):b({kind:"email",error:"that doesn't look like an email."})},[p,f,k]),C=(0,a.useCallback)(async e=>{if(e.preventDefault(),p||"code"!==f.kind)return;let t=String(new FormData(e.currentTarget).get("code")??"").trim();t.length<4||t.length>12?b(e=>"code"===e.kind?{...e,error:"code is 4–12 characters."}:e):await N(f.email,t)},[p,f,N]),M=(0,a.useCallback)(async()=>{"code"!==f.kind||f.resendIn>0||p||await k(f.email,{isResend:!0})},[f,p,k]);return e?(0,t.jsx)("div",{className:"auth-dialog-backdrop",role:"dialog","aria-modal":"true","aria-labelledby":"auth-dialog-title",onClick:e=>{p||e.target!==e.currentTarget||i()},children:(0,t.jsxs)("div",{className:"auth-dialog",children:[(0,t.jsx)("button",{type:"button",className:"auth-close",onClick:i,disabled:p,"aria-label":"close",children:"×"}),(0,t.jsx)("h2",{id:"auth-dialog-title",className:"auth-headline",children:s}),"email"===f.kind&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)("p",{className:"auth-sub",children:n}),(0,t.jsxs)("form",{onSubmit:S,className:"auth-form",children:[(0,t.jsx)("input",{ref:g,id:"auth-dialog-email",name:"email",type:"email",autoComplete:"email",inputMode:"email",spellCheck:!1,placeholder:"you@yourdomain.com",disabled:p,className:"auth-input",required:!0}),f.error&&(0,t.jsx)("div",{className:"auth-error",children:f.error}),(0,t.jsxs)("div",{className:"auth-actions",children:[(0,t.jsx)("button",{type:"submit",className:"auth-btn primary",disabled:p,children:p?"sending…":"send code"}),(0,t.jsx)("button",{type:"button",className:"auth-btn",onClick:i,disabled:p,children:"cancel"})]})]})]}),"code"===f.kind&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)("p",{className:"auth-sub",children:["code sent to ",(0,t.jsx)("span",{className:"auth-email",children:f.email}),". expires in ",Math.ceil(f.expiresIn/60)," min."]}),(0,t.jsxs)("form",{onSubmit:C,className:"auth-form",children:[(0,t.jsx)("input",{ref:y,id:"auth-dialog-code",name:"code",type:"text",inputMode:"numeric",autoComplete:"one-time-code",spellCheck:!1,placeholder:"123456",disabled:p,className:"auth-input auth-input-code",maxLength:12,required:!0}),f.error&&(0,t.jsx)("div",{className:"auth-error",children:f.error}),(0,t.jsxs)("div",{className:"auth-actions",children:[(0,t.jsx)("button",{type:"submit",className:"auth-btn primary",disabled:p,children:p?"verifying…":"verify"}),(0,t.jsx)("button",{type:"button",className:"auth-btn",onClick:M,disabled:p||f.resendIn>0,children:f.resendIn>0?`resend in ${f.resendIn}s`:"resend code"})]}),(0,t.jsx)("button",{type:"button",className:"auth-back",onClick:()=>b({kind:"email",error:null}),disabled:p,children:"← use a different email"})]})]}),"done"===f.kind&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)("p",{className:"auth-sub",children:[(0,t.jsx)("span",{className:"auth-ok",children:"✓"})," signed in as"," ",(0,t.jsx)("span",{className:"auth-email",children:f.user.email}),"."]}),(0,t.jsx)("div",{className:"auth-actions",children:(0,t.jsx)("button",{type:"button",className:"auth-btn primary",onClick:i,children:"continue"})})]})]})}):null}var m=e.i(55574),f=e.i(34713);function b(e){return new Date(e).toLocaleString(void 0,{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit"})}function p(e,t){let a=e-t;if(a<=0)return"now";let s=Math.floor(a/864e5),n=Math.floor(a%864e5/36e5);return s>0?n>0?`${s}d ${n}h`:`${s}d`:n>0?`${n}h`:`${Math.max(1,Math.floor(a/6e4))}m`}function x(e){return e.toLocaleString("en-US")}function v({label:e,value:a,sub:s,tone:n}){return(0,t.jsxs)("div",{className:"set-stat",children:[(0,t.jsx)("div",{className:"set-stat-label",children:e}),(0,t.jsx)("div",{className:`set-stat-value${n?` ${n}`:""}`,children:a}),(0,t.jsx)("div",{className:"set-stat-sub",children:s??" "})]})}function g({lastRunAtMs:e,nextDueAtMs:a,now:s}){if(null==e||null==a||a<=e)return null;let n=Math.min(100,Math.max(0,(s-e)/(a-e)*100));return(0,t.jsxs)("div",{className:"tape","aria-hidden":"true",children:[(0,t.jsxs)("div",{className:"tape-rail",children:[(0,t.jsx)("div",{className:"tape-fill",style:{width:`${n}%`}}),(0,t.jsx)("div",{className:"tape-now",style:{left:`${n}%`}})]}),(0,t.jsxs)("div",{className:"tape-ends",children:[(0,t.jsxs)("span",{children:["last scan · ",b(e)]}),(0,t.jsxs)("span",{className:"tape-next",children:["next · ",p(a,s)]})]})]})}function y({enabled:e,onChange:a,disabled:s,label:n}){return(0,t.jsx)("button",{type:"button",role:"switch","aria-checked":e,"aria-label":n,disabled:s,onClick:a,className:"sw","data-on":e?"true":"false",children:(0,t.jsx)("span",{className:"sw-knob"})})}let w=[{label:"reads",body:"every session transcript on disk — your prompts, the files your agents read and wrote, and command output."},{label:"runs",body:"entirely on this machine. the transcripts never leave it."},{label:"sends",body:"counts, redacted examples, and this machine's name — and only when a scan finds something harmful."}];e.s(["default",0,function({initial:e}){let[s,o]=(0,a.useState)(e),[c,d]=(0,a.useState)(e?.auto??!1),[u,j]=(0,a.useState)(e?.intervalDays??7),[k,N]=(0,a.useState)(!1),[S,C]=(0,a.useState)(!1),[M,$]=(0,a.useState)(!1),[E,A]=(0,a.useState)(null===e),[D,R]=(0,a.useState)(0),_=(0,a.useRef)(!0),T=(0,a.useRef)(null!==e),I=(0,a.useCallback)(async()=>{try{let e=await n();if(!_.current)return;o(e),T.current=!0,d(e.auto),j(e.intervalDays),R(Date.now()),A(!1)}catch{_.current&&!T.current&&A(!0)}},[]);(0,a.useEffect)(()=>(_.current=!0,I(),()=>{_.current=!1}),[I]),(0,a.useEffect)(()=>{let e=()=>void I();return window.addEventListener("focus",e),document.addEventListener("visibilitychange",e),()=>{window.removeEventListener("focus",e),document.removeEventListener("visibilitychange",e)}},[I]);let L=s?.signedInAs??null,F=s?.daemon==="running",O=s?.daemon==="unsupported-platform",P=s?.schedule??null,q=s?.lastScan??null,U=P?.lastExitCode!=null&&0!==P.lastExitCode&&75!==P.lastExitCode,B=(0,a.useCallback)(async()=>{N(!0);try{let e=await i(!0);if(!e.ok){if(d(!1),"unreachable"===e.reason)return void(0,m.toast)("could not reach the server. check your connection and try again.");await I(),$(!0),(0,m.toast)("that sign-in expired. one more code and it's on.");return}d(e.auto),(0,m.toast)("scheduled audits on."),await I()}catch{d(!1),(0,m.toast)("could not turn that on.")}finally{N(!1)}},[I]),J=(0,a.useCallback)(async()=>{if(c){N(!0);try{let e=await i(!1);e.ok&&d(e.auto),(0,m.toast)("scheduled audits off."),await I()}catch{(0,m.toast)("could not turn that off.")}finally{N(!1)}return}L?await B():$(!0)},[c,B,I,L]),W=(0,a.useCallback)(async e=>{N(!0);try{let t=await r(e);j(t.intervalDays),o(e=>e?{...e,intervalDays:t.intervalDays}:e),(0,m.toast)(`scanning every ${t.intervalDays} day${1===t.intervalDays?"":"s"}.`)}catch{j(s?.intervalDays??7),(0,m.toast)("could not save that.")}finally{N(!1)}},[s?.intervalDays]),K=(0,a.useCallback)(async()=>{N(!0);try{await fetch("/api/auth/logout",{method:"POST"}),(0,m.toast)("signed out. scans continue; digests pause."),await I()}catch{(0,m.toast)("could not sign out.")}finally{N(!1)}},[I]),H=(0,a.useCallback)(async()=>{if(!S){C(!0);try{await (0,l.triggerRun)({cli:[],since:"all",noCache:!1}),(0,m.toast)("scan complete."),await I()}catch(e){(0,m.toast)(e instanceof l.RerunError&&"timeout"===e.kind?"the scan is taking a while — it will finish in the background.":"the scan could not be completed.")}finally{C(!1)}}},[I,S]),z=(0,a.useCallback)(async e=>{$(!1),await I(),await B()},[B,I]),G=s?F?{value:"running",sub:null!=s.daemonStartedAtMs&&D>0?`up ${function(e){let t=Math.floor(e/864e5);if(t>0)return`${t}d`;let a=Math.floor(e/36e5);return a>0?`${a}h`:`${Math.max(1,Math.floor(e/6e4))}m`}(Math.max(0,D-s.daemonStartedAtMs))}`:"",tone:"ok"}:O?{value:"unavailable",sub:"not on this platform"}:"not-installed"===s.daemon?{value:"not installed",sub:"run failproofai config",tone:"warn"}:"unknown"===s.daemon?{value:"unknown",sub:"could not read it"}:{value:"stopped",sub:"run failproofai config",tone:"warn"}:{value:"…",sub:"reading"},Q=c?P?.nextDueAtMs==null?{value:"pending",sub:"after the next scan"}:{value:D>0?p(P.nextDueAtMs,D):"—",sub:b(P.nextDueAtMs)}:{value:"off",sub:"nothing scheduled"},V=q?{value:(0,f.formatRelativeTime)(Date.parse(q.finishedAt)),sub:null!=q.sessionsScanned?`${x(q.sessionsScanned)} sessions`:"scanned"}:{value:"none yet",sub:"run one below"},X=q?null==q.findings?{value:"—",sub:"unreadable"}:{value:x(q.findings),sub:"this scan",...q.findings>0?{tone:"warn"}:{}}:{value:"—",sub:"no scan yet"};return(0,t.jsxs)("main",{className:"report",children:[(0,t.jsxs)("section",{className:"section set-sec",children:[(0,t.jsxs)("div",{className:"set-mast",children:[(0,t.jsx)("h1",{className:"set-title",children:"settings"}),(0,t.jsx)("p",{className:"set-lede",children:"keeping watch, so you don't have to."})]}),E?(0,t.jsx)("div",{className:"set-console",children:(0,t.jsx)("div",{className:"set-cell",children:(0,t.jsxs)("p",{className:"set-warn",children:["could not read this machine's settings. check that the dashboard can reach ",(0,t.jsx)("code",{children:"~/.failproofai/config.json"}),"."]})})}):(0,t.jsxs)("div",{className:"set-console",children:[(0,t.jsxs)("div",{className:"set-stats",children:[(0,t.jsx)(v,{label:"daemon",...G}),(0,t.jsx)(v,{label:"next scan",...Q}),(0,t.jsx)(v,{label:"last scan",...V}),(0,t.jsx)(v,{label:"findings",...X})]}),(0,t.jsxs)("div",{className:"set-cols",children:[(0,t.jsxs)("div",{className:"set-cell set-config",children:[(0,t.jsx)("h2",{className:"set-cell-title",children:"scheduled audit"}),(0,t.jsxs)("div",{className:"set-row set-row-main",children:[(0,t.jsx)(y,{enabled:c,disabled:k||null===s,onChange:()=>void J(),label:c?"turn off scheduled audits":"turn on scheduled audits"}),(0,t.jsxs)("div",{className:"set-row-copy",children:[(0,t.jsx)("span",{className:"set-strong",children:c?"scanning on a schedule.":"scan on a schedule."}),(0,t.jsx)("span",{className:"set-dim",children:c?"you'll get an email only when a scan finds something.":"off. nothing runs and nothing is sent."})]})]}),(0,t.jsxs)("div",{className:"set-row set-row-interval",children:[(0,t.jsx)("span",{className:"set-dim",children:"scan every"}),(0,t.jsx)("input",{type:"number",className:"set-num",min:1,max:90,value:u,disabled:k||null===s,"aria-label":"days between scheduled scans",onChange:e=>j(Number(e.target.value)),onBlur:e=>{let t=Number(e.target.value);Number.isFinite(t)?t!==s?.intervalDays&&W(t):j(s?.intervalDays??7)}}),(0,t.jsx)("span",{className:"set-dim",children:"days"}),(0,t.jsxs)("span",{className:"set-hint",children:[1,"–",90]})]}),(0,t.jsx)("div",{className:"set-rule"}),(0,t.jsx)("div",{className:"set-row set-row-identity",children:L?(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)("span",{className:"set-dim",children:"reports go to"}),(0,t.jsx)("span",{className:"set-email",children:L.email}),(0,t.jsx)("button",{type:"button",className:"set-link",disabled:k,onClick:()=>void K(),children:"sign out"})]}):c?(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)("span",{className:"set-warn",children:"signed out — scans continue, digests are paused."}),(0,t.jsx)("button",{type:"button",className:"set-link",disabled:k,onClick:()=>$(!0),children:"sign in to resume"})]}):(0,t.jsx)("span",{className:"set-dim",children:"turning this on asks for an email, so there is somewhere to send the report."})}),c&&s&&!F&&(0,t.jsx)("p",{className:"set-warn",children:O?"the background service isn't available on this platform, so scheduled scans can't run here. you can still run one now.":"not-installed"===s.daemon?"the background service isn't installed, so nothing will run on the timer. install it with `failproofai config`.":"the background service is stopped, so nothing will run until it starts. repair it with `failproofai config`."}),U&&(0,t.jsxs)("p",{className:"set-warn",children:["the last scheduled scan exited ",P?.lastExitCode,". the next one will still run."]}),(0,t.jsx)("div",{className:"set-actions",children:(0,t.jsx)("button",{type:"button",className:"btn btn-press",disabled:S,onClick:()=>void H(),children:S?"[ scanning… ]":"[ run a scan now ]"})})]}),(0,t.jsxs)("div",{className:"set-cell set-how",children:[(0,t.jsx)("h2",{className:"set-cell-title",children:"how it works"}),(0,t.jsx)("dl",{className:"set-how-list",children:w.map(e=>(0,t.jsxs)("div",{className:"set-how-row",children:[(0,t.jsx)("dt",{className:"set-how-label",children:e.label}),(0,t.jsx)("dd",{className:"set-how-body",children:e.body})]},e.label))})]})]})]}),c&&D>0&&(0,t.jsx)(g,{lastRunAtMs:P?.lastRunAtMs??null,nextDueAtMs:P?.nextDueAtMs??null,now:D})]}),(0,t.jsx)(h,{open:M,source:"settings_scheduled_audit",headline:"where should the report go?",subhead:"we'll send a one-time code to confirm.",onClose:()=>$(!1),onAuthed:e=>void z(e)})]})}],93237)},34713,e=>{"use strict";e.s(["formatDuration",0,function(e){if(e<1e3)return`${e}ms`;let t=Math.round(e/100);if(t<600)return`${(t/10).toFixed(1)}s`;let a=Math.round(e/1e3);if(a<3600){let e=Math.floor(a/60);return`${e}m ${a%60}s`}let s=Math.round(e/6e4),n=Math.floor(s/60);return`${n}h ${s%60}m`},"formatRelativeTime",0,function(e){let t=Date.now()-e;return t<6e4?`${Math.max(1,Math.floor(t/1e3))}s ago`:t<36e5?`${Math.floor(t/6e4)}m ago`:t<864e5?`${Math.floor(t/36e5)}h ago`:`${Math.floor(t/864e5)}d ago`}])}]);
@@ -1 +0,0 @@
1
- (globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,24358,e=>{"use strict";var s=e.i(43476),a=e.i(71645),t=e.i(95187);let n=(0,t.createServerReference)("00840e34fdc0ab0093541d34b83cc649ce4f5d86f3",t.callServer,void 0,t.findSourceMapURL,"getAuditResultAction");var r=e.i(12344);function i({cachedAt:e,fixed:a=!1}){return(0,s.jsxs)("footer",{className:a?"report-footer report-footer--fixed":"report-footer",children:[(0,s.jsx)("img",{src:"/logo.svg",alt:"failproof_ai",style:{height:18,display:"inline-block",verticalAlign:"middle"}}),(0,s.jsx)("span",{style:{margin:"0 12px",color:"var(--line-2)"},children:"·"}),"audit v1.0",(0,s.jsx)("span",{style:{margin:"0 12px",color:"var(--line-2)"},children:"·"}),"generated ",function(e){if(!e)return"—";let s=new Date(e);if(Number.isNaN(s.getTime()))return"—";let a=s.getUTCDate().toString().padStart(2,"0"),t=["jan","feb","mar","apr","may","jun","jul","aug","sep","oct","nov","dec"][s.getUTCMonth()],n=s.getUTCFullYear(),r=s.getUTCHours().toString().padStart(2,"0"),i=s.getUTCMinutes().toString().padStart(2,"0");return`${a} ${t} ${n}, ${r}:${i} utc`}(e),(0,s.jsx)("span",{style:{margin:"0 12px",color:"var(--line-2)"},children:"·"}),(0,s.jsx)("span",{style:{color:"var(--ink-2)"},children:"auto-healing for your agents."})]})}let l=(0,t.createServerReference)("40d9250b20c84e4d86f5898290e4a7a464c019b309",t.callServer,void 0,t.findSourceMapURL,"dismissLeakAction"),c=(0,t.createServerReference)("00290d6c5d144e8bf121d1b8e95c08990b6bafca27",t.callServer,void 0,t.findSourceMapURL,"getLeaksAction"),d=(0,t.createServerReference)("40f2667668aae1ab9d2a5b00c81eebc40f91a3fc8b",t.callServer,void 0,t.findSourceMapURL,"setLeakNotifyAction");function o(){let[e,t]=(0,a.useState)(null),[n,r]=(0,a.useState)(!0),[i,o]=(0,a.useState)(null),u=(0,a.useCallback)(async()=>{let e=await c();t(e.rows),r(e.notify)},[]);(0,a.useEffect)(()=>{u()},[u]);let h=(0,a.useCallback)(async e=>{o(e);try{await l(e)&&t(s=>s?.filter(s=>s.id!==e)??null)}finally{o(null)}},[]),p=(0,a.useCallback)(async()=>{let e=!n;r(e),await d(e)||r(!e)},[n]);return null===e?null:(0,s.jsxs)("section",{className:"audit-sec","data-screen-label":"02 Leaks",children:[(0,s.jsxs)("div",{className:"audit-sec-head",children:[(0,s.jsxs)("span",{className:"audit-sec-eyebrow",children:[(0,s.jsx)("span",{className:"ix",children:"02"}),"// credentials"]}),(0,s.jsx)("button",{type:"button",className:"cbb-toggle leak-notify","data-on":n,onClick:p,"aria-label":n?"turn desktop notifications off":"turn desktop notifications on",title:"desktop notification when a new credential is found",children:(0,s.jsx)("span",{className:"cbb-toggle-knob"})})]}),0===e.length?(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)("h2",{className:"audit-sec-title",children:"no credentials found"}),(0,s.jsxs)("div",{className:"audit-sec-sub",children:["// nothing in this machine's transcripts matched a known key format",(0,s.jsx)("br",{}),"// or a secret-named assignment."]})]}):(0,s.jsxs)(s.Fragment,{children:[(0,s.jsxs)("h2",{className:"audit-sec-title",children:[e.length," credential",1===e.length?"":"s"," in your transcripts"]}),(0,s.jsx)("div",{className:"audit-sec-sub",children:"// one row per distinct key — an exposure count is not a key count."}),(0,s.jsx)("ul",{className:"leak-list",children:e.map(e=>(0,s.jsxs)("li",{className:"leak-row","data-attributed":e.attributed,children:[(0,s.jsxs)("div",{className:"leak-row-top",children:[(0,s.jsx)("code",{className:"leak-key",children:e.display}),(0,s.jsx)("span",{className:"leak-label",children:e.label}),e.name?(0,s.jsx)("span",{className:"leak-name",children:e.name}):null,(0,s.jsx)("button",{type:"button",className:"leak-dismiss",onClick:()=>void h(e.id),disabled:i===e.id,children:"not a secret"})]}),(0,s.jsxs)("div",{className:"leak-how",children:[(0,s.jsx)("span",{className:"leak-verb",children:e.mechanism})," in ",(0,s.jsx)("span",{className:"leak-where",children:e.project})," via ",(0,s.jsx)("span",{className:"leak-who",children:e.cli})," · ",(0,s.jsx)("span",{className:"leak-when",children:function(e){let s=Date.parse(e);if(!Number.isFinite(s))return"unknown";let a=Math.floor((Date.now()-s)/864e5);return a<=0?"today":1===a?"yesterday":a<30?`${a}d ago`:new Date(s).toLocaleDateString(void 0,{month:"short",day:"numeric"})}(e.lastSeen)})]}),(0,s.jsxs)("div",{className:"leak-foot",children:[(0,s.jsxs)("span",{className:"leak-meta",children:[e.occurrences," exposure",1===e.occurrences?"":"s",e.sessions>1?` \xb7 ${e.sessions} sessions`:""," · ",e.length," chars"]}),(0,s.jsx)("span",{className:"leak-dir",children:"input"===e.direction?"sent by the agent — blockable at PreToolUse":"returned to the agent — already in the transcript"}),(0,s.jsx)("span",{className:"leak-fix",children:e.attributed?`rotate it in the ${e.label.replace(/ (API )?(key|token).*$/i,"")} console`:e.name?`find what reads ${e.name}, then rotate it there`:"trace it to its owner, then rotate it"})]})]},e.id))})]})]})}var u=e.i(86616);function h({mode:e,running:a,onStarted:t,onCompleted:n}){let{capture:i}=(0,r.usePostHog)(),l=async()=>{i("audit_first_run_clicked",{source:"empty_state",mode:e}),t();try{await (0,u.triggerRun)({cli:[],since:"all"})}catch(e){console.error("audit first run failed:",e)}finally{await n()}};return"no-cache"===e?(0,s.jsxs)("section",{className:"section empty-section","data-screen-label":"00 Empty",children:[(0,s.jsxs)("div",{className:"section-mast",children:[(0,s.jsxs)("div",{className:"section-label",children:[(0,s.jsx)("span",{className:"glyph",children:"━━"})," audit"," ",(0,s.jsx)("span",{className:"sep",children:"·"})," first run"]}),(0,s.jsxs)("div",{className:"section-meta",children:[(0,s.jsx)("span",{style:{color:"var(--dim)"},children:"○"})," no cache yet"]})]}),(0,s.jsx)("h2",{className:"section-h",children:"scan and see."}),(0,s.jsxs)("div",{className:"panel empty-panel",children:[(0,s.jsxs)("div",{className:"empty-glyph","aria-hidden":"true",children:[(0,s.jsx)("div",{className:"empty-glyph-grid",children:Array.from({length:36}).map((e,a)=>{let t=["1","5","8","10","13","17","20","23","25","30","32"].includes(String(a));return(0,s.jsx)("span",{className:"px"+(t?" on":"")},a)})}),(0,s.jsx)("div",{className:"empty-glyph-label",children:"▮▮ no audit data yet"})]}),(0,s.jsx)("h3",{className:"empty-headline",children:"run your first audit."}),(0,s.jsxs)("p",{className:"empty-sub",children:["we'll walk every transcript across your installed CLIs — Claude Code, Codex, Copilot, Cursor, OpenCode, Pi — and count every wasteful","or risky action. you'll get your agent's archetype and a punch-list."]}),(0,s.jsxs)("div",{className:"empty-actions",children:[(0,s.jsx)("button",{type:"button",className:"btn btn-primary btn-press empty-cta",onClick:l,disabled:a,children:a?"[ scanning… ]":"[ run audit ]"}),(0,s.jsx)("span",{className:"empty-meta",children:"scans all sessions · all installed CLIs · may take a while"})]})]})]}):(0,s.jsxs)("section",{className:"section empty-section","data-screen-label":"00 Empty",children:[(0,s.jsxs)("div",{className:"section-mast",children:[(0,s.jsxs)("div",{className:"section-label",children:[(0,s.jsx)("span",{className:"glyph",children:"━━"})," audit"," ",(0,s.jsx)("span",{className:"sep",children:"·"})," zero transcripts"]}),(0,s.jsxs)("div",{className:"section-meta",children:[(0,s.jsx)("span",{style:{color:"var(--amber)"},children:"●"})," hooks not installed"]})]}),(0,s.jsx)("h2",{className:"section-h",children:"nothing to read."}),(0,s.jsxs)("div",{className:"panel empty-panel",children:[(0,s.jsxs)("div",{className:"empty-glyph","aria-hidden":"true",children:[(0,s.jsx)("div",{className:"empty-glyph-grid",children:Array.from({length:36}).map((e,a)=>{let t=["2","4","9","11","16","18","23","25","27","30","33"].includes(String(a));return(0,s.jsx)("span",{className:"px"+(t?" on":"")},a)})}),(0,s.jsx)("div",{className:"empty-glyph-label",children:"▮▮ no sessions found"})]}),(0,s.jsx)("h3",{className:"empty-headline",children:"install hooks first."}),(0,s.jsx)("p",{className:"empty-sub",children:"failproofai couldn't find any transcripts to scan on this machine. install the hooks for at least one CLI and come back."}),(0,s.jsxs)("div",{className:"empty-actions",children:[(0,s.jsx)("a",{href:"https://docs.befailproof.ai/getting-started",target:"_blank",rel:"noopener noreferrer",className:"btn btn-primary btn-press empty-cta",onClick:()=>{i("audit_install_guide_clicked",{source:"empty_state",mode:e})},children:"[ install guide → ]"}),(0,s.jsx)("span",{className:"empty-meta",children:"takes about 30 seconds · one command per CLI"})]})]})]})}let p=[{label:"discovering transcripts",detail:"walking ~/.claude, ~/.codex, ~/.cursor, …"},{label:"parsing session logs",detail:"reading JSONL + sqlite session stores"},{label:"running policy checks",detail:"replaying every policy against each tool call"},{label:"aggregating results",detail:"counting hits, ranking by frequency"}];function m(){let[e,t]=(0,a.useState)(0),[n,r]=(0,a.useState)(0);(0,a.useEffect)(()=>{let e=setInterval(()=>{t(e=>Math.min(e+1,p.length-1))},4e3),s=setInterval(()=>r(e=>(e+1)%4),350);return()=>{clearInterval(e),clearInterval(s)}},[]);let i=".".repeat(n+1),l=e===p.length-1,c=Math.round(100*Math.min(.9,(e+1)/p.length*.9));return(0,s.jsxs)("section",{className:"section running-section","data-screen-label":"00 Running",children:[(0,s.jsxs)("div",{className:"section-mast",children:[(0,s.jsxs)("div",{className:"section-label",children:[(0,s.jsx)("span",{className:"glyph",children:"━━"})," audit"," ",(0,s.jsx)("span",{className:"sep",children:"·"})," in progress"]}),(0,s.jsxs)("div",{className:"section-meta",children:[(0,s.jsx)("span",{style:{color:"var(--accent-pink)"},children:"●"})," scanning"]})]}),(0,s.jsxs)("h2",{className:"section-h",children:["scanning sessions",i]}),(0,s.jsxs)("div",{className:"panel running-panel",children:[(0,s.jsxs)("div",{className:"running-header",children:[(0,s.jsx)("span",{className:"running-prompt",children:"$"}),(0,s.jsx)("span",{className:"running-cmd",children:"failproofai audit"}),(0,s.jsx)("span",{className:"running-cursor","aria-hidden":"true",children:"▮"})]}),(0,s.jsx)("ul",{className:"running-stages",children:p.map((a,t)=>{let r=t<e,i=t===e;return(0,s.jsxs)("li",{className:"running-stage"+(r?" done":i?" active":" queued"),children:[(0,s.jsx)("span",{className:"running-marker","aria-hidden":"true",children:r?"✓":i?"▮▮":"○"}),(0,s.jsxs)("div",{className:"running-stage-body",children:[(0,s.jsx)("div",{className:"running-stage-label",children:a.label}),i&&(0,s.jsx)("div",{className:"running-stage-detail",children:l?"finishing up…":a.detail})]}),i&&(0,s.jsx)("span",{className:"running-stage-spin","aria-hidden":"true",children:["⠋","⠙","⠹","⠸"][n]})]},t)})}),(0,s.jsxs)("div",{className:"running-bar-label",children:[(0,s.jsx)("span",{children:"progress"}),(0,s.jsxs)("span",{style:{color:"var(--dim)"},children:[c,"%"]})]}),(0,s.jsx)("div",{className:"running-bar-track",children:(0,s.jsx)("div",{className:"running-bar-fill",style:{width:`${c}%`}})}),(0,s.jsx)("p",{className:"running-foot",children:"this can take a while depending on how much session history you have."})]})]})}let g={timeout:"audit took too long — try again",network:"network hiccup — check your connection",post_failed:"audit failed — try again"};function x({status:e,onDismiss:t}){let[n,r]=(0,a.useState)(()=>Date.now());if((0,a.useEffect)(()=>{if("running"!==e.kind)return;let s=setInterval(()=>r(Date.now()),1e3);return()=>clearInterval(s)},[e.kind]),"idle"===e.kind)return null;if("running"===e.kind){let a=Math.max(0,n-e.startedAt);return(0,s.jsxs)("div",{className:"audit-progress-strip",role:"status","aria-live":"polite",children:[(0,s.jsxs)("div",{className:"audit-progress-strip__inner",children:[(0,s.jsxs)("span",{className:"audit-progress-strip__label",children:[(0,s.jsx)("span",{className:"audit-progress-strip__spinner","aria-hidden":"true"}),"re-auditing your sessions"]}),(0,s.jsx)("span",{className:"audit-progress-strip__elapsed",children:function(e){if(e<0)return"00:00";let s=Math.floor(e/1e3),a=Math.floor(s/60).toString().padStart(2,"0"),t=(s%60).toString().padStart(2,"0");return`${a}:${t}`}(a)})]}),(0,s.jsx)("div",{className:"audit-progress-strip__pulse","aria-hidden":"true"})]})}return(0,s.jsx)("div",{className:"audit-progress-strip audit-progress-strip--failed",role:"alert",children:(0,s.jsxs)("div",{className:"audit-progress-strip__inner",children:[(0,s.jsxs)("span",{className:"audit-progress-strip__label",children:[(0,s.jsx)("span",{className:"audit-progress-strip__x","aria-hidden":"true",children:"×"}),g[e.reason]]}),(0,s.jsx)("button",{type:"button",className:"audit-progress-strip__dismiss",onClick:t,"aria-label":"dismiss",children:"[ dismiss ]"})]})})}function f({result:e,cachedAt:t,projectFromUrl:n,isRunning:l,rerunStatus:c,onRerun:d,onDismissRerun:u}){let{capture:h}=(0,r.usePostHog)(),{detectorsTriggered:p,missing:m}=(0,a.useMemo)(()=>{let s=0,a=0;for(let t of e.results)t.hits>0&&s++,"builtin"===t.source&&!t.enabledInConfig&&t.hits>0&&a++;return{detectorsTriggered:s,missing:a}},[e]),g=(0,a.useRef)(!1);return(0,a.useEffect)(()=>{g.current||(g.current=!0,h("audit_dashboard_viewed",{missing:m,transcripts_scanned:e.transcripts.scanned,results_count:e.results.length,detectors_triggered:p}))},[h,m,e.transcripts.scanned,e.results.length,p]),(0,s.jsxs)("div",{className:"app",children:[(0,s.jsx)(x,{status:c,onDismiss:u}),(0,s.jsxs)("div",{className:"app-shell",children:[(0,s.jsxs)("div",{className:"report",children:[(0,s.jsx)(j,{transcripts:e.transcripts.scanned,events:e.eventsScanned??0,projects:e.projectsScanned.length}),(0,s.jsx)(o,{})]}),(0,s.jsx)(i,{cachedAt:t})]})]})}function j({transcripts:e,events:a,projects:t}){return(0,s.jsxs)("section",{className:"audit-sec","data-screen-label":"01 Scan",children:[(0,s.jsx)("div",{className:"audit-sec-head",children:(0,s.jsxs)("span",{className:"audit-sec-eyebrow",children:[(0,s.jsx)("span",{className:"ix",children:"01"}),"// scan"]})}),(0,s.jsx)("h2",{className:"audit-sec-title",children:"scan complete"}),(0,s.jsxs)("div",{className:"audit-sec-sub",children:[a.toLocaleString()," tool call",1===a?"":"s"," across ",e.toLocaleString()," ","transcript",1===e?"":"s",t>0?` \xb7 ${t.toLocaleString()} project${1===t?"":"s"}`:""]}),(0,s.jsxs)("div",{className:"audit-sec-sub",children:["// the report is being rebuilt around leak detection. the scan, the",(0,s.jsx)("br",{}),"// 12-CLI transcript reader and the emailed digest are unaffected."]})]})}function y({running:e,mode:a="no-cache",rerunStatus:t,onDismissRerun:n,onStarted:r,onCompleted:l}){return(0,s.jsxs)("div",{className:"app",children:[(0,s.jsx)(x,{status:t,onDismiss:n}),(0,s.jsxs)("div",{className:"app-shell",children:[(0,s.jsx)("div",{className:"report",children:e?(0,s.jsx)(m,{}):(0,s.jsx)(h,{mode:a,running:e,onStarted:r,onCompleted:l})}),(0,s.jsx)(i,{cachedAt:null,fixed:!0})]})]})}e.s(["AuditDashboard",0,function({initial:e,projectFromUrl:t,totalCatalogSize:i}){let[l,c]=(0,a.useState)(e),[d,o]=(0,a.useState)(!1),[h,p]=(0,a.useState)({kind:"idle"}),{capture:m}=(0,r.usePostHog)(),g=(0,a.useRef)(null),x=(0,a.useRef)(!1),j="cached"===l.status?l.result.transcripts.scanned:0,b="cached"===l.status?l.result.results.length:0,N=(0,a.useCallback)(async()=>{c(await n())},[]),v=(0,a.useCallback)(async e=>{if(d)return;m("audit_rerun_clicked",{source:e,since:"all"}),o(!0);let s=Date.now();p({kind:"running",startedAt:s});try{await (0,u.triggerRun)({cli:[],since:"all",noCache:!0}),await N(),m("audit_rerun_succeeded",{source:e,since:"all",duration_ms:Date.now()-s}),p({kind:"idle"})}catch(t){let a=t instanceof u.RerunError?t.kind:"network";m("audit_rerun_failed",{kind:a,source:e,since:"all",cli_filter:"all",duration_ms:Date.now()-s}),p({kind:"failed",reason:a,failedAt:Date.now()})}finally{o(!1)}},[m,N,d]),k=(0,a.useCallback)(()=>{p({kind:"idle"})},[]);if((0,a.useEffect)(()=>(document.body.classList.add("audit-body"),()=>document.body.classList.remove("audit-body")),[]),(0,a.useEffect)(()=>{let e=d?"running":"empty"===l.status?"empty":0===j?"zero_sessions":"report";g.current!==e&&(g.current=e,m("audit_page_viewed",{state:e,has_cache:"cached"===l.status}))},[l.status,m,d,j]),(0,a.useEffect)(()=>{x.current=!1},[l.status,d,j]),(0,a.useEffect)(()=>{if(d||"cached"!==l.status||0===j)return;let e=0,s=()=>{if(e=0,x.current)return;let s=document.documentElement.scrollHeight-window.innerHeight;s<=0||window.scrollY>=s-24&&(x.current=!0,m("audit_page_scrolled_to_end",{results_count:b,transcripts_scanned:j}))},a=()=>{0===e&&(e=requestAnimationFrame(s))};return s(),window.addEventListener("scroll",a,{passive:!0}),()=>{window.removeEventListener("scroll",a),0!==e&&cancelAnimationFrame(e)}},[l.status,m,b,d,j]),"empty"===l.status&&!d)return(0,s.jsx)(y,{running:!1,rerunStatus:h,onDismissRerun:k,onStarted:()=>o(!0),onCompleted:async()=>{o(!1),await N()}});if("empty"===l.status&&d)return(0,s.jsx)(y,{running:!0,rerunStatus:h,onDismissRerun:k,onStarted:()=>{},onCompleted:async()=>{o(!1),await N()}});let w="cached"===l.status?l.result:null;if(!w)return null;let S="cached"===l.status?l.cachedAt:null;return 0===w.transcripts.scanned?(0,s.jsx)(y,{running:d,mode:"zero-sessions",rerunStatus:h,onDismissRerun:k,onStarted:()=>o(!0),onCompleted:async()=>{o(!1),await N()}}):(0,s.jsx)(f,{result:w,cachedAt:S,projectFromUrl:t,isRunning:d,rerunStatus:h,onRerun:e=>v(e),onDismissRerun:k})}],24358)},86616,29054,e=>{"use strict";function s(e,a={},t=15e3){let n=AbortSignal.timeout(t),r=a.signal?AbortSignal.any([a.signal,n]):n;return fetch(e,{...a,signal:r})}function a(e){if(null===e||"object"!=typeof e)return!1;let s=e.name;return"AbortError"===s||"TimeoutError"===s}e.s(["fetchWithTimeout",0,s,"isAbortError",0,a],29054);class t extends Error{kind;constructor(e,s){super(s),this.kind=e,this.name="RerunError"}}async function n(e){try{let a=await s("/api/audit/run",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({cli:e.cli.length>0?e.cli:void 0,since:"all"===e.since?void 0:e.since,noCache:!!e.noCache||void 0})});if(!a.ok&&409!==a.status){let e=await a.text().catch(()=>"");throw console.error("audit run failed:",a.status,e),new t("post_failed",`audit run failed (${a.status})`)}}catch(e){if(e instanceof t)throw e;throw console.error("audit run request failed:",e),new t(a(e)?"timeout":"network","audit run request failed")}let n=0;for(;;){await new Promise(e=>setTimeout(e,1e3));let e=null;try{let a=await s("/api/audit/status",{cache:"no-store"});a.ok&&(e=await a.json())}catch{}if(null===e){if(++n>=10)throw new t("network","audit status poll lost the server");continue}if(n=0,!e.running){if(e.error)throw new t("post_failed",e.error);return}}}e.s(["RerunError",0,t,"triggerRun",0,n],86616)}]);