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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (176) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/build-manifest.json +3 -3
  3. package/.next/standalone/.next/prerender-manifest.json +3 -3
  4. package/.next/standalone/.next/required-server-files.json +1 -1
  5. package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
  6. package/.next/standalone/.next/server/app/_global-error/page.js +2 -2
  7. package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
  8. package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  9. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  10. package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
  11. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +6 -6
  12. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
  13. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  14. package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  15. package/.next/standalone/.next/server/app/_not-found/page.js +2 -2
  16. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  17. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  18. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  19. package/.next/standalone/.next/server/app/_not-found.rsc +14 -14
  20. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +14 -14
  21. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +13 -13
  22. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  23. package/.next/standalone/.next/server/app/api/audit/invite/route.js.nft.json +1 -1
  24. package/.next/standalone/.next/server/app/api/audit/run/route.js +1 -1
  25. package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -1
  26. package/.next/standalone/.next/server/app/api/audit/status/route.js.nft.json +1 -1
  27. package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -1
  28. package/.next/standalone/.next/server/app/api/auth/login-verify/route.js.nft.json +1 -1
  29. package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
  30. package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -1
  31. package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
  32. package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +5 -5
  33. package/.next/standalone/.next/server/app/audit/page.js +3 -3
  34. package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -1
  35. package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
  36. package/.next/standalone/.next/server/app/index.html +1 -1
  37. package/.next/standalone/.next/server/app/index.rsc +14 -14
  38. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +13 -13
  39. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +14 -14
  40. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  41. package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
  42. package/.next/standalone/.next/server/app/page.js +2 -2
  43. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  44. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  45. package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +14 -14
  46. package/.next/standalone/.next/server/app/policies/page.js +4 -4
  47. package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
  48. package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
  49. package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
  50. package/.next/standalone/.next/server/app/project/[name]/page.js +3 -3
  51. package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
  52. package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
  53. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
  54. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
  55. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js +4 -4
  56. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
  57. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
  58. package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
  59. package/.next/standalone/.next/server/app/projects/page.js +3 -3
  60. package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
  61. package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  62. package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +4 -4
  63. package/.next/standalone/.next/server/app/settings/page.js +2 -2
  64. package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
  65. package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  66. package/.next/standalone/.next/server/chunks/{[externals]__1lh7m5d._.js → [externals]__0v1hz15._.js} +1 -1
  67. package/.next/standalone/.next/server/chunks/{[externals]__1rqkg_y._.js → [externals]__1nb206a._.js} +1 -1
  68. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0o07qi9._.js +1 -1
  69. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0rv7m0k._.js +1 -1
  70. package/.next/standalone/.next/server/chunks/[root-of-the-server]__17g9wh7._.js +1 -1
  71. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1legmza._.js +1 -1
  72. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1p-qi2t._.js +1 -1
  73. package/.next/standalone/.next/server/chunks/{_08w6xzm._.js → _0otft92._.js} +2 -2
  74. package/.next/standalone/.next/server/chunks/_0tovk6q._.js +1 -1
  75. package/.next/standalone/.next/server/chunks/_0trp3yc._.js +1 -1
  76. package/.next/standalone/.next/server/chunks/_1ek68ln._.js +4 -4
  77. package/.next/standalone/.next/server/chunks/_1vslkoe._.js +1 -1
  78. package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
  79. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0p-5p8u._.js → [root-of-the-server]__0-4ja6q._.js} +3 -3
  80. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1p2otjt._.js → [root-of-the-server]__00cr3xu._.js} +3 -3
  81. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__013jr2b._.js → [root-of-the-server]__04px77e._.js} +3 -3
  82. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__190won8._.js → [root-of-the-server]__0dxf928._.js} +1 -1
  83. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0s740oi._.js → [root-of-the-server]__0egr5s1._.js} +3 -3
  84. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__01wy8d-._.js → [root-of-the-server]__0i0l1di._.js} +3 -3
  85. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0n_lxhg._.js → [root-of-the-server]__0kokc8z._.js} +1 -1
  86. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1ctpynv._.js → [root-of-the-server]__0n2txhk._.js} +1 -1
  87. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0oa1lav._.js +1 -1
  88. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__02npjtd._.js → [root-of-the-server]__0r3c1_0._.js} +3 -3
  89. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0ftmoxc._.js → [root-of-the-server]__17xnxlx._.js} +3 -3
  90. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0da85px._.js → [root-of-the-server]__1ckpmkk._.js} +3 -3
  91. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__00-s7h8._.js → [root-of-the-server]__1fvfw59._.js} +1 -1
  92. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1ui5ur8._.js +3 -0
  93. package/.next/standalone/.next/server/chunks/ssr/_02b3i98._.js +23 -0
  94. package/.next/standalone/.next/server/chunks/ssr/{_0oq1dh6._.js → _04ng_6x._.js} +2 -2
  95. package/.next/standalone/.next/server/chunks/ssr/{_1u8-lu2._.js → _07t3jol._.js} +2 -2
  96. package/.next/standalone/.next/server/chunks/ssr/_08x1r5t._.js +1 -1
  97. package/.next/standalone/.next/server/chunks/ssr/{_0h_douw._.js → _0s-77v5._.js} +1 -1
  98. package/.next/standalone/.next/server/chunks/ssr/_1_ozgif._.js +1 -1
  99. package/.next/standalone/.next/server/chunks/ssr/_1ddpc5g._.js +1 -1
  100. package/.next/standalone/.next/server/chunks/ssr/_1es2j7i._.js +4 -1
  101. package/.next/standalone/.next/server/chunks/ssr/_next-internal_server_app_policies_page_actions_1sp2-yo.js +2 -2
  102. package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +1 -1
  103. package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
  104. package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +1 -1
  105. package/.next/standalone/.next/server/chunks/ssr/app_settings_settings-client_tsx_20lq-mq._.js +1 -1
  106. package/.next/standalone/.next/server/chunks/ssr/src_hooks_fp-home_ts_0je3xkv._.js +1 -1
  107. package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
  108. package/.next/standalone/.next/server/pages/404.html +1 -1
  109. package/.next/standalone/.next/server/pages/500.html +1 -1
  110. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  111. package/.next/standalone/.next/server/server-reference-manifest.json +22 -22
  112. package/.next/standalone/.next/static/chunks/{1pb1oztsbwcss.js → 07c6l1lq5_69b.js} +1 -1
  113. package/.next/standalone/.next/static/chunks/{0o-hh5_turzlz.css → 0jpd8dv2vk930.css} +1 -1
  114. package/.next/standalone/.next/static/chunks/{32spub4wqjem-.js → 12bsgz8czvcnn.js} +1 -1
  115. package/.next/standalone/.next/static/chunks/{3m4upvybtrexd.js → 1gn08w2pgqh09.js} +1 -1
  116. package/.next/standalone/.next/static/chunks/{010bv1w6j171t.js → 1xgq22tri86an.js} +1 -1
  117. package/.next/standalone/.next/static/chunks/{2aquitk72k2op.js → 20xkiqzvfkuvm.js} +1 -1
  118. package/.next/standalone/.next/static/chunks/{2bi_1y0a_smt7.js → 2a84ug32tzik2.js} +1 -1
  119. package/.next/standalone/.next/static/chunks/{2ej3b8gk5ittu.js → 32m2ryfankf_2.js} +1 -1
  120. package/.next/standalone/.next/static/chunks/3ioub_lpen-sq.js +1 -0
  121. package/.next/standalone/.next/static/chunks/{0wz8yftk18ts2.js → 3jxd133cw2vm3.js} +1 -1
  122. package/.next/standalone/.next/static/chunks/44ncu88eq6z71.js +1 -0
  123. package/.next/standalone/app/actions/get-leaks.ts +5 -1
  124. package/.next/standalone/app/actions/update-scheduled-audit.ts +4 -56
  125. package/.next/standalone/app/api/auth/status/route.ts +3 -2
  126. package/.next/standalone/app/audit/_components/audit-dashboard.tsx +29 -2
  127. package/.next/standalone/app/audit/_components/leak-section.tsx +15 -2
  128. package/.next/standalone/app/audit/audit-styles.css +18 -0
  129. package/.next/standalone/app/settings/page.tsx +1 -1
  130. package/.next/standalone/app/settings/settings-client.tsx +13 -39
  131. package/.next/standalone/lib/auth/api-server-client.ts +6 -6
  132. package/.next/standalone/lib/codex-sessions.ts +20 -4
  133. package/.next/standalone/lib/copilot-sessions.ts +32 -1
  134. package/.next/standalone/lib/cursor-sessions.ts +62 -5
  135. package/.next/standalone/lib/sqlite-reader.ts +78 -1
  136. package/.next/standalone/package.json +10 -10
  137. package/.next/standalone/server.js +1 -1
  138. package/bin/failproofai.mjs +1 -1
  139. package/dist/cli.mjs +1191 -1130
  140. package/dist/worker.mjs +198 -359
  141. package/lib/auth/api-server-client.ts +6 -6
  142. package/lib/codex-sessions.ts +20 -4
  143. package/lib/copilot-sessions.ts +32 -1
  144. package/lib/cursor-sessions.ts +62 -5
  145. package/lib/sqlite-reader.ts +78 -1
  146. package/package.json +10 -10
  147. package/pi-extension/index.ts +11 -4
  148. package/src/audit/cache.ts +6 -0
  149. package/src/audit/cli-adapters/claude.ts +13 -0
  150. package/src/audit/cli-login.ts +4 -1
  151. package/src/audit/cli.ts +67 -51
  152. package/src/audit/harm-report.ts +12 -6
  153. package/src/audit/index.ts +151 -8
  154. package/src/audit/leak-fingerprint.ts +2 -4
  155. package/src/audit/leak-record.ts +13 -9
  156. package/src/audit/leak-scan.ts +20 -44
  157. package/src/audit/leak-store.ts +5 -2
  158. package/src/audit/machine-store.ts +8 -9
  159. package/src/audit/macos-notifier.ts +2 -2
  160. package/src/audit/redact-example.ts +62 -5
  161. package/src/audit/report-harm.ts +31 -46
  162. package/src/audit/schedule-cli.ts +17 -33
  163. package/src/audit/types.ts +11 -0
  164. package/src/hooks/configure-wizard.ts +28 -0
  165. package/src/hooks/fp-config.ts +29 -54
  166. package/src/hooks/handler.ts +1 -59
  167. package/src/hooks/integrations.ts +4 -1
  168. package/src/hooks/notice.ts +23 -154
  169. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0rgu2r3._.js +0 -3
  170. package/.next/standalone/.next/server/chunks/ssr/_0-oij9d._.js +0 -23
  171. package/.next/standalone/.next/static/chunks/04r6ch8uf_n8m.js +0 -1
  172. package/.next/standalone/.next/static/chunks/0zebh1n9jkfbt.js +0 -1
  173. package/src/audit/leak-notice.ts +0 -161
  174. /package/.next/standalone/.next/static/{aKNv4Kmv98Xpwns0Xa-C- → aeM365dNTtUZOZvNkX8ba}/_buildManifest.js +0 -0
  175. /package/.next/standalone/.next/static/{aKNv4Kmv98Xpwns0Xa-C- → aeM365dNTtUZOZvNkX8ba}/_clientMiddlewareManifest.js +0 -0
  176. /package/.next/standalone/.next/static/{aKNv4Kmv98Xpwns0Xa-C- → aeM365dNTtUZOZvNkX8ba}/_ssgManifest.js +0 -0
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.2", 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",
@@ -150,20 +150,20 @@ var init_package = __esm(() => {
150
150
  vite: "8.0.16",
151
151
  undici: "7.29.0",
152
152
  "brace-expansion": "5.0.9",
153
- sharp: "0.35.0",
153
+ sharp: "0.35.4",
154
154
  browserslist: "4.28.8"
155
155
  },
156
156
  optionalDependencies: {
157
- "@failproofai/failproofaid-linux-x64": "1.0.4-beta.2",
158
- "@failproofai/failproofaid-linux-arm64": "1.0.4-beta.2",
159
- "@failproofai/failproofaid-darwin-x64": "1.0.4-beta.2",
160
- "@failproofai/failproofaid-darwin-arm64": "1.0.4-beta.2"
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": "3039575242ff240c68a79c4ebd4e0e35e865da99c6d8a46d1a17b2d7962cb47b",
164
- "linux-arm64": "02fe993dca0faccb528c48472ca1d637274c562992ba7da1bc8d439103dbcc13",
165
- "darwin-x64": "2be5a422007a773253611f24f2ad9e2a301f075392ed7bc2dc0f6354d3186696",
166
- "darwin-arm64": "5882a4acd7317289346934290ac8277ca79edadb009e284c9fc0b23b74d321d7"
163
+ "linux-x64": "24118b8bd058cc5d8711053c4c77cdca9361c12dbf0f421a757d33f07596d428",
164
+ "linux-arm64": "b4278c34a288de2c747bcebcc623d8fd5bda3a1f1e55800926eb1a4b89f0a5e9",
165
+ "darwin-x64": "ecb66699f45f605b0d54ac9e4bac360ac11e4e136442dcccdd083514d77c7d42",
166
+ "darwin-arm64": "b3dbad58bda960ef9481f90bc5085ba8624b2472519cc0bf212a0e8451dd2db4"
167
167
  }
168
168
  };
169
169
  });
@@ -11865,7 +11865,10 @@ export default async function failproofaiPlugin({ client, directory }) {
11865
11865
  const claudeEvent = BUS_EVENT_MAP[event.type];
11866
11866
  if (!claudeEvent) return;
11867
11867
  const props = event.properties || {};
11868
- 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;
11869
11872
  const r = await runFailproofai(claudeEvent, {
11870
11873
  session_id: sessionID, cwd: directory, hook_event_name: claudeEvent,
11871
11874
  }, directory);
@@ -16480,374 +16483,6 @@ var init_delivery_health = __esm(() => {
16480
16483
  };
16481
16484
  });
16482
16485
 
16483
- // src/hooks/notice.ts
16484
- function shapeNotice(cli, notice, existingStdout = "") {
16485
- const empty = { stdout: existingStdout, stderr: "" };
16486
- if (!notice.trim() || !cli)
16487
- return empty;
16488
- const channel = NOTICE_CHANNEL[cli] ?? "none";
16489
- const text = notice.length > MAX_NOTICE_CHARS ? notice.slice(0, MAX_NOTICE_CHARS - 1) + "…" : notice;
16490
- switch (channel) {
16491
- case "systemMessage": {
16492
- if (existingStdout.trim().startsWith("{")) {
16493
- try {
16494
- const parsed = JSON.parse(existingStdout);
16495
- parsed.systemMessage = text;
16496
- return { stdout: JSON.stringify(parsed), stderr: "" };
16497
- } catch {
16498
- return empty;
16499
- }
16500
- }
16501
- if (existingStdout.trim())
16502
- return empty;
16503
- return { stdout: JSON.stringify({ systemMessage: text }), stderr: "" };
16504
- }
16505
- case "stderr":
16506
- return { stdout: existingStdout, stderr: text + `
16507
- ` };
16508
- case "stdout":
16509
- if (existingStdout.trim())
16510
- return empty;
16511
- return { stdout: text + `
16512
- `, stderr: "" };
16513
- default:
16514
- return empty;
16515
- }
16516
- }
16517
- function canDeliverNotice(cli) {
16518
- return !!cli && (NOTICE_CHANNEL[cli] ?? "none") !== "none";
16519
- }
16520
- function leakNoticeText(newFindings) {
16521
- const n = newFindings === 1 ? "a credential" : `${newFindings} credentials`;
16522
- return `failproofai found ${n} in this project's agent transcripts.
16523
- ` + "Run `failproofai audit` to see the details, " + "or `failproofai audit --schedule` to get these by email.";
16524
- }
16525
- var NOTICE_CHANNEL, MAX_NOTICE_CHARS = 900;
16526
- var init_notice = __esm(() => {
16527
- NOTICE_CHANNEL = {
16528
- claude: "systemMessage",
16529
- codex: "systemMessage",
16530
- copilot: "stderr",
16531
- factory: "stdout"
16532
- };
16533
- });
16534
-
16535
- // lib/atomic-write.ts
16536
- import {
16537
- chmodSync as chmodSync2,
16538
- existsSync as existsSync11,
16539
- mkdirSync as mkdirSync7,
16540
- renameSync as renameSync4,
16541
- rmSync as rmSync3,
16542
- statSync as statSync7,
16543
- writeFileSync as writeFileSync6
16544
- } from "node:fs";
16545
- import { dirname as dirname7 } from "node:path";
16546
- import { randomBytes } from "node:crypto";
16547
- function writeJsonAtomically(filePath, value, opts = {}) {
16548
- const mode = opts.mode ?? 384;
16549
- const dirMode = opts.dirMode ?? 448;
16550
- const dir = dirname7(filePath);
16551
- if (!existsSync11(dir))
16552
- mkdirSync7(dir, { recursive: true, mode: dirMode });
16553
- const tmp = `${filePath}.${process.pid}.${randomBytes(6).toString("hex")}.tmp`;
16554
- try {
16555
- writeFileSync6(tmp, JSON.stringify(value, null, 2), { mode });
16556
- try {
16557
- if ((statSync7(tmp).mode & 63) !== 0)
16558
- chmodSync2(tmp, mode);
16559
- } catch {}
16560
- renameSync4(tmp, filePath);
16561
- try {
16562
- if ((statSync7(filePath).mode & 63) !== 0)
16563
- chmodSync2(filePath, mode);
16564
- } catch {}
16565
- } catch (err) {
16566
- try {
16567
- rmSync3(tmp, { force: true });
16568
- } catch {}
16569
- throw err;
16570
- }
16571
- }
16572
- var init_atomic_write = () => {};
16573
-
16574
- // src/audit/leak-record.ts
16575
- function upsertFinding(record, incoming) {
16576
- const { sighting, ...rest } = incoming;
16577
- const existing = record.findings.find((f) => f.id === rest.id);
16578
- if (!existing) {
16579
- record.findings.push({
16580
- ...rest,
16581
- firstSeen: sighting.at,
16582
- lastSeen: sighting.at,
16583
- occurrences: 1,
16584
- sightings: [sighting]
16585
- });
16586
- return { record, isNew: true };
16587
- }
16588
- existing.occurrences += 1;
16589
- if (sighting.at > existing.lastSeen)
16590
- existing.lastSeen = sighting.at;
16591
- if (sighting.at < existing.firstSeen)
16592
- existing.firstSeen = sighting.at;
16593
- if (existing.sightings.length < MAX_SIGHTINGS) {
16594
- const seen = existing.sightings.some((s) => s.sessionId === sighting.sessionId && s.at === sighting.at);
16595
- if (!seen)
16596
- existing.sightings.push(sighting);
16597
- }
16598
- return { record, isNew: false };
16599
- }
16600
- function pruneRecord(record, nowMs) {
16601
- const cutoff = new Date(nowMs - FINDING_TTL_DAYS * 86400000).toISOString();
16602
- const live = record.findings.filter((f) => f.lastSeen >= cutoff);
16603
- live.sort((a, b) => a.lastSeen < b.lastSeen ? 1 : a.lastSeen > b.lastSeen ? -1 : 0);
16604
- record.findings = live.slice(0, MAX_FINDINGS);
16605
- return record;
16606
- }
16607
- function emptyRecord(salt, nowIso) {
16608
- return {
16609
- schemaVersion: LEAK_RECORD_SCHEMA_VERSION,
16610
- salt,
16611
- updatedAt: nowIso,
16612
- findings: []
16613
- };
16614
- }
16615
- function describeMechanism(toolName, direction, shortPath) {
16616
- const where = shortPath ? ` ${shortPath}` : "";
16617
- let summary;
16618
- if (direction === "result") {
16619
- summary = shortPath ? `appeared in the output of reading${where}` : "appeared in tool output";
16620
- } else {
16621
- switch (toolName) {
16622
- case "Read":
16623
- summary = `read from${where || " a file"}`;
16624
- break;
16625
- case "Write":
16626
- summary = `written to${where || " a file"}`;
16627
- break;
16628
- case "Edit":
16629
- case "NotebookEdit":
16630
- summary = `edited into${where || " a file"}`;
16631
- break;
16632
- case "Bash":
16633
- summary = "passed in a shell command";
16634
- break;
16635
- default:
16636
- summary = `sent to the ${toolName} tool`;
16637
- }
16638
- }
16639
- return { summary, toolName, direction };
16640
- }
16641
- var MAX_SIGHTINGS = 5, FINDING_TTL_DAYS = 90, MAX_FINDINGS = 500, LEAK_RECORD_SCHEMA_VERSION = 1;
16642
-
16643
- // src/audit/leak-fingerprint.ts
16644
- function matchPublicPrefix(value) {
16645
- for (const entry of PUBLIC_PREFIXES) {
16646
- if (value.startsWith(entry[0]))
16647
- return entry;
16648
- }
16649
- return null;
16650
- }
16651
- function fingerprintSecret(value, fallbackLabel = "secret") {
16652
- const length = value.length;
16653
- const matched = matchPublicPrefix(value);
16654
- if (!matched) {
16655
- return {
16656
- display: `[${length}-char ${fallbackLabel}]`,
16657
- label: fallbackLabel,
16658
- length,
16659
- attributed: false
16660
- };
16661
- }
16662
- const [prefix, label] = matched;
16663
- const bodyLength = length - prefix.length;
16664
- const run = MASK_CHAR.repeat(Math.max(1, Math.min(MAX_MASK_RUN, bodyLength)));
16665
- if (length >= MIN_LEN_FOR_TAIL && bodyLength > TAIL_CHARS * 2) {
16666
- return {
16667
- display: `${prefix}${run}${value.slice(-TAIL_CHARS)}`,
16668
- label,
16669
- length,
16670
- attributed: true
16671
- };
16672
- }
16673
- return { display: `${prefix}${run}`, label, length, attributed: true };
16674
- }
16675
- function isFindingId(id) {
16676
- return /^[0-9a-f]{16}$/.test(id);
16677
- }
16678
- function fingerprintId(value, machineSalt) {
16679
- const { createHmac } = __require("node:crypto");
16680
- return createHmac("sha256", machineSalt).update(value).digest("hex").slice(0, 16);
16681
- }
16682
- var MASK_CHAR = "•", MAX_MASK_RUN = 8, MIN_LEN_FOR_TAIL = 24, TAIL_CHARS = 4, PUBLIC_PREFIXES;
16683
- var init_leak_fingerprint = __esm(() => {
16684
- PUBLIC_PREFIXES = [
16685
- ["sk-ant-api03-", "Anthropic API key"],
16686
- ["sk-ant-oat01-", "Anthropic OAuth token"],
16687
- ["sk-ant-", "Anthropic key"],
16688
- ["sk-proj-", "OpenAI project key"],
16689
- ["sk-svcacct-", "OpenAI service-account key"],
16690
- ["sk-admin-", "OpenAI admin key"],
16691
- ["sk-or-v1-", "OpenRouter key"],
16692
- ["github_pat_", "GitHub fine-grained token"],
16693
- ["ghp_", "GitHub personal access token"],
16694
- ["gho_", "GitHub OAuth token"],
16695
- ["ghu_", "GitHub user-to-server token"],
16696
- ["ghs_", "GitHub server-to-server token"],
16697
- ["ghr_", "GitHub refresh token"],
16698
- ["glpat-", "GitLab personal access token"],
16699
- ["xoxb-", "Slack bot token"],
16700
- ["xoxp-", "Slack user token"],
16701
- ["xapp-", "Slack app-level token"],
16702
- ["sk_live_", "Stripe live secret key"],
16703
- ["sk_test_", "Stripe test secret key"],
16704
- ["rk_live_", "Stripe restricted key"],
16705
- ["AKIA", "AWS access key ID"],
16706
- ["ASIA", "AWS temporary access key ID"],
16707
- ["AIza", "Google API key"],
16708
- ["hf_", "Hugging Face token"],
16709
- ["gsk_", "Groq API key"],
16710
- ["r8_", "Replicate token"],
16711
- ["xai-", "xAI key"],
16712
- ["npm_", "npm access token"],
16713
- ["dop_v1_", "DigitalOcean token"],
16714
- ["shpat_", "Shopify access token"],
16715
- ["sbp_", "Supabase token"]
16716
- ];
16717
- });
16718
-
16719
- // src/audit/leak-store.ts
16720
- import { randomBytes as randomBytes2 } from "node:crypto";
16721
- import { existsSync as existsSync12, mkdirSync as mkdirSync8, readFileSync as readFileSync8 } from "node:fs";
16722
- import { dirname as dirname8 } from "node:path";
16723
- function readJson(path) {
16724
- try {
16725
- if (!existsSync12(path))
16726
- return null;
16727
- return JSON.parse(readFileSync8(path, "utf8"));
16728
- } catch {
16729
- return null;
16730
- }
16731
- }
16732
- function readLeakIdentity(home) {
16733
- const existing = readJson(auditLeakIdentityFile(home));
16734
- if (existing && typeof existing.salt === "string" && existing.salt.length >= 32) {
16735
- return { salt: existing.salt, dismissed: existing.dismissed ?? [] };
16736
- }
16737
- const minted = { salt: randomBytes2(32).toString("hex"), dismissed: [] };
16738
- writeLeakIdentity(minted, home);
16739
- return minted;
16740
- }
16741
- function writeLeakIdentity(identity, home) {
16742
- const path = auditLeakIdentityFile(home);
16743
- try {
16744
- mkdirSync8(dirname8(path), { recursive: true });
16745
- writeJsonAtomically(path, identity, { mode: FILE_MODE });
16746
- return true;
16747
- } catch {
16748
- return false;
16749
- }
16750
- }
16751
- function sanitizeFinding(raw) {
16752
- if (!raw || typeof raw !== "object" || Array.isArray(raw))
16753
- return null;
16754
- const f = raw;
16755
- if (typeof f.id !== "string" || !isFindingId(f.id))
16756
- return null;
16757
- const fp = f.fingerprint;
16758
- if (!fp || typeof fp !== "object" || typeof fp.display !== "string" || typeof fp.label !== "string") {
16759
- return null;
16760
- }
16761
- const sightings = Array.isArray(f.sightings) ? f.sightings.filter((s) => {
16762
- if (!s || typeof s !== "object")
16763
- return false;
16764
- const m = s.mechanism;
16765
- return !!m && typeof m === "object" && typeof m.summary === "string";
16766
- }) : [];
16767
- return {
16768
- ...f,
16769
- fingerprint: {
16770
- display: fp.display,
16771
- label: fp.label,
16772
- length: typeof fp.length === "number" && Number.isFinite(fp.length) ? fp.length : 0,
16773
- attributed: fp.attributed === true
16774
- },
16775
- name: typeof f.name === "string" ? f.name : null,
16776
- firstSeen: typeof f.firstSeen === "string" ? f.firstSeen : "",
16777
- lastSeen: typeof f.lastSeen === "string" ? f.lastSeen : "",
16778
- occurrences: typeof f.occurrences === "number" && Number.isFinite(f.occurrences) ? f.occurrences : sightings.length,
16779
- sightings
16780
- };
16781
- }
16782
- function readLeakRecord(home) {
16783
- const identity = readLeakIdentity(home);
16784
- const raw = readJson(auditLeaksFile(home));
16785
- if (!raw || raw.schemaVersion !== LEAK_RECORD_SCHEMA_VERSION || !Array.isArray(raw.findings)) {
16786
- return emptyRecord(identity.salt, new Date().toISOString());
16787
- }
16788
- const findings = raw.findings.map(sanitizeFinding).filter((f) => f !== null);
16789
- return { ...raw, findings, salt: identity.salt };
16790
- }
16791
- function writeLeakRecord(record, home, nowMs = Date.now()) {
16792
- const path = auditLeaksFile(home);
16793
- try {
16794
- mkdirSync8(dirname8(path), { recursive: true });
16795
- const pruned = pruneRecord(record, nowMs);
16796
- pruned.updatedAt = new Date(nowMs).toISOString();
16797
- writeJsonAtomically(path, pruned, { mode: FILE_MODE });
16798
- return true;
16799
- } catch {
16800
- return false;
16801
- }
16802
- }
16803
- function activeFindings(record, home) {
16804
- const dismissed = new Set(readLeakIdentity(home).dismissed);
16805
- return record.findings.filter((f) => !dismissed.has(f.id)).sort((a, b) => a.lastSeen < b.lastSeen ? 1 : a.lastSeen > b.lastSeen ? -1 : 0);
16806
- }
16807
- var FILE_MODE = 384;
16808
- var init_leak_store = __esm(() => {
16809
- init_fp_home();
16810
- init_atomic_write();
16811
- init_leak_fingerprint();
16812
- });
16813
-
16814
- // src/audit/leak-notice.ts
16815
- import { existsSync as existsSync13, mkdirSync as mkdirSync9, readdirSync as readdirSync5, statSync as statSync8, writeFileSync as writeFileSync7, rmSync as rmSync4 } from "node:fs";
16816
- import { resolve as resolve11 } from "node:path";
16817
- function pendingLeakNotice(home, channel = "cli") {
16818
- try {
16819
- const dir = NOTICE_DIR(home, channel);
16820
- const claimed = new Set(existsSync13(dir) ? readdirSync5(dir) : []);
16821
- const ids = activeFindings(readLeakRecord(home), home).map((f) => f.id).filter((id) => !claimed.has(id));
16822
- return { ids, count: ids.length };
16823
- } catch {
16824
- return { ids: [], count: 0 };
16825
- }
16826
- }
16827
- function markLeakNoticeDelivered(ids, home, channel = "cli") {
16828
- const won = [];
16829
- try {
16830
- const dir = NOTICE_DIR(home, channel);
16831
- mkdirSync9(dir, { recursive: true });
16832
- for (const id of ids) {
16833
- if (!isFindingId(id))
16834
- continue;
16835
- try {
16836
- writeFileSync7(resolve11(dir, id), "", { flag: "wx", mode: 384 });
16837
- won.push(id);
16838
- } catch {}
16839
- }
16840
- } catch {}
16841
- return won;
16842
- }
16843
- var NOTICE_DIR = (home, channel = "cli") => resolve11(auditDir(home), channel === "cli" ? "notified" : `notified-${channel}`), MARKER_TTL_MS;
16844
- var init_leak_notice = __esm(() => {
16845
- init_fp_home();
16846
- init_leak_store();
16847
- init_leak_fingerprint();
16848
- MARKER_TTL_MS = 120 * 86400000;
16849
- });
16850
-
16851
16486
  // src/hooks/resolve-cwd.ts
16852
16487
  function resolveCwd(integration, parsed) {
16853
16488
  const direct = typeof parsed.cwd === "string" && parsed.cwd.length > 0 ? parsed.cwd : undefined;
@@ -17540,10 +17175,23 @@ var init_cursor_projects = __esm(() => {
17540
17175
  });
17541
17176
 
17542
17177
  // lib/sqlite-reader.ts
17543
- import { existsSync as existsSync14, readFileSync as readFileSync9 } from "node:fs";
17178
+ import { existsSync as existsSync11, readFileSync as readFileSync8 } from "node:fs";
17544
17179
  import initSqlJs from "sql.js/dist/sql-asm.js";
17180
+ function silenceSqliteExperimentalWarning() {
17181
+ if (warningPatched)
17182
+ return;
17183
+ warningPatched = true;
17184
+ const original = process.emitWarning.bind(process);
17185
+ process.emitWarning = (warning, ...rest) => {
17186
+ const text = typeof warning === "string" ? warning : String(warning?.message ?? "");
17187
+ if (text.includes("SQLite is an experimental feature"))
17188
+ return;
17189
+ return original(warning, ...rest);
17190
+ };
17191
+ }
17545
17192
  async function tryNodeSqlite(dbPath) {
17546
17193
  try {
17194
+ silenceSqliteExperimentalWarning();
17547
17195
  const mod = await import("node:sqlite");
17548
17196
  const db = new mod.DatabaseSync(dbPath, { readOnly: true });
17549
17197
  return {
@@ -17564,10 +17212,21 @@ function loadSqlJs() {
17564
17212
  sqlPromise = initSqlJs();
17565
17213
  return sqlPromise;
17566
17214
  }
17215
+ function clearWalFlag(bytes) {
17216
+ if (bytes.length < 20)
17217
+ return bytes;
17218
+ if (bytes.toString("latin1", 0, 16) !== SQLITE_MAGIC)
17219
+ return bytes;
17220
+ if (bytes[18] === 1 && bytes[19] === 1)
17221
+ return bytes;
17222
+ bytes[18] = 1;
17223
+ bytes[19] = 1;
17224
+ return bytes;
17225
+ }
17567
17226
  async function trySqlJs(dbPath) {
17568
17227
  try {
17569
17228
  const SQL = await loadSqlJs();
17570
- const db = new SQL.Database(readFileSync9(dbPath));
17229
+ const db = new SQL.Database(clearWalFlag(readFileSync8(dbPath)));
17571
17230
  return {
17572
17231
  query(sql, params) {
17573
17232
  const stmt = db.prepare(sql);
@@ -17591,11 +17250,11 @@ async function trySqlJs(dbPath) {
17591
17250
  }
17592
17251
  }
17593
17252
  async function openSqliteReadonly(dbPath) {
17594
- if (!existsSync14(dbPath))
17253
+ if (!existsSync11(dbPath))
17595
17254
  return null;
17596
17255
  return await tryNodeSqlite(dbPath) ?? await trySqlJs(dbPath);
17597
17256
  }
17598
- var sqlPromise = null;
17257
+ var warningPatched = false, sqlPromise = null, SQLITE_MAGIC = "SQLite format 3\x00";
17599
17258
  var init_sqlite_reader = () => {};
17600
17259
 
17601
17260
  // lib/opencode-db.ts
@@ -18248,7 +17907,7 @@ var init_hermes_projects = __esm(() => {
18248
17907
 
18249
17908
  // lib/openclaw-sessions.ts
18250
17909
  import { readFile as readFile7 } from "node:fs/promises";
18251
- import { readdirSync as readdirSync6, statSync as statSync9 } from "node:fs";
17910
+ import { readdirSync as readdirSync5, statSync as statSync7 } from "node:fs";
18252
17911
  import { homedir as homedir12 } from "node:os";
18253
17912
  import { join as join14 } from "node:path";
18254
17913
  function openclawHome() {
@@ -18367,7 +18026,7 @@ function openclawLinesToLogEntries(lines, source = "session") {
18367
18026
  }
18368
18027
  function listOpenClawAgents() {
18369
18028
  try {
18370
- 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();
18371
18030
  } catch {
18372
18031
  return [];
18373
18032
  }
@@ -18377,7 +18036,7 @@ function listOpenClawTranscripts() {
18377
18036
  const out = [];
18378
18037
  let agentIds;
18379
18038
  try {
18380
- 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);
18381
18040
  } catch {
18382
18041
  return out;
18383
18042
  }
@@ -18385,7 +18044,7 @@ function listOpenClawTranscripts() {
18385
18044
  const sessionsDir = join14(agentsDir, agentId, "sessions");
18386
18045
  let files;
18387
18046
  try {
18388
- files = readdirSync6(sessionsDir);
18047
+ files = readdirSync5(sessionsDir);
18389
18048
  } catch {
18390
18049
  continue;
18391
18050
  }
@@ -18397,7 +18056,7 @@ function listOpenClawTranscripts() {
18397
18056
  continue;
18398
18057
  const transcriptPath = join14(sessionsDir, file);
18399
18058
  try {
18400
- const st = statSync9(transcriptPath);
18059
+ const st = statSync7(transcriptPath);
18401
18060
  out.push({ agentId, sessionId, transcriptPath, mtimeMs: st.mtimeMs, sizeBytes: st.size });
18402
18061
  } catch {}
18403
18062
  }
@@ -18448,7 +18107,7 @@ __export(exports_openclaw_projects, {
18448
18107
  getOpenClawSessions: () => getOpenClawSessions,
18449
18108
  openClawProjectPath: () => openClawProjectPath
18450
18109
  });
18451
- import { readFileSync as readFileSync10 } from "node:fs";
18110
+ import { readFileSync as readFileSync9 } from "node:fs";
18452
18111
  import { join as join15 } from "node:path";
18453
18112
  function str(v) {
18454
18113
  return typeof v === "string" && v.length > 0 ? v : undefined;
@@ -18458,7 +18117,7 @@ function readSessionsIndex(agentId) {
18458
18117
  const indexPath = join15(openclawHome(), "agents", agentId, "sessions", "sessions.json");
18459
18118
  let raw;
18460
18119
  try {
18461
- raw = JSON.parse(readFileSync10(indexPath, "utf-8"));
18120
+ raw = JSON.parse(readFileSync9(indexPath, "utf-8"));
18462
18121
  } catch {
18463
18122
  return out;
18464
18123
  }
@@ -18607,7 +18266,7 @@ var init_openclaw_projects = __esm(() => {
18607
18266
 
18608
18267
  // lib/factory-sessions.ts
18609
18268
  import { readFile as readFile8 } from "node:fs/promises";
18610
- import { readdirSync as readdirSync7, statSync as statSync10 } from "node:fs";
18269
+ import { readdirSync as readdirSync6, statSync as statSync8 } from "node:fs";
18611
18270
  import { homedir as homedir13 } from "node:os";
18612
18271
  import { join as join16 } from "node:path";
18613
18272
  function factoryHome() {
@@ -18753,7 +18412,7 @@ function listFactoryTranscripts() {
18753
18412
  const out = [];
18754
18413
  let projectDirs;
18755
18414
  try {
18756
- projectDirs = readdirSync7(root, { withFileTypes: true }).filter((d) => d.isDirectory());
18415
+ projectDirs = readdirSync6(root, { withFileTypes: true }).filter((d) => d.isDirectory());
18757
18416
  } catch {
18758
18417
  return out;
18759
18418
  }
@@ -18763,7 +18422,7 @@ function listFactoryTranscripts() {
18763
18422
  const projectPath = join16(root, projectName);
18764
18423
  let files;
18765
18424
  try {
18766
- files = readdirSync7(projectPath);
18425
+ files = readdirSync6(projectPath);
18767
18426
  } catch {
18768
18427
  continue;
18769
18428
  }
@@ -18775,7 +18434,7 @@ function listFactoryTranscripts() {
18775
18434
  continue;
18776
18435
  const transcriptPath = join16(projectPath, file);
18777
18436
  try {
18778
- const st = statSync10(transcriptPath);
18437
+ const st = statSync8(transcriptPath);
18779
18438
  out.push({ projectName, cwd, sessionId, transcriptPath, mtimeMs: st.mtimeMs, sizeBytes: st.size });
18780
18439
  } catch {}
18781
18440
  }
@@ -19195,7 +18854,7 @@ var init_devin_projects = __esm(() => {
19195
18854
 
19196
18855
  // lib/antigravity-sessions.ts
19197
18856
  import { readFile as readFile9 } from "node:fs/promises";
19198
- import { readdirSync as readdirSync8, statSync as statSync11 } from "node:fs";
18857
+ import { readdirSync as readdirSync7, statSync as statSync9 } from "node:fs";
19199
18858
  import { homedir as homedir15 } from "node:os";
19200
18859
  import { join as join18 } from "node:path";
19201
18860
  function antigravityHome() {
@@ -19320,7 +18979,7 @@ function listAntigravityTranscripts() {
19320
18979
  const out = [];
19321
18980
  let convoDirs;
19322
18981
  try {
19323
- convoDirs = readdirSync8(root, { withFileTypes: true }).filter((d) => d.isDirectory());
18982
+ convoDirs = readdirSync7(root, { withFileTypes: true }).filter((d) => d.isDirectory());
19324
18983
  } catch {
19325
18984
  return out;
19326
18985
  }
@@ -19330,7 +18989,7 @@ function listAntigravityTranscripts() {
19330
18989
  continue;
19331
18990
  const transcriptPath = join18(root, conversationId, rel);
19332
18991
  try {
19333
- const st = statSync11(transcriptPath);
18992
+ const st = statSync9(transcriptPath);
19334
18993
  if (!st.isFile())
19335
18994
  continue;
19336
18995
  out.push({ conversationId, transcriptPath, mtimeMs: st.mtimeMs, sizeBytes: st.size });
@@ -19343,7 +19002,7 @@ function findAntigravityTranscript(conversationId) {
19343
19002
  return null;
19344
19003
  const transcriptPath = join18(antigravityBrainRoot(), conversationId, antigravityTranscriptRelPath());
19345
19004
  try {
19346
- if (statSync11(transcriptPath).isFile())
19005
+ if (statSync9(transcriptPath).isFile())
19347
19006
  return transcriptPath;
19348
19007
  } catch {}
19349
19008
  return null;
@@ -19795,7 +19454,7 @@ var init_goose_projects = __esm(() => {
19795
19454
 
19796
19455
  // lib/projects.ts
19797
19456
  import { readdir as readdir5, stat as stat4 } from "node:fs/promises";
19798
- import { join as join21, resolve as resolve12, sep } from "node:path";
19457
+ import { join as join21, resolve as resolve11, sep } from "node:path";
19799
19458
  async function getMtime(path, label) {
19800
19459
  try {
19801
19460
  return (await stat4(path)).mtime;
@@ -19947,8 +19606,8 @@ function resolveProjectPath(projectName) {
19947
19606
  throw new RangeError("Empty project name");
19948
19607
  if (/^[/\\]/.test(projectName))
19949
19608
  throw new RangeError("Absolute project name");
19950
- const projectsPath = resolve12(getClaudeProjectsPath());
19951
- const candidate = resolve12(join21(projectsPath, projectName));
19609
+ const projectsPath = resolve11(getClaudeProjectsPath());
19610
+ const candidate = resolve11(join21(projectsPath, projectName));
19952
19611
  if (!candidate.startsWith(projectsPath + sep)) {
19953
19612
  throw new RangeError("Project path escapes root");
19954
19613
  }
@@ -20258,30 +19917,30 @@ var init_log_entries = __esm(() => {
20258
19917
  });
20259
19918
 
20260
19919
  // lib/codex-sessions.ts
20261
- 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";
20262
19921
  import { readFile as readFile11 } from "node:fs/promises";
20263
- import { dirname as dirname9, join as join24 } from "node:path";
19922
+ import { dirname as dirname7, join as join24 } from "node:path";
20264
19923
  import { homedir as homedir17 } from "node:os";
20265
19924
  function readCache() {
20266
19925
  try {
20267
- if (!existsSync15(CACHE_PATH))
19926
+ if (!existsSync12(CACHE_PATH))
20268
19927
  return {};
20269
- return JSON.parse(readFileSync11(CACHE_PATH, "utf-8"));
19928
+ return JSON.parse(readFileSync10(CACHE_PATH, "utf-8"));
20270
19929
  } catch {
20271
19930
  return {};
20272
19931
  }
20273
19932
  }
20274
19933
  function writeCacheEntry(sessionId, path) {
20275
19934
  try {
20276
- mkdirSync10(dirname9(CACHE_PATH), { recursive: true });
19935
+ mkdirSync7(dirname7(CACHE_PATH), { recursive: true });
20277
19936
  const cache = readCache();
20278
19937
  cache[sessionId] = path;
20279
- writeFileSync8(CACHE_PATH, JSON.stringify(cache), "utf-8");
19938
+ writeFileSync6(CACHE_PATH, JSON.stringify(cache), "utf-8");
20280
19939
  } catch {}
20281
19940
  }
20282
19941
  function dirSearch(dir, sessionId) {
20283
19942
  try {
20284
- for (const f of readdirSync9(dir, { withFileTypes: true })) {
19943
+ for (const f of readdirSync8(dir, { withFileTypes: true })) {
20285
19944
  if (f.isFile() && f.name.includes(sessionId) && f.name.endsWith(".jsonl")) {
20286
19945
  return join24(dir, f.name);
20287
19946
  }
@@ -20292,7 +19951,7 @@ function dirSearch(dir, sessionId) {
20292
19951
  function findCodexTranscript(sessionId) {
20293
19952
  const cache = readCache();
20294
19953
  const cached = cache[sessionId];
20295
- if (cached && existsSync15(cached))
19954
+ if (cached && existsSync12(cached))
20296
19955
  return cached;
20297
19956
  const root = join24(homedir17(), ".codex", "sessions");
20298
19957
  const today = new Date;
@@ -20311,13 +19970,13 @@ function findCodexTranscript(sessionId) {
20311
19970
  }
20312
19971
  }
20313
19972
  try {
20314
- for (const y of readdirSync9(root, { withFileTypes: true })) {
19973
+ for (const y of readdirSync8(root, { withFileTypes: true })) {
20315
19974
  if (!y.isDirectory())
20316
19975
  continue;
20317
- for (const m of readdirSync9(join24(root, y.name), { withFileTypes: true })) {
19976
+ for (const m of readdirSync8(join24(root, y.name), { withFileTypes: true })) {
20318
19977
  if (!m.isDirectory())
20319
19978
  continue;
20320
- 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 })) {
20321
19980
  if (!d.isDirectory())
20322
19981
  continue;
20323
19982
  const hit = dirSearch(join24(root, y.name, m.name, d.name), sessionId);
@@ -20346,6 +20005,15 @@ function joinTexts(blocks, wantedType) {
20346
20005
  return blocks.filter((b) => b?.type === wantedType && typeof b.text === "string").map((b) => b.text).join(`
20347
20006
  `);
20348
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
+ }
20349
20017
  async function parseCodexLog(fileContent, source = "session") {
20350
20018
  const lines = fileContent.split(`
20351
20019
  `).filter((line) => line.trim() !== "");
@@ -20422,10 +20090,11 @@ async function parseCodexLog(fileContent, source = "session") {
20422
20090
  });
20423
20091
  continue;
20424
20092
  }
20425
- if (subType === "function_call") {
20093
+ if (subType === "function_call" || subType === "custom_tool_call") {
20426
20094
  const callId = payload.call_id;
20427
20095
  const name = payload.name ?? "function_call";
20428
- const input = safeJsonParse4(payload.arguments);
20096
+ const encodedInput = payload.arguments ?? payload.input;
20097
+ const input = safeJsonParse4(encodedInput);
20429
20098
  const toolUse = {
20430
20099
  type: "tool_use",
20431
20100
  id: callId ?? `${timestamp}-${name}`,
@@ -20444,7 +20113,7 @@ async function parseCodexLog(fileContent, source = "session") {
20444
20113
  }
20445
20114
  continue;
20446
20115
  }
20447
- if (subType === "function_call_output") {
20116
+ if (subType === "function_call_output" || subType === "custom_tool_call_output") {
20448
20117
  const callId = payload.call_id;
20449
20118
  const block = callId ? toolUseById.get(callId) : undefined;
20450
20119
  if (block) {
@@ -20453,7 +20122,7 @@ async function parseCodexLog(fileContent, source = "session") {
20453
20122
  block.result = {
20454
20123
  timestamp,
20455
20124
  timestampFormatted: formatTimestamp(date),
20456
- content: typeof payload.output === "string" ? payload.output : JSON.stringify(payload.output),
20125
+ content: toolOutputText(payload.output),
20457
20126
  durationMs: duration,
20458
20127
  durationFormatted: formatDuration(duration)
20459
20128
  };
@@ -20546,7 +20215,7 @@ var init_codex_sessions = __esm(() => {
20546
20215
  });
20547
20216
 
20548
20217
  // src/hooks/resolve-permission-mode.ts
20549
- import { readFileSync as readFileSync12 } from "node:fs";
20218
+ import { readFileSync as readFileSync11 } from "node:fs";
20550
20219
  function resolvePermissionMode(integration, parsed, sessionId) {
20551
20220
  if (integration === "claude") {
20552
20221
  return parsed.permission_mode ?? "default";
@@ -20561,7 +20230,7 @@ function resolveCodexMode(sessionId) {
20561
20230
  const path = findCodexTranscript(sessionId);
20562
20231
  if (!path)
20563
20232
  return;
20564
- for (const line of readFileSync12(path, "utf-8").split(`
20233
+ for (const line of readFileSync11(path, "utf-8").split(`
20565
20234
  `)) {
20566
20235
  if (!line.includes("turn_context"))
20567
20236
  continue;
@@ -20586,9 +20255,9 @@ var init_resolve_permission_mode = __esm(() => {
20586
20255
  });
20587
20256
 
20588
20257
  // lib/copilot-sessions.ts
20589
- 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";
20590
20259
  import { readFile as readFile12 } from "node:fs/promises";
20591
- 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";
20592
20261
  import { homedir as homedir18 } from "node:os";
20593
20262
  function getCopilotHome() {
20594
20263
  return process.env.COPILOT_HOME || join25(homedir18(), ".copilot");
@@ -20599,8 +20268,8 @@ function getCopilotSessionStateRoot2() {
20599
20268
  function getCopilotSessionDir(sessionId) {
20600
20269
  if (!sessionId)
20601
20270
  return null;
20602
- const root = resolve13(getCopilotSessionStateRoot2());
20603
- const candidate = resolve13(root, sessionId);
20271
+ const root = resolve12(getCopilotSessionStateRoot2());
20272
+ const candidate = resolve12(root, sessionId);
20604
20273
  if (candidate === root || !candidate.startsWith(`${root}${sep2}`))
20605
20274
  return null;
20606
20275
  return candidate;
@@ -20615,17 +20284,17 @@ function findCopilotTranscript(sessionId) {
20615
20284
  const candidate = resolveSessionFile(sessionId, "events.jsonl");
20616
20285
  if (!candidate)
20617
20286
  return null;
20618
- return existsSync16(candidate) ? candidate : null;
20287
+ return existsSync13(candidate) ? candidate : null;
20619
20288
  }
20620
20289
  function findCopilotWorkspace(sessionId) {
20621
20290
  const candidate = resolveSessionFile(sessionId, "workspace.yaml");
20622
20291
  if (!candidate)
20623
20292
  return null;
20624
- return existsSync16(candidate) ? candidate : null;
20293
+ return existsSync13(candidate) ? candidate : null;
20625
20294
  }
20626
20295
  function readYamlScalar(path, key) {
20627
20296
  try {
20628
- const text = readFileSync13(path, "utf-8");
20297
+ const text = readFileSync12(path, "utf-8");
20629
20298
  const re = new RegExp(`^${key}\\s*:\\s*(.+?)\\s*$`, "m");
20630
20299
  const m = text.match(re);
20631
20300
  if (!m)
@@ -20648,6 +20317,8 @@ async function parseCopilotLog(fileContent, source = "session") {
20648
20317
  const rawLines = [];
20649
20318
  const toolUseById = new Map;
20650
20319
  const toolUseStartMs = new Map;
20320
+ let mostRecentToolUse;
20321
+ let mostRecentToolUseStartMs = 0;
20651
20322
  let cwd;
20652
20323
  let seenSessionStart = false;
20653
20324
  for (let i = 0;i < lines.length; i++) {
@@ -20743,8 +20414,24 @@ async function parseCopilotLog(fileContent, source = "session") {
20743
20414
  toolUseById.set(callId, toolUse);
20744
20415
  toolUseStartMs.set(callId, date.getTime());
20745
20416
  }
20417
+ mostRecentToolUse = toolUse;
20418
+ mostRecentToolUseStartMs = date.getTime();
20746
20419
  continue;
20747
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
+ }
20748
20435
  if (recType === "tool.execution_complete") {
20749
20436
  const callId = data.toolCallId;
20750
20437
  const block = callId ? toolUseById.get(callId) : undefined;
@@ -20754,7 +20441,8 @@ async function parseCopilotLog(fileContent, source = "session") {
20754
20441
  const telemetry = data.toolTelemetry ?? {};
20755
20442
  const reportedMs = telemetry.metrics?.commandTimeMs ?? telemetry.metrics?.durationMs ?? null;
20756
20443
  const durationMs = typeof reportedMs === "number" && reportedMs >= 0 ? reportedMs : Math.max(0, date.getTime() - startMs);
20757
- const content = result.detailedContent ?? result.content ?? "";
20444
+ const completionContent = result.detailedContent ?? result.content ?? "";
20445
+ const content = block.result?.content || completionContent;
20758
20446
  block.result = {
20759
20447
  timestamp,
20760
20448
  timestampFormatted: formatTimestamp(date),
@@ -20803,9 +20491,9 @@ var init_copilot_sessions = __esm(() => {
20803
20491
  });
20804
20492
 
20805
20493
  // lib/cursor-sessions.ts
20806
- 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";
20807
20495
  import { readFile as readFile13 } from "node:fs/promises";
20808
- 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";
20809
20497
  import { homedir as homedir19 } from "node:os";
20810
20498
  function getCursorHome2() {
20811
20499
  return process.env.CURSOR_HOME || join26(homedir19(), ".cursor");
@@ -20813,28 +20501,28 @@ function getCursorHome2() {
20813
20501
  function getCursorSessionDir(sessionId) {
20814
20502
  if (!sessionId)
20815
20503
  return null;
20816
- const home = resolve14(getCursorHome2());
20817
- const projectsRoot = resolve14(home, NEW_PROJECTS_DIR2);
20504
+ const home = resolve13(getCursorHome2());
20505
+ const projectsRoot = resolve13(home, NEW_PROJECTS_DIR2);
20818
20506
  let projectEntries = [];
20819
20507
  try {
20820
- projectEntries = readdirSync11(projectsRoot, { withFileTypes: true });
20508
+ projectEntries = readdirSync10(projectsRoot, { withFileTypes: true });
20821
20509
  } catch {}
20822
20510
  for (const entry of projectEntries) {
20823
20511
  if (!entry.isDirectory())
20824
20512
  continue;
20825
- const candidate = resolve14(projectsRoot, entry.name, NEW_AGENT_TRANSCRIPTS_DIR2, sessionId);
20826
- 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);
20827
20515
  if (candidate === transcriptRoot || !candidate.startsWith(`${transcriptRoot}${sep3}`))
20828
20516
  continue;
20829
- if (existsSync17(candidate))
20517
+ if (existsSync14(candidate))
20830
20518
  return candidate;
20831
20519
  }
20832
20520
  for (const sub of LEGACY_SESSION_ROOT_CANDIDATES2) {
20833
- const root = resolve14(home, sub);
20834
- const candidate = resolve14(root, sessionId);
20521
+ const root = resolve13(home, sub);
20522
+ const candidate = resolve13(root, sessionId);
20835
20523
  if (candidate === root || !candidate.startsWith(`${root}${sep3}`))
20836
20524
  continue;
20837
- if (existsSync17(candidate))
20525
+ if (existsSync14(candidate))
20838
20526
  return candidate;
20839
20527
  }
20840
20528
  return null;
@@ -20844,11 +20532,11 @@ function findCursorTranscript(sessionId) {
20844
20532
  if (!dir)
20845
20533
  return null;
20846
20534
  const newCandidate = join26(dir, `${basename3(dir)}.jsonl`);
20847
- if (existsSync17(newCandidate))
20535
+ if (existsSync14(newCandidate))
20848
20536
  return newCandidate;
20849
20537
  for (const name of LEGACY_TRANSCRIPT_FILE_CANDIDATES2) {
20850
20538
  const candidate = join26(dir, name);
20851
- if (existsSync17(candidate))
20539
+ if (existsSync14(candidate))
20852
20540
  return candidate;
20853
20541
  }
20854
20542
  return null;
@@ -20878,8 +20566,27 @@ async function parseCursorLog(fileContent, source = "session") {
20878
20566
  if (!raw.type && raw.role && raw.message?.content) {
20879
20567
  const synthDate = new Date(SYNTH_T0 + i);
20880
20568
  const synthTs = synthDate.toISOString();
20881
- 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("");
20882
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
+ }
20883
20590
  const queryMatch = /<user_query>\s*([\s\S]*?)\s*<\/user_query>/.exec(textParts);
20884
20591
  const text = queryMatch ? queryMatch[1] : textParts;
20885
20592
  if (text) {
@@ -20888,11 +20595,35 @@ async function parseCursorLog(fileContent, source = "session") {
20888
20595
  ...baseEntry(rawCopy, synthTs, synthDate, source),
20889
20596
  message: { role: "user", content: text }
20890
20597
  });
20598
+ } else if (!attachedResult) {
20599
+ entries.push({
20600
+ type: "system",
20601
+ ...baseEntry(rawCopy, synthTs, synthDate, source),
20602
+ raw: rawCopy
20603
+ });
20891
20604
  }
20892
20605
  continue;
20893
20606
  }
20894
20607
  if (raw.role === "assistant") {
20895
- 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
+ }
20896
20627
  if (blocks.length === 0) {
20897
20628
  entries.push({
20898
20629
  type: "system",
@@ -21059,9 +20790,9 @@ var init_cursor_sessions = __esm(() => {
21059
20790
  });
21060
20791
 
21061
20792
  // lib/pi-sessions.ts
21062
- 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";
21063
20794
  import { readFile as readFile14 } from "node:fs/promises";
21064
- 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";
21065
20796
  import { homedir as homedir20 } from "node:os";
21066
20797
  function getPiSessionStateRoot() {
21067
20798
  return process.env.PI_SESSIONS_DIR || join27(homedir20(), ".pi", "agent", "sessions");
@@ -21072,20 +20803,20 @@ function isSafeSessionId(sessionId) {
21072
20803
  function findPiTranscript(sessionId) {
21073
20804
  if (!isSafeSessionId(sessionId))
21074
20805
  return null;
21075
- const root = resolve15(getPiSessionStateRoot());
20806
+ const root = resolve14(getPiSessionStateRoot());
21076
20807
  let cwdDirs;
21077
20808
  try {
21078
- cwdDirs = readdirSync12(root);
20809
+ cwdDirs = readdirSync11(root);
21079
20810
  } catch {
21080
20811
  return null;
21081
20812
  }
21082
20813
  for (const cwdDir of cwdDirs) {
21083
- const cwdPath = resolve15(root, cwdDir);
20814
+ const cwdPath = resolve14(root, cwdDir);
21084
20815
  if (!cwdPath.startsWith(`${root}${sep4}`))
21085
20816
  continue;
21086
20817
  let files;
21087
20818
  try {
21088
- files = readdirSync12(cwdPath);
20819
+ files = readdirSync11(cwdPath);
21089
20820
  } catch {
21090
20821
  continue;
21091
20822
  }
@@ -21093,10 +20824,10 @@ function findPiTranscript(sessionId) {
21093
20824
  const m = SESSION_FILE_RE2.exec(f);
21094
20825
  if (!m || m[1].toLowerCase() !== sessionId.toLowerCase())
21095
20826
  continue;
21096
- const candidate = resolve15(cwdPath, f);
20827
+ const candidate = resolve14(cwdPath, f);
21097
20828
  if (!candidate.startsWith(`${cwdPath}${sep4}`))
21098
20829
  continue;
21099
- if (existsSync18(candidate))
20830
+ if (existsSync15(candidate))
21100
20831
  return candidate;
21101
20832
  }
21102
20833
  }
@@ -21499,14 +21230,53 @@ var init_pack_failclosed = __esm(() => {
21499
21230
  ]);
21500
21231
  });
21501
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
+
21502
21272
  // src/hooks/session-pause.ts
21503
- 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";
21504
21274
  import { createHash as createHash6 } from "node:crypto";
21505
- import { join as join28, resolve as resolve16 } from "node:path";
21275
+ import { join as join28, resolve as resolve15 } from "node:path";
21506
21276
  function pauseStateDir() {
21507
21277
  const override = process.env.FAILPROOFAI_STATE_DIR;
21508
21278
  if (override)
21509
- return resolve16(override, "sessions");
21279
+ return resolve15(override, "sessions");
21510
21280
  return sessionPauseDir();
21511
21281
  }
21512
21282
  function pauseFilePath(sessionId) {
@@ -21567,9 +21337,9 @@ function readActivePause(sessionId, now = Date.now()) {
21567
21337
  return null;
21568
21338
  try {
21569
21339
  const path = pauseFilePath(sessionId);
21570
- if (!existsSync19(path))
21340
+ if (!existsSync17(path))
21571
21341
  return null;
21572
- const stored = parseStored(JSON.parse(readFileSync16(path, "utf8")));
21342
+ const stored = parseStored(JSON.parse(readFileSync15(path, "utf8")));
21573
21343
  if (!stored)
21574
21344
  return null;
21575
21345
  if (stored.expiresAt <= now)
@@ -21592,16 +21362,16 @@ function writePause(opts) {
21592
21362
  setBy: opts.setBy ?? "cli",
21593
21363
  ...opts.cwd ? { cwd: opts.cwd } : {}
21594
21364
  };
21595
- mkdirSync11(pauseStateDir(), { recursive: true, mode: 448 });
21365
+ mkdirSync9(pauseStateDir(), { recursive: true, mode: 448 });
21596
21366
  writeJsonAtomically(pauseFilePath(opts.sessionId), { schemaVersion: SCHEMA_VERSION, ...pause });
21597
21367
  return pause;
21598
21368
  }
21599
21369
  function clearPause(sessionId) {
21600
21370
  const path = pauseFilePath(sessionId);
21601
- if (!existsSync19(path))
21371
+ if (!existsSync17(path))
21602
21372
  return false;
21603
21373
  try {
21604
- rmSync5(path);
21374
+ rmSync4(path);
21605
21375
  return true;
21606
21376
  } catch {
21607
21377
  return false;
@@ -21609,12 +21379,12 @@ function clearPause(sessionId) {
21609
21379
  }
21610
21380
  function listActivePauses(now = Date.now()) {
21611
21381
  const dir = pauseStateDir();
21612
- if (!existsSync19(dir))
21382
+ if (!existsSync17(dir))
21613
21383
  return [];
21614
21384
  const out = [];
21615
21385
  let names;
21616
21386
  try {
21617
- names = readdirSync13(dir);
21387
+ names = readdirSync12(dir);
21618
21388
  } catch {
21619
21389
  return [];
21620
21390
  }
@@ -21622,7 +21392,7 @@ function listActivePauses(now = Date.now()) {
21622
21392
  if (!name.endsWith(".json"))
21623
21393
  continue;
21624
21394
  try {
21625
- const stored = parseStored(JSON.parse(readFileSync16(join28(dir, name), "utf8")));
21395
+ const stored = parseStored(JSON.parse(readFileSync15(join28(dir, name), "utf8")));
21626
21396
  if (!stored || stored.expiresAt <= now)
21627
21397
  continue;
21628
21398
  const { schemaVersion: _ignored, ...pause } = stored;
@@ -21663,17 +21433,17 @@ var init_session_pause = __esm(() => {
21663
21433
  import { createHash as createHash7 } from "node:crypto";
21664
21434
  import {
21665
21435
  chmodSync as chmodSync3,
21666
- existsSync as existsSync20,
21667
- mkdirSync as mkdirSync12,
21668
- readdirSync as readdirSync14,
21669
- readFileSync as readFileSync17,
21436
+ existsSync as existsSync18,
21437
+ mkdirSync as mkdirSync10,
21438
+ readdirSync as readdirSync13,
21439
+ readFileSync as readFileSync16,
21670
21440
  renameSync as renameSync5,
21671
- rmSync as rmSync6,
21672
- statSync as statSync16,
21673
- writeFileSync as writeFileSync9
21441
+ rmSync as rmSync5,
21442
+ statSync as statSync15,
21443
+ writeFileSync as writeFileSync8
21674
21444
  } from "node:fs";
21675
21445
  import { createRequire as createRequire2 } from "node:module";
21676
- import { dirname as dirname10, resolve as resolve17 } from "node:path";
21446
+ import { dirname as dirname9, resolve as resolve16 } from "node:path";
21677
21447
  import { gunzipSync } from "node:zlib";
21678
21448
  function baseUrl2() {
21679
21449
  return (process.env.FAILPROOFAI_DAEMON_BASE_URL || DEFAULT_BASE_URL2).replace(/\/+$/, "");
@@ -21682,7 +21452,7 @@ function daemonBinaryDir() {
21682
21452
  return binDir();
21683
21453
  }
21684
21454
  function installedBinaryPath(ver = version2) {
21685
- return resolve17(daemonBinaryDir(), `failproofaid-${ver}`);
21455
+ return resolve16(daemonBinaryDir(), `failproofaid-${ver}`);
21686
21456
  }
21687
21457
  function daemonAssetUrl(key, ver = version2) {
21688
21458
  return `${baseUrl2()}/v${ver}/failproofaid-${key}.gz`;
@@ -21699,35 +21469,35 @@ function npmPlatformBinaryPath(key) {
21699
21469
  return null;
21700
21470
  const name = platformPackageName(key);
21701
21471
  try {
21702
- const requireFromRoot = createRequire2(resolve17(packageRoot, "package.json"));
21703
- 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`)));
21704
21474
  if (found)
21705
21475
  return found;
21706
21476
  } catch {}
21707
- return platformPackageBinary(resolve17(packageRoot, "node_modules", name));
21477
+ return platformPackageBinary(resolve16(packageRoot, "node_modules", name));
21708
21478
  }
21709
21479
  function platformPackageBinary(dir) {
21710
21480
  try {
21711
- const manifest = JSON.parse(readFileSync17(resolve17(dir, "package.json"), "utf8"));
21481
+ const manifest = JSON.parse(readFileSync16(resolve16(dir, "package.json"), "utf8"));
21712
21482
  if (manifest.version !== version2)
21713
21483
  return null;
21714
21484
  } catch {
21715
21485
  return null;
21716
21486
  }
21717
- const candidate = resolve17(dir, "bin", "failproofaid");
21718
- return existsSync20(candidate) ? candidate : null;
21487
+ const candidate = resolve16(dir, "bin", "failproofaid");
21488
+ return existsSync18(candidate) ? candidate : null;
21719
21489
  }
21720
21490
  function pruneOldDaemonBinaries(keep = 2) {
21721
21491
  const removed = [];
21722
21492
  try {
21723
21493
  const dir = daemonBinaryDir();
21724
- const entries = readdirSync14(dir).filter((f) => f.startsWith("failproofaid-") && !f.endsWith(".tmp")).map((f) => {
21725
- const full = resolve17(dir, f);
21726
- 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 };
21727
21497
  }).sort((a, b) => b.mtime - a.mtime);
21728
21498
  for (const stale of entries.slice(keep)) {
21729
21499
  try {
21730
- rmSync6(stale.full, { force: true });
21500
+ rmSync5(stale.full, { force: true });
21731
21501
  removed.push(stale.full);
21732
21502
  } catch {}
21733
21503
  }
@@ -21738,13 +21508,13 @@ function installBinaryBytes(binary) {
21738
21508
  const target = installedBinaryPath();
21739
21509
  const tempPath = `${target}.${process.pid}.tmp`;
21740
21510
  try {
21741
- mkdirSync12(daemonBinaryDir(), { recursive: true });
21742
- writeFileSync9(tempPath, binary);
21511
+ mkdirSync10(daemonBinaryDir(), { recursive: true });
21512
+ writeFileSync8(tempPath, binary);
21743
21513
  chmodSync3(tempPath, 493);
21744
21514
  renameSync5(tempPath, target);
21745
21515
  return target;
21746
21516
  } catch (err) {
21747
- rmSync6(tempPath, { force: true });
21517
+ rmSync5(tempPath, { force: true });
21748
21518
  throw err;
21749
21519
  }
21750
21520
  }
@@ -21758,7 +21528,7 @@ function installFromNpmPackage(key) {
21758
21528
  if (!source)
21759
21529
  return { error: `${platformPackageName(key)} is not installed` };
21760
21530
  try {
21761
- const bytes = readFileSync17(source);
21531
+ const bytes = readFileSync16(source);
21762
21532
  const mismatch = binaryDigestMismatch(expectedNpmBinaryDigest(key), bytes, source);
21763
21533
  if (mismatch)
21764
21534
  return { error: mismatch };
@@ -21793,7 +21563,7 @@ function digestFor2(manifest, assetName) {
21793
21563
  }
21794
21564
  async function downloadFailproofaidBinary(key) {
21795
21565
  const target = installedBinaryPath();
21796
- if (existsSync20(target))
21566
+ if (existsSync18(target))
21797
21567
  return { path: target };
21798
21568
  if (process.env.FAILPROOFAI_NO_DOWNLOAD) {
21799
21569
  return { error: "daemon downloads are disabled (FAILPROOFAI_NO_DOWNLOAD)" };
@@ -21827,10 +21597,10 @@ var init_daemon_download = __esm(() => {
21827
21597
 
21828
21598
  // src/hooks/daemon-client.ts
21829
21599
  import { createConnection as createConnection2 } from "node:net";
21830
- import { existsSync as existsSync21 } from "node:fs";
21600
+ import { existsSync as existsSync19 } from "node:fs";
21831
21601
  function daemonSocketPresent() {
21832
21602
  try {
21833
- return existsSync21(socketPath2());
21603
+ return existsSync19(socketPath2());
21834
21604
  } catch {
21835
21605
  return false;
21836
21606
  }
@@ -21956,16 +21726,16 @@ var init_daemon_client2 = __esm(() => {
21956
21726
 
21957
21727
  // src/hooks/daemon-service.ts
21958
21728
  import {
21959
- existsSync as existsSync22,
21960
- mkdirSync as mkdirSync13,
21729
+ existsSync as existsSync20,
21730
+ mkdirSync as mkdirSync11,
21961
21731
  mkdtempSync,
21962
- readFileSync as readFileSync18,
21963
- writeFileSync as writeFileSync10,
21732
+ readFileSync as readFileSync17,
21733
+ writeFileSync as writeFileSync9,
21964
21734
  unlinkSync as unlinkSync3,
21965
- rmSync as rmSync7
21735
+ rmSync as rmSync6
21966
21736
  } from "node:fs";
21967
21737
  import { homedir as homedir21, tmpdir as tmpdir2, userInfo } from "node:os";
21968
- import { resolve as resolve18 } from "node:path";
21738
+ import { resolve as resolve17 } from "node:path";
21969
21739
  import { execFileSync as execFileSync2 } from "node:child_process";
21970
21740
  function setDaemonConfigured(value, installedVersion) {
21971
21741
  try {
@@ -21987,13 +21757,13 @@ function resolveFailproofaidBinaryPath() {
21987
21757
  if (process.env.FAILPROOFAI_DAEMON_BINARY)
21988
21758
  return process.env.FAILPROOFAI_DAEMON_BINARY;
21989
21759
  const downloaded = installedBinaryPath();
21990
- if (existsSync22(downloaded))
21760
+ if (existsSync20(downloaded))
21991
21761
  return downloaded;
21992
21762
  const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT;
21993
21763
  if (packageRoot) {
21994
21764
  for (const profile of ["release", "debug"]) {
21995
- const candidate = resolve18(packageRoot, "target", profile, "failproofaid");
21996
- if (existsSync22(candidate))
21765
+ const candidate = resolve17(packageRoot, "target", profile, "failproofaid");
21766
+ if (existsSync20(candidate))
21997
21767
  return candidate;
21998
21768
  }
21999
21769
  }
@@ -22023,8 +21793,8 @@ function resolveWorkerCommand() {
22023
21793
  const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT;
22024
21794
  if (!packageRoot)
22025
21795
  return null;
22026
- const workerScript = resolve18(packageRoot, "dist", "worker.mjs");
22027
- if (!existsSync22(workerScript))
21796
+ const workerScript = resolve17(packageRoot, "dist", "worker.mjs");
21797
+ if (!existsSync20(workerScript))
22028
21798
  return null;
22029
21799
  return `${shellQuote(process.execPath)} ${shellQuote(workerScript)}`;
22030
21800
  }
@@ -22034,8 +21804,8 @@ function resolveCliCommand() {
22034
21804
  const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT;
22035
21805
  if (!packageRoot)
22036
21806
  return null;
22037
- const cliScript = resolve18(packageRoot, "dist", "cli.mjs");
22038
- if (!existsSync22(cliScript))
21807
+ const cliScript = resolve17(packageRoot, "dist", "cli.mjs");
21808
+ if (!existsSync20(cliScript))
22039
21809
  return null;
22040
21810
  return `${shellQuote(process.execPath)} ${shellQuote(cliScript)}`;
22041
21811
  }
@@ -22048,8 +21818,8 @@ function workerScriptPath() {
22048
21818
  const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT;
22049
21819
  if (!packageRoot)
22050
21820
  return null;
22051
- const workerScript = resolve18(packageRoot, "dist", "worker.mjs");
22052
- return existsSync22(workerScript) ? workerScript : null;
21821
+ const workerScript = resolve17(packageRoot, "dist", "worker.mjs");
21822
+ return existsSync20(workerScript) ? workerScript : null;
22053
21823
  }
22054
21824
  function assertUnitSafe(value, field) {
22055
21825
  if (UNIT_UNSAFE_RE.test(value)) {
@@ -22075,10 +21845,10 @@ function systemdUnitDir() {
22075
21845
  return process.env.FAILPROOFAI_SYSTEMD_DIR || "/etc/systemd/system";
22076
21846
  }
22077
21847
  function systemdUnitPath(user = serviceUser()) {
22078
- return resolve18(systemdUnitDir(), systemdUnitName(user));
21848
+ return resolve17(systemdUnitDir(), systemdUnitName(user));
22079
21849
  }
22080
21850
  function legacySystemdUserUnitPath() {
22081
- return resolve18(homedir21(), ".config", "systemd", "user", "failproofaid.service");
21851
+ return resolve17(homedir21(), ".config", "systemd", "user", "failproofaid.service");
22082
21852
  }
22083
21853
  function launchdLabel(user = serviceUser()) {
22084
21854
  return `ai.failproof.failproofaid.${user}`;
@@ -22087,7 +21857,7 @@ function launchdPlistPath(user = serviceUser()) {
22087
21857
  return `/Library/LaunchDaemons/${launchdLabel(user)}.plist`;
22088
21858
  }
22089
21859
  function legacyLaunchAgentPlistPath() {
22090
- return resolve18(homedir21(), "Library", "LaunchAgents", "ai.failproof.failproofaid.plist");
21860
+ return resolve17(homedir21(), "Library", "LaunchAgents", "ai.failproof.failproofaid.plist");
22091
21861
  }
22092
21862
  function legacySharedLaunchDaemonPath() {
22093
21863
  return "/Library/LaunchDaemons/ai.failproof.failproofaid.plist";
@@ -22135,20 +21905,20 @@ function runPrivileged(command, args) {
22135
21905
  execFileSync2(cmd, argv, { stdio: "ignore", timeout: SERVICE_CMD_TIMEOUT_MS });
22136
21906
  }
22137
21907
  function writePrivilegedFile(destination, contents, mode = "0644") {
22138
- const stagingDir = mkdtempSync(resolve18(tmpdir2(), "failproofaid-stage-"));
22139
- const staging = resolve18(stagingDir, "service-definition");
21908
+ const stagingDir = mkdtempSync(resolve17(tmpdir2(), "failproofaid-stage-"));
21909
+ const staging = resolve17(stagingDir, "service-definition");
22140
21910
  try {
22141
- writeFileSync10(staging, contents, "utf8");
21911
+ writeFileSync9(staging, contents, "utf8");
22142
21912
  runPrivileged("install", ["-m", mode, staging, destination]);
22143
21913
  } finally {
22144
- rmSync7(stagingDir, { recursive: true, force: true });
21914
+ rmSync6(stagingDir, { recursive: true, force: true });
22145
21915
  }
22146
21916
  }
22147
21917
  function removeLegacyUserService() {
22148
21918
  try {
22149
21919
  if (process.platform === "linux") {
22150
21920
  const legacy = legacySystemdUserUnitPath();
22151
- if (!existsSync22(legacy))
21921
+ if (!existsSync20(legacy))
22152
21922
  return;
22153
21923
  try {
22154
21924
  execFileSync2("systemctl", ["--user", "disable", "--now", "failproofaid.service"], {
@@ -22165,7 +21935,7 @@ function removeLegacyUserService() {
22165
21935
  } catch {}
22166
21936
  } else {
22167
21937
  const legacyAgent = legacyLaunchAgentPlistPath();
22168
- if (existsSync22(legacyAgent)) {
21938
+ if (existsSync20(legacyAgent)) {
22169
21939
  try {
22170
21940
  execFileSync2("launchctl", ["unload", "-w", legacyAgent], {
22171
21941
  stdio: "ignore",
@@ -22175,7 +21945,7 @@ function removeLegacyUserService() {
22175
21945
  unlinkSync3(legacyAgent);
22176
21946
  }
22177
21947
  const legacyDaemon = legacySharedLaunchDaemonPath();
22178
- if (existsSync22(legacyDaemon)) {
21948
+ if (existsSync20(legacyDaemon)) {
22179
21949
  try {
22180
21950
  runPrivileged("launchctl", ["unload", "-w", legacyDaemon]);
22181
21951
  } catch {}
@@ -22192,7 +21962,7 @@ function systemdUnitContents(binaryPath, workerCmd, cliCmd = null) {
22192
21962
  const user = assertUnitSafe(serviceUser(), "User");
22193
21963
  assertUnitSafe(binaryPath, "ExecStart");
22194
21964
  assertUnitSafe(homedir21(), "HOME");
22195
- const conditionPaths = [binaryPath, workerScriptPath()].filter((p) => typeof p === "string" && existsSync22(p));
21965
+ const conditionPaths = [binaryPath, workerScriptPath()].filter((p) => typeof p === "string" && existsSync20(p));
22196
21966
  const conditionLines = conditionPaths.map((p) => `ConditionPathExists=${assertUnitSafe(p, "ConditionPathExists")}
22197
21967
  `).join("");
22198
21968
  return `[Unit]
@@ -22253,9 +22023,9 @@ ${env.map(([key, value]) => ` <key>${key}</key>
22253
22023
  <key>UserName</key>
22254
22024
  <string>${escapeXml(serviceUser())}</string>
22255
22025
  ${envBlock} <key>StandardOutPath</key>
22256
- <string>${escapeXml(resolve18(logDir, "failproofaid.log"))}</string>
22026
+ <string>${escapeXml(resolve17(logDir, "failproofaid.log"))}</string>
22257
22027
  <key>StandardErrorPath</key>
22258
- <string>${escapeXml(resolve18(logDir, "failproofaid.err.log"))}</string>
22028
+ <string>${escapeXml(resolve17(logDir, "failproofaid.err.log"))}</string>
22259
22029
  </dict>
22260
22030
  </plist>
22261
22031
  `;
@@ -22301,7 +22071,7 @@ async function installDaemonService() {
22301
22071
  } else {
22302
22072
  const plistPath = launchdPlistPath();
22303
22073
  const logDir = logsDir();
22304
- mkdirSync13(logDir, { recursive: true });
22074
+ mkdirSync11(logDir, { recursive: true });
22305
22075
  try {
22306
22076
  runPrivileged("launchctl", ["unload", plistPath]);
22307
22077
  } catch {}
@@ -22387,10 +22157,10 @@ function readInstalledServiceDefinition() {
22387
22157
  if (!isDaemonSupportedPlatform())
22388
22158
  return null;
22389
22159
  const path = daemonServiceFilePath();
22390
- if (!path || !existsSync22(path))
22160
+ if (!path || !existsSync20(path))
22391
22161
  return null;
22392
22162
  try {
22393
- return readFileSync18(path, "utf8");
22163
+ return readFileSync17(path, "utf8");
22394
22164
  } catch {
22395
22165
  return null;
22396
22166
  }
@@ -22499,7 +22269,7 @@ async function ensureDaemonServiceCurrent() {
22499
22269
  restartSystemdUnit();
22500
22270
  } else {
22501
22271
  const plistPath = launchdPlistPath();
22502
- mkdirSync13(logDir, { recursive: true });
22272
+ mkdirSync11(logDir, { recursive: true });
22503
22273
  previous = definition;
22504
22274
  try {
22505
22275
  runPrivileged("launchctl", ["unload", plistPath]);
@@ -22523,7 +22293,7 @@ async function uninstallDaemonService() {
22523
22293
  try {
22524
22294
  if (process.platform === "linux") {
22525
22295
  const unitPath = systemdUnitPath();
22526
- if (!existsSync22(unitPath))
22296
+ if (!existsSync20(unitPath))
22527
22297
  return;
22528
22298
  try {
22529
22299
  runPrivileged("systemctl", ["disable", "--now", systemdUnitName()]);
@@ -22534,7 +22304,7 @@ async function uninstallDaemonService() {
22534
22304
  } catch {}
22535
22305
  } else {
22536
22306
  const plistPath = launchdPlistPath();
22537
- if (!existsSync22(plistPath))
22307
+ if (!existsSync20(plistPath))
22538
22308
  return;
22539
22309
  try {
22540
22310
  runPrivileged("launchctl", ["unload", "-w", plistPath]);
@@ -22551,7 +22321,7 @@ function daemonVersionSkew() {
22551
22321
  const recorded = readVersionFile()?.daemon;
22552
22322
  if (!recorded)
22553
22323
  return null;
22554
- if (!existsSync22(installedBinaryPath(recorded)))
22324
+ if (!existsSync20(installedBinaryPath(recorded)))
22555
22325
  return null;
22556
22326
  return recorded === version2 ? null : { installed: recorded, expected: version2 };
22557
22327
  }
@@ -22569,7 +22339,7 @@ function daemonServiceStatus() {
22569
22339
  if (!isDaemonSupportedPlatform())
22570
22340
  return "unsupported-platform";
22571
22341
  if (process.platform === "linux") {
22572
- if (!existsSync22(systemdUnitPath()))
22342
+ if (!existsSync20(systemdUnitPath()))
22573
22343
  return "not-installed";
22574
22344
  try {
22575
22345
  const out = execFileSync2("systemctl", ["is-active", systemdUnitName()], {
@@ -22582,7 +22352,7 @@ function daemonServiceStatus() {
22582
22352
  }
22583
22353
  }
22584
22354
  const plistPath = launchdPlistPath();
22585
- if (!existsSync22(plistPath))
22355
+ if (!existsSync20(plistPath))
22586
22356
  return "not-installed";
22587
22357
  try {
22588
22358
  const root = typeof process.getuid === "function" && process.getuid() === 0;
@@ -22614,48 +22384,48 @@ var init_daemon_service = __esm(() => {
22614
22384
  // src/hooks/fp-reset.ts
22615
22385
  import {
22616
22386
  copyFileSync,
22617
- existsSync as existsSync23,
22618
- mkdirSync as mkdirSync14,
22619
- readFileSync as readFileSync19,
22620
- readdirSync as readdirSync15,
22387
+ existsSync as existsSync21,
22388
+ mkdirSync as mkdirSync12,
22389
+ readFileSync as readFileSync18,
22390
+ readdirSync as readdirSync14,
22621
22391
  renameSync as renameSync6,
22622
- rmSync as rmSync8,
22392
+ rmSync as rmSync7,
22623
22393
  rmdirSync,
22624
- statSync as statSync17,
22625
- writeFileSync as writeFileSync11
22394
+ statSync as statSync16,
22395
+ writeFileSync as writeFileSync10
22626
22396
  } from "node:fs";
22627
- 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";
22628
22398
  function migrateConventionPolicies() {
22629
22399
  const from = legacy.customPoliciesDir();
22630
- if (!existsSync23(from))
22400
+ if (!existsSync21(from))
22631
22401
  return [];
22632
22402
  const moved = [];
22633
22403
  const mergeInto = (dir, dest, prefix) => {
22634
22404
  let entries;
22635
22405
  try {
22636
- entries = readdirSync15(dir, { withFileTypes: true });
22406
+ entries = readdirSync14(dir, { withFileTypes: true });
22637
22407
  } catch {
22638
22408
  return;
22639
22409
  }
22640
22410
  if (entries.length === 0)
22641
22411
  return;
22642
22412
  try {
22643
- mkdirSync14(dest, { recursive: true });
22413
+ mkdirSync12(dest, { recursive: true });
22644
22414
  } catch {
22645
22415
  return;
22646
22416
  }
22647
22417
  for (const entry of entries) {
22648
- const source = resolve19(dir, entry.name);
22649
- const target = resolve19(dest, entry.name);
22418
+ const source = resolve18(dir, entry.name);
22419
+ const target = resolve18(dest, entry.name);
22650
22420
  const name = `${prefix}${entry.name}`;
22651
- if (!existsSync23(target)) {
22421
+ if (!existsSync21(target)) {
22652
22422
  try {
22653
22423
  renameSync6(source, target);
22654
22424
  moved.push(name);
22655
22425
  } catch {}
22656
22426
  continue;
22657
22427
  }
22658
- if (entry.isDirectory() && statSync17(target).isDirectory()) {
22428
+ if (entry.isDirectory() && statSync16(target).isDirectory()) {
22659
22429
  mergeInto(source, target, `${name}/`);
22660
22430
  try {
22661
22431
  rmdirSync(source);
@@ -22675,23 +22445,23 @@ function migrateLegacySpool() {
22675
22445
  [legacy.spoolDir(), spoolDir()],
22676
22446
  [legacy.failedDir(), failedDir()]
22677
22447
  ]) {
22678
- if (!existsSync23(from))
22448
+ if (!existsSync21(from))
22679
22449
  continue;
22680
22450
  try {
22681
- mkdirSync14(to, { recursive: true });
22682
- for (const entry of readdirSync15(from, { withFileTypes: true })) {
22451
+ mkdirSync12(to, { recursive: true });
22452
+ for (const entry of readdirSync14(from, { withFileTypes: true })) {
22683
22453
  if (!entry.isFile())
22684
22454
  continue;
22685
22455
  let name = entry.name;
22686
22456
  let n = 0;
22687
- while (existsSync23(resolve19(to, name)))
22457
+ while (existsSync21(resolve18(to, name)))
22688
22458
  name = `legacy-${n++}-${entry.name}`;
22689
22459
  try {
22690
- renameSync6(resolve19(from, entry.name), resolve19(to, name));
22460
+ renameSync6(resolve18(from, entry.name), resolve18(to, name));
22691
22461
  moved.push(name);
22692
22462
  } catch {
22693
22463
  try {
22694
- copyFileSync(resolve19(from, entry.name), resolve19(to, name));
22464
+ copyFileSync(resolve18(from, entry.name), resolve18(to, name));
22695
22465
  moved.push(name);
22696
22466
  } catch {}
22697
22467
  }
@@ -22702,24 +22472,24 @@ function migrateLegacySpool() {
22702
22472
  }
22703
22473
  function migrateHookActivity() {
22704
22474
  const from = legacy.hookActivityDir();
22705
- if (!existsSync23(from))
22475
+ if (!existsSync21(from))
22706
22476
  return [];
22707
22477
  const moved = [];
22708
22478
  try {
22709
- 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"));
22710
22480
  if (entries.length === 0)
22711
22481
  return [];
22712
22482
  const to = hookActivityDir();
22713
- mkdirSync14(to, { recursive: true });
22483
+ mkdirSync12(to, { recursive: true });
22714
22484
  const stamp = Date.now();
22715
22485
  let seq = 0;
22716
22486
  for (const entry of entries) {
22717
- const source = resolve19(from, entry.name);
22487
+ const source = resolve18(from, entry.name);
22718
22488
  let name = entry.name === "current.jsonl" ? `page-${stamp}-${seq++}.jsonl` : entry.name;
22719
- let target = resolve19(to, name);
22720
- while (existsSync23(target)) {
22489
+ let target = resolve18(to, name);
22490
+ while (existsSync21(target)) {
22721
22491
  name = `page-${stamp}-${seq++}.jsonl`;
22722
- target = resolve19(to, name);
22492
+ target = resolve18(to, name);
22723
22493
  }
22724
22494
  try {
22725
22495
  renameSync6(source, target);
@@ -22743,7 +22513,7 @@ function retirePolicyConfigKeys() {
22743
22513
  const at = globalPolicyConfigFile();
22744
22514
  let parsed;
22745
22515
  try {
22746
- const raw = JSON.parse(readFileSync19(at, "utf8"));
22516
+ const raw = JSON.parse(readFileSync18(at, "utf8"));
22747
22517
  if (!raw || typeof raw !== "object" || Array.isArray(raw))
22748
22518
  return [];
22749
22519
  parsed = raw;
@@ -22757,9 +22527,9 @@ function retirePolicyConfigKeys() {
22757
22527
  delete parsed[key];
22758
22528
  try {
22759
22529
  if (Object.keys(parsed).length === 0)
22760
- rmSync8(at, { force: true });
22530
+ rmSync7(at, { force: true });
22761
22531
  else
22762
- writeFileSync11(at, JSON.stringify(parsed, null, 2) + `
22532
+ writeFileSync10(at, JSON.stringify(parsed, null, 2) + `
22763
22533
  `, "utf8");
22764
22534
  } catch {
22765
22535
  return [];
@@ -22767,12 +22537,12 @@ function retirePolicyConfigKeys() {
22767
22537
  return [...removed];
22768
22538
  }
22769
22539
  function readCarriedPolicyConfig() {
22770
- const from = resolve19(legacy.localPoliciesDir(), "policies-config.json");
22771
- if (!existsSync23(from))
22540
+ const from = resolve18(legacy.localPoliciesDir(), "policies-config.json");
22541
+ if (!existsSync21(from))
22772
22542
  return null;
22773
22543
  let parsed;
22774
22544
  try {
22775
- parsed = JSON.parse(readFileSync19(from, "utf8"));
22545
+ parsed = JSON.parse(readFileSync18(from, "utf8"));
22776
22546
  } catch {
22777
22547
  return null;
22778
22548
  }
@@ -22797,11 +22567,11 @@ function rewriteCarriedCustomPaths(carried) {
22797
22567
  const repoint = (value) => {
22798
22568
  if (typeof value !== "string" || value === "")
22799
22569
  return value;
22800
- const abs = resolve19(value);
22570
+ const abs = resolve18(value);
22801
22571
  const rel = relative4(fromDir, abs);
22802
22572
  if (rel === "" || rel.startsWith("..") || isAbsolute3(rel))
22803
22573
  return value;
22804
- return resolve19(toDir, rel);
22574
+ return resolve18(toDir, rel);
22805
22575
  };
22806
22576
  if (Array.isArray(carried.customPoliciesPaths)) {
22807
22577
  carried.customPoliciesPaths = carried.customPoliciesPaths.map(repoint);
@@ -22816,14 +22586,14 @@ function writeCarriedPolicyConfig(carried) {
22816
22586
  const to = globalPolicyConfigFile();
22817
22587
  let existing = {};
22818
22588
  try {
22819
- const parsed = JSON.parse(readFileSync19(to, "utf8"));
22589
+ const parsed = JSON.parse(readFileSync18(to, "utf8"));
22820
22590
  if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
22821
22591
  existing = parsed;
22822
22592
  }
22823
22593
  } catch {}
22824
22594
  try {
22825
- mkdirSync14(dirname11(to), { recursive: true });
22826
- writeFileSync11(to, JSON.stringify({ ...existing, ...carried }, null, 2) + `
22595
+ mkdirSync12(dirname10(to), { recursive: true });
22596
+ writeFileSync10(to, JSON.stringify({ ...existing, ...carried }, null, 2) + `
22827
22597
  `, "utf8");
22828
22598
  } catch {
22829
22599
  return [];
@@ -22832,10 +22602,10 @@ function writeCarriedPolicyConfig(carried) {
22832
22602
  }
22833
22603
  function readCarriedTelemetryOptOut() {
22834
22604
  const from = legacy.configToml();
22835
- if (!existsSync23(from))
22605
+ if (!existsSync21(from))
22836
22606
  return false;
22837
22607
  try {
22838
- const text = readFileSync19(from, "utf8");
22608
+ const text = readFileSync18(from, "utf8");
22839
22609
  const start = text.search(/^\s*\[telemetry\]\s*$/m);
22840
22610
  if (start === -1)
22841
22611
  return false;
@@ -22887,26 +22657,26 @@ function parseLegacyToml(text) {
22887
22657
  }
22888
22658
  function readCarriedLegacyConfig() {
22889
22659
  const from = legacy.configToml();
22890
- if (!existsSync23(from))
22660
+ if (!existsSync21(from))
22891
22661
  return null;
22892
22662
  try {
22893
- return projectConfig(parseLegacyToml(readFileSync19(from, "utf8")));
22663
+ return projectConfig(parseLegacyToml(readFileSync18(from, "utf8")));
22894
22664
  } catch {
22895
22665
  return null;
22896
22666
  }
22897
22667
  }
22898
22668
  function readCarriedLegacyCredentials() {
22899
22669
  const toml = legacy.credentialsToml();
22900
- if (existsSync23(toml)) {
22670
+ if (existsSync21(toml)) {
22901
22671
  try {
22902
- const creds = projectCredentials(parseLegacyToml(readFileSync19(toml, "utf8")));
22672
+ const creds = projectCredentials(parseLegacyToml(readFileSync18(toml, "utf8")));
22903
22673
  if (Object.keys(creds).length > 0)
22904
22674
  return creds;
22905
22675
  } catch {}
22906
22676
  }
22907
22677
  const readJson = (path) => {
22908
22678
  try {
22909
- const parsed = JSON.parse(readFileSync19(path, "utf8"));
22679
+ const parsed = JSON.parse(readFileSync18(path, "utf8"));
22910
22680
  return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
22911
22681
  } catch {
22912
22682
  return null;
@@ -22940,10 +22710,10 @@ function resetHome(from, to = LAYOUT_VERSION) {
22940
22710
  const spooled = migrateLegacySpool();
22941
22711
  const removed = [];
22942
22712
  for (const path of resettablePaths()) {
22943
- if (!existsSync23(path))
22713
+ if (!existsSync21(path))
22944
22714
  continue;
22945
22715
  try {
22946
- rmSync8(path, { recursive: true, force: true });
22716
+ rmSync7(path, { recursive: true, force: true });
22947
22717
  removed.push(path);
22948
22718
  } catch {}
22949
22719
  }
@@ -22965,7 +22735,7 @@ function layoutWarningForHook() {
22965
22735
  if (state.kind === "future") {
22966
22736
  return `[failproofai] this directory was written by a newer version (layout ${state.found} vs ${LAYOUT_VERSION}) — policies are NOT being enforced. ` + `Upgrade failproofai.`;
22967
22737
  }
22968
- if (existsSync23(globalPolicyConfigFile()))
22738
+ if (existsSync21(globalPolicyConfigFile()))
22969
22739
  return null;
22970
22740
  return `[failproofai] setup predates this version — global policies are NOT being enforced. ` + `Run \`failproofai config\` to re-create it.`;
22971
22741
  }
@@ -23012,31 +22782,6 @@ function canonicalizeEventType(raw, cli) {
23012
22782
  }
23013
22783
  return raw;
23014
22784
  }
23015
- function attachLeakNotice(eventType, cli, outcome) {
23016
- try {
23017
- if (!canDeliverNotice(cli))
23018
- return outcome;
23019
- if (!cli)
23020
- return outcome;
23021
- const canonical = canonicalizeEventType(eventType, cli);
23022
- if (canonical !== "Stop" && canonical !== "SessionStart")
23023
- return outcome;
23024
- const pending = pendingLeakNotice();
23025
- if (pending.count === 0)
23026
- return outcome;
23027
- const shaped = shapeNotice(cli, leakNoticeText(pending.count), outcome.stdout);
23028
- if (shaped.stdout === outcome.stdout && !shaped.stderr)
23029
- return outcome;
23030
- markLeakNoticeDelivered(pending.ids);
23031
- return {
23032
- exitCode: outcome.exitCode,
23033
- stdout: shaped.stdout,
23034
- stderr: outcome.stderr + shaped.stderr
23035
- };
23036
- } catch {
23037
- return outcome;
23038
- }
23039
- }
23040
22785
  async function runObserved(hook, ctx, hookName, eventType, cli) {
23041
22786
  try {
23042
22787
  return await Promise.race([
@@ -23339,12 +23084,7 @@ async function evaluateHookEvent(eventType, cli = "claude", stdinPayload, opts)
23339
23084
  }
23340
23085
  } catch {}
23341
23086
  }
23342
- const withNotice = attachLeakNotice(eventType, cli, {
23343
- exitCode: result.exitCode,
23344
- stdout: result.stdout,
23345
- stderr: result.stderr
23346
- });
23347
- return withNotice;
23087
+ return { exitCode: result.exitCode, stdout: result.stdout, stderr: result.stderr };
23348
23088
  } finally {
23349
23089
  if (opts?.awaitTelemetryFlush ?? true) {
23350
23090
  await flushHookTelemetry2();
@@ -23403,8 +23143,6 @@ var init_handler = __esm(() => {
23403
23143
  init_custom_hooks_loader();
23404
23144
  init_hook_activity_store();
23405
23145
  init_delivery_health();
23406
- init_notice();
23407
- init_leak_notice();
23408
23146
  init_hook_telemetry2();
23409
23147
  init_resolve_permission_mode();
23410
23148
  init_resolve_transcript_path();
@@ -24045,17 +23783,17 @@ var init_collector_config = __esm(() => {
24045
23783
  });
24046
23784
 
24047
23785
  // src/hooks/flush-cli.ts
24048
- import { existsSync as existsSync24, mkdirSync as mkdirSync15, writeFileSync as writeFileSync12, readdirSync as readdirSync16 } from "node:fs";
24049
- 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";
24050
23788
  function flushRequestPath(home) {
24051
23789
  return join29(failproofaiHome(home), "state", "flush-request.json");
24052
23790
  }
24053
23791
  function spoolDirs(home) {
24054
23792
  const root = spoolDir(home);
24055
- if (!existsSync24(root))
23793
+ if (!existsSync22(root))
24056
23794
  return [];
24057
23795
  try {
24058
- 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));
24059
23797
  } catch {
24060
23798
  return [];
24061
23799
  }
@@ -24064,7 +23802,7 @@ function pendingBatches(home) {
24064
23802
  let n = 0;
24065
23803
  for (const dir of spoolDirs(home)) {
24066
23804
  try {
24067
- n += readdirSync16(dir).filter((f) => f.endsWith(".jsonl")).length;
23805
+ n += readdirSync15(dir).filter((f) => f.endsWith(".jsonl")).length;
24068
23806
  } catch {}
24069
23807
  }
24070
23808
  return n;
@@ -24121,8 +23859,8 @@ async function runFlushCommand(opts = {}) {
24121
23859
  return { exitCode: 0, pending: 0, lines: ["Nothing spooled — everything already delivered."] };
24122
23860
  }
24123
23861
  const path = flushRequestPath(home);
24124
- mkdirSync15(dirname12(path), { recursive: true });
24125
- 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)}
24126
23864
  `, {
24127
23865
  mode: 384
24128
23866
  });
@@ -24156,14 +23894,14 @@ var init_flush_cli = __esm(() => {
24156
23894
  import {
24157
23895
  chmodSync as chmodSync4,
24158
23896
  copyFileSync as copyFileSync2,
24159
- existsSync as existsSync25,
24160
- mkdirSync as mkdirSync16,
24161
- readFileSync as readFileSync20,
23897
+ existsSync as existsSync23,
23898
+ mkdirSync as mkdirSync14,
23899
+ readFileSync as readFileSync19,
24162
23900
  renameSync as renameSync7,
24163
- rmSync as rmSync9,
24164
- writeFileSync as writeFileSync13
23901
+ rmSync as rmSync8,
23902
+ writeFileSync as writeFileSync12
24165
23903
  } from "node:fs";
24166
- 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";
24167
23905
  function migrateToLayout4() {
24168
23906
  const moves = [
24169
23907
  { from: legacy.authJson(), to: auditSessionFile() },
@@ -24179,13 +23917,13 @@ function migrateToLayout4() {
24179
23917
  }
24180
23918
  const migrated = [];
24181
23919
  for (const { from, to } of moves) {
24182
- if (!existsSync25(from))
23920
+ if (!existsSync23(from))
24183
23921
  continue;
24184
- if (existsSync25(to)) {
24185
- rmSync9(from, { force: true });
23922
+ if (existsSync23(to)) {
23923
+ rmSync8(from, { force: true });
24186
23924
  continue;
24187
23925
  }
24188
- mkdirSync16(dirname13(to), { recursive: true });
23926
+ mkdirSync14(dirname12(to), { recursive: true });
24189
23927
  try {
24190
23928
  renameSync7(from, to);
24191
23929
  } catch {
@@ -24193,16 +23931,16 @@ function migrateToLayout4() {
24193
23931
  copyFileSync2(from, to);
24194
23932
  } catch (err) {
24195
23933
  try {
24196
- rmSync9(to, { force: true });
23934
+ rmSync8(to, { force: true });
24197
23935
  } catch {}
24198
23936
  throw err;
24199
23937
  }
24200
- rmSync9(from, { force: true });
23938
+ rmSync8(from, { force: true });
24201
23939
  }
24202
23940
  migrated.push(`${basename4(from)} → audit/${basename4(to)}`);
24203
23941
  }
24204
23942
  for (const secret of [auditSessionFile()]) {
24205
- if (!existsSync25(secret))
23943
+ if (!existsSync23(secret))
24206
23944
  continue;
24207
23945
  try {
24208
23946
  chmodSync4(secret, 384);
@@ -24228,7 +23966,7 @@ function planMigration(from, registry = MIGRATIONS) {
24228
23966
  }
24229
23967
  function readLedger() {
24230
23968
  try {
24231
- const parsed = JSON.parse(readFileSync20(migrationLedgerFile(), "utf8"));
23969
+ const parsed = JSON.parse(readFileSync19(migrationLedgerFile(), "utf8"));
24232
23970
  return Array.isArray(parsed) ? parsed : [];
24233
23971
  } catch {
24234
23972
  return [];
@@ -24236,9 +23974,9 @@ function readLedger() {
24236
23974
  }
24237
23975
  function appendLedger(entry) {
24238
23976
  try {
24239
- mkdirSync16(migrationsDir(), { recursive: true });
23977
+ mkdirSync14(migrationsDir(), { recursive: true });
24240
23978
  const all = [...readLedger(), entry];
24241
- writeFileSync13(migrationLedgerFile(), `${JSON.stringify(all, null, 2)}
23979
+ writeFileSync12(migrationLedgerFile(), `${JSON.stringify(all, null, 2)}
24242
23980
  `, "utf8");
24243
23981
  } catch {}
24244
23982
  }
@@ -24250,12 +23988,12 @@ function pruneMigratedCredentials(from) {
24250
23988
  for (let layout = from;layout < LAYOUT_VERSION; layout++) {
24251
23989
  for (const { as, landsAt } of PRUNED_AFTER_SUCCESS) {
24252
23990
  try {
24253
- if (!existsSync25(landsAt()))
23991
+ if (!existsSync23(landsAt()))
24254
23992
  continue;
24255
- const copy = resolve20(migrationBackupDir(layout), as);
24256
- if (!existsSync25(copy))
23993
+ const copy = resolve19(migrationBackupDir(layout), as);
23994
+ if (!existsSync23(copy))
24257
23995
  continue;
24258
- rmSync9(copy, { force: true });
23996
+ rmSync8(copy, { force: true });
24259
23997
  pruned.push(as);
24260
23998
  } catch {}
24261
23999
  }
@@ -24266,7 +24004,7 @@ function filesToBackUp() {
24266
24004
  const seen = new Map;
24267
24005
  for (const f of [...BACKED_UP, ...BACKED_UP_LEGACY]) {
24268
24006
  const path = f.at();
24269
- if (existsSync25(path))
24007
+ if (existsSync23(path))
24270
24008
  seen.set(path, backupNameOf(f));
24271
24009
  }
24272
24010
  return [...seen].map(([path, as]) => ({ path, as }));
@@ -24275,14 +24013,14 @@ function backupBeforeMigrating(from) {
24275
24013
  const dir = migrationBackupDir(from);
24276
24014
  const saved = [];
24277
24015
  try {
24278
- rmSync9(dir, { recursive: true, force: true });
24279
- mkdirSync16(dir, { recursive: true });
24016
+ rmSync8(dir, { recursive: true, force: true });
24017
+ mkdirSync14(dir, { recursive: true });
24280
24018
  } catch {
24281
24019
  return [];
24282
24020
  }
24283
24021
  for (const { path: source, as } of filesToBackUp()) {
24284
24022
  try {
24285
- copyFileSync2(source, resolve20(dir, as));
24023
+ copyFileSync2(source, resolve19(dir, as));
24286
24024
  saved.push(as);
24287
24025
  } catch {}
24288
24026
  }
@@ -24572,7 +24310,7 @@ var init_fp_reset2 = __esm(() => {
24572
24310
  // scripts/install-telemetry.mjs
24573
24311
  import { createHmac, randomUUID as randomUUID2 } from "node:crypto";
24574
24312
  import { execSync as execSync5 } from "node:child_process";
24575
- 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";
24576
24314
  import { homedir as homedir22, platform, arch, hostname, cpus } from "node:os";
24577
24315
  import { join as join31 } from "node:path";
24578
24316
  function hashToId3(raw) {
@@ -24582,7 +24320,7 @@ function getInstanceId3() {
24582
24320
  const idDir = join31(homedir22(), ".failproofai");
24583
24321
  const idFile = join31(idDir, "instance-id");
24584
24322
  try {
24585
- const existing = readFileSync21(idFile, "utf-8").trim();
24323
+ const existing = readFileSync20(idFile, "utf-8").trim();
24586
24324
  if (existing)
24587
24325
  return existing;
24588
24326
  } catch {}
@@ -24591,7 +24329,7 @@ function getInstanceId3() {
24591
24329
  if (p === "linux") {
24592
24330
  for (const machineIdPath of ["/etc/machine-id", "/var/lib/dbus/machine-id"]) {
24593
24331
  try {
24594
- const id = readFileSync21(machineIdPath, "utf-8").trim();
24332
+ const id = readFileSync20(machineIdPath, "utf-8").trim();
24595
24333
  if (id)
24596
24334
  return hashToId3(id);
24597
24335
  } catch {}
@@ -24623,8 +24361,8 @@ function getInstanceId3() {
24623
24361
  } catch {}
24624
24362
  const id = randomUUID2();
24625
24363
  try {
24626
- mkdirSync17(idDir, { recursive: true });
24627
- writeFileSync14(idFile, id, "utf-8");
24364
+ mkdirSync15(idDir, { recursive: true });
24365
+ writeFileSync13(idFile, id, "utf-8");
24628
24366
  } catch {}
24629
24367
  return id;
24630
24368
  }
@@ -24656,8 +24394,8 @@ var NAMESPACE3 = "failproofai-telemetry-v1", API_KEY3 = "phc_Ac1Ww1GqKc0z1SyrRWb
24656
24394
  var init_install_telemetry = () => {};
24657
24395
 
24658
24396
  // lib/install-check.ts
24659
- import { existsSync as existsSync26, readFileSync as readFileSync22, writeFileSync as writeFileSync15, mkdirSync as mkdirSync18 } from "node:fs";
24660
- 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";
24661
24399
  import { platform as platform2, arch as arch2, release, homedir as homedir23, hostname as hostname2 } from "node:os";
24662
24400
  import { createHmac as createHmac2 } from "node:crypto";
24663
24401
  function hashToId4(raw) {
@@ -24712,12 +24450,12 @@ function compareSemver(a, b) {
24712
24450
  }
24713
24451
  function checkHooks() {
24714
24452
  const hooksConfigPath = globalPolicyConfigFile();
24715
- if (!existsSync26(hooksConfigPath)) {
24453
+ if (!existsSync24(hooksConfigPath)) {
24716
24454
  return { configured: false, registered: false, policyCount: 0 };
24717
24455
  }
24718
24456
  let config;
24719
24457
  try {
24720
- config = JSON.parse(readFileSync22(hooksConfigPath, "utf8"));
24458
+ config = JSON.parse(readFileSync21(hooksConfigPath, "utf8"));
24721
24459
  } catch {
24722
24460
  return { configured: false, registered: false, policyCount: 0 };
24723
24461
  }
@@ -24725,12 +24463,12 @@ function checkHooks() {
24725
24463
  return { configured: false, registered: false, policyCount: 0 };
24726
24464
  }
24727
24465
  const policyCount = config.enabledPolicies.length;
24728
- const settingsPath = resolve21(homedir23(), ".claude", "settings.json");
24729
- if (!existsSync26(settingsPath))
24466
+ const settingsPath = resolve20(homedir23(), ".claude", "settings.json");
24467
+ if (!existsSync24(settingsPath))
24730
24468
  return { configured: true, registered: false, policyCount };
24731
24469
  let settings;
24732
24470
  try {
24733
- settings = JSON.parse(readFileSync22(settingsPath, "utf8"));
24471
+ settings = JSON.parse(readFileSync21(settingsPath, "utf8"));
24734
24472
  } catch {
24735
24473
  return { configured: true, registered: false, policyCount };
24736
24474
  }
@@ -24754,8 +24492,8 @@ async function maybeReportInstall(version) {
24754
24492
  const versionFile = lastVersionPath();
24755
24493
  let previousVersion = null;
24756
24494
  try {
24757
- if (existsSync26(versionFile)) {
24758
- previousVersion = readFileSync22(versionFile, "utf8").trim() || null;
24495
+ if (existsSync24(versionFile)) {
24496
+ previousVersion = readFileSync21(versionFile, "utf8").trim() || null;
24759
24497
  }
24760
24498
  } catch {}
24761
24499
  if (previousVersion === version)
@@ -24791,8 +24529,8 @@ async function maybeReportInstall(version) {
24791
24529
  enabled_policy_count: hooks.policyCount
24792
24530
  }, { version, timeoutMs: REPORT_TIMEOUT_MS, enabled: telemetryEnabled }));
24793
24531
  try {
24794
- mkdirSync18(dirname14(versionFile), { recursive: true });
24795
- writeFileSync15(versionFile, version, "utf8");
24532
+ mkdirSync16(dirname13(versionFile), { recursive: true });
24533
+ writeFileSync14(versionFile, version, "utf8");
24796
24534
  } catch {}
24797
24535
  await Promise.all(events.map((p) => p.catch(() => {})));
24798
24536
  } catch {}
@@ -24842,8 +24580,8 @@ var init_cli_error = __esm(() => {
24842
24580
 
24843
24581
  // src/hooks/manager.ts
24844
24582
  import { execSync as execSync6 } from "node:child_process";
24845
- import { existsSync as existsSync27 } from "node:fs";
24846
- 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";
24847
24585
  import { platform as platform3, arch as arch3, release as release2, hostname as hostname3 } from "node:os";
24848
24586
  function getSettingsPath(scope, cwd) {
24849
24587
  return claudeCode.getSettingsPath(scope, cwd);
@@ -25062,9 +24800,9 @@ async function installHooksImpl(policyNames, scope = "user", cwd, includeBeta =
25062
24800
  delete configToWrite.customPoliciesPath;
25063
24801
  delete configToWrite.customPoliciesPaths;
25064
24802
  } else if (customPoliciesPath && (typeof customPoliciesPath === "string" || customPoliciesPath.length > 0)) {
25065
- const incoming = (typeof customPoliciesPath === "string" ? [customPoliciesPath] : customPoliciesPath).map((path) => resolve22(path));
25066
- const carried = (previousConfig.customPoliciesPaths ?? (previousConfig.customPoliciesPath ? [previousConfig.customPoliciesPath] : [])).map((path) => resolve22(path)).filter((path) => {
25067
- 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))
25068
24806
  return true;
25069
24807
  console.log(`Dropping custom policies path (file no longer exists): ${path}`);
25070
24808
  return false;
@@ -25287,7 +25025,7 @@ async function removeHooks(policyNames, scope = "user", cwd, opts) {
25287
25025
  const scopesToRemove = scope === "all" ? [...integration.scopes] : integration.scopes.includes(scope) ? [scope] : [];
25288
25026
  for (const s of scopesToRemove) {
25289
25027
  const settingsPaths = settingsPathsFor(integration, s, cwd);
25290
- const existing = settingsPaths.filter((p) => existsSync27(p));
25028
+ const existing = settingsPaths.filter((p) => existsSync25(p));
25291
25029
  if (existing.length === 0) {
25292
25030
  if (scope !== "all" && selectedClis.length === 1) {
25293
25031
  console.log("No settings file found. Nothing to remove.");
@@ -25374,16 +25112,92 @@ var init_manager = __esm(() => {
25374
25112
  VALID_POLICY_NAMES = new Set(BUILTIN_POLICIES.map((p) => p.name));
25375
25113
  });
25376
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
+
25377
25191
  // src/audit/macos-notifier.ts
25378
25192
  import { execFileSync as execFileSync3 } from "node:child_process";
25379
- 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";
25380
25194
  import { homedir as homedir24 } from "node:os";
25381
- import { resolve as resolve23 } from "node:path";
25195
+ import { resolve as resolve22 } from "node:path";
25382
25196
  function macNotifierAppPath(home) {
25383
- return resolve23(runDir(home), "..", "bin", "FailproofAI Notifier.app");
25197
+ return resolve22(runDir(home), "..", "bin", "FailproofAI Notifier.app");
25384
25198
  }
25385
25199
  function macNotifierPlistPath() {
25386
- return resolve23(homedir24(), "Library", "LaunchAgents", `${MAC_NOTIFIER_LABEL}.plist`);
25200
+ return resolve22(homedir24(), "Library", "LaunchAgents", `${MAC_NOTIFIER_LABEL}.plist`);
25387
25201
  }
25388
25202
  function escapeXml2(s) {
25389
25203
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
@@ -25427,7 +25241,7 @@ function notifierPlistContents(appPath, watchDir) {
25427
25241
  <string>${escapeXml2(MAC_NOTIFIER_LABEL)}</string>
25428
25242
  <key>ProgramArguments</key>
25429
25243
  <array>
25430
- <string>${escapeXml2(resolve23(appPath, "Contents", "MacOS", "applet"))}</string>
25244
+ <string>${escapeXml2(resolve22(appPath, "Contents", "MacOS", "applet"))}</string>
25431
25245
  </array>
25432
25246
  <!-- Started only when something is queued, and it exits when the queue is
25433
25247
  empty. RunAtLoad would fire it once at login with nothing to say. -->
@@ -25456,18 +25270,18 @@ function installMacNotifier(home) {
25456
25270
  try {
25457
25271
  const app = macNotifierAppPath(home);
25458
25272
  const watch = macNotifyDir(home);
25459
- mkdirSync19(watch, { recursive: true, mode: 448 });
25460
- mkdirSync19(resolve23(app, ".."), { recursive: true });
25461
- const scriptPath = resolve23(watch, "..", "notifier.applescript");
25462
- writeFileSync16(scriptPath, notifierScript(home), { mode: 384 });
25463
- 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 });
25464
25278
  run("osacompile", ["-o", app, scriptPath]);
25465
- rmSync10(scriptPath, { force: true });
25466
- const plist = resolve23(app, "Contents", "Info.plist");
25279
+ rmSync9(scriptPath, { force: true });
25280
+ const plist = resolve22(app, "Contents", "Info.plist");
25467
25281
  run("defaults", ["write", plist, "CFBundleIdentifier", MAC_NOTIFIER_LABEL]);
25468
25282
  run("defaults", ["write", plist, "CFBundleName", "failproofai"]);
25469
- mkdirSync19(resolve23(macNotifierPlistPath(), ".."), { recursive: true });
25470
- writeFileSync16(macNotifierPlistPath(), notifierPlistContents(app, watch), { mode: 420 });
25283
+ mkdirSync17(resolve22(macNotifierPlistPath(), ".."), { recursive: true });
25284
+ writeFileSync15(macNotifierPlistPath(), notifierPlistContents(app, watch), { mode: 420 });
25471
25285
  const target = `gui/${process.getuid?.() ?? 0}`;
25472
25286
  try {
25473
25287
  run("launchctl", ["bootout", `${target}/${MAC_NOTIFIER_LABEL}`]);
@@ -25484,49 +25298,49 @@ function uninstallMacNotifier(home) {
25484
25298
  try {
25485
25299
  run("launchctl", ["bootout", `gui/${process.getuid?.() ?? 0}/${MAC_NOTIFIER_LABEL}`]);
25486
25300
  } catch {}
25487
- rmSync10(macNotifierPlistPath(), { force: true });
25488
- rmSync10(macNotifierAppPath(home), { recursive: true, force: true });
25489
- 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 });
25490
25304
  }
25491
25305
  function queueMacNotification(id, title, body, home) {
25492
25306
  if (!isFindingId(id))
25493
25307
  return false;
25494
25308
  const dir = macNotifyDir(home);
25495
- const tmp = resolve23(dir, "..", `notify-${id}.tmp`);
25309
+ const tmp = resolve22(dir, "..", `notify-${id}.tmp`);
25496
25310
  try {
25497
- mkdirSync19(dir, { recursive: true, mode: 448 });
25311
+ mkdirSync17(dir, { recursive: true, mode: 448 });
25498
25312
  const payload = `${title.replace(/\s+/g, " ")}
25499
25313
  ${body.replace(/\s+/g, " ")}
25500
25314
  `;
25501
- writeFileSync16(tmp, payload, { mode: 384 });
25502
- renameSync8(tmp, resolve23(dir, id));
25315
+ writeFileSync15(tmp, payload, { mode: 384 });
25316
+ renameSync8(tmp, resolve22(dir, id));
25503
25317
  return true;
25504
25318
  } catch {
25505
25319
  try {
25506
- rmSync10(tmp, { force: true });
25320
+ rmSync9(tmp, { force: true });
25507
25321
  } catch {}
25508
25322
  return false;
25509
25323
  }
25510
25324
  }
25511
25325
  function macNotifierInstalled(home) {
25512
- return existsSync28(macNotifierPlistPath()) && existsSync28(macNotifierAppPath(home));
25326
+ return existsSync26(macNotifierPlistPath()) && existsSync26(macNotifierAppPath(home));
25513
25327
  }
25514
25328
  function pruneMacNotifyQueue(home, maxAgeMs = 7 * 86400000) {
25515
25329
  try {
25516
25330
  const dir = macNotifyDir(home);
25517
- if (!existsSync28(dir))
25331
+ if (!existsSync26(dir))
25518
25332
  return;
25519
25333
  const { statSync } = __require("node:fs");
25520
- for (const name of readdirSync17(dir)) {
25521
- const path = resolve23(dir, name);
25334
+ for (const name of readdirSync16(dir)) {
25335
+ const path = resolve22(dir, name);
25522
25336
  try {
25523
25337
  if (Date.now() - statSync(path).mtimeMs > maxAgeMs)
25524
- rmSync10(path, { force: true });
25338
+ rmSync9(path, { force: true });
25525
25339
  } catch {}
25526
25340
  }
25527
25341
  } catch {}
25528
25342
  }
25529
- 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");
25530
25344
  var init_macos_notifier = __esm(() => {
25531
25345
  init_fp_home();
25532
25346
  init_leak_fingerprint();
@@ -25548,7 +25362,7 @@ var DEFAULT_FETCH_TIMEOUT_MS = 15000;
25548
25362
 
25549
25363
  // src/hooks/cloud-enrollment.ts
25550
25364
  import { randomUUID as randomUUID3 } from "node:crypto";
25551
- 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";
25552
25366
  import { hostname as hostname4 } from "node:os";
25553
25367
  function cloudCredentialPath() {
25554
25368
  return process.env.FAILPROOFAI_CLOUD_CREDENTIALS ?? credentialsFile();
@@ -25587,10 +25401,10 @@ function readCloudCredentials() {
25587
25401
  if (!usingJsonOverride())
25588
25402
  return readCredentials().cloud ?? null;
25589
25403
  const path = cloudCredentialPath();
25590
- if (!existsSync29(path))
25404
+ if (!existsSync27(path))
25591
25405
  return null;
25592
25406
  try {
25593
- const raw = JSON.parse(readFileSync23(path, "utf8"));
25407
+ const raw = JSON.parse(readFileSync22(path, "utf8"));
25594
25408
  if (raw.schemaVersion !== SCHEMA_VERSION2)
25595
25409
  return null;
25596
25410
  if (typeof raw.url !== "string" || typeof raw.machineId !== "string" || typeof raw.token !== "string") {
@@ -25629,10 +25443,10 @@ function resolveMachineLabel(explicit) {
25629
25443
  function clearCloudCredentials() {
25630
25444
  if (usingJsonOverride()) {
25631
25445
  const path = cloudCredentialPath();
25632
- if (!existsSync29(path))
25446
+ if (!existsSync27(path))
25633
25447
  return false;
25634
25448
  try {
25635
- rmSync11(path);
25449
+ rmSync10(path);
25636
25450
  return true;
25637
25451
  } catch {
25638
25452
  return false;
@@ -25880,21 +25694,21 @@ var init_cloud_connection = __esm(() => {
25880
25694
  });
25881
25695
 
25882
25696
  // src/hooks/setup-state.ts
25883
- import { existsSync as existsSync30, realpathSync as realpathSync2, statSync as statSync18 } from "node:fs";
25884
- 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";
25885
25699
  import { homedir as homedir25 } from "node:os";
25886
25700
  function globalConfigPath(home = homedir25()) {
25887
25701
  return globalPolicyConfigFile(home);
25888
25702
  }
25889
25703
  function projectConfigPath(projectRoot) {
25890
- return resolve24(projectRoot, ".failproofai", "policies-config.json");
25704
+ return resolve23(projectRoot, ".failproofai", "policies-config.json");
25891
25705
  }
25892
25706
  function legacyMarkerPath(home) {
25893
25707
  return launcherMarker(home);
25894
25708
  }
25895
25709
  function isDir(path) {
25896
25710
  try {
25897
- return statSync18(path).isDirectory();
25711
+ return statSync17(path).isDirectory();
25898
25712
  } catch {
25899
25713
  return false;
25900
25714
  }
@@ -25903,14 +25717,14 @@ function findProjectRoot(start, home = homedir25()) {
25903
25717
  const resolvedHome = realResolve(home);
25904
25718
  let dir = realResolve(start);
25905
25719
  while (dir !== resolvedHome) {
25906
- if (isDir(resolve24(dir, ".failproofai")))
25720
+ if (isDir(resolve23(dir, ".failproofai")))
25907
25721
  return dir;
25908
- const parent = dirname15(dir);
25722
+ const parent = dirname14(dir);
25909
25723
  if (parent === dir)
25910
25724
  break;
25911
25725
  dir = parent;
25912
25726
  }
25913
- return resolve24(start);
25727
+ return resolve23(start);
25914
25728
  }
25915
25729
  function hasGlobalHooksInstalled() {
25916
25730
  for (const id of INTEGRATION_TYPES) {
@@ -25922,7 +25736,7 @@ function hasGlobalHooksInstalled() {
25922
25736
  return false;
25923
25737
  }
25924
25738
  function realResolve(path) {
25925
- const lexical = resolve24(path);
25739
+ const lexical = resolve23(path);
25926
25740
  try {
25927
25741
  return realpathSync2(lexical);
25928
25742
  } catch {
@@ -25937,10 +25751,10 @@ function detectSetupState(cwd = process.cwd(), home = homedir25()) {
25937
25751
  cwd: resolvedCwd,
25938
25752
  home: resolvedHome,
25939
25753
  projectRoot,
25940
- hasGlobalConfig: existsSync30(globalConfigPath(resolvedHome)),
25941
- hasProjectConfig: projectRoot !== resolvedHome && existsSync30(projectConfigPath(projectRoot)),
25754
+ hasGlobalConfig: existsSync28(globalConfigPath(resolvedHome)),
25755
+ hasProjectConfig: projectRoot !== resolvedHome && existsSync28(projectConfigPath(projectRoot)),
25942
25756
  hasGlobalHooks: hasGlobalHooksInstalled(),
25943
- hasLegacyMarker: existsSync30(legacyMarkerPath(resolvedHome)),
25757
+ hasLegacyMarker: existsSync28(legacyMarkerPath(resolvedHome)),
25944
25758
  inHomeDir: resolvedCwd === resolvedHome
25945
25759
  };
25946
25760
  }
@@ -25957,14 +25771,14 @@ var init_setup_state = __esm(() => {
25957
25771
  });
25958
25772
 
25959
25773
  // src/hooks/onboarding-attempt.ts
25960
- import { existsSync as existsSync31, mkdirSync as mkdirSync20, readFileSync as readFileSync24, rmSync as rmSync12, writeFileSync as writeFileSync17 } from "node:fs";
25961
- 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";
25962
25776
  function readOnboardingAttempt() {
25963
25777
  const path = onboardingAttemptFile();
25964
- if (!existsSync31(path))
25778
+ if (!existsSync29(path))
25965
25779
  return null;
25966
25780
  try {
25967
- const raw = JSON.parse(readFileSync24(path, "utf8"));
25781
+ const raw = JSON.parse(readFileSync23(path, "utf8"));
25968
25782
  if (raw.schemaVersion !== SCHEMA_VERSION3)
25969
25783
  return null;
25970
25784
  if (typeof raw.reason !== "string" || typeof raw.cliVersion !== "string")
@@ -25983,7 +25797,7 @@ function readOnboardingAttempt() {
25983
25797
  function recordOnboardingAttempt(reason, cliVersion, daemonStatus, now = Date.now()) {
25984
25798
  try {
25985
25799
  const path = onboardingAttemptFile();
25986
- mkdirSync20(dirname16(path), { recursive: true });
25800
+ mkdirSync18(dirname15(path), { recursive: true });
25987
25801
  const record = {
25988
25802
  schemaVersion: SCHEMA_VERSION3,
25989
25803
  reason,
@@ -25991,12 +25805,12 @@ function recordOnboardingAttempt(reason, cliVersion, daemonStatus, now = Date.no
25991
25805
  daemonStatus,
25992
25806
  at: now
25993
25807
  };
25994
- writeFileSync17(path, JSON.stringify(record, null, 2), "utf8");
25808
+ writeFileSync16(path, JSON.stringify(record, null, 2), "utf8");
25995
25809
  } catch {}
25996
25810
  }
25997
25811
  function clearOnboardingAttempt() {
25998
25812
  try {
25999
- rmSync12(onboardingAttemptFile(), { force: true });
25813
+ rmSync11(onboardingAttemptFile(), { force: true });
26000
25814
  } catch {}
26001
25815
  }
26002
25816
  function blockerCleared(attempt, probe) {
@@ -26038,7 +25852,7 @@ var init_onboarding_attempt = __esm(() => {
26038
25852
  });
26039
25853
 
26040
25854
  // src/hooks/onboarding-lock.ts
26041
- 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";
26042
25856
  import { homedir as homedir26 } from "node:os";
26043
25857
  function onboardingLockPath(home = homedir26()) {
26044
25858
  return onboardingLockFile(home);
@@ -26055,7 +25869,7 @@ function processAlive(pid) {
26055
25869
  }
26056
25870
  function readLock(path) {
26057
25871
  try {
26058
- const parsed = JSON.parse(readFileSync25(path, "utf8"));
25872
+ const parsed = JSON.parse(readFileSync24(path, "utf8"));
26059
25873
  if (typeof parsed.pid !== "number")
26060
25874
  return null;
26061
25875
  return { pid: parsed.pid, startedAt: Number(parsed.startedAt) || 0 };
@@ -26069,9 +25883,9 @@ function acquireOnboardingLock(home = homedir26()) {
26069
25883
  const held = readLock(path);
26070
25884
  if (held && held.pid !== process.pid && processAlive(held.pid))
26071
25885
  return null;
26072
- mkdirSync21(stateDir(home), { recursive: true });
25886
+ mkdirSync19(stateDir(home), { recursive: true });
26073
25887
  const body = { pid: process.pid, startedAt: Date.now() };
26074
- writeFileSync18(path, JSON.stringify(body), "utf8");
25888
+ writeFileSync17(path, JSON.stringify(body), "utf8");
26075
25889
  let released = false;
26076
25890
  return {
26077
25891
  release() {
@@ -26081,7 +25895,7 @@ function acquireOnboardingLock(home = homedir26()) {
26081
25895
  try {
26082
25896
  const current = readLock(path);
26083
25897
  if (!current || current.pid === process.pid)
26084
- rmSync13(path, { force: true });
25898
+ rmSync12(path, { force: true });
26085
25899
  } catch {}
26086
25900
  }
26087
25901
  };
@@ -26094,7 +25908,7 @@ var init_onboarding_lock = __esm(() => {
26094
25908
  });
26095
25909
 
26096
25910
  // lib/claude-sessions.ts
26097
- 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";
26098
25912
  import { join as join32, basename as basename6 } from "node:path";
26099
25913
  function getClaudeProjectsRoot() {
26100
25914
  return getClaudeProjectsPath();
@@ -26103,7 +25917,7 @@ function listClaudeProjects() {
26103
25917
  const root = getClaudeProjectsRoot();
26104
25918
  let entries;
26105
25919
  try {
26106
- entries = readdirSync18(root, { withFileTypes: true });
25920
+ entries = readdirSync17(root, { withFileTypes: true });
26107
25921
  } catch {
26108
25922
  return [];
26109
25923
  }
@@ -26118,7 +25932,7 @@ function collectSubagentTranscripts(dir, relPrefix, project, out, depth) {
26118
25932
  return;
26119
25933
  let entries;
26120
25934
  try {
26121
- entries = readdirSync18(dir, { withFileTypes: true });
25935
+ entries = readdirSync17(dir, { withFileTypes: true });
26122
25936
  } catch {
26123
25937
  return;
26124
25938
  }
@@ -26134,7 +25948,7 @@ function collectSubagentTranscripts(dir, relPrefix, project, out, depth) {
26134
25948
  const stem = entry.name.slice(0, -".jsonl".length);
26135
25949
  const transcriptPath = join32(dir, entry.name);
26136
25950
  try {
26137
- const s = statSync19(transcriptPath);
25951
+ const s = statSync18(transcriptPath);
26138
25952
  out.push({
26139
25953
  projectName: project.name,
26140
25954
  cwd: project.cwd,
@@ -26151,7 +25965,7 @@ function listClaudeTranscripts(project) {
26151
25965
  const out = [];
26152
25966
  let entries;
26153
25967
  try {
26154
- entries = readdirSync18(project.path, { withFileTypes: true });
25968
+ entries = readdirSync17(project.path, { withFileTypes: true });
26155
25969
  } catch {
26156
25970
  return out;
26157
25971
  }
@@ -26162,7 +25976,7 @@ function listClaudeTranscripts(project) {
26162
25976
  continue;
26163
25977
  const transcriptPath = join32(project.path, entry.name);
26164
25978
  try {
26165
- const s = statSync19(transcriptPath);
25979
+ const s = statSync18(transcriptPath);
26166
25980
  out.push({
26167
25981
  projectName: project.name,
26168
25982
  cwd: project.cwd,
@@ -26175,7 +25989,7 @@ function listClaudeTranscripts(project) {
26175
25989
  } catch {}
26176
25990
  } else if (entry.isDirectory() && UUID_RE2.test(entry.name)) {
26177
25991
  const subDir = join32(project.path, entry.name, "subagents");
26178
- if (!existsSync32(subDir))
25992
+ if (!existsSync30(subDir))
26179
25993
  continue;
26180
25994
  collectSubagentTranscripts(subDir, entry.name, project, out, 0);
26181
25995
  }
@@ -26241,6 +26055,7 @@ var init_shared = __esm(() => {
26241
26055
 
26242
26056
  // src/audit/cli-adapters/claude.ts
26243
26057
  import { readFile as readFile15, open as open2 } from "node:fs/promises";
26058
+ import { readFileSync as readFileSync25 } from "node:fs";
26244
26059
  async function listClaudeTranscriptMetadata(opts = {}) {
26245
26060
  const projectFilter = opts.projects ? new Set(opts.projects) : null;
26246
26061
  const sinceMs = opts.sinceMs ?? 0;
@@ -26257,13 +26072,22 @@ async function listClaudeTranscriptMetadata(opts = {}) {
26257
26072
  for (const t of transcripts) {
26258
26073
  if (t.mtimeMs < sinceMs)
26259
26074
  continue;
26075
+ let sessionDescription;
26076
+ if (t.isSubagent) {
26077
+ try {
26078
+ const meta = JSON.parse(readFileSync25(t.transcriptPath.replace(/\.jsonl$/, ".meta.json"), "utf8"));
26079
+ if (typeof meta.description === "string")
26080
+ sessionDescription = meta.description;
26081
+ } catch {}
26082
+ }
26260
26083
  out.push({
26261
26084
  cli: "claude",
26262
26085
  projectName: project.name,
26263
26086
  sessionId: t.sessionId,
26264
26087
  transcriptPath: t.transcriptPath,
26265
26088
  mtimeMs: t.mtimeMs,
26266
- sizeBytes: t.sizeBytes
26089
+ sizeBytes: t.sizeBytes,
26090
+ sessionDescription
26267
26091
  });
26268
26092
  }
26269
26093
  }
@@ -26382,7 +26206,7 @@ var init_claude = __esm(() => {
26382
26206
  });
26383
26207
 
26384
26208
  // src/audit/cli-adapters/codex.ts
26385
- import { statSync as statSync20 } from "node:fs";
26209
+ import { statSync as statSync19 } from "node:fs";
26386
26210
  async function listCodexTranscriptMetadata(opts = {}) {
26387
26211
  const projectFilter = opts.projects ? new Set(opts.projects) : null;
26388
26212
  const sinceMs = opts.sinceMs ?? 0;
@@ -26399,7 +26223,7 @@ async function listCodexTranscriptMetadata(opts = {}) {
26399
26223
  continue;
26400
26224
  let sizeBytes = 0;
26401
26225
  try {
26402
- sizeBytes = statSync20(s.path).size;
26226
+ sizeBytes = statSync19(s.path).size;
26403
26227
  } catch {}
26404
26228
  if (!s.sessionId)
26405
26229
  continue;
@@ -26433,7 +26257,7 @@ var init_codex = __esm(() => {
26433
26257
  });
26434
26258
 
26435
26259
  // src/audit/cli-adapters/copilot.ts
26436
- import { statSync as statSync21 } from "node:fs";
26260
+ import { statSync as statSync20 } from "node:fs";
26437
26261
  async function listCopilotTranscriptMetadata(opts = {}) {
26438
26262
  const projectFilter = opts.projects ? new Set(opts.projects) : null;
26439
26263
  const sinceMs = opts.sinceMs ?? 0;
@@ -26450,7 +26274,7 @@ async function listCopilotTranscriptMetadata(opts = {}) {
26450
26274
  continue;
26451
26275
  let sizeBytes = 0;
26452
26276
  try {
26453
- sizeBytes = statSync21(s.path).size;
26277
+ sizeBytes = statSync20(s.path).size;
26454
26278
  } catch {}
26455
26279
  if (!s.sessionId)
26456
26280
  continue;
@@ -26484,7 +26308,7 @@ var init_copilot = __esm(() => {
26484
26308
  });
26485
26309
 
26486
26310
  // src/audit/cli-adapters/cursor.ts
26487
- import { statSync as statSync22 } from "node:fs";
26311
+ import { statSync as statSync21 } from "node:fs";
26488
26312
  async function listCursorTranscriptMetadata(opts = {}) {
26489
26313
  const projectFilter = opts.projects ? new Set(opts.projects) : null;
26490
26314
  const sinceMs = opts.sinceMs ?? 0;
@@ -26501,7 +26325,7 @@ async function listCursorTranscriptMetadata(opts = {}) {
26501
26325
  continue;
26502
26326
  let sizeBytes = 0;
26503
26327
  try {
26504
- sizeBytes = statSync22(s.path).size;
26328
+ sizeBytes = statSync21(s.path).size;
26505
26329
  } catch {}
26506
26330
  if (!s.sessionId)
26507
26331
  continue;
@@ -26742,7 +26566,7 @@ var init_opencode = __esm(() => {
26742
26566
  });
26743
26567
 
26744
26568
  // src/audit/cli-adapters/pi.ts
26745
- import { statSync as statSync23 } from "node:fs";
26569
+ import { statSync as statSync22 } from "node:fs";
26746
26570
  async function listPiTranscriptMetadata(opts = {}) {
26747
26571
  const projectFilter = opts.projects ? new Set(opts.projects) : null;
26748
26572
  const sinceMs = opts.sinceMs ?? 0;
@@ -26759,7 +26583,7 @@ async function listPiTranscriptMetadata(opts = {}) {
26759
26583
  continue;
26760
26584
  let sizeBytes = 0;
26761
26585
  try {
26762
- sizeBytes = statSync23(s.path).size;
26586
+ sizeBytes = statSync22(s.path).size;
26763
26587
  } catch {}
26764
26588
  if (!s.sessionId)
26765
26589
  continue;
@@ -27493,6 +27317,276 @@ var init_features = __esm(() => {
27493
27317
  })();
27494
27318
  });
27495
27319
 
27320
+ // src/audit/leak-scan.ts
27321
+ function unquote(v) {
27322
+ return v.startsWith('"') && v.endsWith('"') || v.startsWith("'") && v.endsWith("'") ? v.slice(1, -1) : v;
27323
+ }
27324
+ function isDocsLiteral(value) {
27325
+ const { createHash } = __require("node:crypto");
27326
+ return DOCS_LITERALS.has(createHash("sha256").update(value).digest("hex"));
27327
+ }
27328
+ function isSelfOutput(text) {
27329
+ return SELF_OUTPUT_MARKERS.some((m) => text.includes(m));
27330
+ }
27331
+ function literalPrefixOf(source) {
27332
+ let out = "";
27333
+ for (let i = 0;i < source.length; i++) {
27334
+ const c = source[i];
27335
+ if (c === "\\") {
27336
+ const next = source[i + 1];
27337
+ if (next === undefined)
27338
+ break;
27339
+ if (/[dwsSDWbB]/.test(next))
27340
+ break;
27341
+ out += next;
27342
+ i++;
27343
+ continue;
27344
+ }
27345
+ if ("[](){}|?*+^$.".includes(c))
27346
+ break;
27347
+ out += c;
27348
+ }
27349
+ return out.length >= 2 ? out : null;
27350
+ }
27351
+ function applicablePatterns(text) {
27352
+ return GATED_PATTERNS.filter(([, , gate]) => gate === null || text.includes(gate));
27353
+ }
27354
+ function findSecrets(text) {
27355
+ if (!text)
27356
+ return [];
27357
+ if (isSelfOutput(text))
27358
+ return [];
27359
+ const byValue = new Map;
27360
+ for (const [pattern, label] of applicablePatterns(text)) {
27361
+ const re = new RegExp(pattern.source, pattern.flags.includes("g") ? pattern.flags : pattern.flags + "g");
27362
+ for (const m of text.matchAll(re)) {
27363
+ const value = m[0];
27364
+ if (isDocsLiteral(value))
27365
+ continue;
27366
+ if (!byValue.has(value))
27367
+ byValue.set(value, { value, name: null, rule: label, shaped: true });
27368
+ }
27369
+ }
27370
+ for (const m of text.matchAll(ASSIGNMENT_RE)) {
27371
+ const name = m[2];
27372
+ const value = unquote(m[4]);
27373
+ const existing = byValue.get(value);
27374
+ if (existing)
27375
+ existing.name ??= name;
27376
+ }
27377
+ return [...byValue.values()];
27378
+ }
27379
+ function flattenToolInput(input, depth = 0) {
27380
+ if (depth > 6 || input == null)
27381
+ return "";
27382
+ if (typeof input === "string")
27383
+ return input;
27384
+ if (typeof input === "number" || typeof input === "boolean")
27385
+ return String(input);
27386
+ if (Array.isArray(input))
27387
+ return input.map((v) => flattenToolInput(v, depth + 1)).join(`
27388
+ `);
27389
+ if (typeof input === "object") {
27390
+ return Object.entries(input).map(([k, v]) => `${k}=${flattenToolInput(v, depth + 1)}`).join(`
27391
+ `);
27392
+ }
27393
+ return "";
27394
+ }
27395
+ var LEAK_SCAN_VERSION = 6, ASSIGNMENT_RE, DOCS_LITERALS, SELF_OUTPUT_MARKERS, GATED_PATTERNS;
27396
+ var init_leak_scan = __esm(() => {
27397
+ init_builtin_policies();
27398
+ ASSIGNMENT_RE = /(["']?)\b([A-Za-z_][A-Za-z0-9_]{0,127})\1([ \t]*(?::(?!\/\/)|=)[ \t]*)("[^"]*"|'[^']*'|[^\s;|&"']+)/g;
27399
+ DOCS_LITERALS = new Set([
27400
+ "1a5d44a2dca19669d72edf4c4f1c27c4c1ca4b4408fbb17f6ce4ad452d78ddb3",
27401
+ "78314b11be2e581549ac1c4f616563fad3fdf0c3b71678f6e2299182080e0598",
27402
+ "cb20d34a7adda2f5d2043836051e242fd4c2b233e02c80c91fe9d5af9b100574",
27403
+ "3543c50b0cb9cea8e55eb1f529b79f043cb250d485fde7b66cabbb5183add7da",
27404
+ "1fae28c1b317300acfd90078c973567c8159015822b0c8b81508a5ec40517d20",
27405
+ "23219833092a3136d7ad178ccb62ebd6ac8cba54ff24c2cfcd37b84aba9e95cf",
27406
+ "872db7f4419592e397ef45230f910e06b48c36ed9970cf1f9e4fb896e69f129c",
27407
+ "78a08441f4314f0a2833cfe58c62e555a162264206982cda39f6804f5048f570",
27408
+ "2cafc0970149a84f3b9e62eaf169f36f59907a3b3e31f7b82e68c69cd27f7326",
27409
+ "b363ade84d56c43bebbc9339b4971e340e3f13f7f8d45580b53373d2763e9e33"
27410
+ ]);
27411
+ SELF_OUTPUT_MARKERS = [
27412
+ "[REDACTED:",
27413
+ "[redacted:",
27414
+ "failproofai audit",
27415
+ "assigned secret]"
27416
+ ];
27417
+ GATED_PATTERNS = SECRET_PATTERNS.map(([re, label]) => [re, label, literalPrefixOf(re.source)]);
27418
+ });
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
+
27496
27590
  // src/audit/redact-example.ts
27497
27591
  import { homedir as homedir27 } from "node:os";
27498
27592
  function maskTruncatedSecret(input) {
@@ -27529,7 +27623,7 @@ function isSecretName(name) {
27529
27623
  return components.length > 1 && components.some((part) => COMPOUND_ONLY_COMPONENTS.includes(part));
27530
27624
  }
27531
27625
  function maskAssignedSecrets(input) {
27532
- let out = input.replace(ASSIGNMENT_RE, (match, quote, name, separator, value) => {
27626
+ let out = input.replace(ASSIGNMENT_RE2, (match, quote, name, separator, value) => {
27533
27627
  if (!isSecretName(name))
27534
27628
  return match;
27535
27629
  if (value.startsWith("[REDACTED"))
@@ -27588,7 +27682,7 @@ function redactExample(input, home = homedir27()) {
27588
27682
  const collapsed = shortened.replace(/\s+/g, " ").trim();
27589
27683
  return collapsed.length > REDACTED_EXAMPLE_MAX_CHARS ? `${collapsed.slice(0, REDACTED_EXAMPLE_MAX_CHARS - 1)}…` : collapsed;
27590
27684
  }
27591
- var REDACTED_EXAMPLE_MAX_CHARS = 160, KEPT_PARENT_SEGMENTS = 0, ABSOLUTE_PATH_RE, PUBLIC_PATH_ROOTS, SECRET_PREFIXES, SECRET_NAME_SUBSTRINGS, SECRET_NAME_COMPONENTS, COMPOUND_ONLY_COMPONENTS, ASSIGNMENT_RE, URL_CREDENTIALS_RE, BASIC_AUTH_FLAG_RE, CLIENT_BUNDLE_PREFIXES, PUBLISHED_MARKERS;
27685
+ var REDACTED_EXAMPLE_MAX_CHARS = 160, KEPT_PARENT_SEGMENTS = 0, ABSOLUTE_PATH_RE, PUBLIC_PATH_ROOTS, SECRET_PREFIXES, SECRET_NAME_SUBSTRINGS, SECRET_NAME_COMPONENTS, COMPOUND_ONLY_COMPONENTS, ASSIGNMENT_RE2, URL_CREDENTIALS_RE, BASIC_AUTH_FLAG_RE, CLIENT_BUNDLE_PREFIXES, PUBLISHED_MARKERS;
27592
27686
  var init_redact_example = __esm(() => {
27593
27687
  init_builtin_policies();
27594
27688
  ABSOLUTE_PATH_RE = /(?:\/[\w.\-@+]+){2,}\/?/g;
@@ -27616,9 +27710,9 @@ var init_redact_example = __esm(() => {
27616
27710
  "APIKEY",
27617
27711
  "PRIVATEKEY"
27618
27712
  ];
27619
- SECRET_NAME_COMPONENTS = ["KEY", "PASS", "AUTH", "PAT", "SIG", "SIGNATURE", "SESSION", "COOKIE"];
27620
- COMPOUND_ONLY_COMPONENTS = ["PWD"];
27621
- ASSIGNMENT_RE = /(["']?)\b([A-Za-z_][A-Za-z0-9_]{0,127})\1([ \t]*(?::(?!\/\/)|=)[ \t]*)("[^"]*"|'[^']*'|[^\s;|&"']+)/g;
27713
+ SECRET_NAME_COMPONENTS = ["PASS", "AUTH", "PAT", "SIG", "SIGNATURE", "COOKIE"];
27714
+ COMPOUND_ONLY_COMPONENTS = ["PWD", "KEY"];
27715
+ ASSIGNMENT_RE2 = /(["']?)\b([A-Za-z_][A-Za-z0-9_]{0,127})\1([ \t]*(?::(?!\/\/)|=)[ \t]*)("[^"]*"|'[^']*'|[^\s;|&"']+)/g;
27622
27716
  URL_CREDENTIALS_RE = /([a-z][a-z0-9+.\-]{0,31}:\/\/)[^\s/:@]{1,256}:[^\s/@]{1,256}@/gi;
27623
27717
  BASIC_AUTH_FLAG_RE = /((?:^|\s)(?:-u|--user)[\s=])\S+:\S+/g;
27624
27718
  CLIENT_BUNDLE_PREFIXES = [
@@ -27634,136 +27728,9 @@ var init_redact_example = __esm(() => {
27634
27728
  PUBLISHED_MARKERS = /PUBLISHABLE|(^|_)PUBLIC_KEY$|(^|_)ANON_KEY$/;
27635
27729
  });
27636
27730
 
27637
- // src/audit/leak-scan.ts
27638
- function isNotACredential(value) {
27639
- if (value.length < MIN_VALUE_LEN)
27640
- return true;
27641
- if (/^[$<{(`%]/.test(value))
27642
- return true;
27643
- if (value.includes("${") || value.includes("{{") || value.includes("%("))
27644
- return true;
27645
- if (/^[A-Za-z_$][\w$]*(\.[A-Za-z_$][\w$]*)+$/.test(value))
27646
- return true;
27647
- if (value.includes("[REDACTED") || /^[•*#.]+$/.test(value))
27648
- return true;
27649
- if (/(.)\1{5,}/.test(value))
27650
- return true;
27651
- if (/^(true|false|null|undefined|none)$/i.test(value))
27652
- return true;
27653
- if (/^-?\d+(\.\d+)?$/.test(value))
27654
- return true;
27655
- if (/^\/|^~\/|^\.\.?\//.test(value))
27656
- return true;
27657
- return false;
27658
- }
27659
- function unquote(v) {
27660
- return v.startsWith('"') && v.endsWith('"') || v.startsWith("'") && v.endsWith("'") ? v.slice(1, -1) : v;
27661
- }
27662
- function isDocsLiteral(value) {
27663
- const { createHash } = __require("node:crypto");
27664
- return DOCS_LITERALS.has(createHash("sha256").update(value).digest("hex"));
27665
- }
27666
- function isSelfOutput(text) {
27667
- return SELF_OUTPUT_MARKERS.some((m) => text.includes(m));
27668
- }
27669
- function literalPrefixOf(source) {
27670
- let out = "";
27671
- for (let i = 0;i < source.length; i++) {
27672
- const c = source[i];
27673
- if (c === "\\") {
27674
- const next = source[i + 1];
27675
- if (next === undefined)
27676
- break;
27677
- if (/[dwsSDWbB]/.test(next))
27678
- break;
27679
- out += next;
27680
- i++;
27681
- continue;
27682
- }
27683
- if ("[](){}|?*+^$.".includes(c))
27684
- break;
27685
- out += c;
27686
- }
27687
- return out.length >= 2 ? out : null;
27688
- }
27689
- function applicablePatterns(text) {
27690
- return GATED_PATTERNS.filter(([, , gate]) => gate === null || text.includes(gate));
27691
- }
27692
- function findSecrets(text) {
27693
- if (!text)
27694
- return [];
27695
- if (isSelfOutput(text))
27696
- return [];
27697
- const byValue = new Map;
27698
- for (const [pattern, label] of applicablePatterns(text)) {
27699
- const re = new RegExp(pattern.source, pattern.flags.includes("g") ? pattern.flags : pattern.flags + "g");
27700
- for (const m of text.matchAll(re)) {
27701
- const value = m[0];
27702
- if (isDocsLiteral(value))
27703
- continue;
27704
- if (!byValue.has(value))
27705
- byValue.set(value, { value, name: null, rule: label, shaped: true });
27706
- }
27707
- }
27708
- for (const m of text.matchAll(ASSIGNMENT_RE2)) {
27709
- const name = m[2];
27710
- const value = unquote(m[4]);
27711
- if (!isSecretName(name) || isNotACredential(value) || isDocsLiteral(value))
27712
- continue;
27713
- const existing = byValue.get(value);
27714
- if (existing) {
27715
- existing.name ??= name;
27716
- continue;
27717
- }
27718
- byValue.set(value, { value, name, rule: "assigned secret", shaped: false });
27719
- }
27720
- return [...byValue.values()];
27721
- }
27722
- function flattenToolInput(input, depth = 0) {
27723
- if (depth > 6 || input == null)
27724
- return "";
27725
- if (typeof input === "string")
27726
- return input;
27727
- if (typeof input === "number" || typeof input === "boolean")
27728
- return String(input);
27729
- if (Array.isArray(input))
27730
- return input.map((v) => flattenToolInput(v, depth + 1)).join(`
27731
- `);
27732
- if (typeof input === "object") {
27733
- return Object.entries(input).map(([k, v]) => `${k}=${flattenToolInput(v, depth + 1)}`).join(`
27734
- `);
27735
- }
27736
- return "";
27737
- }
27738
- var ASSIGNMENT_RE2, MIN_VALUE_LEN = 8, DOCS_LITERALS, SELF_OUTPUT_MARKERS, GATED_PATTERNS;
27739
- var init_leak_scan = __esm(() => {
27740
- init_builtin_policies();
27741
- init_redact_example();
27742
- ASSIGNMENT_RE2 = /(["']?)\b([A-Za-z_][A-Za-z0-9_]{0,127})\1([ \t]*(?::(?!\/\/)|=)[ \t]*)("[^"]*"|'[^']*'|[^\s;|&"']+)/g;
27743
- DOCS_LITERALS = new Set([
27744
- "1a5d44a2dca19669d72edf4c4f1c27c4c1ca4b4408fbb17f6ce4ad452d78ddb3",
27745
- "78314b11be2e581549ac1c4f616563fad3fdf0c3b71678f6e2299182080e0598",
27746
- "cb20d34a7adda2f5d2043836051e242fd4c2b233e02c80c91fe9d5af9b100574",
27747
- "3543c50b0cb9cea8e55eb1f529b79f043cb250d485fde7b66cabbb5183add7da",
27748
- "1fae28c1b317300acfd90078c973567c8159015822b0c8b81508a5ec40517d20",
27749
- "23219833092a3136d7ad178ccb62ebd6ac8cba54ff24c2cfcd37b84aba9e95cf",
27750
- "872db7f4419592e397ef45230f910e06b48c36ed9970cf1f9e4fb896e69f129c",
27751
- "78a08441f4314f0a2833cfe58c62e555a162264206982cda39f6804f5048f570",
27752
- "2cafc0970149a84f3b9e62eaf169f36f59907a3b3e31f7b82e68c69cd27f7326",
27753
- "b363ade84d56c43bebbc9339b4971e340e3f13f7f8d45580b53373d2763e9e33"
27754
- ]);
27755
- SELF_OUTPUT_MARKERS = [
27756
- "[REDACTED:",
27757
- "[redacted:",
27758
- "failproofai audit",
27759
- "assigned secret]"
27760
- ];
27761
- GATED_PATTERNS = SECRET_PATTERNS.map(([re, label]) => [re, label, literalPrefixOf(re.source)]);
27762
- });
27763
-
27764
27731
  // src/audit/cache.ts
27765
27732
  import { createHash as createHash8 } from "node:crypto";
27766
- import { existsSync as existsSync33, mkdirSync as mkdirSync22, readFileSync as readFileSync26, 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";
27767
27734
  import { join as join33 } from "node:path";
27768
27735
  function getEngineVersion() {
27769
27736
  if (cachedEngineVersion)
@@ -27824,10 +27791,10 @@ function readCachedTranscript(transcriptPath, mtimeMs, sizeBytes) {
27824
27791
  if (sizeBytes === 0)
27825
27792
  return null;
27826
27793
  const cachePath = getCachePathFor(transcriptPath);
27827
- if (!existsSync33(cachePath))
27794
+ if (!existsSync32(cachePath))
27828
27795
  return null;
27829
27796
  try {
27830
- const raw = readFileSync26(cachePath, "utf-8");
27797
+ const raw = readFileSync27(cachePath, "utf-8");
27831
27798
  const entry = JSON.parse(raw);
27832
27799
  if (entry.schemaVersion !== CACHE_SCHEMA_VERSION)
27833
27800
  return null;
@@ -27835,6 +27802,8 @@ function readCachedTranscript(transcriptPath, mtimeMs, sizeBytes) {
27835
27802
  return null;
27836
27803
  if (entry.detectorVersion !== getDetectorVersion())
27837
27804
  return null;
27805
+ if (entry.leakScanVersion !== LEAK_SCAN_VERSION)
27806
+ return null;
27838
27807
  if (!Number.isFinite(entry.cachedAt) || Date.now() - entry.cachedAt > CACHE_TTL_MS)
27839
27808
  return null;
27840
27809
  if (!entry.result)
@@ -27866,7 +27835,7 @@ function writeCachedTranscriptResult(transcriptPath, mtimeMs, sizeBytes, result,
27866
27835
  return;
27867
27836
  const cachePath = getCachePathFor(transcriptPath);
27868
27837
  try {
27869
- mkdirSync22(auditCacheDir(), { recursive: true });
27838
+ mkdirSync21(auditCacheDir(), { recursive: true });
27870
27839
  const entry = {
27871
27840
  schemaVersion: CACHE_SCHEMA_VERSION,
27872
27841
  cachedAt: Date.now(),
@@ -27874,6 +27843,7 @@ function writeCachedTranscriptResult(transcriptPath, mtimeMs, sizeBytes, result,
27874
27843
  sizeBytes,
27875
27844
  engineVersion: getEngineVersion(),
27876
27845
  detectorVersion: getDetectorVersion(),
27846
+ leakScanVersion: LEAK_SCAN_VERSION,
27877
27847
  result
27878
27848
  };
27879
27849
  if (resume && resume.bytesScanned > 0) {
@@ -27884,7 +27854,7 @@ function writeCachedTranscriptResult(transcriptPath, mtimeMs, sizeBytes, result,
27884
27854
  entry.detectorState = encodeDetectorState(resume.detectorState);
27885
27855
  }
27886
27856
  }
27887
- writeFileSync19(cachePath, JSON.stringify(entry), { encoding: "utf-8", mode: 384 });
27857
+ writeFileSync18(cachePath, JSON.stringify(entry), { encoding: "utf-8", mode: 384 });
27888
27858
  try {
27889
27859
  chmodSync5(cachePath, 384);
27890
27860
  } catch {}
@@ -27894,6 +27864,7 @@ var cachedEngineVersion = null, cachedDetectorVersion = null, CACHE_SCHEMA_VERSI
27894
27864
  var init_cache = __esm(() => {
27895
27865
  init_builtin_policies();
27896
27866
  init_detectors();
27867
+ init_leak_scan();
27897
27868
  init_fp_home();
27898
27869
  CACHE_TTL_MS = 30 * 24 * 60 * 60000;
27899
27870
  });
@@ -27962,6 +27933,30 @@ var init_replay = __esm(() => {
27962
27933
  });
27963
27934
 
27964
27935
  // src/audit/index.ts
27936
+ class ByteGate {
27937
+ budget;
27938
+ inFlight = 0;
27939
+ waiting = [];
27940
+ constructor(budget) {
27941
+ this.budget = budget;
27942
+ }
27943
+ async acquire(bytes) {
27944
+ const want = Math.max(0, bytes);
27945
+ while (this.inFlight > 0 && this.inFlight + want > this.budget) {
27946
+ await new Promise((resolve) => this.waiting.push(resolve));
27947
+ }
27948
+ this.inFlight += want;
27949
+ }
27950
+ release(bytes) {
27951
+ this.inFlight -= Math.max(0, bytes);
27952
+ if (this.inFlight < 0)
27953
+ this.inFlight = 0;
27954
+ const waiters = this.waiting;
27955
+ this.waiting = [];
27956
+ for (const wake of waiters)
27957
+ wake();
27958
+ }
27959
+ }
27965
27960
  function shortPolicyName(name) {
27966
27961
  const slash = name.indexOf("/");
27967
27962
  return slash >= 0 ? name.slice(slash + 1) : name;
@@ -28003,6 +27998,27 @@ function parseSinceOpt(since) {
28003
27998
  return t;
28004
27999
  throw new Error(`Invalid --since value: "${since}" (expected e.g. "7d", "30d", or "2026-04-01")`);
28005
28000
  }
28001
+ function isCredentialResearchSession(events, sessionDescription) {
28002
+ if (sessionDescription && CREDENTIAL_RESEARCH_PURPOSE.test(sessionDescription))
28003
+ return true;
28004
+ const matched = new Set;
28005
+ let evidenceEvents = 0;
28006
+ for (const event of events) {
28007
+ const intent = flattenToolInput(event.toolInput);
28008
+ let eventMatched = false;
28009
+ for (let i = 0;i < CREDENTIAL_RESEARCH_MARKERS.length; i++) {
28010
+ if (CREDENTIAL_RESEARCH_MARKERS[i].test(intent)) {
28011
+ matched.add(i);
28012
+ eventMatched = true;
28013
+ }
28014
+ }
28015
+ if (eventMatched)
28016
+ evidenceEvents++;
28017
+ if (matched.size >= 2 || evidenceEvents >= 3)
28018
+ return true;
28019
+ }
28020
+ return false;
28021
+ }
28006
28022
  async function scanOneTranscript(meta, resume) {
28007
28023
  const empty = {
28008
28024
  transcriptPath: meta.transcriptPath,
@@ -28043,6 +28059,9 @@ async function scanOneTranscript(meta, resume) {
28043
28059
  const result = empty;
28044
28060
  result.eventsScanned = events.length;
28045
28061
  result.cwd = result.cwd || events[0].cwd || "";
28062
+ const suppressLeakScan = isCredentialResearchSession(events, meta.sessionDescription);
28063
+ if (suppressLeakScan)
28064
+ result.leakScanSuppressed = "credential-research";
28046
28065
  for (const event of events) {
28047
28066
  let replayHits;
28048
28067
  try {
@@ -28054,7 +28073,8 @@ async function scanOneTranscript(meta, resume) {
28054
28073
  const example = formatPolicyExample(hit.policyName, event);
28055
28074
  recordHit(result, hit.policyName, event.timestamp, event.cwd, truncateExample(example));
28056
28075
  }
28057
- recordLeaks(result, event);
28076
+ if (!suppressLeakScan)
28077
+ recordLeaks(result, event);
28058
28078
  }
28059
28079
  return { result, bytesScanned, detectorState: sessionState, resumed };
28060
28080
  }
@@ -28094,10 +28114,12 @@ function leakSalt() {
28094
28114
  }
28095
28115
  return cachedSalt;
28096
28116
  }
28097
- function persistLeaks(perTranscript) {
28117
+ function persistLeaks(perTranscript, replaceExisting) {
28098
28118
  const fresh = [];
28099
28119
  try {
28100
- const record = readLeakRecord();
28120
+ const previous = readLeakRecord();
28121
+ const previousIds = new Set(previous.findings.map((f) => f.id));
28122
+ const record = replaceExisting ? emptyRecord(previous.salt, new Date().toISOString()) : previous;
28101
28123
  for (const t of perTranscript) {
28102
28124
  for (const leak of t.leaks ?? []) {
28103
28125
  const { isNew } = upsertFinding(record, {
@@ -28114,7 +28136,7 @@ function persistLeaks(perTranscript) {
28114
28136
  mechanism: describeMechanism(leak.toolName, leak.direction, leak.path)
28115
28137
  }
28116
28138
  });
28117
- if (isNew)
28139
+ if (isNew && !previousIds.has(leak.id))
28118
28140
  fresh.push(leak.id);
28119
28141
  }
28120
28142
  }
@@ -28144,6 +28166,12 @@ function mergeIncremental(cached, tail) {
28144
28166
  examplesByName: {},
28145
28167
  rangeByName: { ...cached.rangeByName }
28146
28168
  };
28169
+ if (cached.leakScanSuppressed || tail.leakScanSuppressed) {
28170
+ out.leakScanSuppressed = "credential-research";
28171
+ out.leaks = [];
28172
+ } else {
28173
+ out.leaks = [...cached.leaks ?? [], ...tail.leaks ?? []];
28174
+ }
28147
28175
  for (const [name, list] of Object.entries(cached.examplesByName)) {
28148
28176
  out.examplesByName[name] = [...list];
28149
28177
  }
@@ -28267,16 +28295,19 @@ async function runAuditInner(opts, startedAt) {
28267
28295
  }
28268
28296
  } catch {}
28269
28297
  const allTranscripts = [];
28298
+ let discoveryErrors = 0;
28270
28299
  for (const cli of clis) {
28271
28300
  const adapter = ADAPTERS[cli];
28272
28301
  let list;
28273
28302
  try {
28274
28303
  list = await adapter.listTranscripts({ projects: opts.projects, sinceMs });
28275
28304
  } catch {
28305
+ discoveryErrors++;
28276
28306
  continue;
28277
28307
  }
28278
28308
  allTranscripts.push(...list);
28279
28309
  }
28310
+ const gate = new ByteGate(TRANSCRIPT_BYTE_BUDGET);
28280
28311
  let skipped = 0;
28281
28312
  let errors = 0;
28282
28313
  const tasks = allTranscripts.map((meta) => async () => {
@@ -28289,6 +28320,7 @@ async function runAuditInner(opts, startedAt) {
28289
28320
  resume = found?.kind === "resume" ? { fromByte: found.fromByte, detectorState: found.detectorState } : undefined;
28290
28321
  cachedPrefix = found?.kind === "resume" ? found.result : null;
28291
28322
  }
28323
+ await gate.acquire(meta.sizeBytes);
28292
28324
  try {
28293
28325
  const scan = await scanOneTranscript(meta, resume);
28294
28326
  const fresh = cachedPrefix && scan.resumed ? mergeIncremental(cachedPrefix, scan.result) : scan.result;
@@ -28311,6 +28343,8 @@ async function runAuditInner(opts, startedAt) {
28311
28343
  examplesByName: {},
28312
28344
  rangeByName: {}
28313
28345
  };
28346
+ } finally {
28347
+ gate.release(meta.sizeBytes);
28314
28348
  }
28315
28349
  });
28316
28350
  const settled = await batchAll(tasks, TRANSCRIPT_CONCURRENCY);
@@ -28337,9 +28371,12 @@ async function runAuditInner(opts, startedAt) {
28337
28371
  projectsScannedSet.add(t.cwd);
28338
28372
  eventsScanned += t.eventsScanned ?? 0;
28339
28373
  }
28340
- const newFindingIds = persistLeaks(perTranscript);
28374
+ const coversAllHistory = opts.clis === undefined && opts.projects === undefined && opts.since === undefined && discoveryErrors === 0 && errors === 0 && skipped === 0;
28375
+ const newFindingIds = persistLeaks(perTranscript, coversAllHistory);
28376
+ const leakIds = [...new Set(perTranscript.flatMap((t) => (t.leaks ?? []).map((leak) => leak.id)))];
28341
28377
  const auditResult = {
28342
28378
  version: 2,
28379
+ leakIds,
28343
28380
  newLeakIds: newFindingIds,
28344
28381
  scannedAt: new Date(startedAt).toISOString(),
28345
28382
  scope: {
@@ -28364,7 +28401,7 @@ async function runAuditInner(opts, startedAt) {
28364
28401
  };
28365
28402
  return auditResult;
28366
28403
  }
28367
- var TRANSCRIPT_CONCURRENCY = 8, cachedSalt;
28404
+ var TRANSCRIPT_CONCURRENCY = 8, TRANSCRIPT_BYTE_BUDGET, CREDENTIAL_RESEARCH_MARKERS, CREDENTIAL_RESEARCH_PURPOSE, cachedSalt;
28368
28405
  var init_audit = __esm(() => {
28369
28406
  init_builtin_policies();
28370
28407
  init_hooks_config();
@@ -28380,17 +28417,26 @@ var init_audit = __esm(() => {
28380
28417
  init_cache();
28381
28418
  init_replay();
28382
28419
  init_types2();
28420
+ TRANSCRIPT_BYTE_BUDGET = 48 * 1024 * 1024;
28421
+ CREDENTIAL_RESEARCH_MARKERS = [
28422
+ /\b(?:secret|credential)[-_ ](?:scanner|detection|detector|pattern|regex|corpus)\b/i,
28423
+ /\b(?:trufflehog|trufflesecurity|gitleaks|detect-secrets|secret-detection-rules)\b/i,
28424
+ /\b(?:SECRET_PATTERNS|findSecrets|isDocsLiteral|leak-scan)\b/,
28425
+ /\b(?:fixture|placeholder|synthetic|sample) (?:api )?(?:key|token|secret|credential)s?\b/i,
28426
+ /\b(?:grep|rg|ripgrep|scan|hunt|search)\b[^\n]{0,240}\b(?:secret|credential|token)s?\b/i
28427
+ ];
28428
+ CREDENTIAL_RESEARCH_PURPOSE = /\b(?:hunt|scan|search|research|test)(?:ing)?\b[^\n]{0,80}\b(?:secret|credential|token)s?\b|\b(?:secret|credential|token)s?\b[^\n]{0,80}\b(?:scanner|detector|detection|research|fixtures?|corpus)\b/i;
28383
28429
  });
28384
28430
 
28385
28431
  // src/audit/audit-lock.ts
28386
28432
  import {
28387
28433
  closeSync as closeSync2,
28388
28434
  linkSync,
28389
- mkdirSync as mkdirSync23,
28435
+ mkdirSync as mkdirSync22,
28390
28436
  openSync as openSync2,
28391
- readFileSync as readFileSync27,
28437
+ readFileSync as readFileSync28,
28392
28438
  unlinkSync as unlinkSync4,
28393
- writeFileSync as writeFileSync20,
28439
+ writeFileSync as writeFileSync19,
28394
28440
  writeSync
28395
28441
  } from "node:fs";
28396
28442
  function acquireAuditLock(source, now = Date.now()) {
@@ -28449,7 +28495,7 @@ function handleFor(path, info) {
28449
28495
  }
28450
28496
  function readLock2(path) {
28451
28497
  try {
28452
- const parsed = JSON.parse(readFileSync27(path, "utf8"));
28498
+ const parsed = JSON.parse(readFileSync28(path, "utf8"));
28453
28499
  if (typeof parsed?.pid !== "number" || typeof parsed?.startedAt !== "number")
28454
28500
  return null;
28455
28501
  return {
@@ -28465,7 +28511,7 @@ function writeLockExclusive(path, info) {
28465
28511
  const body = JSON.stringify(info);
28466
28512
  const staging = `${path}.${process.pid}.tmp`;
28467
28513
  try {
28468
- writeFileSync20(staging, body, { mode: 384 });
28514
+ writeFileSync19(staging, body, { mode: 384 });
28469
28515
  } catch {
28470
28516
  return false;
28471
28517
  }
@@ -28499,8 +28545,8 @@ function createThenWrite(path, body) {
28499
28545
  }
28500
28546
  }
28501
28547
  function ensureRunDir() {
28502
- mkdirSync23(failproofaiHome(), { recursive: true });
28503
- mkdirSync23(runDir(), { recursive: true, mode: 448 });
28548
+ mkdirSync22(failproofaiHome(), { recursive: true });
28549
+ mkdirSync22(runDir(), { recursive: true, mode: 448 });
28504
28550
  }
28505
28551
  var AUDIT_LOCK_MAX_AGE_MS;
28506
28552
  var init_audit_lock = __esm(() => {
@@ -28509,7 +28555,7 @@ var init_audit_lock = __esm(() => {
28509
28555
  });
28510
28556
 
28511
28557
  // src/audit/dashboard-cache.ts
28512
- import { existsSync as existsSync34, readFileSync as readFileSync28 } from "node:fs";
28558
+ import { existsSync as existsSync33, readFileSync as readFileSync29 } from "node:fs";
28513
28559
  function getCachePath() {
28514
28560
  return auditDashboardFile();
28515
28561
  }
@@ -28529,10 +28575,10 @@ function writeDashboardCache(params, result) {
28529
28575
  }
28530
28576
  function readDashboardCacheMeta() {
28531
28577
  const cachePath = getCachePath();
28532
- if (!existsSync34(cachePath))
28578
+ if (!existsSync33(cachePath))
28533
28579
  return null;
28534
28580
  try {
28535
- const raw = readFileSync28(cachePath, "utf-8");
28581
+ const raw = readFileSync29(cachePath, "utf-8");
28536
28582
  const entry = JSON.parse(raw);
28537
28583
  if (!entry || entry.schemaVersion !== DASHBOARD_CACHE_SCHEMA_VERSION || typeof entry.cachedAt !== "string" || Number.isNaN(new Date(entry.cachedAt).getTime()))
28538
28584
  return null;
@@ -28756,18 +28802,18 @@ var init_api_server_client = __esm(() => {
28756
28802
  });
28757
28803
 
28758
28804
  // lib/auth/auth-store.ts
28759
- import { existsSync as existsSync35, readFileSync as readFileSync29, readdirSync as readdirSync19, rmSync as rmSync14 } from "node:fs";
28760
- 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";
28761
28807
  function getAuthFilePath() {
28762
28808
  const override = process.env.FAILPROOFAI_AUTH_DIR;
28763
28809
  return override ? join34(override, "session.json") : auditSessionFile();
28764
28810
  }
28765
28811
  function readAuth() {
28766
28812
  const p = getAuthFilePath();
28767
- if (!existsSync35(p))
28813
+ if (!existsSync34(p))
28768
28814
  return null;
28769
28815
  try {
28770
- const raw = readFileSync29(p, "utf-8");
28816
+ const raw = readFileSync30(p, "utf-8");
28771
28817
  const parsed = JSON.parse(raw);
28772
28818
  if (typeof parsed.access_token !== "string" || typeof parsed.refresh_token !== "string" || typeof parsed.access_expires_at !== "number" || typeof parsed.user !== "object" || !parsed.user || typeof parsed.user.id !== "string" || typeof parsed.user.email !== "string") {
28773
28819
  return null;
@@ -28791,18 +28837,18 @@ function writeAuth(auth) {
28791
28837
  }
28792
28838
  function deleteAuth() {
28793
28839
  const p = getAuthFilePath();
28794
- if (existsSync35(p))
28795
- rmSync14(p, { force: true });
28840
+ if (existsSync34(p))
28841
+ rmSync13(p, { force: true });
28796
28842
  try {
28797
28843
  const root = migrationsDir();
28798
- if (!existsSync35(root))
28844
+ if (!existsSync34(root))
28799
28845
  return;
28800
- for (const entry of readdirSync19(root)) {
28846
+ for (const entry of readdirSync18(root)) {
28801
28847
  if (!entry.startsWith("backup-layout"))
28802
28848
  continue;
28803
- const copy = resolve25(root, entry, "auth.json");
28804
- if (existsSync35(copy))
28805
- rmSync14(copy, { force: true });
28849
+ const copy = resolve24(root, entry, "auth.json");
28850
+ if (existsSync34(copy))
28851
+ rmSync13(copy, { force: true });
28806
28852
  }
28807
28853
  } catch {}
28808
28854
  }
@@ -28934,7 +28980,11 @@ function selectLeaks(findings, from, to) {
28934
28980
  const last = ts(f.lastSeen);
28935
28981
  if (last !== null && (last < lo || last > hi))
28936
28982
  continue;
28937
- 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);
28938
28988
  out.push({
28939
28989
  id: f.id,
28940
28990
  display: f.fingerprint?.display ?? "[credential]",
@@ -28966,7 +29016,7 @@ function buildHarmReport(result, lastReportedAt, intervalDays, leakFindings = []
28966
29016
  window_from: from.toISOString(),
28967
29017
  window_to: windowTo.toISOString(),
28968
29018
  harmful: selectHarmful(result, from, windowTo, { includeUnplaceable: isFirstReport }),
28969
- leaks: selectLeaks(leakFindings, from, windowTo)
29019
+ leaks: selectLeaks(leakFindings, from, windowTo).slice(0, 1)
28970
29020
  };
28971
29021
  }
28972
29022
  var HARMFUL_SEVERITIES, ALSO_HARMFUL;
@@ -28977,15 +29027,15 @@ var init_harm_report = __esm(() => {
28977
29027
  });
28978
29028
 
28979
29029
  // src/audit/machine-store.ts
28980
- import { existsSync as existsSync36, readFileSync as readFileSync30, rmSync as rmSync15 } from "node:fs";
29030
+ import { existsSync as existsSync35, readFileSync as readFileSync31, rmSync as rmSync14 } from "node:fs";
28981
29031
  import { hostname as hostname5 } from "node:os";
28982
29032
  import { randomUUID as randomUUID4 } from "node:crypto";
28983
29033
  function readMachineIdentity(home) {
28984
29034
  const path = auditMachineFile(home);
28985
- if (!existsSync36(path))
29035
+ if (!existsSync35(path))
28986
29036
  return null;
28987
29037
  try {
28988
- const parsed = JSON.parse(readFileSync30(path, "utf8"));
29038
+ const parsed = JSON.parse(readFileSync31(path, "utf8"));
28989
29039
  if (typeof parsed.machine_id !== "string" || !parsed.machine_id)
28990
29040
  return null;
28991
29041
  return {
@@ -29031,20 +29081,20 @@ var init_machine_store = __esm(() => {
29031
29081
  // src/audit/report-harm.ts
29032
29082
  async function reportHarm(result) {
29033
29083
  let auto = false;
29034
- let consentedAt;
29035
29084
  let intervalDays = 7;
29036
29085
  try {
29037
29086
  const config = readConfig();
29038
29087
  auto = config.audit.auto;
29039
- consentedAt = config.audit.reportsConsentedAt;
29040
29088
  intervalDays = config.audit.intervalDays;
29041
29089
  } catch {
29042
29090
  return { kind: "disabled" };
29043
29091
  }
29044
29092
  if (!auto)
29045
29093
  return { kind: "disabled" };
29046
- if (consentedAt === undefined)
29047
- 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" };
29048
29098
  const auth = await getValidAccessToken();
29049
29099
  if (!auth) {
29050
29100
  return { kind: "signed-out" };
@@ -29055,8 +29105,6 @@ async function reportHarm(result) {
29055
29105
  } catch (err) {
29056
29106
  return { kind: "failed", error: err instanceof Error ? err.message : String(err) };
29057
29107
  }
29058
- const report = buildHarmReport(result, identity.last_reported_at, intervalDays, activeFindings(readLeakRecord()));
29059
- const hits = report.harmful.reduce((n, p) => n + p.hits, 0);
29060
29108
  try {
29061
29109
  const res = await submitAuditReport(auth.access_token, {
29062
29110
  machine_id: identity.machine_id,
@@ -29070,7 +29118,7 @@ async function reportHarm(result) {
29070
29118
  try {
29071
29119
  recordReportWatermark(res.next_window_from);
29072
29120
  } catch {}
29073
- 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" };
29074
29122
  } catch (err) {
29075
29123
  const error = err instanceof AuthApiError ? `${err.code}: ${err.message}` : err instanceof Error ? err.message : String(err);
29076
29124
  return { kind: "failed", error };
@@ -29079,17 +29127,16 @@ async function reportHarm(result) {
29079
29127
  function describeOutcome2(outcome) {
29080
29128
  switch (outcome.kind) {
29081
29129
  case "disabled":
29130
+ case "no-leak":
29082
29131
  return null;
29083
- case "consent-required":
29084
- 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";
29085
29132
  case "signed-out":
29086
- 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`";
29087
29134
  case "sent":
29088
- return `failproofai: emailed a harm digest (${outcome.hits} finding${outcome.hits === 1 ? "" : "s"})`;
29135
+ return "failproofai: emailed the most recent credential exposure";
29089
29136
  case "held":
29090
- return `failproofai: ${outcome.hits} finding${outcome.hits === 1 ? "" : "s"} reported, no email (${outcome.reason})`;
29137
+ return `failproofai: credential exposure reported, no email (${outcome.reason})`;
29091
29138
  case "failed":
29092
- return `failproofai: could not send the harm report: ${outcome.error}`;
29139
+ return `failproofai: could not send the credential alert: ${outcome.error}`;
29093
29140
  }
29094
29141
  }
29095
29142
  var init_report_harm = __esm(() => {
@@ -29363,6 +29410,15 @@ var init_desktop_notify = __esm(() => {
29363
29410
  ];
29364
29411
  });
29365
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
+
29366
29422
  // src/audit/cli.ts
29367
29423
  function colorOn() {
29368
29424
  if (process.env.NO_COLOR && process.env.NO_COLOR !== "")
@@ -29555,8 +29611,8 @@ var init_cli = __esm(() => {
29555
29611
  init_report_harm();
29556
29612
  init_desktop_notify();
29557
29613
  init_macos_notifier();
29558
- init_leak_notice();
29559
29614
  init_fp_config();
29615
+ init_auth_store();
29560
29616
  init_tui();
29561
29617
  init_package();
29562
29618
  AUDIT_STAGES = [
@@ -29575,9 +29631,9 @@ var init_cli = __esm(() => {
29575
29631
  });
29576
29632
 
29577
29633
  // src/hooks/configure-wizard.ts
29578
- import { existsSync as existsSync37, mkdirSync as mkdirSync24, writeFileSync as writeFileSync21, readFileSync as readFileSync31 } from "node:fs";
29634
+ import { existsSync as existsSync36, mkdirSync as mkdirSync23, writeFileSync as writeFileSync20, readFileSync as readFileSync32 } from "node:fs";
29579
29635
  import { homedir as homedir28 } from "node:os";
29580
- 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";
29581
29637
  async function emit(event, props) {
29582
29638
  try {
29583
29639
  await trackHookEvent2(getInstanceId2(), event, props);
@@ -29600,8 +29656,8 @@ function setCustomPoliciesEnabled(scope, cwd, enabled) {
29600
29656
  const path = getConfigPathForScope(scope, cwd);
29601
29657
  let config = {};
29602
29658
  try {
29603
- if (existsSync37(path))
29604
- config = JSON.parse(readFileSync31(path, "utf8"));
29659
+ if (existsSync36(path))
29660
+ config = JSON.parse(readFileSync32(path, "utf8"));
29605
29661
  } catch {
29606
29662
  return;
29607
29663
  }
@@ -29610,7 +29666,7 @@ function setCustomPoliciesEnabled(scope, cwd, enabled) {
29610
29666
  else
29611
29667
  config.customPoliciesEnabled = false;
29612
29668
  try {
29613
- writeFileSync21(path, JSON.stringify(config, null, 2) + `
29669
+ writeFileSync20(path, JSON.stringify(config, null, 2) + `
29614
29670
  `, "utf8");
29615
29671
  } catch {}
29616
29672
  }
@@ -29641,7 +29697,7 @@ function describeCustomPolicies(cwd) {
29641
29697
  const scopes = [];
29642
29698
  let fileCount = 0;
29643
29699
  const dirs = [
29644
- { dir: resolve26(cwd, ".failproofai", "policies"), label: "project" },
29700
+ { dir: resolve25(cwd, ".failproofai", "policies"), label: "project" },
29645
29701
  { dir: customPoliciesDir(), label: "global" }
29646
29702
  ];
29647
29703
  for (const { dir, label } of dirs) {
@@ -29652,7 +29708,7 @@ function describeCustomPolicies(cwd) {
29652
29708
  fileCount += found.length;
29653
29709
  }
29654
29710
  for (const name of findSkippedPolicyFiles(dir)) {
29655
- 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")}`);
29656
29712
  }
29657
29713
  }
29658
29714
  return { active, warnings, fileCount, scopes };
@@ -29745,8 +29801,8 @@ function firstRunMarkerPath() {
29745
29801
  }
29746
29802
  function markLauncherSeen() {
29747
29803
  try {
29748
- mkdirSync24(dirname17(firstRunMarkerPath()), { recursive: true });
29749
- writeFileSync21(firstRunMarkerPath(), "1", "utf8");
29804
+ mkdirSync23(dirname17(firstRunMarkerPath()), { recursive: true });
29805
+ writeFileSync20(firstRunMarkerPath(), "1", "utf8");
29750
29806
  } catch {}
29751
29807
  }
29752
29808
  function retryProbe() {
@@ -29824,6 +29880,8 @@ async function runConfigureWizard(io = {}, answers = {}) {
29824
29880
  const cwd = process.cwd();
29825
29881
  const unattended = !stdin.isTTY || !stdout.isTTY;
29826
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";
29827
29885
  if (typeof process.getuid === "function" && process.getuid() === 0 && process.env.SUDO_USER) {
29828
29886
  stdout.write(`Run failproofai config as ${process.env.SUDO_USER}, not under sudo.
29829
29887
  ` + `Everything it configures is per-user — hooks, policies and the daemon's own
@@ -30146,6 +30204,11 @@ Hooks keep enforcing; scheduled audits stay off until it is.
30146
30204
  }
30147
30205
  if (daemonInstalled) {
30148
30206
  setDaemonConfigured(true, version2);
30207
+ if (!hadExplicitAuditAuto) {
30208
+ try {
30209
+ updateConfig({ audit: { auto: true } });
30210
+ } catch {}
30211
+ }
30149
30212
  pruneOldDaemonBinaries();
30150
30213
  installMacNotifier();
30151
30214
  }
@@ -30235,21 +30298,22 @@ var init_configure_wizard = __esm(() => {
30235
30298
  init_package();
30236
30299
  init_onboarding_attempt();
30237
30300
  init_onboarding_lock();
30301
+ init_fp_config();
30238
30302
  POLICY_LIST_INDENT = " ".repeat(15);
30239
30303
  });
30240
30304
 
30241
30305
  // src/hooks/flush-cli.ts
30242
- 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";
30243
30307
  import { dirname as dirname18, join as join35 } from "node:path";
30244
30308
  function flushRequestPath2(home) {
30245
30309
  return join35(failproofaiHome(home), "state", "flush-request.json");
30246
30310
  }
30247
30311
  function spoolDirs2(home) {
30248
30312
  const root = spoolDir(home);
30249
- if (!existsSync38(root))
30313
+ if (!existsSync37(root))
30250
30314
  return [];
30251
30315
  try {
30252
- 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));
30253
30317
  } catch {
30254
30318
  return [];
30255
30319
  }
@@ -30258,7 +30322,7 @@ function pendingBatches2(home) {
30258
30322
  let n = 0;
30259
30323
  for (const dir of spoolDirs2(home)) {
30260
30324
  try {
30261
- n += readdirSync20(dir).filter((f) => f.endsWith(".jsonl")).length;
30325
+ n += readdirSync19(dir).filter((f) => f.endsWith(".jsonl")).length;
30262
30326
  } catch {}
30263
30327
  }
30264
30328
  return n;
@@ -30315,8 +30379,8 @@ async function runFlushCommand2(opts = {}) {
30315
30379
  return { exitCode: 0, pending: 0, lines: ["Nothing spooled — everything already delivered."] };
30316
30380
  }
30317
30381
  const path = flushRequestPath2(home);
30318
- mkdirSync25(dirname18(path), { recursive: true });
30319
- 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)}
30320
30384
  `, {
30321
30385
  mode: 384
30322
30386
  });
@@ -30347,7 +30411,7 @@ var init_flush_cli2 = __esm(() => {
30347
30411
  });
30348
30412
 
30349
30413
  // src/hooks/backfill-cli.ts
30350
- 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";
30351
30415
  import { dirname as dirname19, join as join36 } from "node:path";
30352
30416
  function backfillRequestPath(home) {
30353
30417
  return join36(failproofaiHome(home), "state", "backfill-request.json");
@@ -30356,7 +30420,7 @@ function surveySessions(sinceMs, homeDir) {
30356
30420
  const out = [];
30357
30421
  for (const { cli, dir } of SESSION_DIRS) {
30358
30422
  const root = join36(homeDir, dir);
30359
- if (!existsSync39(root))
30423
+ if (!existsSync38(root))
30360
30424
  continue;
30361
30425
  let files = 0;
30362
30426
  let newest = 0;
@@ -30365,7 +30429,7 @@ function surveySessions(sinceMs, homeDir) {
30365
30429
  return;
30366
30430
  let entries;
30367
30431
  try {
30368
- entries = readdirSync21(d, { withFileTypes: true });
30432
+ entries = readdirSync20(d, { withFileTypes: true });
30369
30433
  } catch {
30370
30434
  return;
30371
30435
  }
@@ -30376,7 +30440,7 @@ function surveySessions(sinceMs, homeDir) {
30376
30440
  continue;
30377
30441
  }
30378
30442
  try {
30379
- const st = statSync24(p);
30443
+ const st = statSync23(p);
30380
30444
  if (st.mtimeMs >= sinceMs) {
30381
30445
  files += 1;
30382
30446
  newest = Math.max(newest, st.mtimeMs);
@@ -30394,7 +30458,7 @@ function runBackfillCommand(opts = {}) {
30394
30458
  const now = opts.now ?? Date.now();
30395
30459
  const sinceMs = opts.sinceMs ?? now - DEFAULT_BACKFILL_DAYS * 24 * 60 * 60 * 1000;
30396
30460
  const home = failproofaiHome();
30397
- if (!existsSync39(home)) {
30461
+ if (!existsSync38(home)) {
30398
30462
  return {
30399
30463
  exitCode: 1,
30400
30464
  lines: [`No failproofai home at ${home}. Run \`failproofai config\` first.`]
@@ -30449,8 +30513,8 @@ function runBackfillCommand(opts = {}) {
30449
30513
  }
30450
30514
  try {
30451
30515
  const path = backfillRequestPath();
30452
- mkdirSync26(dirname19(path), { recursive: true });
30453
- 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)}
30454
30518
  `, {
30455
30519
  mode: 384
30456
30520
  });
@@ -30493,7 +30557,7 @@ var init_backfill_cli = __esm(() => {
30493
30557
 
30494
30558
  // src/hooks/harness-cli.ts
30495
30559
  import { homedir as homedir29 } from "node:os";
30496
- import { resolve as resolve27 } from "node:path";
30560
+ import { resolve as resolve26 } from "node:path";
30497
30561
  function unknownHarness(name) {
30498
30562
  return fail([
30499
30563
  `Unknown harness: ${name}`,
@@ -30537,7 +30601,7 @@ function comparableLabel(raw) {
30537
30601
  }
30538
30602
  function comparablePath(raw) {
30539
30603
  const home = homedir29();
30540
- 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;
30541
30605
  return expanded.replace(/\/+$/, "");
30542
30606
  }
30543
30607
  function effectiveLabel(entry) {
@@ -30725,7 +30789,7 @@ var init_harness_cli = __esm(() => {
30725
30789
  });
30726
30790
 
30727
30791
  // src/hooks/fp-config.ts
30728
- import { chmodSync as chmodSync6, existsSync as existsSync40, mkdirSync as mkdirSync27, readFileSync as readFileSync32, 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";
30729
30793
  function detectLayout2() {
30730
30794
  const raw = readVersionFile2();
30731
30795
  if (raw) {
@@ -30733,17 +30797,17 @@ function detectLayout2() {
30733
30797
  return { kind: "current", version: raw };
30734
30798
  return raw.layout > LAYOUT_VERSION ? { kind: "future", found: raw.layout } : { kind: "stale", found: raw.layout };
30735
30799
  }
30736
- if (existsSync40(configFile())) {
30800
+ if (existsSync39(configFile())) {
30737
30801
  const layoutThreePositions = [
30738
30802
  legacy.authJson(),
30739
30803
  legacy.nextAudit(),
30740
30804
  legacy.auditSchedule()
30741
30805
  ];
30742
- if (layoutThreePositions.some((p) => existsSync40(p)))
30806
+ if (layoutThreePositions.some((p) => existsSync39(p)))
30743
30807
  return { kind: "stale", found: 3 };
30744
30808
  return { kind: "current", version: { layout: LAYOUT_VERSION, cli: "" }, inferred: true };
30745
30809
  }
30746
- if (existsSync40(legacy.configToml()))
30810
+ if (existsSync39(legacy.configToml()))
30747
30811
  return { kind: "stale", found: 2 };
30748
30812
  const layoutOneMarkers = [
30749
30813
  legacy.policyConfig(),
@@ -30754,7 +30818,7 @@ function detectLayout2() {
30754
30818
  legacy.ingestCredentials(),
30755
30819
  legacy.auditDashboard()
30756
30820
  ];
30757
- 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" };
30758
30822
  }
30759
30823
  function readLegacyTomlVersion2(text) {
30760
30824
  const layout = Number(/^\s*layout\s*=\s*(\d+)\s*$/m.exec(text)?.[1]);
@@ -30766,7 +30830,7 @@ function readLegacyTomlVersion2(text) {
30766
30830
  function readVersionFile2() {
30767
30831
  let text;
30768
30832
  try {
30769
- text = readFileSync32(versionFile(), "utf8");
30833
+ text = readFileSync33(versionFile(), "utf8");
30770
30834
  } catch {
30771
30835
  return null;
30772
30836
  }
@@ -30797,14 +30861,14 @@ var init_fp_home2 = () => {};
30797
30861
  import {
30798
30862
  chmodSync as chmodSync7,
30799
30863
  copyFileSync as copyFileSync3,
30800
- existsSync as existsSync41,
30801
- mkdirSync as mkdirSync28,
30802
- readFileSync as readFileSync33,
30864
+ existsSync as existsSync40,
30865
+ mkdirSync as mkdirSync27,
30866
+ readFileSync as readFileSync34,
30803
30867
  renameSync as renameSync9,
30804
- rmSync as rmSync16,
30805
- writeFileSync as writeFileSync25
30868
+ rmSync as rmSync15,
30869
+ writeFileSync as writeFileSync24
30806
30870
  } from "node:fs";
30807
- 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";
30808
30872
  function migrateToLayout42() {
30809
30873
  const moves = [
30810
30874
  { from: legacy.authJson(), to: auditSessionFile() },
@@ -30820,13 +30884,13 @@ function migrateToLayout42() {
30820
30884
  }
30821
30885
  const migrated = [];
30822
30886
  for (const { from, to } of moves) {
30823
- if (!existsSync41(from))
30887
+ if (!existsSync40(from))
30824
30888
  continue;
30825
- if (existsSync41(to)) {
30826
- rmSync16(from, { force: true });
30889
+ if (existsSync40(to)) {
30890
+ rmSync15(from, { force: true });
30827
30891
  continue;
30828
30892
  }
30829
- mkdirSync28(dirname20(to), { recursive: true });
30893
+ mkdirSync27(dirname20(to), { recursive: true });
30830
30894
  try {
30831
30895
  renameSync9(from, to);
30832
30896
  } catch {
@@ -30834,16 +30898,16 @@ function migrateToLayout42() {
30834
30898
  copyFileSync3(from, to);
30835
30899
  } catch (err) {
30836
30900
  try {
30837
- rmSync16(to, { force: true });
30901
+ rmSync15(to, { force: true });
30838
30902
  } catch {}
30839
30903
  throw err;
30840
30904
  }
30841
- rmSync16(from, { force: true });
30905
+ rmSync15(from, { force: true });
30842
30906
  }
30843
30907
  migrated.push(`${basename7(from)} → audit/${basename7(to)}`);
30844
30908
  }
30845
30909
  for (const secret of [auditSessionFile()]) {
30846
- if (!existsSync41(secret))
30910
+ if (!existsSync40(secret))
30847
30911
  continue;
30848
30912
  try {
30849
30913
  chmodSync7(secret, 384);
@@ -30869,7 +30933,7 @@ function planMigration2(from, registry = MIGRATIONS2) {
30869
30933
  }
30870
30934
  function readLedger2() {
30871
30935
  try {
30872
- const parsed = JSON.parse(readFileSync33(migrationLedgerFile(), "utf8"));
30936
+ const parsed = JSON.parse(readFileSync34(migrationLedgerFile(), "utf8"));
30873
30937
  return Array.isArray(parsed) ? parsed : [];
30874
30938
  } catch {
30875
30939
  return [];
@@ -30877,9 +30941,9 @@ function readLedger2() {
30877
30941
  }
30878
30942
  function appendLedger2(entry) {
30879
30943
  try {
30880
- mkdirSync28(migrationsDir(), { recursive: true });
30944
+ mkdirSync27(migrationsDir(), { recursive: true });
30881
30945
  const all = [...readLedger2(), entry];
30882
- writeFileSync25(migrationLedgerFile(), `${JSON.stringify(all, null, 2)}
30946
+ writeFileSync24(migrationLedgerFile(), `${JSON.stringify(all, null, 2)}
30883
30947
  `, "utf8");
30884
30948
  } catch {}
30885
30949
  }
@@ -30891,12 +30955,12 @@ function pruneMigratedCredentials2(from) {
30891
30955
  for (let layout = from;layout < LAYOUT_VERSION; layout++) {
30892
30956
  for (const { as, landsAt } of PRUNED_AFTER_SUCCESS2) {
30893
30957
  try {
30894
- if (!existsSync41(landsAt()))
30958
+ if (!existsSync40(landsAt()))
30895
30959
  continue;
30896
- const copy = resolve28(migrationBackupDir(layout), as);
30897
- if (!existsSync41(copy))
30960
+ const copy = resolve27(migrationBackupDir(layout), as);
30961
+ if (!existsSync40(copy))
30898
30962
  continue;
30899
- rmSync16(copy, { force: true });
30963
+ rmSync15(copy, { force: true });
30900
30964
  pruned.push(as);
30901
30965
  } catch {}
30902
30966
  }
@@ -30907,7 +30971,7 @@ function filesToBackUp2() {
30907
30971
  const seen = new Map;
30908
30972
  for (const f of [...BACKED_UP2, ...BACKED_UP_LEGACY2]) {
30909
30973
  const path = f.at();
30910
- if (existsSync41(path))
30974
+ if (existsSync40(path))
30911
30975
  seen.set(path, backupNameOf2(f));
30912
30976
  }
30913
30977
  return [...seen].map(([path, as]) => ({ path, as }));
@@ -30916,14 +30980,14 @@ function backupBeforeMigrating2(from) {
30916
30980
  const dir = migrationBackupDir(from);
30917
30981
  const saved = [];
30918
30982
  try {
30919
- rmSync16(dir, { recursive: true, force: true });
30920
- mkdirSync28(dir, { recursive: true });
30983
+ rmSync15(dir, { recursive: true, force: true });
30984
+ mkdirSync27(dir, { recursive: true });
30921
30985
  } catch {
30922
30986
  return [];
30923
30987
  }
30924
30988
  for (const { path: source, as } of filesToBackUp2()) {
30925
30989
  try {
30926
- copyFileSync3(source, resolve28(dir, as));
30990
+ copyFileSync3(source, resolve27(dir, as));
30927
30991
  saved.push(as);
30928
30992
  } catch {}
30929
30993
  }
@@ -31061,16 +31125,16 @@ var init_migrations2 = __esm(() => {
31061
31125
 
31062
31126
  // src/hooks/daemon-service.ts
31063
31127
  import {
31064
- existsSync as existsSync42,
31065
- mkdirSync as mkdirSync29,
31128
+ existsSync as existsSync41,
31129
+ mkdirSync as mkdirSync28,
31066
31130
  mkdtempSync as mkdtempSync2,
31067
- readFileSync as readFileSync34,
31068
- writeFileSync as writeFileSync26,
31131
+ readFileSync as readFileSync35,
31132
+ writeFileSync as writeFileSync25,
31069
31133
  unlinkSync as unlinkSync5,
31070
- rmSync as rmSync17
31134
+ rmSync as rmSync16
31071
31135
  } from "node:fs";
31072
31136
  import { homedir as homedir30, tmpdir as tmpdir3, userInfo as userInfo2 } from "node:os";
31073
- import { resolve as resolve29 } from "node:path";
31137
+ import { resolve as resolve28 } from "node:path";
31074
31138
  import { execFileSync as execFileSync4 } from "node:child_process";
31075
31139
  function isDaemonSupportedPlatform2() {
31076
31140
  return process.platform === "linux" || process.platform === "darwin";
@@ -31086,13 +31150,13 @@ function resolveFailproofaidBinaryPath2() {
31086
31150
  if (process.env.FAILPROOFAI_DAEMON_BINARY)
31087
31151
  return process.env.FAILPROOFAI_DAEMON_BINARY;
31088
31152
  const downloaded = installedBinaryPath();
31089
- if (existsSync42(downloaded))
31153
+ if (existsSync41(downloaded))
31090
31154
  return downloaded;
31091
31155
  const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT;
31092
31156
  if (packageRoot) {
31093
31157
  for (const profile of ["release", "debug"]) {
31094
- const candidate = resolve29(packageRoot, "target", profile, "failproofaid");
31095
- if (existsSync42(candidate))
31158
+ const candidate = resolve28(packageRoot, "target", profile, "failproofaid");
31159
+ if (existsSync41(candidate))
31096
31160
  return candidate;
31097
31161
  }
31098
31162
  }
@@ -31122,8 +31186,8 @@ function resolveWorkerCommand2() {
31122
31186
  const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT;
31123
31187
  if (!packageRoot)
31124
31188
  return null;
31125
- const workerScript = resolve29(packageRoot, "dist", "worker.mjs");
31126
- if (!existsSync42(workerScript))
31189
+ const workerScript = resolve28(packageRoot, "dist", "worker.mjs");
31190
+ if (!existsSync41(workerScript))
31127
31191
  return null;
31128
31192
  return `${shellQuote2(process.execPath)} ${shellQuote2(workerScript)}`;
31129
31193
  }
@@ -31133,8 +31197,8 @@ function resolveCliCommand2() {
31133
31197
  const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT;
31134
31198
  if (!packageRoot)
31135
31199
  return null;
31136
- const cliScript = resolve29(packageRoot, "dist", "cli.mjs");
31137
- if (!existsSync42(cliScript))
31200
+ const cliScript = resolve28(packageRoot, "dist", "cli.mjs");
31201
+ if (!existsSync41(cliScript))
31138
31202
  return null;
31139
31203
  return `${shellQuote2(process.execPath)} ${shellQuote2(cliScript)}`;
31140
31204
  }
@@ -31147,8 +31211,8 @@ function workerScriptPath2() {
31147
31211
  const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT;
31148
31212
  if (!packageRoot)
31149
31213
  return null;
31150
- const workerScript = resolve29(packageRoot, "dist", "worker.mjs");
31151
- return existsSync42(workerScript) ? workerScript : null;
31214
+ const workerScript = resolve28(packageRoot, "dist", "worker.mjs");
31215
+ return existsSync41(workerScript) ? workerScript : null;
31152
31216
  }
31153
31217
  function assertUnitSafe2(value, field) {
31154
31218
  if (UNIT_UNSAFE_RE2.test(value)) {
@@ -31174,10 +31238,10 @@ function systemdUnitDir2() {
31174
31238
  return process.env.FAILPROOFAI_SYSTEMD_DIR || "/etc/systemd/system";
31175
31239
  }
31176
31240
  function systemdUnitPath2(user = serviceUser2()) {
31177
- return resolve29(systemdUnitDir2(), systemdUnitName2(user));
31241
+ return resolve28(systemdUnitDir2(), systemdUnitName2(user));
31178
31242
  }
31179
31243
  function legacySystemdUserUnitPath2() {
31180
- return resolve29(homedir30(), ".config", "systemd", "user", "failproofaid.service");
31244
+ return resolve28(homedir30(), ".config", "systemd", "user", "failproofaid.service");
31181
31245
  }
31182
31246
  function launchdLabel2(user = serviceUser2()) {
31183
31247
  return `ai.failproof.failproofaid.${user}`;
@@ -31186,7 +31250,7 @@ function launchdPlistPath2(user = serviceUser2()) {
31186
31250
  return `/Library/LaunchDaemons/${launchdLabel2(user)}.plist`;
31187
31251
  }
31188
31252
  function legacyLaunchAgentPlistPath2() {
31189
- return resolve29(homedir30(), "Library", "LaunchAgents", "ai.failproof.failproofaid.plist");
31253
+ return resolve28(homedir30(), "Library", "LaunchAgents", "ai.failproof.failproofaid.plist");
31190
31254
  }
31191
31255
  function legacySharedLaunchDaemonPath2() {
31192
31256
  return "/Library/LaunchDaemons/ai.failproof.failproofaid.plist";
@@ -31224,20 +31288,20 @@ function runPrivileged2(command, args) {
31224
31288
  execFileSync4(cmd, argv, { stdio: "ignore", timeout: SERVICE_CMD_TIMEOUT_MS2 });
31225
31289
  }
31226
31290
  function writePrivilegedFile2(destination, contents, mode = "0644") {
31227
- const stagingDir = mkdtempSync2(resolve29(tmpdir3(), "failproofaid-stage-"));
31228
- const staging = resolve29(stagingDir, "service-definition");
31291
+ const stagingDir = mkdtempSync2(resolve28(tmpdir3(), "failproofaid-stage-"));
31292
+ const staging = resolve28(stagingDir, "service-definition");
31229
31293
  try {
31230
- writeFileSync26(staging, contents, "utf8");
31294
+ writeFileSync25(staging, contents, "utf8");
31231
31295
  runPrivileged2("install", ["-m", mode, staging, destination]);
31232
31296
  } finally {
31233
- rmSync17(stagingDir, { recursive: true, force: true });
31297
+ rmSync16(stagingDir, { recursive: true, force: true });
31234
31298
  }
31235
31299
  }
31236
31300
  function removeLegacyUserService2() {
31237
31301
  try {
31238
31302
  if (process.platform === "linux") {
31239
31303
  const legacy = legacySystemdUserUnitPath2();
31240
- if (!existsSync42(legacy))
31304
+ if (!existsSync41(legacy))
31241
31305
  return;
31242
31306
  try {
31243
31307
  execFileSync4("systemctl", ["--user", "disable", "--now", "failproofaid.service"], {
@@ -31254,7 +31318,7 @@ function removeLegacyUserService2() {
31254
31318
  } catch {}
31255
31319
  } else {
31256
31320
  const legacyAgent = legacyLaunchAgentPlistPath2();
31257
- if (existsSync42(legacyAgent)) {
31321
+ if (existsSync41(legacyAgent)) {
31258
31322
  try {
31259
31323
  execFileSync4("launchctl", ["unload", "-w", legacyAgent], {
31260
31324
  stdio: "ignore",
@@ -31264,7 +31328,7 @@ function removeLegacyUserService2() {
31264
31328
  unlinkSync5(legacyAgent);
31265
31329
  }
31266
31330
  const legacyDaemon = legacySharedLaunchDaemonPath2();
31267
- if (existsSync42(legacyDaemon)) {
31331
+ if (existsSync41(legacyDaemon)) {
31268
31332
  try {
31269
31333
  runPrivileged2("launchctl", ["unload", "-w", legacyDaemon]);
31270
31334
  } catch {}
@@ -31281,7 +31345,7 @@ function systemdUnitContents2(binaryPath, workerCmd, cliCmd = null) {
31281
31345
  const user = assertUnitSafe2(serviceUser2(), "User");
31282
31346
  assertUnitSafe2(binaryPath, "ExecStart");
31283
31347
  assertUnitSafe2(homedir30(), "HOME");
31284
- const conditionPaths = [binaryPath, workerScriptPath2()].filter((p) => typeof p === "string" && existsSync42(p));
31348
+ const conditionPaths = [binaryPath, workerScriptPath2()].filter((p) => typeof p === "string" && existsSync41(p));
31285
31349
  const conditionLines = conditionPaths.map((p) => `ConditionPathExists=${assertUnitSafe2(p, "ConditionPathExists")}
31286
31350
  `).join("");
31287
31351
  return `[Unit]
@@ -31339,9 +31403,9 @@ ${env.map(([key, value]) => ` <key>${key}</key>
31339
31403
  <key>UserName</key>
31340
31404
  <string>${escapeXml3(serviceUser2())}</string>
31341
31405
  ${envBlock} <key>StandardOutPath</key>
31342
- <string>${escapeXml3(resolve29(logDir, "failproofaid.log"))}</string>
31406
+ <string>${escapeXml3(resolve28(logDir, "failproofaid.log"))}</string>
31343
31407
  <key>StandardErrorPath</key>
31344
- <string>${escapeXml3(resolve29(logDir, "failproofaid.err.log"))}</string>
31408
+ <string>${escapeXml3(resolve28(logDir, "failproofaid.err.log"))}</string>
31345
31409
  </dict>
31346
31410
  </plist>
31347
31411
  `;
@@ -31387,7 +31451,7 @@ async function installDaemonService2() {
31387
31451
  } else {
31388
31452
  const plistPath = launchdPlistPath2();
31389
31453
  const logDir = logsDir();
31390
- mkdirSync29(logDir, { recursive: true });
31454
+ mkdirSync28(logDir, { recursive: true });
31391
31455
  try {
31392
31456
  runPrivileged2("launchctl", ["unload", plistPath]);
31393
31457
  } catch {}
@@ -31486,7 +31550,7 @@ function daemonServiceStatus2() {
31486
31550
  if (!isDaemonSupportedPlatform2())
31487
31551
  return "unsupported-platform";
31488
31552
  if (process.platform === "linux") {
31489
- if (!existsSync42(systemdUnitPath2()))
31553
+ if (!existsSync41(systemdUnitPath2()))
31490
31554
  return "not-installed";
31491
31555
  try {
31492
31556
  const out = execFileSync4("systemctl", ["is-active", systemdUnitName2()], {
@@ -31499,7 +31563,7 @@ function daemonServiceStatus2() {
31499
31563
  }
31500
31564
  }
31501
31565
  const plistPath = launchdPlistPath2();
31502
- if (!existsSync42(plistPath))
31566
+ if (!existsSync41(plistPath))
31503
31567
  return "not-installed";
31504
31568
  try {
31505
31569
  const root = typeof process.getuid === "function" && process.getuid() === 0;
@@ -31529,7 +31593,7 @@ var init_daemon_service2 = __esm(() => {
31529
31593
  });
31530
31594
 
31531
31595
  // src/hooks/uninstall-cli.ts
31532
- import { existsSync as existsSync43, rmSync as rmSync18 } from "node:fs";
31596
+ import { existsSync as existsSync42, rmSync as rmSync17 } from "node:fs";
31533
31597
  function survey(cwd) {
31534
31598
  const clis = [];
31535
31599
  for (const id of listInstallableIds()) {
@@ -31550,9 +31614,9 @@ function survey(cwd) {
31550
31614
  return {
31551
31615
  clis,
31552
31616
  servicePath,
31553
- serviceInstalled: !!servicePath && existsSync43(servicePath),
31617
+ serviceInstalled: !!servicePath && existsSync42(servicePath),
31554
31618
  daemonConfigured,
31555
- homeExists: existsSync43(failproofaiHome())
31619
+ homeExists: existsSync42(failproofaiHome())
31556
31620
  };
31557
31621
  }
31558
31622
  async function runUninstallCommand(opts = {}) {
@@ -31650,7 +31714,7 @@ async function runUninstallCommand(opts = {}) {
31650
31714
  } catch {}
31651
31715
  try {
31652
31716
  await uninstallDaemonService();
31653
- if (found.servicePath && existsSync43(found.servicePath)) {
31717
+ if (found.servicePath && existsSync42(found.servicePath)) {
31654
31718
  failures.push(`the service at ${found.servicePath} is still there (most often: no sudo). ` + `Remove it with the commands below.`);
31655
31719
  } else {
31656
31720
  lines.push(`✓ stopped and removed the daemon service`);
@@ -31665,7 +31729,7 @@ async function runUninstallCommand(opts = {}) {
31665
31729
  }
31666
31730
  if (opts.purge && found.homeExists) {
31667
31731
  try {
31668
- rmSync18(failproofaiHome(), { recursive: true, force: true });
31732
+ rmSync17(failproofaiHome(), { recursive: true, force: true });
31669
31733
  purged = true;
31670
31734
  lines.push(`✓ deleted ${failproofaiHome()}`);
31671
31735
  } catch (err) {
@@ -31676,7 +31740,7 @@ async function runUninstallCommand(opts = {}) {
31676
31740
  lines.push(``, `Not everything could be removed:`);
31677
31741
  for (const f of failures)
31678
31742
  lines.push(` ✗ ${f}`);
31679
- if (found.servicePath && existsSync43(found.servicePath)) {
31743
+ if (found.servicePath && existsSync42(found.servicePath)) {
31680
31744
  lines.push(``, `To remove the service by hand:`, ...manualServiceRemoval(found.servicePath), ``, `(\`${daemonStatusCommand()}\` shows its current state.)`);
31681
31745
  }
31682
31746
  return { exitCode: 1, lines, planLines, purged };
@@ -31711,8 +31775,8 @@ var init_uninstall_cli = __esm(() => {
31711
31775
  import { execFileSync as execFileSync5 } from "node:child_process";
31712
31776
  import { homedir as homedir31, tmpdir as tmpdir4 } from "node:os";
31713
31777
  import { createHash as createHash9 } from "node:crypto";
31714
- import { copyFileSync as copyFileSync4, existsSync as existsSync44, mkdirSync as mkdirSync30, mkdtempSync as mkdtempSync3, readFileSync as readFileSync35, readdirSync as readdirSync22, realpathSync as realpathSync3, rmSync as rmSync19, statSync as statSync26, writeFileSync as writeFileSync27 } from "node:fs";
31715
- 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";
31716
31780
  function parseList(rest, flag) {
31717
31781
  const idx = rest.findIndex((a) => a === flag || a.startsWith(`${flag}=`));
31718
31782
  if (idx === -1)
@@ -31812,7 +31876,7 @@ async function build(rest) {
31812
31876
  const version = flag("version");
31813
31877
  const commit = flag("commit");
31814
31878
  const effect = flag("effect") ?? "enforce";
31815
- const outDir = resolve30(flag("out") ?? "dist-pack");
31879
+ const outDir = resolve29(flag("out") ?? "dist-pack");
31816
31880
  if (!entry || !id || !version) {
31817
31881
  return fail2([
31818
31882
  "Usage: failproofai publish <entry.mjs> --repo <owner>/<repo> --version <version>",
@@ -31825,10 +31889,10 @@ async function build(rest) {
31825
31889
  } catch (err) {
31826
31890
  return fail2([err instanceof Error ? err.message : String(err)]);
31827
31891
  }
31828
- const entryPath = resolve30(entry);
31829
- if (!existsSync44(entryPath))
31892
+ const entryPath = resolve29(entry);
31893
+ if (!existsSync43(entryPath))
31830
31894
  return fail2([`No such file: ${entryPath}`]);
31831
- const source = readFileSync35(entryPath, "utf8");
31895
+ const source = readFileSync36(entryPath, "utf8");
31832
31896
  const localImport = /(?:^|\n)\s*(?:import|export)[^;\n]*from\s+["'](\.[^"']*)["']/.exec(source);
31833
31897
  if (localImport) {
31834
31898
  return fail2([
@@ -31884,14 +31948,14 @@ async function build(rest) {
31884
31948
  policies
31885
31949
  }, null, 2) + `
31886
31950
  `;
31887
- mkdirSync30(outDir, { recursive: true });
31888
- const manifestPath = resolve30(outDir, PACK_MANIFEST_ASSET);
31889
- const entryOut = resolve30(outDir, PACK_ENTRY_ASSET);
31890
- 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");
31891
31955
  copyFileSync4(entryPath, entryOut);
31892
31956
  const sha = (bytes) => createHash9("sha256").update(bytes).digest("hex");
31893
- writeFileSync27(resolve30(outDir, PACK_CHECKSUMS_ASSET), `${sha(manifest)} ${PACK_MANIFEST_ASSET}
31894
- ${sha(readFileSync35(entryOut))} ${PACK_ENTRY_ASSET}
31957
+ writeFileSync26(resolve29(outDir, PACK_CHECKSUMS_ASSET), `${sha(manifest)} ${PACK_MANIFEST_ASSET}
31958
+ ${sha(readFileSync36(entryOut))} ${PACK_ENTRY_ASSET}
31895
31959
  `, "utf8");
31896
31960
  const on = policies.filter((p) => p.defaultEnabled).length;
31897
31961
  return ok2([
@@ -32020,12 +32084,12 @@ async function scaffold(target) {
32020
32084
  return ok2(["Nothing written."]);
32021
32085
  chosen = answer.trim();
32022
32086
  }
32023
- const path = resolve30(withPolicyExtension(chosen ?? "my-policies"));
32024
- if (existsSync44(path)) {
32087
+ const path = resolve29(withPolicyExtension(chosen ?? "my-policies"));
32088
+ if (existsSync43(path)) {
32025
32089
  return fail2([`${path} already exists — name a different file, or edit that one.`]);
32026
32090
  }
32027
- mkdirSync30(resolve30(path, ".."), { recursive: true });
32028
- writeFileSync27(path, `import { customPolicies, allow, deny } from "failproofai";
32091
+ mkdirSync29(resolve29(path, ".."), { recursive: true });
32092
+ writeFileSync26(path, `import { customPolicies, allow, deny } from "failproofai";
32029
32093
 
32030
32094
  // One file, no relative imports: only this entry is digest-pinned, so a pack
32031
32095
  // that imported siblings could not honestly claim to be verified.
@@ -32062,7 +32126,7 @@ customPolicies.add({
32062
32126
  function inferRepo(entryPath) {
32063
32127
  try {
32064
32128
  const url = execFileSync5("git", ["remote", "get-url", "origin"], {
32065
- cwd: resolve30(entryPath, ".."),
32129
+ cwd: resolve29(entryPath, ".."),
32066
32130
  encoding: "utf8",
32067
32131
  stdio: ["ignore", "pipe", "ignore"],
32068
32132
  timeout: 5000
@@ -32074,7 +32138,7 @@ function inferRepo(entryPath) {
32074
32138
  }
32075
32139
  }
32076
32140
  function inferCommit(entryPath, outDir, sources) {
32077
- const cwd = resolve30(entryPath, "..");
32141
+ const cwd = resolve29(entryPath, "..");
32078
32142
  const raw = (args) => {
32079
32143
  try {
32080
32144
  return execFileSync5("git", args, {
@@ -32129,9 +32193,9 @@ function realOrSelf(path) {
32129
32193
  }
32130
32194
  }
32131
32195
  function sourcesInHead(git, raw, sources) {
32132
- const paths = sources.map((f) => realOrSelf(resolve30(f)));
32196
+ const paths = sources.map((f) => realOrSelf(resolve29(f)));
32133
32197
  const shown = git(["rev-parse", "--show-toplevel"]);
32134
- const top = shown === null ? null : realOrSelf(resolve30(shown));
32198
+ const top = shown === null ? null : realOrSelf(resolve29(shown));
32135
32199
  const missing = [];
32136
32200
  for (const path of paths) {
32137
32201
  const rel = top ? relative5(top, path) : null;
@@ -32155,7 +32219,7 @@ function sourcesInHead(git, raw, sources) {
32155
32219
  ]);
32156
32220
  if (status === null)
32157
32221
  return { ok: false, offending: paths, why: "modified" };
32158
- 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)));
32159
32223
  if (dirty.length > 0)
32160
32224
  return { ok: false, offending: dirty, why: "modified" };
32161
32225
  return { ok: true };
@@ -32163,19 +32227,19 @@ function sourcesInHead(git, raw, sources) {
32163
32227
  function skipOutDir(git, entryPath, outDir) {
32164
32228
  if (!outDir)
32165
32229
  return [];
32166
- const out = resolve30(outDir);
32167
- if (resolve30(entryPath).startsWith(out + sep6))
32230
+ const out = resolve29(outDir);
32231
+ if (resolve29(entryPath).startsWith(out + sep6))
32168
32232
  return [];
32169
32233
  const top = git(["rev-parse", "--show-toplevel"]);
32170
32234
  if (!top)
32171
32235
  return [];
32172
- const rel = relative5(resolve30(top), out);
32236
+ const rel = relative5(resolve29(top), out);
32173
32237
  if (!rel || rel.startsWith("..") || isAbsolute4(rel))
32174
32238
  return [];
32175
32239
  return ["--", ":(top)", `:(exclude,literal,top)${rel.split(sep6).join("/")}`];
32176
32240
  }
32177
32241
  function inferTaggedVersion(entryPath, sources) {
32178
- const cwd = resolve30(entryPath, "..");
32242
+ const cwd = resolve29(entryPath, "..");
32179
32243
  const raw = (args) => {
32180
32244
  try {
32181
32245
  return execFileSync5("git", args, {
@@ -32205,7 +32269,7 @@ function inferTaggedVersion(entryPath, sources) {
32205
32269
  function findEntry(dir) {
32206
32270
  let names;
32207
32271
  try {
32208
- names = readdirSync22(dir);
32272
+ names = readdirSync21(dir);
32209
32273
  } catch {
32210
32274
  return [];
32211
32275
  }
@@ -32213,11 +32277,11 @@ function findEntry(dir) {
32213
32277
  for (const name of names) {
32214
32278
  if (!/\.(mjs|js|ts)$/.test(name))
32215
32279
  continue;
32216
- const full = resolve30(dir, name);
32280
+ const full = resolve29(dir, name);
32217
32281
  try {
32218
- if (statSync26(full).size > 512 * 1024)
32282
+ if (statSync25(full).size > 512 * 1024)
32219
32283
  continue;
32220
- const text = readFileSync35(full, "utf8");
32284
+ const text = readFileSync36(full, "utf8");
32221
32285
  if (/from\s+["']failproofai["']/.test(text) && /customPolicies\s*\.\s*add\s*\(/.test(text)) {
32222
32286
  found.push(full);
32223
32287
  }
@@ -32228,27 +32292,27 @@ function findEntry(dir) {
32228
32292
  return found.sort();
32229
32293
  }
32230
32294
  function withLocalImports(sources) {
32231
- const seen = new Set(sources.map((f) => resolve30(f)));
32295
+ const seen = new Set(sources.map((f) => resolve29(f)));
32232
32296
  const queue = [...seen];
32233
32297
  while (queue.length > 0 && seen.size < 500) {
32234
32298
  const file = queue.shift();
32235
32299
  let text;
32236
32300
  try {
32237
- if (statSync26(file).size > 512 * 1024)
32301
+ if (statSync25(file).size > 512 * 1024)
32238
32302
  continue;
32239
- text = readFileSync35(file, "utf8");
32303
+ text = readFileSync36(file, "utf8");
32240
32304
  } catch {
32241
32305
  continue;
32242
32306
  }
32243
32307
  for (const re of LOCAL_IMPORT_RES) {
32244
32308
  for (const match of text.matchAll(re)) {
32245
- const base = resolve30(dirname21(file), match[1]);
32309
+ const base = resolve29(dirname21(file), match[1]);
32246
32310
  for (const ext of LOCAL_IMPORT_EXTENSIONS) {
32247
32311
  const candidate = base + ext;
32248
32312
  if (seen.has(candidate))
32249
32313
  break;
32250
32314
  try {
32251
- if (!statSync26(candidate).isFile())
32315
+ if (!statSync25(candidate).isFile())
32252
32316
  continue;
32253
32317
  } catch {
32254
32318
  continue;
@@ -32263,7 +32327,7 @@ function withLocalImports(sources) {
32263
32327
  return [...seen];
32264
32328
  }
32265
32329
  function settleGitState(entryPath, provenance, packFiles, id, outDir) {
32266
- const cwd = resolve30(entryPath, "..");
32330
+ const cwd = resolve29(entryPath, "..");
32267
32331
  const raw = (args) => {
32268
32332
  try {
32269
32333
  return execFileSync5("git", args, {
@@ -32338,11 +32402,11 @@ function settleGitState(entryPath, provenance, packFiles, id, outDir) {
32338
32402
  if (root === null || status === null)
32339
32403
  return null;
32340
32404
  const entries = porcelainEntries(status);
32341
- const dirty = entries.map((entry) => resolve30(root, entry.path));
32342
- 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));
32343
32407
  if (dirty.length === 0)
32344
32408
  return null;
32345
- const mine = new Set(packFiles.map((f) => resolve30(f)));
32409
+ const mine = new Set(packFiles.map((f) => resolve29(f)));
32346
32410
  const foreign = dirty.filter((path) => !mine.has(path));
32347
32411
  const toStage = [...dirty, ...renamedFrom];
32348
32412
  if (foreign.length > 0) {
@@ -32475,7 +32539,7 @@ function pushExistingHistory(dir, owner, name, token) {
32475
32539
  return false;
32476
32540
  const askpass = join38(mkdtempSync3(join38(tmpdir4(), "fpai-askpass-")), "askpass.sh");
32477
32541
  try {
32478
- writeFileSync27(askpass, `#!/bin/sh
32542
+ writeFileSync26(askpass, `#!/bin/sh
32479
32543
  case "$1" in
32480
32544
  *Username*) echo x-access-token ;;
32481
32545
  *) echo "$FPAI_GH_TOKEN" ;;
@@ -32495,7 +32559,7 @@ esac
32495
32559
  return true;
32496
32560
  } finally {
32497
32561
  try {
32498
- rmSync19(dirname21(askpass), { recursive: true, force: true });
32562
+ rmSync18(dirname21(askpass), { recursive: true, force: true });
32499
32563
  } catch {}
32500
32564
  }
32501
32565
  }
@@ -32519,8 +32583,8 @@ failproofai policies add ${owner}/${name}
32519
32583
  function findBun() {
32520
32584
  const candidates = [
32521
32585
  "bun",
32522
- process.env.BUN_INSTALL ? resolve30(process.env.BUN_INSTALL, "bin", "bun") : null,
32523
- resolve30(homedir31(), ".bun", "bin", "bun"),
32586
+ process.env.BUN_INSTALL ? resolve29(process.env.BUN_INSTALL, "bin", "bun") : null,
32587
+ resolve29(homedir31(), ".bun", "bin", "bun"),
32524
32588
  "/opt/homebrew/bin/bun",
32525
32589
  "/usr/local/bin/bun"
32526
32590
  ].filter((c) => c !== null);
@@ -32546,12 +32610,12 @@ function bundleEntry(sources, outDir) {
32546
32610
  ]
32547
32611
  };
32548
32612
  }
32549
- mkdirSync30(outDir, { recursive: true });
32550
- const entry = resolve30(outDir, ".entry.generated.mjs");
32551
- 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(`
32552
32616
  `) + `
32553
32617
  `, "utf8");
32554
- const bundled = resolve30(outDir, ".bundled.mjs");
32618
+ const bundled = resolve29(outDir, ".bundled.mjs");
32555
32619
  try {
32556
32620
  execFileSync5(bun, [
32557
32621
  "build",
@@ -32669,7 +32733,7 @@ async function publish(rest) {
32669
32733
  `);
32670
32734
  const token = githubToken();
32671
32735
  const login = token ? await credentialLogin(token) : null;
32672
- const folder = basename8(resolve30(entry, ".."));
32736
+ const folder = basename8(resolve29(entry, ".."));
32673
32737
  const answered = await askWhereToPublish(`${login ?? "your-account"}/${folder}`, { stdin: process.stdin, stdout: process.stdout });
32674
32738
  if (answered === null)
32675
32739
  return ok2(["Nothing was published."]);
@@ -32680,7 +32744,7 @@ async function publish(rest) {
32680
32744
  let versionFromSha = false;
32681
32745
  const dryRun = rest.includes("--dry-run") || !repo;
32682
32746
  const allowPrivate = rest.includes("--allow-private");
32683
- 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);
32684
32748
  const [owner, name] = (repo ?? "/").split("/");
32685
32749
  if (repo && (!owner || !name || repo.split("/").length !== 2)) {
32686
32750
  return fail2([`--repo must be <owner>/<repo>, got ${JSON.stringify(repo)}`]);
@@ -32699,7 +32763,7 @@ async function publish(rest) {
32699
32763
  "With no --repo it writes the three release assets and stops."
32700
32764
  ]);
32701
32765
  }
32702
- const outDirEarly = resolve30(flag("out") ?? "dist-pack");
32766
+ const outDirEarly = resolve29(flag("out") ?? "dist-pack");
32703
32767
  let provenance = entry ? inferCommit(entry, outDirEarly, bundledSources) : null;
32704
32768
  const gitLines = [];
32705
32769
  if (!version && entry && interactive) {
@@ -32739,7 +32803,7 @@ async function publish(rest) {
32739
32803
  "It needs write access to releases on that repository, and nothing else."
32740
32804
  ]);
32741
32805
  }
32742
- const ensured = await ensureRepo(owner, name, id, token, resolve30(entry, ".."));
32806
+ const ensured = await ensureRepo(owner, name, id, token, resolve29(entry, ".."));
32743
32807
  if ("error" in ensured)
32744
32808
  return fail2(ensured.error);
32745
32809
  created = ensured.created;
@@ -32759,7 +32823,7 @@ async function publish(rest) {
32759
32823
  }
32760
32824
  const tag = flag("tag") ?? version;
32761
32825
  let entryToBuild = entry;
32762
- const needsBundle = discovered.length > 1 || /(?:^|\n)\s*(?:import|export)[^;\n]*from\s+["']\.[^"']*["']/.test(readFileSync35(entry, "utf8"));
32826
+ const needsBundle = discovered.length > 1 || /(?:^|\n)\s*(?:import|export)[^;\n]*from\s+["']\.[^"']*["']/.test(readFileSync36(entry, "utf8"));
32763
32827
  if (needsBundle) {
32764
32828
  const sources = discovered.length > 1 ? discovered : [entry];
32765
32829
  const bundled = bundleEntry(sources, outDirEarly);
@@ -32838,7 +32902,7 @@ async function publish(rest) {
32838
32902
  if (prior) {
32839
32903
  await gh(`${GITHUB_API2}/repos/${owner}/${name}/releases/assets/${prior.id}`, auth, { method: "DELETE" });
32840
32904
  }
32841
- const bytes = readFileSync35(resolve30(outDir, asset));
32905
+ const bytes = readFileSync36(resolve29(outDir, asset));
32842
32906
  const upload = await gh(`${GITHUB_UPLOADS2}/repos/${owner}/${name}/releases/${releaseId}/assets?name=${encodeURIComponent(asset)}`, auth, {
32843
32907
  method: "POST",
32844
32908
  contentType: asset.endsWith(".json") ? "application/json" : "application/octet-stream",
@@ -33519,8 +33583,8 @@ var init_install_prompt = __esm(() => {
33519
33583
 
33520
33584
  // src/hooks/manager.ts
33521
33585
  import { execSync as execSync7 } from "node:child_process";
33522
- import { existsSync as existsSync45 } from "node:fs";
33523
- 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";
33524
33588
  import { platform as platform4, arch as arch4, release as release3, hostname as hostname6 } from "node:os";
33525
33589
  function getSettingsPath2(scope, cwd) {
33526
33590
  return claudeCode.getSettingsPath(scope, cwd);
@@ -33739,9 +33803,9 @@ async function installHooksImpl2(policyNames, scope = "user", cwd, includeBeta =
33739
33803
  delete configToWrite.customPoliciesPath;
33740
33804
  delete configToWrite.customPoliciesPaths;
33741
33805
  } else if (customPoliciesPath && (typeof customPoliciesPath === "string" || customPoliciesPath.length > 0)) {
33742
- const incoming = (typeof customPoliciesPath === "string" ? [customPoliciesPath] : customPoliciesPath).map((path) => resolve31(path));
33743
- const carried = (previousConfig.customPoliciesPaths ?? (previousConfig.customPoliciesPath ? [previousConfig.customPoliciesPath] : [])).map((path) => resolve31(path)).filter((path) => {
33744
- 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))
33745
33809
  return true;
33746
33810
  console.log(`Dropping custom policies path (file no longer exists): ${path}`);
33747
33811
  return false;
@@ -33964,7 +34028,7 @@ async function removeHooks2(policyNames, scope = "user", cwd, opts) {
33964
34028
  const scopesToRemove = scope === "all" ? [...integration.scopes] : integration.scopes.includes(scope) ? [scope] : [];
33965
34029
  for (const s of scopesToRemove) {
33966
34030
  const settingsPaths = settingsPathsFor(integration, s, cwd);
33967
- const existing = settingsPaths.filter((p) => existsSync45(p));
34031
+ const existing = settingsPaths.filter((p) => existsSync44(p));
33968
34032
  if (existing.length === 0) {
33969
34033
  if (scope !== "all" && selectedClis.length === 1) {
33970
34034
  console.log("No settings file found. Nothing to remove.");
@@ -34108,9 +34172,9 @@ async function listHooks(cwd) {
34108
34172
  if (explicitPaths.length > 0) {
34109
34173
  groups.push(rule("Custom Policies", opts));
34110
34174
  for (const path of explicitPaths) {
34111
- const absPath = resolve31(findProjectConfigDir(cwd ?? process.cwd()), path);
34175
+ const absPath = resolve30(findProjectConfigDir(cwd ?? process.cwd()), path);
34112
34176
  groups.push(note(absPath, opts));
34113
- if (!existsSync45(absPath)) {
34177
+ if (!existsSync44(absPath)) {
34114
34178
  groups.push(warning([`file not found: ${absPath}`], opts));
34115
34179
  continue;
34116
34180
  }
@@ -34130,7 +34194,7 @@ async function listHooks(cwd) {
34130
34194
  }
34131
34195
  }
34132
34196
  const base = findProjectConfigDir(cwd ?? process.cwd());
34133
- const projectDir = resolve31(base, ".failproofai", "policies");
34197
+ const projectDir = resolve30(base, ".failproofai", "policies");
34134
34198
  const userDir = customPoliciesDir();
34135
34199
  const sameDir = userDir === projectDir;
34136
34200
  const conventionDirs = [
@@ -34242,11 +34306,11 @@ var init_manager2 = __esm(() => {
34242
34306
  });
34243
34307
 
34244
34308
  // src/audit/audit-schedule.ts
34245
- import { readFileSync as readFileSync36 } from "node:fs";
34309
+ import { readFileSync as readFileSync37 } from "node:fs";
34246
34310
  function readAuditSchedule(home) {
34247
34311
  let raw;
34248
34312
  try {
34249
- raw = readFileSync36(auditScheduleFile(home), "utf8");
34313
+ raw = readFileSync37(auditScheduleFile(home), "utf8");
34250
34314
  } catch {
34251
34315
  return null;
34252
34316
  }
@@ -34310,7 +34374,9 @@ async function ensureSignedIn(preset) {
34310
34374
  }
34311
34375
  if (!canPrompt()) {
34312
34376
  throw new LoginError(`Signing in needs an interactive terminal, and this one is not.
34313
- ` + "Run `failproofai audit --schedule` from a shell you are sitting at,\n" + "or sign in from the dashboard — both write the same session file.");
34377
+ ` + "Run `failproofai audit --schedule` from a shell you are sitting at,\n" + `or sign in from the dashboard — both write the same session file.
34378
+ ` + `
34379
+ ` + "`--email` does not avoid this: it fills in the address so you are not\n" + "asked for it, but a one-time code is still sent there for you to paste.");
34314
34380
  }
34315
34381
  return { user: await runLogin(preset), prompted: true };
34316
34382
  }
@@ -34434,21 +34500,20 @@ async function runScheduleOn(daysArg, emailArg) {
34434
34500
  if (bad)
34435
34501
  throw new ScheduleCliError(bad);
34436
34502
  }
34437
- const { user, prompted } = await ensureSignedIn(emailArg);
34503
+ const signedIn = emailArg === undefined ? { user: readAuth()?.user ?? null, prompted: false } : await ensureSignedIn(emailArg);
34438
34504
  const next = updateConfig({
34439
34505
  audit: {
34440
34506
  auto: true,
34441
- reportsConsentedAt: Date.now(),
34442
34507
  ...days !== undefined ? { intervalDays: days } : {}
34443
34508
  }
34444
34509
  });
34445
34510
  const interval = next.audit.intervalDays;
34446
34511
  const summary = [
34447
- `every ${interval} day${interval === 1 ? "" : "s"} · reports to ${user.email}`,
34448
- "you only hear from it when a scan finds something harmful",
34449
- "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"
34450
34515
  ];
34451
- if (prompted) {
34516
+ if (signedIn.prompted) {
34452
34517
  step("scheduled audits are on", summary);
34453
34518
  } else {
34454
34519
  process.stdout.write(`
@@ -34457,7 +34522,7 @@ ${green("✓")} ${bold("scheduled audits are on")}
34457
34522
  `).join(""));
34458
34523
  }
34459
34524
  warnIfDaemonWontRun();
34460
- if (prompted) {
34525
+ if (signedIn.prompted) {
34461
34526
  outro("failproofai audit --status · when the next scan is due");
34462
34527
  } else {
34463
34528
  process.stdout.write(dim(`
@@ -34509,12 +34574,7 @@ function runScheduleStatus() {
34509
34574
  ]);
34510
34575
  detail.push(["reports to", live ? live.user.email : dim("— signed out")]);
34511
34576
  if (on && !live) {
34512
- detail.push(["", pink("scans continue; digests are paused until you sign in")]);
34513
- } else if (on && config.audit.reportsConsentedAt === undefined) {
34514
- detail.push([
34515
- "",
34516
- pink("scans continue; digests need a fresh opt-in — run `--schedule` to turn them on")
34517
- ]);
34577
+ detail.push(["", pink("scans and desktop alerts continue; email alerts are paused")]);
34518
34578
  }
34519
34579
  detail.push(["daemon", describeDaemon(daemon)]);
34520
34580
  if (sched?.nextDueAtMs != null && on) {
@@ -34629,14 +34689,14 @@ var init_schedule_cli = __esm(() => {
34629
34689
  });
34630
34690
 
34631
34691
  // scripts/parse-script-args.ts
34632
- import { resolve as resolve32 } from "path";
34692
+ import { resolve as resolve31 } from "path";
34633
34693
  function parseStringFlag(flagName, errorLabel, inlineValue, args, index, options) {
34634
34694
  const raw = inlineValue ?? args[index + 1];
34635
34695
  if (raw === undefined || inlineValue === null && raw.startsWith("-")) {
34636
34696
  console.error(`Error: ${flagName} requires ${errorLabel}`);
34637
34697
  process.exit(1);
34638
34698
  }
34639
- const value = options?.resolve ? resolve32(raw) : raw;
34699
+ const value = options?.resolve ? resolve31(raw) : raw;
34640
34700
  return { value, spliceCount: inlineValue !== null ? 1 : 2 };
34641
34701
  }
34642
34702
  function parseScriptArgs(argv) {
@@ -34692,21 +34752,21 @@ function parseScriptArgs(argv) {
34692
34752
  var init_parse_script_args = () => {};
34693
34753
 
34694
34754
  // scripts/install-diagnosis.mjs
34695
- import { existsSync as existsSync46, readFileSync as readFileSync37, realpathSync as realpathSync4 } from "node:fs";
34696
- 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";
34697
34757
  import { homedir as homedir32, platform as platform5 } from "node:os";
34698
34758
  import { spawnSync } from "node:child_process";
34699
34759
  function findPackageRoot(start) {
34700
34760
  try {
34701
34761
  let dir = realpathSync4(start);
34702
- if (existsSync46(dir) && !existsSync46(resolve33(dir, "package.json"))) {
34762
+ if (existsSync45(dir) && !existsSync45(resolve32(dir, "package.json"))) {
34703
34763
  dir = dirname22(dir);
34704
34764
  }
34705
34765
  while (true) {
34706
- const pkgPath = resolve33(dir, "package.json");
34707
- if (existsSync46(pkgPath)) {
34766
+ const pkgPath = resolve32(dir, "package.json");
34767
+ if (existsSync45(pkgPath)) {
34708
34768
  try {
34709
- const pkg = JSON.parse(readFileSync37(pkgPath, "utf8"));
34769
+ const pkg = JSON.parse(readFileSync38(pkgPath, "utf8"));
34710
34770
  if (pkg.name === PKG_NAME)
34711
34771
  return dir;
34712
34772
  } catch {}
@@ -34724,7 +34784,7 @@ function readPackageVersion(packageRoot) {
34724
34784
  if (!packageRoot)
34725
34785
  return null;
34726
34786
  try {
34727
- const pkg = JSON.parse(readFileSync37(resolve33(packageRoot, "package.json"), "utf8"));
34787
+ const pkg = JSON.parse(readFileSync38(resolve32(packageRoot, "package.json"), "utf8"));
34728
34788
  return typeof pkg.version === "string" ? pkg.version : null;
34729
34789
  } catch {
34730
34790
  return null;
@@ -34750,16 +34810,16 @@ function locateNpmGlobal() {
34750
34810
  const root = (res.stdout || "").trim();
34751
34811
  if (!root)
34752
34812
  return null;
34753
- const candidate = resolve33(root, PKG_NAME);
34754
- return existsSync46(resolve33(candidate, "package.json")) ? candidate : null;
34813
+ const candidate = resolve32(root, PKG_NAME);
34814
+ return existsSync45(resolve32(candidate, "package.json")) ? candidate : null;
34755
34815
  } catch {
34756
34816
  return null;
34757
34817
  }
34758
34818
  }
34759
34819
  function locateBunGlobal() {
34760
34820
  try {
34761
- const candidate = resolve33(homedir32(), ".bun", "install", "global", "node_modules", PKG_NAME);
34762
- 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;
34763
34823
  } catch {
34764
34824
  return null;
34765
34825
  }
@@ -34767,8 +34827,8 @@ function locateBunGlobal() {
34767
34827
  function buildRecommendation(pathFirstBin) {
34768
34828
  if (!pathFirstBin)
34769
34829
  return null;
34770
- const bunBinPrefix = resolve33(homedir32(), ".bun", "bin") + "/";
34771
- const bunGlobalPrefix = resolve33(homedir32(), ".bun", "install", "global") + "/";
34830
+ const bunBinPrefix = resolve32(homedir32(), ".bun", "bin") + "/";
34831
+ const bunGlobalPrefix = resolve32(homedir32(), ".bun", "install", "global") + "/";
34772
34832
  const isBun = pathFirstBin.startsWith(bunBinPrefix) || pathFirstBin.startsWith(bunGlobalPrefix);
34773
34833
  if (isBun) {
34774
34834
  return `rm -f ~/.bun/bin/${PKG_NAME} && rm -rf ~/.bun/install/global/node_modules/${PKG_NAME}`;
@@ -34862,8 +34922,8 @@ var init_dashboard_host = __esm(() => {
34862
34922
 
34863
34923
  // scripts/launch.ts
34864
34924
  import { spawn as spawn2 } from "child_process";
34865
- import { realpathSync as realpathSync5, existsSync as existsSync47 } from "node:fs";
34866
- 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";
34867
34927
  import { fileURLToPath as fileURLToPath2 } from "node:url";
34868
34928
  import { createInterface } from "node:readline";
34869
34929
  function launch(mode) {
@@ -34887,9 +34947,9 @@ function launch(mode) {
34887
34947
  process.env.PORT = port;
34888
34948
  process.env.HOSTNAME = bindHost;
34889
34949
  cmd = "node";
34890
- const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT ?? resolve34(dirname23(realpathSync5(fileURLToPath2(import.meta.url))), "..");
34891
- const serverJsPath = resolve34(packageRoot, ".next/standalone/server.js");
34892
- 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)) {
34893
34953
  let shadowMessage = null;
34894
34954
  try {
34895
34955
  const diag = diagnoseShadow({ selfPackageRoot: packageRoot, selfVersion: version2 });
@@ -34972,23 +35032,27 @@ function helpText() {
34972
35032
  const lines = helpScreen({
34973
35033
  command: "audit",
34974
35034
  version: version2,
34975
- tagline: "review your agent CLIs for risky and wasteful patterns",
35035
+ tagline: "find credentials your agents leaked into their own transcripts",
34976
35036
  sections: [
34977
35037
  {
34978
35038
  label: "usage",
34979
35039
  entries: [
34980
- ["(bare)", `Scan your session history, then open http://localhost:${DASHBOARD_PORT}/audit`],
34981
- ["--schedule [days]", "Scan on a timer and email the findings. Default 7 days, range 1-90. Signs you in the first time."],
34982
- ["--email <address>", "With --schedule, skips the sign-in prompt."],
35040
+ ["(bare)", `Scan your session history for leaked keys, then open http://localhost:${DASHBOARD_PORT}/audit`],
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."],
34983
35043
  ["--no-schedule", "Stop the timer. Leaves you signed in."],
34984
35044
  ["--notify", "Show a desktop notification when a scan finds a credential. On by default."],
34985
- ["--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."],
34986
35046
  ["--status", "Whether scheduling is on, where reports go, the daemon's state, and when the next scan is due."],
34987
35047
  ["-h, --help", "Show this help."]
34988
35048
  ]
34989
35049
  }
34990
35050
  ],
34991
- footer: ["Everything runs on this machine; only a scheduled digest ever leaves it."]
35051
+ footer: [
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."
35055
+ ]
34992
35056
  }, helpOptsFor(process.stdout));
34993
35057
  return ["", ...lines, ""].join(`
34994
35058
  `) + `
@@ -35137,29 +35201,26 @@ function heldByLine(held) {
35137
35201
  const ageS = Math.max(0, Math.round((Date.now() - held.startedAt) / 1000));
35138
35202
  return `another audit is already running (pid ${held.pid}, started by ${held.source} ${ageS}s ago)`;
35139
35203
  }
35140
- async function announceLeaksOnDesktop(result) {
35204
+ async function announceLeaksOnDesktop(result, report) {
35141
35205
  try {
35142
- await announceLeaksOrThrow(result);
35206
+ await announceLeaksOrThrow(result, report);
35143
35207
  } catch (err) {
35144
35208
  process.stderr.write(`failproofai: could not announce a leak on the desktop: ` + `${err instanceof Error ? err.message : String(err)}
35145
35209
  `);
35146
35210
  }
35147
35211
  }
35148
- async function announceLeaksOrThrow(result) {
35149
- const ids = result.newLeakIds ?? [];
35212
+ async function announceLeaksOrThrow(result, report) {
35213
+ const ids = result.leakIds ?? result.newLeakIds ?? [];
35150
35214
  if (ids.length === 0)
35151
35215
  return;
35152
35216
  if (!readConfig().audit.notify)
35153
35217
  return;
35154
- const claimed = markLeakNoticeDelivered(ids, undefined, "desktop");
35155
- if (claimed.length === 0)
35156
- return;
35157
- const n = claimed.length === 1 ? "a credential" : `${claimed.length} credentials`;
35158
- const title = "failproofai found a leaked credential";
35159
- const body = `${n} in your agent transcripts. Run failproofai audit to see them — ` + "or failproofai audit --schedule to get them by email.";
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);
35160
35221
  if (process.platform === "darwin") {
35161
35222
  pruneMacNotifyQueue();
35162
- if (!queueMacNotification(claimed[0], title, body)) {
35223
+ if (!queueMacNotification(ids[0], title, body)) {
35163
35224
  process.stderr.write(`failproofai: found ${n} but could not queue a notification
35164
35225
  `);
35165
35226
  } else if (!macNotifierInstalled()) {
@@ -35205,8 +35266,8 @@ async function runScheduledAudit() {
35205
35266
  }
35206
35267
  process.stdout.write(`failproofai: audit complete — ${num2(result.eventsScanned)} tool calls across ` + `${num2(result.transcripts.scanned)} sessions, ${num2(result.totals.hits)} hits
35207
35268
  `);
35208
- await announceLeaksOnDesktop(result);
35209
35269
  const outcome = await reportHarm(result);
35270
+ await announceLeaksOnDesktop(result, outcome);
35210
35271
  const line = describeOutcome2(outcome);
35211
35272
  if (line) {
35212
35273
  const stream = outcome.kind === "sent" ? process.stdout : process.stderr;
@@ -35364,8 +35425,8 @@ var init_cli2 = __esm(() => {
35364
35425
  init_report_harm();
35365
35426
  init_desktop_notify();
35366
35427
  init_macos_notifier();
35367
- init_leak_notice();
35368
35428
  init_fp_config();
35429
+ init_auth_store();
35369
35430
  init_tui();
35370
35431
  init_package();
35371
35432
  AUDIT_STAGES2 = [
@@ -35698,8 +35759,8 @@ var init_session_pause_cli = __esm(() => {
35698
35759
 
35699
35760
  // scripts/launch.ts
35700
35761
  import { spawn as spawn3 } from "child_process";
35701
- import { realpathSync as realpathSync6, existsSync as existsSync48 } from "node:fs";
35702
- 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";
35703
35764
  import { fileURLToPath as fileURLToPath3 } from "node:url";
35704
35765
  import { createInterface as createInterface2 } from "node:readline";
35705
35766
  function launch2(mode) {
@@ -35723,9 +35784,9 @@ function launch2(mode) {
35723
35784
  process.env.PORT = port;
35724
35785
  process.env.HOSTNAME = bindHost;
35725
35786
  cmd = "node";
35726
- const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT ?? resolve35(dirname24(realpathSync6(fileURLToPath3(import.meta.url))), "..");
35727
- const serverJsPath = resolve35(packageRoot, ".next/standalone/server.js");
35728
- 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)) {
35729
35790
  let shadowMessage = null;
35730
35791
  try {
35731
35792
  const diag = diagnoseShadow({ selfPackageRoot: packageRoot, selfVersion: version2 });
@@ -35822,17 +35883,17 @@ var init_cli_error2 = __esm(() => {
35822
35883
 
35823
35884
  // bin/failproofai.mjs
35824
35885
  import { realpathSync as realpathSync7 } from "fs";
35825
- import { dirname as dirname25, resolve as resolve36 } from "path";
35886
+ import { dirname as dirname25, resolve as resolve35 } from "path";
35826
35887
  import { fileURLToPath as fileURLToPath4 } from "url";
35827
35888
  // package.json
35828
- var version = "1.0.4-beta.2";
35889
+ var version = "1.0.4-beta.6";
35829
35890
 
35830
35891
  // bin/failproofai.mjs
35831
35892
  if (!process.env.FAILPROOFAI_PACKAGE_ROOT) {
35832
- 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))), "..");
35833
35894
  }
35834
35895
  if (!process.env.FAILPROOFAI_DIST_PATH) {
35835
- 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");
35836
35897
  }
35837
35898
  var args = process.argv.slice(2);
35838
35899
  if (args[0] === "p" || args[0] === "policy")
@@ -36070,7 +36131,7 @@ Run \`failproofai help\` for usage.`);
36070
36131
  label: "see what it caught",
36071
36132
  entries: [
36072
36133
  ["(no args)", "Open the policy dashboard on localhost:8020"],
36073
- ["audit", "Scan your agents' history, then open the audit view"],
36134
+ ["audit", "Find credentials your agents leaked, and get told about it"],
36074
36135
  ["config --status", "Cloud connection, daemon version, pause state"]
36075
36136
  ]
36076
36137
  },