failproofai 1.0.0-beta.0 → 1.0.0-beta.10

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 (357) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/app-path-routes-manifest.json +2 -1
  3. package/.next/standalone/.next/build-manifest.json +6 -6
  4. package/.next/standalone/.next/prerender-manifest.json +3 -3
  5. package/.next/standalone/.next/required-server-files.json +1 -1
  6. package/.next/standalone/.next/routes-manifest.json +6 -0
  7. package/.next/standalone/.next/server/app/_global-error/page/build-manifest.json +3 -3
  8. package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
  9. package/.next/standalone/.next/server/app/_global-error/page.js +3 -1
  10. package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
  11. package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  12. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  13. package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
  14. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +2 -2
  15. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
  16. package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +3 -3
  17. package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +3 -3
  18. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  19. package/.next/standalone/.next/server/app/_not-found/page/build-manifest.json +3 -3
  20. package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  21. package/.next/standalone/.next/server/app/_not-found/page.js +3 -1
  22. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  23. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  24. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  25. package/.next/standalone/.next/server/app/_not-found.rsc +15 -15
  26. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +15 -15
  27. package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
  28. package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +10 -10
  29. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
  30. package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
  31. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  32. package/.next/standalone/.next/server/app/api/audit/invite/route.js +3 -2
  33. package/.next/standalone/.next/server/app/api/audit/invite/route.js.nft.json +1 -1
  34. package/.next/standalone/.next/server/app/api/audit/run/route.js +4 -3
  35. package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -1
  36. package/.next/standalone/.next/server/app/api/audit/status/route.js +1 -1
  37. package/.next/standalone/.next/server/app/api/audit/status/route.js.nft.json +1 -1
  38. package/.next/standalone/.next/server/app/api/auth/login-request/route.js +2 -1
  39. package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -1
  40. package/.next/standalone/.next/server/app/api/auth/login-verify/route.js +3 -2
  41. package/.next/standalone/.next/server/app/api/auth/login-verify/route.js.nft.json +1 -1
  42. package/.next/standalone/.next/server/app/api/auth/logout/route.js +3 -2
  43. package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
  44. package/.next/standalone/.next/server/app/api/auth/reminder/route.js +3 -2
  45. package/.next/standalone/.next/server/app/api/auth/reminder/route.js.nft.json +1 -1
  46. package/.next/standalone/.next/server/app/api/auth/status/route.js +3 -2
  47. package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -1
  48. package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js +1 -1
  49. package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
  50. package/.next/standalone/.next/server/app/audit/page/build-manifest.json +3 -3
  51. package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +2 -2
  52. package/.next/standalone/.next/server/app/audit/page.js +5 -3
  53. package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -1
  54. package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
  55. package/.next/standalone/.next/server/app/index.html +1 -1
  56. package/.next/standalone/.next/server/app/index.rsc +15 -15
  57. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  58. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +15 -15
  59. package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +4 -4
  60. package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +10 -10
  61. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  62. package/.next/standalone/.next/server/app/page/build-manifest.json +3 -3
  63. package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
  64. package/.next/standalone/.next/server/app/page.js +3 -1
  65. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  66. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  67. package/.next/standalone/.next/server/app/policies/page/build-manifest.json +3 -3
  68. package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +30 -18
  69. package/.next/standalone/.next/server/app/policies/page.js +5 -3
  70. package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
  71. package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
  72. package/.next/standalone/.next/server/app/project/[name]/page/build-manifest.json +3 -3
  73. package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
  74. package/.next/standalone/.next/server/app/project/[name]/page.js +4 -2
  75. package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
  76. package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
  77. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/build-manifest.json +3 -3
  78. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
  79. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
  80. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js +6 -4
  81. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
  82. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
  83. package/.next/standalone/.next/server/app/projects/page/build-manifest.json +3 -3
  84. package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
  85. package/.next/standalone/.next/server/app/projects/page.js +4 -2
  86. package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
  87. package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  88. package/.next/standalone/.next/server/app/settings/page/app-paths-manifest.json +3 -0
  89. package/.next/standalone/.next/server/app/settings/page/build-manifest.json +18 -0
  90. package/.next/standalone/.next/server/app/settings/page/next-font-manifest.json +6 -0
  91. package/.next/standalone/.next/server/app/settings/page/react-loadable-manifest.json +1 -0
  92. package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +53 -0
  93. package/.next/standalone/.next/server/app/settings/page.js +18 -0
  94. package/.next/standalone/.next/server/app/settings/page.js.map +5 -0
  95. package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -0
  96. package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +3 -0
  97. package/.next/standalone/.next/server/app-paths-manifest.json +2 -1
  98. package/.next/standalone/.next/server/chunks/[externals]__0h9_83k._.js +3 -0
  99. package/.next/standalone/.next/server/chunks/{[externals]__1nl3dvw._.js → [externals]__0r-zamh._.js} +2 -2
  100. package/.next/standalone/.next/server/chunks/[externals]__1ifpkx-._.js +3 -0
  101. package/.next/standalone/.next/server/chunks/[root-of-the-server]__06hexd0._.js +3 -0
  102. package/.next/standalone/.next/server/chunks/[root-of-the-server]__094p1f1._.js +3 -0
  103. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0_0xu5z._.js +1 -1
  104. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ed01_d._.js +3 -0
  105. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0g0vcwt._.js +3 -0
  106. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0h3lfmp._.js → [root-of-the-server]__0ky_n0r._.js} +2 -2
  107. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__18d-9oi._.js → [root-of-the-server]__0lk_935._.js} +2 -2
  108. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__16le-kd._.js → [root-of-the-server]__0pbp9fe._.js} +2 -2
  109. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0q-v9z2._.js +1 -1
  110. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__10oa-v9._.js → [root-of-the-server]__0v2fpxe._.js} +2 -2
  111. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0sb_5m8._.js → [root-of-the-server]__131ebum._.js} +3 -3
  112. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0-dh5jy._.js → [root-of-the-server]__1_ps0jw._.js} +2 -2
  113. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0l4vuqm._.js → [root-of-the-server]__1a7i2q4._.js} +2 -2
  114. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1ibjy5x._.js +3 -0
  115. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1iny24d._.js +3 -0
  116. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1tvn4wf._.js +1 -1
  117. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1tyedjt._.js +3 -0
  118. package/.next/standalone/.next/server/chunks/_0lxbzdq._.js +5 -0
  119. package/.next/standalone/.next/server/chunks/_1zuiiy3._.js +5 -0
  120. package/.next/standalone/.next/server/chunks/lib_telemetry_ts_0dctyyw._.js +5 -0
  121. package/.next/standalone/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_17k9e3w.js +5 -5
  122. package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_01r25oi._.js +2 -1
  123. package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_09z9-p7._.js +2 -1
  124. package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
  125. package/.next/standalone/.next/server/chunks/ssr/[externals]__1aq139v._.js +3 -0
  126. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__04pwh4t._.js +3 -0
  127. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__06bp_fg._.js +5 -0
  128. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__074qmkp._.js +3 -0
  129. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__170799-._.js → [root-of-the-server]__0spkm68._.js} +11 -11
  130. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__10butu6._.js +3 -0
  131. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1a2hcb_._.js +3 -0
  132. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1qapotl._.js +1 -1
  133. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1apb7k_._.js → [root-of-the-server]__1rdruw4._.js} +2 -2
  134. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1rv-sc9._.js +3 -0
  135. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1tyf0tc._.js +5 -0
  136. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1u-wx42._.js +4 -0
  137. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1v185mo._.js +3 -0
  138. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__01od0m6._.js → [root-of-the-server]__1yw368c._.js} +2 -2
  139. package/.next/standalone/.next/server/chunks/ssr/_0-yi74u._.js +3 -0
  140. package/.next/standalone/.next/server/chunks/ssr/_04mekdy._.js +3 -0
  141. package/.next/standalone/.next/server/chunks/ssr/_0r-dsre._.js +3 -0
  142. package/.next/standalone/.next/server/chunks/ssr/_0rjgfln._.js +3 -0
  143. package/.next/standalone/.next/server/chunks/ssr/_0se484m._.js +3 -0
  144. package/.next/standalone/.next/server/chunks/ssr/_0uz7o9y._.js +3 -0
  145. package/.next/standalone/.next/server/chunks/ssr/_11_p9y8._.js +1 -1
  146. package/.next/standalone/.next/server/chunks/ssr/_1e19atl._.js +1 -1
  147. package/.next/standalone/.next/server/chunks/ssr/_1fahg9e._.js +3 -0
  148. package/.next/standalone/.next/server/chunks/ssr/_1gmzkwj._.js +5 -0
  149. package/.next/standalone/.next/server/chunks/ssr/_1w8sola._.js +3 -0
  150. package/.next/standalone/.next/server/chunks/ssr/_1w_6p9g._.js +3 -0
  151. package/.next/standalone/.next/server/chunks/ssr/_1y4qr7u._.js +3 -0
  152. package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +2 -2
  153. package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
  154. package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +2 -2
  155. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0dwo94s.js +4 -0
  156. package/.next/standalone/.next/server/chunks/ssr/node_modules_posthog-node_dist_entrypoints_index_node_mjs_11bnuzn._.js +2 -1
  157. package/.next/standalone/.next/server/chunks/ssr/src_hooks_builtin-policies_ts_09j2ndl._.js +3 -0
  158. package/.next/standalone/.next/server/chunks/ssr/src_hooks_fp-config_ts_04t589g._.js +5 -0
  159. package/.next/standalone/.next/server/middleware-build-manifest.js +6 -6
  160. package/.next/standalone/.next/server/middleware.js +2 -2
  161. package/.next/standalone/.next/server/pages/404.html +1 -1
  162. package/.next/standalone/.next/server/pages/500.html +1 -1
  163. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  164. package/.next/standalone/.next/server/server-reference-manifest.json +74 -20
  165. package/.next/standalone/.next/static/chunks/00adubtgov21s.js +1 -0
  166. package/.next/standalone/.next/static/chunks/{03fmihek9n986.js → 06zgzyh3wv1ig.js} +1 -1
  167. package/.next/standalone/.next/static/chunks/{1hdhteui932bq.js → 0qmo2t50kpb30.js} +1 -1
  168. package/.next/standalone/.next/static/chunks/{1grd7y94-igz9.js → 0yudogeqddpzr.js} +1 -1
  169. package/.next/standalone/.next/static/chunks/16p68cybetr31.js +1 -0
  170. package/.next/standalone/.next/static/chunks/1bm0q12hgs22l.css +2 -0
  171. package/.next/standalone/.next/static/chunks/{1d6ncspjagm53.js → 1fu90ch80qngv.js} +1 -1
  172. package/.next/standalone/.next/static/chunks/{2vr7aazw6k2-n.js → 1m416lie3qwsj.js} +1 -1
  173. package/.next/standalone/.next/static/chunks/1v1gqvpjk62jm.js +1 -0
  174. package/.next/standalone/.next/static/chunks/1ypqzvoal8j56.js +6 -0
  175. package/.next/standalone/.next/static/chunks/23kev26by1e4f.js +1 -0
  176. package/.next/standalone/.next/static/chunks/{29k6ef49zppxj.js → 2h4sbmp0ad78w.js} +1 -1
  177. package/.next/standalone/.next/static/chunks/2obwg4tterjpa.js +1 -0
  178. package/.next/standalone/.next/static/chunks/2uvhw57mf9lg_.css +2 -0
  179. package/.next/standalone/.next/static/chunks/{29ydr-8q0zis6.js → 30ufy4_e2n78e.js} +22 -22
  180. package/.next/standalone/.next/static/chunks/31coz11ia5vc4.js +1 -0
  181. package/.next/standalone/.next/static/chunks/{1s-_swlc80y43.js → 3p4j0l1o_p-nm.js} +1 -1
  182. package/.next/standalone/.next/static/chunks/{0ip1n8xmgxarv.js → 3uxnxwxcctyj0.js} +1 -1
  183. package/.next/standalone/.next/static/chunks/{turbopack-1lsv92x7klwrn.js → turbopack-3diub4ctvn1n0.js} +1 -1
  184. package/.next/standalone/app/actions/get-active-pauses.ts +16 -0
  185. package/.next/standalone/app/actions/get-hooks-config.ts +2 -1
  186. package/.next/standalone/app/actions/get-scheduled-audit.ts +70 -0
  187. package/.next/standalone/app/actions/update-scheduled-audit.ts +44 -0
  188. package/.next/standalone/app/api/audit/run/route.ts +28 -0
  189. package/.next/standalone/app/api/audit/status/route.ts +13 -1
  190. package/.next/standalone/app/api/auth/status/route.ts +1 -1
  191. package/.next/standalone/app/audit/_components/auth-dialog.css +159 -0
  192. package/.next/standalone/app/audit/_components/auth-dialog.tsx +3 -0
  193. package/.next/standalone/app/audit/audit-styles.css +6 -149
  194. package/.next/standalone/app/components/pause-notices.tsx +111 -0
  195. package/.next/standalone/app/policies/hooks-client.tsx +81 -6
  196. package/.next/standalone/app/settings/page.tsx +31 -0
  197. package/.next/standalone/app/settings/settings-client.tsx +488 -0
  198. package/.next/standalone/components/navbar.tsx +2 -0
  199. package/.next/standalone/lib/auth/api-server-client.ts +2 -3
  200. package/.next/standalone/lib/auth/auth-store.ts +4 -4
  201. package/.next/standalone/lib/codex-sessions.ts +2 -1
  202. package/.next/standalone/lib/dashboard-host.ts +101 -0
  203. package/.next/standalone/lib/install-check.ts +22 -7
  204. package/.next/standalone/lib/pi-sessions.ts +99 -14
  205. package/.next/standalone/lib/telemetry-enabled.ts +54 -0
  206. package/.next/standalone/lib/telemetry-id.ts +52 -1
  207. package/.next/standalone/lib/telemetry.ts +8 -4
  208. package/.next/standalone/node_modules/react/cjs/react.development.js +1 -1
  209. package/.next/standalone/node_modules/react/cjs/react.production.js +1 -1
  210. package/.next/standalone/node_modules/react/package.json +3 -3
  211. package/.next/standalone/node_modules/react-dom/cjs/react-dom-server-legacy.browser.production.js +1 -1
  212. package/.next/standalone/node_modules/react-dom/cjs/react-dom-server-legacy.node.production.js +1 -1
  213. package/.next/standalone/node_modules/react-dom/cjs/react-dom-server.browser.production.js +3 -3
  214. package/.next/standalone/node_modules/react-dom/cjs/react-dom-server.edge.production.js +3 -3
  215. package/.next/standalone/node_modules/react-dom/cjs/react-dom-server.node.production.js +3 -3
  216. package/.next/standalone/node_modules/react-dom/cjs/react-dom.production.js +1 -1
  217. package/.next/standalone/node_modules/react-dom/package.json +4 -4
  218. package/.next/standalone/package.json +17 -10
  219. package/.next/standalone/proxy.ts +89 -1
  220. package/.next/standalone/server.js +1 -1
  221. package/bin/failproofai.mjs +518 -79
  222. package/dist/cli.mjs +11484 -6046
  223. package/dist/worker.mjs +2019 -272
  224. package/lib/auth/api-server-client.ts +2 -3
  225. package/lib/auth/auth-store.ts +4 -4
  226. package/lib/codex-sessions.ts +2 -1
  227. package/lib/dashboard-host.ts +101 -0
  228. package/lib/install-check.ts +22 -7
  229. package/lib/pi-sessions.ts +99 -14
  230. package/lib/telemetry-enabled.ts +54 -0
  231. package/lib/telemetry-id.ts +52 -1
  232. package/lib/telemetry.ts +8 -4
  233. package/package.json +17 -10
  234. package/scripts/build-daemon-packages.mjs +210 -0
  235. package/scripts/daemon-platforms.mjs +42 -0
  236. package/scripts/install-telemetry.mjs +8 -1
  237. package/scripts/launch.ts +25 -3
  238. package/scripts/parse-script-args.ts +17 -1
  239. package/scripts/prune-standalone.mjs +26 -0
  240. package/scripts/publish-aliases.mjs +62 -41
  241. package/scripts/repro-npm-install.sh +155 -0
  242. package/scripts/translate-docs/readme-translator.ts +163 -4
  243. package/scripts/validate-mdx.ts +153 -13
  244. package/src/audit/audit-lock.ts +285 -0
  245. package/src/audit/audit-schedule.ts +111 -0
  246. package/src/audit/cache.ts +18 -4
  247. package/src/audit/cli-adapters/goose.ts +2 -1
  248. package/src/audit/cli-adapters/hermes.ts +28 -10
  249. package/src/audit/cli.ts +191 -35
  250. package/src/audit/dashboard-cache.ts +2 -1
  251. package/src/hooks/backfill-cli.ts +247 -0
  252. package/src/hooks/builtin-policies.ts +390 -2
  253. package/src/hooks/cloud-connection.ts +354 -0
  254. package/src/hooks/cloud-enrollment-cli.ts +325 -0
  255. package/src/hooks/cloud-enrollment.ts +243 -0
  256. package/src/hooks/cloud-introspect.ts +147 -0
  257. package/src/hooks/cloud-managed-policies.ts +169 -0
  258. package/src/hooks/collector-config.ts +234 -0
  259. package/src/hooks/configure-wizard.ts +915 -158
  260. package/src/hooks/custom-hooks-loader.ts +191 -33
  261. package/src/hooks/daemon-client.ts +136 -17
  262. package/src/hooks/daemon-download.ts +192 -30
  263. package/src/hooks/daemon-service.ts +1190 -92
  264. package/src/hooks/first-run-gate.ts +50 -0
  265. package/src/hooks/fp-config.ts +497 -0
  266. package/src/hooks/fp-home.ts +375 -0
  267. package/src/hooks/fp-reset.ts +464 -0
  268. package/src/hooks/handler.ts +185 -6
  269. package/src/hooks/hook-activity-store.ts +85 -20
  270. package/src/hooks/hook-logger.ts +2 -1
  271. package/src/hooks/hook-telemetry.ts +5 -1
  272. package/src/hooks/hooks-config.ts +4 -3
  273. package/src/hooks/loader-utils.ts +171 -8
  274. package/src/hooks/manager.ts +5 -4
  275. package/src/hooks/onboarding-attempt.ts +179 -0
  276. package/src/hooks/onboarding-lock.ts +119 -0
  277. package/src/hooks/policy-types.ts +28 -0
  278. package/src/hooks/session-pause-cli.ts +159 -0
  279. package/src/hooks/session-pause.ts +268 -0
  280. package/src/hooks/setup-state.ts +256 -0
  281. package/src/hooks/tui.ts +119 -4
  282. package/src/hooks/uninstall-cli.ts +345 -0
  283. package/src/hooks/worker-server.ts +65 -3
  284. package/.next/standalone/.next/server/chunks/[externals]__14odj07._.js +0 -3
  285. package/.next/standalone/.next/server/chunks/[externals]__1s61mel._.js +0 -3
  286. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0id_xf7._.js +0 -3
  287. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0longh-._.js +0 -3
  288. package/.next/standalone/.next/server/chunks/[root-of-the-server]__17g9wh7._.js +0 -3
  289. package/.next/standalone/.next/server/chunks/[root-of-the-server]__19120tr._.js +0 -3
  290. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1fwl2mz._.js +0 -3
  291. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1myjm-d._.js +0 -3
  292. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1rhmvod._.js +0 -3
  293. package/.next/standalone/.next/server/chunks/ssr/[externals]__1_g_b3t._.js +0 -3
  294. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0114ewg._.js +0 -4
  295. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0259h38._.js +0 -3
  296. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__02r5bgf._.js +0 -4
  297. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0e8sjqm._.js +0 -4
  298. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0lkzqax._.js +0 -4
  299. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0qucxyj._.js +0 -4
  300. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0u02miy._.js +0 -4
  301. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0uno39i._.js +0 -3
  302. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__14dd6h8._.js +0 -3
  303. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1ath6v_._.js +0 -4
  304. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1zj-87g._.js +0 -3
  305. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1zqz4v8._.js +0 -4
  306. package/.next/standalone/.next/server/chunks/ssr/_1m_p7pi._.js +0 -3
  307. package/.next/standalone/.next/server/chunks/ssr/node_modules_html-to-image_es_index_1-upb14.js +0 -3
  308. package/.next/standalone/.next/server/chunks/ssr/src_hooks_1ezd2jf._.js +0 -5
  309. package/.next/standalone/.next/server/chunks/ssr/src_hooks_1tnuifj._.js +0 -5
  310. package/.next/standalone/.next/static/chunks/0h7auy7hzjyhw.js +0 -1
  311. package/.next/standalone/.next/static/chunks/0u9hc6oxx-gpj.js +0 -6
  312. package/.next/standalone/.next/static/chunks/0zbxssxh53n-3.js +0 -1
  313. package/.next/standalone/.next/static/chunks/2mazwb1qmur1p.js +0 -1
  314. package/.next/standalone/.next/static/chunks/2pujpnfx4pws6.css +0 -2
  315. package/.next/standalone/.next/static/chunks/33u59vf_8xpd-.js +0 -1
  316. package/.next/standalone/.next/static/chunks/3i27c3hcriawq.css +0 -1
  317. package/.next/standalone/.next/static/chunks/3wrgbih-516uj.js +0 -1
  318. package/.next/standalone/Cargo.lock +0 -428
  319. package/.next/standalone/Cargo.toml +0 -9
  320. package/.next/standalone/crates/PROTOCOL.md +0 -122
  321. package/.next/standalone/crates/failproofaid/Cargo.toml +0 -18
  322. package/.next/standalone/crates/failproofaid/src/lock.rs +0 -81
  323. package/.next/standalone/crates/failproofaid/src/main.rs +0 -83
  324. package/.next/standalone/crates/failproofaid/src/paths.rs +0 -172
  325. package/.next/standalone/crates/failproofaid/src/server.rs +0 -502
  326. package/.next/standalone/crates/failproofaid/src/worker.rs +0 -400
  327. package/.next/standalone/crates/failproofaid/tests/daemon_e2e.rs +0 -241
  328. package/.next/standalone/crates/fpai-ipc/Cargo.toml +0 -16
  329. package/.next/standalone/crates/fpai-ipc/src/envelope.rs +0 -175
  330. package/.next/standalone/crates/fpai-ipc/src/framing.rs +0 -177
  331. package/.next/standalone/crates/fpai-ipc/src/lib.rs +0 -10
  332. package/.next/standalone/crates/fpai-ipc/src/peer.rs +0 -80
  333. package/.next/standalone/docker-hook-sync/Dockerfile +0 -79
  334. package/.next/standalone/docker-hook-sync/entrypoint.sh +0 -109
  335. package/.next/standalone/integration-suite/Dockerfile +0 -47
  336. package/.next/standalone/integration-suite/README.md +0 -129
  337. package/.next/standalone/integration-suite/canary-policies.mjs +0 -45
  338. package/.next/standalone/integration-suite/capture-tokens.sh +0 -48
  339. package/.next/standalone/integration-suite/ci-entrypoint.sh +0 -179
  340. package/.next/standalone/integration-suite/inject-tokens.sh +0 -44
  341. package/.next/standalone/integration-suite/install-clis.sh +0 -136
  342. package/.next/standalone/integration-suite/probe-cli.sh +0 -248
  343. package/.next/standalone/integration-suite/report.js +0 -120
  344. package/.next/standalone/integration-suite/run.sh +0 -159
  345. package/.next/standalone/openclaw-plugin/index.js +0 -223
  346. package/.next/standalone/openclaw-plugin/openclaw.plugin.json +0 -6
  347. package/.next/standalone/openclaw-plugin/package.json +0 -12
  348. package/.next/standalone/osv-scanner.toml +0 -17
  349. package/.next/standalone/pi-extension/index.ts +0 -524
  350. package/.next/standalone/pi-extension/package.json +0 -12
  351. package/.next/standalone/postcss.config.mjs +0 -8
  352. package/.next/standalone/readme-arch-hq.gif +0 -0
  353. package/.next/standalone/rust-toolchain.toml +0 -4
  354. package/src/auth/cli.ts +0 -371
  355. /package/.next/standalone/.next/static/{7Lxtd352rSaHB-pmm6G8M → pBBcTvE6_VueYGbacy1kg}/_buildManifest.js +0 -0
  356. /package/.next/standalone/.next/static/{7Lxtd352rSaHB-pmm6G8M → pBBcTvE6_VueYGbacy1kg}/_clientMiddlewareManifest.js +0 -0
  357. /package/.next/standalone/.next/static/{7Lxtd352rSaHB-pmm6G8M → pBBcTvE6_VueYGbacy1kg}/_ssgManifest.js +0 -0
package/dist/worker.mjs CHANGED
@@ -362,6 +362,37 @@ function normalizeCliPayload(cli, parsed) {
362
362
  }
363
363
  }
364
364
 
365
+ // src/hooks/fp-home.ts
366
+ import { homedir } from "node:os";
367
+ import { resolve } from "node:path";
368
+ function failproofaiHome(home) {
369
+ if (home)
370
+ return resolve(home, ".failproofai");
371
+ return process.env.FAILPROOFAI_HOME || resolve(homedir(), ".failproofai");
372
+ }
373
+ var LAYOUT_VERSION = 2, at = (...parts) => resolve(failproofaiHome(), ...parts), atHome = (home, ...parts) => home ? resolve(failproofaiHome(home), ...parts) : at(...parts), versionFile = (home) => atHome(home, "VERSION"), configFile = (home) => atHome(home, "config.toml"), policiesDir = (home) => atHome(home, "policies"), localPoliciesDir = (home) => atHome(home, "policies", "local-policies"), globalPolicyConfigFile = (home) => resolve(localPoliciesDir(home), "policies-config.json"), cloudPoliciesDir = (home) => resolve(policiesDir(home), "cloud-policies"), customPoliciesDir = (home) => resolve(policiesDir(home), "custom-policies"), hookActivityDir = (home) => atHome(home, "hook-activity"), stateDir = (home) => atHome(home, "state"), shimsDir = (home) => resolve(stateDir(home), "shims"), sessionPauseDir = () => resolve(stateDir(), "sessions"), telemetryIdFile = (home) => resolve(stateDir(home), "telemetry-id"), codexSessionPathsFile = (home) => resolve(stateDir(home), "codex-session-paths.json"), logsDir = (home) => atHome(home, "logs"), legacy;
374
+ var init_fp_home = __esm(() => {
375
+ legacy = {
376
+ policyConfig: () => at("policies-config.json"),
377
+ policyConfigLocal: () => at("policies-config.local.json"),
378
+ cloudCredentials: () => at("cloud.json"),
379
+ ingestCredentials: () => at("ingest.json"),
380
+ launcherMarker: () => at(".launcher-configured"),
381
+ lastVersion: () => at("last-version"),
382
+ auditDashboard: () => at("audit-dashboard.json"),
383
+ cacheDir: () => at("cache"),
384
+ hookActivityDir: () => at("cache", "hook-activity"),
385
+ auditCacheDir: () => at("cache", "audit"),
386
+ codexSessionPaths: () => at("cache", "codex-session-paths.json"),
387
+ spoolDir: () => at("spool"),
388
+ failedDir: () => at("failed"),
389
+ collectorHealth: () => at("collector-health.json"),
390
+ sessionPauseDir: () => at("state", "sessions"),
391
+ cloudManagedPolicies: () => at("policies", "cloud-managed"),
392
+ onboardingLock: () => at(".onboarding.lock")
393
+ };
394
+ });
395
+
365
396
  // src/hooks/hook-logger.ts
366
397
  import {
367
398
  appendFileSync,
@@ -371,7 +402,6 @@ import {
371
402
  statSync
372
403
  } from "node:fs";
373
404
  import { join } from "node:path";
374
- import { homedir } from "node:os";
375
405
  function ensureResolved() {
376
406
  if (resolved)
377
407
  return;
@@ -443,15 +473,16 @@ function hookLogError(msg) {
443
473
  }
444
474
  var LEVEL_ORDER, MAX_FILE_SIZE, LOG_FILENAME = "hooks.log", DEFAULT_LOG_DIR, resolved = false, currentLevel = "warn", fileLoggingEnabled = false, logDir;
445
475
  var init_hook_logger = __esm(() => {
476
+ init_fp_home();
446
477
  LEVEL_ORDER = { info: 0, warn: 1, error: 2 };
447
478
  MAX_FILE_SIZE = 512 * 1024;
448
- DEFAULT_LOG_DIR = join(homedir(), ".failproofai", "logs");
479
+ DEFAULT_LOG_DIR = logsDir();
449
480
  logDir = DEFAULT_LOG_DIR;
450
481
  });
451
482
 
452
483
  // src/hooks/hooks-config.ts
453
484
  import { readFileSync, writeFileSync, existsSync as existsSync2, mkdirSync as mkdirSync2, statSync as statSync2 } from "node:fs";
454
- import { resolve, dirname } from "node:path";
485
+ import { resolve as resolve2, dirname } from "node:path";
455
486
  import { homedir as homedir2 } from "node:os";
456
487
  function readConfigAt(path) {
457
488
  if (!existsSync2(path))
@@ -466,9 +497,9 @@ function readConfigAt(path) {
466
497
  }
467
498
  function findProjectConfigDir(start) {
468
499
  const home = homedir2();
469
- let dir = resolve(start);
500
+ let dir = resolve2(start);
470
501
  while (dir !== home) {
471
- const marker = resolve(dir, ".failproofai");
502
+ const marker = resolve2(dir, ".failproofai");
472
503
  try {
473
504
  if (statSync2(marker).isDirectory())
474
505
  return dir;
@@ -478,13 +509,13 @@ function findProjectConfigDir(start) {
478
509
  break;
479
510
  dir = parent;
480
511
  }
481
- return resolve(start);
512
+ return resolve2(start);
482
513
  }
483
514
  function readMergedHooksConfig(cwd) {
484
515
  const base = findProjectConfigDir(cwd ?? process.cwd());
485
- const projectPath = resolve(base, ".failproofai", "policies-config.json");
486
- const localPath = resolve(base, ".failproofai", "policies-config.local.json");
487
- const globalPath = resolve(homedir2(), ".failproofai", "policies-config.json");
516
+ const projectPath = resolve2(base, ".failproofai", "policies-config.json");
517
+ const localPath = resolve2(base, ".failproofai", "policies-config.local.json");
518
+ const globalPath = globalPolicyConfigFile();
488
519
  const project = readConfigAt(projectPath);
489
520
  const local = readConfigAt(localPath);
490
521
  const global_ = readConfigAt(globalPath);
@@ -522,6 +553,7 @@ function readMergedHooksConfig(cwd) {
522
553
  }
523
554
  var init_hooks_config = __esm(() => {
524
555
  init_hook_logger();
556
+ init_fp_home();
525
557
  });
526
558
 
527
559
  // src/hooks/policy-helpers.ts
@@ -596,7 +628,7 @@ function clearPolicies() {
596
628
  var REGISTRY_KEY = "__FAILPROOFAI_POLICY_REGISTRY__", INDEX_CACHE_KEY = "__FAILPROOFAI_POLICY_INDEX_CACHE__", DEFAULT_POLICY_NAMESPACE = "failproofai";
597
629
 
598
630
  // src/hooks/builtin-policies.ts
599
- import { resolve as resolve2, join as join2 } from "node:path";
631
+ import { resolve as resolve3, join as join2 } from "node:path";
600
632
  import { statSync as statSync3 } from "node:fs";
601
633
  import { readFile, writeFile } from "node:fs/promises";
602
634
  import { execSync, execFileSync } from "node:child_process";
@@ -655,6 +687,65 @@ function getFilePath(ctx) {
655
687
  function parseArgvTokens(cmd) {
656
688
  return cmd.trim().split(/\s+/).map((t) => t.replace(/^['"]|['"]$/g, ""));
657
689
  }
690
+ function namesSelfPause(command) {
691
+ for (const segment of command.split(SEGMENT_SEPARATORS)) {
692
+ const tokens = segment.split(/\s+/).filter(Boolean);
693
+ let i = 0;
694
+ while (i < tokens.length) {
695
+ const token = tokens[i];
696
+ const isSkippable = ENV_ASSIGNMENT_RE.test(token) || token.startsWith("-") || token.startsWith(">") || token.startsWith("<") || RUNNER_OPERAND_RE.test(token) || COMMAND_PREFIX_TOKENS.has(token.slice(token.lastIndexOf("/") + 1));
697
+ if (!isSkippable)
698
+ break;
699
+ i++;
700
+ }
701
+ if (i >= tokens.length)
702
+ continue;
703
+ if (!SELF_BINARY_TOKEN_RE.test(tokens[i]))
704
+ continue;
705
+ const args = tokens.slice(i + 1);
706
+ const configAt = args.findIndex((a) => CONFIG_SUBCOMMAND_RE.test(a));
707
+ if (configAt === -1)
708
+ continue;
709
+ if (args.slice(configAt + 1).some((a) => PAUSE_FLAG_RE.test(a)))
710
+ return true;
711
+ }
712
+ return false;
713
+ }
714
+ function decodeAnsiC(body) {
715
+ return body.replace(/\\(x[0-9A-Fa-f]{1,2}|u[0-9A-Fa-f]{1,4}|U[0-9A-Fa-f]{1,8}|[0-7]{1,3}|.)/g, (_, seq) => {
716
+ try {
717
+ if (seq[0] === "x")
718
+ return String.fromCharCode(parseInt(seq.slice(1), 16));
719
+ if (seq[0] === "u" || seq[0] === "U")
720
+ return String.fromCodePoint(parseInt(seq.slice(1), 16));
721
+ if (/^[0-7]+$/.test(seq))
722
+ return String.fromCharCode(parseInt(seq, 8));
723
+ } catch {
724
+ return seq;
725
+ }
726
+ const named = {
727
+ a: "\x07",
728
+ b: "\b",
729
+ e: "\x1B",
730
+ f: "\f",
731
+ n: `
732
+ `,
733
+ r: "\r",
734
+ t: "\t",
735
+ v: "\v",
736
+ "\\": "\\",
737
+ "'": "'",
738
+ '"': '"',
739
+ "?": "?"
740
+ };
741
+ return named[seq] ?? seq;
742
+ });
743
+ }
744
+ function stripShellQuoting(command) {
745
+ const joined = command.replace(/\\\r?\n/g, "");
746
+ const ansiDecoded = joined.replace(/\$'((?:[^'\\]|\\.)*)'/g, (_, body) => decodeAnsiC(body));
747
+ return ansiDecoded.replace(/\\(.)/g, "$1").replace(/['"]/g, "");
748
+ }
658
749
  function statGitHeadMtimeMs(cwd) {
659
750
  try {
660
751
  return statSync3(join2(cwd, ".git", "HEAD")).mtimeMs;
@@ -899,11 +990,82 @@ function blockEnvFiles(ctx) {
899
990
  }
900
991
  return allow();
901
992
  }
993
+ function quoteAwareSegments(command) {
994
+ const segments = [];
995
+ let tokens = [];
996
+ let token = "";
997
+ let quote = null;
998
+ const endToken = () => {
999
+ if (token)
1000
+ tokens.push(token);
1001
+ token = "";
1002
+ };
1003
+ const endSegment = () => {
1004
+ endToken();
1005
+ if (tokens.length)
1006
+ segments.push(tokens);
1007
+ tokens = [];
1008
+ };
1009
+ for (let i = 0;i < command.length; i++) {
1010
+ const c = command[i];
1011
+ if (quote) {
1012
+ if (c === "\\" && quote === '"' && i + 1 < command.length) {
1013
+ token += command[++i];
1014
+ continue;
1015
+ }
1016
+ if (c === quote) {
1017
+ quote = null;
1018
+ continue;
1019
+ }
1020
+ token += c;
1021
+ continue;
1022
+ }
1023
+ if (c === "\\" && i + 1 < command.length) {
1024
+ token += command[++i];
1025
+ continue;
1026
+ }
1027
+ if (c === '"' || c === "'") {
1028
+ quote = c;
1029
+ continue;
1030
+ }
1031
+ if (/\s/.test(c)) {
1032
+ endToken();
1033
+ continue;
1034
+ }
1035
+ if (/[;&|\n\r(){}`]/.test(c)) {
1036
+ endSegment();
1037
+ continue;
1038
+ }
1039
+ token += c;
1040
+ }
1041
+ endSegment();
1042
+ return segments;
1043
+ }
1044
+ function namesElevation(command, depth = 0) {
1045
+ for (const tokens of quoteAwareSegments(command)) {
1046
+ let i = 0;
1047
+ while (i < tokens.length) {
1048
+ const token = tokens[i];
1049
+ const base = token.slice(token.lastIndexOf("/") + 1);
1050
+ if (base === "sudo" || base === "doas")
1051
+ return true;
1052
+ const isSkippable = ENV_ASSIGNMENT_RE.test(token) || token.startsWith("-") || token.startsWith(">") || token.startsWith("<") || RUNNER_OPERAND_RE.test(token) || COMMAND_PREFIX_TOKENS.has(base);
1053
+ if (!isSkippable)
1054
+ break;
1055
+ if (EVAL_FLAG_RE.test(token) && depth < 3 && i + 1 < tokens.length) {
1056
+ if (namesElevation(tokens[i + 1], depth + 1))
1057
+ return true;
1058
+ }
1059
+ i++;
1060
+ }
1061
+ }
1062
+ return false;
1063
+ }
902
1064
  function blockSudo(ctx) {
903
1065
  if (ctx.toolName !== "Bash")
904
1066
  return allow();
905
1067
  const cmd = getCommand(ctx).trimStart();
906
- if (SUDO_RE.test(cmd) || cmd.startsWith("sudo ")) {
1068
+ if (namesElevation(cmd)) {
907
1069
  const allowPatterns = ctx.params?.allowPatterns ?? [];
908
1070
  if (allowPatterns.some((p) => matchesAllowedPattern(cmd, p)))
909
1071
  return allow();
@@ -917,6 +1079,15 @@ function blockSudo(ctx) {
917
1079
  }
918
1080
  return allow();
919
1081
  }
1082
+ function blockSelfPause(ctx) {
1083
+ if (ctx.toolName !== "Bash")
1084
+ return allow();
1085
+ const cmd = getCommand(ctx);
1086
+ if (namesSelfPause(cmd) || namesSelfPause(stripShellQuoting(cmd))) {
1087
+ return deny("Pausing failproofai enforcement is a human action, not an agent one. " + "If a policy is blocking legitimate work, say so and let the operator decide.");
1088
+ }
1089
+ return allow();
1090
+ }
920
1091
  function blockCurlPipeSh(ctx) {
921
1092
  if (ctx.toolName !== "Bash")
922
1093
  return allow();
@@ -1142,7 +1313,7 @@ function blockReadOutsideCwd(ctx) {
1142
1313
  const paths = extractAbsolutePaths(cmd);
1143
1314
  const cwdWithSep2 = cwd.endsWith("/") ? cwd : cwd + "/";
1144
1315
  for (const p of paths) {
1145
- const resolved3 = resolve2(cwd, p);
1316
+ const resolved3 = resolve3(cwd, p);
1146
1317
  if (isClaudeSettingsFile(resolved3)) {
1147
1318
  return deny(`Reading agent settings file blocked: ${resolved3}`);
1148
1319
  }
@@ -1163,7 +1334,7 @@ function blockReadOutsideCwd(ctx) {
1163
1334
  const target = filePath || searchPath;
1164
1335
  if (!target)
1165
1336
  return allow();
1166
- const resolved2 = resolve2(cwd, target);
1337
+ const resolved2 = resolve3(cwd, target);
1167
1338
  if (isClaudeSettingsFile(resolved2)) {
1168
1339
  return deny(`Reading agent settings file blocked: ${resolved2}`);
1169
1340
  }
@@ -1654,7 +1825,7 @@ function registerBuiltinPolicies(enabledNames) {
1654
1825
  }
1655
1826
  }
1656
1827
  }
1657
- var isClaudeInternalPath, isClaudeSettingsFile, SHELL_OPERATORS, SHELL_METACHAR_RE, JWT_RE, API_KEY_PATTERNS, CONNECTION_STRING_RE, PRIVATE_KEY_RE, BEARER_TOKEN_RE, SQL_TOOL_RE, DESTRUCTIVE_SQL_RE, DELETE_NO_WHERE_RE, SQL_WHERE_RE, SCHEMA_ALTER_RE, PUBLISH_CMD_RE, ENV_PRINTENV_RE, ECHO_ENV_RE, EXPORT_RE, PS_ENV_VAR_RE, PS_CHILDITEM_ENV_RE, DOTNET_GETENV_RE, CMD_ECHO_ENV_RE, ENV_FILE_PATH_RE, ENV_CMD_RE, SUDO_RE, PS_ELEVATION_RE, RUNAS_RE, CURL_PIPE_SH_RE, PS_WEB_PIPE_RE, SHORT_FLAG_BUNDLE_RE, SAFE_FORCE_PREFIXES, SECRET_FILE_RE, SECRET_FILE_ID_RSA_RE, SECRET_FILE_CREDENTIALS_RE, GIT_COMMIT_MERGE_RE, FAILPROOFAI_CLI_RE, FAILPROOFAI_UNINSTALL_RE, GIT_AMEND_RE, GIT_STASH_DROP_RE, GIT_ADD_ALL_RE, NPM_GLOBAL_RE, YARN_GLOBAL_RE, PNPM_GLOBAL_RE, BUN_GLOBAL_RE, CARGO_INSTALL_RE, PIP_SYSTEM_RE, PKG_MANAGER_DETECTORS, NOHUP_RE, SCREEN_DETACH_RE, TMUX_DETACH_RE, DISOWN_RE, BACKGROUND_AMPERSAND_RE, KUBECTL_RE, TERRAFORM_RE, AWS_CLI_RE, GCLOUD_RE, AZ_CLI_RE, HELM_RE, GH_PIPELINE_RE, gitBranchCache, GIT_BRANCH_CACHE_MAX_ENTRIES = 500, HOME_PREFIX_RE, RM_CMD_RE, FIND_CMD_RE, FIND_EXEC_RE, FIND_GLOBAL_OPT_RE, FIND_EXPR_START_RE, SCRATCH_ROOTS, CATASTROPHIC_DEPTH = 2, READ_LIKE_CMDS, TOOL_CALL_TRACKER_MAX_BYTES = 65536, SEGMENT_SPLIT_RE, BUILTIN_POLICIES;
1828
+ var isClaudeInternalPath, isClaudeSettingsFile, SHELL_OPERATORS, SHELL_METACHAR_RE, JWT_RE, API_KEY_PATTERNS, CONNECTION_STRING_RE, PRIVATE_KEY_RE, BEARER_TOKEN_RE, SQL_TOOL_RE, DESTRUCTIVE_SQL_RE, DELETE_NO_WHERE_RE, SQL_WHERE_RE, SCHEMA_ALTER_RE, PUBLISH_CMD_RE, ENV_PRINTENV_RE, ECHO_ENV_RE, EXPORT_RE, PS_ENV_VAR_RE, PS_CHILDITEM_ENV_RE, DOTNET_GETENV_RE, CMD_ECHO_ENV_RE, ENV_FILE_PATH_RE, ENV_CMD_RE, PS_ELEVATION_RE, RUNAS_RE, CURL_PIPE_SH_RE, SEGMENT_SEPARATORS, COMMAND_PREFIX_TOKENS, SELF_BINARY_TOKEN_RE, CONFIG_SUBCOMMAND_RE, PAUSE_FLAG_RE, ENV_ASSIGNMENT_RE, RUNNER_OPERAND_RE, PS_WEB_PIPE_RE, SHORT_FLAG_BUNDLE_RE, SAFE_FORCE_PREFIXES, SECRET_FILE_RE, SECRET_FILE_ID_RSA_RE, SECRET_FILE_CREDENTIALS_RE, GIT_COMMIT_MERGE_RE, FAILPROOFAI_CLI_RE, FAILPROOFAI_UNINSTALL_RE, GIT_AMEND_RE, GIT_STASH_DROP_RE, GIT_ADD_ALL_RE, NPM_GLOBAL_RE, YARN_GLOBAL_RE, PNPM_GLOBAL_RE, BUN_GLOBAL_RE, CARGO_INSTALL_RE, PIP_SYSTEM_RE, PKG_MANAGER_DETECTORS, NOHUP_RE, SCREEN_DETACH_RE, TMUX_DETACH_RE, DISOWN_RE, BACKGROUND_AMPERSAND_RE, KUBECTL_RE, TERRAFORM_RE, AWS_CLI_RE, GCLOUD_RE, AZ_CLI_RE, HELM_RE, GH_PIPELINE_RE, gitBranchCache, GIT_BRANCH_CACHE_MAX_ENTRIES = 500, EVAL_FLAG_RE, HOME_PREFIX_RE, RM_CMD_RE, FIND_CMD_RE, FIND_EXEC_RE, FIND_GLOBAL_OPT_RE, FIND_EXPR_START_RE, SCRATCH_ROOTS, CATASTROPHIC_DEPTH = 2, READ_LIKE_CMDS, TOOL_CALL_TRACKER_MAX_BYTES = 65536, SEGMENT_SPLIT_RE, BUILTIN_POLICIES;
1658
1829
  var init_builtin_policies = __esm(() => {
1659
1830
  init_hook_logger();
1660
1831
  isClaudeInternalPath = isAgentInternalPath;
@@ -1691,10 +1862,48 @@ var init_builtin_policies = __esm(() => {
1691
1862
  CMD_ECHO_ENV_RE = /echo\s+%[A-Za-z_]/i;
1692
1863
  ENV_FILE_PATH_RE = /(?:^|[\\/])\.env(?:\.|$)/;
1693
1864
  ENV_CMD_RE = /\.env(?:\b|\s|$|\.)/;
1694
- SUDO_RE = /(?:^|;|&&|\|\|)\s*sudo\s/;
1695
1865
  PS_ELEVATION_RE = /Start-Process\s+.*-Verb\s+RunAs/i;
1696
1866
  RUNAS_RE = /(?:^|;|&&|\|\|)\s*runas\s/i;
1697
1867
  CURL_PIPE_SH_RE = /(?:curl|wget)\s.*\|\s*(?:sh|bash|zsh|dash|ksh|csh|tcsh|fish|ash)\b/;
1868
+ SEGMENT_SEPARATORS = /[;&|\n\r(){}`]+/;
1869
+ COMMAND_PREFIX_TOKENS = new Set([
1870
+ "npx",
1871
+ "bunx",
1872
+ "pnpx",
1873
+ "npm",
1874
+ "pnpm",
1875
+ "yarn",
1876
+ "dlx",
1877
+ "exec",
1878
+ "run",
1879
+ "node",
1880
+ "bun",
1881
+ "deno",
1882
+ "env",
1883
+ "command",
1884
+ "builtin",
1885
+ "nohup",
1886
+ "setsid",
1887
+ "time",
1888
+ "timeout",
1889
+ "nice",
1890
+ "stdbuf",
1891
+ "xargs",
1892
+ "sudo",
1893
+ "doas",
1894
+ "sh",
1895
+ "bash",
1896
+ "zsh",
1897
+ "dash",
1898
+ "ksh",
1899
+ "fish",
1900
+ "ash"
1901
+ ]);
1902
+ SELF_BINARY_TOKEN_RE = /(?:^|\/)failproofai[^/]*$/;
1903
+ CONFIG_SUBCOMMAND_RE = /^(?:config|configure|setup)$/;
1904
+ PAUSE_FLAG_RE = /^--pause(?:=|$)/;
1905
+ ENV_ASSIGNMENT_RE = /^[A-Za-z_][A-Za-z0-9_]*=/;
1906
+ RUNNER_OPERAND_RE = /^\d+[a-z]*$/i;
1698
1907
  PS_WEB_PIPE_RE = /(?:Invoke-WebRequest|iwr|Invoke-RestMethod|irm)\s+.*\|\s*(?:Invoke-Expression|iex)/i;
1699
1908
  SHORT_FLAG_BUNDLE_RE = /^-[a-zA-Z]*f[a-zA-Z]*$/;
1700
1909
  SAFE_FORCE_PREFIXES = ["--force-with-lease", "--force-if-includes"];
@@ -1738,6 +1947,7 @@ var init_builtin_policies = __esm(() => {
1738
1947
  HELM_RE = /(?:^|[;\n]|&&|\|\|?|&)\s*helm(?:\s|$)/;
1739
1948
  GH_PIPELINE_RE = /(?:^|[;\n]|&&|\|\|?|&)\s*gh\s+(?:workflow\s+(?:run|enable|disable)|run\s+(?:rerun|cancel)|pr\s+merge|release\s+(?:create|delete)|cache\s+delete|secret\s+(?:set|delete))\b/;
1740
1949
  gitBranchCache = new Map;
1950
+ EVAL_FLAG_RE = /^-{1,2}c$/;
1741
1951
  HOME_PREFIX_RE = /^(?:~[A-Za-z0-9_.-]*|\$HOME|\$\{HOME\})(?=$|\/)/;
1742
1952
  RM_CMD_RE = /^(?:\/\S*\/)?rm$/;
1743
1953
  FIND_CMD_RE = /^(?:\/\S*\/)?find$/;
@@ -1842,6 +2052,16 @@ var init_builtin_policies = __esm(() => {
1842
2052
  }
1843
2053
  }
1844
2054
  },
2055
+ {
2056
+ name: "block-self-pause",
2057
+ displayTitle: "Tried to pause failproofai enforcement",
2058
+ impact: "An agent that can pause enforcement can switch off every other policy.",
2059
+ description: "Block agents from pausing failproofai enforcement",
2060
+ fn: blockSelfPause,
2061
+ match: { events: ["PreToolUse", "PermissionRequest"], toolNames: ["Bash"] },
2062
+ defaultEnabled: true,
2063
+ category: "Dangerous Commands"
2064
+ },
1845
2065
  {
1846
2066
  name: "block-sudo",
1847
2067
  displayTitle: "Tried to run a command with sudo",
@@ -2285,12 +2505,1080 @@ var init_builtin_policies = __esm(() => {
2285
2505
  });
2286
2506
 
2287
2507
  // package.json
2288
- var version = "1.0.0-beta.0";
2508
+ var version = "1.0.0-beta.10";
2289
2509
  var init_package = () => {};
2290
2510
 
2291
2511
  // src/posthog-key.ts
2292
2512
  var POSTHOG_API_KEY = "phc_Ac1Ww1GqKc0z1SyrRWbmatEeQdlOQIsDEEdP8l8JRgX", POSTHOG_PRODUCT = "failproofai-oss";
2293
2513
 
2514
+ // node_modules/smol-toml/dist/date.js
2515
+ var DATE_TIME_RE, TomlDate;
2516
+ var init_date = __esm(() => {
2517
+ /*!
2518
+ * Copyright (c) Squirrel Chat et al., All rights reserved.
2519
+ * SPDX-License-Identifier: BSD-3-Clause
2520
+ *
2521
+ * Redistribution and use in source and binary forms, with or without
2522
+ * modification, are permitted provided that the following conditions are met:
2523
+ *
2524
+ * 1. Redistributions of source code must retain the above copyright notice, this
2525
+ * list of conditions and the following disclaimer.
2526
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
2527
+ * this list of conditions and the following disclaimer in the
2528
+ * documentation and/or other materials provided with the distribution.
2529
+ * 3. Neither the name of the copyright holder nor the names of its contributors
2530
+ * may be used to endorse or promote products derived from this software without
2531
+ * specific prior written permission.
2532
+ *
2533
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
2534
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
2535
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2536
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
2537
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2538
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2539
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
2540
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2541
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2542
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2543
+ */
2544
+ DATE_TIME_RE = /^(\d{4}-\d{2}-\d{2})?[T ]?(?:(\d{2}):\d{2}(?::\d{2}(?:\.\d+)?)?)?(Z|[-+]\d{2}:\d{2})?$/i;
2545
+ TomlDate = class TomlDate extends Date {
2546
+ #hasDate = false;
2547
+ #hasTime = false;
2548
+ #offset = null;
2549
+ constructor(date) {
2550
+ let hasDate = true;
2551
+ let hasTime = true;
2552
+ let offset = "Z";
2553
+ if (typeof date === "string") {
2554
+ let match = date.match(DATE_TIME_RE);
2555
+ if (match) {
2556
+ if (!match[1]) {
2557
+ hasDate = false;
2558
+ date = `0000-01-01T${date}`;
2559
+ }
2560
+ hasTime = !!match[2];
2561
+ hasTime && date[10] === " " && (date = date.replace(" ", "T"));
2562
+ if (match[2] && +match[2] > 23) {
2563
+ date = "";
2564
+ } else {
2565
+ offset = match[3] || null;
2566
+ date = date.toUpperCase();
2567
+ if (!offset && hasTime)
2568
+ date += "Z";
2569
+ }
2570
+ } else {
2571
+ date = "";
2572
+ }
2573
+ }
2574
+ super(date);
2575
+ if (!isNaN(this.getTime())) {
2576
+ this.#hasDate = hasDate;
2577
+ this.#hasTime = hasTime;
2578
+ this.#offset = offset;
2579
+ }
2580
+ }
2581
+ isDateTime() {
2582
+ return this.#hasDate && this.#hasTime;
2583
+ }
2584
+ isLocal() {
2585
+ return !this.#hasDate || !this.#hasTime || !this.#offset;
2586
+ }
2587
+ isDate() {
2588
+ return this.#hasDate && !this.#hasTime;
2589
+ }
2590
+ isTime() {
2591
+ return this.#hasTime && !this.#hasDate;
2592
+ }
2593
+ isValid() {
2594
+ return this.#hasDate || this.#hasTime;
2595
+ }
2596
+ toISOString() {
2597
+ let iso = super.toISOString();
2598
+ if (this.isDate())
2599
+ return iso.slice(0, 10);
2600
+ if (this.isTime())
2601
+ return iso.slice(11, 23);
2602
+ if (this.#offset === null)
2603
+ return iso.slice(0, -1);
2604
+ if (this.#offset === "Z")
2605
+ return iso;
2606
+ let offset = +this.#offset.slice(1, 3) * 60 + +this.#offset.slice(4, 6);
2607
+ offset = this.#offset[0] === "-" ? offset : -offset;
2608
+ let offsetDate = new Date(this.getTime() - offset * 60000);
2609
+ return offsetDate.toISOString().slice(0, -1) + this.#offset;
2610
+ }
2611
+ static wrapAsOffsetDateTime(jsDate, offset = "Z") {
2612
+ let date = new TomlDate(jsDate);
2613
+ date.#offset = offset;
2614
+ return date;
2615
+ }
2616
+ static wrapAsLocalDateTime(jsDate) {
2617
+ let date = new TomlDate(jsDate);
2618
+ date.#offset = null;
2619
+ return date;
2620
+ }
2621
+ static wrapAsLocalDate(jsDate) {
2622
+ let date = new TomlDate(jsDate);
2623
+ date.#hasTime = false;
2624
+ date.#offset = null;
2625
+ return date;
2626
+ }
2627
+ static wrapAsLocalTime(jsDate) {
2628
+ let date = new TomlDate(jsDate);
2629
+ date.#hasDate = false;
2630
+ date.#offset = null;
2631
+ return date;
2632
+ }
2633
+ };
2634
+ });
2635
+
2636
+ // node_modules/smol-toml/dist/error.js
2637
+ function getLineColFromPtr(string, ptr) {
2638
+ let lines = string.slice(0, ptr).split(/\r\n|\n|\r/g);
2639
+ return [lines.length, lines.pop().length + 1];
2640
+ }
2641
+ function makeCodeBlock(string, line, column) {
2642
+ let lines = string.split(/\r\n|\n|\r/g);
2643
+ let codeblock = "";
2644
+ let numberLen = (Math.log10(line + 1) | 0) + 1;
2645
+ for (let i = line - 1;i <= line + 1; i++) {
2646
+ let l = lines[i - 1];
2647
+ if (!l)
2648
+ continue;
2649
+ codeblock += i.toString().padEnd(numberLen, " ");
2650
+ codeblock += ": ";
2651
+ codeblock += l;
2652
+ codeblock += `
2653
+ `;
2654
+ if (i === line) {
2655
+ codeblock += " ".repeat(numberLen + column + 2);
2656
+ codeblock += `^
2657
+ `;
2658
+ }
2659
+ }
2660
+ return codeblock;
2661
+ }
2662
+ var TomlError;
2663
+ var init_error = __esm(() => {
2664
+ /*!
2665
+ * Copyright (c) Squirrel Chat et al., All rights reserved.
2666
+ * SPDX-License-Identifier: BSD-3-Clause
2667
+ *
2668
+ * Redistribution and use in source and binary forms, with or without
2669
+ * modification, are permitted provided that the following conditions are met:
2670
+ *
2671
+ * 1. Redistributions of source code must retain the above copyright notice, this
2672
+ * list of conditions and the following disclaimer.
2673
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
2674
+ * this list of conditions and the following disclaimer in the
2675
+ * documentation and/or other materials provided with the distribution.
2676
+ * 3. Neither the name of the copyright holder nor the names of its contributors
2677
+ * may be used to endorse or promote products derived from this software without
2678
+ * specific prior written permission.
2679
+ *
2680
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
2681
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
2682
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2683
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
2684
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2685
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2686
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
2687
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2688
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2689
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2690
+ */
2691
+ TomlError = class TomlError extends Error {
2692
+ line;
2693
+ column;
2694
+ codeblock;
2695
+ constructor(message, options) {
2696
+ const [line, column] = getLineColFromPtr(options.toml, options.ptr);
2697
+ const codeblock = makeCodeBlock(options.toml, line, column);
2698
+ super(`Invalid TOML document: ${message}
2699
+
2700
+ ${codeblock}`, options);
2701
+ this.line = line;
2702
+ this.column = column;
2703
+ this.codeblock = codeblock;
2704
+ }
2705
+ };
2706
+ });
2707
+
2708
+ // node_modules/smol-toml/dist/primitive.js
2709
+ function parseString(str, ptr) {
2710
+ let c = str[ptr++];
2711
+ let first = c;
2712
+ let isLiteral = c === "'";
2713
+ let isMultiline = c === str[ptr] && c === str[ptr + 1];
2714
+ if (isMultiline) {
2715
+ if (str[ptr += 2] === `
2716
+ `)
2717
+ ptr++;
2718
+ else if (str[ptr] === "\r" && str[ptr + 1] === `
2719
+ `)
2720
+ ptr += 2;
2721
+ }
2722
+ let parsed = "";
2723
+ let sliceStart = ptr;
2724
+ let state = 0;
2725
+ for (let i = ptr;i < str.length; i++) {
2726
+ c = str[i];
2727
+ if (isMultiline && (c === `
2728
+ ` || c === "\r" && str[i + 1] === `
2729
+ `)) {
2730
+ state = state && 3;
2731
+ } else if (c < " " && c !== "\t" || c === "") {
2732
+ throw new TomlError("control characters are not allowed in strings", {
2733
+ toml: str,
2734
+ ptr: i
2735
+ });
2736
+ } else if ((!state || state === 3) && c === first && (!isMultiline || str[i + 1] === first && str[i + 2] === first)) {
2737
+ if (isMultiline) {
2738
+ if (str[i + 3] === first)
2739
+ i++;
2740
+ if (str[i + 3] === first)
2741
+ i++;
2742
+ }
2743
+ return [
2744
+ state ? parsed : parsed + str.slice(sliceStart, i),
2745
+ i + (isMultiline ? 3 : 1)
2746
+ ];
2747
+ } else if (!state) {
2748
+ if (!isLiteral && c === "\\") {
2749
+ parsed += str.slice(sliceStart, sliceStart = i);
2750
+ state = 1;
2751
+ }
2752
+ } else if (state === 1) {
2753
+ if (c === "x" || c === "u" || c === "U") {
2754
+ let value = 0;
2755
+ let len = c === "x" ? 2 : c === "u" ? 4 : 8;
2756
+ for (let j = 0;j < len; j++, i++) {
2757
+ let hex = str.charCodeAt(i + 1);
2758
+ let digit = hex >= 48 && hex <= 57 ? hex - 48 : hex >= 65 && hex <= 70 ? hex - 65 + 10 : hex >= 97 && hex <= 102 ? hex - 97 + 10 : -1;
2759
+ if (digit < 0)
2760
+ throw new TomlError("invalid non-hex character in unicode escape", { toml: str, ptr: i + 1 });
2761
+ value = value << 4 | digit;
2762
+ }
2763
+ if (value < 0 || value > 1114111 || value >= 55296 && value <= 57343) {
2764
+ throw new TomlError("invalid unicode escape", { toml: str, ptr: i });
2765
+ }
2766
+ parsed += String.fromCodePoint(value);
2767
+ sliceStart = i + 1;
2768
+ state = 0;
2769
+ } else if (c === " " || c === "\t") {
2770
+ state = 2;
2771
+ } else {
2772
+ if (c === "b")
2773
+ parsed += "\b";
2774
+ else if (c === "t")
2775
+ parsed += "\t";
2776
+ else if (c === "n")
2777
+ parsed += `
2778
+ `;
2779
+ else if (c === "f")
2780
+ parsed += "\f";
2781
+ else if (c === "r")
2782
+ parsed += "\r";
2783
+ else if (c === "e")
2784
+ parsed += "\x1B";
2785
+ else if (c === '"')
2786
+ parsed += '"';
2787
+ else if (c === "\\")
2788
+ parsed += "\\";
2789
+ else
2790
+ throw new TomlError("unrecognized escape sequence", { toml: str, ptr: i });
2791
+ sliceStart = i + 1;
2792
+ state = 0;
2793
+ }
2794
+ } else if (c !== " " && c !== "\t") {
2795
+ if (state === 2) {
2796
+ throw new TomlError("invalid escape: only line-ending whitespace may be escaped", {
2797
+ toml: str,
2798
+ ptr: sliceStart
2799
+ });
2800
+ }
2801
+ state = !isLiteral && c === "\\" ? 1 : 0;
2802
+ sliceStart = i;
2803
+ }
2804
+ }
2805
+ throw new TomlError("unfinished string", { toml: str, ptr });
2806
+ }
2807
+ function parseValue(value, toml, ptr, integersAsBigInt) {
2808
+ if (value === "true")
2809
+ return true;
2810
+ if (value === "false")
2811
+ return false;
2812
+ if (value === "-inf")
2813
+ return -Infinity;
2814
+ if (value === "inf" || value === "+inf")
2815
+ return Infinity;
2816
+ if (value === "nan" || value === "+nan" || value === "-nan")
2817
+ return NaN;
2818
+ if (value === "-0")
2819
+ return integersAsBigInt ? 0n : 0;
2820
+ let isInt = INT_REGEX.test(value);
2821
+ if (isInt || FLOAT_REGEX.test(value)) {
2822
+ if (LEADING_ZERO.test(value)) {
2823
+ throw new TomlError("leading zeroes are not allowed", {
2824
+ toml,
2825
+ ptr
2826
+ });
2827
+ }
2828
+ value = value.replace(/_/g, "");
2829
+ let numeric = +value;
2830
+ if (isNaN(numeric)) {
2831
+ throw new TomlError("invalid number", {
2832
+ toml,
2833
+ ptr
2834
+ });
2835
+ }
2836
+ if (isInt) {
2837
+ if ((isInt = !Number.isSafeInteger(numeric)) && !integersAsBigInt) {
2838
+ throw new TomlError("integer value cannot be represented losslessly", {
2839
+ toml,
2840
+ ptr
2841
+ });
2842
+ }
2843
+ if (isInt || integersAsBigInt === true)
2844
+ numeric = BigInt(value);
2845
+ }
2846
+ return numeric;
2847
+ }
2848
+ const date = new TomlDate(value);
2849
+ if (!date.isValid()) {
2850
+ throw new TomlError("invalid value", {
2851
+ toml,
2852
+ ptr
2853
+ });
2854
+ }
2855
+ return date;
2856
+ }
2857
+ var INT_REGEX, FLOAT_REGEX, LEADING_ZERO;
2858
+ var init_primitive = __esm(() => {
2859
+ init_date();
2860
+ init_error();
2861
+ /*!
2862
+ * Copyright (c) Squirrel Chat et al., All rights reserved.
2863
+ * SPDX-License-Identifier: BSD-3-Clause
2864
+ *
2865
+ * Redistribution and use in source and binary forms, with or without
2866
+ * modification, are permitted provided that the following conditions are met:
2867
+ *
2868
+ * 1. Redistributions of source code must retain the above copyright notice, this
2869
+ * list of conditions and the following disclaimer.
2870
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
2871
+ * this list of conditions and the following disclaimer in the
2872
+ * documentation and/or other materials provided with the distribution.
2873
+ * 3. Neither the name of the copyright holder nor the names of its contributors
2874
+ * may be used to endorse or promote products derived from this software without
2875
+ * specific prior written permission.
2876
+ *
2877
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
2878
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
2879
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2880
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
2881
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2882
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2883
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
2884
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2885
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2886
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2887
+ */
2888
+ INT_REGEX = /^((0x[0-9a-fA-F](_?[0-9a-fA-F])*)|(([+-]|0[ob])?\d(_?\d)*))$/;
2889
+ FLOAT_REGEX = /^[+-]?\d(_?\d)*(\.\d(_?\d)*)?([eE][+-]?\d(_?\d)*)?$/;
2890
+ LEADING_ZERO = /^[+-]?0[0-9_]/;
2891
+ });
2892
+
2893
+ // node_modules/smol-toml/dist/util.js
2894
+ function indexOfNewline(str, start = 0, end = str.length) {
2895
+ let idx = str.indexOf(`
2896
+ `, start);
2897
+ if (str[idx - 1] === "\r")
2898
+ idx--;
2899
+ return idx <= end ? idx : -1;
2900
+ }
2901
+ function skipComment(str, ptr) {
2902
+ for (let i = ptr;i < str.length; i++) {
2903
+ let c = str[i];
2904
+ if (c === `
2905
+ `)
2906
+ return i;
2907
+ if (c === "\r" && str[i + 1] === `
2908
+ `)
2909
+ return i + 1;
2910
+ if (c < " " && c !== "\t" || c === "") {
2911
+ throw new TomlError("control characters are not allowed in comments", {
2912
+ toml: str,
2913
+ ptr
2914
+ });
2915
+ }
2916
+ }
2917
+ return str.length;
2918
+ }
2919
+ function skipVoid(str, ptr, banNewLines, banComments) {
2920
+ let c;
2921
+ while (true) {
2922
+ while ((c = str[ptr]) === " " || c === "\t" || !banNewLines && (c === `
2923
+ ` || c === "\r" && str[ptr + 1] === `
2924
+ `))
2925
+ ptr++;
2926
+ if (banComments || c !== "#")
2927
+ break;
2928
+ ptr = skipComment(str, ptr);
2929
+ }
2930
+ return ptr;
2931
+ }
2932
+ function skipUntil(str, ptr, sep, end, banNewLines = false) {
2933
+ if (!end) {
2934
+ ptr = indexOfNewline(str, ptr);
2935
+ return ptr < 0 ? str.length : ptr;
2936
+ }
2937
+ for (let i = ptr;i < str.length; i++) {
2938
+ let c = str[i];
2939
+ if (c === "#") {
2940
+ i = indexOfNewline(str, i);
2941
+ if (i < 0)
2942
+ break;
2943
+ } else if (c === sep) {
2944
+ return i + 1;
2945
+ } else if (c === end || banNewLines && (c === `
2946
+ ` || c === "\r" && str[i + 1] === `
2947
+ `)) {
2948
+ return i;
2949
+ }
2950
+ }
2951
+ throw new TomlError("cannot find end of structure", {
2952
+ toml: str,
2953
+ ptr
2954
+ });
2955
+ }
2956
+ var init_util = __esm(() => {
2957
+ init_error();
2958
+ /*!
2959
+ * Copyright (c) Squirrel Chat et al., All rights reserved.
2960
+ * SPDX-License-Identifier: BSD-3-Clause
2961
+ *
2962
+ * Redistribution and use in source and binary forms, with or without
2963
+ * modification, are permitted provided that the following conditions are met:
2964
+ *
2965
+ * 1. Redistributions of source code must retain the above copyright notice, this
2966
+ * list of conditions and the following disclaimer.
2967
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
2968
+ * this list of conditions and the following disclaimer in the
2969
+ * documentation and/or other materials provided with the distribution.
2970
+ * 3. Neither the name of the copyright holder nor the names of its contributors
2971
+ * may be used to endorse or promote products derived from this software without
2972
+ * specific prior written permission.
2973
+ *
2974
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
2975
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
2976
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2977
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
2978
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2979
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2980
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
2981
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2982
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2983
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2984
+ */
2985
+ });
2986
+
2987
+ // node_modules/smol-toml/dist/extract.js
2988
+ function sliceAndTrimEndOf(str, startPtr, endPtr) {
2989
+ let value = str.slice(startPtr, endPtr);
2990
+ let commentIdx = value.indexOf("#");
2991
+ if (commentIdx > -1) {
2992
+ skipComment(str, commentIdx);
2993
+ value = value.slice(0, commentIdx);
2994
+ }
2995
+ return [value.trimEnd(), commentIdx];
2996
+ }
2997
+ function extractValue(str, ptr, end, depth, integersAsBigInt) {
2998
+ if (depth === 0) {
2999
+ throw new TomlError("document contains excessively nested structures. aborting.", {
3000
+ toml: str,
3001
+ ptr
3002
+ });
3003
+ }
3004
+ let c = str[ptr];
3005
+ if (c === "[" || c === "{") {
3006
+ let [value, endPtr2] = c === "[" ? parseArray(str, ptr, depth, integersAsBigInt) : parseInlineTable(str, ptr, depth, integersAsBigInt);
3007
+ if (end) {
3008
+ endPtr2 = skipVoid(str, endPtr2);
3009
+ if (str[endPtr2] === ",")
3010
+ endPtr2++;
3011
+ else if (str[endPtr2] !== end) {
3012
+ throw new TomlError("expected comma or end of structure", {
3013
+ toml: str,
3014
+ ptr: endPtr2
3015
+ });
3016
+ }
3017
+ }
3018
+ return [value, endPtr2];
3019
+ }
3020
+ if (c === '"' || c === "'") {
3021
+ let [parsed, endPtr2] = parseString(str, ptr);
3022
+ if (end) {
3023
+ endPtr2 = skipVoid(str, endPtr2);
3024
+ if (str[endPtr2] && str[endPtr2] !== "," && str[endPtr2] !== end && str[endPtr2] !== `
3025
+ ` && str[endPtr2] !== "\r") {
3026
+ throw new TomlError("unexpected character encountered", {
3027
+ toml: str,
3028
+ ptr: endPtr2
3029
+ });
3030
+ }
3031
+ if (str[endPtr2] === ",")
3032
+ endPtr2++;
3033
+ }
3034
+ return [parsed, endPtr2];
3035
+ }
3036
+ let endPtr = skipUntil(str, ptr, ",", end);
3037
+ let slice = sliceAndTrimEndOf(str, ptr, endPtr - (str[endPtr - 1] === "," ? 1 : 0));
3038
+ if (!slice[0]) {
3039
+ throw new TomlError("incomplete key-value declaration: no value specified", {
3040
+ toml: str,
3041
+ ptr
3042
+ });
3043
+ }
3044
+ if (end && slice[1] > -1) {
3045
+ endPtr = skipVoid(str, ptr + slice[1]);
3046
+ if (str[endPtr] === ",")
3047
+ endPtr++;
3048
+ }
3049
+ return [
3050
+ parseValue(slice[0], str, ptr, integersAsBigInt),
3051
+ endPtr
3052
+ ];
3053
+ }
3054
+ var init_extract = __esm(() => {
3055
+ init_primitive();
3056
+ init_struct();
3057
+ init_util();
3058
+ init_error();
3059
+ /*!
3060
+ * Copyright (c) Squirrel Chat et al., All rights reserved.
3061
+ * SPDX-License-Identifier: BSD-3-Clause
3062
+ *
3063
+ * Redistribution and use in source and binary forms, with or without
3064
+ * modification, are permitted provided that the following conditions are met:
3065
+ *
3066
+ * 1. Redistributions of source code must retain the above copyright notice, this
3067
+ * list of conditions and the following disclaimer.
3068
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
3069
+ * this list of conditions and the following disclaimer in the
3070
+ * documentation and/or other materials provided with the distribution.
3071
+ * 3. Neither the name of the copyright holder nor the names of its contributors
3072
+ * may be used to endorse or promote products derived from this software without
3073
+ * specific prior written permission.
3074
+ *
3075
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
3076
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
3077
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
3078
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
3079
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3080
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
3081
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
3082
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
3083
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3084
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3085
+ */
3086
+ });
3087
+
3088
+ // node_modules/smol-toml/dist/struct.js
3089
+ function parseKey(str, ptr, end = "=") {
3090
+ let dot = ptr - 1;
3091
+ let parsed = [];
3092
+ let endPtr = str.indexOf(end, ptr);
3093
+ if (endPtr < 0) {
3094
+ throw new TomlError("incomplete key-value: cannot find end of key", {
3095
+ toml: str,
3096
+ ptr
3097
+ });
3098
+ }
3099
+ do {
3100
+ let c = str[ptr = ++dot];
3101
+ if (c !== " " && c !== "\t") {
3102
+ if (c === '"' || c === "'") {
3103
+ if (c === str[ptr + 1] && c === str[ptr + 2]) {
3104
+ throw new TomlError("multiline strings are not allowed in keys", {
3105
+ toml: str,
3106
+ ptr
3107
+ });
3108
+ }
3109
+ let [part, eos] = parseString(str, ptr);
3110
+ dot = str.indexOf(".", eos);
3111
+ let strEnd = str.slice(eos, dot < 0 || dot > endPtr ? endPtr : dot);
3112
+ let newLine = indexOfNewline(strEnd);
3113
+ if (newLine > -1) {
3114
+ throw new TomlError("newlines are not allowed in keys", {
3115
+ toml: str,
3116
+ ptr: ptr + dot + newLine
3117
+ });
3118
+ }
3119
+ if (strEnd.trimStart()) {
3120
+ throw new TomlError("found extra tokens after the string part", {
3121
+ toml: str,
3122
+ ptr: eos
3123
+ });
3124
+ }
3125
+ if (endPtr < eos) {
3126
+ endPtr = str.indexOf(end, eos);
3127
+ if (endPtr < 0) {
3128
+ throw new TomlError("incomplete key-value: cannot find end of key", {
3129
+ toml: str,
3130
+ ptr
3131
+ });
3132
+ }
3133
+ }
3134
+ parsed.push(part);
3135
+ } else {
3136
+ dot = str.indexOf(".", ptr);
3137
+ let part = str.slice(ptr, dot < 0 || dot > endPtr ? endPtr : dot);
3138
+ if (!KEY_PART_RE.test(part)) {
3139
+ throw new TomlError("only letter, numbers, dashes and underscores are allowed in keys", {
3140
+ toml: str,
3141
+ ptr
3142
+ });
3143
+ }
3144
+ parsed.push(part.trimEnd());
3145
+ }
3146
+ }
3147
+ } while (dot + 1 && dot < endPtr);
3148
+ return [parsed, skipVoid(str, endPtr + 1, true, true)];
3149
+ }
3150
+ function parseInlineTable(str, ptr, depth, integersAsBigInt) {
3151
+ let res = {};
3152
+ let seen = new Set;
3153
+ let c;
3154
+ ptr++;
3155
+ while ((c = str[ptr++]) !== "}" && c) {
3156
+ if (c === ",") {
3157
+ throw new TomlError("expected value, found comma", {
3158
+ toml: str,
3159
+ ptr: ptr - 1
3160
+ });
3161
+ } else if (c === "#")
3162
+ ptr = skipComment(str, ptr);
3163
+ else if (c !== " " && c !== "\t" && c !== `
3164
+ ` && c !== "\r") {
3165
+ let k;
3166
+ let t = res;
3167
+ let hasOwn = false;
3168
+ let [key, keyEndPtr] = parseKey(str, ptr - 1);
3169
+ for (let i = 0;i < key.length; i++) {
3170
+ if (i)
3171
+ t = hasOwn ? t[k] : t[k] = {};
3172
+ k = key[i];
3173
+ if ((hasOwn = Object.hasOwn(t, k)) && (typeof t[k] !== "object" || seen.has(t[k]))) {
3174
+ throw new TomlError("trying to redefine an already defined value", {
3175
+ toml: str,
3176
+ ptr
3177
+ });
3178
+ }
3179
+ if (!hasOwn && k === "__proto__") {
3180
+ Object.defineProperty(t, k, { enumerable: true, configurable: true, writable: true });
3181
+ }
3182
+ }
3183
+ if (hasOwn) {
3184
+ throw new TomlError("trying to redefine an already defined value", {
3185
+ toml: str,
3186
+ ptr
3187
+ });
3188
+ }
3189
+ let [value, valueEndPtr] = extractValue(str, keyEndPtr, "}", depth - 1, integersAsBigInt);
3190
+ seen.add(value);
3191
+ t[k] = value;
3192
+ ptr = valueEndPtr;
3193
+ }
3194
+ }
3195
+ if (!c) {
3196
+ throw new TomlError("unfinished table encountered", {
3197
+ toml: str,
3198
+ ptr
3199
+ });
3200
+ }
3201
+ return [res, ptr];
3202
+ }
3203
+ function parseArray(str, ptr, depth, integersAsBigInt) {
3204
+ let res = [];
3205
+ let c;
3206
+ ptr++;
3207
+ while ((c = str[ptr++]) !== "]" && c) {
3208
+ if (c === ",") {
3209
+ throw new TomlError("expected value, found comma", {
3210
+ toml: str,
3211
+ ptr: ptr - 1
3212
+ });
3213
+ } else if (c === "#")
3214
+ ptr = skipComment(str, ptr);
3215
+ else if (c !== " " && c !== "\t" && c !== `
3216
+ ` && c !== "\r") {
3217
+ let e = extractValue(str, ptr - 1, "]", depth - 1, integersAsBigInt);
3218
+ res.push(e[0]);
3219
+ ptr = e[1];
3220
+ }
3221
+ }
3222
+ if (!c) {
3223
+ throw new TomlError("unfinished array encountered", {
3224
+ toml: str,
3225
+ ptr
3226
+ });
3227
+ }
3228
+ return [res, ptr];
3229
+ }
3230
+ var KEY_PART_RE;
3231
+ var init_struct = __esm(() => {
3232
+ init_primitive();
3233
+ init_extract();
3234
+ init_util();
3235
+ init_error();
3236
+ /*!
3237
+ * Copyright (c) Squirrel Chat et al., All rights reserved.
3238
+ * SPDX-License-Identifier: BSD-3-Clause
3239
+ *
3240
+ * Redistribution and use in source and binary forms, with or without
3241
+ * modification, are permitted provided that the following conditions are met:
3242
+ *
3243
+ * 1. Redistributions of source code must retain the above copyright notice, this
3244
+ * list of conditions and the following disclaimer.
3245
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
3246
+ * this list of conditions and the following disclaimer in the
3247
+ * documentation and/or other materials provided with the distribution.
3248
+ * 3. Neither the name of the copyright holder nor the names of its contributors
3249
+ * may be used to endorse or promote products derived from this software without
3250
+ * specific prior written permission.
3251
+ *
3252
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
3253
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
3254
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
3255
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
3256
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3257
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
3258
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
3259
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
3260
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3261
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3262
+ */
3263
+ KEY_PART_RE = /^[a-zA-Z0-9-_]+[ \t]*$/;
3264
+ });
3265
+
3266
+ // node_modules/smol-toml/dist/parse.js
3267
+ function peekTable(key, table, meta, type) {
3268
+ let t = table;
3269
+ let m = meta;
3270
+ let k;
3271
+ let hasOwn = false;
3272
+ let state;
3273
+ for (let i = 0;i < key.length; i++) {
3274
+ if (i) {
3275
+ t = hasOwn ? t[k] : t[k] = {};
3276
+ m = (state = m[k]).c;
3277
+ if (type === 0 && (state.t === 1 || state.t === 2)) {
3278
+ return null;
3279
+ }
3280
+ if (state.t === 2) {
3281
+ let l = t.length - 1;
3282
+ t = t[l];
3283
+ m = m[l].c;
3284
+ }
3285
+ }
3286
+ k = key[i];
3287
+ if ((hasOwn = Object.hasOwn(t, k)) && m[k]?.t === 0 && m[k]?.d) {
3288
+ return null;
3289
+ }
3290
+ if (!hasOwn) {
3291
+ if (k === "__proto__") {
3292
+ Object.defineProperty(t, k, { enumerable: true, configurable: true, writable: true });
3293
+ Object.defineProperty(m, k, { enumerable: true, configurable: true, writable: true });
3294
+ }
3295
+ m[k] = {
3296
+ t: i < key.length - 1 && type === 2 ? 3 : type,
3297
+ d: false,
3298
+ i: 0,
3299
+ c: {}
3300
+ };
3301
+ }
3302
+ }
3303
+ state = m[k];
3304
+ if (state.t !== type && !(type === 1 && state.t === 3)) {
3305
+ return null;
3306
+ }
3307
+ if (type === 2) {
3308
+ if (!state.d) {
3309
+ state.d = true;
3310
+ t[k] = [];
3311
+ }
3312
+ t[k].push(t = {});
3313
+ state.c[state.i++] = state = { t: 1, d: false, i: 0, c: {} };
3314
+ }
3315
+ if (state.d) {
3316
+ return null;
3317
+ }
3318
+ state.d = true;
3319
+ if (type === 1) {
3320
+ t = hasOwn ? t[k] : t[k] = {};
3321
+ } else if (type === 0 && hasOwn) {
3322
+ return null;
3323
+ }
3324
+ return [k, t, state.c];
3325
+ }
3326
+ function parse(toml, { maxDepth = 1000, integersAsBigInt } = {}) {
3327
+ let res = {};
3328
+ let meta = {};
3329
+ let tbl = res;
3330
+ let m = meta;
3331
+ for (let ptr = skipVoid(toml, 0);ptr < toml.length; ) {
3332
+ if (toml[ptr] === "[") {
3333
+ let isTableArray = toml[++ptr] === "[";
3334
+ let k = parseKey(toml, ptr += +isTableArray, "]");
3335
+ if (isTableArray) {
3336
+ if (toml[k[1] - 1] !== "]") {
3337
+ throw new TomlError("expected end of table declaration", {
3338
+ toml,
3339
+ ptr: k[1] - 1
3340
+ });
3341
+ }
3342
+ k[1]++;
3343
+ }
3344
+ let p = peekTable(k[0], res, meta, isTableArray ? 2 : 1);
3345
+ if (!p) {
3346
+ throw new TomlError("trying to redefine an already defined table or value", {
3347
+ toml,
3348
+ ptr
3349
+ });
3350
+ }
3351
+ m = p[2];
3352
+ tbl = p[1];
3353
+ ptr = k[1];
3354
+ } else {
3355
+ let k = parseKey(toml, ptr);
3356
+ let p = peekTable(k[0], tbl, m, 0);
3357
+ if (!p) {
3358
+ throw new TomlError("trying to redefine an already defined table or value", {
3359
+ toml,
3360
+ ptr
3361
+ });
3362
+ }
3363
+ let v = extractValue(toml, k[1], undefined, maxDepth, integersAsBigInt);
3364
+ p[1][p[0]] = v[0];
3365
+ ptr = v[1];
3366
+ }
3367
+ ptr = skipVoid(toml, ptr, true);
3368
+ if (toml[ptr] && toml[ptr] !== `
3369
+ ` && toml[ptr] !== "\r") {
3370
+ throw new TomlError("each key-value declaration must be followed by an end-of-line", {
3371
+ toml,
3372
+ ptr
3373
+ });
3374
+ }
3375
+ ptr = skipVoid(toml, ptr);
3376
+ }
3377
+ return res;
3378
+ }
3379
+ var init_parse = __esm(() => {
3380
+ init_struct();
3381
+ init_extract();
3382
+ init_util();
3383
+ init_error();
3384
+ /*!
3385
+ * Copyright (c) Squirrel Chat et al., All rights reserved.
3386
+ * SPDX-License-Identifier: BSD-3-Clause
3387
+ *
3388
+ * Redistribution and use in source and binary forms, with or without
3389
+ * modification, are permitted provided that the following conditions are met:
3390
+ *
3391
+ * 1. Redistributions of source code must retain the above copyright notice, this
3392
+ * list of conditions and the following disclaimer.
3393
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
3394
+ * this list of conditions and the following disclaimer in the
3395
+ * documentation and/or other materials provided with the distribution.
3396
+ * 3. Neither the name of the copyright holder nor the names of its contributors
3397
+ * may be used to endorse or promote products derived from this software without
3398
+ * specific prior written permission.
3399
+ *
3400
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
3401
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
3402
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
3403
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
3404
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3405
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
3406
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
3407
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
3408
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3409
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3410
+ */
3411
+ });
3412
+
3413
+ // node_modules/smol-toml/dist/stringify.js
3414
+ var init_stringify = __esm(() => {
3415
+ /*!
3416
+ * Copyright (c) Squirrel Chat et al., All rights reserved.
3417
+ * SPDX-License-Identifier: BSD-3-Clause
3418
+ *
3419
+ * Redistribution and use in source and binary forms, with or without
3420
+ * modification, are permitted provided that the following conditions are met:
3421
+ *
3422
+ * 1. Redistributions of source code must retain the above copyright notice, this
3423
+ * list of conditions and the following disclaimer.
3424
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
3425
+ * this list of conditions and the following disclaimer in the
3426
+ * documentation and/or other materials provided with the distribution.
3427
+ * 3. Neither the name of the copyright holder nor the names of its contributors
3428
+ * may be used to endorse or promote products derived from this software without
3429
+ * specific prior written permission.
3430
+ *
3431
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
3432
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
3433
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
3434
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
3435
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3436
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
3437
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
3438
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
3439
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3440
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3441
+ */
3442
+ });
3443
+
3444
+ // node_modules/smol-toml/dist/index.js
3445
+ var init_dist = __esm(() => {
3446
+ init_parse();
3447
+ init_stringify();
3448
+ init_date();
3449
+ init_error();
3450
+ /*!
3451
+ * Copyright (c) Squirrel Chat et al., All rights reserved.
3452
+ * SPDX-License-Identifier: BSD-3-Clause
3453
+ *
3454
+ * Redistribution and use in source and binary forms, with or without
3455
+ * modification, are permitted provided that the following conditions are met:
3456
+ *
3457
+ * 1. Redistributions of source code must retain the above copyright notice, this
3458
+ * list of conditions and the following disclaimer.
3459
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
3460
+ * this list of conditions and the following disclaimer in the
3461
+ * documentation and/or other materials provided with the distribution.
3462
+ * 3. Neither the name of the copyright holder nor the names of its contributors
3463
+ * may be used to endorse or promote products derived from this software without
3464
+ * specific prior written permission.
3465
+ *
3466
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
3467
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
3468
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
3469
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
3470
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3471
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
3472
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
3473
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
3474
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3475
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3476
+ */
3477
+ });
3478
+
3479
+ // src/hooks/fp-config.ts
3480
+ import { chmodSync, existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync2, statSync as statSync4, writeFileSync as writeFileSync2 } from "node:fs";
3481
+ function detectLayout() {
3482
+ const raw = readVersionFile();
3483
+ if (raw) {
3484
+ if (raw.layout === LAYOUT_VERSION)
3485
+ return { kind: "current", version: raw };
3486
+ return raw.layout > LAYOUT_VERSION ? { kind: "future", found: raw.layout } : { kind: "stale", found: raw.layout };
3487
+ }
3488
+ const layoutOneMarkers = [
3489
+ legacy.policyConfig(),
3490
+ legacy.cacheDir(),
3491
+ legacy.launcherMarker(),
3492
+ legacy.lastVersion(),
3493
+ legacy.cloudCredentials(),
3494
+ legacy.ingestCredentials(),
3495
+ legacy.auditDashboard()
3496
+ ];
3497
+ return layoutOneMarkers.some((p) => existsSync3(p)) ? { kind: "stale", found: 1 } : { kind: "absent" };
3498
+ }
3499
+ function readVersionFile() {
3500
+ try {
3501
+ const parsed = parse(readFileSync2(versionFile(), "utf8"));
3502
+ const layout = Number(parsed.layout);
3503
+ if (!Number.isFinite(layout))
3504
+ return null;
3505
+ return {
3506
+ layout,
3507
+ cli: typeof parsed.cli === "string" ? parsed.cli : "",
3508
+ daemon: typeof parsed.daemon === "string" ? parsed.daemon : undefined
3509
+ };
3510
+ } catch {
3511
+ return null;
3512
+ }
3513
+ }
3514
+ function readIntervalDays(raw) {
3515
+ if (typeof raw !== "number" || !Number.isFinite(raw))
3516
+ return DEFAULT_AUDIT_INTERVAL_DAYS;
3517
+ const days = Math.floor(raw);
3518
+ if (days < MIN_AUDIT_INTERVAL_DAYS)
3519
+ return DEFAULT_AUDIT_INTERVAL_DAYS;
3520
+ return Math.min(days, MAX_AUDIT_INTERVAL_DAYS);
3521
+ }
3522
+ function readConfig() {
3523
+ try {
3524
+ const parsed = parse(readFileSync2(configFile(), "utf8"));
3525
+ const mode = parsed.mode?.kind;
3526
+ const daemon = parsed.daemon ?? {};
3527
+ const collector = parsed.collector ?? {};
3528
+ const telemetry = parsed.telemetry ?? {};
3529
+ const audit = parsed.audit ?? {};
3530
+ return {
3531
+ mode: mode === "cloud" ? "cloud" : "oss",
3532
+ daemon: { configured: daemon.configured === true },
3533
+ collector: {
3534
+ sessions: collector.sessions === true,
3535
+ hooks: collector.hooks !== false,
3536
+ hooksVerbosity: collector.hooks_verbosity === "all" || collector.hooks_verbosity === "off" ? collector.hooks_verbosity : "decisions",
3537
+ redact: collector.redact === "off" ? "off" : "minimal",
3538
+ environment: typeof collector.environment === "string" ? collector.environment : "local",
3539
+ machineId: typeof collector.machine_id === "string" ? collector.machine_id : undefined
3540
+ },
3541
+ telemetry: { enabled: telemetry.enabled !== false },
3542
+ audit: { auto: audit.auto === true, intervalDays: readIntervalDays(audit.interval_days) }
3543
+ };
3544
+ } catch {
3545
+ return structuredClone(DEFAULT_CONFIG);
3546
+ }
3547
+ }
3548
+ var DEFAULT_AUDIT_INTERVAL_DAYS = 7, MIN_AUDIT_INTERVAL_DAYS = 1, MAX_AUDIT_INTERVAL_DAYS = 90, DEFAULT_CONFIG;
3549
+ var init_fp_config = __esm(() => {
3550
+ init_dist();
3551
+ init_package();
3552
+ init_fp_home();
3553
+ DEFAULT_CONFIG = {
3554
+ mode: "oss",
3555
+ daemon: { configured: false },
3556
+ collector: {
3557
+ sessions: false,
3558
+ hooks: true,
3559
+ hooksVerbosity: "decisions",
3560
+ redact: "minimal",
3561
+ environment: "local"
3562
+ },
3563
+ telemetry: { enabled: true },
3564
+ audit: { auto: false, intervalDays: DEFAULT_AUDIT_INTERVAL_DAYS }
3565
+ };
3566
+ });
3567
+
3568
+ // lib/telemetry-enabled.ts
3569
+ function isTelemetryEnabled() {
3570
+ if (process.env.FAILPROOFAI_TELEMETRY_DISABLED === "1")
3571
+ return false;
3572
+ try {
3573
+ return readConfig().telemetry.enabled;
3574
+ } catch {
3575
+ return true;
3576
+ }
3577
+ }
3578
+ var init_telemetry_enabled = __esm(() => {
3579
+ init_fp_config();
3580
+ });
3581
+
2294
3582
  // src/hooks/hook-telemetry.ts
2295
3583
  async function sendEvent(distinctId, event, properties) {
2296
3584
  const body = JSON.stringify({
@@ -2309,7 +3597,7 @@ async function sendEvent(distinctId, event, properties) {
2309
3597
  } catch {}
2310
3598
  }
2311
3599
  async function trackHookEvent(distinctId, event, properties) {
2312
- if (process.env.FAILPROOFAI_TELEMETRY_DISABLED === "1")
3600
+ if (!isTelemetryEnabled())
2313
3601
  return;
2314
3602
  const p = sendEvent(distinctId, event, properties);
2315
3603
  pending.add(p);
@@ -2324,6 +3612,7 @@ async function flushHookTelemetry() {
2324
3612
  var API_KEY, CAPTURE_URL = "https://us.i.posthog.com/capture/", pending;
2325
3613
  var init_hook_telemetry = __esm(() => {
2326
3614
  init_package();
3615
+ init_telemetry_enabled();
2327
3616
  API_KEY = POSTHOG_API_KEY;
2328
3617
  pending = new Set;
2329
3618
  });
@@ -2387,24 +3676,48 @@ function getFileBasedId() {
2387
3676
  } catch {}
2388
3677
  return id;
2389
3678
  }
3679
+ function publishInstanceId(id) {
3680
+ let target;
3681
+ try {
3682
+ target = telemetryIdFile();
3683
+ if (fs.readFileSync(target, "utf-8").trim() === id)
3684
+ return;
3685
+ } catch {
3686
+ try {
3687
+ target = telemetryIdFile();
3688
+ } catch {
3689
+ return;
3690
+ }
3691
+ }
3692
+ try {
3693
+ fs.mkdirSync(path.dirname(target), { recursive: true });
3694
+ const tmp = `${target}.${process.pid}.tmp`;
3695
+ fs.writeFileSync(tmp, id, { encoding: "utf-8", mode: 384 });
3696
+ fs.renameSync(tmp, target);
3697
+ } catch {}
3698
+ }
2390
3699
  function getInstanceId() {
2391
3700
  if (cachedId)
2392
3701
  return cachedId;
2393
3702
  const machineId = getPlatformMachineId();
2394
3703
  if (machineId) {
2395
3704
  cachedId = hashToId(machineId);
3705
+ publishInstanceId(cachedId);
2396
3706
  return cachedId;
2397
3707
  }
2398
3708
  const sysProps = getSystemPropertiesId();
2399
3709
  if (sysProps) {
2400
3710
  cachedId = hashToId(sysProps);
3711
+ publishInstanceId(cachedId);
2401
3712
  return cachedId;
2402
3713
  }
2403
3714
  cachedId = getFileBasedId();
3715
+ publishInstanceId(cachedId);
2404
3716
  return cachedId;
2405
3717
  }
2406
3718
  var NAMESPACE = "failproofai-telemetry-v1", ID_DIR, ID_FILE, cachedId;
2407
3719
  var init_telemetry_id = __esm(() => {
3720
+ init_fp_home();
2408
3721
  ID_DIR = path.join(os.homedir(), ".failproofai");
2409
3722
  ID_FILE = path.join(ID_DIR, "instance-id");
2410
3723
  });
@@ -3158,13 +4471,43 @@ function clearCustomHooks() {
3158
4471
  const g = globalThis;
3159
4472
  g[REGISTRY_KEY2] = [];
3160
4473
  }
3161
- var REGISTRY_KEY2 = "__failproofai_custom_hooks__";
3162
- var init_custom_hooks_registry = () => {};
4474
+ var REGISTRY_KEY2 = "__failproofai_custom_hooks__", customPolicies;
4475
+ var init_custom_hooks_registry = __esm(() => {
4476
+ customPolicies = {
4477
+ add(hook) {
4478
+ getRegistry2().push(hook);
4479
+ }
4480
+ };
4481
+ });
3163
4482
 
3164
4483
  // src/hooks/loader-utils.ts
3165
- import { readFile as readFile2, writeFile as writeFile2, unlink, access } from "fs/promises";
3166
- import { resolve as resolve3, dirname as dirname2, relative } from "path";
4484
+ import { readFile as readFile2, writeFile as writeFile2, unlink, access, mkdir, lstat } from "fs/promises";
4485
+ import { tmpdir } from "os";
4486
+ import { resolve as resolve4, dirname as dirname2, relative, join as join3 } from "path";
3167
4487
  import { pathToFileURL } from "url";
4488
+ import { createHash } from "crypto";
4489
+ function isTmpArtifact(name) {
4490
+ return TMP_ARTIFACT_RE.test(name);
4491
+ }
4492
+ async function sweepStaleTmpArtifacts(dir, now = Date.now()) {
4493
+ let removed = 0;
4494
+ try {
4495
+ const { readdir, stat: stat2 } = await import("fs/promises");
4496
+ for (const name of await readdir(dir)) {
4497
+ if (!isTmpArtifact(name))
4498
+ continue;
4499
+ const path2 = resolve4(dir, name);
4500
+ try {
4501
+ const info = await stat2(path2);
4502
+ if (now - info.mtimeMs < TMP_SWEEP_MIN_AGE_MS)
4503
+ continue;
4504
+ await unlink(path2);
4505
+ removed++;
4506
+ } catch {}
4507
+ }
4508
+ } catch {}
4509
+ return removed;
4510
+ }
3168
4511
  async function fileExists(path2) {
3169
4512
  try {
3170
4513
  await access(path2);
@@ -3176,14 +4519,14 @@ async function fileExists(path2) {
3176
4519
  async function findDistIndex() {
3177
4520
  const distPath = process.env.FAILPROOFAI_DIST_PATH;
3178
4521
  if (distPath) {
3179
- const candidate = resolve3(distPath, "index.js");
4522
+ const candidate = resolve4(distPath, "index.js");
3180
4523
  if (await fileExists(candidate))
3181
4524
  return candidate;
3182
4525
  }
3183
4526
  const candidates = [
3184
- resolve3(dirname2(process.execPath), "..", "assets", "dist", "index.js"),
3185
- resolve3(process.cwd(), "dist", "index.js"),
3186
- resolve3(process.cwd(), "node_modules", "failproofai", "dist", "index.js")
4527
+ resolve4(dirname2(process.execPath), "..", "assets", "dist", "index.js"),
4528
+ resolve4(process.cwd(), "dist", "index.js"),
4529
+ resolve4(process.cwd(), "node_modules", "failproofai", "dist", "index.js")
3187
4530
  ];
3188
4531
  for (const c of candidates) {
3189
4532
  if (await fileExists(c))
@@ -3192,16 +4535,24 @@ async function findDistIndex() {
3192
4535
  return null;
3193
4536
  }
3194
4537
  async function resolveLocalImport(fromDir, specifier) {
3195
- const base = resolve3(fromDir, specifier);
3196
- const candidates = [base, `${base}.js`, `${base}.mjs`, `${base}.ts`, resolve3(base, "index.js")];
4538
+ const base = resolve4(fromDir, specifier);
4539
+ const candidates = [base, `${base}.js`, `${base}.mjs`, `${base}.ts`, resolve4(base, "index.js")];
3197
4540
  for (const c of candidates) {
3198
4541
  if (await fileExists(c))
3199
4542
  return c;
3200
4543
  }
3201
4544
  return null;
3202
4545
  }
3203
- async function createEsmShim(distIndex, distUrl) {
3204
- const shimPath = distIndex + ".__failproofai_esm_shim__.mjs";
4546
+ async function writeShim(dir, name, code, exclusive) {
4547
+ const shimPath = join3(dir, name);
4548
+ await writeFile2(shimPath, code, {
4549
+ encoding: "utf-8",
4550
+ mode: 384,
4551
+ ...exclusive ? { flag: "wx" } : {}
4552
+ });
4553
+ return shimPath;
4554
+ }
4555
+ async function createEsmShim(distIndex, distUrl, tmpSuffix = TMP_SUFFIX) {
3205
4556
  const shimCode = [
3206
4557
  `import _cjs from '${distUrl}';`,
3207
4558
  `export const customPolicies = _cjs.customPolicies;`,
@@ -3213,16 +4564,30 @@ async function createEsmShim(distIndex, distUrl) {
3213
4564
  `export default _cjs;`
3214
4565
  ].join(`
3215
4566
  `);
3216
- await writeFile2(shimPath, shimCode, "utf-8");
4567
+ const name = `failproofai-dist${tmpSuffix}.shim.mjs`;
4568
+ try {
4569
+ const dir = shimsDir();
4570
+ await mkdir(dir, { recursive: true, mode: 448 });
4571
+ const st = await lstat(dir);
4572
+ const uid = typeof process.getuid === "function" ? process.getuid() : null;
4573
+ if (!st.isDirectory() || st.isSymbolicLink() || uid !== null && st.uid !== uid || st.mode & 63) {
4574
+ throw new Error(`${dir} is not a private directory owned by this user`);
4575
+ }
4576
+ const shimPath2 = await writeShim(dir, name, shimCode, false);
4577
+ return { shimPath: shimPath2, shimUrl: pathToFileURL(shimPath2).href };
4578
+ } catch (err) {
4579
+ hookLogWarn(`policy shim directory unusable (${err instanceof Error ? err.message : String(err)}); falling back to ${tmpdir()}`);
4580
+ }
4581
+ const shimPath = await writeShim(tmpdir(), name, shimCode, true);
3217
4582
  return { shimPath, shimUrl: pathToFileURL(shimPath).href };
3218
4583
  }
3219
- async function rewriteFileTree(entryPath, distUrl, distIndex) {
4584
+ async function rewriteFileTree(entryPath, distUrl, distIndex, tmpSuffix = TMP_SUFFIX, entrySha256) {
3220
4585
  const queue = [entryPath];
3221
4586
  const visited = new Set;
3222
4587
  const tmpFiles = [];
3223
4588
  let esmShimUrl = null;
3224
4589
  if (distIndex && distUrl) {
3225
- const shim = await createEsmShim(distIndex, distUrl);
4590
+ const shim = await createEsmShim(distIndex, distUrl, tmpSuffix);
3226
4591
  tmpFiles.push(shim.shimPath);
3227
4592
  esmShimUrl = shim.shimUrl;
3228
4593
  }
@@ -3231,7 +4596,17 @@ async function rewriteFileTree(entryPath, distUrl, distIndex) {
3231
4596
  if (visited.has(filePath))
3232
4597
  continue;
3233
4598
  visited.add(filePath);
3234
- let code = await readFile2(filePath, "utf-8");
4599
+ let code;
4600
+ if (entrySha256 && filePath === entryPath) {
4601
+ const buf = await readFile2(filePath);
4602
+ const actual = createHash("sha256").update(buf).digest("hex");
4603
+ if (actual !== entrySha256) {
4604
+ throw new Error(`cloud-managed policy failed integrity re-verification at load: expected ${entrySha256}, got ${actual}`);
4605
+ }
4606
+ code = buf.toString("utf-8");
4607
+ } else {
4608
+ code = await readFile2(filePath, "utf-8");
4609
+ }
3235
4610
  if (esmShimUrl) {
3236
4611
  code = code.replace(/from\s+(['"])(?:claudeye|failproofai)\1/g, `from '${esmShimUrl}'`);
3237
4612
  }
@@ -3253,7 +4628,7 @@ async function rewriteFileTree(entryPath, distUrl, distIndex) {
3253
4628
  if (!visited.has(resolved2) && !queue.includes(resolved2)) {
3254
4629
  queue.push(resolved2);
3255
4630
  }
3256
- let relPath = relative(dir, resolved2 + TMP_SUFFIX).split("\\").join("/");
4631
+ let relPath = relative(dir, resolved2 + tmpSuffix).split("\\").join("/");
3257
4632
  if (!relPath.startsWith("."))
3258
4633
  relPath = "./" + relPath;
3259
4634
  rewrites.set(specifier, relPath);
@@ -3266,7 +4641,7 @@ async function rewriteFileTree(entryPath, distUrl, distIndex) {
3266
4641
  code = code.replace(new RegExp(`'${escaped}'`, "g"), `'${replacement}'`);
3267
4642
  code = code.replace(new RegExp(`"${escaped}"`, "g"), `"${replacement}"`);
3268
4643
  }
3269
- const tmpPath = filePath + TMP_SUFFIX;
4644
+ const tmpPath = filePath + tmpSuffix;
3270
4645
  await writeFile2(tmpPath, code, "utf-8");
3271
4646
  tmpFiles.push(tmpPath);
3272
4647
  }
@@ -3279,36 +4654,61 @@ async function cleanupTmpFiles(tmpFiles) {
3279
4654
  } catch {}
3280
4655
  }
3281
4656
  }
3282
- var TMP_SUFFIX = ".__failproofai_tmp__.mjs", LOCAL_IMPORT_RE, LOCAL_REQUIRE_RE;
4657
+ var TMP_SUFFIX = ".__failproofai_tmp__.mjs", TMP_ARTIFACT_RE, TMP_SWEEP_MIN_AGE_MS = 60000, LOCAL_IMPORT_RE, LOCAL_REQUIRE_RE;
3283
4658
  var init_loader_utils = __esm(() => {
4659
+ init_fp_home();
4660
+ init_hook_logger();
4661
+ TMP_ARTIFACT_RE = /\.__failproofai_tmp__\./;
3284
4662
  LOCAL_IMPORT_RE = /(?:import\s+(?:[\s\S]*?\s+from\s+)?|export\s+(?:[\s\S]*?\s+from\s+))(['"])(\.\.?\/[^'"]+)\1/g;
3285
4663
  LOCAL_REQUIRE_RE = /require\s*\(\s*(['"])(\.\.?\/[^'"]+)\1\s*\)/g;
3286
4664
  });
3287
4665
 
3288
4666
  // src/hooks/custom-hooks-loader.ts
3289
- import { resolve as resolve4, isAbsolute, basename } from "node:path";
3290
- import { existsSync as existsSync3, readdirSync } from "node:fs";
4667
+ import { resolve as resolve5, isAbsolute, basename } from "node:path";
4668
+ import { randomUUID } from "crypto";
4669
+ import { existsSync as existsSync4, readdirSync } from "node:fs";
4670
+ import { readFile as readFile3 } from "node:fs/promises";
3291
4671
  import { pathToFileURL as pathToFileURL2 } from "node:url";
3292
- import { homedir as homedir4 } from "node:os";
4672
+ import { createHash as createHash2 } from "node:crypto";
3293
4673
  function discoverPolicyFiles(dir) {
3294
- if (!existsSync3(dir))
4674
+ if (!existsSync4(dir))
3295
4675
  return [];
3296
4676
  try {
3297
4677
  const entries = readdirSync(dir, { withFileTypes: true });
3298
- return entries.filter((e) => e.isFile() && CONVENTION_FILE_RE.test(e.name)).sort((a, b) => a.name.localeCompare(b.name)).map((e) => resolve4(dir, e.name));
4678
+ return entries.filter((e) => e.isFile() && CONVENTION_FILE_RE.test(e.name)).sort((a, b) => a.name.localeCompare(b.name)).map((e) => resolve5(dir, e.name));
3299
4679
  } catch {
3300
4680
  return [];
3301
4681
  }
3302
4682
  }
3303
4683
  function findSkippedPolicyFiles(dir) {
3304
- if (!existsSync3(dir))
4684
+ if (!existsSync4(dir))
3305
4685
  return [];
3306
4686
  try {
3307
- return readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && LOADABLE_EXT_RE.test(e.name) && !CONVENTION_FILE_RE.test(e.name) && !e.name.endsWith(".d.ts")).map((e) => e.name).sort((a, b) => a.localeCompare(b));
4687
+ return readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && LOADABLE_EXT_RE.test(e.name) && !CONVENTION_FILE_RE.test(e.name) && !e.name.endsWith(".d.ts") && !isTmpArtifact(e.name)).map((e) => e.name).sort((a, b) => a.localeCompare(b));
3308
4688
  } catch {
3309
4689
  return [];
3310
4690
  }
3311
4691
  }
4692
+ function moduleLoadTimeoutMs() {
4693
+ const override = Number(process.env.FAILPROOFAI_POLICY_LOAD_TIMEOUT_MS);
4694
+ return Number.isFinite(override) && override > 0 ? override : 1e4;
4695
+ }
4696
+ async function importWithDeadline(fileUrl) {
4697
+ const budget = moduleLoadTimeoutMs();
4698
+ let timer;
4699
+ try {
4700
+ await Promise.race([
4701
+ import(fileUrl),
4702
+ new Promise((_, reject) => {
4703
+ timer = setTimeout(() => reject(new Error(`timed out loading module after ${budget}ms`)), budget);
4704
+ timer.unref?.();
4705
+ })
4706
+ ]);
4707
+ } finally {
4708
+ if (timer)
4709
+ clearTimeout(timer);
4710
+ }
4711
+ }
3312
4712
  async function loadSingleFile(absPath, opts) {
3313
4713
  const g = globalThis;
3314
4714
  g[LOADING_KEY] = true;
@@ -3316,13 +4716,29 @@ async function loadSingleFile(absPath, opts) {
3316
4716
  try {
3317
4717
  const distIndex = await findDistIndex();
3318
4718
  const distUrl = distIndex ? pathToFileURL2(distIndex).href : null;
3319
- tmpFiles = await rewriteFileTree(absPath, distUrl, distIndex);
3320
- const entryTmp = absPath + TMP_SUFFIX;
3321
- const fileUrl = `${pathToFileURL2(entryTmp).href}?v=${++loadSequence}`;
3322
- await import(fileUrl);
4719
+ const sequence = ++loadSequence;
4720
+ const tmpSuffix = `${TMP_SUFFIX}.${process.pid}.${sequence}.${randomUUID()}.mjs`;
4721
+ tmpFiles = await rewriteFileTree(absPath, distUrl, distIndex, tmpSuffix, opts?.verifyEntrySha);
4722
+ const fingerprint = await fingerprintTemporaryTree(tmpFiles, tmpSuffix);
4723
+ const cached = policyModuleCache.get(absPath);
4724
+ if (cached?.fingerprint === fingerprint) {
4725
+ for (const hook of cached.hooks)
4726
+ customPolicies.add({ ...hook });
4727
+ return;
4728
+ }
4729
+ const entryTmp = absPath + tmpSuffix;
4730
+ const fileUrl = pathToFileURL2(entryTmp).href;
4731
+ const hooksBefore = getCustomHooks().length;
4732
+ await importWithDeadline(fileUrl);
4733
+ if (policyModuleCache.size >= POLICY_MODULE_CACHE_MAX_ENTRIES)
4734
+ policyModuleCache.clear();
4735
+ policyModuleCache.set(absPath, {
4736
+ fingerprint,
4737
+ hooks: getCustomHooks().slice(hooksBefore).map((hook) => ({ ...hook }))
4738
+ });
3323
4739
  } catch (err) {
3324
4740
  const msg = err instanceof Error ? err.message : String(err);
3325
- const errorType = /Cannot find module|MODULE_NOT_FOUND|ENOENT/i.test(msg) ? "module_not_found" : /SyntaxError|Unexpected token/i.test(msg) ? "syntax_error" : "runtime_error";
4741
+ const errorType = /Cannot find module|MODULE_NOT_FOUND|ENOENT/i.test(msg) ? "module_not_found" : /SyntaxError|Unexpected token/i.test(msg) ? "syntax_error" : /timed out loading module/i.test(msg) ? "load_timeout" : "runtime_error";
3326
4742
  trackHookEvent(getInstanceId(), "custom_hooks_load_error", {
3327
4743
  error_type: errorType,
3328
4744
  is_convention: !!opts?.conventionScope,
@@ -3337,6 +4753,15 @@ async function loadSingleFile(absPath, opts) {
3337
4753
  await cleanupTmpFiles(tmpFiles);
3338
4754
  }
3339
4755
  }
4756
+ async function fingerprintTemporaryTree(tmpFiles, tmpSuffix) {
4757
+ const hash = createHash2("sha256");
4758
+ for (const tmpFile of [...tmpFiles].sort()) {
4759
+ hash.update(tmpFile.replaceAll(tmpSuffix, TMP_SUFFIX));
4760
+ const contents = await readFile3(tmpFile, "utf8");
4761
+ hash.update(contents.replaceAll(tmpSuffix, TMP_SUFFIX));
4762
+ }
4763
+ return hash.digest("hex");
4764
+ }
3340
4765
  function customPolicyId(file, name) {
3341
4766
  return `custom:${file}:${name}`;
3342
4767
  }
@@ -3356,15 +4781,25 @@ async function loadAllCustomHooks(customPoliciesPaths, opts) {
3356
4781
  const projectRoot = findProjectConfigDir(opts?.sessionCwd ?? process.cwd());
3357
4782
  const conventionEnabled = opts?.customPoliciesEnabled !== false;
3358
4783
  const loadedPaths = new Set;
4784
+ const cloudManagedByPath = new Map((opts?.cloudManagedPolicies ?? []).map((policy) => [resolve5(policy.path), policy]));
3359
4785
  for (const customPoliciesPath of typeof customPoliciesPaths === "string" ? [customPoliciesPaths] : customPoliciesPaths ?? []) {
3360
- const absPath = resolve4(projectRoot, customPoliciesPath);
3361
- if (existsSync3(absPath)) {
4786
+ const absPath = resolve5(projectRoot, customPoliciesPath);
4787
+ if (existsSync4(absPath)) {
3362
4788
  if (!loadedPaths.has(absPath)) {
3363
4789
  loadedPaths.add(absPath);
3364
4790
  const hooksBefore = getCustomHooks().length;
3365
- await loadSingleFile(absPath);
4791
+ await loadSingleFile(absPath, {
4792
+ verifyEntrySha: cloudManagedByPath.get(absPath)?.sha256
4793
+ });
3366
4794
  for (const hook of getCustomHooks().slice(hooksBefore)) {
3367
- hook.__policyId = customPolicyId(absPath, hook.name);
4795
+ const cloudManaged = cloudManagedByPath.get(absPath);
4796
+ const tagged = hook;
4797
+ if (cloudManaged) {
4798
+ tagged.__cloudManaged = cloudManaged;
4799
+ tagged.__policyId = `cloud:${cloudManaged.id}@${cloudManaged.revision}:${hook.name}`;
4800
+ } else {
4801
+ tagged.__policyId = customPolicyId(absPath, hook.name);
4802
+ }
3368
4803
  }
3369
4804
  }
3370
4805
  } else {
@@ -3372,9 +4807,12 @@ async function loadAllCustomHooks(customPoliciesPaths, opts) {
3372
4807
  }
3373
4808
  }
3374
4809
  const hooksBeforeConvention = getCustomHooks().length;
3375
- const projectDir = resolve4(projectRoot, ".failproofai", "policies");
3376
- if (conventionEnabled)
4810
+ const projectDir = resolve5(projectRoot, ".failproofai", "policies");
4811
+ if (conventionEnabled) {
4812
+ sweepStaleTmpArtifacts(projectDir);
3377
4813
  warnSkippedPolicyFiles(projectDir, "project");
4814
+ }
4815
+ sweepStaleTmpArtifacts(shimsDir());
3378
4816
  const projectFiles = conventionEnabled ? discoverPolicyFiles(projectDir).filter((f) => !loadedPaths.has(f)) : [];
3379
4817
  for (const file of projectFiles) {
3380
4818
  loadedPaths.add(file);
@@ -3392,9 +4830,11 @@ async function loadAllCustomHooks(customPoliciesPaths, opts) {
3392
4830
  });
3393
4831
  }
3394
4832
  }
3395
- const userDir = resolve4(homedir4(), ".failproofai", "policies");
3396
- if (conventionEnabled && userDir !== projectDir)
4833
+ const userDir = customPoliciesDir();
4834
+ if (conventionEnabled && userDir !== projectDir) {
4835
+ sweepStaleTmpArtifacts(userDir);
3397
4836
  warnSkippedPolicyFiles(userDir, "user");
4837
+ }
3398
4838
  const userFiles = conventionEnabled && userDir !== projectDir ? discoverPolicyFiles(userDir).filter((f) => !loadedPaths.has(f)) : [];
3399
4839
  for (const file of userFiles) {
3400
4840
  loadedPaths.add(file);
@@ -3436,7 +4876,7 @@ async function loadAllCustomHooks(customPoliciesPaths, opts) {
3436
4876
  }
3437
4877
  return { hooks: allHooks, conventionSources };
3438
4878
  }
3439
- var LOADING_KEY = "__FAILPROOFAI_LOADING_HOOKS__", CONVENTION_FILE_RE, loadSequence = 0, LOADABLE_EXT_RE;
4879
+ var LOADING_KEY = "__FAILPROOFAI_LOADING_HOOKS__", CONVENTION_FILE_RE, loadSequence = 0, policyModuleCache, POLICY_MODULE_CACHE_MAX_ENTRIES = 500, LOADABLE_EXT_RE;
3440
4880
  var init_custom_hooks_loader = __esm(() => {
3441
4881
  init_hook_logger();
3442
4882
  init_custom_hooks_registry();
@@ -3444,44 +4884,45 @@ var init_custom_hooks_loader = __esm(() => {
3444
4884
  init_hooks_config();
3445
4885
  init_hook_telemetry();
3446
4886
  init_telemetry_id();
4887
+ init_fp_home();
3447
4888
  CONVENTION_FILE_RE = /policies\.(js|mjs|ts)$/;
4889
+ policyModuleCache = new Map;
3448
4890
  LOADABLE_EXT_RE = /\.(js|mjs|ts)$/;
3449
4891
  });
3450
4892
 
3451
4893
  // src/hooks/hook-activity-store.ts
3452
4894
  import {
3453
- readFileSync as readFileSync2,
3454
- writeFileSync as writeFileSync2,
4895
+ readFileSync as readFileSync3,
4896
+ writeFileSync as writeFileSync3,
3455
4897
  appendFileSync as appendFileSync2,
3456
4898
  renameSync as renameSync2,
3457
4899
  readdirSync as readdirSync2,
3458
- mkdirSync as mkdirSync3,
3459
- existsSync as existsSync4,
3460
- statSync as statSync4,
4900
+ mkdirSync as mkdirSync4,
4901
+ existsSync as existsSync5,
4902
+ statSync as statSync5,
3461
4903
  unlinkSync
3462
4904
  } from "node:fs";
3463
- import { join as join3 } from "node:path";
3464
- import { homedir as homedir5 } from "node:os";
4905
+ import { join as join4 } from "node:path";
3465
4906
  function ensureDir() {
3466
- if (!existsSync4(storeDir)) {
3467
- mkdirSync3(storeDir, { recursive: true });
4907
+ if (!existsSync5(storeDirValue())) {
4908
+ mkdirSync4(storeDirValue(), { recursive: true });
3468
4909
  }
3469
4910
  }
3470
4911
  function acquireLock() {
3471
4912
  ensureDir();
3472
- const lockPath = join3(storeDir, LOCK_FILE);
4913
+ const lockPath = join4(storeDirValue(), LOCK_FILE);
3473
4914
  const deadline = Date.now() + LOCK_STALE_MS;
3474
4915
  while (Date.now() < deadline) {
3475
4916
  try {
3476
- writeFileSync2(lockPath, String(process.pid), { flag: "wx" });
4917
+ writeFileSync3(lockPath, String(process.pid), { flag: "wx" });
3477
4918
  return;
3478
4919
  } catch (e) {
3479
4920
  if (e.code !== "EEXIST")
3480
4921
  return;
3481
4922
  try {
3482
- const s = statSync4(lockPath);
4923
+ const s = statSync5(lockPath);
3483
4924
  if (Date.now() - s.mtimeMs > LOCK_STALE_MS) {
3484
- writeFileSync2(lockPath, String(process.pid), "utf-8");
4925
+ writeFileSync3(lockPath, String(process.pid), "utf-8");
3485
4926
  return;
3486
4927
  }
3487
4928
  } catch {}
@@ -3490,15 +4931,15 @@ function acquireLock() {
3490
4931
  }
3491
4932
  function releaseLock() {
3492
4933
  try {
3493
- unlinkSync(join3(storeDir, LOCK_FILE));
4934
+ unlinkSync(join4(storeDirValue(), LOCK_FILE));
3494
4935
  } catch {}
3495
4936
  }
3496
4937
  function persistHookActivity(entry) {
3497
4938
  ensureDir();
3498
4939
  acquireLock();
3499
4940
  try {
3500
- const currentPath = join3(storeDir, CURRENT_FILE);
3501
- const countPath = join3(storeDir, COUNT_FILE);
4941
+ const currentPath = join4(storeDirValue(), CURRENT_FILE);
4942
+ const countPath = join4(storeDirValue(), COUNT_FILE);
3502
4943
  const lineCount = readCount(countPath);
3503
4944
  if (lineCount >= PAGE_SIZE) {
3504
4945
  try {
@@ -3518,13 +4959,13 @@ function persistHookActivity(entry) {
3518
4959
  }
3519
4960
  function rotate(currentPath, countPath) {
3520
4961
  const archiveName = `page-${Date.now()}-${rotateSeq++}.jsonl`;
3521
- const archivePath = join3(storeDir, archiveName);
4962
+ const archivePath = join4(storeDirValue(), archiveName);
3522
4963
  renameSync2(currentPath, archivePath);
3523
4964
  writeCount(countPath, 0);
3524
4965
  }
3525
4966
  function readCount(countPath) {
3526
4967
  try {
3527
- const n = parseInt(readFileSync2(countPath, "utf-8"), 10);
4968
+ const n = parseInt(readFileSync3(countPath, "utf-8"), 10);
3528
4969
  return isNaN(n) ? 0 : n;
3529
4970
  } catch {
3530
4971
  return 0;
@@ -3532,12 +4973,12 @@ function readCount(countPath) {
3532
4973
  }
3533
4974
  function writeCount(countPath, n) {
3534
4975
  try {
3535
- writeFileSync2(countPath, String(n), "utf-8");
4976
+ writeFileSync3(countPath, String(n), "utf-8");
3536
4977
  } catch {}
3537
4978
  }
3538
4979
  function readStoredStats() {
3539
4980
  try {
3540
- return JSON.parse(readFileSync2(join3(storeDir, STATS_FILE), "utf-8"));
4981
+ return JSON.parse(readFileSync3(join4(storeDirValue(), STATS_FILE), "utf-8"));
3541
4982
  } catch {
3542
4983
  return { totalEvents: 0, denyCount: 0, policyMap: {} };
3543
4984
  }
@@ -3554,20 +4995,19 @@ function updateStats(entry) {
3554
4995
  } else if (entry.policyName) {
3555
4996
  s.policyMap[entry.policyName] = (s.policyMap[entry.policyName] ?? 0) + 1;
3556
4997
  }
3557
- const tmpPath = join3(storeDir, `stats.json.${process.pid}.tmp`);
4998
+ const tmpPath = join4(storeDirValue(), `stats.json.${process.pid}.tmp`);
3558
4999
  try {
3559
- writeFileSync2(tmpPath, JSON.stringify(s), "utf-8");
3560
- renameSync2(tmpPath, join3(storeDir, STATS_FILE));
5000
+ writeFileSync3(tmpPath, JSON.stringify(s), "utf-8");
5001
+ renameSync2(tmpPath, join4(storeDirValue(), STATS_FILE));
3561
5002
  } catch {
3562
5003
  try {
3563
5004
  unlinkSync(tmpPath);
3564
5005
  } catch {}
3565
5006
  }
3566
5007
  }
3567
- var PAGE_SIZE = 25, DEFAULT_STORE_DIR, CURRENT_FILE = "current.jsonl", COUNT_FILE = "current.count", STATS_FILE = "stats.json", LOCK_FILE = "current.lock", LOCK_STALE_MS = 2000, storeDir, rotateSeq = 0;
5008
+ var PAGE_SIZE = 25, defaultStoreDir = () => hookActivityDir(), CURRENT_FILE = "current.jsonl", COUNT_FILE = "current.count", STATS_FILE = "stats.json", LOCK_FILE = "current.lock", LOCK_STALE_MS = 2000, storeDirOverride = null, storeDirValue = () => storeDirOverride ?? defaultStoreDir(), rotateSeq = 0;
3568
5009
  var init_hook_activity_store = __esm(() => {
3569
- DEFAULT_STORE_DIR = join3(homedir5(), ".failproofai", "cache", "hook-activity");
3570
- storeDir = DEFAULT_STORE_DIR;
5010
+ init_fp_home();
3571
5011
  });
3572
5012
 
3573
5013
  // src/hooks/resolve-cwd.ts
@@ -3616,10 +5056,10 @@ function runtimeCache(fn, revalidateSeconds, options) {
3616
5056
  }
3617
5057
 
3618
5058
  // lib/paths.ts
3619
- import { homedir as homedir6 } from "os";
3620
- import { join as join4 } from "path";
5059
+ import { homedir as homedir4 } from "os";
5060
+ import { join as join5 } from "path";
3621
5061
  function getDefaultClaudeProjectsPath() {
3622
- return join4(homedir6(), ".claude", "projects");
5062
+ return join5(homedir4(), ".claude", "projects");
3623
5063
  }
3624
5064
  function decodeFolderName(name) {
3625
5065
  if (/^[A-Za-z]--/.test(name)) {
@@ -3713,8 +5153,8 @@ __export(exports_codex_projects, {
3713
5153
  getCachedCodexProjects: () => getCachedCodexProjects
3714
5154
  });
3715
5155
  import { open as open2, readdir } from "node:fs/promises";
3716
- import { homedir as homedir7 } from "node:os";
3717
- import { join as join5 } from "node:path";
5156
+ import { homedir as homedir5 } from "node:os";
5157
+ import { join as join6 } from "node:path";
3718
5158
  async function safeReaddir(dir) {
3719
5159
  try {
3720
5160
  return await readdir(dir, { withFileTypes: true });
@@ -3762,7 +5202,7 @@ async function listJsonlFiles(dir) {
3762
5202
  const entries = await safeReaddir(dir);
3763
5203
  if (!entries)
3764
5204
  return [];
3765
- return entries.filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => join5(dir, e.name));
5205
+ return entries.filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => join6(dir, e.name));
3766
5206
  }
3767
5207
  async function scanCodexSessions() {
3768
5208
  const yearDirs = await safeReaddir(CODEX_SESSIONS_ROOT);
@@ -3772,19 +5212,19 @@ async function scanCodexSessions() {
3772
5212
  for (const y of yearDirs) {
3773
5213
  if (!y.isDirectory())
3774
5214
  continue;
3775
- const monthDirs = await safeReaddir(join5(CODEX_SESSIONS_ROOT, y.name));
5215
+ const monthDirs = await safeReaddir(join6(CODEX_SESSIONS_ROOT, y.name));
3776
5216
  if (!monthDirs)
3777
5217
  continue;
3778
5218
  for (const m of monthDirs) {
3779
5219
  if (!m.isDirectory())
3780
5220
  continue;
3781
- const dayDirs = await safeReaddir(join5(CODEX_SESSIONS_ROOT, y.name, m.name));
5221
+ const dayDirs = await safeReaddir(join6(CODEX_SESSIONS_ROOT, y.name, m.name));
3782
5222
  if (!dayDirs)
3783
5223
  continue;
3784
5224
  for (const d of dayDirs) {
3785
5225
  if (!d.isDirectory())
3786
5226
  continue;
3787
- const dayPath = join5(CODEX_SESSIONS_ROOT, y.name, m.name, d.name);
5227
+ const dayPath = join6(CODEX_SESSIONS_ROOT, y.name, m.name, d.name);
3788
5228
  filePaths.push(...await listJsonlFiles(dayPath));
3789
5229
  }
3790
5230
  }
@@ -3892,7 +5332,7 @@ var CODEX_SESSIONS_ROOT, SESSION_ID_RE, FIRST_LINE_CHUNK_BYTES, cachedScan, getC
3892
5332
  var init_codex_projects = __esm(() => {
3893
5333
  init_paths();
3894
5334
  init_logger();
3895
- CODEX_SESSIONS_ROOT = join5(homedir7(), ".codex", "sessions");
5335
+ CODEX_SESSIONS_ROOT = join6(homedir5(), ".codex", "sessions");
3896
5336
  SESSION_ID_RE = /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/i;
3897
5337
  FIRST_LINE_CHUNK_BYTES = 256 * 1024;
3898
5338
  cachedScan = runtimeCache(scanCodexSessions, 30);
@@ -3911,11 +5351,11 @@ __export(exports_copilot_projects, {
3911
5351
  getCachedCopilotSessionsByEncodedName: () => getCachedCopilotSessionsByEncodedName,
3912
5352
  getCachedCopilotProjects: () => getCachedCopilotProjects
3913
5353
  });
3914
- import { readdir as readdir2, readFile as readFile3, stat as stat2 } from "node:fs/promises";
3915
- import { homedir as homedir8 } from "node:os";
3916
- import { join as join6 } from "node:path";
5354
+ import { readdir as readdir2, readFile as readFile4, stat as stat2 } from "node:fs/promises";
5355
+ import { homedir as homedir6 } from "node:os";
5356
+ import { join as join7 } from "node:path";
3917
5357
  function getCopilotSessionStateRoot() {
3918
- return join6(process.env.COPILOT_HOME || join6(homedir8(), ".copilot"), "session-state");
5358
+ return join7(process.env.COPILOT_HOME || join7(homedir6(), ".copilot"), "session-state");
3919
5359
  }
3920
5360
  async function safeReaddir2(dir) {
3921
5361
  try {
@@ -3944,13 +5384,13 @@ async function scanCopilotSessions() {
3944
5384
  return [];
3945
5385
  const candidates = entries.filter((e) => e.isDirectory()).map((e) => ({
3946
5386
  sessionId: e.name,
3947
- workspacePath: join6(root, e.name, "workspace.yaml"),
3948
- eventsPath: join6(root, e.name, "events.jsonl")
5387
+ workspacePath: join7(root, e.name, "workspace.yaml"),
5388
+ eventsPath: join7(root, e.name, "events.jsonl")
3949
5389
  }));
3950
5390
  const settled = await batchAll(candidates.map((c) => async () => {
3951
5391
  let workspaceText;
3952
5392
  try {
3953
- workspaceText = await readFile3(c.workspacePath, "utf-8");
5393
+ workspaceText = await readFile4(c.workspacePath, "utf-8");
3954
5394
  } catch {
3955
5395
  return null;
3956
5396
  }
@@ -4059,11 +5499,11 @@ __export(exports_cursor_projects, {
4059
5499
  getCachedCursorSessionsByEncodedName: () => getCachedCursorSessionsByEncodedName,
4060
5500
  getCachedCursorProjects: () => getCachedCursorProjects
4061
5501
  });
4062
- import { readdir as readdir3, readFile as readFile4, stat as stat3 } from "node:fs/promises";
4063
- import { homedir as homedir9 } from "node:os";
4064
- import { join as join7 } from "node:path";
5502
+ import { readdir as readdir3, readFile as readFile5, stat as stat3 } from "node:fs/promises";
5503
+ import { homedir as homedir7 } from "node:os";
5504
+ import { join as join8 } from "node:path";
4065
5505
  function getCursorHome() {
4066
- return process.env.CURSOR_HOME || join7(homedir9(), ".cursor");
5506
+ return process.env.CURSOR_HOME || join8(homedir7(), ".cursor");
4067
5507
  }
4068
5508
  async function safeReaddir3(dir) {
4069
5509
  try {
@@ -4095,12 +5535,12 @@ function parseCwdFromMetaText(text) {
4095
5535
  }
4096
5536
  async function findFirstUsableMeta(dir, candidates) {
4097
5537
  for (const name of candidates) {
4098
- const path2 = join7(dir, name);
5538
+ const path2 = join8(dir, name);
4099
5539
  if (await statMtime2(path2) === null)
4100
5540
  continue;
4101
5541
  let text;
4102
5542
  try {
4103
- text = await readFile4(path2, "utf-8");
5543
+ text = await readFile5(path2, "utf-8");
4104
5544
  } catch {
4105
5545
  continue;
4106
5546
  }
@@ -4112,7 +5552,7 @@ async function findFirstUsableMeta(dir, candidates) {
4112
5552
  }
4113
5553
  async function findFirstExistingPath(dir, candidates) {
4114
5554
  for (const name of candidates) {
4115
- const path2 = join7(dir, name);
5555
+ const path2 = join8(dir, name);
4116
5556
  if (await statMtime2(path2) !== null)
4117
5557
  return path2;
4118
5558
  }
@@ -4122,7 +5562,7 @@ async function scanCursorSessions() {
4122
5562
  const home = getCursorHome();
4123
5563
  const newCandidates = [];
4124
5564
  const legacyCandidates = [];
4125
- const projectsRoot = join7(home, NEW_PROJECTS_DIR);
5565
+ const projectsRoot = join8(home, NEW_PROJECTS_DIR);
4126
5566
  const projectEntries = await safeReaddir3(projectsRoot);
4127
5567
  if (projectEntries) {
4128
5568
  for (const proj of projectEntries) {
@@ -4130,7 +5570,7 @@ async function scanCursorSessions() {
4130
5570
  continue;
4131
5571
  const decoded = decodeFolderName(proj.name);
4132
5572
  const cwd = decoded.startsWith("/") || /^[A-Za-z]:\//.test(decoded) ? decoded : `/${decoded}`;
4133
- const transcriptsRoot = join7(projectsRoot, proj.name, NEW_AGENT_TRANSCRIPTS_DIR);
5573
+ const transcriptsRoot = join8(projectsRoot, proj.name, NEW_AGENT_TRANSCRIPTS_DIR);
4134
5574
  const sessionDirs = await safeReaddir3(transcriptsRoot);
4135
5575
  if (!sessionDirs)
4136
5576
  continue;
@@ -4139,28 +5579,28 @@ async function scanCursorSessions() {
4139
5579
  continue;
4140
5580
  newCandidates.push({
4141
5581
  sessionId: sd.name,
4142
- dir: join7(transcriptsRoot, sd.name),
5582
+ dir: join8(transcriptsRoot, sd.name),
4143
5583
  cwd
4144
5584
  });
4145
5585
  }
4146
5586
  }
4147
5587
  }
4148
5588
  for (const sub of LEGACY_SESSION_ROOT_CANDIDATES) {
4149
- const root = join7(home, sub);
5589
+ const root = join8(home, sub);
4150
5590
  const entries = await safeReaddir3(root);
4151
5591
  if (!entries)
4152
5592
  continue;
4153
5593
  for (const e of entries) {
4154
5594
  if (!e.isDirectory())
4155
5595
  continue;
4156
- legacyCandidates.push({ sessionId: e.name, dir: join7(root, e.name) });
5596
+ legacyCandidates.push({ sessionId: e.name, dir: join8(root, e.name) });
4157
5597
  }
4158
5598
  }
4159
5599
  if (newCandidates.length === 0 && legacyCandidates.length === 0)
4160
5600
  return [];
4161
5601
  const settled = await batchAll([
4162
5602
  ...newCandidates.map((c) => async () => {
4163
- const transcriptPath = join7(c.dir, `${c.sessionId}.jsonl`);
5603
+ const transcriptPath = join8(c.dir, `${c.sessionId}.jsonl`);
4164
5604
  const transcriptMtime = await statMtime2(transcriptPath);
4165
5605
  if (!transcriptMtime)
4166
5606
  return null;
@@ -4432,11 +5872,11 @@ __export(exports_pi_projects, {
4432
5872
  getCachedPiSessionsByEncodedName: () => getCachedPiSessionsByEncodedName,
4433
5873
  getCachedPiProjects: () => getCachedPiProjects
4434
5874
  });
4435
- import { readdir as readdir4, readFile as readFile5, stat as stat4 } from "node:fs/promises";
4436
- import { homedir as homedir10 } from "node:os";
4437
- import { join as join8 } from "node:path";
5875
+ import { readdir as readdir4, readFile as readFile6, stat as stat4 } from "node:fs/promises";
5876
+ import { homedir as homedir8 } from "node:os";
5877
+ import { join as join9 } from "node:path";
4438
5878
  function getPiSessionsRoot() {
4439
- return process.env.PI_SESSIONS_DIR || join8(homedir10(), ".pi", "agent", "sessions");
5879
+ return process.env.PI_SESSIONS_DIR || join9(homedir8(), ".pi", "agent", "sessions");
4440
5880
  }
4441
5881
  async function safeReaddir4(dir) {
4442
5882
  try {
@@ -4455,7 +5895,7 @@ async function statMtime3(path2) {
4455
5895
  async function readSessionCwd(filePath) {
4456
5896
  let text;
4457
5897
  try {
4458
- text = await readFile5(filePath, "utf-8");
5898
+ text = await readFile6(filePath, "utf-8");
4459
5899
  } catch {
4460
5900
  return null;
4461
5901
  }
@@ -4484,7 +5924,7 @@ async function scanPiSessions() {
4484
5924
  for (const cwdDir of cwdDirs) {
4485
5925
  if (!cwdDir.isDirectory())
4486
5926
  continue;
4487
- const cwdPath = join8(root, cwdDir.name);
5927
+ const cwdPath = join9(root, cwdDir.name);
4488
5928
  const sessionFiles = await safeReaddir4(cwdPath);
4489
5929
  if (!sessionFiles)
4490
5930
  continue;
@@ -4494,7 +5934,7 @@ async function scanPiSessions() {
4494
5934
  const m = SESSION_FILE_RE.exec(f.name);
4495
5935
  if (!m)
4496
5936
  continue;
4497
- candidates.push({ sessionId: m[1], filePath: join8(cwdPath, f.name) });
5937
+ candidates.push({ sessionId: m[1], filePath: join9(cwdPath, f.name) });
4498
5938
  }
4499
5939
  }
4500
5940
  if (candidates.length === 0)
@@ -4596,7 +6036,7 @@ var init_pi_projects = __esm(() => {
4596
6036
  });
4597
6037
 
4598
6038
  // lib/sqlite-reader.ts
4599
- import { existsSync as existsSync5, readFileSync as readFileSync3 } from "node:fs";
6039
+ import { existsSync as existsSync6, readFileSync as readFileSync4 } from "node:fs";
4600
6040
  import initSqlJs from "sql.js/dist/sql-asm.js";
4601
6041
  async function tryNodeSqlite(dbPath) {
4602
6042
  try {
@@ -4623,7 +6063,7 @@ function loadSqlJs() {
4623
6063
  async function trySqlJs(dbPath) {
4624
6064
  try {
4625
6065
  const SQL = await loadSqlJs();
4626
- const db = new SQL.Database(readFileSync3(dbPath));
6066
+ const db = new SQL.Database(readFileSync4(dbPath));
4627
6067
  return {
4628
6068
  query(sql, params) {
4629
6069
  const stmt = db.prepare(sql);
@@ -4647,7 +6087,7 @@ async function trySqlJs(dbPath) {
4647
6087
  }
4648
6088
  }
4649
6089
  async function openSqliteReadonly(dbPath) {
4650
- if (!existsSync5(dbPath))
6090
+ if (!existsSync6(dbPath))
4651
6091
  return null;
4652
6092
  return await tryNodeSqlite(dbPath) ?? await trySqlJs(dbPath);
4653
6093
  }
@@ -4656,18 +6096,18 @@ var init_sqlite_reader = () => {};
4656
6096
 
4657
6097
  // lib/hermes-profiles.ts
4658
6098
  import { readdirSync as readdirSync3 } from "node:fs";
4659
- import { homedir as homedir11 } from "node:os";
4660
- import { basename as basename2, dirname as dirname3, join as join9, resolve as resolve5 } from "node:path";
6099
+ import { homedir as homedir9 } from "node:os";
6100
+ import { basename as basename2, dirname as dirname3, join as join10, resolve as resolve6 } from "node:path";
4661
6101
  function hermesRoot() {
4662
6102
  const env = (process.env.HERMES_HOME || "").trim();
4663
6103
  if (env) {
4664
- const home = resolve5(env);
6104
+ const home = resolve6(env);
4665
6105
  const parent = dirname3(home);
4666
6106
  if (basename2(parent) === PROFILES_DIR)
4667
6107
  return dirname3(parent);
4668
6108
  return home;
4669
6109
  }
4670
- return join9(homedir11(), ".hermes");
6110
+ return join10(homedir9(), ".hermes");
4671
6111
  }
4672
6112
  function listHermesProfiles() {
4673
6113
  const root = hermesRoot();
@@ -4675,7 +6115,7 @@ function listHermesProfiles() {
4675
6115
  const seen = new Set([HERMES_DEFAULT_PROFILE]);
4676
6116
  let names;
4677
6117
  try {
4678
- names = readdirSync3(join9(root, PROFILES_DIR), { withFileTypes: true }).filter((e) => (e.isDirectory() || e.isSymbolicLink()) && !e.name.startsWith(".")).map((e) => e.name).sort();
6118
+ names = readdirSync3(join10(root, PROFILES_DIR), { withFileTypes: true }).filter((e) => (e.isDirectory() || e.isSymbolicLink()) && !e.name.startsWith(".")).map((e) => e.name).sort();
4679
6119
  } catch {
4680
6120
  return out;
4681
6121
  }
@@ -4683,7 +6123,7 @@ function listHermesProfiles() {
4683
6123
  if (seen.has(name))
4684
6124
  continue;
4685
6125
  seen.add(name);
4686
- out.push({ name, home: join9(root, PROFILES_DIR, name) });
6126
+ out.push({ name, home: join10(root, PROFILES_DIR, name) });
4687
6127
  }
4688
6128
  return out;
4689
6129
  }
@@ -4734,14 +6174,14 @@ function formatDuration(ms) {
4734
6174
  }
4735
6175
 
4736
6176
  // lib/hermes-sessions.ts
4737
- import { join as join10 } from "node:path";
6177
+ import { join as join11 } from "node:path";
4738
6178
  function hermesDbPaths() {
4739
6179
  const override = process.env.HERMES_DB_PATH;
4740
6180
  if (override)
4741
6181
  return [{ profile: HERMES_DEFAULT_PROFILE, dbPath: override }];
4742
6182
  return listHermesProfiles().map((p) => ({
4743
6183
  profile: p.name,
4744
- dbPath: join10(p.home, "state.db")
6184
+ dbPath: join11(p.home, "state.db")
4745
6185
  }));
4746
6186
  }
4747
6187
  function epochToMs(value) {
@@ -5037,12 +6477,12 @@ var init_hermes_projects = __esm(() => {
5037
6477
  });
5038
6478
 
5039
6479
  // lib/openclaw-sessions.ts
5040
- import { readFile as readFile6 } from "node:fs/promises";
5041
- import { readdirSync as readdirSync4, statSync as statSync5 } from "node:fs";
5042
- import { homedir as homedir12 } from "node:os";
5043
- import { join as join11 } from "node:path";
6480
+ import { readFile as readFile7 } from "node:fs/promises";
6481
+ import { readdirSync as readdirSync4, statSync as statSync6 } from "node:fs";
6482
+ import { homedir as homedir10 } from "node:os";
6483
+ import { join as join12 } from "node:path";
5044
6484
  function openclawHome() {
5045
- return process.env.OPENCLAW_HOME || join11(homedir12(), ".openclaw");
6485
+ return process.env.OPENCLAW_HOME || join12(homedir10(), ".openclaw");
5046
6486
  }
5047
6487
  function isPlainObject2(v) {
5048
6488
  return !!v && typeof v === "object" && !Array.isArray(v);
@@ -5157,13 +6597,13 @@ function openclawLinesToLogEntries(lines, source = "session") {
5157
6597
  }
5158
6598
  function listOpenClawAgents() {
5159
6599
  try {
5160
- return readdirSync4(join11(openclawHome(), "agents"), { withFileTypes: true }).filter((d) => d.isDirectory() && !d.name.startsWith(".")).map((d) => d.name).sort();
6600
+ return readdirSync4(join12(openclawHome(), "agents"), { withFileTypes: true }).filter((d) => d.isDirectory() && !d.name.startsWith(".")).map((d) => d.name).sort();
5161
6601
  } catch {
5162
6602
  return [];
5163
6603
  }
5164
6604
  }
5165
6605
  function listOpenClawTranscripts() {
5166
- const agentsDir = join11(openclawHome(), "agents");
6606
+ const agentsDir = join12(openclawHome(), "agents");
5167
6607
  const out = [];
5168
6608
  let agentIds;
5169
6609
  try {
@@ -5172,7 +6612,7 @@ function listOpenClawTranscripts() {
5172
6612
  return out;
5173
6613
  }
5174
6614
  for (const agentId of agentIds) {
5175
- const sessionsDir = join11(agentsDir, agentId, "sessions");
6615
+ const sessionsDir = join12(agentsDir, agentId, "sessions");
5176
6616
  let files;
5177
6617
  try {
5178
6618
  files = readdirSync4(sessionsDir);
@@ -5185,9 +6625,9 @@ function listOpenClawTranscripts() {
5185
6625
  const sessionId = file.slice(0, -".jsonl".length);
5186
6626
  if (!OPENCLAW_SESSION_ID_RE.test(sessionId))
5187
6627
  continue;
5188
- const transcriptPath = join11(sessionsDir, file);
6628
+ const transcriptPath = join12(sessionsDir, file);
5189
6629
  try {
5190
- const st = statSync5(transcriptPath);
6630
+ const st = statSync6(transcriptPath);
5191
6631
  out.push({ agentId, sessionId, transcriptPath, mtimeMs: st.mtimeMs, sizeBytes: st.size });
5192
6632
  } catch {}
5193
6633
  }
@@ -5209,7 +6649,7 @@ async function getOpenClawSessionLog(sessionId) {
5209
6649
  return null;
5210
6650
  let content;
5211
6651
  try {
5212
- content = await readFile6(filePath, "utf-8");
6652
+ content = await readFile7(filePath, "utf-8");
5213
6653
  } catch {
5214
6654
  return null;
5215
6655
  }
@@ -5245,17 +6685,17 @@ __export(exports_openclaw_projects, {
5245
6685
  getCachedOpenClawSessions: () => getCachedOpenClawSessions,
5246
6686
  getCachedOpenClawProjects: () => getCachedOpenClawProjects
5247
6687
  });
5248
- import { readFileSync as readFileSync4 } from "node:fs";
5249
- import { join as join12 } from "node:path";
6688
+ import { readFileSync as readFileSync5 } from "node:fs";
6689
+ import { join as join13 } from "node:path";
5250
6690
  function str(v) {
5251
6691
  return typeof v === "string" && v.length > 0 ? v : undefined;
5252
6692
  }
5253
6693
  function readSessionsIndex(agentId) {
5254
6694
  const out = new Map;
5255
- const indexPath = join12(openclawHome(), "agents", agentId, "sessions", "sessions.json");
6695
+ const indexPath = join13(openclawHome(), "agents", agentId, "sessions", "sessions.json");
5256
6696
  let raw;
5257
6697
  try {
5258
- raw = JSON.parse(readFileSync4(indexPath, "utf-8"));
6698
+ raw = JSON.parse(readFileSync5(indexPath, "utf-8"));
5259
6699
  } catch {
5260
6700
  return out;
5261
6701
  }
@@ -5406,15 +6846,15 @@ var init_openclaw_projects = __esm(() => {
5406
6846
  });
5407
6847
 
5408
6848
  // lib/factory-sessions.ts
5409
- import { readFile as readFile7 } from "node:fs/promises";
5410
- import { readdirSync as readdirSync5, statSync as statSync6 } from "node:fs";
5411
- import { homedir as homedir13 } from "node:os";
5412
- import { join as join13 } from "node:path";
6849
+ import { readFile as readFile8 } from "node:fs/promises";
6850
+ import { readdirSync as readdirSync5, statSync as statSync7 } from "node:fs";
6851
+ import { homedir as homedir11 } from "node:os";
6852
+ import { join as join14 } from "node:path";
5413
6853
  function factoryHome() {
5414
- return process.env.FACTORY_HOME || join13(homedir13(), ".factory");
6854
+ return process.env.FACTORY_HOME || join14(homedir11(), ".factory");
5415
6855
  }
5416
6856
  function factorySessionsRoot() {
5417
- return join13(factoryHome(), "sessions");
6857
+ return join14(factoryHome(), "sessions");
5418
6858
  }
5419
6859
  function isPlainObject3(v) {
5420
6860
  return !!v && typeof v === "object" && !Array.isArray(v);
@@ -5560,7 +7000,7 @@ function listFactoryTranscripts() {
5560
7000
  for (const dir of projectDirs) {
5561
7001
  const projectName = dir.name;
5562
7002
  const cwd = decodeFolderName(projectName);
5563
- const projectPath = join13(root, projectName);
7003
+ const projectPath = join14(root, projectName);
5564
7004
  let files;
5565
7005
  try {
5566
7006
  files = readdirSync5(projectPath);
@@ -5573,9 +7013,9 @@ function listFactoryTranscripts() {
5573
7013
  const sessionId = file.slice(0, -".jsonl".length);
5574
7014
  if (!FACTORY_SESSION_ID_RE.test(sessionId))
5575
7015
  continue;
5576
- const transcriptPath = join13(projectPath, file);
7016
+ const transcriptPath = join14(projectPath, file);
5577
7017
  try {
5578
- const st = statSync6(transcriptPath);
7018
+ const st = statSync7(transcriptPath);
5579
7019
  out.push({ projectName, cwd, sessionId, transcriptPath, mtimeMs: st.mtimeMs, sizeBytes: st.size });
5580
7020
  } catch {}
5581
7021
  }
@@ -5597,7 +7037,7 @@ async function getFactorySessionLog(sessionId) {
5597
7037
  return null;
5598
7038
  let content;
5599
7039
  try {
5600
- content = await readFile7(filePath, "utf-8");
7040
+ content = await readFile8(filePath, "utf-8");
5601
7041
  } catch {
5602
7042
  return null;
5603
7043
  }
@@ -5699,13 +7139,13 @@ var init_factory_projects = __esm(() => {
5699
7139
  });
5700
7140
 
5701
7141
  // lib/devin-sessions.ts
5702
- import { homedir as homedir14 } from "node:os";
5703
- import { join as join14 } from "node:path";
7142
+ import { homedir as homedir12 } from "node:os";
7143
+ import { join as join15 } from "node:path";
5704
7144
  function devinHome() {
5705
- return process.env.DEVIN_HOME || join14(homedir14(), ".local", "share", "devin");
7145
+ return process.env.DEVIN_HOME || join15(homedir12(), ".local", "share", "devin");
5706
7146
  }
5707
7147
  function devinDbPath() {
5708
- return process.env.DEVIN_DB_PATH || join14(devinHome(), "cli", "sessions.db");
7148
+ return process.env.DEVIN_DB_PATH || join15(devinHome(), "cli", "sessions.db");
5709
7149
  }
5710
7150
  function devinEpochToMs(value) {
5711
7151
  if (typeof value === "number" && Number.isFinite(value)) {
@@ -6001,18 +7441,18 @@ var init_devin_projects = __esm(() => {
6001
7441
  });
6002
7442
 
6003
7443
  // lib/antigravity-sessions.ts
6004
- import { readFile as readFile8 } from "node:fs/promises";
6005
- import { readdirSync as readdirSync6, statSync as statSync7 } from "node:fs";
6006
- import { homedir as homedir15 } from "node:os";
6007
- import { join as join15 } from "node:path";
7444
+ import { readFile as readFile9 } from "node:fs/promises";
7445
+ import { readdirSync as readdirSync6, statSync as statSync8 } from "node:fs";
7446
+ import { homedir as homedir13 } from "node:os";
7447
+ import { join as join16 } from "node:path";
6008
7448
  function antigravityHome() {
6009
- return process.env.ANTIGRAVITY_HOME || join15(homedir15(), ".gemini", "antigravity-cli");
7449
+ return process.env.ANTIGRAVITY_HOME || join16(homedir13(), ".gemini", "antigravity-cli");
6010
7450
  }
6011
7451
  function antigravityBrainRoot() {
6012
- return join15(antigravityHome(), "brain");
7452
+ return join16(antigravityHome(), "brain");
6013
7453
  }
6014
7454
  function antigravityTranscriptRelPath() {
6015
- return join15(".system_generated", "logs", "transcript_full.jsonl");
7455
+ return join16(".system_generated", "logs", "transcript_full.jsonl");
6016
7456
  }
6017
7457
  function isPlainObject5(v) {
6018
7458
  return !!v && typeof v === "object" && !Array.isArray(v);
@@ -6135,9 +7575,9 @@ function listAntigravityTranscripts() {
6135
7575
  const conversationId = dir.name;
6136
7576
  if (!ANTIGRAVITY_CONVERSATION_ID_RE.test(conversationId))
6137
7577
  continue;
6138
- const transcriptPath = join15(root, conversationId, rel);
7578
+ const transcriptPath = join16(root, conversationId, rel);
6139
7579
  try {
6140
- const st = statSync7(transcriptPath);
7580
+ const st = statSync8(transcriptPath);
6141
7581
  if (!st.isFile())
6142
7582
  continue;
6143
7583
  out.push({ conversationId, transcriptPath, mtimeMs: st.mtimeMs, sizeBytes: st.size });
@@ -6148,9 +7588,9 @@ function listAntigravityTranscripts() {
6148
7588
  function findAntigravityTranscript(conversationId) {
6149
7589
  if (!ANTIGRAVITY_CONVERSATION_ID_RE.test(conversationId))
6150
7590
  return null;
6151
- const transcriptPath = join15(antigravityBrainRoot(), conversationId, antigravityTranscriptRelPath());
7591
+ const transcriptPath = join16(antigravityBrainRoot(), conversationId, antigravityTranscriptRelPath());
6152
7592
  try {
6153
- if (statSync7(transcriptPath).isFile())
7593
+ if (statSync8(transcriptPath).isFile())
6154
7594
  return transcriptPath;
6155
7595
  } catch {}
6156
7596
  return null;
@@ -6161,7 +7601,7 @@ async function getAntigravitySessionLog(conversationId) {
6161
7601
  return null;
6162
7602
  let content;
6163
7603
  try {
6164
- content = await readFile8(filePath, "utf-8");
7604
+ content = await readFile9(filePath, "utf-8");
6165
7605
  } catch {
6166
7606
  return null;
6167
7607
  }
@@ -6188,9 +7628,9 @@ __export(exports_antigravity_projects, {
6188
7628
  getAntigravityIndex: () => getAntigravityIndex,
6189
7629
  antigravitySummariesDbPath: () => antigravitySummariesDbPath
6190
7630
  });
6191
- import { join as join16 } from "node:path";
7631
+ import { join as join17 } from "node:path";
6192
7632
  function antigravitySummariesDbPath() {
6193
- return join16(antigravityHome(), "conversation_summaries.db");
7633
+ return join17(antigravityHome(), "conversation_summaries.db");
6194
7634
  }
6195
7635
  function parseWorkspaceCwd(raw) {
6196
7636
  if (!raw)
@@ -6333,16 +7773,16 @@ var init_antigravity_projects = __esm(() => {
6333
7773
  });
6334
7774
 
6335
7775
  // lib/goose-sessions.ts
6336
- import { homedir as homedir16 } from "node:os";
6337
- import { join as join17 } from "node:path";
7776
+ import { homedir as homedir14 } from "node:os";
7777
+ import { join as join18 } from "node:path";
6338
7778
  function gooseHome() {
6339
7779
  if (process.env.GOOSE_HOME)
6340
7780
  return process.env.GOOSE_HOME;
6341
7781
  const xdg = process.env.XDG_DATA_HOME;
6342
- return join17(xdg && xdg.length > 0 ? xdg : join17(homedir16(), ".local", "share"), "goose");
7782
+ return join18(xdg && xdg.length > 0 ? xdg : join18(homedir14(), ".local", "share"), "goose");
6343
7783
  }
6344
7784
  function gooseDbPath() {
6345
- return process.env.GOOSE_DB_PATH || join17(gooseHome(), "sessions", "sessions.db");
7785
+ return process.env.GOOSE_DB_PATH || join18(gooseHome(), "sessions", "sessions.db");
6346
7786
  }
6347
7787
  function gooseTimestampToMs(value) {
6348
7788
  if (typeof value === "number" && Number.isFinite(value)) {
@@ -6610,7 +8050,7 @@ var init_goose_projects = __esm(() => {
6610
8050
 
6611
8051
  // lib/projects.ts
6612
8052
  import { readdir as readdir5, stat as stat5 } from "node:fs/promises";
6613
- import { join as join18, resolve as resolve6, sep } from "node:path";
8053
+ import { join as join19, resolve as resolve7, sep } from "node:path";
6614
8054
  async function getMtime(path2, label) {
6615
8055
  try {
6616
8056
  return (await stat5(path2)).mtime;
@@ -6636,7 +8076,7 @@ async function getClaudeProjectFolders() {
6636
8076
  if (!entries)
6637
8077
  return [];
6638
8078
  const settled = await batchAll(entries.filter((entry) => entry.isDirectory()).map((entry) => async () => {
6639
- const folderPath = join18(projectsPath, entry.name);
8079
+ const folderPath = join19(projectsPath, entry.name);
6640
8080
  const mtime = await getMtime(folderPath, entry.name);
6641
8081
  return {
6642
8082
  name: entry.name,
@@ -6762,8 +8202,8 @@ function resolveProjectPath(projectName) {
6762
8202
  throw new RangeError("Empty project name");
6763
8203
  if (/^[/\\]/.test(projectName))
6764
8204
  throw new RangeError("Absolute project name");
6765
- const projectsPath = resolve6(getClaudeProjectsPath());
6766
- const candidate = resolve6(join18(projectsPath, projectName));
8205
+ const projectsPath = resolve7(getClaudeProjectsPath());
8206
+ const candidate = resolve7(join19(projectsPath, projectName));
6767
8207
  if (!candidate.startsWith(projectsPath + sep)) {
6768
8208
  throw new RangeError("Project path escapes root");
6769
8209
  }
@@ -6781,7 +8221,7 @@ async function getSessionFiles(projectPath) {
6781
8221
  return [];
6782
8222
  const jsonlEntries = entries.filter((entry) => entry.isFile() && entry.name.endsWith(".jsonl") && extractSessionId2(entry.name));
6783
8223
  const settled = await batchAll(jsonlEntries.map((entry) => async () => {
6784
- const filePath = join18(projectPath, entry.name);
8224
+ const filePath = join19(projectPath, entry.name);
6785
8225
  const mtime = await getMtime(filePath, entry.name);
6786
8226
  return {
6787
8227
  name: entry.name,
@@ -6810,13 +8250,13 @@ var init_projects = __esm(() => {
6810
8250
 
6811
8251
  // lib/resolve-subagent-path.ts
6812
8252
  import { access as access2 } from "fs/promises";
6813
- import { join as join19, relative as relative2 } from "path";
8253
+ import { join as join20, relative as relative2 } from "path";
6814
8254
  async function resolveSubagentPath(projectsPath, projectName, sessionId, agentId) {
6815
8255
  const fileName = `agent-${agentId}.jsonl`;
6816
8256
  const candidatePaths = [
6817
- join19(projectsPath, projectName, fileName),
6818
- join19(projectsPath, projectName, sessionId, fileName),
6819
- join19(projectsPath, projectName, sessionId, "subagents", fileName)
8257
+ join20(projectsPath, projectName, fileName),
8258
+ join20(projectsPath, projectName, sessionId, fileName),
8259
+ join20(projectsPath, projectName, sessionId, "subagents", fileName)
6820
8260
  ];
6821
8261
  for (const candidatePath of candidatePaths) {
6822
8262
  if (relative2(projectsPath, candidatePath).startsWith("..")) {
@@ -6837,8 +8277,8 @@ async function resolveSubagentPath(projectsPath, projectName, sessionId, agentId
6837
8277
  var init_resolve_subagent_path = () => {};
6838
8278
 
6839
8279
  // lib/log-entries.ts
6840
- import { readFile as readFile9 } from "fs/promises";
6841
- import { join as join20 } from "path";
8280
+ import { readFile as readFile10 } from "fs/promises";
8281
+ import { join as join21 } from "path";
6842
8282
  function formatTimestamp(date) {
6843
8283
  const base = formatDate(date);
6844
8284
  const ms = date.getMilliseconds().toString().padStart(3, "0");
@@ -7032,8 +8472,8 @@ async function parseFileContent(fileContent, source) {
7032
8472
  async function parseSessionLog(projectName, sessionId) {
7033
8473
  const projectDir = resolveProjectPath(projectName);
7034
8474
  const projectsPath = getClaudeProjectsPath();
7035
- const filePath = join20(projectDir, `${sessionId}.jsonl`);
7036
- const fileContent = await readFile9(filePath, "utf-8");
8475
+ const filePath = join21(projectDir, `${sessionId}.jsonl`);
8476
+ const fileContent = await readFile10(filePath, "utf-8");
7037
8477
  const { entries: sessionEntries, rawLines: sessionRawLines, subagentIds } = await parseFileContent(fileContent, "session");
7038
8478
  if (subagentIds.length === 0) {
7039
8479
  return { entries: sessionEntries, rawLines: sessionRawLines, subagentIds: [] };
@@ -7043,7 +8483,7 @@ async function parseSessionLog(projectName, sessionId) {
7043
8483
  const agentPath = await resolveSubagentPath(projectsPath, projectName, sessionId, agentId);
7044
8484
  if (!agentPath)
7045
8485
  return null;
7046
- const agentContent = await readFile9(agentPath, "utf-8");
8486
+ const agentContent = await readFile10(agentPath, "utf-8");
7047
8487
  const { entries, rawLines } = await parseFileContent(agentContent, agentSource);
7048
8488
  return { entries, rawLines };
7049
8489
  }), SUBAGENT_CONCURRENCY);
@@ -7069,32 +8509,32 @@ var init_log_entries = __esm(() => {
7069
8509
  });
7070
8510
 
7071
8511
  // lib/codex-sessions.ts
7072
- import { readFileSync as readFileSync5, readdirSync as readdirSync7, existsSync as existsSync6, writeFileSync as writeFileSync3, mkdirSync as mkdirSync4, statSync as statSync8 } from "node:fs";
7073
- import { readFile as readFile10 } from "node:fs/promises";
7074
- import { dirname as dirname4, join as join21 } from "node:path";
7075
- import { homedir as homedir17 } from "node:os";
8512
+ import { readFileSync as readFileSync6, readdirSync as readdirSync7, existsSync as existsSync7, writeFileSync as writeFileSync4, mkdirSync as mkdirSync5, statSync as statSync9 } from "node:fs";
8513
+ import { readFile as readFile11 } from "node:fs/promises";
8514
+ import { dirname as dirname4, join as join22 } from "node:path";
8515
+ import { homedir as homedir15 } from "node:os";
7076
8516
  function readCache() {
7077
8517
  try {
7078
- if (!existsSync6(CACHE_PATH))
8518
+ if (!existsSync7(CACHE_PATH))
7079
8519
  return {};
7080
- return JSON.parse(readFileSync5(CACHE_PATH, "utf-8"));
8520
+ return JSON.parse(readFileSync6(CACHE_PATH, "utf-8"));
7081
8521
  } catch {
7082
8522
  return {};
7083
8523
  }
7084
8524
  }
7085
8525
  function writeCacheEntry(sessionId, path2) {
7086
8526
  try {
7087
- mkdirSync4(dirname4(CACHE_PATH), { recursive: true });
8527
+ mkdirSync5(dirname4(CACHE_PATH), { recursive: true });
7088
8528
  const cache = readCache();
7089
8529
  cache[sessionId] = path2;
7090
- writeFileSync3(CACHE_PATH, JSON.stringify(cache), "utf-8");
8530
+ writeFileSync4(CACHE_PATH, JSON.stringify(cache), "utf-8");
7091
8531
  } catch {}
7092
8532
  }
7093
8533
  function dirSearch(dir, sessionId) {
7094
8534
  try {
7095
8535
  for (const f of readdirSync7(dir, { withFileTypes: true })) {
7096
8536
  if (f.isFile() && f.name.includes(sessionId) && f.name.endsWith(".jsonl")) {
7097
- return join21(dir, f.name);
8537
+ return join22(dir, f.name);
7098
8538
  }
7099
8539
  }
7100
8540
  } catch {}
@@ -7103,16 +8543,16 @@ function dirSearch(dir, sessionId) {
7103
8543
  function findCodexTranscript(sessionId) {
7104
8544
  const cache = readCache();
7105
8545
  const cached = cache[sessionId];
7106
- if (cached && existsSync6(cached))
8546
+ if (cached && existsSync7(cached))
7107
8547
  return cached;
7108
- const root = join21(homedir17(), ".codex", "sessions");
8548
+ const root = join22(homedir15(), ".codex", "sessions");
7109
8549
  const today = new Date;
7110
8550
  const yesterday = new Date(today.getTime() - 24 * 60 * 60 * 1000);
7111
8551
  const datedDirs = [today, yesterday].map((d) => {
7112
8552
  const y = String(d.getUTCFullYear());
7113
8553
  const m = String(d.getUTCMonth() + 1).padStart(2, "0");
7114
8554
  const day = String(d.getUTCDate()).padStart(2, "0");
7115
- return join21(root, y, m, day);
8555
+ return join22(root, y, m, day);
7116
8556
  });
7117
8557
  for (const dir of datedDirs) {
7118
8558
  const hit = dirSearch(dir, sessionId);
@@ -7125,13 +8565,13 @@ function findCodexTranscript(sessionId) {
7125
8565
  for (const y of readdirSync7(root, { withFileTypes: true })) {
7126
8566
  if (!y.isDirectory())
7127
8567
  continue;
7128
- for (const m of readdirSync7(join21(root, y.name), { withFileTypes: true })) {
8568
+ for (const m of readdirSync7(join22(root, y.name), { withFileTypes: true })) {
7129
8569
  if (!m.isDirectory())
7130
8570
  continue;
7131
- for (const d of readdirSync7(join21(root, y.name, m.name), { withFileTypes: true })) {
8571
+ for (const d of readdirSync7(join22(root, y.name, m.name), { withFileTypes: true })) {
7132
8572
  if (!d.isDirectory())
7133
8573
  continue;
7134
- const hit = dirSearch(join21(root, y.name, m.name, d.name), sessionId);
8574
+ const hit = dirSearch(join22(root, y.name, m.name, d.name), sessionId);
7135
8575
  if (hit) {
7136
8576
  writeCacheEntry(sessionId, hit);
7137
8577
  return hit;
@@ -7344,19 +8784,20 @@ async function getCodexSessionLog(sessionId) {
7344
8784
  const filePath = findCodexTranscript(sessionId);
7345
8785
  if (!filePath)
7346
8786
  return null;
7347
- const fileContent = await readFile10(filePath, "utf-8");
8787
+ const fileContent = await readFile11(filePath, "utf-8");
7348
8788
  const { entries, rawLines, cwd } = await parseCodexLog(fileContent, "session");
7349
8789
  return { entries, rawLines, cwd, filePath };
7350
8790
  }
7351
8791
  var CACHE_PATH, getCachedCodexSessionLog;
7352
8792
  var init_codex_sessions = __esm(() => {
7353
8793
  init_log_entries();
7354
- CACHE_PATH = join21(homedir17(), ".failproofai", "cache", "codex-session-paths.json");
8794
+ init_fp_home();
8795
+ CACHE_PATH = codexSessionPathsFile();
7355
8796
  getCachedCodexSessionLog = runtimeCache((sessionId) => getCodexSessionLog(sessionId), 60, { maxSize: 50 });
7356
8797
  });
7357
8798
 
7358
8799
  // src/hooks/resolve-permission-mode.ts
7359
- import { readFileSync as readFileSync6 } from "node:fs";
8800
+ import { readFileSync as readFileSync7 } from "node:fs";
7360
8801
  function resolvePermissionMode(integration, parsed, sessionId) {
7361
8802
  if (integration === "claude") {
7362
8803
  return parsed.permission_mode ?? "default";
@@ -7371,7 +8812,7 @@ function resolveCodexMode(sessionId) {
7371
8812
  const path2 = findCodexTranscript(sessionId);
7372
8813
  if (!path2)
7373
8814
  return;
7374
- for (const line of readFileSync6(path2, "utf-8").split(`
8815
+ for (const line of readFileSync7(path2, "utf-8").split(`
7375
8816
  `)) {
7376
8817
  if (!line.includes("turn_context"))
7377
8818
  continue;
@@ -7396,21 +8837,21 @@ var init_resolve_permission_mode = __esm(() => {
7396
8837
  });
7397
8838
 
7398
8839
  // lib/copilot-sessions.ts
7399
- import { readFileSync as readFileSync7, readdirSync as readdirSync8, existsSync as existsSync7, statSync as statSync9 } from "node:fs";
7400
- import { readFile as readFile11 } from "node:fs/promises";
7401
- import { join as join22, resolve as resolve7, sep as sep2 } from "node:path";
7402
- import { homedir as homedir18 } from "node:os";
8840
+ import { readFileSync as readFileSync8, readdirSync as readdirSync8, existsSync as existsSync8, statSync as statSync10 } from "node:fs";
8841
+ import { readFile as readFile12 } from "node:fs/promises";
8842
+ import { join as join23, resolve as resolve8, sep as sep2 } from "node:path";
8843
+ import { homedir as homedir16 } from "node:os";
7403
8844
  function getCopilotHome() {
7404
- return process.env.COPILOT_HOME || join22(homedir18(), ".copilot");
8845
+ return process.env.COPILOT_HOME || join23(homedir16(), ".copilot");
7405
8846
  }
7406
8847
  function getCopilotSessionStateRoot2() {
7407
- return join22(getCopilotHome(), "session-state");
8848
+ return join23(getCopilotHome(), "session-state");
7408
8849
  }
7409
8850
  function getCopilotSessionDir(sessionId) {
7410
8851
  if (!sessionId)
7411
8852
  return null;
7412
- const root = resolve7(getCopilotSessionStateRoot2());
7413
- const candidate = resolve7(root, sessionId);
8853
+ const root = resolve8(getCopilotSessionStateRoot2());
8854
+ const candidate = resolve8(root, sessionId);
7414
8855
  if (candidate === root || !candidate.startsWith(`${root}${sep2}`))
7415
8856
  return null;
7416
8857
  return candidate;
@@ -7419,23 +8860,23 @@ function resolveSessionFile(sessionId, filename) {
7419
8860
  const dir = getCopilotSessionDir(sessionId);
7420
8861
  if (!dir)
7421
8862
  return null;
7422
- return join22(dir, filename);
8863
+ return join23(dir, filename);
7423
8864
  }
7424
8865
  function findCopilotTranscript(sessionId) {
7425
8866
  const candidate = resolveSessionFile(sessionId, "events.jsonl");
7426
8867
  if (!candidate)
7427
8868
  return null;
7428
- return existsSync7(candidate) ? candidate : null;
8869
+ return existsSync8(candidate) ? candidate : null;
7429
8870
  }
7430
8871
  function findCopilotWorkspace(sessionId) {
7431
8872
  const candidate = resolveSessionFile(sessionId, "workspace.yaml");
7432
8873
  if (!candidate)
7433
8874
  return null;
7434
- return existsSync7(candidate) ? candidate : null;
8875
+ return existsSync8(candidate) ? candidate : null;
7435
8876
  }
7436
8877
  function readYamlScalar(path2, key) {
7437
8878
  try {
7438
- const text = readFileSync7(path2, "utf-8");
8879
+ const text = readFileSync8(path2, "utf-8");
7439
8880
  const re = new RegExp(`^${key}\\s*:\\s*(.+?)\\s*$`, "m");
7440
8881
  const m = text.match(re);
7441
8882
  if (!m)
@@ -7598,7 +9039,7 @@ async function getCopilotSessionLog(sessionId) {
7598
9039
  return null;
7599
9040
  let fileContent;
7600
9041
  try {
7601
- fileContent = await readFile11(filePath, "utf-8");
9042
+ fileContent = await readFile12(filePath, "utf-8");
7602
9043
  } catch {
7603
9044
  return null;
7604
9045
  }
@@ -7613,18 +9054,18 @@ var init_copilot_sessions = __esm(() => {
7613
9054
  });
7614
9055
 
7615
9056
  // lib/cursor-sessions.ts
7616
- import { readFileSync as readFileSync8, readdirSync as readdirSync9, existsSync as existsSync8, statSync as statSync10 } from "node:fs";
7617
- import { readFile as readFile12 } from "node:fs/promises";
7618
- import { basename as basename3, join as join23, resolve as resolve8, sep as sep3 } from "node:path";
7619
- import { homedir as homedir19 } from "node:os";
9057
+ import { readFileSync as readFileSync9, readdirSync as readdirSync9, existsSync as existsSync9, statSync as statSync11 } from "node:fs";
9058
+ import { readFile as readFile13 } from "node:fs/promises";
9059
+ import { basename as basename3, join as join24, resolve as resolve9, sep as sep3 } from "node:path";
9060
+ import { homedir as homedir17 } from "node:os";
7620
9061
  function getCursorHome2() {
7621
- return process.env.CURSOR_HOME || join23(homedir19(), ".cursor");
9062
+ return process.env.CURSOR_HOME || join24(homedir17(), ".cursor");
7622
9063
  }
7623
9064
  function getCursorSessionDir(sessionId) {
7624
9065
  if (!sessionId)
7625
9066
  return null;
7626
- const home = resolve8(getCursorHome2());
7627
- const projectsRoot = resolve8(home, NEW_PROJECTS_DIR2);
9067
+ const home = resolve9(getCursorHome2());
9068
+ const projectsRoot = resolve9(home, NEW_PROJECTS_DIR2);
7628
9069
  let projectEntries = [];
7629
9070
  try {
7630
9071
  projectEntries = readdirSync9(projectsRoot, { withFileTypes: true });
@@ -7632,19 +9073,19 @@ function getCursorSessionDir(sessionId) {
7632
9073
  for (const entry of projectEntries) {
7633
9074
  if (!entry.isDirectory())
7634
9075
  continue;
7635
- const candidate = resolve8(projectsRoot, entry.name, NEW_AGENT_TRANSCRIPTS_DIR2, sessionId);
7636
- const transcriptRoot = resolve8(projectsRoot, entry.name, NEW_AGENT_TRANSCRIPTS_DIR2);
9076
+ const candidate = resolve9(projectsRoot, entry.name, NEW_AGENT_TRANSCRIPTS_DIR2, sessionId);
9077
+ const transcriptRoot = resolve9(projectsRoot, entry.name, NEW_AGENT_TRANSCRIPTS_DIR2);
7637
9078
  if (candidate === transcriptRoot || !candidate.startsWith(`${transcriptRoot}${sep3}`))
7638
9079
  continue;
7639
- if (existsSync8(candidate))
9080
+ if (existsSync9(candidate))
7640
9081
  return candidate;
7641
9082
  }
7642
9083
  for (const sub of LEGACY_SESSION_ROOT_CANDIDATES2) {
7643
- const root = resolve8(home, sub);
7644
- const candidate = resolve8(root, sessionId);
9084
+ const root = resolve9(home, sub);
9085
+ const candidate = resolve9(root, sessionId);
7645
9086
  if (candidate === root || !candidate.startsWith(`${root}${sep3}`))
7646
9087
  continue;
7647
- if (existsSync8(candidate))
9088
+ if (existsSync9(candidate))
7648
9089
  return candidate;
7649
9090
  }
7650
9091
  return null;
@@ -7653,12 +9094,12 @@ function findCursorTranscript(sessionId) {
7653
9094
  const dir = getCursorSessionDir(sessionId);
7654
9095
  if (!dir)
7655
9096
  return null;
7656
- const newCandidate = join23(dir, `${basename3(dir)}.jsonl`);
7657
- if (existsSync8(newCandidate))
9097
+ const newCandidate = join24(dir, `${basename3(dir)}.jsonl`);
9098
+ if (existsSync9(newCandidate))
7658
9099
  return newCandidate;
7659
9100
  for (const name of LEGACY_TRANSCRIPT_FILE_CANDIDATES2) {
7660
- const candidate = join23(dir, name);
7661
- if (existsSync8(candidate))
9101
+ const candidate = join24(dir, name);
9102
+ if (existsSync9(candidate))
7662
9103
  return candidate;
7663
9104
  }
7664
9105
  return null;
@@ -7853,7 +9294,7 @@ async function getCursorSessionLog(sessionId) {
7853
9294
  return null;
7854
9295
  let fileContent;
7855
9296
  try {
7856
- fileContent = await readFile12(filePath, "utf-8");
9297
+ fileContent = await readFile13(filePath, "utf-8");
7857
9298
  } catch {
7858
9299
  return null;
7859
9300
  }
@@ -7869,12 +9310,12 @@ var init_cursor_sessions = __esm(() => {
7869
9310
  });
7870
9311
 
7871
9312
  // lib/pi-sessions.ts
7872
- import { readFileSync as readFileSync9, readdirSync as readdirSync10, existsSync as existsSync9, statSync as statSync11 } from "node:fs";
7873
- import { readFile as readFile13 } from "node:fs/promises";
7874
- import { join as join24, resolve as resolve9, sep as sep4 } from "node:path";
7875
- import { homedir as homedir20 } from "node:os";
9313
+ import { readFileSync as readFileSync10, readdirSync as readdirSync10, existsSync as existsSync10, statSync as statSync12 } from "node:fs";
9314
+ import { readFile as readFile14 } from "node:fs/promises";
9315
+ import { join as join25, resolve as resolve10, sep as sep4 } from "node:path";
9316
+ import { homedir as homedir18 } from "node:os";
7876
9317
  function getPiSessionStateRoot() {
7877
- return process.env.PI_SESSIONS_DIR || join24(homedir20(), ".pi", "agent", "sessions");
9318
+ return process.env.PI_SESSIONS_DIR || join25(homedir18(), ".pi", "agent", "sessions");
7878
9319
  }
7879
9320
  function isSafeSessionId(sessionId) {
7880
9321
  return UUID_RE.test(sessionId);
@@ -7882,7 +9323,7 @@ function isSafeSessionId(sessionId) {
7882
9323
  function findPiTranscript(sessionId) {
7883
9324
  if (!isSafeSessionId(sessionId))
7884
9325
  return null;
7885
- const root = resolve9(getPiSessionStateRoot());
9326
+ const root = resolve10(getPiSessionStateRoot());
7886
9327
  let cwdDirs;
7887
9328
  try {
7888
9329
  cwdDirs = readdirSync10(root);
@@ -7890,7 +9331,7 @@ function findPiTranscript(sessionId) {
7890
9331
  return null;
7891
9332
  }
7892
9333
  for (const cwdDir of cwdDirs) {
7893
- const cwdPath = resolve9(root, cwdDir);
9334
+ const cwdPath = resolve10(root, cwdDir);
7894
9335
  if (!cwdPath.startsWith(`${root}${sep4}`))
7895
9336
  continue;
7896
9337
  let files;
@@ -7903,10 +9344,10 @@ function findPiTranscript(sessionId) {
7903
9344
  const m = SESSION_FILE_RE2.exec(f);
7904
9345
  if (!m || m[1].toLowerCase() !== sessionId.toLowerCase())
7905
9346
  continue;
7906
- const candidate = resolve9(cwdPath, f);
9347
+ const candidate = resolve10(cwdPath, f);
7907
9348
  if (!candidate.startsWith(`${cwdPath}${sep4}`))
7908
9349
  continue;
7909
- if (existsSync9(candidate))
9350
+ if (existsSync10(candidate))
7910
9351
  return candidate;
7911
9352
  }
7912
9353
  }
@@ -7924,7 +9365,7 @@ function extractMessageText(content) {
7924
9365
 
7925
9366
  `);
7926
9367
  }
7927
- function buildAssistantContent(content) {
9368
+ function buildAssistantContent(content, onToolUse) {
7928
9369
  if (!Array.isArray(content))
7929
9370
  return [];
7930
9371
  const blocks = [];
@@ -7935,6 +9376,14 @@ function buildAssistantContent(content) {
7935
9376
  if (block?.type === "thinking" && typeof block.thinking === "string" && block.thinking.length > 0) {
7936
9377
  blocks.push({ type: "text", text: `[thinking] ${block.thinking}` });
7937
9378
  }
9379
+ if (block?.type === "toolCall") {
9380
+ const id = typeof block.id === "string" && block.id.length > 0 ? block.id : `${typeof block.name === "string" ? block.name : "tool"}-${blocks.length}`;
9381
+ const name = typeof block.name === "string" ? block.name : "tool";
9382
+ const input = block.arguments && typeof block.arguments === "object" && !Array.isArray(block.arguments) ? block.arguments : {};
9383
+ const toolUse = { type: "tool_use", id, name, input };
9384
+ blocks.push(toolUse);
9385
+ onToolUse?.(toolUse);
9386
+ }
7938
9387
  }
7939
9388
  return blocks;
7940
9389
  }
@@ -7945,6 +9394,8 @@ async function parsePiLog(fileContent, source = "session") {
7945
9394
  const rawLines = [];
7946
9395
  let cwd;
7947
9396
  let seenSessionStart = false;
9397
+ const toolUseById = new Map;
9398
+ const toolUseStartMs = new Map;
7948
9399
  for (let i = 0;i < lines.length; i++) {
7949
9400
  if (i > 0 && i % 200 === 0)
7950
9401
  await new Promise((r) => setImmediate(r));
@@ -7992,7 +9443,10 @@ async function parsePiLog(fileContent, source = "session") {
7992
9443
  continue;
7993
9444
  }
7994
9445
  if (role === "assistant") {
7995
- const blocks = buildAssistantContent(content);
9446
+ const blocks = buildAssistantContent(content, (block) => {
9447
+ toolUseById.set(block.id, block);
9448
+ toolUseStartMs.set(block.id, date.getTime());
9449
+ });
7996
9450
  if (blocks.length === 0) {
7997
9451
  entries.push({
7998
9452
  type: "system",
@@ -8008,6 +9462,22 @@ async function parsePiLog(fileContent, source = "session") {
8008
9462
  });
8009
9463
  continue;
8010
9464
  }
9465
+ if (role === "toolResult") {
9466
+ const callId = raw.message.toolCallId;
9467
+ const block = typeof callId === "string" ? toolUseById.get(callId) : undefined;
9468
+ if (block) {
9469
+ const startMs = typeof callId === "string" && toolUseStartMs.get(callId) || date.getTime();
9470
+ const durationMs = Math.max(0, date.getTime() - startMs);
9471
+ block.result = {
9472
+ timestamp,
9473
+ timestampFormatted: formatTimestamp(date),
9474
+ content: extractMessageText(content),
9475
+ durationMs,
9476
+ durationFormatted: formatDuration(durationMs)
9477
+ };
9478
+ continue;
9479
+ }
9480
+ }
8011
9481
  entries.push({
8012
9482
  type: "system",
8013
9483
  ...baseEntry(rawCopy, timestamp, date, source),
@@ -8032,7 +9502,7 @@ async function getPiSessionLog(sessionId) {
8032
9502
  return null;
8033
9503
  let fileContent;
8034
9504
  try {
8035
- fileContent = await readFile13(filePath, "utf-8");
9505
+ fileContent = await readFile14(filePath, "utf-8");
8036
9506
  } catch {
8037
9507
  return null;
8038
9508
  }
@@ -8101,6 +9571,192 @@ var init_resolve_transcript_path = __esm(() => {
8101
9571
  init_factory_sessions();
8102
9572
  init_antigravity_sessions();
8103
9573
  });
9574
+ // src/hooks/cloud-managed-policies.ts
9575
+ import { createHash as createHash3 } from "node:crypto";
9576
+ import { existsSync as existsSync11, readFileSync as readFileSync11, realpathSync, rmSync } from "node:fs";
9577
+ import { isAbsolute as isAbsolute2, relative as relative3, resolve as resolve11 } from "node:path";
9578
+ function cloudManagedPolicyRoot() {
9579
+ return process.env.FAILPROOFAI_CLOUD_POLICY_DIR ?? cloudPoliciesDir();
9580
+ }
9581
+ function parseManifest(value) {
9582
+ if (!value || typeof value !== "object")
9583
+ throw new Error("active manifest is not an object");
9584
+ const manifest = value;
9585
+ if (manifest.schemaVersion !== ACTIVE_SCHEMA_VERSION) {
9586
+ throw new Error(`unsupported active manifest schema ${String(manifest.schemaVersion)}`);
9587
+ }
9588
+ if (!Number.isSafeInteger(manifest.generation) || (manifest.generation ?? -1) < 0) {
9589
+ throw new Error("active manifest generation is invalid");
9590
+ }
9591
+ if (!Array.isArray(manifest.policies))
9592
+ throw new Error("active manifest policies is not an array");
9593
+ return manifest;
9594
+ }
9595
+ function resolveManagedPath(root, candidate) {
9596
+ if (!candidate || isAbsolute2(candidate))
9597
+ throw new Error(`unsafe managed policy path ${JSON.stringify(candidate)}`);
9598
+ const absolute = resolve11(root, candidate);
9599
+ const lexicalRelative = relative3(root, absolute);
9600
+ if (lexicalRelative.startsWith("..") || isAbsolute2(lexicalRelative)) {
9601
+ throw new Error(`managed policy path escapes its root: ${JSON.stringify(candidate)}`);
9602
+ }
9603
+ const realRoot = realpathSync(root);
9604
+ const realFile = realpathSync(absolute);
9605
+ const physicalRelative = relative3(realRoot, realFile);
9606
+ if (physicalRelative.startsWith("..") || isAbsolute2(physicalRelative)) {
9607
+ throw new Error(`managed policy symlink escapes its root: ${JSON.stringify(candidate)}`);
9608
+ }
9609
+ return realFile;
9610
+ }
9611
+ function readActiveCloudManagedPolicies() {
9612
+ const root = cloudManagedPolicyRoot();
9613
+ const activePath = resolve11(root, "active.json");
9614
+ if (!existsSync11(activePath))
9615
+ return [];
9616
+ let raw;
9617
+ try {
9618
+ raw = JSON.parse(readFileSync11(activePath, "utf8"));
9619
+ } catch (err) {
9620
+ throw new Error(`failed to read cloud-managed active manifest: ${err instanceof Error ? err.message : String(err)}`);
9621
+ }
9622
+ const manifest = parseManifest(raw);
9623
+ const seen = new Set;
9624
+ return manifest.policies.map((policy) => {
9625
+ if (!POLICY_ID_RE.test(policy.id) || policy.id === "." || policy.id === "..") {
9626
+ throw new Error(`unsafe cloud-managed policy id ${JSON.stringify(policy.id)}`);
9627
+ }
9628
+ if (!Number.isSafeInteger(policy.revision) || policy.revision < 0) {
9629
+ throw new Error(`invalid revision for cloud-managed policy ${policy.id}`);
9630
+ }
9631
+ if (!SHA256_RE.test(policy.sha256)) {
9632
+ throw new Error(`invalid SHA-256 for cloud-managed policy ${policy.id}`);
9633
+ }
9634
+ if (seen.has(policy.id))
9635
+ throw new Error(`duplicate cloud-managed policy id ${policy.id}`);
9636
+ seen.add(policy.id);
9637
+ const path2 = resolveManagedPath(root, policy.path);
9638
+ const bytes = readFileSync11(path2);
9639
+ const actual = createHash3("sha256").update(bytes).digest("hex");
9640
+ if (actual !== policy.sha256) {
9641
+ throw new Error(`cloud-managed policy ${policy.id} failed integrity verification: expected ${policy.sha256}, got ${actual}`);
9642
+ }
9643
+ if (policy.effect !== undefined && policy.effect !== "enforce" && policy.effect !== "observe") {
9644
+ throw new Error(`unknown effect ${JSON.stringify(policy.effect)} for cloud-managed policy ${policy.id}`);
9645
+ }
9646
+ return {
9647
+ id: policy.id,
9648
+ revision: policy.revision,
9649
+ effect: policy.effect ?? "enforce",
9650
+ sha256: policy.sha256,
9651
+ path: path2,
9652
+ generation: manifest.generation
9653
+ };
9654
+ });
9655
+ }
9656
+ var ACTIVE_SCHEMA_VERSION = 1, SHA256_RE, POLICY_ID_RE;
9657
+ var init_cloud_managed_policies = __esm(() => {
9658
+ init_fp_home();
9659
+ SHA256_RE = /^[a-f0-9]{64}$/;
9660
+ POLICY_ID_RE = /^[A-Za-z0-9._-]{1,128}$/;
9661
+ });
9662
+
9663
+ // lib/atomic-write.ts
9664
+ var init_atomic_write = () => {};
9665
+
9666
+ // src/hooks/session-pause.ts
9667
+ import { existsSync as existsSync12, mkdirSync as mkdirSync6, readdirSync as readdirSync11, readFileSync as readFileSync12, rmSync as rmSync2 } from "node:fs";
9668
+ import { createHash as createHash4 } from "node:crypto";
9669
+ import { join as join26, resolve as resolve12 } from "node:path";
9670
+ function pauseStateDir() {
9671
+ const override = process.env.FAILPROOFAI_STATE_DIR;
9672
+ if (override)
9673
+ return resolve12(override, "sessions");
9674
+ return sessionPauseDir();
9675
+ }
9676
+ function pauseFilePath(sessionId) {
9677
+ const digest = createHash4("sha256").update(sessionId).digest("hex").slice(0, 32);
9678
+ return join26(pauseStateDir(), `${digest}.json`);
9679
+ }
9680
+ function parseStored(raw) {
9681
+ if (!raw || typeof raw !== "object")
9682
+ return null;
9683
+ const p = raw;
9684
+ if (p.schemaVersion !== SCHEMA_VERSION)
9685
+ return null;
9686
+ if (typeof p.sessionId !== "string" || p.sessionId.length === 0)
9687
+ return null;
9688
+ if (!Number.isFinite(p.pausedAt) || !Number.isFinite(p.expiresAt))
9689
+ return null;
9690
+ const pausedAt = p.pausedAt;
9691
+ const firstPausedAt = Number.isFinite(p.firstPausedAt) ? p.firstPausedAt : pausedAt;
9692
+ return {
9693
+ schemaVersion: SCHEMA_VERSION,
9694
+ sessionId: p.sessionId,
9695
+ pausedAt,
9696
+ firstPausedAt,
9697
+ expiresAt: Math.min(p.expiresAt, firstPausedAt + PAUSE_CEILING_MS),
9698
+ setBy: typeof p.setBy === "string" ? p.setBy : "unknown",
9699
+ ...typeof p.cwd === "string" ? { cwd: p.cwd } : {}
9700
+ };
9701
+ }
9702
+ function readActivePause(sessionId, now = Date.now()) {
9703
+ if (!sessionId)
9704
+ return null;
9705
+ try {
9706
+ const path2 = pauseFilePath(sessionId);
9707
+ if (!existsSync12(path2))
9708
+ return null;
9709
+ const stored = parseStored(JSON.parse(readFileSync12(path2, "utf8")));
9710
+ if (!stored)
9711
+ return null;
9712
+ if (stored.expiresAt <= now)
9713
+ return null;
9714
+ const { schemaVersion: _ignored, ...pause } = stored;
9715
+ return pause;
9716
+ } catch {
9717
+ return null;
9718
+ }
9719
+ }
9720
+ var SCHEMA_VERSION = 1, PAUSE_DEFAULT_MS, PAUSE_CEILING_MS;
9721
+ var init_session_pause = __esm(() => {
9722
+ init_atomic_write();
9723
+ init_hook_activity_store();
9724
+ init_fp_home();
9725
+ PAUSE_DEFAULT_MS = 30 * 60000;
9726
+ PAUSE_CEILING_MS = 8 * 60 * 60000;
9727
+ });
9728
+
9729
+ // src/hooks/daemon-download.ts
9730
+ var init_daemon_download = __esm(() => {
9731
+ init_package();
9732
+ init_fp_home();
9733
+ });
9734
+
9735
+ // src/hooks/daemon-service.ts
9736
+ var init_daemon_service = __esm(() => {
9737
+ init_hook_logger();
9738
+ init_daemon_download();
9739
+ init_fp_home();
9740
+ init_package();
9741
+ init_fp_config();
9742
+ });
9743
+
9744
+ // src/hooks/fp-reset.ts
9745
+ function layoutWarningForHook() {
9746
+ const state = detectLayout();
9747
+ if (state.kind === "current" || state.kind === "absent")
9748
+ return null;
9749
+ if (state.kind === "future") {
9750
+ return `[failproofai] this directory was written by a newer version ` + `(layout ${state.found} vs ${LAYOUT_VERSION}) — policies are NOT being enforced. ` + `Upgrade failproofai.`;
9751
+ }
9752
+ return `[failproofai] setup predates this version — global policies are NOT being enforced. ` + `Run \`failproofai config\` to re-create it.`;
9753
+ }
9754
+ var init_fp_reset = __esm(() => {
9755
+ init_fp_home();
9756
+ init_fp_config();
9757
+ init_daemon_service();
9758
+ });
9759
+
8104
9760
  // src/hooks/handler.ts
8105
9761
  function canonicalizeEventType(raw, cli) {
8106
9762
  if (cli === "codex") {
@@ -8135,8 +9791,29 @@ function canonicalizeEventType(raw, cli) {
8135
9791
  }
8136
9792
  return raw;
8137
9793
  }
9794
+ async function runObserved(hook, ctx, hookName, eventType, cli) {
9795
+ try {
9796
+ return await Promise.race([
9797
+ hook.fn(ctx),
9798
+ new Promise((_, reject) => setTimeout(() => reject(new Error("timeout")), 1e4))
9799
+ ]);
9800
+ } catch (err) {
9801
+ const msg = err instanceof Error ? err.message : String(err);
9802
+ trackHookEvent(getInstanceId(), "custom_hook_error", {
9803
+ hook_name: hookName,
9804
+ error_type: msg === "timeout" ? "timeout" : "exception",
9805
+ event_type: eventType,
9806
+ cli,
9807
+ is_observe_mode: true
9808
+ });
9809
+ return { decision: "allow" };
9810
+ }
9811
+ }
8138
9812
  async function evaluateHookEvent(eventType, cli = "claude", stdinPayload, opts) {
8139
9813
  const startTime = performance.now();
9814
+ const layoutWarning = layoutWarningForHook();
9815
+ if (layoutWarning)
9816
+ hookLogWarn(layoutWarning);
8140
9817
  try {
8141
9818
  let parsed = {};
8142
9819
  if (stdinPayload) {
@@ -8176,6 +9853,10 @@ async function evaluateHookEvent(eventType, cli = "claude", stdinPayload, opts)
8176
9853
  let config;
8177
9854
  let customHooksList = [];
8178
9855
  let conventionHookNames = new Set;
9856
+ let activePause = null;
9857
+ const policyAttribution = new Map;
9858
+ let cloudGeneration;
9859
+ const observedResults = [];
8179
9860
  if (opts?.forceDecision) {
8180
9861
  config = { enabledPolicies: [] };
8181
9862
  clearPolicies();
@@ -8184,23 +9865,59 @@ async function evaluateHookEvent(eventType, cli = "claude", stdinPayload, opts)
8184
9865
  } else {
8185
9866
  config = readMergedHooksConfig(session.cwd);
8186
9867
  clearPolicies();
8187
- registerBuiltinPolicies(config.enabledPolicies);
8188
- const loadResult = await loadAllCustomHooks(config.customPoliciesPaths ?? config.customPoliciesPath, {
9868
+ activePause = readActivePause(session.sessionId);
9869
+ registerBuiltinPolicies(activePause ? [] : config.enabledPolicies);
9870
+ let cloudManagedPolicies = [];
9871
+ try {
9872
+ cloudManagedPolicies = readActiveCloudManagedPolicies();
9873
+ } catch (err) {
9874
+ const msg = err instanceof Error ? err.message : String(err);
9875
+ hookLogWarn(`[failproofai] cloud-managed policies could NOT be loaded and are not being enforced: ${msg}. ` + `Local policies are unaffected. Run \`failproofai config --status\` to check this machine's enrolment.`);
9876
+ trackHookEvent(getInstanceId(), "cloud_managed_load_error", {
9877
+ event_type: eventType,
9878
+ cli
9879
+ });
9880
+ }
9881
+ cloudGeneration = cloudManagedPolicies[0]?.generation;
9882
+ const configuredCustomPaths = config.customPoliciesPaths ?? config.customPoliciesPath;
9883
+ const allExplicitPaths = cloudManagedPolicies.length === 0 ? configuredCustomPaths : [
9884
+ ...typeof configuredCustomPaths === "string" ? [configuredCustomPaths] : configuredCustomPaths ?? [],
9885
+ ...cloudManagedPolicies.map((policy) => policy.path)
9886
+ ];
9887
+ const loadResult = await loadAllCustomHooks(allExplicitPaths, {
8189
9888
  sessionCwd: session.cwd,
8190
- customPoliciesEnabled: config.customPoliciesEnabled
9889
+ customPoliciesEnabled: config.customPoliciesEnabled,
9890
+ ...cloudManagedPolicies.length > 0 ? { cloudManagedPolicies } : {}
8191
9891
  });
8192
9892
  customHooksList = loadResult.hooks;
8193
9893
  const disabledCustomPolicies = new Set(config.disabledCustomPolicies ?? []);
8194
9894
  conventionHookNames = new Set(loadResult.conventionSources.flatMap((s) => s.hookNames));
8195
9895
  for (const hook of customHooksList) {
8196
- const policyId = hook.__policyId;
8197
- if (policyId && disabledCustomPolicies.has(policyId))
9896
+ const taggedHook = hook;
9897
+ const policyId = taggedHook.__policyId;
9898
+ const cloudManaged = taggedHook.__cloudManaged;
9899
+ if (!cloudManaged && policyId && disabledCustomPolicies.has(policyId))
9900
+ continue;
9901
+ if (!cloudManaged && activePause)
8198
9902
  continue;
8199
9903
  const hookName = hook.name;
8200
9904
  const conventionScope = hook.__conventionScope;
8201
9905
  const isConvention = !!conventionScope;
8202
- const prefix = isConvention ? `.failproofai-${conventionScope}` : "custom";
9906
+ const prefix = cloudManaged ? `cloud/${cloudManaged.id}@${cloudManaged.revision}` : isConvention ? `.failproofai-${conventionScope}` : "custom";
9907
+ const observeOnly = cloudManaged?.effect === "observe";
8203
9908
  const fn = async (ctx) => {
9909
+ if (observeOnly) {
9910
+ const shadow = await runObserved(hook, ctx, hookName, eventType, cli);
9911
+ if (shadow.decision !== "allow") {
9912
+ observedResults.push({
9913
+ policyId: cloudManaged.id,
9914
+ revision: cloudManaged.revision,
9915
+ decision: shadow.decision,
9916
+ reason: shadow.reason ?? null
9917
+ });
9918
+ }
9919
+ return { decision: "allow" };
9920
+ }
8204
9921
  try {
8205
9922
  const result2 = await Promise.race([
8206
9923
  hook.fn(ctx),
@@ -8222,7 +9939,12 @@ async function evaluateHookEvent(eventType, cli = "claude", stdinPayload, opts)
8222
9939
  return { decision: "allow" };
8223
9940
  }
8224
9941
  };
8225
- registerPolicy(`${prefix}/${hookName}`, hook.description ?? "", fn, hook.match ?? {}, -1);
9942
+ const registeredName = `${prefix}/${hookName}`;
9943
+ policyAttribution.set(registeredName, {
9944
+ source: cloudManaged ? "cloud" : isConvention ? "convention" : "custom",
9945
+ ...cloudManaged ? { cloudPolicyId: cloudManaged.id, cloudRevision: cloudManaged.revision } : {}
9946
+ });
9947
+ registerPolicy(registeredName, hook.description ?? "", fn, hook.match ?? {}, -1);
8226
9948
  }
8227
9949
  if (customHooksList.length > 0) {
8228
9950
  trackHookEvent(getInstanceId(), "custom_hooks_loaded", {
@@ -8263,7 +9985,18 @@ async function evaluateHookEvent(eventType, cli = "claude", stdinPayload, opts)
8263
9985
  transcriptPath: session.transcriptPath,
8264
9986
  cwd: session.cwd,
8265
9987
  permissionMode: session.permissionMode,
8266
- hookEventName: session.hookEventName
9988
+ hookEventName: session.hookEventName,
9989
+ ...result.policyName ? (() => {
9990
+ const attribution = policyAttribution.get(result.policyName);
9991
+ return {
9992
+ policySource: attribution?.source ?? "builtin",
9993
+ ...attribution?.cloudPolicyId ? { cloudPolicyId: attribution.cloudPolicyId } : {},
9994
+ ...attribution?.cloudRevision !== undefined ? { cloudRevision: attribution.cloudRevision } : {}
9995
+ };
9996
+ })() : {},
9997
+ ...cloudGeneration !== undefined ? { cloudGeneration } : {},
9998
+ ...observedResults.length > 0 ? { observed: observedResults } : {},
9999
+ ...activePause ? { pausedBy: activePause.setBy, pauseExpiresAt: activePause.expiresAt } : {}
8267
10000
  };
8268
10001
  try {
8269
10002
  persistHookActivity(activityEntry);
@@ -8315,6 +10048,9 @@ var init_handler = __esm(() => {
8315
10048
  init_resolve_transcript_path();
8316
10049
  init_telemetry_id();
8317
10050
  init_hook_logger();
10051
+ init_cloud_managed_policies();
10052
+ init_session_pause();
10053
+ init_fp_reset();
8318
10054
  });
8319
10055
 
8320
10056
  // src/hooks/worker-server.ts
@@ -8323,12 +10059,12 @@ __export(exports_worker_server, {
8323
10059
  startWorkerServer: () => startWorkerServer
8324
10060
  });
8325
10061
  import { createServer } from "node:net";
8326
- import { existsSync as existsSync10, unlinkSync as unlinkSync2 } from "node:fs";
10062
+ import { existsSync as existsSync13, unlinkSync as unlinkSync2 } from "node:fs";
8327
10063
  function isWorkerHookRequest(msg) {
8328
10064
  if (!msg || typeof msg !== "object")
8329
10065
  return false;
8330
10066
  const m = msg;
8331
- return m.type === "hook" && typeof m.hookEvent === "string" && typeof m.cli === "string" && typeof m.stdin === "string" && (m.cwd === undefined || typeof m.cwd === "string");
10067
+ return m.type === "hook" && typeof m.hookEvent === "string" && typeof m.cli === "string" && typeof m.stdin === "string" && (m.cwd === undefined || m.cwd === null || typeof m.cwd === "string");
8332
10068
  }
8333
10069
  function encodeFrame(value) {
8334
10070
  const body = Buffer.from(JSON.stringify(value), "utf8");
@@ -8337,7 +10073,18 @@ function encodeFrame(value) {
8337
10073
  return Buffer.concat([header, body]);
8338
10074
  }
8339
10075
  function enqueue(task) {
8340
- processingChain = processingChain.then(task).catch(() => {});
10076
+ processingChain = processingChain.then(() => new Promise((settle) => {
10077
+ const timer = setTimeout(() => {
10078
+ hookLogWarn(`worker: a request did not settle within ${TASK_DEADLINE_MS}ms; ` + `exiting so the supervisor can respawn a clean worker`);
10079
+ process.exit(WEDGED_EXIT_CODE);
10080
+ }, TASK_DEADLINE_MS);
10081
+ timer.unref?.();
10082
+ const done = () => {
10083
+ clearTimeout(timer);
10084
+ settle();
10085
+ };
10086
+ task().then(done, done);
10087
+ })).catch(() => {});
8341
10088
  }
8342
10089
  function handleConnection(socket) {
8343
10090
  let recvBuf = Buffer.alloc(0);
@@ -8376,7 +10123,7 @@ function handleConnection(socket) {
8376
10123
  try {
8377
10124
  const result = await evaluateHookEvent(request.hookEvent, request.cli, request.stdin, {
8378
10125
  awaitTelemetryFlush: false,
8379
- fallbackCwd: request.cwd
10126
+ fallbackCwd: request.cwd ?? undefined
8380
10127
  });
8381
10128
  socket.write(encodeFrame({
8382
10129
  type: "hookResult",
@@ -8395,7 +10142,7 @@ function handleConnection(socket) {
8395
10142
  socket.on("error", () => {});
8396
10143
  }
8397
10144
  function startWorkerServer(socketPath) {
8398
- if (existsSync10(socketPath)) {
10145
+ if (existsSync13(socketPath)) {
8399
10146
  try {
8400
10147
  unlinkSync2(socketPath);
8401
10148
  } catch {}
@@ -8404,7 +10151,7 @@ function startWorkerServer(socketPath) {
8404
10151
  server.listen(socketPath);
8405
10152
  return server;
8406
10153
  }
8407
- var MAX_FRAME_LEN, processingChain;
10154
+ var MAX_FRAME_LEN, TASK_DEADLINE_MS = 60000, WEDGED_EXIT_CODE = 75, processingChain;
8408
10155
  var init_worker_server = __esm(() => {
8409
10156
  init_handler();
8410
10157
  init_hook_logger();
@@ -8413,14 +10160,14 @@ var init_worker_server = __esm(() => {
8413
10160
  });
8414
10161
 
8415
10162
  // bin/failproofai-worker.mjs
8416
- import { realpathSync } from "node:fs";
8417
- import { dirname as dirname5, resolve as resolve10 } from "node:path";
10163
+ import { realpathSync as realpathSync2 } from "node:fs";
10164
+ import { dirname as dirname5, resolve as resolve13 } from "node:path";
8418
10165
  import { fileURLToPath } from "node:url";
8419
10166
  if (!process.env.FAILPROOFAI_PACKAGE_ROOT) {
8420
- process.env.FAILPROOFAI_PACKAGE_ROOT = resolve10(dirname5(realpathSync(fileURLToPath(import.meta.url))), "..");
10167
+ process.env.FAILPROOFAI_PACKAGE_ROOT = resolve13(dirname5(realpathSync2(fileURLToPath(import.meta.url))), "..");
8421
10168
  }
8422
10169
  if (!process.env.FAILPROOFAI_DIST_PATH) {
8423
- process.env.FAILPROOFAI_DIST_PATH = resolve10(dirname5(realpathSync(fileURLToPath(import.meta.url))), "..", "dist");
10170
+ process.env.FAILPROOFAI_DIST_PATH = resolve13(dirname5(realpathSync2(fileURLToPath(import.meta.url))), "..", "dist");
8424
10171
  }
8425
10172
  var socketPath = process.env.FAILPROOFAI_WORKER_SOCKET;
8426
10173
  if (!socketPath) {