failproofai 1.0.4-beta.4 → 1.0.4-beta.7

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 (170) 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.nft.json +1 -1
  25. package/.next/standalone/.next/server/app/api/audit/status/route.js.nft.json +1 -1
  26. package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -1
  27. package/.next/standalone/.next/server/app/api/auth/login-verify/route.js.nft.json +1 -1
  28. package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
  29. package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -1
  30. package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
  31. package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +5 -5
  32. package/.next/standalone/.next/server/app/audit/page.js +3 -3
  33. package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -1
  34. package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
  35. package/.next/standalone/.next/server/app/index.html +1 -1
  36. package/.next/standalone/.next/server/app/index.rsc +14 -14
  37. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +13 -13
  38. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +14 -14
  39. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  40. package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
  41. package/.next/standalone/.next/server/app/page.js +2 -2
  42. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  43. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  44. package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +14 -14
  45. package/.next/standalone/.next/server/app/policies/page.js +4 -4
  46. package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
  47. package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
  48. package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
  49. package/.next/standalone/.next/server/app/project/[name]/page.js +3 -3
  50. package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
  51. package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
  52. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
  53. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
  54. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js +4 -4
  55. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
  56. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
  57. package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
  58. package/.next/standalone/.next/server/app/projects/page.js +3 -3
  59. package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
  60. package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  61. package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +15 -4
  62. package/.next/standalone/.next/server/app/settings/page.js +4 -4
  63. package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
  64. package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  65. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0--lkk6._.js +1 -1
  66. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0o07qi9._.js +1 -1
  67. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0q0qzx1._.js +1 -1
  68. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0rv7m0k._.js +1 -1
  69. package/.next/standalone/.next/server/chunks/[root-of-the-server]__17g9wh7._.js +1 -1
  70. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1le9jqc._.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/_0tovk6q._.js +1 -1
  74. package/.next/standalone/.next/server/chunks/_0trp3yc._.js +1 -1
  75. package/.next/standalone/.next/server/chunks/_1ek68ln._.js +11 -11
  76. package/.next/standalone/.next/server/chunks/lib_factory-projects_ts_1eo_bk-._.js +1 -1
  77. package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
  78. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0p-5p8u._.js → [root-of-the-server]__0-4ja6q._.js} +3 -3
  79. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1p2otjt._.js → [root-of-the-server]__00cr3xu._.js} +3 -3
  80. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__013jr2b._.js → [root-of-the-server]__04px77e._.js} +3 -3
  81. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__190won8._.js → [root-of-the-server]__0dxf928._.js} +1 -1
  82. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0s740oi._.js → [root-of-the-server]__0egr5s1._.js} +3 -3
  83. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__01wy8d-._.js → [root-of-the-server]__0i0l1di._.js} +3 -3
  84. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0n_lxhg._.js → [root-of-the-server]__0kokc8z._.js} +1 -1
  85. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1ctpynv._.js → [root-of-the-server]__0n2txhk._.js} +1 -1
  86. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0oa1lav._.js +1 -1
  87. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__02npjtd._.js → [root-of-the-server]__0r3c1_0._.js} +3 -3
  88. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0yl9wb5._.js → [root-of-the-server]__12hbpha._.js} +2 -2
  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/_04ng_6x._.js +3 -0
  93. package/.next/standalone/.next/server/chunks/ssr/{_1u8-lu2._.js → _07t3jol._.js} +2 -2
  94. package/.next/standalone/.next/server/chunks/ssr/_08x1r5t._.js +1 -1
  95. package/.next/standalone/.next/server/chunks/ssr/{_0guxnh-._.js → _0a0zlpr._.js} +2 -2
  96. package/.next/standalone/.next/server/chunks/ssr/{_0h_douw._.js → _0s-77v5._.js} +1 -1
  97. package/.next/standalone/.next/server/chunks/ssr/_1ddpc5g._.js +1 -1
  98. package/.next/standalone/.next/server/chunks/ssr/_1es2j7i._.js +4 -14
  99. package/.next/standalone/.next/server/chunks/ssr/_next-internal_server_app_policies_page_actions_1sp2-yo.js +2 -2
  100. package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +1 -1
  101. package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
  102. package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +1 -1
  103. package/.next/standalone/.next/server/chunks/ssr/app_settings_settings-client_tsx_20lq-mq._.js +1 -1
  104. package/.next/standalone/.next/server/chunks/ssr/src_hooks_builtin-policies_ts_09j2ndl._.js +1 -1
  105. package/.next/standalone/.next/server/chunks/ssr/src_hooks_fp-home_ts_0je3xkv._.js +1 -1
  106. package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
  107. package/.next/standalone/.next/server/pages/404.html +1 -1
  108. package/.next/standalone/.next/server/pages/500.html +1 -1
  109. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  110. package/.next/standalone/.next/server/server-reference-manifest.json +33 -22
  111. package/.next/standalone/.next/static/chunks/{17tfki9x5rd_7.js → 083fk73jtv9a0.js} +1 -1
  112. package/.next/standalone/.next/static/chunks/{1i-i0pxg9q_8y.js → 0divvxng208xo.js} +1 -1
  113. package/.next/standalone/.next/static/chunks/{38dqur43qthrl.js → 0f1pznnc7zlub.js} +1 -1
  114. package/.next/standalone/.next/static/chunks/{323cyb3a2s06y.js → 0ntdfr2552x-h.js} +1 -1
  115. package/.next/standalone/.next/static/chunks/{0po8n4tyotjf2.js → 0t6ea7d3bkmdv.js} +1 -1
  116. package/.next/standalone/.next/static/chunks/{364cqbpeg1y5i.js → 15uon66hpwbgg.js} +1 -1
  117. package/.next/standalone/.next/static/chunks/{42gwu2bsz4ske.js → 1csubx9gwhsf6.js} +2 -2
  118. package/.next/standalone/.next/static/chunks/27du9n7ssja7l.js +1 -0
  119. package/.next/standalone/.next/static/chunks/2h_pcb1y8_jde.js +1 -0
  120. package/.next/standalone/.next/static/chunks/{2bxr2_2h4kaqq.js → 2pwfrn6_mw-1u.js} +1 -1
  121. package/.next/standalone/app/actions/get-leaks.ts +0 -5
  122. package/.next/standalone/app/actions/get-scheduled-audit.ts +5 -0
  123. package/.next/standalone/app/actions/update-scheduled-audit.ts +18 -57
  124. package/.next/standalone/app/api/auth/status/route.ts +3 -2
  125. package/.next/standalone/app/audit/_components/audit-dashboard.tsx +1 -1
  126. package/.next/standalone/app/audit/_components/empty-state.tsx +1 -1
  127. package/.next/standalone/app/audit/_components/leak-section.tsx +1 -1
  128. package/.next/standalone/app/settings/page.tsx +1 -1
  129. package/.next/standalone/app/settings/settings-client.tsx +50 -45
  130. package/.next/standalone/lib/auth/api-server-client.ts +6 -6
  131. package/.next/standalone/lib/codex-sessions.ts +20 -4
  132. package/.next/standalone/lib/copilot-sessions.ts +32 -1
  133. package/.next/standalone/lib/cursor-sessions.ts +62 -5
  134. package/.next/standalone/package.json +9 -9
  135. package/.next/standalone/server.js +1 -1
  136. package/dist/cli.mjs +991 -1101
  137. package/dist/worker.mjs +175 -382
  138. package/lib/auth/api-server-client.ts +6 -6
  139. package/lib/codex-sessions.ts +20 -4
  140. package/lib/copilot-sessions.ts +32 -1
  141. package/lib/cursor-sessions.ts +62 -5
  142. package/package.json +9 -9
  143. package/pi-extension/index.ts +10 -18
  144. package/src/audit/cli.ts +72 -81
  145. package/src/audit/harm-report.ts +12 -6
  146. package/src/audit/index.ts +3 -1
  147. package/src/audit/leak-fingerprint.ts +2 -4
  148. package/src/audit/leak-record.ts +26 -10
  149. package/src/audit/leak-scan.ts +1 -1
  150. package/src/audit/leak-store.ts +1 -46
  151. package/src/audit/machine-store.ts +8 -9
  152. package/src/audit/macos-notifier.ts +56 -68
  153. package/src/audit/redact-example.ts +2 -0
  154. package/src/audit/report-harm.ts +31 -46
  155. package/src/audit/schedule-cli.ts +17 -33
  156. package/src/audit/types.ts +5 -0
  157. package/src/hooks/builtin-policies.ts +2 -2
  158. package/src/hooks/configure-wizard.ts +36 -1
  159. package/src/hooks/fp-config.ts +29 -54
  160. package/src/hooks/handler.ts +1 -79
  161. package/src/hooks/integrations.ts +4 -15
  162. package/src/hooks/notice.ts +12 -179
  163. package/src/hooks/uninstall-cli.ts +3 -3
  164. package/.next/standalone/.next/server/chunks/ssr/_0oq1dh6._.js +0 -3
  165. package/.next/standalone/.next/static/chunks/04o5zfl7p5lhx.js +0 -1
  166. package/.next/standalone/.next/static/chunks/0qx7gav1c2_vu.js +0 -1
  167. package/src/audit/leak-notice.ts +0 -259
  168. /package/.next/standalone/.next/static/{P6icI2V2PvVuePJrqjHCr → YiPsVpjrc-pEQoN7XvhZ0}/_buildManifest.js +0 -0
  169. /package/.next/standalone/.next/static/{P6icI2V2PvVuePJrqjHCr → YiPsVpjrc-pEQoN7XvhZ0}/_clientMiddlewareManifest.js +0 -0
  170. /package/.next/standalone/.next/static/{P6icI2V2PvVuePJrqjHCr → YiPsVpjrc-pEQoN7XvhZ0}/_ssgManifest.js +0 -0
package/dist/cli.mjs CHANGED
@@ -29,7 +29,7 @@ var __esm = (fn, res, err) => () => {
29
29
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
30
30
 
31
31
  // package.json
32
- var version2 = "1.0.4-beta.4", package_default;
32
+ var version2 = "1.0.4-beta.7", package_default;
33
33
  var init_package = __esm(() => {
34
34
  package_default = {
35
35
  name: "failproofai",
@@ -154,16 +154,16 @@ var init_package = __esm(() => {
154
154
  browserslist: "4.28.8"
155
155
  },
156
156
  optionalDependencies: {
157
- "@failproofai/failproofaid-linux-x64": "1.0.4-beta.4",
158
- "@failproofai/failproofaid-linux-arm64": "1.0.4-beta.4",
159
- "@failproofai/failproofaid-darwin-x64": "1.0.4-beta.4",
160
- "@failproofai/failproofaid-darwin-arm64": "1.0.4-beta.4"
157
+ "@failproofai/failproofaid-linux-x64": "1.0.4-beta.7",
158
+ "@failproofai/failproofaid-linux-arm64": "1.0.4-beta.7",
159
+ "@failproofai/failproofaid-darwin-x64": "1.0.4-beta.7",
160
+ "@failproofai/failproofaid-darwin-arm64": "1.0.4-beta.7"
161
161
  },
162
162
  failproofaidBinaries: {
163
- "linux-x64": "4487790ed9b881da2914b5985a23b5adca1f20e226d71c635d8170064e6b2340",
164
- "linux-arm64": "c903c5e201198213ccd8295fdab741c7d08d22c8dd5c276e52aa766595bedcc2",
165
- "darwin-x64": "f0933584abbf0f9ff95cd153f8c6c704e467af1d6ffc8f42f9c426bd44b1142a",
166
- "darwin-arm64": "387a3acbf13f667a557c8ac632fe67dee350cda078e3266e71edfcfacb9ecae6"
163
+ "linux-x64": "e59735a8f94cd8ac697b2bd67aafdd8d76a8394d53db229876980cc13a18f07e",
164
+ "linux-arm64": "b9ce50dd2f79b55f4f7112add265a776a4a6d002c2a56f971e666fbb796f3906",
165
+ "darwin-x64": "b46efc8ec33945a5cc26b7bb288fb87cea65b5983bd83094b5e607d53b8eda4c",
166
+ "darwin-arm64": "a8cc6112cee5ca8a7d517900e9ce32118855135980f22979fa0ff7aa6f68d954"
167
167
  }
168
168
  };
169
169
  });
@@ -3874,8 +3874,8 @@ var init_builtin_policies = __esm(() => {
3874
3874
  [/sk-ant-oat01-[A-Za-z0-9\-_]{20,}/, "Anthropic OAuth token"],
3875
3875
  [/sk-ant-[A-Za-z0-9\-_]{20,}/, "Anthropic API key"],
3876
3876
  [/sk-proj-[A-Za-z0-9\-_]{20,}/, "OpenAI project API key"],
3877
- [/sk-svcacct-[A-Za-z0-9\-_]{20,}/, "OpenAI service-account key"],
3878
- [/sk-admin-[A-Za-z0-9\-_]{20,}/, "OpenAI admin key"],
3877
+ [/(?<!\w)sk-svcacct-[A-Za-z0-9\-_]{20,}/, "OpenAI service-account key"],
3878
+ [/(?<!\w)sk-admin-[A-Za-z0-9\-_]{20,}/, "OpenAI admin key"],
3879
3879
  [/sk-or-v1-[A-Za-z0-9\-_]{20,}/, "OpenRouter API key"],
3880
3880
  [/sk-[A-Za-z0-9]{20,}/, "OpenAI-compatible key (issuer unknown)"],
3881
3881
  [/github_pat_[A-Za-z0-9_]{82}/, "GitHub fine-grained token"],
@@ -11810,19 +11810,6 @@ async function applyDecision(result, ctx, eventName) {
11810
11810
  if (out && out.decision && out.decision.behavior === "deny") {
11811
11811
  throw new Error((out.decision.message) || "Blocked by failproofai");
11812
11812
  }
11813
- const notice = parsed.failproofaiNotice;
11814
- if (typeof notice === "string" && notice && ctx && ctx.client && ctx.client.tui) {
11815
- try {
11816
- await ctx.client.tui.showToast({
11817
- body: {
11818
- title: "failproofai audit",
11819
- message: notice,
11820
- variant: "warning",
11821
- duration: 12_000,
11822
- },
11823
- });
11824
- } catch { /* a courtesy notice must never break the host hook */ }
11825
- }
11826
11813
  // Forward additional context as a prompt to the session. For Stop /
11827
11814
  // SubagentStop the prompt is the only force-retry channel (session.idle
11828
11815
  // already fired), so AWAIT to ensure the SDK round-trip completes before
@@ -11878,7 +11865,10 @@ export default async function failproofaiPlugin({ client, directory }) {
11878
11865
  const claudeEvent = BUS_EVENT_MAP[event.type];
11879
11866
  if (!claudeEvent) return;
11880
11867
  const props = event.properties || {};
11881
- const sessionID = props.sessionID || (props.session && props.session.id) || props.id;
11868
+ const info = props.info || props.session || {};
11869
+
11870
+ const sessionID = info.id || info.sessionID || info.sessionId || info.session_id ||
11871
+ props.sessionID || props.sessionId || props.session_id || props.id;
11882
11872
  const r = await runFailproofai(claudeEvent, {
11883
11873
  session_id: sessionID, cwd: directory, hook_event_name: claudeEvent,
11884
11874
  }, directory);
@@ -16493,432 +16483,6 @@ var init_delivery_health = __esm(() => {
16493
16483
  };
16494
16484
  });
16495
16485
 
16496
- // src/hooks/notice.ts
16497
- function shapeNotice(cli, notice, existingStdout = "") {
16498
- const empty = { stdout: existingStdout, stderr: "" };
16499
- if (!notice.trim() || !cli)
16500
- return empty;
16501
- const channel = NOTICE_CHANNEL[cli] ?? "none";
16502
- const text = notice.length > MAX_NOTICE_CHARS ? notice.slice(0, MAX_NOTICE_CHARS - 1) + "…" : notice;
16503
- switch (channel) {
16504
- case "systemMessage": {
16505
- if (existingStdout.trim().startsWith("{")) {
16506
- try {
16507
- const parsed = JSON.parse(existingStdout);
16508
- parsed.systemMessage = text;
16509
- return { stdout: JSON.stringify(parsed), stderr: "" };
16510
- } catch {
16511
- return empty;
16512
- }
16513
- }
16514
- if (existingStdout.trim())
16515
- return empty;
16516
- return { stdout: JSON.stringify({ systemMessage: text }), stderr: "" };
16517
- }
16518
- case "stderr":
16519
- return { stdout: existingStdout, stderr: text + `
16520
- ` };
16521
- case "stdout":
16522
- if (existingStdout.trim())
16523
- return empty;
16524
- return { stdout: text + `
16525
- `, stderr: "" };
16526
- case "shim": {
16527
- if (existingStdout.trim().startsWith("{")) {
16528
- try {
16529
- const parsed = JSON.parse(existingStdout);
16530
- parsed.failproofaiNotice = text;
16531
- return { stdout: JSON.stringify(parsed), stderr: "" };
16532
- } catch {
16533
- return empty;
16534
- }
16535
- }
16536
- if (existingStdout.trim())
16537
- return empty;
16538
- return { stdout: JSON.stringify({ failproofaiNotice: text }), stderr: "" };
16539
- }
16540
- default:
16541
- return empty;
16542
- }
16543
- }
16544
- function canDeliverNotice(cli) {
16545
- return !!cli && (NOTICE_CHANNEL[cli] ?? "none") !== "none";
16546
- }
16547
- function leakNoticeText(newFindings) {
16548
- const n = newFindings === 1 ? "a possible credential exposure" : `${newFindings} possible credential exposures`;
16549
- return `failproofai found ${n} in this project's agent transcripts.
16550
- ` + "Run `failproofai audit` to review the matches and rotate anything real.";
16551
- }
16552
- function desktopLeakNotice() {
16553
- return {
16554
- title: "failproofai audit needs review",
16555
- body: "Possible credential exposure was found in your agent transcripts. " + "Run failproofai audit to verify the matches and rotate anything real."
16556
- };
16557
- }
16558
- var NOTICE_CHANNEL, MAX_NOTICE_CHARS = 900;
16559
- var init_notice = __esm(() => {
16560
- NOTICE_CHANNEL = {
16561
- claude: "systemMessage",
16562
- codex: "systemMessage",
16563
- copilot: "stderr",
16564
- factory: "stdout",
16565
- opencode: "shim",
16566
- pi: "shim"
16567
- };
16568
- });
16569
-
16570
- // lib/atomic-write.ts
16571
- import {
16572
- chmodSync as chmodSync2,
16573
- existsSync as existsSync11,
16574
- mkdirSync as mkdirSync7,
16575
- renameSync as renameSync4,
16576
- rmSync as rmSync3,
16577
- statSync as statSync7,
16578
- writeFileSync as writeFileSync6
16579
- } from "node:fs";
16580
- import { dirname as dirname7 } from "node:path";
16581
- import { randomBytes } from "node:crypto";
16582
- function writeJsonAtomically(filePath, value, opts = {}) {
16583
- const mode = opts.mode ?? 384;
16584
- const dirMode = opts.dirMode ?? 448;
16585
- const dir = dirname7(filePath);
16586
- if (!existsSync11(dir))
16587
- mkdirSync7(dir, { recursive: true, mode: dirMode });
16588
- const tmp = `${filePath}.${process.pid}.${randomBytes(6).toString("hex")}.tmp`;
16589
- try {
16590
- writeFileSync6(tmp, JSON.stringify(value, null, 2), { mode });
16591
- try {
16592
- if ((statSync7(tmp).mode & 63) !== 0)
16593
- chmodSync2(tmp, mode);
16594
- } catch {}
16595
- renameSync4(tmp, filePath);
16596
- try {
16597
- if ((statSync7(filePath).mode & 63) !== 0)
16598
- chmodSync2(filePath, mode);
16599
- } catch {}
16600
- } catch (err) {
16601
- try {
16602
- rmSync3(tmp, { force: true });
16603
- } catch {}
16604
- throw err;
16605
- }
16606
- }
16607
- var init_atomic_write = () => {};
16608
-
16609
- // src/audit/leak-record.ts
16610
- function upsertFinding(record, incoming) {
16611
- const { sighting, ...rest } = incoming;
16612
- const existing = record.findings.find((f) => f.id === rest.id);
16613
- if (!existing) {
16614
- record.findings.push({
16615
- ...rest,
16616
- firstSeen: sighting.at,
16617
- lastSeen: sighting.at,
16618
- occurrences: 1,
16619
- sightings: [sighting]
16620
- });
16621
- return { record, isNew: true };
16622
- }
16623
- existing.occurrences += 1;
16624
- if (sighting.at > existing.lastSeen)
16625
- existing.lastSeen = sighting.at;
16626
- if (sighting.at < existing.firstSeen)
16627
- existing.firstSeen = sighting.at;
16628
- if (existing.sightings.length < MAX_SIGHTINGS) {
16629
- const seen = existing.sightings.some((s) => s.sessionId === sighting.sessionId && s.at === sighting.at);
16630
- if (!seen)
16631
- existing.sightings.push(sighting);
16632
- }
16633
- return { record, isNew: false };
16634
- }
16635
- function pruneRecord(record, nowMs) {
16636
- const cutoff = new Date(nowMs - FINDING_TTL_DAYS * 86400000).toISOString();
16637
- const live = record.findings.filter((f) => f.lastSeen >= cutoff);
16638
- live.sort((a, b) => a.lastSeen < b.lastSeen ? 1 : a.lastSeen > b.lastSeen ? -1 : 0);
16639
- record.findings = live.slice(0, MAX_FINDINGS);
16640
- return record;
16641
- }
16642
- function emptyRecord(salt, nowIso) {
16643
- return {
16644
- schemaVersion: LEAK_RECORD_SCHEMA_VERSION,
16645
- salt,
16646
- updatedAt: nowIso,
16647
- findings: []
16648
- };
16649
- }
16650
- function describeMechanism(toolName, direction, shortPath) {
16651
- const where = shortPath ? ` ${shortPath}` : "";
16652
- let summary;
16653
- if (direction === "result") {
16654
- summary = shortPath ? `appeared in the output of reading${where}` : "appeared in tool output";
16655
- } else {
16656
- switch (toolName) {
16657
- case "Read":
16658
- summary = `read from${where || " a file"}`;
16659
- break;
16660
- case "Write":
16661
- summary = `written to${where || " a file"}`;
16662
- break;
16663
- case "Edit":
16664
- case "NotebookEdit":
16665
- summary = `edited into${where || " a file"}`;
16666
- break;
16667
- case "Bash":
16668
- summary = "passed in a shell command";
16669
- break;
16670
- default:
16671
- summary = `sent to the ${toolName} tool`;
16672
- }
16673
- }
16674
- return { summary, toolName, direction };
16675
- }
16676
- var MAX_SIGHTINGS = 5, FINDING_TTL_DAYS = 90, MAX_FINDINGS = 500, LEAK_RECORD_SCHEMA_VERSION = 1;
16677
-
16678
- // src/audit/leak-fingerprint.ts
16679
- function matchPublicPrefix(value) {
16680
- for (const entry of PUBLIC_PREFIXES) {
16681
- if (value.startsWith(entry[0]))
16682
- return entry;
16683
- }
16684
- return null;
16685
- }
16686
- function fingerprintSecret(value, fallbackLabel = "secret") {
16687
- const length = value.length;
16688
- const matched = matchPublicPrefix(value);
16689
- if (!matched) {
16690
- return {
16691
- display: `[${length}-char ${fallbackLabel}]`,
16692
- label: fallbackLabel,
16693
- length,
16694
- attributed: false
16695
- };
16696
- }
16697
- const [prefix, label] = matched;
16698
- const bodyLength = length - prefix.length;
16699
- const run = MASK_CHAR.repeat(Math.max(1, Math.min(MAX_MASK_RUN, bodyLength)));
16700
- if (length >= MIN_LEN_FOR_TAIL && bodyLength > TAIL_CHARS * 2) {
16701
- return {
16702
- display: `${prefix}${run}${value.slice(-TAIL_CHARS)}`,
16703
- label,
16704
- length,
16705
- attributed: true
16706
- };
16707
- }
16708
- return { display: `${prefix}${run}`, label, length, attributed: true };
16709
- }
16710
- function isFindingId(id) {
16711
- return /^[0-9a-f]{16}$/.test(id);
16712
- }
16713
- function fingerprintId(value, machineSalt) {
16714
- const { createHmac } = __require("node:crypto");
16715
- return createHmac("sha256", machineSalt).update(value).digest("hex").slice(0, 16);
16716
- }
16717
- var MASK_CHAR = "•", MAX_MASK_RUN = 8, MIN_LEN_FOR_TAIL = 24, TAIL_CHARS = 4, PUBLIC_PREFIXES;
16718
- var init_leak_fingerprint = __esm(() => {
16719
- PUBLIC_PREFIXES = [
16720
- ["sk-ant-api03-", "Anthropic API key"],
16721
- ["sk-ant-oat01-", "Anthropic OAuth token"],
16722
- ["sk-ant-", "Anthropic key"],
16723
- ["sk-proj-", "OpenAI project key"],
16724
- ["sk-svcacct-", "OpenAI service-account key"],
16725
- ["sk-admin-", "OpenAI admin key"],
16726
- ["sk-or-v1-", "OpenRouter key"],
16727
- ["github_pat_", "GitHub fine-grained token"],
16728
- ["ghp_", "GitHub personal access token"],
16729
- ["gho_", "GitHub OAuth token"],
16730
- ["ghu_", "GitHub user-to-server token"],
16731
- ["ghs_", "GitHub server-to-server token"],
16732
- ["ghr_", "GitHub refresh token"],
16733
- ["glpat-", "GitLab personal access token"],
16734
- ["xoxb-", "Slack bot token"],
16735
- ["xoxp-", "Slack user token"],
16736
- ["xapp-", "Slack app-level token"],
16737
- ["sk_live_", "Stripe live secret key"],
16738
- ["sk_test_", "Stripe test secret key"],
16739
- ["rk_live_", "Stripe restricted key"],
16740
- ["AKIA", "AWS access key ID"],
16741
- ["ASIA", "AWS temporary access key ID"],
16742
- ["AIza", "Google API key"],
16743
- ["hf_", "Hugging Face token"],
16744
- ["gsk_", "Groq API key"],
16745
- ["r8_", "Replicate token"],
16746
- ["xai-", "xAI key"],
16747
- ["npm_", "npm access token"],
16748
- ["dop_v1_", "DigitalOcean token"],
16749
- ["shpat_", "Shopify access token"],
16750
- ["sbp_", "Supabase token"]
16751
- ];
16752
- });
16753
-
16754
- // src/audit/leak-store.ts
16755
- import { randomBytes as randomBytes2 } from "node:crypto";
16756
- import { existsSync as existsSync12, mkdirSync as mkdirSync8, readFileSync as readFileSync8 } from "node:fs";
16757
- import { dirname as dirname8 } from "node:path";
16758
- function readJson(path) {
16759
- try {
16760
- if (!existsSync12(path))
16761
- return null;
16762
- return JSON.parse(readFileSync8(path, "utf8"));
16763
- } catch {
16764
- return null;
16765
- }
16766
- }
16767
- function readLeakIdentity(home) {
16768
- const existing = readJson(auditLeakIdentityFile(home));
16769
- if (existing && typeof existing.salt === "string" && existing.salt.length >= 32) {
16770
- return {
16771
- salt: existing.salt,
16772
- dismissed: existing.dismissed ?? [],
16773
- reportViewedAt: typeof existing.reportViewedAt === "number" && Number.isFinite(existing.reportViewedAt) ? existing.reportViewedAt : undefined
16774
- };
16775
- }
16776
- const minted = { salt: randomBytes2(32).toString("hex"), dismissed: [] };
16777
- writeLeakIdentity(minted, home);
16778
- return minted;
16779
- }
16780
- function writeLeakIdentity(identity, home) {
16781
- const path = auditLeakIdentityFile(home);
16782
- try {
16783
- mkdirSync8(dirname8(path), { recursive: true });
16784
- writeJsonAtomically(path, identity, { mode: FILE_MODE });
16785
- return true;
16786
- } catch {
16787
- return false;
16788
- }
16789
- }
16790
- function sanitizeFinding(raw) {
16791
- if (!raw || typeof raw !== "object" || Array.isArray(raw))
16792
- return null;
16793
- const f = raw;
16794
- if (typeof f.id !== "string" || !isFindingId(f.id))
16795
- return null;
16796
- const fp = f.fingerprint;
16797
- if (!fp || typeof fp !== "object" || typeof fp.display !== "string" || typeof fp.label !== "string") {
16798
- return null;
16799
- }
16800
- const sightings = Array.isArray(f.sightings) ? f.sightings.filter((s) => {
16801
- if (!s || typeof s !== "object")
16802
- return false;
16803
- const m = s.mechanism;
16804
- return !!m && typeof m === "object" && typeof m.summary === "string";
16805
- }) : [];
16806
- return {
16807
- ...f,
16808
- fingerprint: {
16809
- display: fp.display,
16810
- label: fp.label,
16811
- length: typeof fp.length === "number" && Number.isFinite(fp.length) ? fp.length : 0,
16812
- attributed: fp.attributed === true
16813
- },
16814
- name: typeof f.name === "string" ? f.name : null,
16815
- firstSeen: typeof f.firstSeen === "string" ? f.firstSeen : "",
16816
- lastSeen: typeof f.lastSeen === "string" ? f.lastSeen : "",
16817
- occurrences: typeof f.occurrences === "number" && Number.isFinite(f.occurrences) ? f.occurrences : sightings.length,
16818
- sightings
16819
- };
16820
- }
16821
- function readLeakRecord(home) {
16822
- const identity = readLeakIdentity(home);
16823
- const raw = readJson(auditLeaksFile(home));
16824
- if (!raw || raw.schemaVersion !== LEAK_RECORD_SCHEMA_VERSION || !Array.isArray(raw.findings)) {
16825
- return emptyRecord(identity.salt, new Date().toISOString());
16826
- }
16827
- const findings = raw.findings.map(sanitizeFinding).filter((f) => f !== null);
16828
- return { ...raw, findings, salt: identity.salt };
16829
- }
16830
- function writeLeakRecord(record, home, nowMs = Date.now()) {
16831
- const path = auditLeaksFile(home);
16832
- try {
16833
- mkdirSync8(dirname8(path), { recursive: true });
16834
- const pruned = pruneRecord(record, nowMs);
16835
- pruned.updatedAt = new Date(nowMs).toISOString();
16836
- writeJsonAtomically(path, pruned, { mode: FILE_MODE });
16837
- return true;
16838
- } catch {
16839
- return false;
16840
- }
16841
- }
16842
- function activeFindings(record, home) {
16843
- const dismissed = new Set(readLeakIdentity(home).dismissed);
16844
- return record.findings.filter((f) => !dismissed.has(f.id)).sort((a, b) => a.lastSeen < b.lastSeen ? 1 : a.lastSeen > b.lastSeen ? -1 : 0);
16845
- }
16846
- var FILE_MODE = 384;
16847
- var init_leak_store = __esm(() => {
16848
- init_fp_home();
16849
- init_atomic_write();
16850
- init_leak_fingerprint();
16851
- });
16852
-
16853
- // src/audit/leak-notice.ts
16854
- import { existsSync as existsSync13, mkdirSync as mkdirSync9, readdirSync as readdirSync5, statSync as statSync8, writeFileSync as writeFileSync7, rmSync as rmSync4 } from "node:fs";
16855
- import { resolve as resolve11 } from "node:path";
16856
- function markLeakNoticeDelivered(ids, home, channel = "cli") {
16857
- const won = [];
16858
- try {
16859
- const dir = NOTICE_DIR(home, channel);
16860
- mkdirSync9(dir, { recursive: true });
16861
- for (const id of ids) {
16862
- if (!isFindingId(id))
16863
- continue;
16864
- try {
16865
- writeFileSync7(resolve11(dir, id), "", { flag: "wx", mode: 384 });
16866
- won.push(id);
16867
- } catch {}
16868
- }
16869
- } catch {}
16870
- return won;
16871
- }
16872
- function releaseLeakNoticeClaims(ids, home, channel = "cli") {
16873
- try {
16874
- const dir = NOTICE_DIR(home, channel);
16875
- for (const id of ids) {
16876
- if (!isFindingId(id))
16877
- continue;
16878
- rmSync4(resolve11(dir, id), { force: true });
16879
- }
16880
- } catch {}
16881
- }
16882
- function sessionNoticePending(sessionId, home) {
16883
- try {
16884
- if (!sessionId || !/^[\w.:-]{1,200}$/.test(sessionId))
16885
- return { ids: [], count: 0 };
16886
- const dir = resolve11(auditDir(home), "notified-sessions");
16887
- if (existsSync13(resolve11(dir, sessionId)))
16888
- return { ids: [], count: 0 };
16889
- const findings = activeFindings(readLeakRecord(home), home);
16890
- if (findings.length === 0)
16891
- return { ids: [], count: 0 };
16892
- const viewedAt = readLeakIdentity(home).reportViewedAt ?? 0;
16893
- const unviewed = findings.filter((f) => {
16894
- const seen = Date.parse(f.firstSeen);
16895
- return !Number.isFinite(seen) || seen > viewedAt;
16896
- });
16897
- return { ids: unviewed.map((f) => f.id), count: unviewed.length };
16898
- } catch {
16899
- return { ids: [], count: 0 };
16900
- }
16901
- }
16902
- function markSessionNoticed(sessionId, home) {
16903
- try {
16904
- if (!sessionId || !/^[\w.:-]{1,200}$/.test(sessionId))
16905
- return false;
16906
- const dir = resolve11(auditDir(home), "notified-sessions");
16907
- mkdirSync9(dir, { recursive: true });
16908
- writeFileSync7(resolve11(dir, sessionId), "", { flag: "wx", mode: 384 });
16909
- return true;
16910
- } catch {
16911
- return false;
16912
- }
16913
- }
16914
- var NOTICE_DIR = (home, channel = "cli") => resolve11(auditDir(home), channel === "cli" ? "notified" : `notified-${channel}`), MARKER_TTL_MS;
16915
- var init_leak_notice = __esm(() => {
16916
- init_fp_home();
16917
- init_leak_store();
16918
- init_leak_fingerprint();
16919
- MARKER_TTL_MS = 120 * 86400000;
16920
- });
16921
-
16922
16486
  // src/hooks/resolve-cwd.ts
16923
16487
  function resolveCwd(integration, parsed) {
16924
16488
  const direct = typeof parsed.cwd === "string" && parsed.cwd.length > 0 ? parsed.cwd : undefined;
@@ -17611,7 +17175,7 @@ var init_cursor_projects = __esm(() => {
17611
17175
  });
17612
17176
 
17613
17177
  // lib/sqlite-reader.ts
17614
- import { existsSync as existsSync14, readFileSync as readFileSync9 } from "node:fs";
17178
+ import { existsSync as existsSync11, readFileSync as readFileSync8 } from "node:fs";
17615
17179
  import initSqlJs from "sql.js/dist/sql-asm.js";
17616
17180
  function silenceSqliteExperimentalWarning() {
17617
17181
  if (warningPatched)
@@ -17662,7 +17226,7 @@ function clearWalFlag(bytes) {
17662
17226
  async function trySqlJs(dbPath) {
17663
17227
  try {
17664
17228
  const SQL = await loadSqlJs();
17665
- const db = new SQL.Database(clearWalFlag(readFileSync9(dbPath)));
17229
+ const db = new SQL.Database(clearWalFlag(readFileSync8(dbPath)));
17666
17230
  return {
17667
17231
  query(sql, params) {
17668
17232
  const stmt = db.prepare(sql);
@@ -17686,7 +17250,7 @@ async function trySqlJs(dbPath) {
17686
17250
  }
17687
17251
  }
17688
17252
  async function openSqliteReadonly(dbPath) {
17689
- if (!existsSync14(dbPath))
17253
+ if (!existsSync11(dbPath))
17690
17254
  return null;
17691
17255
  return await tryNodeSqlite(dbPath) ?? await trySqlJs(dbPath);
17692
17256
  }
@@ -18343,7 +17907,7 @@ var init_hermes_projects = __esm(() => {
18343
17907
 
18344
17908
  // lib/openclaw-sessions.ts
18345
17909
  import { readFile as readFile7 } from "node:fs/promises";
18346
- import { readdirSync as readdirSync6, statSync as statSync9 } from "node:fs";
17910
+ import { readdirSync as readdirSync5, statSync as statSync7 } from "node:fs";
18347
17911
  import { homedir as homedir12 } from "node:os";
18348
17912
  import { join as join14 } from "node:path";
18349
17913
  function openclawHome() {
@@ -18462,7 +18026,7 @@ function openclawLinesToLogEntries(lines, source = "session") {
18462
18026
  }
18463
18027
  function listOpenClawAgents() {
18464
18028
  try {
18465
- return readdirSync6(join14(openclawHome(), "agents"), { withFileTypes: true }).filter((d) => d.isDirectory() && !d.name.startsWith(".")).map((d) => d.name).sort();
18029
+ return readdirSync5(join14(openclawHome(), "agents"), { withFileTypes: true }).filter((d) => d.isDirectory() && !d.name.startsWith(".")).map((d) => d.name).sort();
18466
18030
  } catch {
18467
18031
  return [];
18468
18032
  }
@@ -18472,7 +18036,7 @@ function listOpenClawTranscripts() {
18472
18036
  const out = [];
18473
18037
  let agentIds;
18474
18038
  try {
18475
- agentIds = readdirSync6(agentsDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
18039
+ agentIds = readdirSync5(agentsDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
18476
18040
  } catch {
18477
18041
  return out;
18478
18042
  }
@@ -18480,7 +18044,7 @@ function listOpenClawTranscripts() {
18480
18044
  const sessionsDir = join14(agentsDir, agentId, "sessions");
18481
18045
  let files;
18482
18046
  try {
18483
- files = readdirSync6(sessionsDir);
18047
+ files = readdirSync5(sessionsDir);
18484
18048
  } catch {
18485
18049
  continue;
18486
18050
  }
@@ -18492,7 +18056,7 @@ function listOpenClawTranscripts() {
18492
18056
  continue;
18493
18057
  const transcriptPath = join14(sessionsDir, file);
18494
18058
  try {
18495
- const st = statSync9(transcriptPath);
18059
+ const st = statSync7(transcriptPath);
18496
18060
  out.push({ agentId, sessionId, transcriptPath, mtimeMs: st.mtimeMs, sizeBytes: st.size });
18497
18061
  } catch {}
18498
18062
  }
@@ -18543,7 +18107,7 @@ __export(exports_openclaw_projects, {
18543
18107
  getOpenClawSessions: () => getOpenClawSessions,
18544
18108
  openClawProjectPath: () => openClawProjectPath
18545
18109
  });
18546
- import { readFileSync as readFileSync10 } from "node:fs";
18110
+ import { readFileSync as readFileSync9 } from "node:fs";
18547
18111
  import { join as join15 } from "node:path";
18548
18112
  function str(v) {
18549
18113
  return typeof v === "string" && v.length > 0 ? v : undefined;
@@ -18553,7 +18117,7 @@ function readSessionsIndex(agentId) {
18553
18117
  const indexPath = join15(openclawHome(), "agents", agentId, "sessions", "sessions.json");
18554
18118
  let raw;
18555
18119
  try {
18556
- raw = JSON.parse(readFileSync10(indexPath, "utf-8"));
18120
+ raw = JSON.parse(readFileSync9(indexPath, "utf-8"));
18557
18121
  } catch {
18558
18122
  return out;
18559
18123
  }
@@ -18702,7 +18266,7 @@ var init_openclaw_projects = __esm(() => {
18702
18266
 
18703
18267
  // lib/factory-sessions.ts
18704
18268
  import { readFile as readFile8 } from "node:fs/promises";
18705
- import { readdirSync as readdirSync7, statSync as statSync10 } from "node:fs";
18269
+ import { readdirSync as readdirSync6, statSync as statSync8 } from "node:fs";
18706
18270
  import { homedir as homedir13 } from "node:os";
18707
18271
  import { join as join16 } from "node:path";
18708
18272
  function factoryHome() {
@@ -18848,7 +18412,7 @@ function listFactoryTranscripts() {
18848
18412
  const out = [];
18849
18413
  let projectDirs;
18850
18414
  try {
18851
- projectDirs = readdirSync7(root, { withFileTypes: true }).filter((d) => d.isDirectory());
18415
+ projectDirs = readdirSync6(root, { withFileTypes: true }).filter((d) => d.isDirectory());
18852
18416
  } catch {
18853
18417
  return out;
18854
18418
  }
@@ -18858,7 +18422,7 @@ function listFactoryTranscripts() {
18858
18422
  const projectPath = join16(root, projectName);
18859
18423
  let files;
18860
18424
  try {
18861
- files = readdirSync7(projectPath);
18425
+ files = readdirSync6(projectPath);
18862
18426
  } catch {
18863
18427
  continue;
18864
18428
  }
@@ -18870,7 +18434,7 @@ function listFactoryTranscripts() {
18870
18434
  continue;
18871
18435
  const transcriptPath = join16(projectPath, file);
18872
18436
  try {
18873
- const st = statSync10(transcriptPath);
18437
+ const st = statSync8(transcriptPath);
18874
18438
  out.push({ projectName, cwd, sessionId, transcriptPath, mtimeMs: st.mtimeMs, sizeBytes: st.size });
18875
18439
  } catch {}
18876
18440
  }
@@ -19290,7 +18854,7 @@ var init_devin_projects = __esm(() => {
19290
18854
 
19291
18855
  // lib/antigravity-sessions.ts
19292
18856
  import { readFile as readFile9 } from "node:fs/promises";
19293
- import { readdirSync as readdirSync8, statSync as statSync11 } from "node:fs";
18857
+ import { readdirSync as readdirSync7, statSync as statSync9 } from "node:fs";
19294
18858
  import { homedir as homedir15 } from "node:os";
19295
18859
  import { join as join18 } from "node:path";
19296
18860
  function antigravityHome() {
@@ -19415,7 +18979,7 @@ function listAntigravityTranscripts() {
19415
18979
  const out = [];
19416
18980
  let convoDirs;
19417
18981
  try {
19418
- convoDirs = readdirSync8(root, { withFileTypes: true }).filter((d) => d.isDirectory());
18982
+ convoDirs = readdirSync7(root, { withFileTypes: true }).filter((d) => d.isDirectory());
19419
18983
  } catch {
19420
18984
  return out;
19421
18985
  }
@@ -19425,7 +18989,7 @@ function listAntigravityTranscripts() {
19425
18989
  continue;
19426
18990
  const transcriptPath = join18(root, conversationId, rel);
19427
18991
  try {
19428
- const st = statSync11(transcriptPath);
18992
+ const st = statSync9(transcriptPath);
19429
18993
  if (!st.isFile())
19430
18994
  continue;
19431
18995
  out.push({ conversationId, transcriptPath, mtimeMs: st.mtimeMs, sizeBytes: st.size });
@@ -19438,7 +19002,7 @@ function findAntigravityTranscript(conversationId) {
19438
19002
  return null;
19439
19003
  const transcriptPath = join18(antigravityBrainRoot(), conversationId, antigravityTranscriptRelPath());
19440
19004
  try {
19441
- if (statSync11(transcriptPath).isFile())
19005
+ if (statSync9(transcriptPath).isFile())
19442
19006
  return transcriptPath;
19443
19007
  } catch {}
19444
19008
  return null;
@@ -19890,7 +19454,7 @@ var init_goose_projects = __esm(() => {
19890
19454
 
19891
19455
  // lib/projects.ts
19892
19456
  import { readdir as readdir5, stat as stat4 } from "node:fs/promises";
19893
- import { join as join21, resolve as resolve12, sep } from "node:path";
19457
+ import { join as join21, resolve as resolve11, sep } from "node:path";
19894
19458
  async function getMtime(path, label) {
19895
19459
  try {
19896
19460
  return (await stat4(path)).mtime;
@@ -20042,8 +19606,8 @@ function resolveProjectPath(projectName) {
20042
19606
  throw new RangeError("Empty project name");
20043
19607
  if (/^[/\\]/.test(projectName))
20044
19608
  throw new RangeError("Absolute project name");
20045
- const projectsPath = resolve12(getClaudeProjectsPath());
20046
- const candidate = resolve12(join21(projectsPath, projectName));
19609
+ const projectsPath = resolve11(getClaudeProjectsPath());
19610
+ const candidate = resolve11(join21(projectsPath, projectName));
20047
19611
  if (!candidate.startsWith(projectsPath + sep)) {
20048
19612
  throw new RangeError("Project path escapes root");
20049
19613
  }
@@ -20353,30 +19917,30 @@ var init_log_entries = __esm(() => {
20353
19917
  });
20354
19918
 
20355
19919
  // lib/codex-sessions.ts
20356
- import { readFileSync as readFileSync11, readdirSync as readdirSync9, existsSync as existsSync15, writeFileSync as writeFileSync8, mkdirSync as mkdirSync10, statSync as statSync12 } from "node:fs";
19920
+ import { readFileSync as readFileSync10, readdirSync as readdirSync8, existsSync as existsSync12, writeFileSync as writeFileSync6, mkdirSync as mkdirSync7, statSync as statSync10 } from "node:fs";
20357
19921
  import { readFile as readFile11 } from "node:fs/promises";
20358
- import { dirname as dirname9, join as join24 } from "node:path";
19922
+ import { dirname as dirname7, join as join24 } from "node:path";
20359
19923
  import { homedir as homedir17 } from "node:os";
20360
19924
  function readCache() {
20361
19925
  try {
20362
- if (!existsSync15(CACHE_PATH))
19926
+ if (!existsSync12(CACHE_PATH))
20363
19927
  return {};
20364
- return JSON.parse(readFileSync11(CACHE_PATH, "utf-8"));
19928
+ return JSON.parse(readFileSync10(CACHE_PATH, "utf-8"));
20365
19929
  } catch {
20366
19930
  return {};
20367
19931
  }
20368
19932
  }
20369
19933
  function writeCacheEntry(sessionId, path) {
20370
19934
  try {
20371
- mkdirSync10(dirname9(CACHE_PATH), { recursive: true });
19935
+ mkdirSync7(dirname7(CACHE_PATH), { recursive: true });
20372
19936
  const cache = readCache();
20373
19937
  cache[sessionId] = path;
20374
- writeFileSync8(CACHE_PATH, JSON.stringify(cache), "utf-8");
19938
+ writeFileSync6(CACHE_PATH, JSON.stringify(cache), "utf-8");
20375
19939
  } catch {}
20376
19940
  }
20377
19941
  function dirSearch(dir, sessionId) {
20378
19942
  try {
20379
- for (const f of readdirSync9(dir, { withFileTypes: true })) {
19943
+ for (const f of readdirSync8(dir, { withFileTypes: true })) {
20380
19944
  if (f.isFile() && f.name.includes(sessionId) && f.name.endsWith(".jsonl")) {
20381
19945
  return join24(dir, f.name);
20382
19946
  }
@@ -20387,7 +19951,7 @@ function dirSearch(dir, sessionId) {
20387
19951
  function findCodexTranscript(sessionId) {
20388
19952
  const cache = readCache();
20389
19953
  const cached = cache[sessionId];
20390
- if (cached && existsSync15(cached))
19954
+ if (cached && existsSync12(cached))
20391
19955
  return cached;
20392
19956
  const root = join24(homedir17(), ".codex", "sessions");
20393
19957
  const today = new Date;
@@ -20406,13 +19970,13 @@ function findCodexTranscript(sessionId) {
20406
19970
  }
20407
19971
  }
20408
19972
  try {
20409
- for (const y of readdirSync9(root, { withFileTypes: true })) {
19973
+ for (const y of readdirSync8(root, { withFileTypes: true })) {
20410
19974
  if (!y.isDirectory())
20411
19975
  continue;
20412
- for (const m of readdirSync9(join24(root, y.name), { withFileTypes: true })) {
19976
+ for (const m of readdirSync8(join24(root, y.name), { withFileTypes: true })) {
20413
19977
  if (!m.isDirectory())
20414
19978
  continue;
20415
- for (const d of readdirSync9(join24(root, y.name, m.name), { withFileTypes: true })) {
19979
+ for (const d of readdirSync8(join24(root, y.name, m.name), { withFileTypes: true })) {
20416
19980
  if (!d.isDirectory())
20417
19981
  continue;
20418
19982
  const hit = dirSearch(join24(root, y.name, m.name, d.name), sessionId);
@@ -20441,6 +20005,15 @@ function joinTexts(blocks, wantedType) {
20441
20005
  return blocks.filter((b) => b?.type === wantedType && typeof b.text === "string").map((b) => b.text).join(`
20442
20006
  `);
20443
20007
  }
20008
+ function toolOutputText(output) {
20009
+ if (typeof output === "string")
20010
+ return output;
20011
+ if (Array.isArray(output)) {
20012
+ return output.filter((block) => !!block && typeof block === "object").map((block) => typeof block.text === "string" ? block.text : "").filter(Boolean).join(`
20013
+ `);
20014
+ }
20015
+ return output === undefined ? "" : JSON.stringify(output);
20016
+ }
20444
20017
  async function parseCodexLog(fileContent, source = "session") {
20445
20018
  const lines = fileContent.split(`
20446
20019
  `).filter((line) => line.trim() !== "");
@@ -20517,10 +20090,11 @@ async function parseCodexLog(fileContent, source = "session") {
20517
20090
  });
20518
20091
  continue;
20519
20092
  }
20520
- if (subType === "function_call") {
20093
+ if (subType === "function_call" || subType === "custom_tool_call") {
20521
20094
  const callId = payload.call_id;
20522
20095
  const name = payload.name ?? "function_call";
20523
- const input = safeJsonParse4(payload.arguments);
20096
+ const encodedInput = payload.arguments ?? payload.input;
20097
+ const input = safeJsonParse4(encodedInput);
20524
20098
  const toolUse = {
20525
20099
  type: "tool_use",
20526
20100
  id: callId ?? `${timestamp}-${name}`,
@@ -20539,7 +20113,7 @@ async function parseCodexLog(fileContent, source = "session") {
20539
20113
  }
20540
20114
  continue;
20541
20115
  }
20542
- if (subType === "function_call_output") {
20116
+ if (subType === "function_call_output" || subType === "custom_tool_call_output") {
20543
20117
  const callId = payload.call_id;
20544
20118
  const block = callId ? toolUseById.get(callId) : undefined;
20545
20119
  if (block) {
@@ -20548,7 +20122,7 @@ async function parseCodexLog(fileContent, source = "session") {
20548
20122
  block.result = {
20549
20123
  timestamp,
20550
20124
  timestampFormatted: formatTimestamp(date),
20551
- content: typeof payload.output === "string" ? payload.output : JSON.stringify(payload.output),
20125
+ content: toolOutputText(payload.output),
20552
20126
  durationMs: duration,
20553
20127
  durationFormatted: formatDuration(duration)
20554
20128
  };
@@ -20641,7 +20215,7 @@ var init_codex_sessions = __esm(() => {
20641
20215
  });
20642
20216
 
20643
20217
  // src/hooks/resolve-permission-mode.ts
20644
- import { readFileSync as readFileSync12 } from "node:fs";
20218
+ import { readFileSync as readFileSync11 } from "node:fs";
20645
20219
  function resolvePermissionMode(integration, parsed, sessionId) {
20646
20220
  if (integration === "claude") {
20647
20221
  return parsed.permission_mode ?? "default";
@@ -20656,7 +20230,7 @@ function resolveCodexMode(sessionId) {
20656
20230
  const path = findCodexTranscript(sessionId);
20657
20231
  if (!path)
20658
20232
  return;
20659
- for (const line of readFileSync12(path, "utf-8").split(`
20233
+ for (const line of readFileSync11(path, "utf-8").split(`
20660
20234
  `)) {
20661
20235
  if (!line.includes("turn_context"))
20662
20236
  continue;
@@ -20681,9 +20255,9 @@ var init_resolve_permission_mode = __esm(() => {
20681
20255
  });
20682
20256
 
20683
20257
  // lib/copilot-sessions.ts
20684
- import { readFileSync as readFileSync13, readdirSync as readdirSync10, existsSync as existsSync16, statSync as statSync13 } from "node:fs";
20258
+ import { readFileSync as readFileSync12, readdirSync as readdirSync9, existsSync as existsSync13, statSync as statSync11 } from "node:fs";
20685
20259
  import { readFile as readFile12 } from "node:fs/promises";
20686
- import { join as join25, resolve as resolve13, sep as sep2 } from "node:path";
20260
+ import { join as join25, resolve as resolve12, sep as sep2 } from "node:path";
20687
20261
  import { homedir as homedir18 } from "node:os";
20688
20262
  function getCopilotHome() {
20689
20263
  return process.env.COPILOT_HOME || join25(homedir18(), ".copilot");
@@ -20694,8 +20268,8 @@ function getCopilotSessionStateRoot2() {
20694
20268
  function getCopilotSessionDir(sessionId) {
20695
20269
  if (!sessionId)
20696
20270
  return null;
20697
- const root = resolve13(getCopilotSessionStateRoot2());
20698
- const candidate = resolve13(root, sessionId);
20271
+ const root = resolve12(getCopilotSessionStateRoot2());
20272
+ const candidate = resolve12(root, sessionId);
20699
20273
  if (candidate === root || !candidate.startsWith(`${root}${sep2}`))
20700
20274
  return null;
20701
20275
  return candidate;
@@ -20710,17 +20284,17 @@ function findCopilotTranscript(sessionId) {
20710
20284
  const candidate = resolveSessionFile(sessionId, "events.jsonl");
20711
20285
  if (!candidate)
20712
20286
  return null;
20713
- return existsSync16(candidate) ? candidate : null;
20287
+ return existsSync13(candidate) ? candidate : null;
20714
20288
  }
20715
20289
  function findCopilotWorkspace(sessionId) {
20716
20290
  const candidate = resolveSessionFile(sessionId, "workspace.yaml");
20717
20291
  if (!candidate)
20718
20292
  return null;
20719
- return existsSync16(candidate) ? candidate : null;
20293
+ return existsSync13(candidate) ? candidate : null;
20720
20294
  }
20721
20295
  function readYamlScalar(path, key) {
20722
20296
  try {
20723
- const text = readFileSync13(path, "utf-8");
20297
+ const text = readFileSync12(path, "utf-8");
20724
20298
  const re = new RegExp(`^${key}\\s*:\\s*(.+?)\\s*$`, "m");
20725
20299
  const m = text.match(re);
20726
20300
  if (!m)
@@ -20743,6 +20317,8 @@ async function parseCopilotLog(fileContent, source = "session") {
20743
20317
  const rawLines = [];
20744
20318
  const toolUseById = new Map;
20745
20319
  const toolUseStartMs = new Map;
20320
+ let mostRecentToolUse;
20321
+ let mostRecentToolUseStartMs = 0;
20746
20322
  let cwd;
20747
20323
  let seenSessionStart = false;
20748
20324
  for (let i = 0;i < lines.length; i++) {
@@ -20838,8 +20414,24 @@ async function parseCopilotLog(fileContent, source = "session") {
20838
20414
  toolUseById.set(callId, toolUse);
20839
20415
  toolUseStartMs.set(callId, date.getTime());
20840
20416
  }
20417
+ mostRecentToolUse = toolUse;
20418
+ mostRecentToolUseStartMs = date.getTime();
20841
20419
  continue;
20842
20420
  }
20421
+ if (recType === "hook.start" && data.hookType === "postToolUse" && mostRecentToolUse) {
20422
+ const input = data.input ?? {};
20423
+ const hookResult = input.toolResult ?? {};
20424
+ const hookContent = hookResult.textResultForLlm ?? hookResult.sessionLog;
20425
+ if (typeof hookContent === "string" && hookContent.length > 0) {
20426
+ mostRecentToolUse.result = {
20427
+ timestamp,
20428
+ timestampFormatted: formatTimestamp(date),
20429
+ content: hookContent,
20430
+ durationMs: Math.max(0, date.getTime() - mostRecentToolUseStartMs),
20431
+ durationFormatted: formatDuration(Math.max(0, date.getTime() - mostRecentToolUseStartMs))
20432
+ };
20433
+ }
20434
+ }
20843
20435
  if (recType === "tool.execution_complete") {
20844
20436
  const callId = data.toolCallId;
20845
20437
  const block = callId ? toolUseById.get(callId) : undefined;
@@ -20849,7 +20441,8 @@ async function parseCopilotLog(fileContent, source = "session") {
20849
20441
  const telemetry = data.toolTelemetry ?? {};
20850
20442
  const reportedMs = telemetry.metrics?.commandTimeMs ?? telemetry.metrics?.durationMs ?? null;
20851
20443
  const durationMs = typeof reportedMs === "number" && reportedMs >= 0 ? reportedMs : Math.max(0, date.getTime() - startMs);
20852
- const content = result.detailedContent ?? result.content ?? "";
20444
+ const completionContent = result.detailedContent ?? result.content ?? "";
20445
+ const content = block.result?.content || completionContent;
20853
20446
  block.result = {
20854
20447
  timestamp,
20855
20448
  timestampFormatted: formatTimestamp(date),
@@ -20898,9 +20491,9 @@ var init_copilot_sessions = __esm(() => {
20898
20491
  });
20899
20492
 
20900
20493
  // lib/cursor-sessions.ts
20901
- import { readFileSync as readFileSync14, readdirSync as readdirSync11, existsSync as existsSync17, statSync as statSync14 } from "node:fs";
20494
+ import { readFileSync as readFileSync13, readdirSync as readdirSync10, existsSync as existsSync14, statSync as statSync12 } from "node:fs";
20902
20495
  import { readFile as readFile13 } from "node:fs/promises";
20903
- import { basename as basename3, join as join26, resolve as resolve14, sep as sep3 } from "node:path";
20496
+ import { basename as basename3, join as join26, resolve as resolve13, sep as sep3 } from "node:path";
20904
20497
  import { homedir as homedir19 } from "node:os";
20905
20498
  function getCursorHome2() {
20906
20499
  return process.env.CURSOR_HOME || join26(homedir19(), ".cursor");
@@ -20908,28 +20501,28 @@ function getCursorHome2() {
20908
20501
  function getCursorSessionDir(sessionId) {
20909
20502
  if (!sessionId)
20910
20503
  return null;
20911
- const home = resolve14(getCursorHome2());
20912
- const projectsRoot = resolve14(home, NEW_PROJECTS_DIR2);
20504
+ const home = resolve13(getCursorHome2());
20505
+ const projectsRoot = resolve13(home, NEW_PROJECTS_DIR2);
20913
20506
  let projectEntries = [];
20914
20507
  try {
20915
- projectEntries = readdirSync11(projectsRoot, { withFileTypes: true });
20508
+ projectEntries = readdirSync10(projectsRoot, { withFileTypes: true });
20916
20509
  } catch {}
20917
20510
  for (const entry of projectEntries) {
20918
20511
  if (!entry.isDirectory())
20919
20512
  continue;
20920
- const candidate = resolve14(projectsRoot, entry.name, NEW_AGENT_TRANSCRIPTS_DIR2, sessionId);
20921
- const transcriptRoot = resolve14(projectsRoot, entry.name, NEW_AGENT_TRANSCRIPTS_DIR2);
20513
+ const candidate = resolve13(projectsRoot, entry.name, NEW_AGENT_TRANSCRIPTS_DIR2, sessionId);
20514
+ const transcriptRoot = resolve13(projectsRoot, entry.name, NEW_AGENT_TRANSCRIPTS_DIR2);
20922
20515
  if (candidate === transcriptRoot || !candidate.startsWith(`${transcriptRoot}${sep3}`))
20923
20516
  continue;
20924
- if (existsSync17(candidate))
20517
+ if (existsSync14(candidate))
20925
20518
  return candidate;
20926
20519
  }
20927
20520
  for (const sub of LEGACY_SESSION_ROOT_CANDIDATES2) {
20928
- const root = resolve14(home, sub);
20929
- const candidate = resolve14(root, sessionId);
20521
+ const root = resolve13(home, sub);
20522
+ const candidate = resolve13(root, sessionId);
20930
20523
  if (candidate === root || !candidate.startsWith(`${root}${sep3}`))
20931
20524
  continue;
20932
- if (existsSync17(candidate))
20525
+ if (existsSync14(candidate))
20933
20526
  return candidate;
20934
20527
  }
20935
20528
  return null;
@@ -20939,11 +20532,11 @@ function findCursorTranscript(sessionId) {
20939
20532
  if (!dir)
20940
20533
  return null;
20941
20534
  const newCandidate = join26(dir, `${basename3(dir)}.jsonl`);
20942
- if (existsSync17(newCandidate))
20535
+ if (existsSync14(newCandidate))
20943
20536
  return newCandidate;
20944
20537
  for (const name of LEGACY_TRANSCRIPT_FILE_CANDIDATES2) {
20945
20538
  const candidate = join26(dir, name);
20946
- if (existsSync17(candidate))
20539
+ if (existsSync14(candidate))
20947
20540
  return candidate;
20948
20541
  }
20949
20542
  return null;
@@ -20973,8 +20566,27 @@ async function parseCursorLog(fileContent, source = "session") {
20973
20566
  if (!raw.type && raw.role && raw.message?.content) {
20974
20567
  const synthDate = new Date(SYNTH_T0 + i);
20975
20568
  const synthTs = synthDate.toISOString();
20976
- const textParts = raw.message.content.filter((c) => c?.type === "text" && typeof c.text === "string").map((c) => c.text).join("");
20569
+ const messageContent = raw.message.content;
20570
+ const textParts = messageContent.filter((c) => c?.type === "text" && typeof c.text === "string").map((c) => c.text).join("");
20977
20571
  if (raw.role === "user") {
20572
+ let attachedResult = false;
20573
+ for (const block of messageContent) {
20574
+ if (block?.type !== "tool_result")
20575
+ continue;
20576
+ const callId = typeof block.tool_use_id === "string" ? block.tool_use_id : undefined;
20577
+ const toolUse = callId ? toolUseById.get(callId) : undefined;
20578
+ if (!toolUse)
20579
+ continue;
20580
+ const durationMs = Math.max(0, synthDate.getTime() - (toolUseStartMs.get(callId) ?? synthDate.getTime()));
20581
+ toolUse.result = {
20582
+ timestamp: synthTs,
20583
+ timestampFormatted: formatTimestamp(synthDate),
20584
+ content: typeof block.content === "string" ? block.content : block.content == null ? "" : JSON.stringify(block.content),
20585
+ durationMs,
20586
+ durationFormatted: formatDuration(durationMs)
20587
+ };
20588
+ attachedResult = true;
20589
+ }
20978
20590
  const queryMatch = /<user_query>\s*([\s\S]*?)\s*<\/user_query>/.exec(textParts);
20979
20591
  const text = queryMatch ? queryMatch[1] : textParts;
20980
20592
  if (text) {
@@ -20983,11 +20595,35 @@ async function parseCursorLog(fileContent, source = "session") {
20983
20595
  ...baseEntry(rawCopy, synthTs, synthDate, source),
20984
20596
  message: { role: "user", content: text }
20985
20597
  });
20598
+ } else if (!attachedResult) {
20599
+ entries.push({
20600
+ type: "system",
20601
+ ...baseEntry(rawCopy, synthTs, synthDate, source),
20602
+ raw: rawCopy
20603
+ });
20986
20604
  }
20987
20605
  continue;
20988
20606
  }
20989
20607
  if (raw.role === "assistant") {
20990
- const blocks = textParts ? [{ type: "text", text: textParts }] : [];
20608
+ const blocks = [];
20609
+ if (textParts)
20610
+ blocks.push({ type: "text", text: textParts });
20611
+ for (let j = 0;j < messageContent.length; j++) {
20612
+ const contentBlock = messageContent[j];
20613
+ if (contentBlock?.type !== "tool_use")
20614
+ continue;
20615
+ const name = typeof contentBlock.name === "string" ? contentBlock.name : "tool";
20616
+ const id = typeof contentBlock.id === "string" && contentBlock.id ? contentBlock.id : `cursor-${i}-${name}-${j}`;
20617
+ const toolUse = {
20618
+ type: "tool_use",
20619
+ id,
20620
+ name,
20621
+ input: contentBlock.input && typeof contentBlock.input === "object" ? contentBlock.input : {}
20622
+ };
20623
+ blocks.push(toolUse);
20624
+ toolUseById.set(id, toolUse);
20625
+ toolUseStartMs.set(id, synthDate.getTime());
20626
+ }
20991
20627
  if (blocks.length === 0) {
20992
20628
  entries.push({
20993
20629
  type: "system",
@@ -21154,9 +20790,9 @@ var init_cursor_sessions = __esm(() => {
21154
20790
  });
21155
20791
 
21156
20792
  // lib/pi-sessions.ts
21157
- import { readFileSync as readFileSync15, readdirSync as readdirSync12, existsSync as existsSync18, statSync as statSync15 } from "node:fs";
20793
+ import { readFileSync as readFileSync14, readdirSync as readdirSync11, existsSync as existsSync15, statSync as statSync13 } from "node:fs";
21158
20794
  import { readFile as readFile14 } from "node:fs/promises";
21159
- import { join as join27, resolve as resolve15, sep as sep4 } from "node:path";
20795
+ import { join as join27, resolve as resolve14, sep as sep4 } from "node:path";
21160
20796
  import { homedir as homedir20 } from "node:os";
21161
20797
  function getPiSessionStateRoot() {
21162
20798
  return process.env.PI_SESSIONS_DIR || join27(homedir20(), ".pi", "agent", "sessions");
@@ -21167,20 +20803,20 @@ function isSafeSessionId(sessionId) {
21167
20803
  function findPiTranscript(sessionId) {
21168
20804
  if (!isSafeSessionId(sessionId))
21169
20805
  return null;
21170
- const root = resolve15(getPiSessionStateRoot());
20806
+ const root = resolve14(getPiSessionStateRoot());
21171
20807
  let cwdDirs;
21172
20808
  try {
21173
- cwdDirs = readdirSync12(root);
20809
+ cwdDirs = readdirSync11(root);
21174
20810
  } catch {
21175
20811
  return null;
21176
20812
  }
21177
20813
  for (const cwdDir of cwdDirs) {
21178
- const cwdPath = resolve15(root, cwdDir);
20814
+ const cwdPath = resolve14(root, cwdDir);
21179
20815
  if (!cwdPath.startsWith(`${root}${sep4}`))
21180
20816
  continue;
21181
20817
  let files;
21182
20818
  try {
21183
- files = readdirSync12(cwdPath);
20819
+ files = readdirSync11(cwdPath);
21184
20820
  } catch {
21185
20821
  continue;
21186
20822
  }
@@ -21188,10 +20824,10 @@ function findPiTranscript(sessionId) {
21188
20824
  const m = SESSION_FILE_RE2.exec(f);
21189
20825
  if (!m || m[1].toLowerCase() !== sessionId.toLowerCase())
21190
20826
  continue;
21191
- const candidate = resolve15(cwdPath, f);
20827
+ const candidate = resolve14(cwdPath, f);
21192
20828
  if (!candidate.startsWith(`${cwdPath}${sep4}`))
21193
20829
  continue;
21194
- if (existsSync18(candidate))
20830
+ if (existsSync15(candidate))
21195
20831
  return candidate;
21196
20832
  }
21197
20833
  }
@@ -21594,14 +21230,53 @@ var init_pack_failclosed = __esm(() => {
21594
21230
  ]);
21595
21231
  });
21596
21232
 
21233
+ // lib/atomic-write.ts
21234
+ import {
21235
+ chmodSync as chmodSync2,
21236
+ existsSync as existsSync16,
21237
+ mkdirSync as mkdirSync8,
21238
+ renameSync as renameSync4,
21239
+ rmSync as rmSync3,
21240
+ statSync as statSync14,
21241
+ writeFileSync as writeFileSync7
21242
+ } from "node:fs";
21243
+ import { dirname as dirname8 } from "node:path";
21244
+ import { randomBytes } from "node:crypto";
21245
+ function writeJsonAtomically(filePath, value, opts = {}) {
21246
+ const mode = opts.mode ?? 384;
21247
+ const dirMode = opts.dirMode ?? 448;
21248
+ const dir = dirname8(filePath);
21249
+ if (!existsSync16(dir))
21250
+ mkdirSync8(dir, { recursive: true, mode: dirMode });
21251
+ const tmp = `${filePath}.${process.pid}.${randomBytes(6).toString("hex")}.tmp`;
21252
+ try {
21253
+ writeFileSync7(tmp, JSON.stringify(value, null, 2), { mode });
21254
+ try {
21255
+ if ((statSync14(tmp).mode & 63) !== 0)
21256
+ chmodSync2(tmp, mode);
21257
+ } catch {}
21258
+ renameSync4(tmp, filePath);
21259
+ try {
21260
+ if ((statSync14(filePath).mode & 63) !== 0)
21261
+ chmodSync2(filePath, mode);
21262
+ } catch {}
21263
+ } catch (err) {
21264
+ try {
21265
+ rmSync3(tmp, { force: true });
21266
+ } catch {}
21267
+ throw err;
21268
+ }
21269
+ }
21270
+ var init_atomic_write = () => {};
21271
+
21597
21272
  // src/hooks/session-pause.ts
21598
- import { existsSync as existsSync19, mkdirSync as mkdirSync11, readdirSync as readdirSync13, readFileSync as readFileSync16, rmSync as rmSync5 } from "node:fs";
21273
+ import { existsSync as existsSync17, mkdirSync as mkdirSync9, readdirSync as readdirSync12, readFileSync as readFileSync15, rmSync as rmSync4 } from "node:fs";
21599
21274
  import { createHash as createHash6 } from "node:crypto";
21600
- import { join as join28, resolve as resolve16 } from "node:path";
21275
+ import { join as join28, resolve as resolve15 } from "node:path";
21601
21276
  function pauseStateDir() {
21602
21277
  const override = process.env.FAILPROOFAI_STATE_DIR;
21603
21278
  if (override)
21604
- return resolve16(override, "sessions");
21279
+ return resolve15(override, "sessions");
21605
21280
  return sessionPauseDir();
21606
21281
  }
21607
21282
  function pauseFilePath(sessionId) {
@@ -21662,9 +21337,9 @@ function readActivePause(sessionId, now = Date.now()) {
21662
21337
  return null;
21663
21338
  try {
21664
21339
  const path = pauseFilePath(sessionId);
21665
- if (!existsSync19(path))
21340
+ if (!existsSync17(path))
21666
21341
  return null;
21667
- const stored = parseStored(JSON.parse(readFileSync16(path, "utf8")));
21342
+ const stored = parseStored(JSON.parse(readFileSync15(path, "utf8")));
21668
21343
  if (!stored)
21669
21344
  return null;
21670
21345
  if (stored.expiresAt <= now)
@@ -21687,16 +21362,16 @@ function writePause(opts) {
21687
21362
  setBy: opts.setBy ?? "cli",
21688
21363
  ...opts.cwd ? { cwd: opts.cwd } : {}
21689
21364
  };
21690
- mkdirSync11(pauseStateDir(), { recursive: true, mode: 448 });
21365
+ mkdirSync9(pauseStateDir(), { recursive: true, mode: 448 });
21691
21366
  writeJsonAtomically(pauseFilePath(opts.sessionId), { schemaVersion: SCHEMA_VERSION, ...pause });
21692
21367
  return pause;
21693
21368
  }
21694
21369
  function clearPause(sessionId) {
21695
21370
  const path = pauseFilePath(sessionId);
21696
- if (!existsSync19(path))
21371
+ if (!existsSync17(path))
21697
21372
  return false;
21698
21373
  try {
21699
- rmSync5(path);
21374
+ rmSync4(path);
21700
21375
  return true;
21701
21376
  } catch {
21702
21377
  return false;
@@ -21704,12 +21379,12 @@ function clearPause(sessionId) {
21704
21379
  }
21705
21380
  function listActivePauses(now = Date.now()) {
21706
21381
  const dir = pauseStateDir();
21707
- if (!existsSync19(dir))
21382
+ if (!existsSync17(dir))
21708
21383
  return [];
21709
21384
  const out = [];
21710
21385
  let names;
21711
21386
  try {
21712
- names = readdirSync13(dir);
21387
+ names = readdirSync12(dir);
21713
21388
  } catch {
21714
21389
  return [];
21715
21390
  }
@@ -21717,7 +21392,7 @@ function listActivePauses(now = Date.now()) {
21717
21392
  if (!name.endsWith(".json"))
21718
21393
  continue;
21719
21394
  try {
21720
- const stored = parseStored(JSON.parse(readFileSync16(join28(dir, name), "utf8")));
21395
+ const stored = parseStored(JSON.parse(readFileSync15(join28(dir, name), "utf8")));
21721
21396
  if (!stored || stored.expiresAt <= now)
21722
21397
  continue;
21723
21398
  const { schemaVersion: _ignored, ...pause } = stored;
@@ -21758,17 +21433,17 @@ var init_session_pause = __esm(() => {
21758
21433
  import { createHash as createHash7 } from "node:crypto";
21759
21434
  import {
21760
21435
  chmodSync as chmodSync3,
21761
- existsSync as existsSync20,
21762
- mkdirSync as mkdirSync12,
21763
- readdirSync as readdirSync14,
21764
- readFileSync as readFileSync17,
21436
+ existsSync as existsSync18,
21437
+ mkdirSync as mkdirSync10,
21438
+ readdirSync as readdirSync13,
21439
+ readFileSync as readFileSync16,
21765
21440
  renameSync as renameSync5,
21766
- rmSync as rmSync6,
21767
- statSync as statSync16,
21768
- writeFileSync as writeFileSync9
21441
+ rmSync as rmSync5,
21442
+ statSync as statSync15,
21443
+ writeFileSync as writeFileSync8
21769
21444
  } from "node:fs";
21770
21445
  import { createRequire as createRequire2 } from "node:module";
21771
- import { dirname as dirname10, resolve as resolve17 } from "node:path";
21446
+ import { dirname as dirname9, resolve as resolve16 } from "node:path";
21772
21447
  import { gunzipSync } from "node:zlib";
21773
21448
  function baseUrl2() {
21774
21449
  return (process.env.FAILPROOFAI_DAEMON_BASE_URL || DEFAULT_BASE_URL2).replace(/\/+$/, "");
@@ -21777,7 +21452,7 @@ function daemonBinaryDir() {
21777
21452
  return binDir();
21778
21453
  }
21779
21454
  function installedBinaryPath(ver = version2) {
21780
- return resolve17(daemonBinaryDir(), `failproofaid-${ver}`);
21455
+ return resolve16(daemonBinaryDir(), `failproofaid-${ver}`);
21781
21456
  }
21782
21457
  function daemonAssetUrl(key, ver = version2) {
21783
21458
  return `${baseUrl2()}/v${ver}/failproofaid-${key}.gz`;
@@ -21794,35 +21469,35 @@ function npmPlatformBinaryPath(key) {
21794
21469
  return null;
21795
21470
  const name = platformPackageName(key);
21796
21471
  try {
21797
- const requireFromRoot = createRequire2(resolve17(packageRoot, "package.json"));
21798
- const found = platformPackageBinary(dirname10(requireFromRoot.resolve(`${name}/package.json`)));
21472
+ const requireFromRoot = createRequire2(resolve16(packageRoot, "package.json"));
21473
+ const found = platformPackageBinary(dirname9(requireFromRoot.resolve(`${name}/package.json`)));
21799
21474
  if (found)
21800
21475
  return found;
21801
21476
  } catch {}
21802
- return platformPackageBinary(resolve17(packageRoot, "node_modules", name));
21477
+ return platformPackageBinary(resolve16(packageRoot, "node_modules", name));
21803
21478
  }
21804
21479
  function platformPackageBinary(dir) {
21805
21480
  try {
21806
- const manifest = JSON.parse(readFileSync17(resolve17(dir, "package.json"), "utf8"));
21481
+ const manifest = JSON.parse(readFileSync16(resolve16(dir, "package.json"), "utf8"));
21807
21482
  if (manifest.version !== version2)
21808
21483
  return null;
21809
21484
  } catch {
21810
21485
  return null;
21811
21486
  }
21812
- const candidate = resolve17(dir, "bin", "failproofaid");
21813
- return existsSync20(candidate) ? candidate : null;
21487
+ const candidate = resolve16(dir, "bin", "failproofaid");
21488
+ return existsSync18(candidate) ? candidate : null;
21814
21489
  }
21815
21490
  function pruneOldDaemonBinaries(keep = 2) {
21816
21491
  const removed = [];
21817
21492
  try {
21818
21493
  const dir = daemonBinaryDir();
21819
- const entries = readdirSync14(dir).filter((f) => f.startsWith("failproofaid-") && !f.endsWith(".tmp")).map((f) => {
21820
- const full = resolve17(dir, f);
21821
- return { full, mtime: statSync16(full).mtimeMs };
21494
+ const entries = readdirSync13(dir).filter((f) => f.startsWith("failproofaid-") && !f.endsWith(".tmp")).map((f) => {
21495
+ const full = resolve16(dir, f);
21496
+ return { full, mtime: statSync15(full).mtimeMs };
21822
21497
  }).sort((a, b) => b.mtime - a.mtime);
21823
21498
  for (const stale of entries.slice(keep)) {
21824
21499
  try {
21825
- rmSync6(stale.full, { force: true });
21500
+ rmSync5(stale.full, { force: true });
21826
21501
  removed.push(stale.full);
21827
21502
  } catch {}
21828
21503
  }
@@ -21833,13 +21508,13 @@ function installBinaryBytes(binary) {
21833
21508
  const target = installedBinaryPath();
21834
21509
  const tempPath = `${target}.${process.pid}.tmp`;
21835
21510
  try {
21836
- mkdirSync12(daemonBinaryDir(), { recursive: true });
21837
- writeFileSync9(tempPath, binary);
21511
+ mkdirSync10(daemonBinaryDir(), { recursive: true });
21512
+ writeFileSync8(tempPath, binary);
21838
21513
  chmodSync3(tempPath, 493);
21839
21514
  renameSync5(tempPath, target);
21840
21515
  return target;
21841
21516
  } catch (err) {
21842
- rmSync6(tempPath, { force: true });
21517
+ rmSync5(tempPath, { force: true });
21843
21518
  throw err;
21844
21519
  }
21845
21520
  }
@@ -21853,7 +21528,7 @@ function installFromNpmPackage(key) {
21853
21528
  if (!source)
21854
21529
  return { error: `${platformPackageName(key)} is not installed` };
21855
21530
  try {
21856
- const bytes = readFileSync17(source);
21531
+ const bytes = readFileSync16(source);
21857
21532
  const mismatch = binaryDigestMismatch(expectedNpmBinaryDigest(key), bytes, source);
21858
21533
  if (mismatch)
21859
21534
  return { error: mismatch };
@@ -21888,7 +21563,7 @@ function digestFor2(manifest, assetName) {
21888
21563
  }
21889
21564
  async function downloadFailproofaidBinary(key) {
21890
21565
  const target = installedBinaryPath();
21891
- if (existsSync20(target))
21566
+ if (existsSync18(target))
21892
21567
  return { path: target };
21893
21568
  if (process.env.FAILPROOFAI_NO_DOWNLOAD) {
21894
21569
  return { error: "daemon downloads are disabled (FAILPROOFAI_NO_DOWNLOAD)" };
@@ -21922,10 +21597,10 @@ var init_daemon_download = __esm(() => {
21922
21597
 
21923
21598
  // src/hooks/daemon-client.ts
21924
21599
  import { createConnection as createConnection2 } from "node:net";
21925
- import { existsSync as existsSync21 } from "node:fs";
21600
+ import { existsSync as existsSync19 } from "node:fs";
21926
21601
  function daemonSocketPresent() {
21927
21602
  try {
21928
- return existsSync21(socketPath2());
21603
+ return existsSync19(socketPath2());
21929
21604
  } catch {
21930
21605
  return false;
21931
21606
  }
@@ -22051,16 +21726,16 @@ var init_daemon_client2 = __esm(() => {
22051
21726
 
22052
21727
  // src/hooks/daemon-service.ts
22053
21728
  import {
22054
- existsSync as existsSync22,
22055
- mkdirSync as mkdirSync13,
21729
+ existsSync as existsSync20,
21730
+ mkdirSync as mkdirSync11,
22056
21731
  mkdtempSync,
22057
- readFileSync as readFileSync18,
22058
- writeFileSync as writeFileSync10,
21732
+ readFileSync as readFileSync17,
21733
+ writeFileSync as writeFileSync9,
22059
21734
  unlinkSync as unlinkSync3,
22060
- rmSync as rmSync7
21735
+ rmSync as rmSync6
22061
21736
  } from "node:fs";
22062
21737
  import { homedir as homedir21, tmpdir as tmpdir2, userInfo } from "node:os";
22063
- import { resolve as resolve18 } from "node:path";
21738
+ import { resolve as resolve17 } from "node:path";
22064
21739
  import { execFileSync as execFileSync2 } from "node:child_process";
22065
21740
  function setDaemonConfigured(value, installedVersion) {
22066
21741
  try {
@@ -22082,13 +21757,13 @@ function resolveFailproofaidBinaryPath() {
22082
21757
  if (process.env.FAILPROOFAI_DAEMON_BINARY)
22083
21758
  return process.env.FAILPROOFAI_DAEMON_BINARY;
22084
21759
  const downloaded = installedBinaryPath();
22085
- if (existsSync22(downloaded))
21760
+ if (existsSync20(downloaded))
22086
21761
  return downloaded;
22087
21762
  const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT;
22088
21763
  if (packageRoot) {
22089
21764
  for (const profile of ["release", "debug"]) {
22090
- const candidate = resolve18(packageRoot, "target", profile, "failproofaid");
22091
- if (existsSync22(candidate))
21765
+ const candidate = resolve17(packageRoot, "target", profile, "failproofaid");
21766
+ if (existsSync20(candidate))
22092
21767
  return candidate;
22093
21768
  }
22094
21769
  }
@@ -22118,8 +21793,8 @@ function resolveWorkerCommand() {
22118
21793
  const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT;
22119
21794
  if (!packageRoot)
22120
21795
  return null;
22121
- const workerScript = resolve18(packageRoot, "dist", "worker.mjs");
22122
- if (!existsSync22(workerScript))
21796
+ const workerScript = resolve17(packageRoot, "dist", "worker.mjs");
21797
+ if (!existsSync20(workerScript))
22123
21798
  return null;
22124
21799
  return `${shellQuote(process.execPath)} ${shellQuote(workerScript)}`;
22125
21800
  }
@@ -22129,8 +21804,8 @@ function resolveCliCommand() {
22129
21804
  const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT;
22130
21805
  if (!packageRoot)
22131
21806
  return null;
22132
- const cliScript = resolve18(packageRoot, "dist", "cli.mjs");
22133
- if (!existsSync22(cliScript))
21807
+ const cliScript = resolve17(packageRoot, "dist", "cli.mjs");
21808
+ if (!existsSync20(cliScript))
22134
21809
  return null;
22135
21810
  return `${shellQuote(process.execPath)} ${shellQuote(cliScript)}`;
22136
21811
  }
@@ -22143,8 +21818,8 @@ function workerScriptPath() {
22143
21818
  const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT;
22144
21819
  if (!packageRoot)
22145
21820
  return null;
22146
- const workerScript = resolve18(packageRoot, "dist", "worker.mjs");
22147
- return existsSync22(workerScript) ? workerScript : null;
21821
+ const workerScript = resolve17(packageRoot, "dist", "worker.mjs");
21822
+ return existsSync20(workerScript) ? workerScript : null;
22148
21823
  }
22149
21824
  function assertUnitSafe(value, field) {
22150
21825
  if (UNIT_UNSAFE_RE.test(value)) {
@@ -22170,10 +21845,10 @@ function systemdUnitDir() {
22170
21845
  return process.env.FAILPROOFAI_SYSTEMD_DIR || "/etc/systemd/system";
22171
21846
  }
22172
21847
  function systemdUnitPath(user = serviceUser()) {
22173
- return resolve18(systemdUnitDir(), systemdUnitName(user));
21848
+ return resolve17(systemdUnitDir(), systemdUnitName(user));
22174
21849
  }
22175
21850
  function legacySystemdUserUnitPath() {
22176
- return resolve18(homedir21(), ".config", "systemd", "user", "failproofaid.service");
21851
+ return resolve17(homedir21(), ".config", "systemd", "user", "failproofaid.service");
22177
21852
  }
22178
21853
  function launchdLabel(user = serviceUser()) {
22179
21854
  return `ai.failproof.failproofaid.${user}`;
@@ -22182,7 +21857,7 @@ function launchdPlistPath(user = serviceUser()) {
22182
21857
  return `/Library/LaunchDaemons/${launchdLabel(user)}.plist`;
22183
21858
  }
22184
21859
  function legacyLaunchAgentPlistPath() {
22185
- return resolve18(homedir21(), "Library", "LaunchAgents", "ai.failproof.failproofaid.plist");
21860
+ return resolve17(homedir21(), "Library", "LaunchAgents", "ai.failproof.failproofaid.plist");
22186
21861
  }
22187
21862
  function legacySharedLaunchDaemonPath() {
22188
21863
  return "/Library/LaunchDaemons/ai.failproof.failproofaid.plist";
@@ -22230,20 +21905,20 @@ function runPrivileged(command, args) {
22230
21905
  execFileSync2(cmd, argv, { stdio: "ignore", timeout: SERVICE_CMD_TIMEOUT_MS });
22231
21906
  }
22232
21907
  function writePrivilegedFile(destination, contents, mode = "0644") {
22233
- const stagingDir = mkdtempSync(resolve18(tmpdir2(), "failproofaid-stage-"));
22234
- const staging = resolve18(stagingDir, "service-definition");
21908
+ const stagingDir = mkdtempSync(resolve17(tmpdir2(), "failproofaid-stage-"));
21909
+ const staging = resolve17(stagingDir, "service-definition");
22235
21910
  try {
22236
- writeFileSync10(staging, contents, "utf8");
21911
+ writeFileSync9(staging, contents, "utf8");
22237
21912
  runPrivileged("install", ["-m", mode, staging, destination]);
22238
21913
  } finally {
22239
- rmSync7(stagingDir, { recursive: true, force: true });
21914
+ rmSync6(stagingDir, { recursive: true, force: true });
22240
21915
  }
22241
21916
  }
22242
21917
  function removeLegacyUserService() {
22243
21918
  try {
22244
21919
  if (process.platform === "linux") {
22245
21920
  const legacy = legacySystemdUserUnitPath();
22246
- if (!existsSync22(legacy))
21921
+ if (!existsSync20(legacy))
22247
21922
  return;
22248
21923
  try {
22249
21924
  execFileSync2("systemctl", ["--user", "disable", "--now", "failproofaid.service"], {
@@ -22260,7 +21935,7 @@ function removeLegacyUserService() {
22260
21935
  } catch {}
22261
21936
  } else {
22262
21937
  const legacyAgent = legacyLaunchAgentPlistPath();
22263
- if (existsSync22(legacyAgent)) {
21938
+ if (existsSync20(legacyAgent)) {
22264
21939
  try {
22265
21940
  execFileSync2("launchctl", ["unload", "-w", legacyAgent], {
22266
21941
  stdio: "ignore",
@@ -22270,7 +21945,7 @@ function removeLegacyUserService() {
22270
21945
  unlinkSync3(legacyAgent);
22271
21946
  }
22272
21947
  const legacyDaemon = legacySharedLaunchDaemonPath();
22273
- if (existsSync22(legacyDaemon)) {
21948
+ if (existsSync20(legacyDaemon)) {
22274
21949
  try {
22275
21950
  runPrivileged("launchctl", ["unload", "-w", legacyDaemon]);
22276
21951
  } catch {}
@@ -22287,7 +21962,7 @@ function systemdUnitContents(binaryPath, workerCmd, cliCmd = null) {
22287
21962
  const user = assertUnitSafe(serviceUser(), "User");
22288
21963
  assertUnitSafe(binaryPath, "ExecStart");
22289
21964
  assertUnitSafe(homedir21(), "HOME");
22290
- const conditionPaths = [binaryPath, workerScriptPath()].filter((p) => typeof p === "string" && existsSync22(p));
21965
+ const conditionPaths = [binaryPath, workerScriptPath()].filter((p) => typeof p === "string" && existsSync20(p));
22291
21966
  const conditionLines = conditionPaths.map((p) => `ConditionPathExists=${assertUnitSafe(p, "ConditionPathExists")}
22292
21967
  `).join("");
22293
21968
  return `[Unit]
@@ -22348,9 +22023,9 @@ ${env.map(([key, value]) => ` <key>${key}</key>
22348
22023
  <key>UserName</key>
22349
22024
  <string>${escapeXml(serviceUser())}</string>
22350
22025
  ${envBlock} <key>StandardOutPath</key>
22351
- <string>${escapeXml(resolve18(logDir, "failproofaid.log"))}</string>
22026
+ <string>${escapeXml(resolve17(logDir, "failproofaid.log"))}</string>
22352
22027
  <key>StandardErrorPath</key>
22353
- <string>${escapeXml(resolve18(logDir, "failproofaid.err.log"))}</string>
22028
+ <string>${escapeXml(resolve17(logDir, "failproofaid.err.log"))}</string>
22354
22029
  </dict>
22355
22030
  </plist>
22356
22031
  `;
@@ -22396,7 +22071,7 @@ async function installDaemonService() {
22396
22071
  } else {
22397
22072
  const plistPath = launchdPlistPath();
22398
22073
  const logDir = logsDir();
22399
- mkdirSync13(logDir, { recursive: true });
22074
+ mkdirSync11(logDir, { recursive: true });
22400
22075
  try {
22401
22076
  runPrivileged("launchctl", ["unload", plistPath]);
22402
22077
  } catch {}
@@ -22482,10 +22157,10 @@ function readInstalledServiceDefinition() {
22482
22157
  if (!isDaemonSupportedPlatform())
22483
22158
  return null;
22484
22159
  const path = daemonServiceFilePath();
22485
- if (!path || !existsSync22(path))
22160
+ if (!path || !existsSync20(path))
22486
22161
  return null;
22487
22162
  try {
22488
- return readFileSync18(path, "utf8");
22163
+ return readFileSync17(path, "utf8");
22489
22164
  } catch {
22490
22165
  return null;
22491
22166
  }
@@ -22594,7 +22269,7 @@ async function ensureDaemonServiceCurrent() {
22594
22269
  restartSystemdUnit();
22595
22270
  } else {
22596
22271
  const plistPath = launchdPlistPath();
22597
- mkdirSync13(logDir, { recursive: true });
22272
+ mkdirSync11(logDir, { recursive: true });
22598
22273
  previous = definition;
22599
22274
  try {
22600
22275
  runPrivileged("launchctl", ["unload", plistPath]);
@@ -22618,7 +22293,7 @@ async function uninstallDaemonService() {
22618
22293
  try {
22619
22294
  if (process.platform === "linux") {
22620
22295
  const unitPath = systemdUnitPath();
22621
- if (!existsSync22(unitPath))
22296
+ if (!existsSync20(unitPath))
22622
22297
  return;
22623
22298
  try {
22624
22299
  runPrivileged("systemctl", ["disable", "--now", systemdUnitName()]);
@@ -22629,7 +22304,7 @@ async function uninstallDaemonService() {
22629
22304
  } catch {}
22630
22305
  } else {
22631
22306
  const plistPath = launchdPlistPath();
22632
- if (!existsSync22(plistPath))
22307
+ if (!existsSync20(plistPath))
22633
22308
  return;
22634
22309
  try {
22635
22310
  runPrivileged("launchctl", ["unload", "-w", plistPath]);
@@ -22646,7 +22321,7 @@ function daemonVersionSkew() {
22646
22321
  const recorded = readVersionFile()?.daemon;
22647
22322
  if (!recorded)
22648
22323
  return null;
22649
- if (!existsSync22(installedBinaryPath(recorded)))
22324
+ if (!existsSync20(installedBinaryPath(recorded)))
22650
22325
  return null;
22651
22326
  return recorded === version2 ? null : { installed: recorded, expected: version2 };
22652
22327
  }
@@ -22664,7 +22339,7 @@ function daemonServiceStatus() {
22664
22339
  if (!isDaemonSupportedPlatform())
22665
22340
  return "unsupported-platform";
22666
22341
  if (process.platform === "linux") {
22667
- if (!existsSync22(systemdUnitPath()))
22342
+ if (!existsSync20(systemdUnitPath()))
22668
22343
  return "not-installed";
22669
22344
  try {
22670
22345
  const out = execFileSync2("systemctl", ["is-active", systemdUnitName()], {
@@ -22677,7 +22352,7 @@ function daemonServiceStatus() {
22677
22352
  }
22678
22353
  }
22679
22354
  const plistPath = launchdPlistPath();
22680
- if (!existsSync22(plistPath))
22355
+ if (!existsSync20(plistPath))
22681
22356
  return "not-installed";
22682
22357
  try {
22683
22358
  const root = typeof process.getuid === "function" && process.getuid() === 0;
@@ -22709,48 +22384,48 @@ var init_daemon_service = __esm(() => {
22709
22384
  // src/hooks/fp-reset.ts
22710
22385
  import {
22711
22386
  copyFileSync,
22712
- existsSync as existsSync23,
22713
- mkdirSync as mkdirSync14,
22714
- readFileSync as readFileSync19,
22715
- readdirSync as readdirSync15,
22387
+ existsSync as existsSync21,
22388
+ mkdirSync as mkdirSync12,
22389
+ readFileSync as readFileSync18,
22390
+ readdirSync as readdirSync14,
22716
22391
  renameSync as renameSync6,
22717
- rmSync as rmSync8,
22392
+ rmSync as rmSync7,
22718
22393
  rmdirSync,
22719
- statSync as statSync17,
22720
- writeFileSync as writeFileSync11
22394
+ statSync as statSync16,
22395
+ writeFileSync as writeFileSync10
22721
22396
  } from "node:fs";
22722
- import { dirname as dirname11, isAbsolute as isAbsolute3, relative as relative4, resolve as resolve19 } from "node:path";
22397
+ import { dirname as dirname10, isAbsolute as isAbsolute3, relative as relative4, resolve as resolve18 } from "node:path";
22723
22398
  function migrateConventionPolicies() {
22724
22399
  const from = legacy.customPoliciesDir();
22725
- if (!existsSync23(from))
22400
+ if (!existsSync21(from))
22726
22401
  return [];
22727
22402
  const moved = [];
22728
22403
  const mergeInto = (dir, dest, prefix) => {
22729
22404
  let entries;
22730
22405
  try {
22731
- entries = readdirSync15(dir, { withFileTypes: true });
22406
+ entries = readdirSync14(dir, { withFileTypes: true });
22732
22407
  } catch {
22733
22408
  return;
22734
22409
  }
22735
22410
  if (entries.length === 0)
22736
22411
  return;
22737
22412
  try {
22738
- mkdirSync14(dest, { recursive: true });
22413
+ mkdirSync12(dest, { recursive: true });
22739
22414
  } catch {
22740
22415
  return;
22741
22416
  }
22742
22417
  for (const entry of entries) {
22743
- const source = resolve19(dir, entry.name);
22744
- const target = resolve19(dest, entry.name);
22418
+ const source = resolve18(dir, entry.name);
22419
+ const target = resolve18(dest, entry.name);
22745
22420
  const name = `${prefix}${entry.name}`;
22746
- if (!existsSync23(target)) {
22421
+ if (!existsSync21(target)) {
22747
22422
  try {
22748
22423
  renameSync6(source, target);
22749
22424
  moved.push(name);
22750
22425
  } catch {}
22751
22426
  continue;
22752
22427
  }
22753
- if (entry.isDirectory() && statSync17(target).isDirectory()) {
22428
+ if (entry.isDirectory() && statSync16(target).isDirectory()) {
22754
22429
  mergeInto(source, target, `${name}/`);
22755
22430
  try {
22756
22431
  rmdirSync(source);
@@ -22770,23 +22445,23 @@ function migrateLegacySpool() {
22770
22445
  [legacy.spoolDir(), spoolDir()],
22771
22446
  [legacy.failedDir(), failedDir()]
22772
22447
  ]) {
22773
- if (!existsSync23(from))
22448
+ if (!existsSync21(from))
22774
22449
  continue;
22775
22450
  try {
22776
- mkdirSync14(to, { recursive: true });
22777
- for (const entry of readdirSync15(from, { withFileTypes: true })) {
22451
+ mkdirSync12(to, { recursive: true });
22452
+ for (const entry of readdirSync14(from, { withFileTypes: true })) {
22778
22453
  if (!entry.isFile())
22779
22454
  continue;
22780
22455
  let name = entry.name;
22781
22456
  let n = 0;
22782
- while (existsSync23(resolve19(to, name)))
22457
+ while (existsSync21(resolve18(to, name)))
22783
22458
  name = `legacy-${n++}-${entry.name}`;
22784
22459
  try {
22785
- renameSync6(resolve19(from, entry.name), resolve19(to, name));
22460
+ renameSync6(resolve18(from, entry.name), resolve18(to, name));
22786
22461
  moved.push(name);
22787
22462
  } catch {
22788
22463
  try {
22789
- copyFileSync(resolve19(from, entry.name), resolve19(to, name));
22464
+ copyFileSync(resolve18(from, entry.name), resolve18(to, name));
22790
22465
  moved.push(name);
22791
22466
  } catch {}
22792
22467
  }
@@ -22797,24 +22472,24 @@ function migrateLegacySpool() {
22797
22472
  }
22798
22473
  function migrateHookActivity() {
22799
22474
  const from = legacy.hookActivityDir();
22800
- if (!existsSync23(from))
22475
+ if (!existsSync21(from))
22801
22476
  return [];
22802
22477
  const moved = [];
22803
22478
  try {
22804
- const entries = readdirSync15(from, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".jsonl"));
22479
+ const entries = readdirSync14(from, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".jsonl"));
22805
22480
  if (entries.length === 0)
22806
22481
  return [];
22807
22482
  const to = hookActivityDir();
22808
- mkdirSync14(to, { recursive: true });
22483
+ mkdirSync12(to, { recursive: true });
22809
22484
  const stamp = Date.now();
22810
22485
  let seq = 0;
22811
22486
  for (const entry of entries) {
22812
- const source = resolve19(from, entry.name);
22487
+ const source = resolve18(from, entry.name);
22813
22488
  let name = entry.name === "current.jsonl" ? `page-${stamp}-${seq++}.jsonl` : entry.name;
22814
- let target = resolve19(to, name);
22815
- while (existsSync23(target)) {
22489
+ let target = resolve18(to, name);
22490
+ while (existsSync21(target)) {
22816
22491
  name = `page-${stamp}-${seq++}.jsonl`;
22817
- target = resolve19(to, name);
22492
+ target = resolve18(to, name);
22818
22493
  }
22819
22494
  try {
22820
22495
  renameSync6(source, target);
@@ -22838,7 +22513,7 @@ function retirePolicyConfigKeys() {
22838
22513
  const at = globalPolicyConfigFile();
22839
22514
  let parsed;
22840
22515
  try {
22841
- const raw = JSON.parse(readFileSync19(at, "utf8"));
22516
+ const raw = JSON.parse(readFileSync18(at, "utf8"));
22842
22517
  if (!raw || typeof raw !== "object" || Array.isArray(raw))
22843
22518
  return [];
22844
22519
  parsed = raw;
@@ -22852,9 +22527,9 @@ function retirePolicyConfigKeys() {
22852
22527
  delete parsed[key];
22853
22528
  try {
22854
22529
  if (Object.keys(parsed).length === 0)
22855
- rmSync8(at, { force: true });
22530
+ rmSync7(at, { force: true });
22856
22531
  else
22857
- writeFileSync11(at, JSON.stringify(parsed, null, 2) + `
22532
+ writeFileSync10(at, JSON.stringify(parsed, null, 2) + `
22858
22533
  `, "utf8");
22859
22534
  } catch {
22860
22535
  return [];
@@ -22862,12 +22537,12 @@ function retirePolicyConfigKeys() {
22862
22537
  return [...removed];
22863
22538
  }
22864
22539
  function readCarriedPolicyConfig() {
22865
- const from = resolve19(legacy.localPoliciesDir(), "policies-config.json");
22866
- if (!existsSync23(from))
22540
+ const from = resolve18(legacy.localPoliciesDir(), "policies-config.json");
22541
+ if (!existsSync21(from))
22867
22542
  return null;
22868
22543
  let parsed;
22869
22544
  try {
22870
- parsed = JSON.parse(readFileSync19(from, "utf8"));
22545
+ parsed = JSON.parse(readFileSync18(from, "utf8"));
22871
22546
  } catch {
22872
22547
  return null;
22873
22548
  }
@@ -22892,11 +22567,11 @@ function rewriteCarriedCustomPaths(carried) {
22892
22567
  const repoint = (value) => {
22893
22568
  if (typeof value !== "string" || value === "")
22894
22569
  return value;
22895
- const abs = resolve19(value);
22570
+ const abs = resolve18(value);
22896
22571
  const rel = relative4(fromDir, abs);
22897
22572
  if (rel === "" || rel.startsWith("..") || isAbsolute3(rel))
22898
22573
  return value;
22899
- return resolve19(toDir, rel);
22574
+ return resolve18(toDir, rel);
22900
22575
  };
22901
22576
  if (Array.isArray(carried.customPoliciesPaths)) {
22902
22577
  carried.customPoliciesPaths = carried.customPoliciesPaths.map(repoint);
@@ -22911,14 +22586,14 @@ function writeCarriedPolicyConfig(carried) {
22911
22586
  const to = globalPolicyConfigFile();
22912
22587
  let existing = {};
22913
22588
  try {
22914
- const parsed = JSON.parse(readFileSync19(to, "utf8"));
22589
+ const parsed = JSON.parse(readFileSync18(to, "utf8"));
22915
22590
  if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
22916
22591
  existing = parsed;
22917
22592
  }
22918
22593
  } catch {}
22919
22594
  try {
22920
- mkdirSync14(dirname11(to), { recursive: true });
22921
- writeFileSync11(to, JSON.stringify({ ...existing, ...carried }, null, 2) + `
22595
+ mkdirSync12(dirname10(to), { recursive: true });
22596
+ writeFileSync10(to, JSON.stringify({ ...existing, ...carried }, null, 2) + `
22922
22597
  `, "utf8");
22923
22598
  } catch {
22924
22599
  return [];
@@ -22927,10 +22602,10 @@ function writeCarriedPolicyConfig(carried) {
22927
22602
  }
22928
22603
  function readCarriedTelemetryOptOut() {
22929
22604
  const from = legacy.configToml();
22930
- if (!existsSync23(from))
22605
+ if (!existsSync21(from))
22931
22606
  return false;
22932
22607
  try {
22933
- const text = readFileSync19(from, "utf8");
22608
+ const text = readFileSync18(from, "utf8");
22934
22609
  const start = text.search(/^\s*\[telemetry\]\s*$/m);
22935
22610
  if (start === -1)
22936
22611
  return false;
@@ -22982,26 +22657,26 @@ function parseLegacyToml(text) {
22982
22657
  }
22983
22658
  function readCarriedLegacyConfig() {
22984
22659
  const from = legacy.configToml();
22985
- if (!existsSync23(from))
22660
+ if (!existsSync21(from))
22986
22661
  return null;
22987
22662
  try {
22988
- return projectConfig(parseLegacyToml(readFileSync19(from, "utf8")));
22663
+ return projectConfig(parseLegacyToml(readFileSync18(from, "utf8")));
22989
22664
  } catch {
22990
22665
  return null;
22991
22666
  }
22992
22667
  }
22993
22668
  function readCarriedLegacyCredentials() {
22994
22669
  const toml = legacy.credentialsToml();
22995
- if (existsSync23(toml)) {
22670
+ if (existsSync21(toml)) {
22996
22671
  try {
22997
- const creds = projectCredentials(parseLegacyToml(readFileSync19(toml, "utf8")));
22672
+ const creds = projectCredentials(parseLegacyToml(readFileSync18(toml, "utf8")));
22998
22673
  if (Object.keys(creds).length > 0)
22999
22674
  return creds;
23000
22675
  } catch {}
23001
22676
  }
23002
22677
  const readJson = (path) => {
23003
22678
  try {
23004
- const parsed = JSON.parse(readFileSync19(path, "utf8"));
22679
+ const parsed = JSON.parse(readFileSync18(path, "utf8"));
23005
22680
  return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
23006
22681
  } catch {
23007
22682
  return null;
@@ -23035,10 +22710,10 @@ function resetHome(from, to = LAYOUT_VERSION) {
23035
22710
  const spooled = migrateLegacySpool();
23036
22711
  const removed = [];
23037
22712
  for (const path of resettablePaths()) {
23038
- if (!existsSync23(path))
22713
+ if (!existsSync21(path))
23039
22714
  continue;
23040
22715
  try {
23041
- rmSync8(path, { recursive: true, force: true });
22716
+ rmSync7(path, { recursive: true, force: true });
23042
22717
  removed.push(path);
23043
22718
  } catch {}
23044
22719
  }
@@ -23060,7 +22735,7 @@ function layoutWarningForHook() {
23060
22735
  if (state.kind === "future") {
23061
22736
  return `[failproofai] this directory was written by a newer version (layout ${state.found} vs ${LAYOUT_VERSION}) — policies are NOT being enforced. ` + `Upgrade failproofai.`;
23062
22737
  }
23063
- if (existsSync23(globalPolicyConfigFile()))
22738
+ if (existsSync21(globalPolicyConfigFile()))
23064
22739
  return null;
23065
22740
  return `[failproofai] setup predates this version — global policies are NOT being enforced. ` + `Run \`failproofai config\` to re-create it.`;
23066
22741
  }
@@ -23107,31 +22782,6 @@ function canonicalizeEventType(raw, cli) {
23107
22782
  }
23108
22783
  return raw;
23109
22784
  }
23110
- function attachLeakNotice(eventType, cli, outcome, sessionId) {
23111
- try {
23112
- if (!canDeliverNotice(cli))
23113
- return outcome;
23114
- if (!cli)
23115
- return outcome;
23116
- const canonical = canonicalizeEventType(eventType, cli);
23117
- if (canonical !== "Stop")
23118
- return outcome;
23119
- const pending = sessionNoticePending(sessionId ?? "");
23120
- if (pending.count === 0)
23121
- return outcome;
23122
- const shaped = shapeNotice(cli, leakNoticeText(pending.count), outcome.stdout);
23123
- if (shaped.stdout === outcome.stdout && !shaped.stderr)
23124
- return outcome;
23125
- markSessionNoticed(sessionId ?? "");
23126
- return {
23127
- exitCode: outcome.exitCode,
23128
- stdout: shaped.stdout,
23129
- stderr: outcome.stderr + shaped.stderr
23130
- };
23131
- } catch {
23132
- return outcome;
23133
- }
23134
- }
23135
22785
  async function runObserved(hook, ctx, hookName, eventType, cli) {
23136
22786
  try {
23137
22787
  return await Promise.race([
@@ -23434,8 +23084,7 @@ async function evaluateHookEvent(eventType, cli = "claude", stdinPayload, opts)
23434
23084
  }
23435
23085
  } catch {}
23436
23086
  }
23437
- const withNotice = attachLeakNotice(eventType, cli, { exitCode: result.exitCode, stdout: result.stdout, stderr: result.stderr }, sessionId);
23438
- return withNotice;
23087
+ return { exitCode: result.exitCode, stdout: result.stdout, stderr: result.stderr };
23439
23088
  } finally {
23440
23089
  if (opts?.awaitTelemetryFlush ?? true) {
23441
23090
  await flushHookTelemetry2();
@@ -23494,8 +23143,6 @@ var init_handler = __esm(() => {
23494
23143
  init_custom_hooks_loader();
23495
23144
  init_hook_activity_store();
23496
23145
  init_delivery_health();
23497
- init_notice();
23498
- init_leak_notice();
23499
23146
  init_hook_telemetry2();
23500
23147
  init_resolve_permission_mode();
23501
23148
  init_resolve_transcript_path();
@@ -24136,17 +23783,17 @@ var init_collector_config = __esm(() => {
24136
23783
  });
24137
23784
 
24138
23785
  // src/hooks/flush-cli.ts
24139
- import { existsSync as existsSync24, mkdirSync as mkdirSync15, writeFileSync as writeFileSync12, readdirSync as readdirSync16 } from "node:fs";
24140
- import { dirname as dirname12, join as join29 } from "node:path";
23786
+ import { existsSync as existsSync22, mkdirSync as mkdirSync13, writeFileSync as writeFileSync11, readdirSync as readdirSync15 } from "node:fs";
23787
+ import { dirname as dirname11, join as join29 } from "node:path";
24141
23788
  function flushRequestPath(home) {
24142
23789
  return join29(failproofaiHome(home), "state", "flush-request.json");
24143
23790
  }
24144
23791
  function spoolDirs(home) {
24145
23792
  const root = spoolDir(home);
24146
- if (!existsSync24(root))
23793
+ if (!existsSync22(root))
24147
23794
  return [];
24148
23795
  try {
24149
- return readdirSync16(root, { withFileTypes: true }).filter((e) => e.isDirectory() && e.name !== "failed").map((e) => join29(root, e.name));
23796
+ return readdirSync15(root, { withFileTypes: true }).filter((e) => e.isDirectory() && e.name !== "failed").map((e) => join29(root, e.name));
24150
23797
  } catch {
24151
23798
  return [];
24152
23799
  }
@@ -24155,7 +23802,7 @@ function pendingBatches(home) {
24155
23802
  let n = 0;
24156
23803
  for (const dir of spoolDirs(home)) {
24157
23804
  try {
24158
- n += readdirSync16(dir).filter((f) => f.endsWith(".jsonl")).length;
23805
+ n += readdirSync15(dir).filter((f) => f.endsWith(".jsonl")).length;
24159
23806
  } catch {}
24160
23807
  }
24161
23808
  return n;
@@ -24212,8 +23859,8 @@ async function runFlushCommand(opts = {}) {
24212
23859
  return { exitCode: 0, pending: 0, lines: ["Nothing spooled — everything already delivered."] };
24213
23860
  }
24214
23861
  const path = flushRequestPath(home);
24215
- mkdirSync15(dirname12(path), { recursive: true });
24216
- writeFileSync12(path, `${JSON.stringify({ requestedAtMs: Date.now() }, null, 2)}
23862
+ mkdirSync13(dirname11(path), { recursive: true });
23863
+ writeFileSync11(path, `${JSON.stringify({ requestedAtMs: Date.now() }, null, 2)}
24217
23864
  `, {
24218
23865
  mode: 384
24219
23866
  });
@@ -24247,14 +23894,14 @@ var init_flush_cli = __esm(() => {
24247
23894
  import {
24248
23895
  chmodSync as chmodSync4,
24249
23896
  copyFileSync as copyFileSync2,
24250
- existsSync as existsSync25,
24251
- mkdirSync as mkdirSync16,
24252
- readFileSync as readFileSync20,
23897
+ existsSync as existsSync23,
23898
+ mkdirSync as mkdirSync14,
23899
+ readFileSync as readFileSync19,
24253
23900
  renameSync as renameSync7,
24254
- rmSync as rmSync9,
24255
- writeFileSync as writeFileSync13
23901
+ rmSync as rmSync8,
23902
+ writeFileSync as writeFileSync12
24256
23903
  } from "node:fs";
24257
- import { basename as basename4, dirname as dirname13, join as join30, resolve as resolve20 } from "node:path";
23904
+ import { basename as basename4, dirname as dirname12, join as join30, resolve as resolve19 } from "node:path";
24258
23905
  function migrateToLayout4() {
24259
23906
  const moves = [
24260
23907
  { from: legacy.authJson(), to: auditSessionFile() },
@@ -24270,13 +23917,13 @@ function migrateToLayout4() {
24270
23917
  }
24271
23918
  const migrated = [];
24272
23919
  for (const { from, to } of moves) {
24273
- if (!existsSync25(from))
23920
+ if (!existsSync23(from))
24274
23921
  continue;
24275
- if (existsSync25(to)) {
24276
- rmSync9(from, { force: true });
23922
+ if (existsSync23(to)) {
23923
+ rmSync8(from, { force: true });
24277
23924
  continue;
24278
23925
  }
24279
- mkdirSync16(dirname13(to), { recursive: true });
23926
+ mkdirSync14(dirname12(to), { recursive: true });
24280
23927
  try {
24281
23928
  renameSync7(from, to);
24282
23929
  } catch {
@@ -24284,16 +23931,16 @@ function migrateToLayout4() {
24284
23931
  copyFileSync2(from, to);
24285
23932
  } catch (err) {
24286
23933
  try {
24287
- rmSync9(to, { force: true });
23934
+ rmSync8(to, { force: true });
24288
23935
  } catch {}
24289
23936
  throw err;
24290
23937
  }
24291
- rmSync9(from, { force: true });
23938
+ rmSync8(from, { force: true });
24292
23939
  }
24293
23940
  migrated.push(`${basename4(from)} → audit/${basename4(to)}`);
24294
23941
  }
24295
23942
  for (const secret of [auditSessionFile()]) {
24296
- if (!existsSync25(secret))
23943
+ if (!existsSync23(secret))
24297
23944
  continue;
24298
23945
  try {
24299
23946
  chmodSync4(secret, 384);
@@ -24319,7 +23966,7 @@ function planMigration(from, registry = MIGRATIONS) {
24319
23966
  }
24320
23967
  function readLedger() {
24321
23968
  try {
24322
- const parsed = JSON.parse(readFileSync20(migrationLedgerFile(), "utf8"));
23969
+ const parsed = JSON.parse(readFileSync19(migrationLedgerFile(), "utf8"));
24323
23970
  return Array.isArray(parsed) ? parsed : [];
24324
23971
  } catch {
24325
23972
  return [];
@@ -24327,9 +23974,9 @@ function readLedger() {
24327
23974
  }
24328
23975
  function appendLedger(entry) {
24329
23976
  try {
24330
- mkdirSync16(migrationsDir(), { recursive: true });
23977
+ mkdirSync14(migrationsDir(), { recursive: true });
24331
23978
  const all = [...readLedger(), entry];
24332
- writeFileSync13(migrationLedgerFile(), `${JSON.stringify(all, null, 2)}
23979
+ writeFileSync12(migrationLedgerFile(), `${JSON.stringify(all, null, 2)}
24333
23980
  `, "utf8");
24334
23981
  } catch {}
24335
23982
  }
@@ -24341,12 +23988,12 @@ function pruneMigratedCredentials(from) {
24341
23988
  for (let layout = from;layout < LAYOUT_VERSION; layout++) {
24342
23989
  for (const { as, landsAt } of PRUNED_AFTER_SUCCESS) {
24343
23990
  try {
24344
- if (!existsSync25(landsAt()))
23991
+ if (!existsSync23(landsAt()))
24345
23992
  continue;
24346
- const copy = resolve20(migrationBackupDir(layout), as);
24347
- if (!existsSync25(copy))
23993
+ const copy = resolve19(migrationBackupDir(layout), as);
23994
+ if (!existsSync23(copy))
24348
23995
  continue;
24349
- rmSync9(copy, { force: true });
23996
+ rmSync8(copy, { force: true });
24350
23997
  pruned.push(as);
24351
23998
  } catch {}
24352
23999
  }
@@ -24357,7 +24004,7 @@ function filesToBackUp() {
24357
24004
  const seen = new Map;
24358
24005
  for (const f of [...BACKED_UP, ...BACKED_UP_LEGACY]) {
24359
24006
  const path = f.at();
24360
- if (existsSync25(path))
24007
+ if (existsSync23(path))
24361
24008
  seen.set(path, backupNameOf(f));
24362
24009
  }
24363
24010
  return [...seen].map(([path, as]) => ({ path, as }));
@@ -24366,14 +24013,14 @@ function backupBeforeMigrating(from) {
24366
24013
  const dir = migrationBackupDir(from);
24367
24014
  const saved = [];
24368
24015
  try {
24369
- rmSync9(dir, { recursive: true, force: true });
24370
- mkdirSync16(dir, { recursive: true });
24016
+ rmSync8(dir, { recursive: true, force: true });
24017
+ mkdirSync14(dir, { recursive: true });
24371
24018
  } catch {
24372
24019
  return [];
24373
24020
  }
24374
24021
  for (const { path: source, as } of filesToBackUp()) {
24375
24022
  try {
24376
- copyFileSync2(source, resolve20(dir, as));
24023
+ copyFileSync2(source, resolve19(dir, as));
24377
24024
  saved.push(as);
24378
24025
  } catch {}
24379
24026
  }
@@ -24663,7 +24310,7 @@ var init_fp_reset2 = __esm(() => {
24663
24310
  // scripts/install-telemetry.mjs
24664
24311
  import { createHmac, randomUUID as randomUUID2 } from "node:crypto";
24665
24312
  import { execSync as execSync5 } from "node:child_process";
24666
- import { readFileSync as readFileSync21, writeFileSync as writeFileSync14, mkdirSync as mkdirSync17 } from "node:fs";
24313
+ import { readFileSync as readFileSync20, writeFileSync as writeFileSync13, mkdirSync as mkdirSync15 } from "node:fs";
24667
24314
  import { homedir as homedir22, platform, arch, hostname, cpus } from "node:os";
24668
24315
  import { join as join31 } from "node:path";
24669
24316
  function hashToId3(raw) {
@@ -24673,7 +24320,7 @@ function getInstanceId3() {
24673
24320
  const idDir = join31(homedir22(), ".failproofai");
24674
24321
  const idFile = join31(idDir, "instance-id");
24675
24322
  try {
24676
- const existing = readFileSync21(idFile, "utf-8").trim();
24323
+ const existing = readFileSync20(idFile, "utf-8").trim();
24677
24324
  if (existing)
24678
24325
  return existing;
24679
24326
  } catch {}
@@ -24682,7 +24329,7 @@ function getInstanceId3() {
24682
24329
  if (p === "linux") {
24683
24330
  for (const machineIdPath of ["/etc/machine-id", "/var/lib/dbus/machine-id"]) {
24684
24331
  try {
24685
- const id = readFileSync21(machineIdPath, "utf-8").trim();
24332
+ const id = readFileSync20(machineIdPath, "utf-8").trim();
24686
24333
  if (id)
24687
24334
  return hashToId3(id);
24688
24335
  } catch {}
@@ -24714,8 +24361,8 @@ function getInstanceId3() {
24714
24361
  } catch {}
24715
24362
  const id = randomUUID2();
24716
24363
  try {
24717
- mkdirSync17(idDir, { recursive: true });
24718
- writeFileSync14(idFile, id, "utf-8");
24364
+ mkdirSync15(idDir, { recursive: true });
24365
+ writeFileSync13(idFile, id, "utf-8");
24719
24366
  } catch {}
24720
24367
  return id;
24721
24368
  }
@@ -24747,8 +24394,8 @@ var NAMESPACE3 = "failproofai-telemetry-v1", API_KEY3 = "phc_Ac1Ww1GqKc0z1SyrRWb
24747
24394
  var init_install_telemetry = () => {};
24748
24395
 
24749
24396
  // lib/install-check.ts
24750
- import { existsSync as existsSync26, readFileSync as readFileSync22, writeFileSync as writeFileSync15, mkdirSync as mkdirSync18 } from "node:fs";
24751
- import { dirname as dirname14, resolve as resolve21 } from "node:path";
24397
+ import { existsSync as existsSync24, readFileSync as readFileSync21, writeFileSync as writeFileSync14, mkdirSync as mkdirSync16 } from "node:fs";
24398
+ import { dirname as dirname13, resolve as resolve20 } from "node:path";
24752
24399
  import { platform as platform2, arch as arch2, release, homedir as homedir23, hostname as hostname2 } from "node:os";
24753
24400
  import { createHmac as createHmac2 } from "node:crypto";
24754
24401
  function hashToId4(raw) {
@@ -24803,12 +24450,12 @@ function compareSemver(a, b) {
24803
24450
  }
24804
24451
  function checkHooks() {
24805
24452
  const hooksConfigPath = globalPolicyConfigFile();
24806
- if (!existsSync26(hooksConfigPath)) {
24453
+ if (!existsSync24(hooksConfigPath)) {
24807
24454
  return { configured: false, registered: false, policyCount: 0 };
24808
24455
  }
24809
24456
  let config;
24810
24457
  try {
24811
- config = JSON.parse(readFileSync22(hooksConfigPath, "utf8"));
24458
+ config = JSON.parse(readFileSync21(hooksConfigPath, "utf8"));
24812
24459
  } catch {
24813
24460
  return { configured: false, registered: false, policyCount: 0 };
24814
24461
  }
@@ -24816,12 +24463,12 @@ function checkHooks() {
24816
24463
  return { configured: false, registered: false, policyCount: 0 };
24817
24464
  }
24818
24465
  const policyCount = config.enabledPolicies.length;
24819
- const settingsPath = resolve21(homedir23(), ".claude", "settings.json");
24820
- if (!existsSync26(settingsPath))
24466
+ const settingsPath = resolve20(homedir23(), ".claude", "settings.json");
24467
+ if (!existsSync24(settingsPath))
24821
24468
  return { configured: true, registered: false, policyCount };
24822
24469
  let settings;
24823
24470
  try {
24824
- settings = JSON.parse(readFileSync22(settingsPath, "utf8"));
24471
+ settings = JSON.parse(readFileSync21(settingsPath, "utf8"));
24825
24472
  } catch {
24826
24473
  return { configured: true, registered: false, policyCount };
24827
24474
  }
@@ -24845,8 +24492,8 @@ async function maybeReportInstall(version) {
24845
24492
  const versionFile = lastVersionPath();
24846
24493
  let previousVersion = null;
24847
24494
  try {
24848
- if (existsSync26(versionFile)) {
24849
- previousVersion = readFileSync22(versionFile, "utf8").trim() || null;
24495
+ if (existsSync24(versionFile)) {
24496
+ previousVersion = readFileSync21(versionFile, "utf8").trim() || null;
24850
24497
  }
24851
24498
  } catch {}
24852
24499
  if (previousVersion === version)
@@ -24882,8 +24529,8 @@ async function maybeReportInstall(version) {
24882
24529
  enabled_policy_count: hooks.policyCount
24883
24530
  }, { version, timeoutMs: REPORT_TIMEOUT_MS, enabled: telemetryEnabled }));
24884
24531
  try {
24885
- mkdirSync18(dirname14(versionFile), { recursive: true });
24886
- writeFileSync15(versionFile, version, "utf8");
24532
+ mkdirSync16(dirname13(versionFile), { recursive: true });
24533
+ writeFileSync14(versionFile, version, "utf8");
24887
24534
  } catch {}
24888
24535
  await Promise.all(events.map((p) => p.catch(() => {})));
24889
24536
  } catch {}
@@ -24933,8 +24580,8 @@ var init_cli_error = __esm(() => {
24933
24580
 
24934
24581
  // src/hooks/manager.ts
24935
24582
  import { execSync as execSync6 } from "node:child_process";
24936
- import { existsSync as existsSync27 } from "node:fs";
24937
- import { resolve as resolve22, basename as basename5 } from "node:path";
24583
+ import { existsSync as existsSync25 } from "node:fs";
24584
+ import { resolve as resolve21, basename as basename5 } from "node:path";
24938
24585
  import { platform as platform3, arch as arch3, release as release2, hostname as hostname3 } from "node:os";
24939
24586
  function getSettingsPath(scope, cwd) {
24940
24587
  return claudeCode.getSettingsPath(scope, cwd);
@@ -25153,9 +24800,9 @@ async function installHooksImpl(policyNames, scope = "user", cwd, includeBeta =
25153
24800
  delete configToWrite.customPoliciesPath;
25154
24801
  delete configToWrite.customPoliciesPaths;
25155
24802
  } else if (customPoliciesPath && (typeof customPoliciesPath === "string" || customPoliciesPath.length > 0)) {
25156
- const incoming = (typeof customPoliciesPath === "string" ? [customPoliciesPath] : customPoliciesPath).map((path) => resolve22(path));
25157
- const carried = (previousConfig.customPoliciesPaths ?? (previousConfig.customPoliciesPath ? [previousConfig.customPoliciesPath] : [])).map((path) => resolve22(path)).filter((path) => {
25158
- if (existsSync27(path))
24803
+ const incoming = (typeof customPoliciesPath === "string" ? [customPoliciesPath] : customPoliciesPath).map((path) => resolve21(path));
24804
+ const carried = (previousConfig.customPoliciesPaths ?? (previousConfig.customPoliciesPath ? [previousConfig.customPoliciesPath] : [])).map((path) => resolve21(path)).filter((path) => {
24805
+ if (existsSync25(path))
25159
24806
  return true;
25160
24807
  console.log(`Dropping custom policies path (file no longer exists): ${path}`);
25161
24808
  return false;
@@ -25378,7 +25025,7 @@ async function removeHooks(policyNames, scope = "user", cwd, opts) {
25378
25025
  const scopesToRemove = scope === "all" ? [...integration.scopes] : integration.scopes.includes(scope) ? [scope] : [];
25379
25026
  for (const s of scopesToRemove) {
25380
25027
  const settingsPaths = settingsPathsFor(integration, s, cwd);
25381
- const existing = settingsPaths.filter((p) => existsSync27(p));
25028
+ const existing = settingsPaths.filter((p) => existsSync25(p));
25382
25029
  if (existing.length === 0) {
25383
25030
  if (scope !== "all" && selectedClis.length === 1) {
25384
25031
  console.log("No settings file found. Nothing to remove.");
@@ -25465,51 +25112,123 @@ var init_manager = __esm(() => {
25465
25112
  VALID_POLICY_NAMES = new Set(BUILTIN_POLICIES.map((p) => p.name));
25466
25113
  });
25467
25114
 
25115
+ // src/audit/leak-fingerprint.ts
25116
+ function matchPublicPrefix(value) {
25117
+ for (const entry of PUBLIC_PREFIXES) {
25118
+ if (value.startsWith(entry[0]))
25119
+ return entry;
25120
+ }
25121
+ return null;
25122
+ }
25123
+ function fingerprintSecret(value, fallbackLabel = "secret") {
25124
+ const length = value.length;
25125
+ const matched = matchPublicPrefix(value);
25126
+ if (!matched) {
25127
+ return {
25128
+ display: `[${length}-char ${fallbackLabel}]`,
25129
+ label: fallbackLabel,
25130
+ length,
25131
+ attributed: false
25132
+ };
25133
+ }
25134
+ const [prefix, label] = matched;
25135
+ const bodyLength = length - prefix.length;
25136
+ const run = MASK_CHAR.repeat(Math.max(1, Math.min(MAX_MASK_RUN, bodyLength)));
25137
+ if (length >= MIN_LEN_FOR_TAIL && bodyLength > TAIL_CHARS * 2) {
25138
+ return {
25139
+ display: `${prefix}${run}${value.slice(-TAIL_CHARS)}`,
25140
+ label,
25141
+ length,
25142
+ attributed: true
25143
+ };
25144
+ }
25145
+ return { display: `${prefix}${run}`, label, length, attributed: true };
25146
+ }
25147
+ function isFindingId(id) {
25148
+ return /^[0-9a-f]{16}$/.test(id);
25149
+ }
25150
+ function fingerprintId(value, machineSalt) {
25151
+ const { createHmac } = __require("node:crypto");
25152
+ return createHmac("sha256", machineSalt).update(value).digest("hex").slice(0, 16);
25153
+ }
25154
+ var MASK_CHAR = "•", MAX_MASK_RUN = 8, MIN_LEN_FOR_TAIL = 24, TAIL_CHARS = 4, PUBLIC_PREFIXES;
25155
+ var init_leak_fingerprint = __esm(() => {
25156
+ PUBLIC_PREFIXES = [
25157
+ ["sk-ant-api03-", "Anthropic API key"],
25158
+ ["sk-ant-oat01-", "Anthropic OAuth token"],
25159
+ ["sk-ant-", "Anthropic key"],
25160
+ ["sk-proj-", "OpenAI project key"],
25161
+ ["sk-svcacct-", "OpenAI service-account key"],
25162
+ ["sk-admin-", "OpenAI admin key"],
25163
+ ["sk-or-v1-", "OpenRouter key"],
25164
+ ["github_pat_", "GitHub fine-grained token"],
25165
+ ["ghp_", "GitHub personal access token"],
25166
+ ["gho_", "GitHub OAuth token"],
25167
+ ["ghu_", "GitHub user-to-server token"],
25168
+ ["ghs_", "GitHub server-to-server token"],
25169
+ ["ghr_", "GitHub refresh token"],
25170
+ ["glpat-", "GitLab personal access token"],
25171
+ ["xoxb-", "Slack bot token"],
25172
+ ["xoxp-", "Slack user token"],
25173
+ ["xapp-", "Slack app-level token"],
25174
+ ["sk_live_", "Stripe live secret key"],
25175
+ ["sk_test_", "Stripe test secret key"],
25176
+ ["rk_live_", "Stripe restricted key"],
25177
+ ["AKIA", "AWS access key ID"],
25178
+ ["ASIA", "AWS temporary access key ID"],
25179
+ ["AIza", "Google API key"],
25180
+ ["hf_", "Hugging Face token"],
25181
+ ["gsk_", "Groq API key"],
25182
+ ["r8_", "Replicate token"],
25183
+ ["xai-", "xAI key"],
25184
+ ["npm_", "npm access token"],
25185
+ ["dop_v1_", "DigitalOcean token"],
25186
+ ["shpat_", "Shopify access token"],
25187
+ ["sbp_", "Supabase token"]
25188
+ ];
25189
+ });
25190
+
25468
25191
  // src/audit/macos-notifier.ts
25469
25192
  import { execFileSync as execFileSync3 } from "node:child_process";
25470
- import { existsSync as existsSync28, mkdirSync as mkdirSync19, readdirSync as readdirSync17, renameSync as renameSync8, rmSync as rmSync10, writeFileSync as writeFileSync16 } from "node:fs";
25193
+ import { chmodSync as chmodSync5, existsSync as existsSync26, mkdirSync as mkdirSync17, readdirSync as readdirSync16, renameSync as renameSync8, rmSync as rmSync9, writeFileSync as writeFileSync15 } from "node:fs";
25471
25194
  import { homedir as homedir24 } from "node:os";
25472
- import { resolve as resolve23 } from "node:path";
25195
+ import { resolve as resolve22 } from "node:path";
25473
25196
  function macNotifierAppPath(home) {
25474
- return resolve23(runDir(home), "..", "bin", "FailproofAI Notifier.app");
25197
+ return resolve22(runDir(home), "..", "bin", "FailproofAI Notifier.app");
25198
+ }
25199
+ function macNotifierRunnerPath(home) {
25200
+ return resolve22(runDir(home), "..", "bin", "failproofai-notifier.zsh");
25475
25201
  }
25476
25202
  function macNotifierPlistPath() {
25477
- return resolve23(homedir24(), "Library", "LaunchAgents", `${MAC_NOTIFIER_LABEL}.plist`);
25203
+ return resolve22(homedir24(), "Library", "LaunchAgents", `${MAC_NOTIFIER_LABEL}.plist`);
25478
25204
  }
25479
25205
  function escapeXml2(s) {
25480
25206
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
25481
25207
  }
25482
25208
  function notifierScript(home) {
25483
25209
  const dir = macNotifyDir(home);
25484
- return `on run
25485
- set dropDir to ${JSON.stringify(dir + "/")}
25486
- set listing to ""
25487
- try
25488
- set listing to do shell script "ls -1 " & quoted form of dropDir & " 2>/dev/null"
25489
- end try
25490
- repeat with entryName in paragraphs of listing
25491
- set entryPath to dropDir & (entryName as string)
25492
- if (entryName as string) is not "" then
25493
- try
25494
- set payload to do shell script "cat " & quoted form of entryPath & " 2>/dev/null"
25495
- do shell script "rm -f " & quoted form of entryPath
25496
- set lines_ to paragraphs of payload
25497
- if (count of lines_) is greater than 1 then
25498
- set noteTitle to item 1 of lines_
25499
- set noteBody to ""
25500
- repeat with i from 2 to (count of lines_)
25501
- if noteBody is not "" then set noteBody to noteBody & " "
25502
- set noteBody to noteBody & (item i of lines_)
25503
- end repeat
25504
- display notification noteBody with title noteTitle
25505
- end if
25506
- end try
25507
- end if
25508
- end repeat
25210
+ const quotedDir = `'${dir.replace(/'/g, `'\\''`)}'`;
25211
+ return `#!/bin/zsh
25212
+ set -u
25213
+ setopt NULL_GLOB
25214
+
25215
+ drop_dir=${quotedDir}
25216
+
25217
+ for entry_path in "$drop_dir"/*; do
25218
+ [ -f "$entry_path" ] || continue
25219
+ note_title=$(/usr/bin/sed -n '1p' "$entry_path")
25220
+ note_body=$(/usr/bin/sed -n '2,$p' "$entry_path" | /usr/bin/tr '\\n' ' ')
25221
+ /bin/rm -f "$entry_path"
25222
+ [ -n "$note_title" ] || continue
25223
+ /usr/bin/osascript - "$note_title" "$note_body" <<'APPLESCRIPT'
25224
+ on run argv
25225
+ display notification (item 2 of argv) with title (item 1 of argv)
25509
25226
  end run
25227
+ APPLESCRIPT
25228
+ done
25510
25229
  `;
25511
25230
  }
25512
- function notifierPlistContents(appPath, watchDir) {
25231
+ function notifierPlistContents(runnerPath, watchDir) {
25513
25232
  return `<?xml version="1.0" encoding="UTF-8"?>
25514
25233
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
25515
25234
  <plist version="1.0">
@@ -25518,7 +25237,7 @@ function notifierPlistContents(appPath, watchDir) {
25518
25237
  <string>${escapeXml2(MAC_NOTIFIER_LABEL)}</string>
25519
25238
  <key>ProgramArguments</key>
25520
25239
  <array>
25521
- <string>${escapeXml2(resolve23(appPath, "Contents", "MacOS", "applet"))}</string>
25240
+ <string>${escapeXml2(runnerPath)}</string>
25522
25241
  </array>
25523
25242
  <!-- Started only when something is queued, and it exits when the queue is
25524
25243
  empty. RunAtLoad would fire it once at login with nothing to say. -->
@@ -25545,20 +25264,15 @@ function installMacNotifier(home) {
25545
25264
  if (process.platform !== "darwin")
25546
25265
  return { installed: false, reason: "not macOS" };
25547
25266
  try {
25548
- const app = macNotifierAppPath(home);
25267
+ const runner = macNotifierRunnerPath(home);
25549
25268
  const watch = macNotifyDir(home);
25550
- mkdirSync19(watch, { recursive: true, mode: 448 });
25551
- mkdirSync19(resolve23(app, ".."), { recursive: true });
25552
- const scriptPath = resolve23(watch, "..", "notifier.applescript");
25553
- writeFileSync16(scriptPath, notifierScript(home), { mode: 384 });
25554
- rmSync10(app, { recursive: true, force: true });
25555
- run("osacompile", ["-o", app, scriptPath]);
25556
- rmSync10(scriptPath, { force: true });
25557
- const plist = resolve23(app, "Contents", "Info.plist");
25558
- run("defaults", ["write", plist, "CFBundleIdentifier", MAC_NOTIFIER_LABEL]);
25559
- run("defaults", ["write", plist, "CFBundleName", "failproofai"]);
25560
- mkdirSync19(resolve23(macNotifierPlistPath(), ".."), { recursive: true });
25561
- writeFileSync16(macNotifierPlistPath(), notifierPlistContents(app, watch), { mode: 420 });
25269
+ mkdirSync17(watch, { recursive: true, mode: 448 });
25270
+ mkdirSync17(resolve22(runner, ".."), { recursive: true });
25271
+ writeFileSync15(runner, notifierScript(home), { mode: 448 });
25272
+ chmodSync5(runner, 448);
25273
+ rmSync9(macNotifierAppPath(home), { recursive: true, force: true });
25274
+ mkdirSync17(resolve22(macNotifierPlistPath(), ".."), { recursive: true });
25275
+ writeFileSync15(macNotifierPlistPath(), notifierPlistContents(runner, watch), { mode: 420 });
25562
25276
  const target = `gui/${process.getuid?.() ?? 0}`;
25563
25277
  try {
25564
25278
  run("launchctl", ["bootout", `${target}/${MAC_NOTIFIER_LABEL}`]);
@@ -25575,49 +25289,50 @@ function uninstallMacNotifier(home) {
25575
25289
  try {
25576
25290
  run("launchctl", ["bootout", `gui/${process.getuid?.() ?? 0}/${MAC_NOTIFIER_LABEL}`]);
25577
25291
  } catch {}
25578
- rmSync10(macNotifierPlistPath(), { force: true });
25579
- rmSync10(macNotifierAppPath(home), { recursive: true, force: true });
25580
- rmSync10(macNotifyDir(home), { recursive: true, force: true });
25292
+ rmSync9(macNotifierPlistPath(), { force: true });
25293
+ rmSync9(macNotifierAppPath(home), { recursive: true, force: true });
25294
+ rmSync9(macNotifierRunnerPath(home), { force: true });
25295
+ rmSync9(macNotifyDir(home), { recursive: true, force: true });
25581
25296
  }
25582
25297
  function queueMacNotification(id, title, body, home) {
25583
25298
  if (!isFindingId(id))
25584
25299
  return false;
25585
25300
  const dir = macNotifyDir(home);
25586
- const tmp = resolve23(dir, "..", `notify-${id}.tmp`);
25301
+ const tmp = resolve22(dir, "..", `notify-${id}.tmp`);
25587
25302
  try {
25588
- mkdirSync19(dir, { recursive: true, mode: 448 });
25303
+ mkdirSync17(dir, { recursive: true, mode: 448 });
25589
25304
  const payload = `${title.replace(/\s+/g, " ")}
25590
25305
  ${body.replace(/\s+/g, " ")}
25591
25306
  `;
25592
- writeFileSync16(tmp, payload, { mode: 384 });
25593
- renameSync8(tmp, resolve23(dir, id));
25307
+ writeFileSync15(tmp, payload, { mode: 384 });
25308
+ renameSync8(tmp, resolve22(dir, id));
25594
25309
  return true;
25595
25310
  } catch {
25596
25311
  try {
25597
- rmSync10(tmp, { force: true });
25312
+ rmSync9(tmp, { force: true });
25598
25313
  } catch {}
25599
25314
  return false;
25600
25315
  }
25601
25316
  }
25602
25317
  function macNotifierInstalled(home) {
25603
- return existsSync28(macNotifierPlistPath()) && existsSync28(macNotifierAppPath(home));
25318
+ return existsSync26(macNotifierPlistPath()) && existsSync26(macNotifierRunnerPath(home));
25604
25319
  }
25605
25320
  function pruneMacNotifyQueue(home, maxAgeMs = 7 * 86400000) {
25606
25321
  try {
25607
25322
  const dir = macNotifyDir(home);
25608
- if (!existsSync28(dir))
25323
+ if (!existsSync26(dir))
25609
25324
  return;
25610
25325
  const { statSync } = __require("node:fs");
25611
- for (const name of readdirSync17(dir)) {
25612
- const path = resolve23(dir, name);
25326
+ for (const name of readdirSync16(dir)) {
25327
+ const path = resolve22(dir, name);
25613
25328
  try {
25614
25329
  if (Date.now() - statSync(path).mtimeMs > maxAgeMs)
25615
- rmSync10(path, { force: true });
25330
+ rmSync9(path, { force: true });
25616
25331
  } catch {}
25617
25332
  }
25618
25333
  } catch {}
25619
25334
  }
25620
- var MAC_NOTIFIER_LABEL = "ai.failproof.notifier", macNotifyDir = (home) => resolve23(runDir(home), "notify");
25335
+ var MAC_NOTIFIER_LABEL = "ai.failproof.notifier", macNotifyDir = (home) => resolve22(runDir(home), "notify");
25621
25336
  var init_macos_notifier = __esm(() => {
25622
25337
  init_fp_home();
25623
25338
  init_leak_fingerprint();
@@ -25639,7 +25354,7 @@ var DEFAULT_FETCH_TIMEOUT_MS = 15000;
25639
25354
 
25640
25355
  // src/hooks/cloud-enrollment.ts
25641
25356
  import { randomUUID as randomUUID3 } from "node:crypto";
25642
- import { existsSync as existsSync29, readFileSync as readFileSync23, rmSync as rmSync11 } from "node:fs";
25357
+ import { existsSync as existsSync27, readFileSync as readFileSync22, rmSync as rmSync10 } from "node:fs";
25643
25358
  import { hostname as hostname4 } from "node:os";
25644
25359
  function cloudCredentialPath() {
25645
25360
  return process.env.FAILPROOFAI_CLOUD_CREDENTIALS ?? credentialsFile();
@@ -25678,10 +25393,10 @@ function readCloudCredentials() {
25678
25393
  if (!usingJsonOverride())
25679
25394
  return readCredentials().cloud ?? null;
25680
25395
  const path = cloudCredentialPath();
25681
- if (!existsSync29(path))
25396
+ if (!existsSync27(path))
25682
25397
  return null;
25683
25398
  try {
25684
- const raw = JSON.parse(readFileSync23(path, "utf8"));
25399
+ const raw = JSON.parse(readFileSync22(path, "utf8"));
25685
25400
  if (raw.schemaVersion !== SCHEMA_VERSION2)
25686
25401
  return null;
25687
25402
  if (typeof raw.url !== "string" || typeof raw.machineId !== "string" || typeof raw.token !== "string") {
@@ -25720,10 +25435,10 @@ function resolveMachineLabel(explicit) {
25720
25435
  function clearCloudCredentials() {
25721
25436
  if (usingJsonOverride()) {
25722
25437
  const path = cloudCredentialPath();
25723
- if (!existsSync29(path))
25438
+ if (!existsSync27(path))
25724
25439
  return false;
25725
25440
  try {
25726
- rmSync11(path);
25441
+ rmSync10(path);
25727
25442
  return true;
25728
25443
  } catch {
25729
25444
  return false;
@@ -25971,21 +25686,21 @@ var init_cloud_connection = __esm(() => {
25971
25686
  });
25972
25687
 
25973
25688
  // src/hooks/setup-state.ts
25974
- import { existsSync as existsSync30, realpathSync as realpathSync2, statSync as statSync18 } from "node:fs";
25975
- import { dirname as dirname15, resolve as resolve24 } from "node:path";
25689
+ import { existsSync as existsSync28, realpathSync as realpathSync2, statSync as statSync17 } from "node:fs";
25690
+ import { dirname as dirname14, resolve as resolve23 } from "node:path";
25976
25691
  import { homedir as homedir25 } from "node:os";
25977
25692
  function globalConfigPath(home = homedir25()) {
25978
25693
  return globalPolicyConfigFile(home);
25979
25694
  }
25980
25695
  function projectConfigPath(projectRoot) {
25981
- return resolve24(projectRoot, ".failproofai", "policies-config.json");
25696
+ return resolve23(projectRoot, ".failproofai", "policies-config.json");
25982
25697
  }
25983
25698
  function legacyMarkerPath(home) {
25984
25699
  return launcherMarker(home);
25985
25700
  }
25986
25701
  function isDir(path) {
25987
25702
  try {
25988
- return statSync18(path).isDirectory();
25703
+ return statSync17(path).isDirectory();
25989
25704
  } catch {
25990
25705
  return false;
25991
25706
  }
@@ -25994,14 +25709,14 @@ function findProjectRoot(start, home = homedir25()) {
25994
25709
  const resolvedHome = realResolve(home);
25995
25710
  let dir = realResolve(start);
25996
25711
  while (dir !== resolvedHome) {
25997
- if (isDir(resolve24(dir, ".failproofai")))
25712
+ if (isDir(resolve23(dir, ".failproofai")))
25998
25713
  return dir;
25999
- const parent = dirname15(dir);
25714
+ const parent = dirname14(dir);
26000
25715
  if (parent === dir)
26001
25716
  break;
26002
25717
  dir = parent;
26003
25718
  }
26004
- return resolve24(start);
25719
+ return resolve23(start);
26005
25720
  }
26006
25721
  function hasGlobalHooksInstalled() {
26007
25722
  for (const id of INTEGRATION_TYPES) {
@@ -26013,7 +25728,7 @@ function hasGlobalHooksInstalled() {
26013
25728
  return false;
26014
25729
  }
26015
25730
  function realResolve(path) {
26016
- const lexical = resolve24(path);
25731
+ const lexical = resolve23(path);
26017
25732
  try {
26018
25733
  return realpathSync2(lexical);
26019
25734
  } catch {
@@ -26028,10 +25743,10 @@ function detectSetupState(cwd = process.cwd(), home = homedir25()) {
26028
25743
  cwd: resolvedCwd,
26029
25744
  home: resolvedHome,
26030
25745
  projectRoot,
26031
- hasGlobalConfig: existsSync30(globalConfigPath(resolvedHome)),
26032
- hasProjectConfig: projectRoot !== resolvedHome && existsSync30(projectConfigPath(projectRoot)),
25746
+ hasGlobalConfig: existsSync28(globalConfigPath(resolvedHome)),
25747
+ hasProjectConfig: projectRoot !== resolvedHome && existsSync28(projectConfigPath(projectRoot)),
26033
25748
  hasGlobalHooks: hasGlobalHooksInstalled(),
26034
- hasLegacyMarker: existsSync30(legacyMarkerPath(resolvedHome)),
25749
+ hasLegacyMarker: existsSync28(legacyMarkerPath(resolvedHome)),
26035
25750
  inHomeDir: resolvedCwd === resolvedHome
26036
25751
  };
26037
25752
  }
@@ -26048,14 +25763,14 @@ var init_setup_state = __esm(() => {
26048
25763
  });
26049
25764
 
26050
25765
  // src/hooks/onboarding-attempt.ts
26051
- import { existsSync as existsSync31, mkdirSync as mkdirSync20, readFileSync as readFileSync24, rmSync as rmSync12, writeFileSync as writeFileSync17 } from "node:fs";
26052
- import { dirname as dirname16 } from "node:path";
25766
+ import { existsSync as existsSync29, mkdirSync as mkdirSync18, readFileSync as readFileSync23, rmSync as rmSync11, writeFileSync as writeFileSync16 } from "node:fs";
25767
+ import { dirname as dirname15 } from "node:path";
26053
25768
  function readOnboardingAttempt() {
26054
25769
  const path = onboardingAttemptFile();
26055
- if (!existsSync31(path))
25770
+ if (!existsSync29(path))
26056
25771
  return null;
26057
25772
  try {
26058
- const raw = JSON.parse(readFileSync24(path, "utf8"));
25773
+ const raw = JSON.parse(readFileSync23(path, "utf8"));
26059
25774
  if (raw.schemaVersion !== SCHEMA_VERSION3)
26060
25775
  return null;
26061
25776
  if (typeof raw.reason !== "string" || typeof raw.cliVersion !== "string")
@@ -26074,7 +25789,7 @@ function readOnboardingAttempt() {
26074
25789
  function recordOnboardingAttempt(reason, cliVersion, daemonStatus, now = Date.now()) {
26075
25790
  try {
26076
25791
  const path = onboardingAttemptFile();
26077
- mkdirSync20(dirname16(path), { recursive: true });
25792
+ mkdirSync18(dirname15(path), { recursive: true });
26078
25793
  const record = {
26079
25794
  schemaVersion: SCHEMA_VERSION3,
26080
25795
  reason,
@@ -26082,12 +25797,12 @@ function recordOnboardingAttempt(reason, cliVersion, daemonStatus, now = Date.no
26082
25797
  daemonStatus,
26083
25798
  at: now
26084
25799
  };
26085
- writeFileSync17(path, JSON.stringify(record, null, 2), "utf8");
25800
+ writeFileSync16(path, JSON.stringify(record, null, 2), "utf8");
26086
25801
  } catch {}
26087
25802
  }
26088
25803
  function clearOnboardingAttempt() {
26089
25804
  try {
26090
- rmSync12(onboardingAttemptFile(), { force: true });
25805
+ rmSync11(onboardingAttemptFile(), { force: true });
26091
25806
  } catch {}
26092
25807
  }
26093
25808
  function blockerCleared(attempt, probe) {
@@ -26129,7 +25844,7 @@ var init_onboarding_attempt = __esm(() => {
26129
25844
  });
26130
25845
 
26131
25846
  // src/hooks/onboarding-lock.ts
26132
- import { mkdirSync as mkdirSync21, readFileSync as readFileSync25, rmSync as rmSync13, writeFileSync as writeFileSync18 } from "node:fs";
25847
+ import { mkdirSync as mkdirSync19, readFileSync as readFileSync24, rmSync as rmSync12, writeFileSync as writeFileSync17 } from "node:fs";
26133
25848
  import { homedir as homedir26 } from "node:os";
26134
25849
  function onboardingLockPath(home = homedir26()) {
26135
25850
  return onboardingLockFile(home);
@@ -26146,7 +25861,7 @@ function processAlive(pid) {
26146
25861
  }
26147
25862
  function readLock(path) {
26148
25863
  try {
26149
- const parsed = JSON.parse(readFileSync25(path, "utf8"));
25864
+ const parsed = JSON.parse(readFileSync24(path, "utf8"));
26150
25865
  if (typeof parsed.pid !== "number")
26151
25866
  return null;
26152
25867
  return { pid: parsed.pid, startedAt: Number(parsed.startedAt) || 0 };
@@ -26160,9 +25875,9 @@ function acquireOnboardingLock(home = homedir26()) {
26160
25875
  const held = readLock(path);
26161
25876
  if (held && held.pid !== process.pid && processAlive(held.pid))
26162
25877
  return null;
26163
- mkdirSync21(stateDir(home), { recursive: true });
25878
+ mkdirSync19(stateDir(home), { recursive: true });
26164
25879
  const body = { pid: process.pid, startedAt: Date.now() };
26165
- writeFileSync18(path, JSON.stringify(body), "utf8");
25880
+ writeFileSync17(path, JSON.stringify(body), "utf8");
26166
25881
  let released = false;
26167
25882
  return {
26168
25883
  release() {
@@ -26172,7 +25887,7 @@ function acquireOnboardingLock(home = homedir26()) {
26172
25887
  try {
26173
25888
  const current = readLock(path);
26174
25889
  if (!current || current.pid === process.pid)
26175
- rmSync13(path, { force: true });
25890
+ rmSync12(path, { force: true });
26176
25891
  } catch {}
26177
25892
  }
26178
25893
  };
@@ -26185,7 +25900,7 @@ var init_onboarding_lock = __esm(() => {
26185
25900
  });
26186
25901
 
26187
25902
  // lib/claude-sessions.ts
26188
- import { readdirSync as readdirSync18, statSync as statSync19, existsSync as existsSync32 } from "node:fs";
25903
+ import { readdirSync as readdirSync17, statSync as statSync18, existsSync as existsSync30 } from "node:fs";
26189
25904
  import { join as join32, basename as basename6 } from "node:path";
26190
25905
  function getClaudeProjectsRoot() {
26191
25906
  return getClaudeProjectsPath();
@@ -26194,7 +25909,7 @@ function listClaudeProjects() {
26194
25909
  const root = getClaudeProjectsRoot();
26195
25910
  let entries;
26196
25911
  try {
26197
- entries = readdirSync18(root, { withFileTypes: true });
25912
+ entries = readdirSync17(root, { withFileTypes: true });
26198
25913
  } catch {
26199
25914
  return [];
26200
25915
  }
@@ -26209,7 +25924,7 @@ function collectSubagentTranscripts(dir, relPrefix, project, out, depth) {
26209
25924
  return;
26210
25925
  let entries;
26211
25926
  try {
26212
- entries = readdirSync18(dir, { withFileTypes: true });
25927
+ entries = readdirSync17(dir, { withFileTypes: true });
26213
25928
  } catch {
26214
25929
  return;
26215
25930
  }
@@ -26225,7 +25940,7 @@ function collectSubagentTranscripts(dir, relPrefix, project, out, depth) {
26225
25940
  const stem = entry.name.slice(0, -".jsonl".length);
26226
25941
  const transcriptPath = join32(dir, entry.name);
26227
25942
  try {
26228
- const s = statSync19(transcriptPath);
25943
+ const s = statSync18(transcriptPath);
26229
25944
  out.push({
26230
25945
  projectName: project.name,
26231
25946
  cwd: project.cwd,
@@ -26242,7 +25957,7 @@ function listClaudeTranscripts(project) {
26242
25957
  const out = [];
26243
25958
  let entries;
26244
25959
  try {
26245
- entries = readdirSync18(project.path, { withFileTypes: true });
25960
+ entries = readdirSync17(project.path, { withFileTypes: true });
26246
25961
  } catch {
26247
25962
  return out;
26248
25963
  }
@@ -26253,7 +25968,7 @@ function listClaudeTranscripts(project) {
26253
25968
  continue;
26254
25969
  const transcriptPath = join32(project.path, entry.name);
26255
25970
  try {
26256
- const s = statSync19(transcriptPath);
25971
+ const s = statSync18(transcriptPath);
26257
25972
  out.push({
26258
25973
  projectName: project.name,
26259
25974
  cwd: project.cwd,
@@ -26266,7 +25981,7 @@ function listClaudeTranscripts(project) {
26266
25981
  } catch {}
26267
25982
  } else if (entry.isDirectory() && UUID_RE2.test(entry.name)) {
26268
25983
  const subDir = join32(project.path, entry.name, "subagents");
26269
- if (!existsSync32(subDir))
25984
+ if (!existsSync30(subDir))
26270
25985
  continue;
26271
25986
  collectSubagentTranscripts(subDir, entry.name, project, out, 0);
26272
25987
  }
@@ -26332,7 +26047,7 @@ var init_shared = __esm(() => {
26332
26047
 
26333
26048
  // src/audit/cli-adapters/claude.ts
26334
26049
  import { readFile as readFile15, open as open2 } from "node:fs/promises";
26335
- import { readFileSync as readFileSync26 } from "node:fs";
26050
+ import { readFileSync as readFileSync25 } from "node:fs";
26336
26051
  async function listClaudeTranscriptMetadata(opts = {}) {
26337
26052
  const projectFilter = opts.projects ? new Set(opts.projects) : null;
26338
26053
  const sinceMs = opts.sinceMs ?? 0;
@@ -26352,7 +26067,7 @@ async function listClaudeTranscriptMetadata(opts = {}) {
26352
26067
  let sessionDescription;
26353
26068
  if (t.isSubagent) {
26354
26069
  try {
26355
- const meta = JSON.parse(readFileSync26(t.transcriptPath.replace(/\.jsonl$/, ".meta.json"), "utf8"));
26070
+ const meta = JSON.parse(readFileSync25(t.transcriptPath.replace(/\.jsonl$/, ".meta.json"), "utf8"));
26356
26071
  if (typeof meta.description === "string")
26357
26072
  sessionDescription = meta.description;
26358
26073
  } catch {}
@@ -26483,7 +26198,7 @@ var init_claude = __esm(() => {
26483
26198
  });
26484
26199
 
26485
26200
  // src/audit/cli-adapters/codex.ts
26486
- import { statSync as statSync20 } from "node:fs";
26201
+ import { statSync as statSync19 } from "node:fs";
26487
26202
  async function listCodexTranscriptMetadata(opts = {}) {
26488
26203
  const projectFilter = opts.projects ? new Set(opts.projects) : null;
26489
26204
  const sinceMs = opts.sinceMs ?? 0;
@@ -26500,7 +26215,7 @@ async function listCodexTranscriptMetadata(opts = {}) {
26500
26215
  continue;
26501
26216
  let sizeBytes = 0;
26502
26217
  try {
26503
- sizeBytes = statSync20(s.path).size;
26218
+ sizeBytes = statSync19(s.path).size;
26504
26219
  } catch {}
26505
26220
  if (!s.sessionId)
26506
26221
  continue;
@@ -26534,7 +26249,7 @@ var init_codex = __esm(() => {
26534
26249
  });
26535
26250
 
26536
26251
  // src/audit/cli-adapters/copilot.ts
26537
- import { statSync as statSync21 } from "node:fs";
26252
+ import { statSync as statSync20 } from "node:fs";
26538
26253
  async function listCopilotTranscriptMetadata(opts = {}) {
26539
26254
  const projectFilter = opts.projects ? new Set(opts.projects) : null;
26540
26255
  const sinceMs = opts.sinceMs ?? 0;
@@ -26551,7 +26266,7 @@ async function listCopilotTranscriptMetadata(opts = {}) {
26551
26266
  continue;
26552
26267
  let sizeBytes = 0;
26553
26268
  try {
26554
- sizeBytes = statSync21(s.path).size;
26269
+ sizeBytes = statSync20(s.path).size;
26555
26270
  } catch {}
26556
26271
  if (!s.sessionId)
26557
26272
  continue;
@@ -26585,7 +26300,7 @@ var init_copilot = __esm(() => {
26585
26300
  });
26586
26301
 
26587
26302
  // src/audit/cli-adapters/cursor.ts
26588
- import { statSync as statSync22 } from "node:fs";
26303
+ import { statSync as statSync21 } from "node:fs";
26589
26304
  async function listCursorTranscriptMetadata(opts = {}) {
26590
26305
  const projectFilter = opts.projects ? new Set(opts.projects) : null;
26591
26306
  const sinceMs = opts.sinceMs ?? 0;
@@ -26602,7 +26317,7 @@ async function listCursorTranscriptMetadata(opts = {}) {
26602
26317
  continue;
26603
26318
  let sizeBytes = 0;
26604
26319
  try {
26605
- sizeBytes = statSync22(s.path).size;
26320
+ sizeBytes = statSync21(s.path).size;
26606
26321
  } catch {}
26607
26322
  if (!s.sessionId)
26608
26323
  continue;
@@ -26843,7 +26558,7 @@ var init_opencode = __esm(() => {
26843
26558
  });
26844
26559
 
26845
26560
  // src/audit/cli-adapters/pi.ts
26846
- import { statSync as statSync23 } from "node:fs";
26561
+ import { statSync as statSync22 } from "node:fs";
26847
26562
  async function listPiTranscriptMetadata(opts = {}) {
26848
26563
  const projectFilter = opts.projects ? new Set(opts.projects) : null;
26849
26564
  const sinceMs = opts.sinceMs ?? 0;
@@ -26860,7 +26575,7 @@ async function listPiTranscriptMetadata(opts = {}) {
26860
26575
  continue;
26861
26576
  let sizeBytes = 0;
26862
26577
  try {
26863
- sizeBytes = statSync23(s.path).size;
26578
+ sizeBytes = statSync22(s.path).size;
26864
26579
  } catch {}
26865
26580
  if (!s.sessionId)
26866
26581
  continue;
@@ -27669,7 +27384,7 @@ function flattenToolInput(input, depth = 0) {
27669
27384
  }
27670
27385
  return "";
27671
27386
  }
27672
- var LEAK_SCAN_VERSION = 5, ASSIGNMENT_RE, DOCS_LITERALS, SELF_OUTPUT_MARKERS, GATED_PATTERNS;
27387
+ var LEAK_SCAN_VERSION = 6, ASSIGNMENT_RE, DOCS_LITERALS, SELF_OUTPUT_MARKERS, GATED_PATTERNS;
27673
27388
  var init_leak_scan = __esm(() => {
27674
27389
  init_builtin_policies();
27675
27390
  ASSIGNMENT_RE = /(["']?)\b([A-Za-z_][A-Za-z0-9_]{0,127})\1([ \t]*(?::(?!\/\/)|=)[ \t]*)("[^"]*"|'[^']*'|[^\s;|&"']+)/g;
@@ -27694,6 +27409,176 @@ var init_leak_scan = __esm(() => {
27694
27409
  GATED_PATTERNS = SECRET_PATTERNS.map(([re, label]) => [re, label, literalPrefixOf(re.source)]);
27695
27410
  });
27696
27411
 
27412
+ // src/audit/leak-record.ts
27413
+ function upsertFinding(record, incoming) {
27414
+ const { sighting, ...rest } = incoming;
27415
+ const existing = record.findings.find((f) => f.id === rest.id);
27416
+ if (!existing) {
27417
+ record.findings.push({
27418
+ ...rest,
27419
+ firstSeen: sighting.at,
27420
+ lastSeen: sighting.at,
27421
+ occurrences: 1,
27422
+ sightings: [sighting]
27423
+ });
27424
+ return { record, isNew: true };
27425
+ }
27426
+ const seen = existing.sightings.some((s) => s.sessionId === sighting.sessionId && s.at === sighting.at && s.mechanism.direction === sighting.mechanism.direction && s.mechanism.summary === sighting.mechanism.summary);
27427
+ if (seen)
27428
+ return { record, isNew: false };
27429
+ existing.occurrences += 1;
27430
+ if (sighting.at > existing.lastSeen)
27431
+ existing.lastSeen = sighting.at;
27432
+ if (sighting.at < existing.firstSeen)
27433
+ existing.firstSeen = sighting.at;
27434
+ existing.sightings.push(sighting);
27435
+ existing.sightings.sort((a, b) => a.at.localeCompare(b.at));
27436
+ if (existing.sightings.length > MAX_SIGHTINGS) {
27437
+ existing.sightings.splice(1, existing.sightings.length - MAX_SIGHTINGS);
27438
+ }
27439
+ return { record, isNew: false };
27440
+ }
27441
+ function pruneRecord(record, nowMs) {
27442
+ const cutoff = new Date(nowMs - FINDING_TTL_DAYS * 86400000).toISOString();
27443
+ const live = record.findings.filter((f) => !f.lastSeen || !Number.isFinite(Date.parse(f.lastSeen)) || f.lastSeen >= cutoff);
27444
+ live.sort((a, b) => a.lastSeen < b.lastSeen ? 1 : a.lastSeen > b.lastSeen ? -1 : 0);
27445
+ record.findings = live.slice(0, MAX_FINDINGS);
27446
+ return record;
27447
+ }
27448
+ function emptyRecord(salt, nowIso) {
27449
+ return {
27450
+ schemaVersion: LEAK_RECORD_SCHEMA_VERSION,
27451
+ salt,
27452
+ updatedAt: nowIso,
27453
+ findings: []
27454
+ };
27455
+ }
27456
+ function describeMechanism(toolName, direction, shortPath) {
27457
+ const where = shortPath ? ` ${shortPath}` : "";
27458
+ let summary;
27459
+ if (direction === "result") {
27460
+ summary = shortPath ? `appeared in the output of reading${where}` : "appeared in tool output";
27461
+ } else {
27462
+ switch (toolName) {
27463
+ case "Read":
27464
+ summary = `read from${where || " a file"}`;
27465
+ break;
27466
+ case "Write":
27467
+ summary = `written to${where || " a file"}`;
27468
+ break;
27469
+ case "Edit":
27470
+ case "NotebookEdit":
27471
+ summary = `edited into${where || " a file"}`;
27472
+ break;
27473
+ case "Bash":
27474
+ summary = "passed in a shell command";
27475
+ break;
27476
+ default:
27477
+ summary = `sent to the ${toolName} tool`;
27478
+ }
27479
+ }
27480
+ return { summary, toolName, direction };
27481
+ }
27482
+ var MAX_SIGHTINGS = 5, FINDING_TTL_DAYS = 90, MAX_FINDINGS = 500, LEAK_RECORD_SCHEMA_VERSION = 1;
27483
+
27484
+ // src/audit/leak-store.ts
27485
+ import { randomBytes as randomBytes2 } from "node:crypto";
27486
+ import { existsSync as existsSync31, mkdirSync as mkdirSync20, readFileSync as readFileSync26 } from "node:fs";
27487
+ import { dirname as dirname16 } from "node:path";
27488
+ function readJson(path) {
27489
+ try {
27490
+ if (!existsSync31(path))
27491
+ return null;
27492
+ return JSON.parse(readFileSync26(path, "utf8"));
27493
+ } catch {
27494
+ return null;
27495
+ }
27496
+ }
27497
+ function readLeakIdentity(home) {
27498
+ const existing = readJson(auditLeakIdentityFile(home));
27499
+ if (existing && typeof existing.salt === "string" && existing.salt.length >= 32) {
27500
+ return {
27501
+ salt: existing.salt,
27502
+ dismissed: existing.dismissed ?? []
27503
+ };
27504
+ }
27505
+ const minted = { salt: randomBytes2(32).toString("hex"), dismissed: [] };
27506
+ writeLeakIdentity(minted, home);
27507
+ return minted;
27508
+ }
27509
+ function writeLeakIdentity(identity, home) {
27510
+ const path = auditLeakIdentityFile(home);
27511
+ try {
27512
+ mkdirSync20(dirname16(path), { recursive: true });
27513
+ writeJsonAtomically(path, identity, { mode: FILE_MODE });
27514
+ return true;
27515
+ } catch {
27516
+ return false;
27517
+ }
27518
+ }
27519
+ function sanitizeFinding(raw) {
27520
+ if (!raw || typeof raw !== "object" || Array.isArray(raw))
27521
+ return null;
27522
+ const f = raw;
27523
+ if (typeof f.id !== "string" || !isFindingId(f.id))
27524
+ return null;
27525
+ const fp = f.fingerprint;
27526
+ if (!fp || typeof fp !== "object" || typeof fp.display !== "string" || typeof fp.label !== "string") {
27527
+ return null;
27528
+ }
27529
+ const sightings = Array.isArray(f.sightings) ? f.sightings.filter((s) => {
27530
+ if (!s || typeof s !== "object")
27531
+ return false;
27532
+ const m = s.mechanism;
27533
+ return !!m && typeof m === "object" && typeof m.summary === "string";
27534
+ }) : [];
27535
+ return {
27536
+ ...f,
27537
+ fingerprint: {
27538
+ display: fp.display,
27539
+ label: fp.label,
27540
+ length: typeof fp.length === "number" && Number.isFinite(fp.length) ? fp.length : 0,
27541
+ attributed: fp.attributed === true
27542
+ },
27543
+ name: typeof f.name === "string" ? f.name : null,
27544
+ firstSeen: typeof f.firstSeen === "string" ? f.firstSeen : "",
27545
+ lastSeen: typeof f.lastSeen === "string" ? f.lastSeen : "",
27546
+ occurrences: typeof f.occurrences === "number" && Number.isFinite(f.occurrences) ? f.occurrences : sightings.length,
27547
+ sightings
27548
+ };
27549
+ }
27550
+ function readLeakRecord(home) {
27551
+ const identity = readLeakIdentity(home);
27552
+ const raw = readJson(auditLeaksFile(home));
27553
+ if (!raw || raw.schemaVersion !== LEAK_RECORD_SCHEMA_VERSION || !Array.isArray(raw.findings)) {
27554
+ return emptyRecord(identity.salt, new Date().toISOString());
27555
+ }
27556
+ const findings = raw.findings.map(sanitizeFinding).filter((f) => f !== null);
27557
+ return { ...raw, findings, salt: identity.salt };
27558
+ }
27559
+ function writeLeakRecord(record, home, nowMs = Date.now()) {
27560
+ const path = auditLeaksFile(home);
27561
+ try {
27562
+ mkdirSync20(dirname16(path), { recursive: true });
27563
+ const pruned = pruneRecord(record, nowMs);
27564
+ pruned.updatedAt = new Date(nowMs).toISOString();
27565
+ writeJsonAtomically(path, pruned, { mode: FILE_MODE });
27566
+ return true;
27567
+ } catch {
27568
+ return false;
27569
+ }
27570
+ }
27571
+ function activeFindings(record, home) {
27572
+ const dismissed = new Set(readLeakIdentity(home).dismissed);
27573
+ return record.findings.filter((f) => !dismissed.has(f.id)).sort((a, b) => a.lastSeen < b.lastSeen ? 1 : a.lastSeen > b.lastSeen ? -1 : 0);
27574
+ }
27575
+ var FILE_MODE = 384;
27576
+ var init_leak_store = __esm(() => {
27577
+ init_fp_home();
27578
+ init_atomic_write();
27579
+ init_leak_fingerprint();
27580
+ });
27581
+
27697
27582
  // src/audit/redact-example.ts
27698
27583
  import { homedir as homedir27 } from "node:os";
27699
27584
  function maskTruncatedSecret(input) {
@@ -27837,7 +27722,7 @@ var init_redact_example = __esm(() => {
27837
27722
 
27838
27723
  // src/audit/cache.ts
27839
27724
  import { createHash as createHash8 } from "node:crypto";
27840
- import { existsSync as existsSync33, mkdirSync as mkdirSync22, readFileSync as readFileSync27, writeFileSync as writeFileSync19, chmodSync as chmodSync5, openSync, readSync, closeSync } from "node:fs";
27725
+ import { existsSync as existsSync32, mkdirSync as mkdirSync21, readFileSync as readFileSync27, writeFileSync as writeFileSync18, chmodSync as chmodSync6, openSync, readSync, closeSync } from "node:fs";
27841
27726
  import { join as join33 } from "node:path";
27842
27727
  function getEngineVersion() {
27843
27728
  if (cachedEngineVersion)
@@ -27898,7 +27783,7 @@ function readCachedTranscript(transcriptPath, mtimeMs, sizeBytes) {
27898
27783
  if (sizeBytes === 0)
27899
27784
  return null;
27900
27785
  const cachePath = getCachePathFor(transcriptPath);
27901
- if (!existsSync33(cachePath))
27786
+ if (!existsSync32(cachePath))
27902
27787
  return null;
27903
27788
  try {
27904
27789
  const raw = readFileSync27(cachePath, "utf-8");
@@ -27942,7 +27827,7 @@ function writeCachedTranscriptResult(transcriptPath, mtimeMs, sizeBytes, result,
27942
27827
  return;
27943
27828
  const cachePath = getCachePathFor(transcriptPath);
27944
27829
  try {
27945
- mkdirSync22(auditCacheDir(), { recursive: true });
27830
+ mkdirSync21(auditCacheDir(), { recursive: true });
27946
27831
  const entry = {
27947
27832
  schemaVersion: CACHE_SCHEMA_VERSION,
27948
27833
  cachedAt: Date.now(),
@@ -27961,9 +27846,9 @@ function writeCachedTranscriptResult(transcriptPath, mtimeMs, sizeBytes, result,
27961
27846
  entry.detectorState = encodeDetectorState(resume.detectorState);
27962
27847
  }
27963
27848
  }
27964
- writeFileSync19(cachePath, JSON.stringify(entry), { encoding: "utf-8", mode: 384 });
27849
+ writeFileSync18(cachePath, JSON.stringify(entry), { encoding: "utf-8", mode: 384 });
27965
27850
  try {
27966
- chmodSync5(cachePath, 384);
27851
+ chmodSync6(cachePath, 384);
27967
27852
  } catch {}
27968
27853
  } catch {}
27969
27854
  }
@@ -28480,8 +28365,10 @@ async function runAuditInner(opts, startedAt) {
28480
28365
  }
28481
28366
  const coversAllHistory = opts.clis === undefined && opts.projects === undefined && opts.since === undefined && discoveryErrors === 0 && errors === 0 && skipped === 0;
28482
28367
  const newFindingIds = persistLeaks(perTranscript, coversAllHistory);
28368
+ const leakIds = [...new Set(perTranscript.flatMap((t) => (t.leaks ?? []).map((leak) => leak.id)))];
28483
28369
  const auditResult = {
28484
28370
  version: 2,
28371
+ leakIds,
28485
28372
  newLeakIds: newFindingIds,
28486
28373
  scannedAt: new Date(startedAt).toISOString(),
28487
28374
  scope: {
@@ -28537,11 +28424,11 @@ var init_audit = __esm(() => {
28537
28424
  import {
28538
28425
  closeSync as closeSync2,
28539
28426
  linkSync,
28540
- mkdirSync as mkdirSync23,
28427
+ mkdirSync as mkdirSync22,
28541
28428
  openSync as openSync2,
28542
28429
  readFileSync as readFileSync28,
28543
28430
  unlinkSync as unlinkSync4,
28544
- writeFileSync as writeFileSync20,
28431
+ writeFileSync as writeFileSync19,
28545
28432
  writeSync
28546
28433
  } from "node:fs";
28547
28434
  function acquireAuditLock(source, now = Date.now()) {
@@ -28616,7 +28503,7 @@ function writeLockExclusive(path, info) {
28616
28503
  const body = JSON.stringify(info);
28617
28504
  const staging = `${path}.${process.pid}.tmp`;
28618
28505
  try {
28619
- writeFileSync20(staging, body, { mode: 384 });
28506
+ writeFileSync19(staging, body, { mode: 384 });
28620
28507
  } catch {
28621
28508
  return false;
28622
28509
  }
@@ -28650,8 +28537,8 @@ function createThenWrite(path, body) {
28650
28537
  }
28651
28538
  }
28652
28539
  function ensureRunDir() {
28653
- mkdirSync23(failproofaiHome(), { recursive: true });
28654
- mkdirSync23(runDir(), { recursive: true, mode: 448 });
28540
+ mkdirSync22(failproofaiHome(), { recursive: true });
28541
+ mkdirSync22(runDir(), { recursive: true, mode: 448 });
28655
28542
  }
28656
28543
  var AUDIT_LOCK_MAX_AGE_MS;
28657
28544
  var init_audit_lock = __esm(() => {
@@ -28660,7 +28547,7 @@ var init_audit_lock = __esm(() => {
28660
28547
  });
28661
28548
 
28662
28549
  // src/audit/dashboard-cache.ts
28663
- import { existsSync as existsSync34, readFileSync as readFileSync29 } from "node:fs";
28550
+ import { existsSync as existsSync33, readFileSync as readFileSync29 } from "node:fs";
28664
28551
  function getCachePath() {
28665
28552
  return auditDashboardFile();
28666
28553
  }
@@ -28680,7 +28567,7 @@ function writeDashboardCache(params, result) {
28680
28567
  }
28681
28568
  function readDashboardCacheMeta() {
28682
28569
  const cachePath = getCachePath();
28683
- if (!existsSync34(cachePath))
28570
+ if (!existsSync33(cachePath))
28684
28571
  return null;
28685
28572
  try {
28686
28573
  const raw = readFileSync29(cachePath, "utf-8");
@@ -28907,15 +28794,15 @@ var init_api_server_client = __esm(() => {
28907
28794
  });
28908
28795
 
28909
28796
  // lib/auth/auth-store.ts
28910
- import { existsSync as existsSync35, readFileSync as readFileSync30, readdirSync as readdirSync19, rmSync as rmSync14 } from "node:fs";
28911
- import { join as join34, resolve as resolve25 } from "node:path";
28797
+ import { existsSync as existsSync34, readFileSync as readFileSync30, readdirSync as readdirSync18, rmSync as rmSync13 } from "node:fs";
28798
+ import { join as join34, resolve as resolve24 } from "node:path";
28912
28799
  function getAuthFilePath() {
28913
28800
  const override = process.env.FAILPROOFAI_AUTH_DIR;
28914
28801
  return override ? join34(override, "session.json") : auditSessionFile();
28915
28802
  }
28916
28803
  function readAuth() {
28917
28804
  const p = getAuthFilePath();
28918
- if (!existsSync35(p))
28805
+ if (!existsSync34(p))
28919
28806
  return null;
28920
28807
  try {
28921
28808
  const raw = readFileSync30(p, "utf-8");
@@ -28942,18 +28829,18 @@ function writeAuth(auth) {
28942
28829
  }
28943
28830
  function deleteAuth() {
28944
28831
  const p = getAuthFilePath();
28945
- if (existsSync35(p))
28946
- rmSync14(p, { force: true });
28832
+ if (existsSync34(p))
28833
+ rmSync13(p, { force: true });
28947
28834
  try {
28948
28835
  const root = migrationsDir();
28949
- if (!existsSync35(root))
28836
+ if (!existsSync34(root))
28950
28837
  return;
28951
- for (const entry of readdirSync19(root)) {
28838
+ for (const entry of readdirSync18(root)) {
28952
28839
  if (!entry.startsWith("backup-layout"))
28953
28840
  continue;
28954
- const copy = resolve25(root, entry, "auth.json");
28955
- if (existsSync35(copy))
28956
- rmSync14(copy, { force: true });
28841
+ const copy = resolve24(root, entry, "auth.json");
28842
+ if (existsSync34(copy))
28843
+ rmSync13(copy, { force: true });
28957
28844
  }
28958
28845
  } catch {}
28959
28846
  }
@@ -29085,7 +28972,11 @@ function selectLeaks(findings, from, to) {
29085
28972
  const last = ts(f.lastSeen);
29086
28973
  if (last !== null && (last < lo || last > hi))
29087
28974
  continue;
29088
- const seen = f.sightings?.[f.sightings.length - 1];
28975
+ const seen = f.sightings?.reduce((latest, candidate) => {
28976
+ if (!latest)
28977
+ return candidate;
28978
+ return (ts(candidate.at) ?? 0) >= (ts(latest.at) ?? 0) ? candidate : latest;
28979
+ }, undefined);
29089
28980
  out.push({
29090
28981
  id: f.id,
29091
28982
  display: f.fingerprint?.display ?? "[credential]",
@@ -29117,7 +29008,7 @@ function buildHarmReport(result, lastReportedAt, intervalDays, leakFindings = []
29117
29008
  window_from: from.toISOString(),
29118
29009
  window_to: windowTo.toISOString(),
29119
29010
  harmful: selectHarmful(result, from, windowTo, { includeUnplaceable: isFirstReport }),
29120
- leaks: selectLeaks(leakFindings, from, windowTo)
29011
+ leaks: selectLeaks(leakFindings, from, windowTo).slice(0, 1)
29121
29012
  };
29122
29013
  }
29123
29014
  var HARMFUL_SEVERITIES, ALSO_HARMFUL;
@@ -29128,12 +29019,12 @@ var init_harm_report = __esm(() => {
29128
29019
  });
29129
29020
 
29130
29021
  // src/audit/machine-store.ts
29131
- import { existsSync as existsSync36, readFileSync as readFileSync31, rmSync as rmSync15 } from "node:fs";
29022
+ import { existsSync as existsSync35, readFileSync as readFileSync31, rmSync as rmSync14 } from "node:fs";
29132
29023
  import { hostname as hostname5 } from "node:os";
29133
29024
  import { randomUUID as randomUUID4 } from "node:crypto";
29134
29025
  function readMachineIdentity(home) {
29135
29026
  const path = auditMachineFile(home);
29136
- if (!existsSync36(path))
29027
+ if (!existsSync35(path))
29137
29028
  return null;
29138
29029
  try {
29139
29030
  const parsed = JSON.parse(readFileSync31(path, "utf8"));
@@ -29182,20 +29073,20 @@ var init_machine_store = __esm(() => {
29182
29073
  // src/audit/report-harm.ts
29183
29074
  async function reportHarm(result) {
29184
29075
  let auto = false;
29185
- let consentedAt;
29186
29076
  let intervalDays = 7;
29187
29077
  try {
29188
29078
  const config = readConfig();
29189
29079
  auto = config.audit.auto;
29190
- consentedAt = config.audit.reportsConsentedAt;
29191
29080
  intervalDays = config.audit.intervalDays;
29192
29081
  } catch {
29193
29082
  return { kind: "disabled" };
29194
29083
  }
29195
29084
  if (!auto)
29196
29085
  return { kind: "disabled" };
29197
- if (consentedAt === undefined)
29198
- return { kind: "consent-required" };
29086
+ const prior = readMachineIdentity();
29087
+ const report = buildHarmReport(result, prior?.last_reported_at, intervalDays, activeFindings(readLeakRecord()));
29088
+ if (report.leaks.length === 0)
29089
+ return { kind: "no-leak" };
29199
29090
  const auth = await getValidAccessToken();
29200
29091
  if (!auth) {
29201
29092
  return { kind: "signed-out" };
@@ -29206,8 +29097,6 @@ async function reportHarm(result) {
29206
29097
  } catch (err) {
29207
29098
  return { kind: "failed", error: err instanceof Error ? err.message : String(err) };
29208
29099
  }
29209
- const report = buildHarmReport(result, identity.last_reported_at, intervalDays, activeFindings(readLeakRecord()));
29210
- const hits = report.harmful.reduce((n, p) => n + p.hits, 0);
29211
29100
  try {
29212
29101
  const res = await submitAuditReport(auth.access_token, {
29213
29102
  machine_id: identity.machine_id,
@@ -29221,7 +29110,7 @@ async function reportHarm(result) {
29221
29110
  try {
29222
29111
  recordReportWatermark(res.next_window_from);
29223
29112
  } catch {}
29224
- return res.emailed ? { kind: "sent", hits } : { kind: "held", hits, reason: res.reason ?? "not_sent" };
29113
+ return res.emailed ? { kind: "sent", leaks: report.leaks.length } : { kind: "held", leaks: report.leaks.length, reason: res.reason ?? "not_sent" };
29225
29114
  } catch (err) {
29226
29115
  const error = err instanceof AuthApiError ? `${err.code}: ${err.message}` : err instanceof Error ? err.message : String(err);
29227
29116
  return { kind: "failed", error };
@@ -29230,17 +29119,16 @@ async function reportHarm(result) {
29230
29119
  function describeOutcome2(outcome) {
29231
29120
  switch (outcome.kind) {
29232
29121
  case "disabled":
29122
+ case "no-leak":
29233
29123
  return null;
29234
- case "consent-required":
29235
- return "failproofai: scheduled scans are on, but emailing what they find needs a fresh opt-in — run `failproofai audit --schedule` (or visit /settings) to turn digests on";
29236
29124
  case "signed-out":
29237
- return "failproofai: emailed reports are on but this machine is signed out — run `failproofai audit --schedule` or visit /settings to resume them";
29125
+ return "failproofai: a credential exposure was found, but no email is configured — run `failproofai audit --schedule --email you@example.com`";
29238
29126
  case "sent":
29239
- return `failproofai: emailed a harm digest (${outcome.hits} finding${outcome.hits === 1 ? "" : "s"})`;
29127
+ return "failproofai: emailed the most recent credential exposure";
29240
29128
  case "held":
29241
- return `failproofai: ${outcome.hits} finding${outcome.hits === 1 ? "" : "s"} reported, no email (${outcome.reason})`;
29129
+ return `failproofai: credential exposure reported, no email (${outcome.reason})`;
29242
29130
  case "failed":
29243
- return `failproofai: could not send the harm report: ${outcome.error}`;
29131
+ return `failproofai: could not send the credential alert: ${outcome.error}`;
29244
29132
  }
29245
29133
  }
29246
29134
  var init_report_harm = __esm(() => {
@@ -29514,6 +29402,15 @@ var init_desktop_notify = __esm(() => {
29514
29402
  ];
29515
29403
  });
29516
29404
 
29405
+ // src/hooks/notice.ts
29406
+ function desktopLeakNotice(email = "held") {
29407
+ const followUp = email === "sent" ? "A masked alert was also sent to your email." : email === "missing" ? "Add email alerts with: failproofai audit --schedule --email you@example.com" : email === "failed" ? "Email delivery failed this time; the local result is still available." : "Email was not sent for this run.";
29408
+ return {
29409
+ title: "failproofai audit needs review",
29410
+ body: "Possible credential exposure was found in your agent transcripts. " + `Run failproofai audit to verify the matches and rotate anything real. ${followUp}`
29411
+ };
29412
+ }
29413
+
29517
29414
  // src/audit/cli.ts
29518
29415
  function colorOn() {
29519
29416
  if (process.env.NO_COLOR && process.env.NO_COLOR !== "")
@@ -29706,10 +29603,8 @@ var init_cli = __esm(() => {
29706
29603
  init_report_harm();
29707
29604
  init_desktop_notify();
29708
29605
  init_macos_notifier();
29709
- init_leak_notice();
29710
- init_notice();
29711
- init_leak_store();
29712
29606
  init_fp_config();
29607
+ init_auth_store();
29713
29608
  init_tui();
29714
29609
  init_package();
29715
29610
  AUDIT_STAGES = [
@@ -29728,9 +29623,9 @@ var init_cli = __esm(() => {
29728
29623
  });
29729
29624
 
29730
29625
  // src/hooks/configure-wizard.ts
29731
- import { existsSync as existsSync37, mkdirSync as mkdirSync24, writeFileSync as writeFileSync21, readFileSync as readFileSync32 } from "node:fs";
29626
+ import { existsSync as existsSync36, mkdirSync as mkdirSync23, writeFileSync as writeFileSync20, readFileSync as readFileSync32 } from "node:fs";
29732
29627
  import { homedir as homedir28 } from "node:os";
29733
- import { dirname as dirname17, resolve as resolve26, sep as sep5 } from "node:path";
29628
+ import { dirname as dirname17, resolve as resolve25, sep as sep5 } from "node:path";
29734
29629
  async function emit(event, props) {
29735
29630
  try {
29736
29631
  await trackHookEvent2(getInstanceId2(), event, props);
@@ -29753,7 +29648,7 @@ function setCustomPoliciesEnabled(scope, cwd, enabled) {
29753
29648
  const path = getConfigPathForScope(scope, cwd);
29754
29649
  let config = {};
29755
29650
  try {
29756
- if (existsSync37(path))
29651
+ if (existsSync36(path))
29757
29652
  config = JSON.parse(readFileSync32(path, "utf8"));
29758
29653
  } catch {
29759
29654
  return;
@@ -29763,7 +29658,7 @@ function setCustomPoliciesEnabled(scope, cwd, enabled) {
29763
29658
  else
29764
29659
  config.customPoliciesEnabled = false;
29765
29660
  try {
29766
- writeFileSync21(path, JSON.stringify(config, null, 2) + `
29661
+ writeFileSync20(path, JSON.stringify(config, null, 2) + `
29767
29662
  `, "utf8");
29768
29663
  } catch {}
29769
29664
  }
@@ -29794,7 +29689,7 @@ function describeCustomPolicies(cwd) {
29794
29689
  const scopes = [];
29795
29690
  let fileCount = 0;
29796
29691
  const dirs = [
29797
- { dir: resolve26(cwd, ".failproofai", "policies"), label: "project" },
29692
+ { dir: resolve25(cwd, ".failproofai", "policies"), label: "project" },
29798
29693
  { dir: customPoliciesDir(), label: "global" }
29799
29694
  ];
29800
29695
  for (const { dir, label } of dirs) {
@@ -29805,7 +29700,7 @@ function describeCustomPolicies(cwd) {
29805
29700
  fileCount += found.length;
29806
29701
  }
29807
29702
  for (const name of findSkippedPolicyFiles(dir)) {
29808
- warnings.push(`! ${homeify(resolve26(dir, name))} is NOT loaded — rename to ` + `${name.replace(/\.(js|mjs|ts)$/, "-policies.$1")}`);
29703
+ warnings.push(`! ${homeify(resolve25(dir, name))} is NOT loaded — rename to ` + `${name.replace(/\.(js|mjs|ts)$/, "-policies.$1")}`);
29809
29704
  }
29810
29705
  }
29811
29706
  return { active, warnings, fileCount, scopes };
@@ -29898,8 +29793,8 @@ function firstRunMarkerPath() {
29898
29793
  }
29899
29794
  function markLauncherSeen() {
29900
29795
  try {
29901
- mkdirSync24(dirname17(firstRunMarkerPath()), { recursive: true });
29902
- writeFileSync21(firstRunMarkerPath(), "1", "utf8");
29796
+ mkdirSync23(dirname17(firstRunMarkerPath()), { recursive: true });
29797
+ writeFileSync20(firstRunMarkerPath(), "1", "utf8");
29903
29798
  } catch {}
29904
29799
  }
29905
29800
  function retryProbe() {
@@ -29977,6 +29872,8 @@ async function runConfigureWizard(io = {}, answers = {}) {
29977
29872
  const cwd = process.cwd();
29978
29873
  const unattended = !stdin.isTTY || !stdout.isTTY;
29979
29874
  const preAnswered = Boolean(answers.token);
29875
+ const initialAudit = readConfigRaw().raw.audit;
29876
+ const hadExplicitAuditAuto = !!initialAudit && typeof initialAudit === "object" && !Array.isArray(initialAudit) && typeof initialAudit.auto === "boolean";
29980
29877
  if (typeof process.getuid === "function" && process.getuid() === 0 && process.env.SUDO_USER) {
29981
29878
  stdout.write(`Run failproofai config as ${process.env.SUDO_USER}, not under sudo.
29982
29879
  ` + `Everything it configures is per-user — hooks, policies and the daemon's own
@@ -30299,8 +30196,21 @@ Hooks keep enforcing; scheduled audits stay off until it is.
30299
30196
  }
30300
30197
  if (daemonInstalled) {
30301
30198
  setDaemonConfigured(true, version2);
30199
+ if (!hadExplicitAuditAuto) {
30200
+ try {
30201
+ updateConfig({ audit: { auto: true } });
30202
+ } catch {}
30203
+ }
30302
30204
  pruneOldDaemonBinaries();
30303
- installMacNotifier();
30205
+ const notifier = installMacNotifier();
30206
+ if (process.platform === "darwin" && !notifier.installed) {
30207
+ hookLogWarn(`macOS notification helper was not installed: ${notifier.reason ?? "unknown error"}`);
30208
+ stdout.write(`
30209
+ System notifications could not be installed. Scheduled scans and email alerts
30210
+ still work; re-run \`failproofai config\` after checking the local LaunchAgent.
30211
+
30212
+ `);
30213
+ }
30304
30214
  }
30305
30215
  const applied = emit("configure_applied", {
30306
30216
  target,
@@ -30388,21 +30298,22 @@ var init_configure_wizard = __esm(() => {
30388
30298
  init_package();
30389
30299
  init_onboarding_attempt();
30390
30300
  init_onboarding_lock();
30301
+ init_fp_config();
30391
30302
  POLICY_LIST_INDENT = " ".repeat(15);
30392
30303
  });
30393
30304
 
30394
30305
  // src/hooks/flush-cli.ts
30395
- import { existsSync as existsSync38, mkdirSync as mkdirSync25, writeFileSync as writeFileSync22, readdirSync as readdirSync20 } from "node:fs";
30306
+ import { existsSync as existsSync37, mkdirSync as mkdirSync24, writeFileSync as writeFileSync21, readdirSync as readdirSync19 } from "node:fs";
30396
30307
  import { dirname as dirname18, join as join35 } from "node:path";
30397
30308
  function flushRequestPath2(home) {
30398
30309
  return join35(failproofaiHome(home), "state", "flush-request.json");
30399
30310
  }
30400
30311
  function spoolDirs2(home) {
30401
30312
  const root = spoolDir(home);
30402
- if (!existsSync38(root))
30313
+ if (!existsSync37(root))
30403
30314
  return [];
30404
30315
  try {
30405
- return readdirSync20(root, { withFileTypes: true }).filter((e) => e.isDirectory() && e.name !== "failed").map((e) => join35(root, e.name));
30316
+ return readdirSync19(root, { withFileTypes: true }).filter((e) => e.isDirectory() && e.name !== "failed").map((e) => join35(root, e.name));
30406
30317
  } catch {
30407
30318
  return [];
30408
30319
  }
@@ -30411,7 +30322,7 @@ function pendingBatches2(home) {
30411
30322
  let n = 0;
30412
30323
  for (const dir of spoolDirs2(home)) {
30413
30324
  try {
30414
- n += readdirSync20(dir).filter((f) => f.endsWith(".jsonl")).length;
30325
+ n += readdirSync19(dir).filter((f) => f.endsWith(".jsonl")).length;
30415
30326
  } catch {}
30416
30327
  }
30417
30328
  return n;
@@ -30468,8 +30379,8 @@ async function runFlushCommand2(opts = {}) {
30468
30379
  return { exitCode: 0, pending: 0, lines: ["Nothing spooled — everything already delivered."] };
30469
30380
  }
30470
30381
  const path = flushRequestPath2(home);
30471
- mkdirSync25(dirname18(path), { recursive: true });
30472
- writeFileSync22(path, `${JSON.stringify({ requestedAtMs: Date.now() }, null, 2)}
30382
+ mkdirSync24(dirname18(path), { recursive: true });
30383
+ writeFileSync21(path, `${JSON.stringify({ requestedAtMs: Date.now() }, null, 2)}
30473
30384
  `, {
30474
30385
  mode: 384
30475
30386
  });
@@ -30500,7 +30411,7 @@ var init_flush_cli2 = __esm(() => {
30500
30411
  });
30501
30412
 
30502
30413
  // src/hooks/backfill-cli.ts
30503
- import { existsSync as existsSync39, mkdirSync as mkdirSync26, writeFileSync as writeFileSync23, readdirSync as readdirSync21, statSync as statSync24 } from "node:fs";
30414
+ import { existsSync as existsSync38, mkdirSync as mkdirSync25, writeFileSync as writeFileSync22, readdirSync as readdirSync20, statSync as statSync23 } from "node:fs";
30504
30415
  import { dirname as dirname19, join as join36 } from "node:path";
30505
30416
  function backfillRequestPath(home) {
30506
30417
  return join36(failproofaiHome(home), "state", "backfill-request.json");
@@ -30509,7 +30420,7 @@ function surveySessions(sinceMs, homeDir) {
30509
30420
  const out = [];
30510
30421
  for (const { cli, dir } of SESSION_DIRS) {
30511
30422
  const root = join36(homeDir, dir);
30512
- if (!existsSync39(root))
30423
+ if (!existsSync38(root))
30513
30424
  continue;
30514
30425
  let files = 0;
30515
30426
  let newest = 0;
@@ -30518,7 +30429,7 @@ function surveySessions(sinceMs, homeDir) {
30518
30429
  return;
30519
30430
  let entries;
30520
30431
  try {
30521
- entries = readdirSync21(d, { withFileTypes: true });
30432
+ entries = readdirSync20(d, { withFileTypes: true });
30522
30433
  } catch {
30523
30434
  return;
30524
30435
  }
@@ -30529,7 +30440,7 @@ function surveySessions(sinceMs, homeDir) {
30529
30440
  continue;
30530
30441
  }
30531
30442
  try {
30532
- const st = statSync24(p);
30443
+ const st = statSync23(p);
30533
30444
  if (st.mtimeMs >= sinceMs) {
30534
30445
  files += 1;
30535
30446
  newest = Math.max(newest, st.mtimeMs);
@@ -30547,7 +30458,7 @@ function runBackfillCommand(opts = {}) {
30547
30458
  const now = opts.now ?? Date.now();
30548
30459
  const sinceMs = opts.sinceMs ?? now - DEFAULT_BACKFILL_DAYS * 24 * 60 * 60 * 1000;
30549
30460
  const home = failproofaiHome();
30550
- if (!existsSync39(home)) {
30461
+ if (!existsSync38(home)) {
30551
30462
  return {
30552
30463
  exitCode: 1,
30553
30464
  lines: [`No failproofai home at ${home}. Run \`failproofai config\` first.`]
@@ -30602,8 +30513,8 @@ function runBackfillCommand(opts = {}) {
30602
30513
  }
30603
30514
  try {
30604
30515
  const path = backfillRequestPath();
30605
- mkdirSync26(dirname19(path), { recursive: true });
30606
- writeFileSync23(path, `${JSON.stringify({ sinceMs, requestedAtMs: now }, null, 2)}
30516
+ mkdirSync25(dirname19(path), { recursive: true });
30517
+ writeFileSync22(path, `${JSON.stringify({ sinceMs, requestedAtMs: now }, null, 2)}
30607
30518
  `, {
30608
30519
  mode: 384
30609
30520
  });
@@ -30646,7 +30557,7 @@ var init_backfill_cli = __esm(() => {
30646
30557
 
30647
30558
  // src/hooks/harness-cli.ts
30648
30559
  import { homedir as homedir29 } from "node:os";
30649
- import { resolve as resolve27 } from "node:path";
30560
+ import { resolve as resolve26 } from "node:path";
30650
30561
  function unknownHarness(name) {
30651
30562
  return fail([
30652
30563
  `Unknown harness: ${name}`,
@@ -30690,7 +30601,7 @@ function comparableLabel(raw) {
30690
30601
  }
30691
30602
  function comparablePath(raw) {
30692
30603
  const home = homedir29();
30693
- const expanded = raw === "~" ? home : raw.startsWith("~/") ? resolve27(home, raw.slice(2)) : raw;
30604
+ const expanded = raw === "~" ? home : raw.startsWith("~/") ? resolve26(home, raw.slice(2)) : raw;
30694
30605
  return expanded.replace(/\/+$/, "");
30695
30606
  }
30696
30607
  function effectiveLabel(entry) {
@@ -30878,7 +30789,7 @@ var init_harness_cli = __esm(() => {
30878
30789
  });
30879
30790
 
30880
30791
  // src/hooks/fp-config.ts
30881
- import { chmodSync as chmodSync6, existsSync as existsSync40, mkdirSync as mkdirSync27, readFileSync as readFileSync33, statSync as statSync25, writeFileSync as writeFileSync24 } from "node:fs";
30792
+ import { chmodSync as chmodSync7, existsSync as existsSync39, mkdirSync as mkdirSync26, readFileSync as readFileSync33, statSync as statSync24, writeFileSync as writeFileSync23 } from "node:fs";
30882
30793
  function detectLayout2() {
30883
30794
  const raw = readVersionFile2();
30884
30795
  if (raw) {
@@ -30886,17 +30797,17 @@ function detectLayout2() {
30886
30797
  return { kind: "current", version: raw };
30887
30798
  return raw.layout > LAYOUT_VERSION ? { kind: "future", found: raw.layout } : { kind: "stale", found: raw.layout };
30888
30799
  }
30889
- if (existsSync40(configFile())) {
30800
+ if (existsSync39(configFile())) {
30890
30801
  const layoutThreePositions = [
30891
30802
  legacy.authJson(),
30892
30803
  legacy.nextAudit(),
30893
30804
  legacy.auditSchedule()
30894
30805
  ];
30895
- if (layoutThreePositions.some((p) => existsSync40(p)))
30806
+ if (layoutThreePositions.some((p) => existsSync39(p)))
30896
30807
  return { kind: "stale", found: 3 };
30897
30808
  return { kind: "current", version: { layout: LAYOUT_VERSION, cli: "" }, inferred: true };
30898
30809
  }
30899
- if (existsSync40(legacy.configToml()))
30810
+ if (existsSync39(legacy.configToml()))
30900
30811
  return { kind: "stale", found: 2 };
30901
30812
  const layoutOneMarkers = [
30902
30813
  legacy.policyConfig(),
@@ -30907,7 +30818,7 @@ function detectLayout2() {
30907
30818
  legacy.ingestCredentials(),
30908
30819
  legacy.auditDashboard()
30909
30820
  ];
30910
- return layoutOneMarkers.some((p) => existsSync40(p)) ? { kind: "stale", found: 1 } : { kind: "absent" };
30821
+ return layoutOneMarkers.some((p) => existsSync39(p)) ? { kind: "stale", found: 1 } : { kind: "absent" };
30911
30822
  }
30912
30823
  function readLegacyTomlVersion2(text) {
30913
30824
  const layout = Number(/^\s*layout\s*=\s*(\d+)\s*$/m.exec(text)?.[1]);
@@ -30948,16 +30859,16 @@ var init_fp_home2 = () => {};
30948
30859
 
30949
30860
  // src/hooks/migrations.ts
30950
30861
  import {
30951
- chmodSync as chmodSync7,
30862
+ chmodSync as chmodSync8,
30952
30863
  copyFileSync as copyFileSync3,
30953
- existsSync as existsSync41,
30954
- mkdirSync as mkdirSync28,
30864
+ existsSync as existsSync40,
30865
+ mkdirSync as mkdirSync27,
30955
30866
  readFileSync as readFileSync34,
30956
30867
  renameSync as renameSync9,
30957
- rmSync as rmSync16,
30958
- writeFileSync as writeFileSync25
30868
+ rmSync as rmSync15,
30869
+ writeFileSync as writeFileSync24
30959
30870
  } from "node:fs";
30960
- import { basename as basename7, dirname as dirname20, join as join37, resolve as resolve28 } from "node:path";
30871
+ import { basename as basename7, dirname as dirname20, join as join37, resolve as resolve27 } from "node:path";
30961
30872
  function migrateToLayout42() {
30962
30873
  const moves = [
30963
30874
  { from: legacy.authJson(), to: auditSessionFile() },
@@ -30973,13 +30884,13 @@ function migrateToLayout42() {
30973
30884
  }
30974
30885
  const migrated = [];
30975
30886
  for (const { from, to } of moves) {
30976
- if (!existsSync41(from))
30887
+ if (!existsSync40(from))
30977
30888
  continue;
30978
- if (existsSync41(to)) {
30979
- rmSync16(from, { force: true });
30889
+ if (existsSync40(to)) {
30890
+ rmSync15(from, { force: true });
30980
30891
  continue;
30981
30892
  }
30982
- mkdirSync28(dirname20(to), { recursive: true });
30893
+ mkdirSync27(dirname20(to), { recursive: true });
30983
30894
  try {
30984
30895
  renameSync9(from, to);
30985
30896
  } catch {
@@ -30987,19 +30898,19 @@ function migrateToLayout42() {
30987
30898
  copyFileSync3(from, to);
30988
30899
  } catch (err) {
30989
30900
  try {
30990
- rmSync16(to, { force: true });
30901
+ rmSync15(to, { force: true });
30991
30902
  } catch {}
30992
30903
  throw err;
30993
30904
  }
30994
- rmSync16(from, { force: true });
30905
+ rmSync15(from, { force: true });
30995
30906
  }
30996
30907
  migrated.push(`${basename7(from)} → audit/${basename7(to)}`);
30997
30908
  }
30998
30909
  for (const secret of [auditSessionFile()]) {
30999
- if (!existsSync41(secret))
30910
+ if (!existsSync40(secret))
31000
30911
  continue;
31001
30912
  try {
31002
- chmodSync7(secret, 384);
30913
+ chmodSync8(secret, 384);
31003
30914
  } catch {}
31004
30915
  }
31005
30916
  writeVersionFile({ layout: 4 });
@@ -31030,9 +30941,9 @@ function readLedger2() {
31030
30941
  }
31031
30942
  function appendLedger2(entry) {
31032
30943
  try {
31033
- mkdirSync28(migrationsDir(), { recursive: true });
30944
+ mkdirSync27(migrationsDir(), { recursive: true });
31034
30945
  const all = [...readLedger2(), entry];
31035
- writeFileSync25(migrationLedgerFile(), `${JSON.stringify(all, null, 2)}
30946
+ writeFileSync24(migrationLedgerFile(), `${JSON.stringify(all, null, 2)}
31036
30947
  `, "utf8");
31037
30948
  } catch {}
31038
30949
  }
@@ -31044,12 +30955,12 @@ function pruneMigratedCredentials2(from) {
31044
30955
  for (let layout = from;layout < LAYOUT_VERSION; layout++) {
31045
30956
  for (const { as, landsAt } of PRUNED_AFTER_SUCCESS2) {
31046
30957
  try {
31047
- if (!existsSync41(landsAt()))
30958
+ if (!existsSync40(landsAt()))
31048
30959
  continue;
31049
- const copy = resolve28(migrationBackupDir(layout), as);
31050
- if (!existsSync41(copy))
30960
+ const copy = resolve27(migrationBackupDir(layout), as);
30961
+ if (!existsSync40(copy))
31051
30962
  continue;
31052
- rmSync16(copy, { force: true });
30963
+ rmSync15(copy, { force: true });
31053
30964
  pruned.push(as);
31054
30965
  } catch {}
31055
30966
  }
@@ -31060,7 +30971,7 @@ function filesToBackUp2() {
31060
30971
  const seen = new Map;
31061
30972
  for (const f of [...BACKED_UP2, ...BACKED_UP_LEGACY2]) {
31062
30973
  const path = f.at();
31063
- if (existsSync41(path))
30974
+ if (existsSync40(path))
31064
30975
  seen.set(path, backupNameOf2(f));
31065
30976
  }
31066
30977
  return [...seen].map(([path, as]) => ({ path, as }));
@@ -31069,14 +30980,14 @@ function backupBeforeMigrating2(from) {
31069
30980
  const dir = migrationBackupDir(from);
31070
30981
  const saved = [];
31071
30982
  try {
31072
- rmSync16(dir, { recursive: true, force: true });
31073
- mkdirSync28(dir, { recursive: true });
30983
+ rmSync15(dir, { recursive: true, force: true });
30984
+ mkdirSync27(dir, { recursive: true });
31074
30985
  } catch {
31075
30986
  return [];
31076
30987
  }
31077
30988
  for (const { path: source, as } of filesToBackUp2()) {
31078
30989
  try {
31079
- copyFileSync3(source, resolve28(dir, as));
30990
+ copyFileSync3(source, resolve27(dir, as));
31080
30991
  saved.push(as);
31081
30992
  } catch {}
31082
30993
  }
@@ -31214,16 +31125,16 @@ var init_migrations2 = __esm(() => {
31214
31125
 
31215
31126
  // src/hooks/daemon-service.ts
31216
31127
  import {
31217
- existsSync as existsSync42,
31218
- mkdirSync as mkdirSync29,
31128
+ existsSync as existsSync41,
31129
+ mkdirSync as mkdirSync28,
31219
31130
  mkdtempSync as mkdtempSync2,
31220
31131
  readFileSync as readFileSync35,
31221
- writeFileSync as writeFileSync26,
31132
+ writeFileSync as writeFileSync25,
31222
31133
  unlinkSync as unlinkSync5,
31223
- rmSync as rmSync17
31134
+ rmSync as rmSync16
31224
31135
  } from "node:fs";
31225
31136
  import { homedir as homedir30, tmpdir as tmpdir3, userInfo as userInfo2 } from "node:os";
31226
- import { resolve as resolve29 } from "node:path";
31137
+ import { resolve as resolve28 } from "node:path";
31227
31138
  import { execFileSync as execFileSync4 } from "node:child_process";
31228
31139
  function isDaemonSupportedPlatform2() {
31229
31140
  return process.platform === "linux" || process.platform === "darwin";
@@ -31239,13 +31150,13 @@ function resolveFailproofaidBinaryPath2() {
31239
31150
  if (process.env.FAILPROOFAI_DAEMON_BINARY)
31240
31151
  return process.env.FAILPROOFAI_DAEMON_BINARY;
31241
31152
  const downloaded = installedBinaryPath();
31242
- if (existsSync42(downloaded))
31153
+ if (existsSync41(downloaded))
31243
31154
  return downloaded;
31244
31155
  const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT;
31245
31156
  if (packageRoot) {
31246
31157
  for (const profile of ["release", "debug"]) {
31247
- const candidate = resolve29(packageRoot, "target", profile, "failproofaid");
31248
- if (existsSync42(candidate))
31158
+ const candidate = resolve28(packageRoot, "target", profile, "failproofaid");
31159
+ if (existsSync41(candidate))
31249
31160
  return candidate;
31250
31161
  }
31251
31162
  }
@@ -31275,8 +31186,8 @@ function resolveWorkerCommand2() {
31275
31186
  const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT;
31276
31187
  if (!packageRoot)
31277
31188
  return null;
31278
- const workerScript = resolve29(packageRoot, "dist", "worker.mjs");
31279
- if (!existsSync42(workerScript))
31189
+ const workerScript = resolve28(packageRoot, "dist", "worker.mjs");
31190
+ if (!existsSync41(workerScript))
31280
31191
  return null;
31281
31192
  return `${shellQuote2(process.execPath)} ${shellQuote2(workerScript)}`;
31282
31193
  }
@@ -31286,8 +31197,8 @@ function resolveCliCommand2() {
31286
31197
  const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT;
31287
31198
  if (!packageRoot)
31288
31199
  return null;
31289
- const cliScript = resolve29(packageRoot, "dist", "cli.mjs");
31290
- if (!existsSync42(cliScript))
31200
+ const cliScript = resolve28(packageRoot, "dist", "cli.mjs");
31201
+ if (!existsSync41(cliScript))
31291
31202
  return null;
31292
31203
  return `${shellQuote2(process.execPath)} ${shellQuote2(cliScript)}`;
31293
31204
  }
@@ -31300,8 +31211,8 @@ function workerScriptPath2() {
31300
31211
  const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT;
31301
31212
  if (!packageRoot)
31302
31213
  return null;
31303
- const workerScript = resolve29(packageRoot, "dist", "worker.mjs");
31304
- return existsSync42(workerScript) ? workerScript : null;
31214
+ const workerScript = resolve28(packageRoot, "dist", "worker.mjs");
31215
+ return existsSync41(workerScript) ? workerScript : null;
31305
31216
  }
31306
31217
  function assertUnitSafe2(value, field) {
31307
31218
  if (UNIT_UNSAFE_RE2.test(value)) {
@@ -31327,10 +31238,10 @@ function systemdUnitDir2() {
31327
31238
  return process.env.FAILPROOFAI_SYSTEMD_DIR || "/etc/systemd/system";
31328
31239
  }
31329
31240
  function systemdUnitPath2(user = serviceUser2()) {
31330
- return resolve29(systemdUnitDir2(), systemdUnitName2(user));
31241
+ return resolve28(systemdUnitDir2(), systemdUnitName2(user));
31331
31242
  }
31332
31243
  function legacySystemdUserUnitPath2() {
31333
- return resolve29(homedir30(), ".config", "systemd", "user", "failproofaid.service");
31244
+ return resolve28(homedir30(), ".config", "systemd", "user", "failproofaid.service");
31334
31245
  }
31335
31246
  function launchdLabel2(user = serviceUser2()) {
31336
31247
  return `ai.failproof.failproofaid.${user}`;
@@ -31339,7 +31250,7 @@ function launchdPlistPath2(user = serviceUser2()) {
31339
31250
  return `/Library/LaunchDaemons/${launchdLabel2(user)}.plist`;
31340
31251
  }
31341
31252
  function legacyLaunchAgentPlistPath2() {
31342
- return resolve29(homedir30(), "Library", "LaunchAgents", "ai.failproof.failproofaid.plist");
31253
+ return resolve28(homedir30(), "Library", "LaunchAgents", "ai.failproof.failproofaid.plist");
31343
31254
  }
31344
31255
  function legacySharedLaunchDaemonPath2() {
31345
31256
  return "/Library/LaunchDaemons/ai.failproof.failproofaid.plist";
@@ -31377,20 +31288,20 @@ function runPrivileged2(command, args) {
31377
31288
  execFileSync4(cmd, argv, { stdio: "ignore", timeout: SERVICE_CMD_TIMEOUT_MS2 });
31378
31289
  }
31379
31290
  function writePrivilegedFile2(destination, contents, mode = "0644") {
31380
- const stagingDir = mkdtempSync2(resolve29(tmpdir3(), "failproofaid-stage-"));
31381
- const staging = resolve29(stagingDir, "service-definition");
31291
+ const stagingDir = mkdtempSync2(resolve28(tmpdir3(), "failproofaid-stage-"));
31292
+ const staging = resolve28(stagingDir, "service-definition");
31382
31293
  try {
31383
- writeFileSync26(staging, contents, "utf8");
31294
+ writeFileSync25(staging, contents, "utf8");
31384
31295
  runPrivileged2("install", ["-m", mode, staging, destination]);
31385
31296
  } finally {
31386
- rmSync17(stagingDir, { recursive: true, force: true });
31297
+ rmSync16(stagingDir, { recursive: true, force: true });
31387
31298
  }
31388
31299
  }
31389
31300
  function removeLegacyUserService2() {
31390
31301
  try {
31391
31302
  if (process.platform === "linux") {
31392
31303
  const legacy = legacySystemdUserUnitPath2();
31393
- if (!existsSync42(legacy))
31304
+ if (!existsSync41(legacy))
31394
31305
  return;
31395
31306
  try {
31396
31307
  execFileSync4("systemctl", ["--user", "disable", "--now", "failproofaid.service"], {
@@ -31407,7 +31318,7 @@ function removeLegacyUserService2() {
31407
31318
  } catch {}
31408
31319
  } else {
31409
31320
  const legacyAgent = legacyLaunchAgentPlistPath2();
31410
- if (existsSync42(legacyAgent)) {
31321
+ if (existsSync41(legacyAgent)) {
31411
31322
  try {
31412
31323
  execFileSync4("launchctl", ["unload", "-w", legacyAgent], {
31413
31324
  stdio: "ignore",
@@ -31417,7 +31328,7 @@ function removeLegacyUserService2() {
31417
31328
  unlinkSync5(legacyAgent);
31418
31329
  }
31419
31330
  const legacyDaemon = legacySharedLaunchDaemonPath2();
31420
- if (existsSync42(legacyDaemon)) {
31331
+ if (existsSync41(legacyDaemon)) {
31421
31332
  try {
31422
31333
  runPrivileged2("launchctl", ["unload", "-w", legacyDaemon]);
31423
31334
  } catch {}
@@ -31434,7 +31345,7 @@ function systemdUnitContents2(binaryPath, workerCmd, cliCmd = null) {
31434
31345
  const user = assertUnitSafe2(serviceUser2(), "User");
31435
31346
  assertUnitSafe2(binaryPath, "ExecStart");
31436
31347
  assertUnitSafe2(homedir30(), "HOME");
31437
- const conditionPaths = [binaryPath, workerScriptPath2()].filter((p) => typeof p === "string" && existsSync42(p));
31348
+ const conditionPaths = [binaryPath, workerScriptPath2()].filter((p) => typeof p === "string" && existsSync41(p));
31438
31349
  const conditionLines = conditionPaths.map((p) => `ConditionPathExists=${assertUnitSafe2(p, "ConditionPathExists")}
31439
31350
  `).join("");
31440
31351
  return `[Unit]
@@ -31492,9 +31403,9 @@ ${env.map(([key, value]) => ` <key>${key}</key>
31492
31403
  <key>UserName</key>
31493
31404
  <string>${escapeXml3(serviceUser2())}</string>
31494
31405
  ${envBlock} <key>StandardOutPath</key>
31495
- <string>${escapeXml3(resolve29(logDir, "failproofaid.log"))}</string>
31406
+ <string>${escapeXml3(resolve28(logDir, "failproofaid.log"))}</string>
31496
31407
  <key>StandardErrorPath</key>
31497
- <string>${escapeXml3(resolve29(logDir, "failproofaid.err.log"))}</string>
31408
+ <string>${escapeXml3(resolve28(logDir, "failproofaid.err.log"))}</string>
31498
31409
  </dict>
31499
31410
  </plist>
31500
31411
  `;
@@ -31540,7 +31451,7 @@ async function installDaemonService2() {
31540
31451
  } else {
31541
31452
  const plistPath = launchdPlistPath2();
31542
31453
  const logDir = logsDir();
31543
- mkdirSync29(logDir, { recursive: true });
31454
+ mkdirSync28(logDir, { recursive: true });
31544
31455
  try {
31545
31456
  runPrivileged2("launchctl", ["unload", plistPath]);
31546
31457
  } catch {}
@@ -31639,7 +31550,7 @@ function daemonServiceStatus2() {
31639
31550
  if (!isDaemonSupportedPlatform2())
31640
31551
  return "unsupported-platform";
31641
31552
  if (process.platform === "linux") {
31642
- if (!existsSync42(systemdUnitPath2()))
31553
+ if (!existsSync41(systemdUnitPath2()))
31643
31554
  return "not-installed";
31644
31555
  try {
31645
31556
  const out = execFileSync4("systemctl", ["is-active", systemdUnitName2()], {
@@ -31652,7 +31563,7 @@ function daemonServiceStatus2() {
31652
31563
  }
31653
31564
  }
31654
31565
  const plistPath = launchdPlistPath2();
31655
- if (!existsSync42(plistPath))
31566
+ if (!existsSync41(plistPath))
31656
31567
  return "not-installed";
31657
31568
  try {
31658
31569
  const root = typeof process.getuid === "function" && process.getuid() === 0;
@@ -31682,7 +31593,7 @@ var init_daemon_service2 = __esm(() => {
31682
31593
  });
31683
31594
 
31684
31595
  // src/hooks/uninstall-cli.ts
31685
- import { existsSync as existsSync43, rmSync as rmSync18 } from "node:fs";
31596
+ import { existsSync as existsSync42, rmSync as rmSync17 } from "node:fs";
31686
31597
  function survey(cwd) {
31687
31598
  const clis = [];
31688
31599
  for (const id of listInstallableIds()) {
@@ -31703,9 +31614,9 @@ function survey(cwd) {
31703
31614
  return {
31704
31615
  clis,
31705
31616
  servicePath,
31706
- serviceInstalled: !!servicePath && existsSync43(servicePath),
31617
+ serviceInstalled: !!servicePath && existsSync42(servicePath),
31707
31618
  daemonConfigured,
31708
- homeExists: existsSync43(failproofaiHome())
31619
+ homeExists: existsSync42(failproofaiHome())
31709
31620
  };
31710
31621
  }
31711
31622
  async function runUninstallCommand(opts = {}) {
@@ -31734,6 +31645,7 @@ async function runUninstallCommand(opts = {}) {
31734
31645
  if (found.daemonConfigured) {
31735
31646
  plan.push(` • stop requiring the daemon (policies go back to evaluating in-process)`);
31736
31647
  }
31648
+ let removeDaemon = opts.purge === true;
31737
31649
  if (found.serviceInstalled) {
31738
31650
  plan.push(opts.purge || opts.yes ? ` • stop, disable and delete the service at ${found.servicePath} — needs sudo` : ` • ask whether to remove the service at ${found.servicePath} (kept unless you say so)`);
31739
31651
  }
@@ -31793,7 +31705,7 @@ async function runUninstallCommand(opts = {}) {
31793
31705
  }
31794
31706
  }
31795
31707
  if (found.serviceInstalled) {
31796
- const removeDaemon = opts.purge || opts.yes ? true : await opts.confirmDaemon?.() ?? false;
31708
+ removeDaemon = opts.purge || opts.yes ? true : await opts.confirmDaemon?.() ?? false;
31797
31709
  if (!removeDaemon) {
31798
31710
  lines.push(`• kept the daemon service at ${found.servicePath}`, ` Remove it later with: failproofai uninstall --purge`);
31799
31711
  } else {
@@ -31803,7 +31715,7 @@ async function runUninstallCommand(opts = {}) {
31803
31715
  } catch {}
31804
31716
  try {
31805
31717
  await uninstallDaemonService();
31806
- if (found.servicePath && existsSync43(found.servicePath)) {
31718
+ if (found.servicePath && existsSync42(found.servicePath)) {
31807
31719
  failures.push(`the service at ${found.servicePath} is still there (most often: no sudo). ` + `Remove it with the commands below.`);
31808
31720
  } else {
31809
31721
  lines.push(`✓ stopped and removed the daemon service`);
@@ -31813,12 +31725,12 @@ async function runUninstallCommand(opts = {}) {
31813
31725
  }
31814
31726
  }
31815
31727
  }
31816
- if (opts.purge || found.serviceInstalled && (opts.purge || opts.yes)) {
31728
+ if (opts.purge || removeDaemon) {
31817
31729
  uninstallMacNotifier();
31818
31730
  }
31819
31731
  if (opts.purge && found.homeExists) {
31820
31732
  try {
31821
- rmSync18(failproofaiHome(), { recursive: true, force: true });
31733
+ rmSync17(failproofaiHome(), { recursive: true, force: true });
31822
31734
  purged = true;
31823
31735
  lines.push(`✓ deleted ${failproofaiHome()}`);
31824
31736
  } catch (err) {
@@ -31829,7 +31741,7 @@ async function runUninstallCommand(opts = {}) {
31829
31741
  lines.push(``, `Not everything could be removed:`);
31830
31742
  for (const f of failures)
31831
31743
  lines.push(` ✗ ${f}`);
31832
- if (found.servicePath && existsSync43(found.servicePath)) {
31744
+ if (found.servicePath && existsSync42(found.servicePath)) {
31833
31745
  lines.push(``, `To remove the service by hand:`, ...manualServiceRemoval(found.servicePath), ``, `(\`${daemonStatusCommand()}\` shows its current state.)`);
31834
31746
  }
31835
31747
  return { exitCode: 1, lines, planLines, purged };
@@ -31864,8 +31776,8 @@ var init_uninstall_cli = __esm(() => {
31864
31776
  import { execFileSync as execFileSync5 } from "node:child_process";
31865
31777
  import { homedir as homedir31, tmpdir as tmpdir4 } from "node:os";
31866
31778
  import { createHash as createHash9 } from "node:crypto";
31867
- import { copyFileSync as copyFileSync4, existsSync as existsSync44, mkdirSync as mkdirSync30, mkdtempSync as mkdtempSync3, readFileSync as readFileSync36, readdirSync as readdirSync22, realpathSync as realpathSync3, rmSync as rmSync19, statSync as statSync26, writeFileSync as writeFileSync27 } from "node:fs";
31868
- import { basename as basename8, dirname as dirname21, isAbsolute as isAbsolute4, join as join38, relative as relative5, resolve as resolve30, sep as sep6 } from "node:path";
31779
+ import { copyFileSync as copyFileSync4, existsSync as existsSync43, mkdirSync as mkdirSync29, mkdtempSync as mkdtempSync3, readFileSync as readFileSync36, readdirSync as readdirSync21, realpathSync as realpathSync3, rmSync as rmSync18, statSync as statSync25, writeFileSync as writeFileSync26 } from "node:fs";
31780
+ import { basename as basename8, dirname as dirname21, isAbsolute as isAbsolute4, join as join38, relative as relative5, resolve as resolve29, sep as sep6 } from "node:path";
31869
31781
  function parseList(rest, flag) {
31870
31782
  const idx = rest.findIndex((a) => a === flag || a.startsWith(`${flag}=`));
31871
31783
  if (idx === -1)
@@ -31965,7 +31877,7 @@ async function build(rest) {
31965
31877
  const version = flag("version");
31966
31878
  const commit = flag("commit");
31967
31879
  const effect = flag("effect") ?? "enforce";
31968
- const outDir = resolve30(flag("out") ?? "dist-pack");
31880
+ const outDir = resolve29(flag("out") ?? "dist-pack");
31969
31881
  if (!entry || !id || !version) {
31970
31882
  return fail2([
31971
31883
  "Usage: failproofai publish <entry.mjs> --repo <owner>/<repo> --version <version>",
@@ -31978,8 +31890,8 @@ async function build(rest) {
31978
31890
  } catch (err) {
31979
31891
  return fail2([err instanceof Error ? err.message : String(err)]);
31980
31892
  }
31981
- const entryPath = resolve30(entry);
31982
- if (!existsSync44(entryPath))
31893
+ const entryPath = resolve29(entry);
31894
+ if (!existsSync43(entryPath))
31983
31895
  return fail2([`No such file: ${entryPath}`]);
31984
31896
  const source = readFileSync36(entryPath, "utf8");
31985
31897
  const localImport = /(?:^|\n)\s*(?:import|export)[^;\n]*from\s+["'](\.[^"']*)["']/.exec(source);
@@ -32037,13 +31949,13 @@ async function build(rest) {
32037
31949
  policies
32038
31950
  }, null, 2) + `
32039
31951
  `;
32040
- mkdirSync30(outDir, { recursive: true });
32041
- const manifestPath = resolve30(outDir, PACK_MANIFEST_ASSET);
32042
- const entryOut = resolve30(outDir, PACK_ENTRY_ASSET);
32043
- writeFileSync27(manifestPath, manifest, "utf8");
31952
+ mkdirSync29(outDir, { recursive: true });
31953
+ const manifestPath = resolve29(outDir, PACK_MANIFEST_ASSET);
31954
+ const entryOut = resolve29(outDir, PACK_ENTRY_ASSET);
31955
+ writeFileSync26(manifestPath, manifest, "utf8");
32044
31956
  copyFileSync4(entryPath, entryOut);
32045
31957
  const sha = (bytes) => createHash9("sha256").update(bytes).digest("hex");
32046
- writeFileSync27(resolve30(outDir, PACK_CHECKSUMS_ASSET), `${sha(manifest)} ${PACK_MANIFEST_ASSET}
31958
+ writeFileSync26(resolve29(outDir, PACK_CHECKSUMS_ASSET), `${sha(manifest)} ${PACK_MANIFEST_ASSET}
32047
31959
  ${sha(readFileSync36(entryOut))} ${PACK_ENTRY_ASSET}
32048
31960
  `, "utf8");
32049
31961
  const on = policies.filter((p) => p.defaultEnabled).length;
@@ -32173,12 +32085,12 @@ async function scaffold(target) {
32173
32085
  return ok2(["Nothing written."]);
32174
32086
  chosen = answer.trim();
32175
32087
  }
32176
- const path = resolve30(withPolicyExtension(chosen ?? "my-policies"));
32177
- if (existsSync44(path)) {
32088
+ const path = resolve29(withPolicyExtension(chosen ?? "my-policies"));
32089
+ if (existsSync43(path)) {
32178
32090
  return fail2([`${path} already exists — name a different file, or edit that one.`]);
32179
32091
  }
32180
- mkdirSync30(resolve30(path, ".."), { recursive: true });
32181
- writeFileSync27(path, `import { customPolicies, allow, deny } from "failproofai";
32092
+ mkdirSync29(resolve29(path, ".."), { recursive: true });
32093
+ writeFileSync26(path, `import { customPolicies, allow, deny } from "failproofai";
32182
32094
 
32183
32095
  // One file, no relative imports: only this entry is digest-pinned, so a pack
32184
32096
  // that imported siblings could not honestly claim to be verified.
@@ -32215,7 +32127,7 @@ customPolicies.add({
32215
32127
  function inferRepo(entryPath) {
32216
32128
  try {
32217
32129
  const url = execFileSync5("git", ["remote", "get-url", "origin"], {
32218
- cwd: resolve30(entryPath, ".."),
32130
+ cwd: resolve29(entryPath, ".."),
32219
32131
  encoding: "utf8",
32220
32132
  stdio: ["ignore", "pipe", "ignore"],
32221
32133
  timeout: 5000
@@ -32227,7 +32139,7 @@ function inferRepo(entryPath) {
32227
32139
  }
32228
32140
  }
32229
32141
  function inferCommit(entryPath, outDir, sources) {
32230
- const cwd = resolve30(entryPath, "..");
32142
+ const cwd = resolve29(entryPath, "..");
32231
32143
  const raw = (args) => {
32232
32144
  try {
32233
32145
  return execFileSync5("git", args, {
@@ -32282,9 +32194,9 @@ function realOrSelf(path) {
32282
32194
  }
32283
32195
  }
32284
32196
  function sourcesInHead(git, raw, sources) {
32285
- const paths = sources.map((f) => realOrSelf(resolve30(f)));
32197
+ const paths = sources.map((f) => realOrSelf(resolve29(f)));
32286
32198
  const shown = git(["rev-parse", "--show-toplevel"]);
32287
- const top = shown === null ? null : realOrSelf(resolve30(shown));
32199
+ const top = shown === null ? null : realOrSelf(resolve29(shown));
32288
32200
  const missing = [];
32289
32201
  for (const path of paths) {
32290
32202
  const rel = top ? relative5(top, path) : null;
@@ -32308,7 +32220,7 @@ function sourcesInHead(git, raw, sources) {
32308
32220
  ]);
32309
32221
  if (status === null)
32310
32222
  return { ok: false, offending: paths, why: "modified" };
32311
- const dirty = porcelainEntries(status).flatMap((entry) => [entry.path, entry.from].filter(Boolean).map((path) => resolve30(top ?? ".", path)));
32223
+ const dirty = porcelainEntries(status).flatMap((entry) => [entry.path, entry.from].filter(Boolean).map((path) => resolve29(top ?? ".", path)));
32312
32224
  if (dirty.length > 0)
32313
32225
  return { ok: false, offending: dirty, why: "modified" };
32314
32226
  return { ok: true };
@@ -32316,19 +32228,19 @@ function sourcesInHead(git, raw, sources) {
32316
32228
  function skipOutDir(git, entryPath, outDir) {
32317
32229
  if (!outDir)
32318
32230
  return [];
32319
- const out = resolve30(outDir);
32320
- if (resolve30(entryPath).startsWith(out + sep6))
32231
+ const out = resolve29(outDir);
32232
+ if (resolve29(entryPath).startsWith(out + sep6))
32321
32233
  return [];
32322
32234
  const top = git(["rev-parse", "--show-toplevel"]);
32323
32235
  if (!top)
32324
32236
  return [];
32325
- const rel = relative5(resolve30(top), out);
32237
+ const rel = relative5(resolve29(top), out);
32326
32238
  if (!rel || rel.startsWith("..") || isAbsolute4(rel))
32327
32239
  return [];
32328
32240
  return ["--", ":(top)", `:(exclude,literal,top)${rel.split(sep6).join("/")}`];
32329
32241
  }
32330
32242
  function inferTaggedVersion(entryPath, sources) {
32331
- const cwd = resolve30(entryPath, "..");
32243
+ const cwd = resolve29(entryPath, "..");
32332
32244
  const raw = (args) => {
32333
32245
  try {
32334
32246
  return execFileSync5("git", args, {
@@ -32358,7 +32270,7 @@ function inferTaggedVersion(entryPath, sources) {
32358
32270
  function findEntry(dir) {
32359
32271
  let names;
32360
32272
  try {
32361
- names = readdirSync22(dir);
32273
+ names = readdirSync21(dir);
32362
32274
  } catch {
32363
32275
  return [];
32364
32276
  }
@@ -32366,9 +32278,9 @@ function findEntry(dir) {
32366
32278
  for (const name of names) {
32367
32279
  if (!/\.(mjs|js|ts)$/.test(name))
32368
32280
  continue;
32369
- const full = resolve30(dir, name);
32281
+ const full = resolve29(dir, name);
32370
32282
  try {
32371
- if (statSync26(full).size > 512 * 1024)
32283
+ if (statSync25(full).size > 512 * 1024)
32372
32284
  continue;
32373
32285
  const text = readFileSync36(full, "utf8");
32374
32286
  if (/from\s+["']failproofai["']/.test(text) && /customPolicies\s*\.\s*add\s*\(/.test(text)) {
@@ -32381,13 +32293,13 @@ function findEntry(dir) {
32381
32293
  return found.sort();
32382
32294
  }
32383
32295
  function withLocalImports(sources) {
32384
- const seen = new Set(sources.map((f) => resolve30(f)));
32296
+ const seen = new Set(sources.map((f) => resolve29(f)));
32385
32297
  const queue = [...seen];
32386
32298
  while (queue.length > 0 && seen.size < 500) {
32387
32299
  const file = queue.shift();
32388
32300
  let text;
32389
32301
  try {
32390
- if (statSync26(file).size > 512 * 1024)
32302
+ if (statSync25(file).size > 512 * 1024)
32391
32303
  continue;
32392
32304
  text = readFileSync36(file, "utf8");
32393
32305
  } catch {
@@ -32395,13 +32307,13 @@ function withLocalImports(sources) {
32395
32307
  }
32396
32308
  for (const re of LOCAL_IMPORT_RES) {
32397
32309
  for (const match of text.matchAll(re)) {
32398
- const base = resolve30(dirname21(file), match[1]);
32310
+ const base = resolve29(dirname21(file), match[1]);
32399
32311
  for (const ext of LOCAL_IMPORT_EXTENSIONS) {
32400
32312
  const candidate = base + ext;
32401
32313
  if (seen.has(candidate))
32402
32314
  break;
32403
32315
  try {
32404
- if (!statSync26(candidate).isFile())
32316
+ if (!statSync25(candidate).isFile())
32405
32317
  continue;
32406
32318
  } catch {
32407
32319
  continue;
@@ -32416,7 +32328,7 @@ function withLocalImports(sources) {
32416
32328
  return [...seen];
32417
32329
  }
32418
32330
  function settleGitState(entryPath, provenance, packFiles, id, outDir) {
32419
- const cwd = resolve30(entryPath, "..");
32331
+ const cwd = resolve29(entryPath, "..");
32420
32332
  const raw = (args) => {
32421
32333
  try {
32422
32334
  return execFileSync5("git", args, {
@@ -32491,11 +32403,11 @@ function settleGitState(entryPath, provenance, packFiles, id, outDir) {
32491
32403
  if (root === null || status === null)
32492
32404
  return null;
32493
32405
  const entries = porcelainEntries(status);
32494
- const dirty = entries.map((entry) => resolve30(root, entry.path));
32495
- const renamedFrom = entries.filter((entry) => entry.from).map((entry) => resolve30(root, entry.from));
32406
+ const dirty = entries.map((entry) => resolve29(root, entry.path));
32407
+ const renamedFrom = entries.filter((entry) => entry.from).map((entry) => resolve29(root, entry.from));
32496
32408
  if (dirty.length === 0)
32497
32409
  return null;
32498
- const mine = new Set(packFiles.map((f) => resolve30(f)));
32410
+ const mine = new Set(packFiles.map((f) => resolve29(f)));
32499
32411
  const foreign = dirty.filter((path) => !mine.has(path));
32500
32412
  const toStage = [...dirty, ...renamedFrom];
32501
32413
  if (foreign.length > 0) {
@@ -32628,7 +32540,7 @@ function pushExistingHistory(dir, owner, name, token) {
32628
32540
  return false;
32629
32541
  const askpass = join38(mkdtempSync3(join38(tmpdir4(), "fpai-askpass-")), "askpass.sh");
32630
32542
  try {
32631
- writeFileSync27(askpass, `#!/bin/sh
32543
+ writeFileSync26(askpass, `#!/bin/sh
32632
32544
  case "$1" in
32633
32545
  *Username*) echo x-access-token ;;
32634
32546
  *) echo "$FPAI_GH_TOKEN" ;;
@@ -32648,7 +32560,7 @@ esac
32648
32560
  return true;
32649
32561
  } finally {
32650
32562
  try {
32651
- rmSync19(dirname21(askpass), { recursive: true, force: true });
32563
+ rmSync18(dirname21(askpass), { recursive: true, force: true });
32652
32564
  } catch {}
32653
32565
  }
32654
32566
  }
@@ -32672,8 +32584,8 @@ failproofai policies add ${owner}/${name}
32672
32584
  function findBun() {
32673
32585
  const candidates = [
32674
32586
  "bun",
32675
- process.env.BUN_INSTALL ? resolve30(process.env.BUN_INSTALL, "bin", "bun") : null,
32676
- resolve30(homedir31(), ".bun", "bin", "bun"),
32587
+ process.env.BUN_INSTALL ? resolve29(process.env.BUN_INSTALL, "bin", "bun") : null,
32588
+ resolve29(homedir31(), ".bun", "bin", "bun"),
32677
32589
  "/opt/homebrew/bin/bun",
32678
32590
  "/usr/local/bin/bun"
32679
32591
  ].filter((c) => c !== null);
@@ -32699,12 +32611,12 @@ function bundleEntry(sources, outDir) {
32699
32611
  ]
32700
32612
  };
32701
32613
  }
32702
- mkdirSync30(outDir, { recursive: true });
32703
- const entry = resolve30(outDir, ".entry.generated.mjs");
32704
- writeFileSync27(entry, sources.map((f) => `import ${JSON.stringify(f.startsWith("/") ? f : resolve30(f))};`).join(`
32614
+ mkdirSync29(outDir, { recursive: true });
32615
+ const entry = resolve29(outDir, ".entry.generated.mjs");
32616
+ writeFileSync26(entry, sources.map((f) => `import ${JSON.stringify(f.startsWith("/") ? f : resolve29(f))};`).join(`
32705
32617
  `) + `
32706
32618
  `, "utf8");
32707
- const bundled = resolve30(outDir, ".bundled.mjs");
32619
+ const bundled = resolve29(outDir, ".bundled.mjs");
32708
32620
  try {
32709
32621
  execFileSync5(bun, [
32710
32622
  "build",
@@ -32822,7 +32734,7 @@ async function publish(rest) {
32822
32734
  `);
32823
32735
  const token = githubToken();
32824
32736
  const login = token ? await credentialLogin(token) : null;
32825
- const folder = basename8(resolve30(entry, ".."));
32737
+ const folder = basename8(resolve29(entry, ".."));
32826
32738
  const answered = await askWhereToPublish(`${login ?? "your-account"}/${folder}`, { stdin: process.stdin, stdout: process.stdout });
32827
32739
  if (answered === null)
32828
32740
  return ok2(["Nothing was published."]);
@@ -32833,7 +32745,7 @@ async function publish(rest) {
32833
32745
  let versionFromSha = false;
32834
32746
  const dryRun = rest.includes("--dry-run") || !repo;
32835
32747
  const allowPrivate = rest.includes("--allow-private");
32836
- const id = flag("id") ?? repo ?? (dryRun && entry ? `local/${basename8(resolve30(entry, ".."))}` : undefined);
32748
+ const id = flag("id") ?? repo ?? (dryRun && entry ? `local/${basename8(resolve29(entry, ".."))}` : undefined);
32837
32749
  const [owner, name] = (repo ?? "/").split("/");
32838
32750
  if (repo && (!owner || !name || repo.split("/").length !== 2)) {
32839
32751
  return fail2([`--repo must be <owner>/<repo>, got ${JSON.stringify(repo)}`]);
@@ -32852,7 +32764,7 @@ async function publish(rest) {
32852
32764
  "With no --repo it writes the three release assets and stops."
32853
32765
  ]);
32854
32766
  }
32855
- const outDirEarly = resolve30(flag("out") ?? "dist-pack");
32767
+ const outDirEarly = resolve29(flag("out") ?? "dist-pack");
32856
32768
  let provenance = entry ? inferCommit(entry, outDirEarly, bundledSources) : null;
32857
32769
  const gitLines = [];
32858
32770
  if (!version && entry && interactive) {
@@ -32892,7 +32804,7 @@ async function publish(rest) {
32892
32804
  "It needs write access to releases on that repository, and nothing else."
32893
32805
  ]);
32894
32806
  }
32895
- const ensured = await ensureRepo(owner, name, id, token, resolve30(entry, ".."));
32807
+ const ensured = await ensureRepo(owner, name, id, token, resolve29(entry, ".."));
32896
32808
  if ("error" in ensured)
32897
32809
  return fail2(ensured.error);
32898
32810
  created = ensured.created;
@@ -32991,7 +32903,7 @@ async function publish(rest) {
32991
32903
  if (prior) {
32992
32904
  await gh(`${GITHUB_API2}/repos/${owner}/${name}/releases/assets/${prior.id}`, auth, { method: "DELETE" });
32993
32905
  }
32994
- const bytes = readFileSync36(resolve30(outDir, asset));
32906
+ const bytes = readFileSync36(resolve29(outDir, asset));
32995
32907
  const upload = await gh(`${GITHUB_UPLOADS2}/repos/${owner}/${name}/releases/${releaseId}/assets?name=${encodeURIComponent(asset)}`, auth, {
32996
32908
  method: "POST",
32997
32909
  contentType: asset.endsWith(".json") ? "application/json" : "application/octet-stream",
@@ -33672,8 +33584,8 @@ var init_install_prompt = __esm(() => {
33672
33584
 
33673
33585
  // src/hooks/manager.ts
33674
33586
  import { execSync as execSync7 } from "node:child_process";
33675
- import { existsSync as existsSync45 } from "node:fs";
33676
- import { resolve as resolve31, basename as basename9 } from "node:path";
33587
+ import { existsSync as existsSync44 } from "node:fs";
33588
+ import { resolve as resolve30, basename as basename9 } from "node:path";
33677
33589
  import { platform as platform4, arch as arch4, release as release3, hostname as hostname6 } from "node:os";
33678
33590
  function getSettingsPath2(scope, cwd) {
33679
33591
  return claudeCode.getSettingsPath(scope, cwd);
@@ -33892,9 +33804,9 @@ async function installHooksImpl2(policyNames, scope = "user", cwd, includeBeta =
33892
33804
  delete configToWrite.customPoliciesPath;
33893
33805
  delete configToWrite.customPoliciesPaths;
33894
33806
  } else if (customPoliciesPath && (typeof customPoliciesPath === "string" || customPoliciesPath.length > 0)) {
33895
- const incoming = (typeof customPoliciesPath === "string" ? [customPoliciesPath] : customPoliciesPath).map((path) => resolve31(path));
33896
- const carried = (previousConfig.customPoliciesPaths ?? (previousConfig.customPoliciesPath ? [previousConfig.customPoliciesPath] : [])).map((path) => resolve31(path)).filter((path) => {
33897
- if (existsSync45(path))
33807
+ const incoming = (typeof customPoliciesPath === "string" ? [customPoliciesPath] : customPoliciesPath).map((path) => resolve30(path));
33808
+ const carried = (previousConfig.customPoliciesPaths ?? (previousConfig.customPoliciesPath ? [previousConfig.customPoliciesPath] : [])).map((path) => resolve30(path)).filter((path) => {
33809
+ if (existsSync44(path))
33898
33810
  return true;
33899
33811
  console.log(`Dropping custom policies path (file no longer exists): ${path}`);
33900
33812
  return false;
@@ -34117,7 +34029,7 @@ async function removeHooks2(policyNames, scope = "user", cwd, opts) {
34117
34029
  const scopesToRemove = scope === "all" ? [...integration.scopes] : integration.scopes.includes(scope) ? [scope] : [];
34118
34030
  for (const s of scopesToRemove) {
34119
34031
  const settingsPaths = settingsPathsFor(integration, s, cwd);
34120
- const existing = settingsPaths.filter((p) => existsSync45(p));
34032
+ const existing = settingsPaths.filter((p) => existsSync44(p));
34121
34033
  if (existing.length === 0) {
34122
34034
  if (scope !== "all" && selectedClis.length === 1) {
34123
34035
  console.log("No settings file found. Nothing to remove.");
@@ -34261,9 +34173,9 @@ async function listHooks(cwd) {
34261
34173
  if (explicitPaths.length > 0) {
34262
34174
  groups.push(rule("Custom Policies", opts));
34263
34175
  for (const path of explicitPaths) {
34264
- const absPath = resolve31(findProjectConfigDir(cwd ?? process.cwd()), path);
34176
+ const absPath = resolve30(findProjectConfigDir(cwd ?? process.cwd()), path);
34265
34177
  groups.push(note(absPath, opts));
34266
- if (!existsSync45(absPath)) {
34178
+ if (!existsSync44(absPath)) {
34267
34179
  groups.push(warning([`file not found: ${absPath}`], opts));
34268
34180
  continue;
34269
34181
  }
@@ -34283,7 +34195,7 @@ async function listHooks(cwd) {
34283
34195
  }
34284
34196
  }
34285
34197
  const base = findProjectConfigDir(cwd ?? process.cwd());
34286
- const projectDir = resolve31(base, ".failproofai", "policies");
34198
+ const projectDir = resolve30(base, ".failproofai", "policies");
34287
34199
  const userDir = customPoliciesDir();
34288
34200
  const sameDir = userDir === projectDir;
34289
34201
  const conventionDirs = [
@@ -34589,21 +34501,20 @@ async function runScheduleOn(daysArg, emailArg) {
34589
34501
  if (bad)
34590
34502
  throw new ScheduleCliError(bad);
34591
34503
  }
34592
- const { user, prompted } = await ensureSignedIn(emailArg);
34504
+ const signedIn = emailArg === undefined ? { user: readAuth()?.user ?? null, prompted: false } : await ensureSignedIn(emailArg);
34593
34505
  const next = updateConfig({
34594
34506
  audit: {
34595
34507
  auto: true,
34596
- reportsConsentedAt: Date.now(),
34597
34508
  ...days !== undefined ? { intervalDays: days } : {}
34598
34509
  }
34599
34510
  });
34600
34511
  const interval = next.audit.intervalDays;
34601
34512
  const summary = [
34602
- `every ${interval} day${interval === 1 ? "" : "s"} · reports to ${user.email}`,
34603
- "you only hear from it when a scan finds something harmful",
34604
- "each report sends: finding counts, redacted example commands, this machine's name"
34513
+ `every ${interval} day${interval === 1 ? "" : "s"} · desktop notification on leaks`,
34514
+ signedIn.user ? `masked leak alerts also go to ${signedIn.user.email}` : "email is optional · add it with --email you@example.com",
34515
+ "email contains only the most recent masked credential exposure"
34605
34516
  ];
34606
- if (prompted) {
34517
+ if (signedIn.prompted) {
34607
34518
  step("scheduled audits are on", summary);
34608
34519
  } else {
34609
34520
  process.stdout.write(`
@@ -34612,7 +34523,7 @@ ${green("✓")} ${bold("scheduled audits are on")}
34612
34523
  `).join(""));
34613
34524
  }
34614
34525
  warnIfDaemonWontRun();
34615
- if (prompted) {
34526
+ if (signedIn.prompted) {
34616
34527
  outro("failproofai audit --status · when the next scan is due");
34617
34528
  } else {
34618
34529
  process.stdout.write(dim(`
@@ -34664,12 +34575,7 @@ function runScheduleStatus() {
34664
34575
  ]);
34665
34576
  detail.push(["reports to", live ? live.user.email : dim("— signed out")]);
34666
34577
  if (on && !live) {
34667
- detail.push(["", pink("scans continue; digests are paused until you sign in")]);
34668
- } else if (on && config.audit.reportsConsentedAt === undefined) {
34669
- detail.push([
34670
- "",
34671
- pink("scans continue; digests need a fresh opt-in — run `--schedule` to turn them on")
34672
- ]);
34578
+ detail.push(["", pink("scans and desktop alerts continue; email alerts are paused")]);
34673
34579
  }
34674
34580
  detail.push(["daemon", describeDaemon(daemon)]);
34675
34581
  if (sched?.nextDueAtMs != null && on) {
@@ -34784,14 +34690,14 @@ var init_schedule_cli = __esm(() => {
34784
34690
  });
34785
34691
 
34786
34692
  // scripts/parse-script-args.ts
34787
- import { resolve as resolve32 } from "path";
34693
+ import { resolve as resolve31 } from "path";
34788
34694
  function parseStringFlag(flagName, errorLabel, inlineValue, args, index, options) {
34789
34695
  const raw = inlineValue ?? args[index + 1];
34790
34696
  if (raw === undefined || inlineValue === null && raw.startsWith("-")) {
34791
34697
  console.error(`Error: ${flagName} requires ${errorLabel}`);
34792
34698
  process.exit(1);
34793
34699
  }
34794
- const value = options?.resolve ? resolve32(raw) : raw;
34700
+ const value = options?.resolve ? resolve31(raw) : raw;
34795
34701
  return { value, spliceCount: inlineValue !== null ? 1 : 2 };
34796
34702
  }
34797
34703
  function parseScriptArgs(argv) {
@@ -34847,19 +34753,19 @@ function parseScriptArgs(argv) {
34847
34753
  var init_parse_script_args = () => {};
34848
34754
 
34849
34755
  // scripts/install-diagnosis.mjs
34850
- import { existsSync as existsSync46, readFileSync as readFileSync38, realpathSync as realpathSync4 } from "node:fs";
34851
- import { dirname as dirname22, resolve as resolve33 } from "node:path";
34756
+ import { existsSync as existsSync45, readFileSync as readFileSync38, realpathSync as realpathSync4 } from "node:fs";
34757
+ import { dirname as dirname22, resolve as resolve32 } from "node:path";
34852
34758
  import { homedir as homedir32, platform as platform5 } from "node:os";
34853
34759
  import { spawnSync } from "node:child_process";
34854
34760
  function findPackageRoot(start) {
34855
34761
  try {
34856
34762
  let dir = realpathSync4(start);
34857
- if (existsSync46(dir) && !existsSync46(resolve33(dir, "package.json"))) {
34763
+ if (existsSync45(dir) && !existsSync45(resolve32(dir, "package.json"))) {
34858
34764
  dir = dirname22(dir);
34859
34765
  }
34860
34766
  while (true) {
34861
- const pkgPath = resolve33(dir, "package.json");
34862
- if (existsSync46(pkgPath)) {
34767
+ const pkgPath = resolve32(dir, "package.json");
34768
+ if (existsSync45(pkgPath)) {
34863
34769
  try {
34864
34770
  const pkg = JSON.parse(readFileSync38(pkgPath, "utf8"));
34865
34771
  if (pkg.name === PKG_NAME)
@@ -34879,7 +34785,7 @@ function readPackageVersion(packageRoot) {
34879
34785
  if (!packageRoot)
34880
34786
  return null;
34881
34787
  try {
34882
- const pkg = JSON.parse(readFileSync38(resolve33(packageRoot, "package.json"), "utf8"));
34788
+ const pkg = JSON.parse(readFileSync38(resolve32(packageRoot, "package.json"), "utf8"));
34883
34789
  return typeof pkg.version === "string" ? pkg.version : null;
34884
34790
  } catch {
34885
34791
  return null;
@@ -34905,16 +34811,16 @@ function locateNpmGlobal() {
34905
34811
  const root = (res.stdout || "").trim();
34906
34812
  if (!root)
34907
34813
  return null;
34908
- const candidate = resolve33(root, PKG_NAME);
34909
- return existsSync46(resolve33(candidate, "package.json")) ? candidate : null;
34814
+ const candidate = resolve32(root, PKG_NAME);
34815
+ return existsSync45(resolve32(candidate, "package.json")) ? candidate : null;
34910
34816
  } catch {
34911
34817
  return null;
34912
34818
  }
34913
34819
  }
34914
34820
  function locateBunGlobal() {
34915
34821
  try {
34916
- const candidate = resolve33(homedir32(), ".bun", "install", "global", "node_modules", PKG_NAME);
34917
- return existsSync46(resolve33(candidate, "package.json")) ? candidate : null;
34822
+ const candidate = resolve32(homedir32(), ".bun", "install", "global", "node_modules", PKG_NAME);
34823
+ return existsSync45(resolve32(candidate, "package.json")) ? candidate : null;
34918
34824
  } catch {
34919
34825
  return null;
34920
34826
  }
@@ -34922,8 +34828,8 @@ function locateBunGlobal() {
34922
34828
  function buildRecommendation(pathFirstBin) {
34923
34829
  if (!pathFirstBin)
34924
34830
  return null;
34925
- const bunBinPrefix = resolve33(homedir32(), ".bun", "bin") + "/";
34926
- const bunGlobalPrefix = resolve33(homedir32(), ".bun", "install", "global") + "/";
34831
+ const bunBinPrefix = resolve32(homedir32(), ".bun", "bin") + "/";
34832
+ const bunGlobalPrefix = resolve32(homedir32(), ".bun", "install", "global") + "/";
34927
34833
  const isBun = pathFirstBin.startsWith(bunBinPrefix) || pathFirstBin.startsWith(bunGlobalPrefix);
34928
34834
  if (isBun) {
34929
34835
  return `rm -f ~/.bun/bin/${PKG_NAME} && rm -rf ~/.bun/install/global/node_modules/${PKG_NAME}`;
@@ -35017,8 +34923,8 @@ var init_dashboard_host = __esm(() => {
35017
34923
 
35018
34924
  // scripts/launch.ts
35019
34925
  import { spawn as spawn2 } from "child_process";
35020
- import { realpathSync as realpathSync5, existsSync as existsSync47 } from "node:fs";
35021
- import { resolve as resolve34, dirname as dirname23 } from "node:path";
34926
+ import { realpathSync as realpathSync5, existsSync as existsSync46 } from "node:fs";
34927
+ import { resolve as resolve33, dirname as dirname23 } from "node:path";
35022
34928
  import { fileURLToPath as fileURLToPath2 } from "node:url";
35023
34929
  import { createInterface } from "node:readline";
35024
34930
  function launch(mode) {
@@ -35042,9 +34948,9 @@ function launch(mode) {
35042
34948
  process.env.PORT = port;
35043
34949
  process.env.HOSTNAME = bindHost;
35044
34950
  cmd = "node";
35045
- const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT ?? resolve34(dirname23(realpathSync5(fileURLToPath2(import.meta.url))), "..");
35046
- const serverJsPath = resolve34(packageRoot, ".next/standalone/server.js");
35047
- if (!existsSync47(serverJsPath)) {
34951
+ const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT ?? resolve33(dirname23(realpathSync5(fileURLToPath2(import.meta.url))), "..");
34952
+ const serverJsPath = resolve33(packageRoot, ".next/standalone/server.js");
34953
+ if (!existsSync46(serverJsPath)) {
35048
34954
  let shadowMessage = null;
35049
34955
  try {
35050
34956
  const diag = diagnoseShadow({ selfPackageRoot: packageRoot, selfVersion: version2 });
@@ -35133,20 +35039,20 @@ function helpText() {
35133
35039
  label: "usage",
35134
35040
  entries: [
35135
35041
  ["(bare)", `Scan your session history for leaked keys, then open http://localhost:${DASHBOARD_PORT}/audit`],
35136
- ["--schedule [days]", "Scan on a timer, notify you on this machine, and email the findings. Default 7 days, range 1-90. Signs you in the first time."],
35137
- ["--email <address>", "With --schedule, fills in your address. A sign-in code is still emailed to you to paste."],
35042
+ ["--schedule [days]", "Scan on a timer and notify you on this machine. Default 7 days, range 1-90. No account required."],
35043
+ ["--email <address>", "With --schedule, add email alerts for the most recent masked credential leak. A sign-in code is emailed to you."],
35138
35044
  ["--no-schedule", "Stop the timer. Leaves you signed in."],
35139
35045
  ["--notify", "Show a desktop notification when a scan finds a credential. On by default."],
35140
- ["--no-notify", "Stop those notifications. Scans and the digest are unaffected."],
35046
+ ["--no-notify", "Stop desktop notifications. Scheduled scans and optional email alerts are unaffected."],
35141
35047
  ["--status", "Whether scheduling is on, where reports go, the daemon's state, and when the next scan is due."],
35142
35048
  ["-h, --help", "Show this help."]
35143
35049
  ]
35144
35050
  }
35145
35051
  ],
35146
35052
  footer: [
35147
- "Everything runs on this machine. A scan tells you three ways: a desktop",
35148
- "notification, two lines in your agent session, and the emailed digest —",
35149
- "and only that digest ever leaves."
35053
+ "Every scan runs on this machine. Leak alerts appear as desktop system",
35054
+ "notifications, never inside agent sessions. If you add email, only the",
35055
+ "newest masked credential exposure and its metadata leave the machine."
35150
35056
  ]
35151
35057
  }, helpOptsFor(process.stdout));
35152
35058
  return ["", ...lines, ""].join(`
@@ -35296,52 +35202,38 @@ function heldByLine(held) {
35296
35202
  const ageS = Math.max(0, Math.round((Date.now() - held.startedAt) / 1000));
35297
35203
  return `another audit is already running (pid ${held.pid}, started by ${held.source} ${ageS}s ago)`;
35298
35204
  }
35299
- async function announceLeaksOnDesktop(result) {
35205
+ async function announceLeaksOnDesktop(result, report) {
35300
35206
  try {
35301
- await announceLeaksOrThrow(result);
35207
+ await announceLeaksOrThrow(result, report);
35302
35208
  } catch (err) {
35303
35209
  process.stderr.write(`failproofai: could not announce a leak on the desktop: ` + `${err instanceof Error ? err.message : String(err)}
35304
35210
  `);
35305
35211
  }
35306
35212
  }
35307
- async function announceLeaksOrThrow(result) {
35308
- const ids = result.newLeakIds ?? [];
35213
+ async function announceLeaksOrThrow(result, report) {
35214
+ const ids = result.leakIds ?? result.newLeakIds ?? [];
35309
35215
  if (ids.length === 0)
35310
35216
  return;
35311
35217
  if (!readConfig().audit.notify)
35312
35218
  return;
35313
- const claimed = markLeakNoticeDelivered(ids, undefined, "desktop");
35314
- if (claimed.length === 0)
35315
- return;
35316
- const live = new Set(activeFindings(readLeakRecord()).map((f) => f.id));
35317
- const shown = claimed.filter((id) => live.has(id)).length || claimed.length;
35318
- const n = shown === 1 ? "a possible credential exposure" : `${shown} possible credential exposures`;
35319
- const { title, body } = desktopLeakNotice();
35320
- let delivered = false;
35321
- try {
35322
- if (process.platform === "darwin") {
35323
- pruneMacNotifyQueue();
35324
- if (!queueMacNotification(claimed[0], title, body)) {
35325
- process.stderr.write(`failproofai: found ${n} but could not queue a notification
35219
+ const n = ids.length === 1 ? "a possible credential exposure" : `${ids.length} possible credential exposures`;
35220
+ const emailState = report.kind === "sent" ? "sent" : report.kind === "signed-out" || !readAuth() ? "missing" : report.kind === "failed" ? "failed" : "held";
35221
+ const { title, body } = desktopLeakNotice(emailState);
35222
+ if (process.platform === "darwin") {
35223
+ pruneMacNotifyQueue();
35224
+ if (!queueMacNotification(ids[0], title, body)) {
35225
+ process.stderr.write(`failproofai: found ${n} but could not queue a notification
35326
35226
  `);
35327
- } else {
35328
- delivered = true;
35329
- }
35330
- if (delivered && !macNotifierInstalled()) {
35331
- process.stderr.write(`failproofai: found ${n}; the notifier is not installed, so nothing will show it ` + `(run \`failproofai config\`)
35227
+ } else if (!macNotifierInstalled()) {
35228
+ process.stderr.write(`failproofai: found ${n}; the notifier is not installed, so nothing will show it ` + `(run \`failproofai config\`)
35332
35229
  `);
35333
- }
35334
- return;
35335
35230
  }
35336
- const outcome = await notifyDesktop(title, body, 0);
35337
- delivered = outcome.ok;
35338
- if (!outcome.ok) {
35339
- process.stderr.write(`failproofai: found ${n} but could not raise a desktop notification (${outcome.reason})
35231
+ return;
35232
+ }
35233
+ const outcome = await notifyDesktop(title, body, 0);
35234
+ if (!outcome.ok) {
35235
+ process.stderr.write(`failproofai: found ${n} but could not raise a desktop notification (${outcome.reason})
35340
35236
  `);
35341
- }
35342
- } finally {
35343
- if (!delivered)
35344
- releaseLeakNoticeClaims(claimed, undefined, "desktop");
35345
35237
  }
35346
35238
  }
35347
35239
  async function runScheduledAudit() {
@@ -35375,8 +35267,8 @@ async function runScheduledAudit() {
35375
35267
  }
35376
35268
  process.stdout.write(`failproofai: audit complete — ${num2(result.eventsScanned)} tool calls across ` + `${num2(result.transcripts.scanned)} sessions, ${num2(result.totals.hits)} hits
35377
35269
  `);
35378
- await announceLeaksOnDesktop(result);
35379
35270
  const outcome = await reportHarm(result);
35271
+ await announceLeaksOnDesktop(result, outcome);
35380
35272
  const line = describeOutcome2(outcome);
35381
35273
  if (line) {
35382
35274
  const stream = outcome.kind === "sent" ? process.stdout : process.stderr;
@@ -35534,10 +35426,8 @@ var init_cli2 = __esm(() => {
35534
35426
  init_report_harm();
35535
35427
  init_desktop_notify();
35536
35428
  init_macos_notifier();
35537
- init_leak_notice();
35538
- init_notice();
35539
- init_leak_store();
35540
35429
  init_fp_config();
35430
+ init_auth_store();
35541
35431
  init_tui();
35542
35432
  init_package();
35543
35433
  AUDIT_STAGES2 = [
@@ -35870,8 +35760,8 @@ var init_session_pause_cli = __esm(() => {
35870
35760
 
35871
35761
  // scripts/launch.ts
35872
35762
  import { spawn as spawn3 } from "child_process";
35873
- import { realpathSync as realpathSync6, existsSync as existsSync48 } from "node:fs";
35874
- import { resolve as resolve35, dirname as dirname24 } from "node:path";
35763
+ import { realpathSync as realpathSync6, existsSync as existsSync47 } from "node:fs";
35764
+ import { resolve as resolve34, dirname as dirname24 } from "node:path";
35875
35765
  import { fileURLToPath as fileURLToPath3 } from "node:url";
35876
35766
  import { createInterface as createInterface2 } from "node:readline";
35877
35767
  function launch2(mode) {
@@ -35895,9 +35785,9 @@ function launch2(mode) {
35895
35785
  process.env.PORT = port;
35896
35786
  process.env.HOSTNAME = bindHost;
35897
35787
  cmd = "node";
35898
- const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT ?? resolve35(dirname24(realpathSync6(fileURLToPath3(import.meta.url))), "..");
35899
- const serverJsPath = resolve35(packageRoot, ".next/standalone/server.js");
35900
- if (!existsSync48(serverJsPath)) {
35788
+ const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT ?? resolve34(dirname24(realpathSync6(fileURLToPath3(import.meta.url))), "..");
35789
+ const serverJsPath = resolve34(packageRoot, ".next/standalone/server.js");
35790
+ if (!existsSync47(serverJsPath)) {
35901
35791
  let shadowMessage = null;
35902
35792
  try {
35903
35793
  const diag = diagnoseShadow({ selfPackageRoot: packageRoot, selfVersion: version2 });
@@ -35994,17 +35884,17 @@ var init_cli_error2 = __esm(() => {
35994
35884
 
35995
35885
  // bin/failproofai.mjs
35996
35886
  import { realpathSync as realpathSync7 } from "fs";
35997
- import { dirname as dirname25, resolve as resolve36 } from "path";
35887
+ import { dirname as dirname25, resolve as resolve35 } from "path";
35998
35888
  import { fileURLToPath as fileURLToPath4 } from "url";
35999
35889
  // package.json
36000
- var version = "1.0.4-beta.4";
35890
+ var version = "1.0.4-beta.7";
36001
35891
 
36002
35892
  // bin/failproofai.mjs
36003
35893
  if (!process.env.FAILPROOFAI_PACKAGE_ROOT) {
36004
- process.env.FAILPROOFAI_PACKAGE_ROOT = resolve36(dirname25(realpathSync7(fileURLToPath4(import.meta.url))), "..");
35894
+ process.env.FAILPROOFAI_PACKAGE_ROOT = resolve35(dirname25(realpathSync7(fileURLToPath4(import.meta.url))), "..");
36005
35895
  }
36006
35896
  if (!process.env.FAILPROOFAI_DIST_PATH) {
36007
- process.env.FAILPROOFAI_DIST_PATH = resolve36(dirname25(realpathSync7(fileURLToPath4(import.meta.url))), "..", "dist");
35897
+ process.env.FAILPROOFAI_DIST_PATH = resolve35(dirname25(realpathSync7(fileURLToPath4(import.meta.url))), "..", "dist");
36008
35898
  }
36009
35899
  var args = process.argv.slice(2);
36010
35900
  if (args[0] === "p" || args[0] === "policy")