failproofai 1.0.4-beta.4 → 1.0.4-beta.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (162) 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 +4 -4
  62. package/.next/standalone/.next/server/app/settings/page.js +2 -2
  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 +4 -4
  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]__0ftmoxc._.js → [root-of-the-server]__17xnxlx._.js} +3 -3
  89. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0da85px._.js → [root-of-the-server]__1ckpmkk._.js} +3 -3
  90. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__00-s7h8._.js → [root-of-the-server]__1fvfw59._.js} +1 -1
  91. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0yl9wb5._.js → [root-of-the-server]__1ui5ur8._.js} +2 -2
  92. package/.next/standalone/.next/server/chunks/ssr/{_0guxnh-._.js → _02b3i98._.js} +2 -2
  93. package/.next/standalone/.next/server/chunks/ssr/_04ng_6x._.js +3 -0
  94. package/.next/standalone/.next/server/chunks/ssr/{_1u8-lu2._.js → _07t3jol._.js} +2 -2
  95. package/.next/standalone/.next/server/chunks/ssr/_08x1r5t._.js +1 -1
  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_fp-home_ts_0je3xkv._.js +1 -1
  105. package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
  106. package/.next/standalone/.next/server/pages/404.html +1 -1
  107. package/.next/standalone/.next/server/pages/500.html +1 -1
  108. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  109. package/.next/standalone/.next/server/server-reference-manifest.json +22 -22
  110. package/.next/standalone/.next/static/chunks/{364cqbpeg1y5i.js → 07c6l1lq5_69b.js} +1 -1
  111. package/.next/standalone/.next/static/chunks/{2bxr2_2h4kaqq.js → 12bsgz8czvcnn.js} +1 -1
  112. package/.next/standalone/.next/static/chunks/{38dqur43qthrl.js → 1gn08w2pgqh09.js} +1 -1
  113. package/.next/standalone/.next/static/chunks/{1i-i0pxg9q_8y.js → 1xgq22tri86an.js} +1 -1
  114. package/.next/standalone/.next/static/chunks/{17tfki9x5rd_7.js → 20xkiqzvfkuvm.js} +1 -1
  115. package/.next/standalone/.next/static/chunks/{42gwu2bsz4ske.js → 2a84ug32tzik2.js} +2 -2
  116. package/.next/standalone/.next/static/chunks/{0po8n4tyotjf2.js → 32m2ryfankf_2.js} +1 -1
  117. package/.next/standalone/.next/static/chunks/3ioub_lpen-sq.js +1 -0
  118. package/.next/standalone/.next/static/chunks/{323cyb3a2s06y.js → 3jxd133cw2vm3.js} +1 -1
  119. package/.next/standalone/.next/static/chunks/{0qx7gav1c2_vu.js → 44ncu88eq6z71.js} +1 -1
  120. package/.next/standalone/app/actions/get-leaks.ts +0 -5
  121. package/.next/standalone/app/actions/update-scheduled-audit.ts +4 -56
  122. package/.next/standalone/app/api/auth/status/route.ts +3 -2
  123. package/.next/standalone/app/settings/page.tsx +1 -1
  124. package/.next/standalone/app/settings/settings-client.tsx +13 -39
  125. package/.next/standalone/lib/auth/api-server-client.ts +6 -6
  126. package/.next/standalone/lib/codex-sessions.ts +20 -4
  127. package/.next/standalone/lib/copilot-sessions.ts +32 -1
  128. package/.next/standalone/lib/cursor-sessions.ts +62 -5
  129. package/.next/standalone/package.json +9 -9
  130. package/.next/standalone/server.js +1 -1
  131. package/dist/cli.mjs +952 -1063
  132. package/dist/worker.mjs +173 -380
  133. package/lib/auth/api-server-client.ts +6 -6
  134. package/lib/codex-sessions.ts +20 -4
  135. package/lib/copilot-sessions.ts +32 -1
  136. package/lib/cursor-sessions.ts +62 -5
  137. package/package.json +9 -9
  138. package/pi-extension/index.ts +10 -18
  139. package/src/audit/cli.ts +72 -81
  140. package/src/audit/harm-report.ts +12 -6
  141. package/src/audit/index.ts +2 -0
  142. package/src/audit/leak-fingerprint.ts +2 -4
  143. package/src/audit/leak-record.ts +13 -9
  144. package/src/audit/leak-scan.ts +1 -1
  145. package/src/audit/leak-store.ts +1 -46
  146. package/src/audit/machine-store.ts +8 -9
  147. package/src/audit/macos-notifier.ts +2 -2
  148. package/src/audit/redact-example.ts +2 -0
  149. package/src/audit/report-harm.ts +31 -46
  150. package/src/audit/schedule-cli.ts +17 -33
  151. package/src/audit/types.ts +5 -0
  152. package/src/hooks/configure-wizard.ts +28 -0
  153. package/src/hooks/fp-config.ts +29 -54
  154. package/src/hooks/handler.ts +1 -79
  155. package/src/hooks/integrations.ts +4 -15
  156. package/src/hooks/notice.ts +12 -179
  157. package/.next/standalone/.next/server/chunks/ssr/_0oq1dh6._.js +0 -3
  158. package/.next/standalone/.next/static/chunks/04o5zfl7p5lhx.js +0 -1
  159. package/src/audit/leak-notice.ts +0 -259
  160. /package/.next/standalone/.next/static/{P6icI2V2PvVuePJrqjHCr → aeM365dNTtUZOZvNkX8ba}/_buildManifest.js +0 -0
  161. /package/.next/standalone/.next/static/{P6icI2V2PvVuePJrqjHCr → aeM365dNTtUZOZvNkX8ba}/_clientMiddlewareManifest.js +0 -0
  162. /package/.next/standalone/.next/static/{P6icI2V2PvVuePJrqjHCr → aeM365dNTtUZOZvNkX8ba}/_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.6", 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.6",
158
+ "@failproofai/failproofaid-linux-arm64": "1.0.4-beta.6",
159
+ "@failproofai/failproofaid-darwin-x64": "1.0.4-beta.6",
160
+ "@failproofai/failproofaid-darwin-arm64": "1.0.4-beta.6"
161
161
  },
162
162
  failproofaidBinaries: {
163
- "linux-x64": "4487790ed9b881da2914b5985a23b5adca1f20e226d71c635d8170064e6b2340",
164
- "linux-arm64": "c903c5e201198213ccd8295fdab741c7d08d22c8dd5c276e52aa766595bedcc2",
165
- "darwin-x64": "f0933584abbf0f9ff95cd153f8c6c704e467af1d6ffc8f42f9c426bd44b1142a",
166
- "darwin-arm64": "387a3acbf13f667a557c8ac632fe67dee350cda078e3266e71edfcfacb9ecae6"
163
+ "linux-x64": "24118b8bd058cc5d8711053c4c77cdca9361c12dbf0f421a757d33f07596d428",
164
+ "linux-arm64": "b4278c34a288de2c747bcebcc623d8fd5bda3a1f1e55800926eb1a4b89f0a5e9",
165
+ "darwin-x64": "ecb66699f45f605b0d54ac9e4bac360ac11e4e136442dcccdd083514d77c7d42",
166
+ "darwin-arm64": "b3dbad58bda960ef9481f90bc5085ba8624b2472519cc0bf212a0e8451dd2db4"
167
167
  }
168
168
  };
169
169
  });
@@ -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,16 +25112,92 @@ 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 { 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");
25475
25198
  }
25476
25199
  function macNotifierPlistPath() {
25477
- return resolve23(homedir24(), "Library", "LaunchAgents", `${MAC_NOTIFIER_LABEL}.plist`);
25200
+ return resolve22(homedir24(), "Library", "LaunchAgents", `${MAC_NOTIFIER_LABEL}.plist`);
25478
25201
  }
25479
25202
  function escapeXml2(s) {
25480
25203
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
@@ -25518,7 +25241,7 @@ function notifierPlistContents(appPath, watchDir) {
25518
25241
  <string>${escapeXml2(MAC_NOTIFIER_LABEL)}</string>
25519
25242
  <key>ProgramArguments</key>
25520
25243
  <array>
25521
- <string>${escapeXml2(resolve23(appPath, "Contents", "MacOS", "applet"))}</string>
25244
+ <string>${escapeXml2(resolve22(appPath, "Contents", "MacOS", "applet"))}</string>
25522
25245
  </array>
25523
25246
  <!-- Started only when something is queued, and it exits when the queue is
25524
25247
  empty. RunAtLoad would fire it once at login with nothing to say. -->
@@ -25547,18 +25270,18 @@ function installMacNotifier(home) {
25547
25270
  try {
25548
25271
  const app = macNotifierAppPath(home);
25549
25272
  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 });
25273
+ mkdirSync17(watch, { recursive: true, mode: 448 });
25274
+ mkdirSync17(resolve22(app, ".."), { recursive: true });
25275
+ const scriptPath = resolve22(watch, "..", "notifier.applescript");
25276
+ writeFileSync15(scriptPath, notifierScript(home), { mode: 384 });
25277
+ rmSync9(app, { recursive: true, force: true });
25555
25278
  run("osacompile", ["-o", app, scriptPath]);
25556
- rmSync10(scriptPath, { force: true });
25557
- const plist = resolve23(app, "Contents", "Info.plist");
25279
+ rmSync9(scriptPath, { force: true });
25280
+ const plist = resolve22(app, "Contents", "Info.plist");
25558
25281
  run("defaults", ["write", plist, "CFBundleIdentifier", MAC_NOTIFIER_LABEL]);
25559
25282
  run("defaults", ["write", plist, "CFBundleName", "failproofai"]);
25560
- mkdirSync19(resolve23(macNotifierPlistPath(), ".."), { recursive: true });
25561
- writeFileSync16(macNotifierPlistPath(), notifierPlistContents(app, watch), { mode: 420 });
25283
+ mkdirSync17(resolve22(macNotifierPlistPath(), ".."), { recursive: true });
25284
+ writeFileSync15(macNotifierPlistPath(), notifierPlistContents(app, watch), { mode: 420 });
25562
25285
  const target = `gui/${process.getuid?.() ?? 0}`;
25563
25286
  try {
25564
25287
  run("launchctl", ["bootout", `${target}/${MAC_NOTIFIER_LABEL}`]);
@@ -25575,49 +25298,49 @@ function uninstallMacNotifier(home) {
25575
25298
  try {
25576
25299
  run("launchctl", ["bootout", `gui/${process.getuid?.() ?? 0}/${MAC_NOTIFIER_LABEL}`]);
25577
25300
  } catch {}
25578
- rmSync10(macNotifierPlistPath(), { force: true });
25579
- rmSync10(macNotifierAppPath(home), { recursive: true, force: true });
25580
- rmSync10(macNotifyDir(home), { recursive: true, force: true });
25301
+ rmSync9(macNotifierPlistPath(), { force: true });
25302
+ rmSync9(macNotifierAppPath(home), { recursive: true, force: true });
25303
+ rmSync9(macNotifyDir(home), { recursive: true, force: true });
25581
25304
  }
25582
25305
  function queueMacNotification(id, title, body, home) {
25583
25306
  if (!isFindingId(id))
25584
25307
  return false;
25585
25308
  const dir = macNotifyDir(home);
25586
- const tmp = resolve23(dir, "..", `notify-${id}.tmp`);
25309
+ const tmp = resolve22(dir, "..", `notify-${id}.tmp`);
25587
25310
  try {
25588
- mkdirSync19(dir, { recursive: true, mode: 448 });
25311
+ mkdirSync17(dir, { recursive: true, mode: 448 });
25589
25312
  const payload = `${title.replace(/\s+/g, " ")}
25590
25313
  ${body.replace(/\s+/g, " ")}
25591
25314
  `;
25592
- writeFileSync16(tmp, payload, { mode: 384 });
25593
- renameSync8(tmp, resolve23(dir, id));
25315
+ writeFileSync15(tmp, payload, { mode: 384 });
25316
+ renameSync8(tmp, resolve22(dir, id));
25594
25317
  return true;
25595
25318
  } catch {
25596
25319
  try {
25597
- rmSync10(tmp, { force: true });
25320
+ rmSync9(tmp, { force: true });
25598
25321
  } catch {}
25599
25322
  return false;
25600
25323
  }
25601
25324
  }
25602
25325
  function macNotifierInstalled(home) {
25603
- return existsSync28(macNotifierPlistPath()) && existsSync28(macNotifierAppPath(home));
25326
+ return existsSync26(macNotifierPlistPath()) && existsSync26(macNotifierAppPath(home));
25604
25327
  }
25605
25328
  function pruneMacNotifyQueue(home, maxAgeMs = 7 * 86400000) {
25606
25329
  try {
25607
25330
  const dir = macNotifyDir(home);
25608
- if (!existsSync28(dir))
25331
+ if (!existsSync26(dir))
25609
25332
  return;
25610
25333
  const { statSync } = __require("node:fs");
25611
- for (const name of readdirSync17(dir)) {
25612
- const path = resolve23(dir, name);
25334
+ for (const name of readdirSync16(dir)) {
25335
+ const path = resolve22(dir, name);
25613
25336
  try {
25614
25337
  if (Date.now() - statSync(path).mtimeMs > maxAgeMs)
25615
- rmSync10(path, { force: true });
25338
+ rmSync9(path, { force: true });
25616
25339
  } catch {}
25617
25340
  }
25618
25341
  } catch {}
25619
25342
  }
25620
- var MAC_NOTIFIER_LABEL = "ai.failproof.notifier", macNotifyDir = (home) => resolve23(runDir(home), "notify");
25343
+ var MAC_NOTIFIER_LABEL = "ai.failproof.notifier", macNotifyDir = (home) => resolve22(runDir(home), "notify");
25621
25344
  var init_macos_notifier = __esm(() => {
25622
25345
  init_fp_home();
25623
25346
  init_leak_fingerprint();
@@ -25639,7 +25362,7 @@ var DEFAULT_FETCH_TIMEOUT_MS = 15000;
25639
25362
 
25640
25363
  // src/hooks/cloud-enrollment.ts
25641
25364
  import { randomUUID as randomUUID3 } from "node:crypto";
25642
- import { existsSync as existsSync29, readFileSync as readFileSync23, rmSync as rmSync11 } from "node:fs";
25365
+ import { existsSync as existsSync27, readFileSync as readFileSync22, rmSync as rmSync10 } from "node:fs";
25643
25366
  import { hostname as hostname4 } from "node:os";
25644
25367
  function cloudCredentialPath() {
25645
25368
  return process.env.FAILPROOFAI_CLOUD_CREDENTIALS ?? credentialsFile();
@@ -25678,10 +25401,10 @@ function readCloudCredentials() {
25678
25401
  if (!usingJsonOverride())
25679
25402
  return readCredentials().cloud ?? null;
25680
25403
  const path = cloudCredentialPath();
25681
- if (!existsSync29(path))
25404
+ if (!existsSync27(path))
25682
25405
  return null;
25683
25406
  try {
25684
- const raw = JSON.parse(readFileSync23(path, "utf8"));
25407
+ const raw = JSON.parse(readFileSync22(path, "utf8"));
25685
25408
  if (raw.schemaVersion !== SCHEMA_VERSION2)
25686
25409
  return null;
25687
25410
  if (typeof raw.url !== "string" || typeof raw.machineId !== "string" || typeof raw.token !== "string") {
@@ -25720,10 +25443,10 @@ function resolveMachineLabel(explicit) {
25720
25443
  function clearCloudCredentials() {
25721
25444
  if (usingJsonOverride()) {
25722
25445
  const path = cloudCredentialPath();
25723
- if (!existsSync29(path))
25446
+ if (!existsSync27(path))
25724
25447
  return false;
25725
25448
  try {
25726
- rmSync11(path);
25449
+ rmSync10(path);
25727
25450
  return true;
25728
25451
  } catch {
25729
25452
  return false;
@@ -25971,21 +25694,21 @@ var init_cloud_connection = __esm(() => {
25971
25694
  });
25972
25695
 
25973
25696
  // 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";
25697
+ import { existsSync as existsSync28, realpathSync as realpathSync2, statSync as statSync17 } from "node:fs";
25698
+ import { dirname as dirname14, resolve as resolve23 } from "node:path";
25976
25699
  import { homedir as homedir25 } from "node:os";
25977
25700
  function globalConfigPath(home = homedir25()) {
25978
25701
  return globalPolicyConfigFile(home);
25979
25702
  }
25980
25703
  function projectConfigPath(projectRoot) {
25981
- return resolve24(projectRoot, ".failproofai", "policies-config.json");
25704
+ return resolve23(projectRoot, ".failproofai", "policies-config.json");
25982
25705
  }
25983
25706
  function legacyMarkerPath(home) {
25984
25707
  return launcherMarker(home);
25985
25708
  }
25986
25709
  function isDir(path) {
25987
25710
  try {
25988
- return statSync18(path).isDirectory();
25711
+ return statSync17(path).isDirectory();
25989
25712
  } catch {
25990
25713
  return false;
25991
25714
  }
@@ -25994,14 +25717,14 @@ function findProjectRoot(start, home = homedir25()) {
25994
25717
  const resolvedHome = realResolve(home);
25995
25718
  let dir = realResolve(start);
25996
25719
  while (dir !== resolvedHome) {
25997
- if (isDir(resolve24(dir, ".failproofai")))
25720
+ if (isDir(resolve23(dir, ".failproofai")))
25998
25721
  return dir;
25999
- const parent = dirname15(dir);
25722
+ const parent = dirname14(dir);
26000
25723
  if (parent === dir)
26001
25724
  break;
26002
25725
  dir = parent;
26003
25726
  }
26004
- return resolve24(start);
25727
+ return resolve23(start);
26005
25728
  }
26006
25729
  function hasGlobalHooksInstalled() {
26007
25730
  for (const id of INTEGRATION_TYPES) {
@@ -26013,7 +25736,7 @@ function hasGlobalHooksInstalled() {
26013
25736
  return false;
26014
25737
  }
26015
25738
  function realResolve(path) {
26016
- const lexical = resolve24(path);
25739
+ const lexical = resolve23(path);
26017
25740
  try {
26018
25741
  return realpathSync2(lexical);
26019
25742
  } catch {
@@ -26028,10 +25751,10 @@ function detectSetupState(cwd = process.cwd(), home = homedir25()) {
26028
25751
  cwd: resolvedCwd,
26029
25752
  home: resolvedHome,
26030
25753
  projectRoot,
26031
- hasGlobalConfig: existsSync30(globalConfigPath(resolvedHome)),
26032
- hasProjectConfig: projectRoot !== resolvedHome && existsSync30(projectConfigPath(projectRoot)),
25754
+ hasGlobalConfig: existsSync28(globalConfigPath(resolvedHome)),
25755
+ hasProjectConfig: projectRoot !== resolvedHome && existsSync28(projectConfigPath(projectRoot)),
26033
25756
  hasGlobalHooks: hasGlobalHooksInstalled(),
26034
- hasLegacyMarker: existsSync30(legacyMarkerPath(resolvedHome)),
25757
+ hasLegacyMarker: existsSync28(legacyMarkerPath(resolvedHome)),
26035
25758
  inHomeDir: resolvedCwd === resolvedHome
26036
25759
  };
26037
25760
  }
@@ -26048,14 +25771,14 @@ var init_setup_state = __esm(() => {
26048
25771
  });
26049
25772
 
26050
25773
  // 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";
25774
+ import { existsSync as existsSync29, mkdirSync as mkdirSync18, readFileSync as readFileSync23, rmSync as rmSync11, writeFileSync as writeFileSync16 } from "node:fs";
25775
+ import { dirname as dirname15 } from "node:path";
26053
25776
  function readOnboardingAttempt() {
26054
25777
  const path = onboardingAttemptFile();
26055
- if (!existsSync31(path))
25778
+ if (!existsSync29(path))
26056
25779
  return null;
26057
25780
  try {
26058
- const raw = JSON.parse(readFileSync24(path, "utf8"));
25781
+ const raw = JSON.parse(readFileSync23(path, "utf8"));
26059
25782
  if (raw.schemaVersion !== SCHEMA_VERSION3)
26060
25783
  return null;
26061
25784
  if (typeof raw.reason !== "string" || typeof raw.cliVersion !== "string")
@@ -26074,7 +25797,7 @@ function readOnboardingAttempt() {
26074
25797
  function recordOnboardingAttempt(reason, cliVersion, daemonStatus, now = Date.now()) {
26075
25798
  try {
26076
25799
  const path = onboardingAttemptFile();
26077
- mkdirSync20(dirname16(path), { recursive: true });
25800
+ mkdirSync18(dirname15(path), { recursive: true });
26078
25801
  const record = {
26079
25802
  schemaVersion: SCHEMA_VERSION3,
26080
25803
  reason,
@@ -26082,12 +25805,12 @@ function recordOnboardingAttempt(reason, cliVersion, daemonStatus, now = Date.no
26082
25805
  daemonStatus,
26083
25806
  at: now
26084
25807
  };
26085
- writeFileSync17(path, JSON.stringify(record, null, 2), "utf8");
25808
+ writeFileSync16(path, JSON.stringify(record, null, 2), "utf8");
26086
25809
  } catch {}
26087
25810
  }
26088
25811
  function clearOnboardingAttempt() {
26089
25812
  try {
26090
- rmSync12(onboardingAttemptFile(), { force: true });
25813
+ rmSync11(onboardingAttemptFile(), { force: true });
26091
25814
  } catch {}
26092
25815
  }
26093
25816
  function blockerCleared(attempt, probe) {
@@ -26129,7 +25852,7 @@ var init_onboarding_attempt = __esm(() => {
26129
25852
  });
26130
25853
 
26131
25854
  // src/hooks/onboarding-lock.ts
26132
- import { mkdirSync as mkdirSync21, readFileSync as readFileSync25, rmSync as rmSync13, writeFileSync as writeFileSync18 } from "node:fs";
25855
+ import { mkdirSync as mkdirSync19, readFileSync as readFileSync24, rmSync as rmSync12, writeFileSync as writeFileSync17 } from "node:fs";
26133
25856
  import { homedir as homedir26 } from "node:os";
26134
25857
  function onboardingLockPath(home = homedir26()) {
26135
25858
  return onboardingLockFile(home);
@@ -26146,7 +25869,7 @@ function processAlive(pid) {
26146
25869
  }
26147
25870
  function readLock(path) {
26148
25871
  try {
26149
- const parsed = JSON.parse(readFileSync25(path, "utf8"));
25872
+ const parsed = JSON.parse(readFileSync24(path, "utf8"));
26150
25873
  if (typeof parsed.pid !== "number")
26151
25874
  return null;
26152
25875
  return { pid: parsed.pid, startedAt: Number(parsed.startedAt) || 0 };
@@ -26160,9 +25883,9 @@ function acquireOnboardingLock(home = homedir26()) {
26160
25883
  const held = readLock(path);
26161
25884
  if (held && held.pid !== process.pid && processAlive(held.pid))
26162
25885
  return null;
26163
- mkdirSync21(stateDir(home), { recursive: true });
25886
+ mkdirSync19(stateDir(home), { recursive: true });
26164
25887
  const body = { pid: process.pid, startedAt: Date.now() };
26165
- writeFileSync18(path, JSON.stringify(body), "utf8");
25888
+ writeFileSync17(path, JSON.stringify(body), "utf8");
26166
25889
  let released = false;
26167
25890
  return {
26168
25891
  release() {
@@ -26172,7 +25895,7 @@ function acquireOnboardingLock(home = homedir26()) {
26172
25895
  try {
26173
25896
  const current = readLock(path);
26174
25897
  if (!current || current.pid === process.pid)
26175
- rmSync13(path, { force: true });
25898
+ rmSync12(path, { force: true });
26176
25899
  } catch {}
26177
25900
  }
26178
25901
  };
@@ -26185,7 +25908,7 @@ var init_onboarding_lock = __esm(() => {
26185
25908
  });
26186
25909
 
26187
25910
  // lib/claude-sessions.ts
26188
- import { readdirSync as readdirSync18, statSync as statSync19, existsSync as existsSync32 } from "node:fs";
25911
+ import { readdirSync as readdirSync17, statSync as statSync18, existsSync as existsSync30 } from "node:fs";
26189
25912
  import { join as join32, basename as basename6 } from "node:path";
26190
25913
  function getClaudeProjectsRoot() {
26191
25914
  return getClaudeProjectsPath();
@@ -26194,7 +25917,7 @@ function listClaudeProjects() {
26194
25917
  const root = getClaudeProjectsRoot();
26195
25918
  let entries;
26196
25919
  try {
26197
- entries = readdirSync18(root, { withFileTypes: true });
25920
+ entries = readdirSync17(root, { withFileTypes: true });
26198
25921
  } catch {
26199
25922
  return [];
26200
25923
  }
@@ -26209,7 +25932,7 @@ function collectSubagentTranscripts(dir, relPrefix, project, out, depth) {
26209
25932
  return;
26210
25933
  let entries;
26211
25934
  try {
26212
- entries = readdirSync18(dir, { withFileTypes: true });
25935
+ entries = readdirSync17(dir, { withFileTypes: true });
26213
25936
  } catch {
26214
25937
  return;
26215
25938
  }
@@ -26225,7 +25948,7 @@ function collectSubagentTranscripts(dir, relPrefix, project, out, depth) {
26225
25948
  const stem = entry.name.slice(0, -".jsonl".length);
26226
25949
  const transcriptPath = join32(dir, entry.name);
26227
25950
  try {
26228
- const s = statSync19(transcriptPath);
25951
+ const s = statSync18(transcriptPath);
26229
25952
  out.push({
26230
25953
  projectName: project.name,
26231
25954
  cwd: project.cwd,
@@ -26242,7 +25965,7 @@ function listClaudeTranscripts(project) {
26242
25965
  const out = [];
26243
25966
  let entries;
26244
25967
  try {
26245
- entries = readdirSync18(project.path, { withFileTypes: true });
25968
+ entries = readdirSync17(project.path, { withFileTypes: true });
26246
25969
  } catch {
26247
25970
  return out;
26248
25971
  }
@@ -26253,7 +25976,7 @@ function listClaudeTranscripts(project) {
26253
25976
  continue;
26254
25977
  const transcriptPath = join32(project.path, entry.name);
26255
25978
  try {
26256
- const s = statSync19(transcriptPath);
25979
+ const s = statSync18(transcriptPath);
26257
25980
  out.push({
26258
25981
  projectName: project.name,
26259
25982
  cwd: project.cwd,
@@ -26266,7 +25989,7 @@ function listClaudeTranscripts(project) {
26266
25989
  } catch {}
26267
25990
  } else if (entry.isDirectory() && UUID_RE2.test(entry.name)) {
26268
25991
  const subDir = join32(project.path, entry.name, "subagents");
26269
- if (!existsSync32(subDir))
25992
+ if (!existsSync30(subDir))
26270
25993
  continue;
26271
25994
  collectSubagentTranscripts(subDir, entry.name, project, out, 0);
26272
25995
  }
@@ -26332,7 +26055,7 @@ var init_shared = __esm(() => {
26332
26055
 
26333
26056
  // src/audit/cli-adapters/claude.ts
26334
26057
  import { readFile as readFile15, open as open2 } from "node:fs/promises";
26335
- import { readFileSync as readFileSync26 } from "node:fs";
26058
+ import { readFileSync as readFileSync25 } from "node:fs";
26336
26059
  async function listClaudeTranscriptMetadata(opts = {}) {
26337
26060
  const projectFilter = opts.projects ? new Set(opts.projects) : null;
26338
26061
  const sinceMs = opts.sinceMs ?? 0;
@@ -26352,7 +26075,7 @@ async function listClaudeTranscriptMetadata(opts = {}) {
26352
26075
  let sessionDescription;
26353
26076
  if (t.isSubagent) {
26354
26077
  try {
26355
- const meta = JSON.parse(readFileSync26(t.transcriptPath.replace(/\.jsonl$/, ".meta.json"), "utf8"));
26078
+ const meta = JSON.parse(readFileSync25(t.transcriptPath.replace(/\.jsonl$/, ".meta.json"), "utf8"));
26356
26079
  if (typeof meta.description === "string")
26357
26080
  sessionDescription = meta.description;
26358
26081
  } catch {}
@@ -26483,7 +26206,7 @@ var init_claude = __esm(() => {
26483
26206
  });
26484
26207
 
26485
26208
  // src/audit/cli-adapters/codex.ts
26486
- import { statSync as statSync20 } from "node:fs";
26209
+ import { statSync as statSync19 } from "node:fs";
26487
26210
  async function listCodexTranscriptMetadata(opts = {}) {
26488
26211
  const projectFilter = opts.projects ? new Set(opts.projects) : null;
26489
26212
  const sinceMs = opts.sinceMs ?? 0;
@@ -26500,7 +26223,7 @@ async function listCodexTranscriptMetadata(opts = {}) {
26500
26223
  continue;
26501
26224
  let sizeBytes = 0;
26502
26225
  try {
26503
- sizeBytes = statSync20(s.path).size;
26226
+ sizeBytes = statSync19(s.path).size;
26504
26227
  } catch {}
26505
26228
  if (!s.sessionId)
26506
26229
  continue;
@@ -26534,7 +26257,7 @@ var init_codex = __esm(() => {
26534
26257
  });
26535
26258
 
26536
26259
  // src/audit/cli-adapters/copilot.ts
26537
- import { statSync as statSync21 } from "node:fs";
26260
+ import { statSync as statSync20 } from "node:fs";
26538
26261
  async function listCopilotTranscriptMetadata(opts = {}) {
26539
26262
  const projectFilter = opts.projects ? new Set(opts.projects) : null;
26540
26263
  const sinceMs = opts.sinceMs ?? 0;
@@ -26551,7 +26274,7 @@ async function listCopilotTranscriptMetadata(opts = {}) {
26551
26274
  continue;
26552
26275
  let sizeBytes = 0;
26553
26276
  try {
26554
- sizeBytes = statSync21(s.path).size;
26277
+ sizeBytes = statSync20(s.path).size;
26555
26278
  } catch {}
26556
26279
  if (!s.sessionId)
26557
26280
  continue;
@@ -26585,7 +26308,7 @@ var init_copilot = __esm(() => {
26585
26308
  });
26586
26309
 
26587
26310
  // src/audit/cli-adapters/cursor.ts
26588
- import { statSync as statSync22 } from "node:fs";
26311
+ import { statSync as statSync21 } from "node:fs";
26589
26312
  async function listCursorTranscriptMetadata(opts = {}) {
26590
26313
  const projectFilter = opts.projects ? new Set(opts.projects) : null;
26591
26314
  const sinceMs = opts.sinceMs ?? 0;
@@ -26602,7 +26325,7 @@ async function listCursorTranscriptMetadata(opts = {}) {
26602
26325
  continue;
26603
26326
  let sizeBytes = 0;
26604
26327
  try {
26605
- sizeBytes = statSync22(s.path).size;
26328
+ sizeBytes = statSync21(s.path).size;
26606
26329
  } catch {}
26607
26330
  if (!s.sessionId)
26608
26331
  continue;
@@ -26843,7 +26566,7 @@ var init_opencode = __esm(() => {
26843
26566
  });
26844
26567
 
26845
26568
  // src/audit/cli-adapters/pi.ts
26846
- import { statSync as statSync23 } from "node:fs";
26569
+ import { statSync as statSync22 } from "node:fs";
26847
26570
  async function listPiTranscriptMetadata(opts = {}) {
26848
26571
  const projectFilter = opts.projects ? new Set(opts.projects) : null;
26849
26572
  const sinceMs = opts.sinceMs ?? 0;
@@ -26860,7 +26583,7 @@ async function listPiTranscriptMetadata(opts = {}) {
26860
26583
  continue;
26861
26584
  let sizeBytes = 0;
26862
26585
  try {
26863
- sizeBytes = statSync23(s.path).size;
26586
+ sizeBytes = statSync22(s.path).size;
26864
26587
  } catch {}
26865
26588
  if (!s.sessionId)
26866
26589
  continue;
@@ -27669,7 +27392,7 @@ function flattenToolInput(input, depth = 0) {
27669
27392
  }
27670
27393
  return "";
27671
27394
  }
27672
- var LEAK_SCAN_VERSION = 5, ASSIGNMENT_RE, DOCS_LITERALS, SELF_OUTPUT_MARKERS, GATED_PATTERNS;
27395
+ var LEAK_SCAN_VERSION = 6, ASSIGNMENT_RE, DOCS_LITERALS, SELF_OUTPUT_MARKERS, GATED_PATTERNS;
27673
27396
  var init_leak_scan = __esm(() => {
27674
27397
  init_builtin_policies();
27675
27398
  ASSIGNMENT_RE = /(["']?)\b([A-Za-z_][A-Za-z0-9_]{0,127})\1([ \t]*(?::(?!\/\/)|=)[ \t]*)("[^"]*"|'[^']*'|[^\s;|&"']+)/g;
@@ -27694,6 +27417,176 @@ var init_leak_scan = __esm(() => {
27694
27417
  GATED_PATTERNS = SECRET_PATTERNS.map(([re, label]) => [re, label, literalPrefixOf(re.source)]);
27695
27418
  });
27696
27419
 
27420
+ // src/audit/leak-record.ts
27421
+ function upsertFinding(record, incoming) {
27422
+ const { sighting, ...rest } = incoming;
27423
+ const existing = record.findings.find((f) => f.id === rest.id);
27424
+ if (!existing) {
27425
+ record.findings.push({
27426
+ ...rest,
27427
+ firstSeen: sighting.at,
27428
+ lastSeen: sighting.at,
27429
+ occurrences: 1,
27430
+ sightings: [sighting]
27431
+ });
27432
+ return { record, isNew: true };
27433
+ }
27434
+ existing.occurrences += 1;
27435
+ if (sighting.at > existing.lastSeen)
27436
+ existing.lastSeen = sighting.at;
27437
+ if (sighting.at < existing.firstSeen)
27438
+ existing.firstSeen = sighting.at;
27439
+ const seen = existing.sightings.some((s) => s.sessionId === sighting.sessionId && s.at === sighting.at);
27440
+ if (!seen) {
27441
+ existing.sightings.push(sighting);
27442
+ existing.sightings.sort((a, b) => a.at.localeCompare(b.at));
27443
+ if (existing.sightings.length > MAX_SIGHTINGS) {
27444
+ existing.sightings.splice(1, existing.sightings.length - MAX_SIGHTINGS);
27445
+ }
27446
+ }
27447
+ return { record, isNew: false };
27448
+ }
27449
+ function pruneRecord(record, nowMs) {
27450
+ const cutoff = new Date(nowMs - FINDING_TTL_DAYS * 86400000).toISOString();
27451
+ const live = record.findings.filter((f) => f.lastSeen >= cutoff);
27452
+ live.sort((a, b) => a.lastSeen < b.lastSeen ? 1 : a.lastSeen > b.lastSeen ? -1 : 0);
27453
+ record.findings = live.slice(0, MAX_FINDINGS);
27454
+ return record;
27455
+ }
27456
+ function emptyRecord(salt, nowIso) {
27457
+ return {
27458
+ schemaVersion: LEAK_RECORD_SCHEMA_VERSION,
27459
+ salt,
27460
+ updatedAt: nowIso,
27461
+ findings: []
27462
+ };
27463
+ }
27464
+ function describeMechanism(toolName, direction, shortPath) {
27465
+ const where = shortPath ? ` ${shortPath}` : "";
27466
+ let summary;
27467
+ if (direction === "result") {
27468
+ summary = shortPath ? `appeared in the output of reading${where}` : "appeared in tool output";
27469
+ } else {
27470
+ switch (toolName) {
27471
+ case "Read":
27472
+ summary = `read from${where || " a file"}`;
27473
+ break;
27474
+ case "Write":
27475
+ summary = `written to${where || " a file"}`;
27476
+ break;
27477
+ case "Edit":
27478
+ case "NotebookEdit":
27479
+ summary = `edited into${where || " a file"}`;
27480
+ break;
27481
+ case "Bash":
27482
+ summary = "passed in a shell command";
27483
+ break;
27484
+ default:
27485
+ summary = `sent to the ${toolName} tool`;
27486
+ }
27487
+ }
27488
+ return { summary, toolName, direction };
27489
+ }
27490
+ var MAX_SIGHTINGS = 5, FINDING_TTL_DAYS = 90, MAX_FINDINGS = 500, LEAK_RECORD_SCHEMA_VERSION = 1;
27491
+
27492
+ // src/audit/leak-store.ts
27493
+ import { randomBytes as randomBytes2 } from "node:crypto";
27494
+ import { existsSync as existsSync31, mkdirSync as mkdirSync20, readFileSync as readFileSync26 } from "node:fs";
27495
+ import { dirname as dirname16 } from "node:path";
27496
+ function readJson(path) {
27497
+ try {
27498
+ if (!existsSync31(path))
27499
+ return null;
27500
+ return JSON.parse(readFileSync26(path, "utf8"));
27501
+ } catch {
27502
+ return null;
27503
+ }
27504
+ }
27505
+ function readLeakIdentity(home) {
27506
+ const existing = readJson(auditLeakIdentityFile(home));
27507
+ if (existing && typeof existing.salt === "string" && existing.salt.length >= 32) {
27508
+ return {
27509
+ salt: existing.salt,
27510
+ dismissed: existing.dismissed ?? []
27511
+ };
27512
+ }
27513
+ const minted = { salt: randomBytes2(32).toString("hex"), dismissed: [] };
27514
+ writeLeakIdentity(minted, home);
27515
+ return minted;
27516
+ }
27517
+ function writeLeakIdentity(identity, home) {
27518
+ const path = auditLeakIdentityFile(home);
27519
+ try {
27520
+ mkdirSync20(dirname16(path), { recursive: true });
27521
+ writeJsonAtomically(path, identity, { mode: FILE_MODE });
27522
+ return true;
27523
+ } catch {
27524
+ return false;
27525
+ }
27526
+ }
27527
+ function sanitizeFinding(raw) {
27528
+ if (!raw || typeof raw !== "object" || Array.isArray(raw))
27529
+ return null;
27530
+ const f = raw;
27531
+ if (typeof f.id !== "string" || !isFindingId(f.id))
27532
+ return null;
27533
+ const fp = f.fingerprint;
27534
+ if (!fp || typeof fp !== "object" || typeof fp.display !== "string" || typeof fp.label !== "string") {
27535
+ return null;
27536
+ }
27537
+ const sightings = Array.isArray(f.sightings) ? f.sightings.filter((s) => {
27538
+ if (!s || typeof s !== "object")
27539
+ return false;
27540
+ const m = s.mechanism;
27541
+ return !!m && typeof m === "object" && typeof m.summary === "string";
27542
+ }) : [];
27543
+ return {
27544
+ ...f,
27545
+ fingerprint: {
27546
+ display: fp.display,
27547
+ label: fp.label,
27548
+ length: typeof fp.length === "number" && Number.isFinite(fp.length) ? fp.length : 0,
27549
+ attributed: fp.attributed === true
27550
+ },
27551
+ name: typeof f.name === "string" ? f.name : null,
27552
+ firstSeen: typeof f.firstSeen === "string" ? f.firstSeen : "",
27553
+ lastSeen: typeof f.lastSeen === "string" ? f.lastSeen : "",
27554
+ occurrences: typeof f.occurrences === "number" && Number.isFinite(f.occurrences) ? f.occurrences : sightings.length,
27555
+ sightings
27556
+ };
27557
+ }
27558
+ function readLeakRecord(home) {
27559
+ const identity = readLeakIdentity(home);
27560
+ const raw = readJson(auditLeaksFile(home));
27561
+ if (!raw || raw.schemaVersion !== LEAK_RECORD_SCHEMA_VERSION || !Array.isArray(raw.findings)) {
27562
+ return emptyRecord(identity.salt, new Date().toISOString());
27563
+ }
27564
+ const findings = raw.findings.map(sanitizeFinding).filter((f) => f !== null);
27565
+ return { ...raw, findings, salt: identity.salt };
27566
+ }
27567
+ function writeLeakRecord(record, home, nowMs = Date.now()) {
27568
+ const path = auditLeaksFile(home);
27569
+ try {
27570
+ mkdirSync20(dirname16(path), { recursive: true });
27571
+ const pruned = pruneRecord(record, nowMs);
27572
+ pruned.updatedAt = new Date(nowMs).toISOString();
27573
+ writeJsonAtomically(path, pruned, { mode: FILE_MODE });
27574
+ return true;
27575
+ } catch {
27576
+ return false;
27577
+ }
27578
+ }
27579
+ function activeFindings(record, home) {
27580
+ const dismissed = new Set(readLeakIdentity(home).dismissed);
27581
+ return record.findings.filter((f) => !dismissed.has(f.id)).sort((a, b) => a.lastSeen < b.lastSeen ? 1 : a.lastSeen > b.lastSeen ? -1 : 0);
27582
+ }
27583
+ var FILE_MODE = 384;
27584
+ var init_leak_store = __esm(() => {
27585
+ init_fp_home();
27586
+ init_atomic_write();
27587
+ init_leak_fingerprint();
27588
+ });
27589
+
27697
27590
  // src/audit/redact-example.ts
27698
27591
  import { homedir as homedir27 } from "node:os";
27699
27592
  function maskTruncatedSecret(input) {
@@ -27837,7 +27730,7 @@ var init_redact_example = __esm(() => {
27837
27730
 
27838
27731
  // src/audit/cache.ts
27839
27732
  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";
27733
+ import { existsSync as existsSync32, mkdirSync as mkdirSync21, readFileSync as readFileSync27, writeFileSync as writeFileSync18, chmodSync as chmodSync5, openSync, readSync, closeSync } from "node:fs";
27841
27734
  import { join as join33 } from "node:path";
27842
27735
  function getEngineVersion() {
27843
27736
  if (cachedEngineVersion)
@@ -27898,7 +27791,7 @@ function readCachedTranscript(transcriptPath, mtimeMs, sizeBytes) {
27898
27791
  if (sizeBytes === 0)
27899
27792
  return null;
27900
27793
  const cachePath = getCachePathFor(transcriptPath);
27901
- if (!existsSync33(cachePath))
27794
+ if (!existsSync32(cachePath))
27902
27795
  return null;
27903
27796
  try {
27904
27797
  const raw = readFileSync27(cachePath, "utf-8");
@@ -27942,7 +27835,7 @@ function writeCachedTranscriptResult(transcriptPath, mtimeMs, sizeBytes, result,
27942
27835
  return;
27943
27836
  const cachePath = getCachePathFor(transcriptPath);
27944
27837
  try {
27945
- mkdirSync22(auditCacheDir(), { recursive: true });
27838
+ mkdirSync21(auditCacheDir(), { recursive: true });
27946
27839
  const entry = {
27947
27840
  schemaVersion: CACHE_SCHEMA_VERSION,
27948
27841
  cachedAt: Date.now(),
@@ -27961,7 +27854,7 @@ function writeCachedTranscriptResult(transcriptPath, mtimeMs, sizeBytes, result,
27961
27854
  entry.detectorState = encodeDetectorState(resume.detectorState);
27962
27855
  }
27963
27856
  }
27964
- writeFileSync19(cachePath, JSON.stringify(entry), { encoding: "utf-8", mode: 384 });
27857
+ writeFileSync18(cachePath, JSON.stringify(entry), { encoding: "utf-8", mode: 384 });
27965
27858
  try {
27966
27859
  chmodSync5(cachePath, 384);
27967
27860
  } catch {}
@@ -28480,8 +28373,10 @@ async function runAuditInner(opts, startedAt) {
28480
28373
  }
28481
28374
  const coversAllHistory = opts.clis === undefined && opts.projects === undefined && opts.since === undefined && discoveryErrors === 0 && errors === 0 && skipped === 0;
28482
28375
  const newFindingIds = persistLeaks(perTranscript, coversAllHistory);
28376
+ const leakIds = [...new Set(perTranscript.flatMap((t) => (t.leaks ?? []).map((leak) => leak.id)))];
28483
28377
  const auditResult = {
28484
28378
  version: 2,
28379
+ leakIds,
28485
28380
  newLeakIds: newFindingIds,
28486
28381
  scannedAt: new Date(startedAt).toISOString(),
28487
28382
  scope: {
@@ -28537,11 +28432,11 @@ var init_audit = __esm(() => {
28537
28432
  import {
28538
28433
  closeSync as closeSync2,
28539
28434
  linkSync,
28540
- mkdirSync as mkdirSync23,
28435
+ mkdirSync as mkdirSync22,
28541
28436
  openSync as openSync2,
28542
28437
  readFileSync as readFileSync28,
28543
28438
  unlinkSync as unlinkSync4,
28544
- writeFileSync as writeFileSync20,
28439
+ writeFileSync as writeFileSync19,
28545
28440
  writeSync
28546
28441
  } from "node:fs";
28547
28442
  function acquireAuditLock(source, now = Date.now()) {
@@ -28616,7 +28511,7 @@ function writeLockExclusive(path, info) {
28616
28511
  const body = JSON.stringify(info);
28617
28512
  const staging = `${path}.${process.pid}.tmp`;
28618
28513
  try {
28619
- writeFileSync20(staging, body, { mode: 384 });
28514
+ writeFileSync19(staging, body, { mode: 384 });
28620
28515
  } catch {
28621
28516
  return false;
28622
28517
  }
@@ -28650,8 +28545,8 @@ function createThenWrite(path, body) {
28650
28545
  }
28651
28546
  }
28652
28547
  function ensureRunDir() {
28653
- mkdirSync23(failproofaiHome(), { recursive: true });
28654
- mkdirSync23(runDir(), { recursive: true, mode: 448 });
28548
+ mkdirSync22(failproofaiHome(), { recursive: true });
28549
+ mkdirSync22(runDir(), { recursive: true, mode: 448 });
28655
28550
  }
28656
28551
  var AUDIT_LOCK_MAX_AGE_MS;
28657
28552
  var init_audit_lock = __esm(() => {
@@ -28660,7 +28555,7 @@ var init_audit_lock = __esm(() => {
28660
28555
  });
28661
28556
 
28662
28557
  // src/audit/dashboard-cache.ts
28663
- import { existsSync as existsSync34, readFileSync as readFileSync29 } from "node:fs";
28558
+ import { existsSync as existsSync33, readFileSync as readFileSync29 } from "node:fs";
28664
28559
  function getCachePath() {
28665
28560
  return auditDashboardFile();
28666
28561
  }
@@ -28680,7 +28575,7 @@ function writeDashboardCache(params, result) {
28680
28575
  }
28681
28576
  function readDashboardCacheMeta() {
28682
28577
  const cachePath = getCachePath();
28683
- if (!existsSync34(cachePath))
28578
+ if (!existsSync33(cachePath))
28684
28579
  return null;
28685
28580
  try {
28686
28581
  const raw = readFileSync29(cachePath, "utf-8");
@@ -28907,15 +28802,15 @@ var init_api_server_client = __esm(() => {
28907
28802
  });
28908
28803
 
28909
28804
  // 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";
28805
+ import { existsSync as existsSync34, readFileSync as readFileSync30, readdirSync as readdirSync18, rmSync as rmSync13 } from "node:fs";
28806
+ import { join as join34, resolve as resolve24 } from "node:path";
28912
28807
  function getAuthFilePath() {
28913
28808
  const override = process.env.FAILPROOFAI_AUTH_DIR;
28914
28809
  return override ? join34(override, "session.json") : auditSessionFile();
28915
28810
  }
28916
28811
  function readAuth() {
28917
28812
  const p = getAuthFilePath();
28918
- if (!existsSync35(p))
28813
+ if (!existsSync34(p))
28919
28814
  return null;
28920
28815
  try {
28921
28816
  const raw = readFileSync30(p, "utf-8");
@@ -28942,18 +28837,18 @@ function writeAuth(auth) {
28942
28837
  }
28943
28838
  function deleteAuth() {
28944
28839
  const p = getAuthFilePath();
28945
- if (existsSync35(p))
28946
- rmSync14(p, { force: true });
28840
+ if (existsSync34(p))
28841
+ rmSync13(p, { force: true });
28947
28842
  try {
28948
28843
  const root = migrationsDir();
28949
- if (!existsSync35(root))
28844
+ if (!existsSync34(root))
28950
28845
  return;
28951
- for (const entry of readdirSync19(root)) {
28846
+ for (const entry of readdirSync18(root)) {
28952
28847
  if (!entry.startsWith("backup-layout"))
28953
28848
  continue;
28954
- const copy = resolve25(root, entry, "auth.json");
28955
- if (existsSync35(copy))
28956
- rmSync14(copy, { force: true });
28849
+ const copy = resolve24(root, entry, "auth.json");
28850
+ if (existsSync34(copy))
28851
+ rmSync13(copy, { force: true });
28957
28852
  }
28958
28853
  } catch {}
28959
28854
  }
@@ -29085,7 +28980,11 @@ function selectLeaks(findings, from, to) {
29085
28980
  const last = ts(f.lastSeen);
29086
28981
  if (last !== null && (last < lo || last > hi))
29087
28982
  continue;
29088
- const seen = f.sightings?.[f.sightings.length - 1];
28983
+ const seen = f.sightings?.reduce((latest, candidate) => {
28984
+ if (!latest)
28985
+ return candidate;
28986
+ return (ts(candidate.at) ?? 0) >= (ts(latest.at) ?? 0) ? candidate : latest;
28987
+ }, undefined);
29089
28988
  out.push({
29090
28989
  id: f.id,
29091
28990
  display: f.fingerprint?.display ?? "[credential]",
@@ -29117,7 +29016,7 @@ function buildHarmReport(result, lastReportedAt, intervalDays, leakFindings = []
29117
29016
  window_from: from.toISOString(),
29118
29017
  window_to: windowTo.toISOString(),
29119
29018
  harmful: selectHarmful(result, from, windowTo, { includeUnplaceable: isFirstReport }),
29120
- leaks: selectLeaks(leakFindings, from, windowTo)
29019
+ leaks: selectLeaks(leakFindings, from, windowTo).slice(0, 1)
29121
29020
  };
29122
29021
  }
29123
29022
  var HARMFUL_SEVERITIES, ALSO_HARMFUL;
@@ -29128,12 +29027,12 @@ var init_harm_report = __esm(() => {
29128
29027
  });
29129
29028
 
29130
29029
  // src/audit/machine-store.ts
29131
- import { existsSync as existsSync36, readFileSync as readFileSync31, rmSync as rmSync15 } from "node:fs";
29030
+ import { existsSync as existsSync35, readFileSync as readFileSync31, rmSync as rmSync14 } from "node:fs";
29132
29031
  import { hostname as hostname5 } from "node:os";
29133
29032
  import { randomUUID as randomUUID4 } from "node:crypto";
29134
29033
  function readMachineIdentity(home) {
29135
29034
  const path = auditMachineFile(home);
29136
- if (!existsSync36(path))
29035
+ if (!existsSync35(path))
29137
29036
  return null;
29138
29037
  try {
29139
29038
  const parsed = JSON.parse(readFileSync31(path, "utf8"));
@@ -29182,20 +29081,20 @@ var init_machine_store = __esm(() => {
29182
29081
  // src/audit/report-harm.ts
29183
29082
  async function reportHarm(result) {
29184
29083
  let auto = false;
29185
- let consentedAt;
29186
29084
  let intervalDays = 7;
29187
29085
  try {
29188
29086
  const config = readConfig();
29189
29087
  auto = config.audit.auto;
29190
- consentedAt = config.audit.reportsConsentedAt;
29191
29088
  intervalDays = config.audit.intervalDays;
29192
29089
  } catch {
29193
29090
  return { kind: "disabled" };
29194
29091
  }
29195
29092
  if (!auto)
29196
29093
  return { kind: "disabled" };
29197
- if (consentedAt === undefined)
29198
- return { kind: "consent-required" };
29094
+ const prior = readMachineIdentity();
29095
+ const report = buildHarmReport(result, prior?.last_reported_at, intervalDays, activeFindings(readLeakRecord()));
29096
+ if (report.leaks.length === 0)
29097
+ return { kind: "no-leak" };
29199
29098
  const auth = await getValidAccessToken();
29200
29099
  if (!auth) {
29201
29100
  return { kind: "signed-out" };
@@ -29206,8 +29105,6 @@ async function reportHarm(result) {
29206
29105
  } catch (err) {
29207
29106
  return { kind: "failed", error: err instanceof Error ? err.message : String(err) };
29208
29107
  }
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
29108
  try {
29212
29109
  const res = await submitAuditReport(auth.access_token, {
29213
29110
  machine_id: identity.machine_id,
@@ -29221,7 +29118,7 @@ async function reportHarm(result) {
29221
29118
  try {
29222
29119
  recordReportWatermark(res.next_window_from);
29223
29120
  } catch {}
29224
- return res.emailed ? { kind: "sent", hits } : { kind: "held", hits, reason: res.reason ?? "not_sent" };
29121
+ return res.emailed ? { kind: "sent", leaks: report.leaks.length } : { kind: "held", leaks: report.leaks.length, reason: res.reason ?? "not_sent" };
29225
29122
  } catch (err) {
29226
29123
  const error = err instanceof AuthApiError ? `${err.code}: ${err.message}` : err instanceof Error ? err.message : String(err);
29227
29124
  return { kind: "failed", error };
@@ -29230,17 +29127,16 @@ async function reportHarm(result) {
29230
29127
  function describeOutcome2(outcome) {
29231
29128
  switch (outcome.kind) {
29232
29129
  case "disabled":
29130
+ case "no-leak":
29233
29131
  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
29132
  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";
29133
+ return "failproofai: a credential exposure was found, but no email is configured — run `failproofai audit --schedule --email you@example.com`";
29238
29134
  case "sent":
29239
- return `failproofai: emailed a harm digest (${outcome.hits} finding${outcome.hits === 1 ? "" : "s"})`;
29135
+ return "failproofai: emailed the most recent credential exposure";
29240
29136
  case "held":
29241
- return `failproofai: ${outcome.hits} finding${outcome.hits === 1 ? "" : "s"} reported, no email (${outcome.reason})`;
29137
+ return `failproofai: credential exposure reported, no email (${outcome.reason})`;
29242
29138
  case "failed":
29243
- return `failproofai: could not send the harm report: ${outcome.error}`;
29139
+ return `failproofai: could not send the credential alert: ${outcome.error}`;
29244
29140
  }
29245
29141
  }
29246
29142
  var init_report_harm = __esm(() => {
@@ -29514,6 +29410,15 @@ var init_desktop_notify = __esm(() => {
29514
29410
  ];
29515
29411
  });
29516
29412
 
29413
+ // src/hooks/notice.ts
29414
+ function desktopLeakNotice(email = "held") {
29415
+ 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.";
29416
+ return {
29417
+ title: "failproofai audit needs review",
29418
+ body: "Possible credential exposure was found in your agent transcripts. " + `Run failproofai audit to verify the matches and rotate anything real. ${followUp}`
29419
+ };
29420
+ }
29421
+
29517
29422
  // src/audit/cli.ts
29518
29423
  function colorOn() {
29519
29424
  if (process.env.NO_COLOR && process.env.NO_COLOR !== "")
@@ -29706,10 +29611,8 @@ var init_cli = __esm(() => {
29706
29611
  init_report_harm();
29707
29612
  init_desktop_notify();
29708
29613
  init_macos_notifier();
29709
- init_leak_notice();
29710
- init_notice();
29711
- init_leak_store();
29712
29614
  init_fp_config();
29615
+ init_auth_store();
29713
29616
  init_tui();
29714
29617
  init_package();
29715
29618
  AUDIT_STAGES = [
@@ -29728,9 +29631,9 @@ var init_cli = __esm(() => {
29728
29631
  });
29729
29632
 
29730
29633
  // src/hooks/configure-wizard.ts
29731
- import { existsSync as existsSync37, mkdirSync as mkdirSync24, writeFileSync as writeFileSync21, readFileSync as readFileSync32 } from "node:fs";
29634
+ import { existsSync as existsSync36, mkdirSync as mkdirSync23, writeFileSync as writeFileSync20, readFileSync as readFileSync32 } from "node:fs";
29732
29635
  import { homedir as homedir28 } from "node:os";
29733
- import { dirname as dirname17, resolve as resolve26, sep as sep5 } from "node:path";
29636
+ import { dirname as dirname17, resolve as resolve25, sep as sep5 } from "node:path";
29734
29637
  async function emit(event, props) {
29735
29638
  try {
29736
29639
  await trackHookEvent2(getInstanceId2(), event, props);
@@ -29753,7 +29656,7 @@ function setCustomPoliciesEnabled(scope, cwd, enabled) {
29753
29656
  const path = getConfigPathForScope(scope, cwd);
29754
29657
  let config = {};
29755
29658
  try {
29756
- if (existsSync37(path))
29659
+ if (existsSync36(path))
29757
29660
  config = JSON.parse(readFileSync32(path, "utf8"));
29758
29661
  } catch {
29759
29662
  return;
@@ -29763,7 +29666,7 @@ function setCustomPoliciesEnabled(scope, cwd, enabled) {
29763
29666
  else
29764
29667
  config.customPoliciesEnabled = false;
29765
29668
  try {
29766
- writeFileSync21(path, JSON.stringify(config, null, 2) + `
29669
+ writeFileSync20(path, JSON.stringify(config, null, 2) + `
29767
29670
  `, "utf8");
29768
29671
  } catch {}
29769
29672
  }
@@ -29794,7 +29697,7 @@ function describeCustomPolicies(cwd) {
29794
29697
  const scopes = [];
29795
29698
  let fileCount = 0;
29796
29699
  const dirs = [
29797
- { dir: resolve26(cwd, ".failproofai", "policies"), label: "project" },
29700
+ { dir: resolve25(cwd, ".failproofai", "policies"), label: "project" },
29798
29701
  { dir: customPoliciesDir(), label: "global" }
29799
29702
  ];
29800
29703
  for (const { dir, label } of dirs) {
@@ -29805,7 +29708,7 @@ function describeCustomPolicies(cwd) {
29805
29708
  fileCount += found.length;
29806
29709
  }
29807
29710
  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")}`);
29711
+ warnings.push(`! ${homeify(resolve25(dir, name))} is NOT loaded — rename to ` + `${name.replace(/\.(js|mjs|ts)$/, "-policies.$1")}`);
29809
29712
  }
29810
29713
  }
29811
29714
  return { active, warnings, fileCount, scopes };
@@ -29898,8 +29801,8 @@ function firstRunMarkerPath() {
29898
29801
  }
29899
29802
  function markLauncherSeen() {
29900
29803
  try {
29901
- mkdirSync24(dirname17(firstRunMarkerPath()), { recursive: true });
29902
- writeFileSync21(firstRunMarkerPath(), "1", "utf8");
29804
+ mkdirSync23(dirname17(firstRunMarkerPath()), { recursive: true });
29805
+ writeFileSync20(firstRunMarkerPath(), "1", "utf8");
29903
29806
  } catch {}
29904
29807
  }
29905
29808
  function retryProbe() {
@@ -29977,6 +29880,8 @@ async function runConfigureWizard(io = {}, answers = {}) {
29977
29880
  const cwd = process.cwd();
29978
29881
  const unattended = !stdin.isTTY || !stdout.isTTY;
29979
29882
  const preAnswered = Boolean(answers.token);
29883
+ const initialAudit = readConfigRaw().raw.audit;
29884
+ const hadExplicitAuditAuto = !!initialAudit && typeof initialAudit === "object" && !Array.isArray(initialAudit) && typeof initialAudit.auto === "boolean";
29980
29885
  if (typeof process.getuid === "function" && process.getuid() === 0 && process.env.SUDO_USER) {
29981
29886
  stdout.write(`Run failproofai config as ${process.env.SUDO_USER}, not under sudo.
29982
29887
  ` + `Everything it configures is per-user — hooks, policies and the daemon's own
@@ -30299,6 +30204,11 @@ Hooks keep enforcing; scheduled audits stay off until it is.
30299
30204
  }
30300
30205
  if (daemonInstalled) {
30301
30206
  setDaemonConfigured(true, version2);
30207
+ if (!hadExplicitAuditAuto) {
30208
+ try {
30209
+ updateConfig({ audit: { auto: true } });
30210
+ } catch {}
30211
+ }
30302
30212
  pruneOldDaemonBinaries();
30303
30213
  installMacNotifier();
30304
30214
  }
@@ -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 chmodSync6, 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]);
@@ -30950,14 +30861,14 @@ var init_fp_home2 = () => {};
30950
30861
  import {
30951
30862
  chmodSync as chmodSync7,
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,16 +30898,16 @@ 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
30913
  chmodSync7(secret, 384);
@@ -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 = {}) {
@@ -31803,7 +31714,7 @@ async function runUninstallCommand(opts = {}) {
31803
31714
  } catch {}
31804
31715
  try {
31805
31716
  await uninstallDaemonService();
31806
- if (found.servicePath && existsSync43(found.servicePath)) {
31717
+ if (found.servicePath && existsSync42(found.servicePath)) {
31807
31718
  failures.push(`the service at ${found.servicePath} is still there (most often: no sudo). ` + `Remove it with the commands below.`);
31808
31719
  } else {
31809
31720
  lines.push(`✓ stopped and removed the daemon service`);
@@ -31818,7 +31729,7 @@ async function runUninstallCommand(opts = {}) {
31818
31729
  }
31819
31730
  if (opts.purge && found.homeExists) {
31820
31731
  try {
31821
- rmSync18(failproofaiHome(), { recursive: true, force: true });
31732
+ rmSync17(failproofaiHome(), { recursive: true, force: true });
31822
31733
  purged = true;
31823
31734
  lines.push(`✓ deleted ${failproofaiHome()}`);
31824
31735
  } catch (err) {
@@ -31829,7 +31740,7 @@ async function runUninstallCommand(opts = {}) {
31829
31740
  lines.push(``, `Not everything could be removed:`);
31830
31741
  for (const f of failures)
31831
31742
  lines.push(` ✗ ${f}`);
31832
- if (found.servicePath && existsSync43(found.servicePath)) {
31743
+ if (found.servicePath && existsSync42(found.servicePath)) {
31833
31744
  lines.push(``, `To remove the service by hand:`, ...manualServiceRemoval(found.servicePath), ``, `(\`${daemonStatusCommand()}\` shows its current state.)`);
31834
31745
  }
31835
31746
  return { exitCode: 1, lines, planLines, purged };
@@ -31864,8 +31775,8 @@ var init_uninstall_cli = __esm(() => {
31864
31775
  import { execFileSync as execFileSync5 } from "node:child_process";
31865
31776
  import { homedir as homedir31, tmpdir as tmpdir4 } from "node:os";
31866
31777
  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";
31778
+ 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";
31779
+ 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
31780
  function parseList(rest, flag) {
31870
31781
  const idx = rest.findIndex((a) => a === flag || a.startsWith(`${flag}=`));
31871
31782
  if (idx === -1)
@@ -31965,7 +31876,7 @@ async function build(rest) {
31965
31876
  const version = flag("version");
31966
31877
  const commit = flag("commit");
31967
31878
  const effect = flag("effect") ?? "enforce";
31968
- const outDir = resolve30(flag("out") ?? "dist-pack");
31879
+ const outDir = resolve29(flag("out") ?? "dist-pack");
31969
31880
  if (!entry || !id || !version) {
31970
31881
  return fail2([
31971
31882
  "Usage: failproofai publish <entry.mjs> --repo <owner>/<repo> --version <version>",
@@ -31978,8 +31889,8 @@ async function build(rest) {
31978
31889
  } catch (err) {
31979
31890
  return fail2([err instanceof Error ? err.message : String(err)]);
31980
31891
  }
31981
- const entryPath = resolve30(entry);
31982
- if (!existsSync44(entryPath))
31892
+ const entryPath = resolve29(entry);
31893
+ if (!existsSync43(entryPath))
31983
31894
  return fail2([`No such file: ${entryPath}`]);
31984
31895
  const source = readFileSync36(entryPath, "utf8");
31985
31896
  const localImport = /(?:^|\n)\s*(?:import|export)[^;\n]*from\s+["'](\.[^"']*)["']/.exec(source);
@@ -32037,13 +31948,13 @@ async function build(rest) {
32037
31948
  policies
32038
31949
  }, null, 2) + `
32039
31950
  `;
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");
31951
+ mkdirSync29(outDir, { recursive: true });
31952
+ const manifestPath = resolve29(outDir, PACK_MANIFEST_ASSET);
31953
+ const entryOut = resolve29(outDir, PACK_ENTRY_ASSET);
31954
+ writeFileSync26(manifestPath, manifest, "utf8");
32044
31955
  copyFileSync4(entryPath, entryOut);
32045
31956
  const sha = (bytes) => createHash9("sha256").update(bytes).digest("hex");
32046
- writeFileSync27(resolve30(outDir, PACK_CHECKSUMS_ASSET), `${sha(manifest)} ${PACK_MANIFEST_ASSET}
31957
+ writeFileSync26(resolve29(outDir, PACK_CHECKSUMS_ASSET), `${sha(manifest)} ${PACK_MANIFEST_ASSET}
32047
31958
  ${sha(readFileSync36(entryOut))} ${PACK_ENTRY_ASSET}
32048
31959
  `, "utf8");
32049
31960
  const on = policies.filter((p) => p.defaultEnabled).length;
@@ -32173,12 +32084,12 @@ async function scaffold(target) {
32173
32084
  return ok2(["Nothing written."]);
32174
32085
  chosen = answer.trim();
32175
32086
  }
32176
- const path = resolve30(withPolicyExtension(chosen ?? "my-policies"));
32177
- if (existsSync44(path)) {
32087
+ const path = resolve29(withPolicyExtension(chosen ?? "my-policies"));
32088
+ if (existsSync43(path)) {
32178
32089
  return fail2([`${path} already exists — name a different file, or edit that one.`]);
32179
32090
  }
32180
- mkdirSync30(resolve30(path, ".."), { recursive: true });
32181
- writeFileSync27(path, `import { customPolicies, allow, deny } from "failproofai";
32091
+ mkdirSync29(resolve29(path, ".."), { recursive: true });
32092
+ writeFileSync26(path, `import { customPolicies, allow, deny } from "failproofai";
32182
32093
 
32183
32094
  // One file, no relative imports: only this entry is digest-pinned, so a pack
32184
32095
  // that imported siblings could not honestly claim to be verified.
@@ -32215,7 +32126,7 @@ customPolicies.add({
32215
32126
  function inferRepo(entryPath) {
32216
32127
  try {
32217
32128
  const url = execFileSync5("git", ["remote", "get-url", "origin"], {
32218
- cwd: resolve30(entryPath, ".."),
32129
+ cwd: resolve29(entryPath, ".."),
32219
32130
  encoding: "utf8",
32220
32131
  stdio: ["ignore", "pipe", "ignore"],
32221
32132
  timeout: 5000
@@ -32227,7 +32138,7 @@ function inferRepo(entryPath) {
32227
32138
  }
32228
32139
  }
32229
32140
  function inferCommit(entryPath, outDir, sources) {
32230
- const cwd = resolve30(entryPath, "..");
32141
+ const cwd = resolve29(entryPath, "..");
32231
32142
  const raw = (args) => {
32232
32143
  try {
32233
32144
  return execFileSync5("git", args, {
@@ -32282,9 +32193,9 @@ function realOrSelf(path) {
32282
32193
  }
32283
32194
  }
32284
32195
  function sourcesInHead(git, raw, sources) {
32285
- const paths = sources.map((f) => realOrSelf(resolve30(f)));
32196
+ const paths = sources.map((f) => realOrSelf(resolve29(f)));
32286
32197
  const shown = git(["rev-parse", "--show-toplevel"]);
32287
- const top = shown === null ? null : realOrSelf(resolve30(shown));
32198
+ const top = shown === null ? null : realOrSelf(resolve29(shown));
32288
32199
  const missing = [];
32289
32200
  for (const path of paths) {
32290
32201
  const rel = top ? relative5(top, path) : null;
@@ -32308,7 +32219,7 @@ function sourcesInHead(git, raw, sources) {
32308
32219
  ]);
32309
32220
  if (status === null)
32310
32221
  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)));
32222
+ const dirty = porcelainEntries(status).flatMap((entry) => [entry.path, entry.from].filter(Boolean).map((path) => resolve29(top ?? ".", path)));
32312
32223
  if (dirty.length > 0)
32313
32224
  return { ok: false, offending: dirty, why: "modified" };
32314
32225
  return { ok: true };
@@ -32316,19 +32227,19 @@ function sourcesInHead(git, raw, sources) {
32316
32227
  function skipOutDir(git, entryPath, outDir) {
32317
32228
  if (!outDir)
32318
32229
  return [];
32319
- const out = resolve30(outDir);
32320
- if (resolve30(entryPath).startsWith(out + sep6))
32230
+ const out = resolve29(outDir);
32231
+ if (resolve29(entryPath).startsWith(out + sep6))
32321
32232
  return [];
32322
32233
  const top = git(["rev-parse", "--show-toplevel"]);
32323
32234
  if (!top)
32324
32235
  return [];
32325
- const rel = relative5(resolve30(top), out);
32236
+ const rel = relative5(resolve29(top), out);
32326
32237
  if (!rel || rel.startsWith("..") || isAbsolute4(rel))
32327
32238
  return [];
32328
32239
  return ["--", ":(top)", `:(exclude,literal,top)${rel.split(sep6).join("/")}`];
32329
32240
  }
32330
32241
  function inferTaggedVersion(entryPath, sources) {
32331
- const cwd = resolve30(entryPath, "..");
32242
+ const cwd = resolve29(entryPath, "..");
32332
32243
  const raw = (args) => {
32333
32244
  try {
32334
32245
  return execFileSync5("git", args, {
@@ -32358,7 +32269,7 @@ function inferTaggedVersion(entryPath, sources) {
32358
32269
  function findEntry(dir) {
32359
32270
  let names;
32360
32271
  try {
32361
- names = readdirSync22(dir);
32272
+ names = readdirSync21(dir);
32362
32273
  } catch {
32363
32274
  return [];
32364
32275
  }
@@ -32366,9 +32277,9 @@ function findEntry(dir) {
32366
32277
  for (const name of names) {
32367
32278
  if (!/\.(mjs|js|ts)$/.test(name))
32368
32279
  continue;
32369
- const full = resolve30(dir, name);
32280
+ const full = resolve29(dir, name);
32370
32281
  try {
32371
- if (statSync26(full).size > 512 * 1024)
32282
+ if (statSync25(full).size > 512 * 1024)
32372
32283
  continue;
32373
32284
  const text = readFileSync36(full, "utf8");
32374
32285
  if (/from\s+["']failproofai["']/.test(text) && /customPolicies\s*\.\s*add\s*\(/.test(text)) {
@@ -32381,13 +32292,13 @@ function findEntry(dir) {
32381
32292
  return found.sort();
32382
32293
  }
32383
32294
  function withLocalImports(sources) {
32384
- const seen = new Set(sources.map((f) => resolve30(f)));
32295
+ const seen = new Set(sources.map((f) => resolve29(f)));
32385
32296
  const queue = [...seen];
32386
32297
  while (queue.length > 0 && seen.size < 500) {
32387
32298
  const file = queue.shift();
32388
32299
  let text;
32389
32300
  try {
32390
- if (statSync26(file).size > 512 * 1024)
32301
+ if (statSync25(file).size > 512 * 1024)
32391
32302
  continue;
32392
32303
  text = readFileSync36(file, "utf8");
32393
32304
  } catch {
@@ -32395,13 +32306,13 @@ function withLocalImports(sources) {
32395
32306
  }
32396
32307
  for (const re of LOCAL_IMPORT_RES) {
32397
32308
  for (const match of text.matchAll(re)) {
32398
- const base = resolve30(dirname21(file), match[1]);
32309
+ const base = resolve29(dirname21(file), match[1]);
32399
32310
  for (const ext of LOCAL_IMPORT_EXTENSIONS) {
32400
32311
  const candidate = base + ext;
32401
32312
  if (seen.has(candidate))
32402
32313
  break;
32403
32314
  try {
32404
- if (!statSync26(candidate).isFile())
32315
+ if (!statSync25(candidate).isFile())
32405
32316
  continue;
32406
32317
  } catch {
32407
32318
  continue;
@@ -32416,7 +32327,7 @@ function withLocalImports(sources) {
32416
32327
  return [...seen];
32417
32328
  }
32418
32329
  function settleGitState(entryPath, provenance, packFiles, id, outDir) {
32419
- const cwd = resolve30(entryPath, "..");
32330
+ const cwd = resolve29(entryPath, "..");
32420
32331
  const raw = (args) => {
32421
32332
  try {
32422
32333
  return execFileSync5("git", args, {
@@ -32491,11 +32402,11 @@ function settleGitState(entryPath, provenance, packFiles, id, outDir) {
32491
32402
  if (root === null || status === null)
32492
32403
  return null;
32493
32404
  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));
32405
+ const dirty = entries.map((entry) => resolve29(root, entry.path));
32406
+ const renamedFrom = entries.filter((entry) => entry.from).map((entry) => resolve29(root, entry.from));
32496
32407
  if (dirty.length === 0)
32497
32408
  return null;
32498
- const mine = new Set(packFiles.map((f) => resolve30(f)));
32409
+ const mine = new Set(packFiles.map((f) => resolve29(f)));
32499
32410
  const foreign = dirty.filter((path) => !mine.has(path));
32500
32411
  const toStage = [...dirty, ...renamedFrom];
32501
32412
  if (foreign.length > 0) {
@@ -32628,7 +32539,7 @@ function pushExistingHistory(dir, owner, name, token) {
32628
32539
  return false;
32629
32540
  const askpass = join38(mkdtempSync3(join38(tmpdir4(), "fpai-askpass-")), "askpass.sh");
32630
32541
  try {
32631
- writeFileSync27(askpass, `#!/bin/sh
32542
+ writeFileSync26(askpass, `#!/bin/sh
32632
32543
  case "$1" in
32633
32544
  *Username*) echo x-access-token ;;
32634
32545
  *) echo "$FPAI_GH_TOKEN" ;;
@@ -32648,7 +32559,7 @@ esac
32648
32559
  return true;
32649
32560
  } finally {
32650
32561
  try {
32651
- rmSync19(dirname21(askpass), { recursive: true, force: true });
32562
+ rmSync18(dirname21(askpass), { recursive: true, force: true });
32652
32563
  } catch {}
32653
32564
  }
32654
32565
  }
@@ -32672,8 +32583,8 @@ failproofai policies add ${owner}/${name}
32672
32583
  function findBun() {
32673
32584
  const candidates = [
32674
32585
  "bun",
32675
- process.env.BUN_INSTALL ? resolve30(process.env.BUN_INSTALL, "bin", "bun") : null,
32676
- resolve30(homedir31(), ".bun", "bin", "bun"),
32586
+ process.env.BUN_INSTALL ? resolve29(process.env.BUN_INSTALL, "bin", "bun") : null,
32587
+ resolve29(homedir31(), ".bun", "bin", "bun"),
32677
32588
  "/opt/homebrew/bin/bun",
32678
32589
  "/usr/local/bin/bun"
32679
32590
  ].filter((c) => c !== null);
@@ -32699,12 +32610,12 @@ function bundleEntry(sources, outDir) {
32699
32610
  ]
32700
32611
  };
32701
32612
  }
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(`
32613
+ mkdirSync29(outDir, { recursive: true });
32614
+ const entry = resolve29(outDir, ".entry.generated.mjs");
32615
+ writeFileSync26(entry, sources.map((f) => `import ${JSON.stringify(f.startsWith("/") ? f : resolve29(f))};`).join(`
32705
32616
  `) + `
32706
32617
  `, "utf8");
32707
- const bundled = resolve30(outDir, ".bundled.mjs");
32618
+ const bundled = resolve29(outDir, ".bundled.mjs");
32708
32619
  try {
32709
32620
  execFileSync5(bun, [
32710
32621
  "build",
@@ -32822,7 +32733,7 @@ async function publish(rest) {
32822
32733
  `);
32823
32734
  const token = githubToken();
32824
32735
  const login = token ? await credentialLogin(token) : null;
32825
- const folder = basename8(resolve30(entry, ".."));
32736
+ const folder = basename8(resolve29(entry, ".."));
32826
32737
  const answered = await askWhereToPublish(`${login ?? "your-account"}/${folder}`, { stdin: process.stdin, stdout: process.stdout });
32827
32738
  if (answered === null)
32828
32739
  return ok2(["Nothing was published."]);
@@ -32833,7 +32744,7 @@ async function publish(rest) {
32833
32744
  let versionFromSha = false;
32834
32745
  const dryRun = rest.includes("--dry-run") || !repo;
32835
32746
  const allowPrivate = rest.includes("--allow-private");
32836
- const id = flag("id") ?? repo ?? (dryRun && entry ? `local/${basename8(resolve30(entry, ".."))}` : undefined);
32747
+ const id = flag("id") ?? repo ?? (dryRun && entry ? `local/${basename8(resolve29(entry, ".."))}` : undefined);
32837
32748
  const [owner, name] = (repo ?? "/").split("/");
32838
32749
  if (repo && (!owner || !name || repo.split("/").length !== 2)) {
32839
32750
  return fail2([`--repo must be <owner>/<repo>, got ${JSON.stringify(repo)}`]);
@@ -32852,7 +32763,7 @@ async function publish(rest) {
32852
32763
  "With no --repo it writes the three release assets and stops."
32853
32764
  ]);
32854
32765
  }
32855
- const outDirEarly = resolve30(flag("out") ?? "dist-pack");
32766
+ const outDirEarly = resolve29(flag("out") ?? "dist-pack");
32856
32767
  let provenance = entry ? inferCommit(entry, outDirEarly, bundledSources) : null;
32857
32768
  const gitLines = [];
32858
32769
  if (!version && entry && interactive) {
@@ -32892,7 +32803,7 @@ async function publish(rest) {
32892
32803
  "It needs write access to releases on that repository, and nothing else."
32893
32804
  ]);
32894
32805
  }
32895
- const ensured = await ensureRepo(owner, name, id, token, resolve30(entry, ".."));
32806
+ const ensured = await ensureRepo(owner, name, id, token, resolve29(entry, ".."));
32896
32807
  if ("error" in ensured)
32897
32808
  return fail2(ensured.error);
32898
32809
  created = ensured.created;
@@ -32991,7 +32902,7 @@ async function publish(rest) {
32991
32902
  if (prior) {
32992
32903
  await gh(`${GITHUB_API2}/repos/${owner}/${name}/releases/assets/${prior.id}`, auth, { method: "DELETE" });
32993
32904
  }
32994
- const bytes = readFileSync36(resolve30(outDir, asset));
32905
+ const bytes = readFileSync36(resolve29(outDir, asset));
32995
32906
  const upload = await gh(`${GITHUB_UPLOADS2}/repos/${owner}/${name}/releases/${releaseId}/assets?name=${encodeURIComponent(asset)}`, auth, {
32996
32907
  method: "POST",
32997
32908
  contentType: asset.endsWith(".json") ? "application/json" : "application/octet-stream",
@@ -33672,8 +33583,8 @@ var init_install_prompt = __esm(() => {
33672
33583
 
33673
33584
  // src/hooks/manager.ts
33674
33585
  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";
33586
+ import { existsSync as existsSync44 } from "node:fs";
33587
+ import { resolve as resolve30, basename as basename9 } from "node:path";
33677
33588
  import { platform as platform4, arch as arch4, release as release3, hostname as hostname6 } from "node:os";
33678
33589
  function getSettingsPath2(scope, cwd) {
33679
33590
  return claudeCode.getSettingsPath(scope, cwd);
@@ -33892,9 +33803,9 @@ async function installHooksImpl2(policyNames, scope = "user", cwd, includeBeta =
33892
33803
  delete configToWrite.customPoliciesPath;
33893
33804
  delete configToWrite.customPoliciesPaths;
33894
33805
  } 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))
33806
+ const incoming = (typeof customPoliciesPath === "string" ? [customPoliciesPath] : customPoliciesPath).map((path) => resolve30(path));
33807
+ const carried = (previousConfig.customPoliciesPaths ?? (previousConfig.customPoliciesPath ? [previousConfig.customPoliciesPath] : [])).map((path) => resolve30(path)).filter((path) => {
33808
+ if (existsSync44(path))
33898
33809
  return true;
33899
33810
  console.log(`Dropping custom policies path (file no longer exists): ${path}`);
33900
33811
  return false;
@@ -34117,7 +34028,7 @@ async function removeHooks2(policyNames, scope = "user", cwd, opts) {
34117
34028
  const scopesToRemove = scope === "all" ? [...integration.scopes] : integration.scopes.includes(scope) ? [scope] : [];
34118
34029
  for (const s of scopesToRemove) {
34119
34030
  const settingsPaths = settingsPathsFor(integration, s, cwd);
34120
- const existing = settingsPaths.filter((p) => existsSync45(p));
34031
+ const existing = settingsPaths.filter((p) => existsSync44(p));
34121
34032
  if (existing.length === 0) {
34122
34033
  if (scope !== "all" && selectedClis.length === 1) {
34123
34034
  console.log("No settings file found. Nothing to remove.");
@@ -34261,9 +34172,9 @@ async function listHooks(cwd) {
34261
34172
  if (explicitPaths.length > 0) {
34262
34173
  groups.push(rule("Custom Policies", opts));
34263
34174
  for (const path of explicitPaths) {
34264
- const absPath = resolve31(findProjectConfigDir(cwd ?? process.cwd()), path);
34175
+ const absPath = resolve30(findProjectConfigDir(cwd ?? process.cwd()), path);
34265
34176
  groups.push(note(absPath, opts));
34266
- if (!existsSync45(absPath)) {
34177
+ if (!existsSync44(absPath)) {
34267
34178
  groups.push(warning([`file not found: ${absPath}`], opts));
34268
34179
  continue;
34269
34180
  }
@@ -34283,7 +34194,7 @@ async function listHooks(cwd) {
34283
34194
  }
34284
34195
  }
34285
34196
  const base = findProjectConfigDir(cwd ?? process.cwd());
34286
- const projectDir = resolve31(base, ".failproofai", "policies");
34197
+ const projectDir = resolve30(base, ".failproofai", "policies");
34287
34198
  const userDir = customPoliciesDir();
34288
34199
  const sameDir = userDir === projectDir;
34289
34200
  const conventionDirs = [
@@ -34589,21 +34500,20 @@ async function runScheduleOn(daysArg, emailArg) {
34589
34500
  if (bad)
34590
34501
  throw new ScheduleCliError(bad);
34591
34502
  }
34592
- const { user, prompted } = await ensureSignedIn(emailArg);
34503
+ const signedIn = emailArg === undefined ? { user: readAuth()?.user ?? null, prompted: false } : await ensureSignedIn(emailArg);
34593
34504
  const next = updateConfig({
34594
34505
  audit: {
34595
34506
  auto: true,
34596
- reportsConsentedAt: Date.now(),
34597
34507
  ...days !== undefined ? { intervalDays: days } : {}
34598
34508
  }
34599
34509
  });
34600
34510
  const interval = next.audit.intervalDays;
34601
34511
  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"
34512
+ `every ${interval} day${interval === 1 ? "" : "s"} · desktop notification on leaks`,
34513
+ signedIn.user ? `masked leak alerts also go to ${signedIn.user.email}` : "email is optional · add it with --email you@example.com",
34514
+ "email contains only the most recent masked credential exposure"
34605
34515
  ];
34606
- if (prompted) {
34516
+ if (signedIn.prompted) {
34607
34517
  step("scheduled audits are on", summary);
34608
34518
  } else {
34609
34519
  process.stdout.write(`
@@ -34612,7 +34522,7 @@ ${green("✓")} ${bold("scheduled audits are on")}
34612
34522
  `).join(""));
34613
34523
  }
34614
34524
  warnIfDaemonWontRun();
34615
- if (prompted) {
34525
+ if (signedIn.prompted) {
34616
34526
  outro("failproofai audit --status · when the next scan is due");
34617
34527
  } else {
34618
34528
  process.stdout.write(dim(`
@@ -34664,12 +34574,7 @@ function runScheduleStatus() {
34664
34574
  ]);
34665
34575
  detail.push(["reports to", live ? live.user.email : dim("— signed out")]);
34666
34576
  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
- ]);
34577
+ detail.push(["", pink("scans and desktop alerts continue; email alerts are paused")]);
34673
34578
  }
34674
34579
  detail.push(["daemon", describeDaemon(daemon)]);
34675
34580
  if (sched?.nextDueAtMs != null && on) {
@@ -34784,14 +34689,14 @@ var init_schedule_cli = __esm(() => {
34784
34689
  });
34785
34690
 
34786
34691
  // scripts/parse-script-args.ts
34787
- import { resolve as resolve32 } from "path";
34692
+ import { resolve as resolve31 } from "path";
34788
34693
  function parseStringFlag(flagName, errorLabel, inlineValue, args, index, options) {
34789
34694
  const raw = inlineValue ?? args[index + 1];
34790
34695
  if (raw === undefined || inlineValue === null && raw.startsWith("-")) {
34791
34696
  console.error(`Error: ${flagName} requires ${errorLabel}`);
34792
34697
  process.exit(1);
34793
34698
  }
34794
- const value = options?.resolve ? resolve32(raw) : raw;
34699
+ const value = options?.resolve ? resolve31(raw) : raw;
34795
34700
  return { value, spliceCount: inlineValue !== null ? 1 : 2 };
34796
34701
  }
34797
34702
  function parseScriptArgs(argv) {
@@ -34847,19 +34752,19 @@ function parseScriptArgs(argv) {
34847
34752
  var init_parse_script_args = () => {};
34848
34753
 
34849
34754
  // 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";
34755
+ import { existsSync as existsSync45, readFileSync as readFileSync38, realpathSync as realpathSync4 } from "node:fs";
34756
+ import { dirname as dirname22, resolve as resolve32 } from "node:path";
34852
34757
  import { homedir as homedir32, platform as platform5 } from "node:os";
34853
34758
  import { spawnSync } from "node:child_process";
34854
34759
  function findPackageRoot(start) {
34855
34760
  try {
34856
34761
  let dir = realpathSync4(start);
34857
- if (existsSync46(dir) && !existsSync46(resolve33(dir, "package.json"))) {
34762
+ if (existsSync45(dir) && !existsSync45(resolve32(dir, "package.json"))) {
34858
34763
  dir = dirname22(dir);
34859
34764
  }
34860
34765
  while (true) {
34861
- const pkgPath = resolve33(dir, "package.json");
34862
- if (existsSync46(pkgPath)) {
34766
+ const pkgPath = resolve32(dir, "package.json");
34767
+ if (existsSync45(pkgPath)) {
34863
34768
  try {
34864
34769
  const pkg = JSON.parse(readFileSync38(pkgPath, "utf8"));
34865
34770
  if (pkg.name === PKG_NAME)
@@ -34879,7 +34784,7 @@ function readPackageVersion(packageRoot) {
34879
34784
  if (!packageRoot)
34880
34785
  return null;
34881
34786
  try {
34882
- const pkg = JSON.parse(readFileSync38(resolve33(packageRoot, "package.json"), "utf8"));
34787
+ const pkg = JSON.parse(readFileSync38(resolve32(packageRoot, "package.json"), "utf8"));
34883
34788
  return typeof pkg.version === "string" ? pkg.version : null;
34884
34789
  } catch {
34885
34790
  return null;
@@ -34905,16 +34810,16 @@ function locateNpmGlobal() {
34905
34810
  const root = (res.stdout || "").trim();
34906
34811
  if (!root)
34907
34812
  return null;
34908
- const candidate = resolve33(root, PKG_NAME);
34909
- return existsSync46(resolve33(candidate, "package.json")) ? candidate : null;
34813
+ const candidate = resolve32(root, PKG_NAME);
34814
+ return existsSync45(resolve32(candidate, "package.json")) ? candidate : null;
34910
34815
  } catch {
34911
34816
  return null;
34912
34817
  }
34913
34818
  }
34914
34819
  function locateBunGlobal() {
34915
34820
  try {
34916
- const candidate = resolve33(homedir32(), ".bun", "install", "global", "node_modules", PKG_NAME);
34917
- return existsSync46(resolve33(candidate, "package.json")) ? candidate : null;
34821
+ const candidate = resolve32(homedir32(), ".bun", "install", "global", "node_modules", PKG_NAME);
34822
+ return existsSync45(resolve32(candidate, "package.json")) ? candidate : null;
34918
34823
  } catch {
34919
34824
  return null;
34920
34825
  }
@@ -34922,8 +34827,8 @@ function locateBunGlobal() {
34922
34827
  function buildRecommendation(pathFirstBin) {
34923
34828
  if (!pathFirstBin)
34924
34829
  return null;
34925
- const bunBinPrefix = resolve33(homedir32(), ".bun", "bin") + "/";
34926
- const bunGlobalPrefix = resolve33(homedir32(), ".bun", "install", "global") + "/";
34830
+ const bunBinPrefix = resolve32(homedir32(), ".bun", "bin") + "/";
34831
+ const bunGlobalPrefix = resolve32(homedir32(), ".bun", "install", "global") + "/";
34927
34832
  const isBun = pathFirstBin.startsWith(bunBinPrefix) || pathFirstBin.startsWith(bunGlobalPrefix);
34928
34833
  if (isBun) {
34929
34834
  return `rm -f ~/.bun/bin/${PKG_NAME} && rm -rf ~/.bun/install/global/node_modules/${PKG_NAME}`;
@@ -35017,8 +34922,8 @@ var init_dashboard_host = __esm(() => {
35017
34922
 
35018
34923
  // scripts/launch.ts
35019
34924
  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";
34925
+ import { realpathSync as realpathSync5, existsSync as existsSync46 } from "node:fs";
34926
+ import { resolve as resolve33, dirname as dirname23 } from "node:path";
35022
34927
  import { fileURLToPath as fileURLToPath2 } from "node:url";
35023
34928
  import { createInterface } from "node:readline";
35024
34929
  function launch(mode) {
@@ -35042,9 +34947,9 @@ function launch(mode) {
35042
34947
  process.env.PORT = port;
35043
34948
  process.env.HOSTNAME = bindHost;
35044
34949
  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)) {
34950
+ const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT ?? resolve33(dirname23(realpathSync5(fileURLToPath2(import.meta.url))), "..");
34951
+ const serverJsPath = resolve33(packageRoot, ".next/standalone/server.js");
34952
+ if (!existsSync46(serverJsPath)) {
35048
34953
  let shadowMessage = null;
35049
34954
  try {
35050
34955
  const diag = diagnoseShadow({ selfPackageRoot: packageRoot, selfVersion: version2 });
@@ -35133,20 +35038,20 @@ function helpText() {
35133
35038
  label: "usage",
35134
35039
  entries: [
35135
35040
  ["(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."],
35041
+ ["--schedule [days]", "Scan on a timer and notify you on this machine. Default 7 days, range 1-90. No account required."],
35042
+ ["--email <address>", "With --schedule, add email alerts for the most recent masked credential leak. A sign-in code is emailed to you."],
35138
35043
  ["--no-schedule", "Stop the timer. Leaves you signed in."],
35139
35044
  ["--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."],
35045
+ ["--no-notify", "Stop desktop notifications. Scheduled scans and optional email alerts are unaffected."],
35141
35046
  ["--status", "Whether scheduling is on, where reports go, the daemon's state, and when the next scan is due."],
35142
35047
  ["-h, --help", "Show this help."]
35143
35048
  ]
35144
35049
  }
35145
35050
  ],
35146
35051
  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."
35052
+ "Every scan runs on this machine. Leak alerts appear as desktop system",
35053
+ "notifications, never inside agent sessions. If you add email, only the",
35054
+ "newest masked credential exposure and its metadata leave the machine."
35150
35055
  ]
35151
35056
  }, helpOptsFor(process.stdout));
35152
35057
  return ["", ...lines, ""].join(`
@@ -35296,52 +35201,38 @@ function heldByLine(held) {
35296
35201
  const ageS = Math.max(0, Math.round((Date.now() - held.startedAt) / 1000));
35297
35202
  return `another audit is already running (pid ${held.pid}, started by ${held.source} ${ageS}s ago)`;
35298
35203
  }
35299
- async function announceLeaksOnDesktop(result) {
35204
+ async function announceLeaksOnDesktop(result, report) {
35300
35205
  try {
35301
- await announceLeaksOrThrow(result);
35206
+ await announceLeaksOrThrow(result, report);
35302
35207
  } catch (err) {
35303
35208
  process.stderr.write(`failproofai: could not announce a leak on the desktop: ` + `${err instanceof Error ? err.message : String(err)}
35304
35209
  `);
35305
35210
  }
35306
35211
  }
35307
- async function announceLeaksOrThrow(result) {
35308
- const ids = result.newLeakIds ?? [];
35212
+ async function announceLeaksOrThrow(result, report) {
35213
+ const ids = result.leakIds ?? result.newLeakIds ?? [];
35309
35214
  if (ids.length === 0)
35310
35215
  return;
35311
35216
  if (!readConfig().audit.notify)
35312
35217
  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
35218
+ const n = ids.length === 1 ? "a possible credential exposure" : `${ids.length} possible credential exposures`;
35219
+ const emailState = report.kind === "sent" ? "sent" : report.kind === "signed-out" || !readAuth() ? "missing" : report.kind === "failed" ? "failed" : "held";
35220
+ const { title, body } = desktopLeakNotice(emailState);
35221
+ if (process.platform === "darwin") {
35222
+ pruneMacNotifyQueue();
35223
+ if (!queueMacNotification(ids[0], title, body)) {
35224
+ process.stderr.write(`failproofai: found ${n} but could not queue a notification
35326
35225
  `);
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\`)
35226
+ } else if (!macNotifierInstalled()) {
35227
+ process.stderr.write(`failproofai: found ${n}; the notifier is not installed, so nothing will show it ` + `(run \`failproofai config\`)
35332
35228
  `);
35333
- }
35334
- return;
35335
35229
  }
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})
35230
+ return;
35231
+ }
35232
+ const outcome = await notifyDesktop(title, body, 0);
35233
+ if (!outcome.ok) {
35234
+ process.stderr.write(`failproofai: found ${n} but could not raise a desktop notification (${outcome.reason})
35340
35235
  `);
35341
- }
35342
- } finally {
35343
- if (!delivered)
35344
- releaseLeakNoticeClaims(claimed, undefined, "desktop");
35345
35236
  }
35346
35237
  }
35347
35238
  async function runScheduledAudit() {
@@ -35375,8 +35266,8 @@ async function runScheduledAudit() {
35375
35266
  }
35376
35267
  process.stdout.write(`failproofai: audit complete — ${num2(result.eventsScanned)} tool calls across ` + `${num2(result.transcripts.scanned)} sessions, ${num2(result.totals.hits)} hits
35377
35268
  `);
35378
- await announceLeaksOnDesktop(result);
35379
35269
  const outcome = await reportHarm(result);
35270
+ await announceLeaksOnDesktop(result, outcome);
35380
35271
  const line = describeOutcome2(outcome);
35381
35272
  if (line) {
35382
35273
  const stream = outcome.kind === "sent" ? process.stdout : process.stderr;
@@ -35534,10 +35425,8 @@ var init_cli2 = __esm(() => {
35534
35425
  init_report_harm();
35535
35426
  init_desktop_notify();
35536
35427
  init_macos_notifier();
35537
- init_leak_notice();
35538
- init_notice();
35539
- init_leak_store();
35540
35428
  init_fp_config();
35429
+ init_auth_store();
35541
35430
  init_tui();
35542
35431
  init_package();
35543
35432
  AUDIT_STAGES2 = [
@@ -35870,8 +35759,8 @@ var init_session_pause_cli = __esm(() => {
35870
35759
 
35871
35760
  // scripts/launch.ts
35872
35761
  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";
35762
+ import { realpathSync as realpathSync6, existsSync as existsSync47 } from "node:fs";
35763
+ import { resolve as resolve34, dirname as dirname24 } from "node:path";
35875
35764
  import { fileURLToPath as fileURLToPath3 } from "node:url";
35876
35765
  import { createInterface as createInterface2 } from "node:readline";
35877
35766
  function launch2(mode) {
@@ -35895,9 +35784,9 @@ function launch2(mode) {
35895
35784
  process.env.PORT = port;
35896
35785
  process.env.HOSTNAME = bindHost;
35897
35786
  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)) {
35787
+ const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT ?? resolve34(dirname24(realpathSync6(fileURLToPath3(import.meta.url))), "..");
35788
+ const serverJsPath = resolve34(packageRoot, ".next/standalone/server.js");
35789
+ if (!existsSync47(serverJsPath)) {
35901
35790
  let shadowMessage = null;
35902
35791
  try {
35903
35792
  const diag = diagnoseShadow({ selfPackageRoot: packageRoot, selfVersion: version2 });
@@ -35994,17 +35883,17 @@ var init_cli_error2 = __esm(() => {
35994
35883
 
35995
35884
  // bin/failproofai.mjs
35996
35885
  import { realpathSync as realpathSync7 } from "fs";
35997
- import { dirname as dirname25, resolve as resolve36 } from "path";
35886
+ import { dirname as dirname25, resolve as resolve35 } from "path";
35998
35887
  import { fileURLToPath as fileURLToPath4 } from "url";
35999
35888
  // package.json
36000
- var version = "1.0.4-beta.4";
35889
+ var version = "1.0.4-beta.6";
36001
35890
 
36002
35891
  // bin/failproofai.mjs
36003
35892
  if (!process.env.FAILPROOFAI_PACKAGE_ROOT) {
36004
- process.env.FAILPROOFAI_PACKAGE_ROOT = resolve36(dirname25(realpathSync7(fileURLToPath4(import.meta.url))), "..");
35893
+ process.env.FAILPROOFAI_PACKAGE_ROOT = resolve35(dirname25(realpathSync7(fileURLToPath4(import.meta.url))), "..");
36005
35894
  }
36006
35895
  if (!process.env.FAILPROOFAI_DIST_PATH) {
36007
- process.env.FAILPROOFAI_DIST_PATH = resolve36(dirname25(realpathSync7(fileURLToPath4(import.meta.url))), "..", "dist");
35896
+ process.env.FAILPROOFAI_DIST_PATH = resolve35(dirname25(realpathSync7(fileURLToPath4(import.meta.url))), "..", "dist");
36008
35897
  }
36009
35898
  var args = process.argv.slice(2);
36010
35899
  if (args[0] === "p" || args[0] === "policy")