failproofai 1.0.7 → 1.0.8

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 (268) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/build-manifest.json +3 -3
  3. package/.next/standalone/.next/prerender-manifest.json +3 -3
  4. package/.next/standalone/.next/required-server-files.json +1 -1
  5. package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
  6. package/.next/standalone/.next/server/app/_global-error/page.js +4 -4
  7. package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
  8. package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  9. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  10. package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
  11. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +6 -6
  12. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
  13. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  14. package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  15. package/.next/standalone/.next/server/app/_not-found/page.js +4 -4
  16. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  17. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  18. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  19. package/.next/standalone/.next/server/app/_not-found.rsc +15 -15
  20. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +15 -15
  21. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +14 -14
  22. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  23. package/.next/standalone/.next/server/app/api/audit/invite/route.js.nft.json +1 -1
  24. package/.next/standalone/.next/server/app/api/audit/run/route.js +8 -7
  25. package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -1
  26. package/.next/standalone/.next/server/app/api/audit/status/route.js.nft.json +1 -1
  27. package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -1
  28. package/.next/standalone/.next/server/app/api/auth/login-verify/route.js.nft.json +1 -1
  29. package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
  30. package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -1
  31. package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
  32. package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +2 -2
  33. package/.next/standalone/.next/server/app/audit/page.js +9 -7
  34. package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -1
  35. package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
  36. package/.next/standalone/.next/server/app/index.html +1 -1
  37. package/.next/standalone/.next/server/app/index.rsc +15 -15
  38. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +14 -14
  39. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +15 -15
  40. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  41. package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
  42. package/.next/standalone/.next/server/app/page.js +6 -6
  43. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  44. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  45. package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +14 -14
  46. package/.next/standalone/.next/server/app/policies/page.js +11 -10
  47. package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
  48. package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
  49. package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
  50. package/.next/standalone/.next/server/app/project/[name]/page.js +8 -7
  51. package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
  52. package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
  53. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
  54. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
  55. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js +6 -6
  56. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
  57. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
  58. package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
  59. package/.next/standalone/.next/server/app/projects/page.js +7 -6
  60. package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
  61. package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  62. package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +52 -8
  63. package/.next/standalone/.next/server/app/settings/page.js +12 -7
  64. package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
  65. package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  66. package/.next/standalone/.next/server/chunks/{[externals]__1msfs-h._.js → [externals]__19_pzeq._.js} +1 -1
  67. package/.next/standalone/.next/server/chunks/{[externals]__1_bftcl._.js → [externals]__20kzpkf._.js} +1 -1
  68. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0o07qi9._.js +1 -1
  69. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1ttrwnd._.js +22 -0
  70. package/.next/standalone/.next/server/chunks/_09dz7xv._.js +21 -21
  71. package/.next/standalone/.next/server/chunks/_0tovk6q._.js +1 -1
  72. package/.next/standalone/.next/server/chunks/_0trp3yc._.js +1 -1
  73. package/.next/standalone/.next/server/chunks/_1ek68ln._.js +16 -16
  74. package/.next/standalone/.next/server/chunks/{_1c3k-8x._.js → _1q5i8mb._.js} +2 -2
  75. package/.next/standalone/.next/server/chunks/lib_16xa545._.js +3 -0
  76. package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
  77. package/.next/standalone/.next/server/chunks/src_hooks_1aveq0u._.js +5 -0
  78. package/.next/standalone/.next/server/chunks/src_hooks_1eem5a7._.js +3 -0
  79. package/.next/standalone/.next/server/chunks/src_hooks_custom-hooks-loader_ts_0lnb3n3._.js +4 -2
  80. package/.next/standalone/.next/server/chunks/ssr/[externals]__0ohnuzs._.js +3 -0
  81. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__01bmjsj._.js +3 -0
  82. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__04usis8._.js +4 -0
  83. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__02npjtd._.js → [root-of-the-server]__056wjo4._.js} +3 -3
  84. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__059yza8._.js +3 -0
  85. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__06pflha._.js +3 -0
  86. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0eip4_k._.js +22 -0
  87. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0p-5p8u._.js → [root-of-the-server]__0n0xg95._.js} +3 -3
  88. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0qcb0mg._.js +3 -0
  89. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__013jr2b._.js → [root-of-the-server]__0rwtwpm._.js} +3 -3
  90. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0yrsbd_._.js +3 -0
  91. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0da85px._.js → [root-of-the-server]__11mayhe._.js} +3 -3
  92. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__12e7nhs._.js +3 -0
  93. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__13d-wb6._.js +3 -0
  94. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__13t1zkw._.js +3 -0
  95. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__15578wp._.js +4 -0
  96. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__19evfi8._.js +3 -0
  97. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1dinjii._.js +3 -0
  98. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1m_svbe._.js +4 -0
  99. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0cxe_2_._.js → [root-of-the-server]__1mf3zp6._.js} +3 -3
  100. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0ftmoxc._.js → [root-of-the-server]__1pprgri._.js} +3 -3
  101. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1p2otjt._.js → [root-of-the-server]__1q4p5b8._.js} +3 -3
  102. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1qiz0e4._.js +3 -0
  103. package/.next/standalone/.next/server/chunks/ssr/{_166t73i._.js → _0-vcssj._.js} +1 -1
  104. package/.next/standalone/.next/server/chunks/ssr/_042cgl1._.js +3 -0
  105. package/.next/standalone/.next/server/chunks/ssr/_08x1r5t._.js +1 -1
  106. package/.next/standalone/.next/server/chunks/ssr/_0bqoto4._.js +3 -0
  107. package/.next/standalone/.next/server/chunks/ssr/_0uyu3jf._.js +3 -0
  108. package/.next/standalone/.next/server/chunks/ssr/_13kfn90._.js +23 -0
  109. package/.next/standalone/.next/server/chunks/ssr/{_1es2j7i._.js → _1gb0ifp._.js} +5 -5
  110. package/.next/standalone/.next/server/chunks/ssr/{_1_qswah._.js → _1q46vxx._.js} +2 -2
  111. package/.next/standalone/.next/server/chunks/ssr/_1zopuov._.js +1 -1
  112. package/.next/standalone/.next/server/chunks/ssr/_next-internal_server_app_policies_page_actions_1sp2-yo.js +13 -13
  113. package/.next/standalone/.next/server/chunks/ssr/app_actions_get-scheduled-audit_ts_0ei9sni._.js +3 -0
  114. package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +1 -1
  115. package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
  116. package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +2 -2
  117. package/.next/standalone/.next/server/chunks/ssr/app_settings_02tf1h4._.js +3 -0
  118. package/.next/standalone/.next/server/chunks/ssr/{node_modules_next_dist_0drixxt._.js → node_modules_next_dist_0w6mzq5._.js} +4 -4
  119. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_18_d8l1._.js +151 -0
  120. package/.next/standalone/.next/server/chunks/ssr/src_hooks_0-q0umm._.js +3 -0
  121. package/.next/standalone/.next/server/chunks/ssr/src_hooks_06kzv9d._.js +12 -0
  122. package/.next/standalone/.next/server/chunks/ssr/src_hooks_0g194sy._.js +3 -0
  123. package/.next/standalone/.next/server/chunks/ssr/src_hooks_1cv9_c4._.js +4 -2
  124. package/.next/standalone/.next/server/chunks/ssr/src_hooks_1kx9e0d._.js +3 -0
  125. package/.next/standalone/.next/server/chunks/ssr/src_hooks_effective-reviewers_ts_1h4wtvo._.js +5 -0
  126. package/.next/standalone/.next/server/chunks/ssr/src_hooks_fp-config_ts_04t589g._.js +1 -1
  127. package/.next/standalone/.next/server/chunks/ssr/src_hooks_fp-home_ts_0je3xkv._.js +1 -1
  128. package/.next/standalone/.next/server/chunks/ssr/src_hooks_pack-cli_ts_0t7me65._.js +1 -1
  129. package/.next/standalone/.next/server/chunks/ssr/src_hooks_semantic_pack-policies_ts_0gh_bu_._.js +3 -0
  130. package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
  131. package/.next/standalone/.next/server/pages/404.html +1 -1
  132. package/.next/standalone/.next/server/pages/500.html +1 -1
  133. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  134. package/.next/standalone/.next/server/server-reference-manifest.json +67 -23
  135. package/.next/standalone/.next/static/chunks/06dnzbolj00mc.js +6 -0
  136. package/.next/standalone/.next/static/chunks/0bhidk90e-07f.css +2 -0
  137. package/.next/standalone/.next/static/chunks/{2mdh397ghgnvv.js → 0m-9d6yn9hx4j.js} +1 -1
  138. package/.next/standalone/.next/static/chunks/{0__8a7m868fvf.js → 0wbjy0zo-m7is.js} +1 -1
  139. package/.next/standalone/.next/static/chunks/16f3fa-lx38hk.js +1 -0
  140. package/.next/standalone/.next/static/chunks/{0o6qlkgubtoex.js → 21uv-uusw329x.js} +1 -1
  141. package/.next/standalone/.next/static/chunks/2g2tki08kdhie.js +1 -0
  142. package/.next/standalone/.next/static/chunks/2qdpj67x6ifk_.js +69 -0
  143. package/.next/standalone/.next/static/chunks/2qv4hshejedtx.css +1 -0
  144. package/.next/standalone/.next/static/chunks/3-nbtkhg9y-1j.js +1 -0
  145. package/.next/standalone/.next/static/chunks/355km0ihuqo1p.js +1 -0
  146. package/.next/standalone/.next/static/chunks/{13i7-9is-vhys.js → 3c3qbmosdjl6w.js} +1 -1
  147. package/.next/standalone/PROBE-FOLLOWUP.md +186 -0
  148. package/.next/standalone/app/actions/get-jev-config.ts +604 -0
  149. package/.next/standalone/app/actions/pack-actions.ts +12 -0
  150. package/.next/standalone/app/actions/update-jev-config.ts +569 -0
  151. package/.next/standalone/app/components/jev-notices.tsx +96 -0
  152. package/.next/standalone/app/policies/hooks-client.tsx +14 -3
  153. package/.next/standalone/app/settings/jev-panel.tsx +630 -0
  154. package/.next/standalone/app/settings/page.tsx +20 -1
  155. package/.next/standalone/app/settings/settings-client.tsx +27 -1
  156. package/.next/standalone/app/settings/settings.css +79 -0
  157. package/.next/standalone/fp-cloud-cli/CHANGELOG.md +22 -4
  158. package/.next/standalone/fp-cloud-cli/fp_cli/client.py +14 -1
  159. package/.next/standalone/fp-cloud-cli/fp_cli/commands/keys_cmds.py +17 -3
  160. package/.next/standalone/fp-cloud-cli/fp_cli/commands/policies_cmds.py +3 -0
  161. package/.next/standalone/fp-cloud-cli/fp_cli/permissions.py +22 -0
  162. package/.next/standalone/fp-cloud-cli/fp_cli/policy_check.py +169 -0
  163. package/.next/standalone/fp-cloud-cli/skill/references/commands.md +1 -1
  164. package/.next/standalone/fp-cloud-cli/tests/test_keys_queries.py +65 -0
  165. package/.next/standalone/fp-cloud-cli/tests/test_policy_check.py +61 -0
  166. package/.next/standalone/package.json +10 -10
  167. package/.next/standalone/sdk/python/CHANGELOG.md +7 -0
  168. package/.next/standalone/sdk/python/failproofai_sdk/_version.py +1 -1
  169. package/.next/standalone/sdk/typescript/CHANGELOG.md +18 -1
  170. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/package-lock.json +0 -274
  171. package/.next/standalone/sdk/typescript/scripts/release.mjs +30 -0
  172. package/.next/standalone/server.js +1 -1
  173. package/README.md +3 -2
  174. package/bin/failproofai.mjs +148 -4
  175. package/dist/cli.mjs +18599 -9478
  176. package/dist/index.js +19 -1
  177. package/dist/worker.mjs +10500 -3773
  178. package/package.json +10 -10
  179. package/pi-extension/index.ts +11 -0
  180. package/scripts/build-policy-pack.mjs +53 -2
  181. package/src/audit/features.ts +3 -2
  182. package/src/hooks/builtin-policies.ts +195 -8
  183. package/src/hooks/cloud-connection.ts +190 -1
  184. package/src/hooks/cloud-enrollment-cli.ts +57 -8
  185. package/src/hooks/cloud-introspect.ts +6 -0
  186. package/src/hooks/cloud-managed-policies.ts +22 -0
  187. package/src/hooks/configure-wizard.ts +26 -6
  188. package/src/hooks/custom-hooks-loader.ts +98 -10
  189. package/src/hooks/custom-hooks-registry.ts +45 -1
  190. package/src/hooks/effective-reviewers.ts +243 -0
  191. package/src/hooks/first-run-gate.ts +5 -0
  192. package/src/hooks/flush-cli.ts +35 -8
  193. package/src/hooks/fp-config.ts +266 -1
  194. package/src/hooks/fp-home.ts +23 -0
  195. package/src/hooks/fp-reset.ts +22 -4
  196. package/src/hooks/handler.ts +303 -7
  197. package/src/hooks/hook-activity-store.ts +118 -6
  198. package/src/hooks/hook-telemetry.ts +41 -0
  199. package/src/hooks/jev-activity.ts +385 -0
  200. package/src/hooks/jev-cli.ts +2172 -0
  201. package/src/hooks/jev-cloud-connection.ts +392 -0
  202. package/src/hooks/loader-utils.ts +6 -0
  203. package/src/hooks/manager.ts +45 -7
  204. package/src/hooks/pack-cli.ts +568 -37
  205. package/src/hooks/pack-failclosed.ts +3 -0
  206. package/src/hooks/pack-manifest.ts +489 -7
  207. package/src/hooks/pack-store.ts +194 -11
  208. package/src/hooks/policy-authority.ts +386 -0
  209. package/src/hooks/policy-catalog.ts +206 -0
  210. package/src/hooks/policy-evaluator.ts +963 -796
  211. package/src/hooks/policy-registry.ts +27 -1
  212. package/src/hooks/policy-reviewability.ts +258 -0
  213. package/src/hooks/policy-types.ts +128 -0
  214. package/src/hooks/semantic/combine.ts +581 -0
  215. package/src/hooks/semantic/compile.ts +176 -0
  216. package/src/hooks/semantic/decide.ts +513 -0
  217. package/src/hooks/semantic/envelope.ts +1255 -0
  218. package/src/hooks/semantic/evaluator.ts +556 -0
  219. package/src/hooks/semantic/facts.ts +387 -0
  220. package/src/hooks/semantic/intent.ts +1190 -0
  221. package/src/hooks/semantic/jev-client.ts +1155 -0
  222. package/src/hooks/semantic/jev-config.ts +1142 -0
  223. package/src/hooks/semantic/jev-review.ts +389 -0
  224. package/src/hooks/semantic/jev-stats.ts +289 -0
  225. package/src/hooks/semantic/jev-throttle.ts +427 -0
  226. package/src/hooks/semantic/pack-policies.ts +294 -0
  227. package/src/hooks/semantic/policies.ts +597 -0
  228. package/src/hooks/semantic/precondition-names.ts +60 -0
  229. package/src/hooks/semantic/preconditions.ts +58 -0
  230. package/src/hooks/semantic/redact.ts +2937 -0
  231. package/src/hooks/semantic/session-root.ts +116 -0
  232. package/src/hooks/semantic/types.ts +162 -0
  233. package/src/hooks/semver-precedence.ts +128 -0
  234. package/src/hooks/tui.ts +4 -0
  235. package/src/hooks/types.ts +1 -1
  236. package/src/hooks/worker-server.ts +121 -27
  237. package/src/index.ts +6 -0
  238. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0cuho4x._.js +0 -3
  239. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1_r2rbg._.js +0 -24
  240. package/.next/standalone/.next/server/chunks/src_hooks_0iu54mz._.js +0 -3
  241. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0-_ki57._.js +0 -4
  242. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__01wy8d-._.js +0 -4
  243. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0bd3mje._.js +0 -3
  244. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0cg-bgc._.js +0 -5
  245. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0cpu_mj._.js +0 -3
  246. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0u3w0ll._.js +0 -22
  247. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__17d_ffl._.js +0 -3
  248. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__19d9tgz._.js +0 -5
  249. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1ctpynv._.js +0 -3
  250. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1jiwfsj._.js +0 -3
  251. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1phc187._.js +0 -3
  252. package/.next/standalone/.next/server/chunks/ssr/_06imw3p._.js +0 -5
  253. package/.next/standalone/.next/server/chunks/ssr/_0h_douw._.js +0 -3
  254. package/.next/standalone/.next/server/chunks/ssr/_1-i_gzc._.js +0 -23
  255. package/.next/standalone/.next/server/chunks/ssr/_1u8-lu2._.js +0 -3
  256. package/.next/standalone/.next/server/chunks/ssr/app_settings_settings-client_tsx_20lq-mq._.js +0 -3
  257. package/.next/standalone/.next/server/chunks/ssr/src_hooks_builtin-policies_ts_09j2ndl._.js +0 -3
  258. package/.next/standalone/.next/static/chunks/094xgi4owxaqf.js +0 -1
  259. package/.next/standalone/.next/static/chunks/1rz20_pz828f3.js +0 -6
  260. package/.next/standalone/.next/static/chunks/2k9f4tyv04809.css +0 -1
  261. package/.next/standalone/.next/static/chunks/2klitrtzpaoe0.js +0 -1
  262. package/.next/standalone/.next/static/chunks/2rshywgeqsyzk.css +0 -2
  263. package/.next/standalone/.next/static/chunks/3pzx4chkhko9k.js +0 -1
  264. package/.next/standalone/.next/static/chunks/3rh5o7e16irrm.js +0 -69
  265. package/.next/standalone/.next/static/chunks/43ufqrz8qo3h-.js +0 -1
  266. /package/.next/standalone/.next/static/{PgeWCHmyVbjRznv2VO7KF → 5yKM8NoTOpUI0MoQl8eo5}/_buildManifest.js +0 -0
  267. /package/.next/standalone/.next/static/{PgeWCHmyVbjRznv2VO7KF → 5yKM8NoTOpUI0MoQl8eo5}/_clientMiddlewareManifest.js +0 -0
  268. /package/.next/standalone/.next/static/{PgeWCHmyVbjRznv2VO7KF → 5yKM8NoTOpUI0MoQl8eo5}/_ssgManifest.js +0 -0
@@ -0,0 +1,116 @@
1
+ /**
2
+ * The project a session started in, pinned the first time the session is seen.
3
+ *
4
+ * The hook payload's `cwd` is the agent's LIVE shell directory. Claude Code
5
+ * keeps a `cd` across calls, so a session started in `~/work` that once ran
6
+ * `cd ~/work/api` reports `~/work/api` from then on — and `facts.projectRoot`,
7
+ * derived from that, shrank with it. Every file elsewhere in `~/work` then read
8
+ * as `outside_project_in_home`, and `read-outside-workspace` fired on the
9
+ * project the human opened.
10
+ *
11
+ * Letting the root FOLLOW the `cd` instead would be a bypass: `cd ~/.ssh` in
12
+ * one call and `cat id_rsa` in the next would make `~/.ssh` the project. So the
13
+ * root is fixed at the session's first reviewed call and never moves after.
14
+ * A `cd` can change how a relative path resolves (that is still the live cwd's
15
+ * job, in `extractPaths`) but never what counts as inside the project.
16
+ *
17
+ * Failure is never stricter or looser than before this file existed: no
18
+ * session id, an unreadable store, or a store someone else can write to all
19
+ * fall back to the live cwd's root — exactly the old behaviour. A session whose
20
+ * first reviewed call came after a `cd` pins that later directory; same again.
21
+ */
22
+ import { mkdirSync, readdirSync, readFileSync, statSync, unlinkSync, writeFileSync } from "node:fs";
23
+ import { isAbsolute, resolve } from "node:path";
24
+ import { semanticDir } from "../fp-home";
25
+ import { findProjectRoot } from "./facts";
26
+ import { looseIntentStoreDir } from "./intent";
27
+
28
+ const SESSION_ID_RE = /^[A-Za-z0-9._-]{1,128}$/;
29
+ const ROOT_FILE_RE = /^[A-Za-z0-9._-]{1,128}\.json$/;
30
+ /** Sessions outlive the intent store's six hours; a week covers any real one. */
31
+ export const SESSION_ROOT_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1000;
32
+ const DIR_WRITABLE_BY_OTHERS = 0o022;
33
+
34
+ const rootsDir = (): string => resolve(semanticDir(), "roots");
35
+ const rootFile = (sessionId: string): string => resolve(rootsDir(), `${sessionId}.json`);
36
+
37
+ /** A stored root is only believed when it is a plain absolute path, and never `/`. */
38
+ function validRoot(v: unknown): v is string {
39
+ return typeof v === "string" && isAbsolute(v) && resolve(v) === v && v !== "/";
40
+ }
41
+
42
+ /**
43
+ * Whether the store may be trusted. A directory anyone else can write to lets
44
+ * them swap in a root of their choosing — a wider root is fewer paths outside
45
+ * it — so a loose one is ignored, after the same tightening the intent store
46
+ * applies (`looseIntentStoreDir`).
47
+ */
48
+ function storeIsOurs(): boolean {
49
+ if (process.platform === "win32") return true;
50
+ if (looseIntentStoreDir() !== null) return false;
51
+ try {
52
+ const mode = statSync(rootsDir()).mode & 0o777;
53
+ return (mode & DIR_WRITABLE_BY_OTHERS) === 0;
54
+ } catch {
55
+ return true; // Not there yet: nothing to read out of it.
56
+ }
57
+ }
58
+
59
+ function readPinned(sessionId: string): string | null {
60
+ try {
61
+ const parsed = JSON.parse(readFileSync(rootFile(sessionId), "utf8")) as { root?: unknown };
62
+ return validRoot(parsed?.root) ? parsed.root : null;
63
+ } catch {
64
+ return null;
65
+ }
66
+ }
67
+
68
+ /** Delete root files older than {@link SESSION_ROOT_MAX_AGE_MS}. Best effort. */
69
+ export function pruneSessionRoots(now: number = Date.now()): number {
70
+ let removed = 0;
71
+ try {
72
+ const dir = rootsDir();
73
+ for (const name of readdirSync(dir)) {
74
+ if (!ROOT_FILE_RE.test(name)) continue;
75
+ const path = resolve(dir, name);
76
+ try {
77
+ const st = statSync(path);
78
+ if (st.isFile() && now - st.mtimeMs > SESSION_ROOT_MAX_AGE_MS) {
79
+ unlinkSync(path);
80
+ removed++;
81
+ }
82
+ } catch {
83
+ // Raced with another writer, or already gone.
84
+ }
85
+ }
86
+ } catch {
87
+ // No directory yet.
88
+ }
89
+ return removed;
90
+ }
91
+
92
+ /**
93
+ * The project root to judge this call's paths against: the one pinned for the
94
+ * session, or — on its first reviewed call — the live cwd's root, pinned now.
95
+ * Null only when there is no cwd at all. Never throws.
96
+ */
97
+ export function sessionProjectRoot(sessionId: string | undefined, cwd: string | undefined, now: number = Date.now()): string | null {
98
+ if (!cwd) return null;
99
+ const live = findProjectRoot(cwd);
100
+ if (!sessionId || !SESSION_ID_RE.test(sessionId)) return live;
101
+ try {
102
+ if (!storeIsOurs()) return live;
103
+ const pinned = readPinned(sessionId);
104
+ if (pinned !== null) return pinned;
105
+ if (!validRoot(live)) return live;
106
+ mkdirSync(rootsDir(), { recursive: true, mode: 0o700 });
107
+ // `wx`: the first writer wins. Two calls racing on a new session both
108
+ // computed a root from the same moment; whichever lands is the pin, and
109
+ // the loser's EEXIST just means it answers with the live root this once.
110
+ writeFileSync(rootFile(sessionId), JSON.stringify({ root: live, at: now }), { mode: 0o600, flag: "wx" });
111
+ pruneSessionRoots(now);
112
+ } catch {
113
+ // Unwritable store: the old behaviour, for this call.
114
+ }
115
+ return live;
116
+ }
@@ -0,0 +1,162 @@
1
+ /**
2
+ * Types for the semantic (Jev-backed) evaluator.
3
+ *
4
+ * The regex engine answers "does this string match"; this one asks TypeSafe's
5
+ * Jev a set of typed yes/no questions about the tool call and decides from the
6
+ * probabilities. Everything here is plain data so the decision can be replayed
7
+ * offline from a recorded response — see `decide.ts`.
8
+ */
9
+
10
+ /** Coarse class of a tool, derived deterministically from its canonical name. */
11
+ export type ToolClass = "shell" | "write" | "read" | "network" | "other";
12
+
13
+ /** A single yes/no question sent to Jev (the `noul` primitive). */
14
+ export interface NoulQuestion {
15
+ type: "noul";
16
+ instructions: string;
17
+ criteria?: { true: string; false: string };
18
+ }
19
+
20
+ export interface JevRequest {
21
+ model: string;
22
+ state: Record<string, unknown>;
23
+ questions: Record<string, NoulQuestion>;
24
+ }
25
+
26
+ export interface JevNoulAnswer {
27
+ type?: "noul";
28
+ noul: number;
29
+ }
30
+
31
+ export interface JevResponse {
32
+ model: string;
33
+ answers: Record<string, JevNoulAnswer>;
34
+ usage?: { input_tokens?: number; output_tokens?: number };
35
+ /** Set when the provider did not report which Jev version answered (Cloudflare's unversioned alias). */
36
+ modelUnverified?: boolean;
37
+ }
38
+
39
+ /** A yes/no probe. A policy fires only when every one of its probes holds. */
40
+ export interface Probe {
41
+ id: string;
42
+ instructions: string;
43
+ criteria?: { true: string; false: string };
44
+ }
45
+
46
+ export interface SemanticPolicy {
47
+ /** Short slug; registered as `semantic/<name>` in reasons and logs. */
48
+ name: string;
49
+ /** Past-tense, human-readable description of what was caught. */
50
+ title: string;
51
+ /** Tool classes this policy is asked about. Unknown/MCP tools get every policy. */
52
+ appliesTo: ReadonlyArray<ToolClass>;
53
+ /**
54
+ * `deny` policies block when the evidence is strong and instruct when it is
55
+ * moderate; `instruct` policies only ever warn.
56
+ */
57
+ mode: "deny" | "instruct";
58
+ /**
59
+ * Whether the user's own explicit request may clear this policy. False for
60
+ * the few things a prompt injection most wants to be approved for.
61
+ */
62
+ userCanOverride: boolean;
63
+ /** Every probe must hold for the policy to fire (conjunction). */
64
+ probes: ReadonlyArray<Probe>;
65
+ /** If this holds, the policy does not fire — the documented exceptions. */
66
+ exempt?: Probe;
67
+ /** Deterministic precondition over the facts; when false nothing is asked. */
68
+ precondition?: (facts: Facts) => boolean;
69
+ /** Shown to the agent when the policy fires. */
70
+ guidance: string;
71
+ /** The pack that declared it; absent for the compiled-in set. Attribution only. */
72
+ origin?: { packId: string; packVersion?: string };
73
+ }
74
+
75
+ export interface PathFact {
76
+ asWritten: string;
77
+ resolved: string;
78
+ relation: "inside_project" | "project_root" | "outside_project_in_home" | "home_root" | "system" | "root";
79
+ }
80
+
81
+ /** Deterministic facts computed locally, so Jev never has to count or resolve. */
82
+ export interface Facts {
83
+ toolName: string;
84
+ toolClass: ToolClass;
85
+ /** False for tools no canonical map recognised — MCP tools, skills, etc. */
86
+ toolIsKnown: boolean;
87
+ cwd: string | null;
88
+ projectRoot: string | null;
89
+ currentGitBranch: string | null;
90
+ paths: PathFact[];
91
+ permissionMode: string | null;
92
+ }
93
+
94
+ export interface SemanticInput {
95
+ eventType: string;
96
+ toolName: string;
97
+ toolInput: Record<string, unknown>;
98
+ cwd?: string;
99
+ /**
100
+ * The project root pinned for the session (`session-root.ts`), so a `cd`
101
+ * cannot move what counts as inside the project. Absent: derived from `cwd`.
102
+ */
103
+ projectRoot?: string;
104
+ permissionMode?: string;
105
+ /** What the human typed recently, oldest first. Trusted channel only. */
106
+ userSaid: string[];
107
+ /**
108
+ * The agent's last visible message before the human's latest one — what a
109
+ * reply like "yes" or "do it" refers to. Agent-written, so it may only ever
110
+ * explain a human reply; it is never consent on its own.
111
+ */
112
+ agentLastMessage?: string | null;
113
+ }
114
+
115
+ /**
116
+ * How "did the human ask for this?" is put to Jev.
117
+ *
118
+ * - `v0`: one `user_asked` question per policy, phrased as the policy's harm,
119
+ * plus a global `scope` question. Measured to clear a policy 6 times in
120
+ * 1,332 cases.
121
+ * - `v1`: three task-level questions asked once per call — is this a step
122
+ * toward the human's task, did they ask for this exact operation, does it
123
+ * reach beyond what they asked — judged only against the human's own words
124
+ * with harness-written text removed.
125
+ */
126
+ export type IntentMode = "v0" | "v1";
127
+
128
+ export interface PolicyOutcome {
129
+ policy: string;
130
+ mode: "deny" | "instruct";
131
+ /** The policy's own `userCanOverride`: false is a check no consent can clear. */
132
+ userCanOverride?: boolean;
133
+ /** The pack that declared the check, when one did (`SemanticPolicy.origin`). */
134
+ origin?: { packId: string; packVersion?: string };
135
+ /** min over probe probabilities — one weak probe spoils the evidence. */
136
+ evidence: number;
137
+ exempt: number | null;
138
+ userAsked: number | null;
139
+ targetNamedByUser: boolean;
140
+ /** Fired, and the request also addressed the reviewer — so it was blocked outright. */
141
+ escalatedByInjection: boolean;
142
+ verdict: "deny" | "instruct" | "overridden" | "none";
143
+ /** v1 only: why an override applied, or that a deny was softened to instruct. */
144
+ intent?: "op-requested" | "task-step" | "downgraded-task-step";
145
+ /**
146
+ * Set when a clear was withheld because the shell scan may have missed part
147
+ * of the command (`ScannedCommand.complete` false): what the call touches is
148
+ * not known locally, so no intent answer may clear or soften it.
149
+ */
150
+ targetScanIncomplete?: true;
151
+ }
152
+
153
+ export interface SemanticVerdict {
154
+ decision: "allow" | "deny" | "instruct";
155
+ reason: string | null;
156
+ outcomes: PolicyOutcome[];
157
+ injectionSuspected: number | null;
158
+ /** The `scope` answer: does the request stay within what the user asked? null when not asked. */
159
+ scopeWithinRequest: number | null;
160
+ /** v1 only: set when the call was flagged for reaching beyond the human's task. */
161
+ beyondTask?: boolean;
162
+ }
@@ -0,0 +1,128 @@
1
+ /**
2
+ * Semver PRECEDENCE — ordering two version strings — for the one question a
3
+ * pack manifest asks: is the CLI about to run this pack at least the version
4
+ * the pack says it needs?
5
+ *
6
+ * ## Why this is written out rather than reused
7
+ *
8
+ * Nothing in this repo orders two versions. `daemonVersionSkew()` compares them
9
+ * for EQUALITY, which is the right test there — the CLI and the daemon ship
10
+ * from one commit, so anything but identical is skew — and it yields no
11
+ * ordering at all. There is no semver dependency either: this module runs on
12
+ * the hook path, and the loader's rule is that nothing there may pull in a
13
+ * package.
14
+ *
15
+ * ## Why the obvious implementation is wrong here
16
+ *
17
+ * Splitting on dots and comparing numbers gets the release triple right and the
18
+ * PRERELEASE exactly backwards. This package's version is `1.0.7-beta.0`, and
19
+ * the beta cut from that line is the first build that understands
20
+ * `minCliVersion` at all — so it is the build a pack's minimum is aimed at. On
21
+ * numbers alone `1.0.7-beta.0` satisfies a minimum of `1.0.7`, which reads the
22
+ * beta as the newer build when it is the older one, and the pack installs on a
23
+ * CLI that may be missing the feature the minimum exists to require.
24
+ *
25
+ * So precedence follows semver §11 for real:
26
+ *
27
+ * 1.0.6 < 1.0.7-beta.0 < 1.0.7-beta.1 < 1.0.7 < 1.0.8
28
+ *
29
+ * - the release triple is compared numerically, field by field;
30
+ * - a version WITH a prerelease is lower than the same triple without one;
31
+ * - prerelease identifiers are compared left to right, numeric ones
32
+ * numerically and always below alphanumeric ones, and a longer identifier
33
+ * list wins when every shared identifier is equal;
34
+ * - build metadata (`+2026.09.24`) is ignored, because it carries no precedence.
35
+ *
36
+ * Anything this cannot order is reported as unorderable rather than guessed at.
37
+ * A caller comparing versions to decide whether to REFUSE something needs to
38
+ * know the difference between "older" and "I cannot tell".
39
+ */
40
+
41
+ /** A version decomposed far enough to be ordered. Build metadata is dropped. */
42
+ export interface SemVer {
43
+ major: number;
44
+ minor: number;
45
+ patch: number;
46
+ /** Dot-separated prerelease identifiers, numeric ones as numbers. Empty for a release. */
47
+ prerelease: ReadonlyArray<string | number>;
48
+ }
49
+
50
+ /**
51
+ * Strict semver, and strict on purpose. `v1.0.0`, `1.0`, `01.2.3` and
52
+ * `1.0.7-beta.0.` are all things people write and none of them has one
53
+ * unambiguous ordering, so they are refused rather than normalised — a
54
+ * `minCliVersion` nobody can order is a requirement nobody can check.
55
+ */
56
+ const SEMVER_RE =
57
+ /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*)(?:\.(?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*))*))?(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?$/;
58
+
59
+ const NUMERIC_ID = /^(?:0|[1-9]\d*)$/;
60
+
61
+ /** Decompose a version, or `null` when it is not one this can order. */
62
+ export function parseSemver(value: unknown): SemVer | null {
63
+ if (typeof value !== "string") return null;
64
+ const m = SEMVER_RE.exec(value);
65
+ if (!m) return null;
66
+ return {
67
+ major: Number(m[1]),
68
+ minor: Number(m[2]),
69
+ patch: Number(m[3]),
70
+ prerelease: m[4] === undefined ? [] : m[4].split(".").map((id) => (NUMERIC_ID.test(id) ? Number(id) : id)),
71
+ };
72
+ }
73
+
74
+ const cmp = (a: number, b: number): number => (a < b ? -1 : a > b ? 1 : 0);
75
+
76
+ /**
77
+ * Compare two prerelease identifier lists. An EMPTY list is a release, and a
78
+ * release outranks every prerelease of the same triple — the rule the naive
79
+ * implementation loses, and the one that decides this release's own case.
80
+ */
81
+ function comparePrerelease(a: ReadonlyArray<string | number>, b: ReadonlyArray<string | number>): number {
82
+ if (a.length === 0 && b.length === 0) return 0;
83
+ if (a.length === 0) return 1;
84
+ if (b.length === 0) return -1;
85
+ for (let i = 0; i < Math.min(a.length, b.length); i++) {
86
+ const x = a[i];
87
+ const y = b[i];
88
+ if (x === y) continue;
89
+ const xNum = typeof x === "number";
90
+ const yNum = typeof y === "number";
91
+ // "Numeric identifiers always have lower precedence than non-numeric
92
+ // ones" (semver §11.4.3): `1.0.0-1` is below `1.0.0-alpha`, so an `rc.1`
93
+ // line and a `1` line never interleave by accident.
94
+ if (xNum !== yNum) return xNum ? -1 : 1;
95
+ if (xNum && yNum) return cmp(x as number, y as number);
96
+ return (x as string) < (y as string) ? -1 : 1;
97
+ }
98
+ // Every shared identifier is equal, so the longer list is the later build:
99
+ // `1.0.0-beta` < `1.0.0-beta.1`.
100
+ return cmp(a.length, b.length);
101
+ }
102
+
103
+ /** `-1`, `0` or `1` by semver precedence. */
104
+ export function compareSemver(a: SemVer, b: SemVer): number {
105
+ return cmp(a.major, b.major) || cmp(a.minor, b.minor) || cmp(a.patch, b.patch) || comparePrerelease(a.prerelease, b.prerelease);
106
+ }
107
+
108
+ /**
109
+ * `-1` / `0` / `1` for two version STRINGS, or `null` when either one cannot be
110
+ * ordered. Null is deliberately not 0: a caller that treats "unorderable" as
111
+ * "equal" silently accepts the requirement it could not check.
112
+ *
113
+ * There is deliberately NO `meetsMinimum(current, minimum): boolean | null` here.
114
+ * It existed, and it collapsed two situations that need opposite treatment into
115
+ * one value: an ABSENT minimum (every pack published before today has none, so it
116
+ * must satisfy) and a MALFORMED one. A call site reading `=== false` would then
117
+ * ignore a typo'd requirement, and one reading `!== true` would refuse every
118
+ * pre-existing pack — and on an `enforce` pack that means denying every tool call
119
+ * the pack covers. Neither mistake shows up until a user hits it, so the decision
120
+ * is encoded once, where the field lives: `checkPackMinCliVersion` in
121
+ * `pack-manifest.ts`.
122
+ */
123
+ export function compareVersions(a: unknown, b: unknown): number | null {
124
+ const left = parseSemver(a);
125
+ const right = parseSemver(b);
126
+ if (!left || !right) return null;
127
+ return compareSemver(left, right);
128
+ }
package/src/hooks/tui.ts CHANGED
@@ -96,6 +96,10 @@ export interface MultiSelectOptions<T> {
96
96
 
97
97
  const ESC = "\x1B";
98
98
 
99
+ /** How every "the key was on argv" warning opens, whichever command took it (`jev setup --token`, `config --token`). */
100
+ export const TOKEN_ON_ARGV =
101
+ "--token was on the command line: your shell history has it, and while this command ran any process of yours could read it from the process list.";
102
+
99
103
  // ── glyphs ────────────────────────────────────────────────────────────────
100
104
  // Exported so the other branded prompts (install-prompt.ts) share the exact
101
105
  // same set instead of hand-syncing copies.
@@ -1059,7 +1059,7 @@ export type HookEventType = (typeof HOOK_EVENT_TYPES)[number];
1059
1059
  *
1060
1060
  * It stays in `HOOK_EVENT_TYPES` because that list is the canonical set a
1061
1061
  * policy may subscribe to; this one governs what we write into settings.json.
1062
- * No builtin matches it (all 39 match only PreToolUse / PostToolUse /
1062
+ * No builtin matches it (all 40 match only PreToolUse / PostToolUse /
1063
1063
  * PermissionRequest / Stop), so nothing is lost by not registering.
1064
1064
  */
1065
1065
  export const CLAUDE_INSTALL_EVENT_TYPES = HOOK_EVENT_TYPES.filter(
@@ -17,7 +17,10 @@
17
17
  * evaluations could have request B's `clearPolicies()` wipe request A's
18
18
  * in-flight registration. Serializing keeps the existing registry code
19
19
  * correct with zero changes; a worker_threads/process pool is a valid
20
- * future enhancement if this becomes a real throughput bottleneck.
20
+ * future enhancement if this becomes a real throughput bottleneck. The one
21
+ * exception is the network wait of a two-tier (Jev) review, which happens
22
+ * after the registry is no longer read and so does not hold the queue (see
23
+ * `enqueue`).
21
24
  */
22
25
  import { createConnection, createServer, type Server, type Socket } from "node:net";
23
26
  import { existsSync, unlinkSync } from "node:fs";
@@ -74,7 +77,8 @@ const TASK_DEADLINE_MS = 60_000;
74
77
 
75
78
  /**
76
79
  * Serializes every request across every connection through one chain, so
77
- * `evaluateHookEvent` calls never overlap. `.catch()` on each link keeps the
80
+ * `evaluateHookEvent` calls never overlap while reading the registry (see
81
+ * `release` below). `.catch()` on each link keeps the
78
82
  * chain alive even if a handler throws unexpectedly — one bad request must
79
83
  * never wedge every request queued behind it.
80
84
  *
@@ -97,37 +101,115 @@ const TASK_DEADLINE_MS = 60_000;
97
101
  * worker whose `try_wait()` reports it gone), which costs one cold start and
98
102
  * denies the in-flight requests — the same fail-closed outcome they were headed
99
103
  * for anyway, but recovered on the next call instead of never.
104
+ *
105
+ * A task may hand its place in the chain back early by calling `release`:
106
+ * the next request starts while the task finishes on its own. Only the
107
+ * two-tier (Jev) path does, at the point it stops reading the registry and
108
+ * starts waiting on Jev's network answer (`EvaluateHookEventOptions.
109
+ * releaseRegistry`). Without that, every hook on the machine — PostToolUse,
110
+ * UserPromptSubmit, other agents' calls — would queue behind each gated call's
111
+ * round trip, and a slow or unreachable provider would push the calls at the
112
+ * back of the queue past the client's 30 s budget into fail-closed denies.
113
+ * A released task no longer holds the registry, so the deadline it was running
114
+ * under — the one that protects the QUEUE — has done its job. It gets a fresh
115
+ * one of its own instead of none: it is still running, its connection's later
116
+ * replies still queue behind it (see `handleConnection`), and a task that has
117
+ * not settled a minute after handing the queue back is wedged on something
118
+ * that is not going to finish. Its Jev wait is bounded by the configured
119
+ * timeout, so nothing on the intended path comes close.
120
+ *
121
+ * Released tasks therefore run concurrently with each other and with the
122
+ * queue: two gated calls can be waiting on Jev at once (T5's throttle shares
123
+ * one cache and token bucket across them, and does not merge identical
124
+ * in-flight requests). Replies on one connection still leave in request order
125
+ * (see `handleConnection`).
100
126
  */
101
127
  const WEDGED_EXIT_CODE = 75;
128
+ /**
129
+ * A released task's own deadline, counted from the moment it handed the queue
130
+ * back. Its Jev wait is bounded by the configured timeout (at most 10 s, plus
131
+ * the review's own backstop), so only a task stuck on something else ever
132
+ * reaches this.
133
+ */
134
+ const RELEASED_TASK_DEADLINE_MS = 60_000;
135
+
136
+ /** What a wedged task costs: this worker, so the supervisor respawns a clean one. */
137
+ function exitWedged(ms: number, released: boolean): void {
138
+ hookLogWarn(
139
+ `worker: a ${released ? "released " : ""}request did not settle within ${ms}ms; ` +
140
+ `exiting so the supervisor can respawn a clean worker`,
141
+ );
142
+ process.exit(WEDGED_EXIT_CODE);
143
+ }
144
+
145
+ export interface QueuedTaskOptions {
146
+ taskMs?: number;
147
+ releasedMs?: number;
148
+ onWedged?: (ms: number, released: boolean) => void;
149
+ }
150
+
151
+ /**
152
+ * Runs one queued task under a wedge deadline, calling `settle` when the next
153
+ * task may start — because this one finished, or because it handed its place
154
+ * back early with the `release` it is given. A released task keeps running
155
+ * under a deadline of its own (see `RELEASED_TASK_DEADLINE_MS`); dropping the
156
+ * deadline at that point would have made every wedge past the release
157
+ * invisible.
158
+ *
159
+ * Exported for the deadlines' own tests: they are a minute long and expiry
160
+ * exits the process, so a test passes its own values and its own `onWedged`.
161
+ */
162
+ export function runQueuedTask(task: (release: () => void) => Promise<void>, settle: () => void, opts: QueuedTaskOptions = {}): void {
163
+ const onWedged = opts.onWedged ?? exitWedged;
164
+ let timer: ReturnType<typeof setTimeout> | undefined;
165
+ let finished = false;
166
+ let started = false;
167
+ const arm = (ms: number, released: boolean) => {
168
+ clearTimeout(timer);
169
+ timer = setTimeout(() => onWedged(ms, released), ms);
170
+ // Never let the deadline itself hold the event loop open.
171
+ timer.unref?.();
172
+ };
173
+ /** The next task starts once, whether this one released first or just finished. */
174
+ const startNext = () => {
175
+ if (started) return;
176
+ started = true;
177
+ settle();
178
+ };
179
+ const finish = () => {
180
+ finished = true;
181
+ clearTimeout(timer);
182
+ startNext();
183
+ };
184
+ const release = () => {
185
+ if (finished) return;
186
+ arm(opts.releasedMs ?? RELEASED_TASK_DEADLINE_MS, true);
187
+ startNext();
188
+ };
189
+ arm(opts.taskMs ?? TASK_DEADLINE_MS, false);
190
+ void task(release).then(finish, finish);
191
+ }
102
192
 
103
193
  let processingChain: Promise<void> = Promise.resolve();
104
- function enqueue(task: () => Promise<void>): void {
105
- processingChain = processingChain
106
- .then(
107
- () =>
108
- new Promise<void>((settle) => {
109
- const timer = setTimeout(() => {
110
- hookLogWarn(
111
- `worker: a request did not settle within ${TASK_DEADLINE_MS}ms; ` +
112
- `exiting so the supervisor can respawn a clean worker`,
113
- );
114
- process.exit(WEDGED_EXIT_CODE);
115
- }, TASK_DEADLINE_MS);
116
- // Never let the deadline itself hold the event loop open.
117
- timer.unref?.();
118
- const done = () => {
119
- clearTimeout(timer);
120
- settle();
121
- };
122
- void task().then(done, done);
123
- }),
124
- )
125
- .catch(() => {});
194
+ function enqueue(task: (release: () => void) => Promise<void>): void {
195
+ processingChain = processingChain.then(() => new Promise<void>((settle) => runQueuedTask(task, settle))).catch(() => {});
126
196
  }
127
197
 
128
198
  function handleConnection(socket: Socket, shutdown: () => void): void {
129
199
  let recvBuf = Buffer.alloc(0);
130
200
  let declaredLen: number | null = null;
201
+ /**
202
+ * Hook replies leave in the order their requests arrived on this
203
+ * connection. The wire carries no request id, so a client that pipelines
204
+ * several requests on one connection can match replies only by order — which
205
+ * the strictly serialized queue used to guarantee by itself. A two-tier task
206
+ * that releases the queue early (see `enqueue`) can finish after a request
207
+ * that arrived behind it, so each reply waits for every earlier one on its
208
+ * connection. The Rust supervisor opens one connection per request, so today
209
+ * this never delays anything; it keeps the ordering true for any client that
210
+ * does pipeline.
211
+ */
212
+ let replies: Promise<void> = Promise.resolve();
131
213
 
132
214
  socket.on("data", (chunk: Buffer) => {
133
215
  recvBuf = Buffer.concat([recvBuf, chunk]);
@@ -178,15 +260,27 @@ function handleConnection(socket: Socket, shutdown: () => void): void {
178
260
  }
179
261
  const request = message;
180
262
 
181
- enqueue(async () => {
263
+ let deliver!: (frame: Buffer) => void;
264
+ const reply = new Promise<Buffer>((resolveReply) => {
265
+ deliver = resolveReply;
266
+ });
267
+ replies = replies
268
+ .then(() => reply)
269
+ .then((frame) => {
270
+ socket.write(frame);
271
+ })
272
+ .catch(() => {});
273
+
274
+ enqueue(async (release) => {
182
275
  try {
183
276
  const result = await evaluateHookEvent(request.hookEvent, request.cli, request.stdin, {
184
277
  awaitTelemetryFlush: false,
185
278
  // Normalised here so no consumer has to know the wire spells
186
279
  // "absent" as null.
187
280
  fallbackCwd: request.cwd ?? undefined,
281
+ releaseRegistry: release,
188
282
  });
189
- socket.write(
283
+ deliver(
190
284
  encodeFrame({
191
285
  type: "hookResult",
192
286
  exitCode: result.exitCode,
@@ -198,7 +292,7 @@ function handleConnection(socket: Socket, shutdown: () => void): void {
198
292
  } catch (err) {
199
293
  const msg = err instanceof Error ? err.message : String(err);
200
294
  hookLogWarn(`worker: evaluateHookEvent threw: ${msg}`);
201
- socket.write(encodeFrame({ type: "error", message: msg }));
295
+ deliver(encodeFrame({ type: "error", message: msg }));
202
296
  }
203
297
  });
204
298
  }
package/src/index.ts CHANGED
@@ -6,7 +6,9 @@
6
6
  */
7
7
  export {
8
8
  customPolicies,
9
+ semanticPolicies,
9
10
  getCustomHooks,
11
+ getSemanticRegistrations,
10
12
  clearCustomHooks,
11
13
  } from "./hooks/custom-hooks-registry";
12
14
  export { allow, deny, instruct } from "./hooks/policy-helpers";
@@ -16,4 +18,8 @@ export type {
16
18
  CustomHook,
17
19
  PolicyDecision,
18
20
  PolicyFunction,
21
+ PolicyAuthority,
22
+ SemanticPolicyDeclaration,
23
+ SemanticProbeDeclaration,
24
+ SemanticToolClass,
19
25
  } from "./hooks/policy-types";
@@ -1,3 +0,0 @@
1
- module.exports=[24868,(e,t,r)=>{t.exports=e.x("fs/promises",()=>require("fs/promises"))},12714,(e,t,r)=>{t.exports=e.x("node:fs/promises",()=>require("node:fs/promises"))},46786,(e,t,r)=>{t.exports=e.x("os",()=>require("os"))},14747,(e,t,r)=>{t.exports=e.x("path",()=>require("path"))},71809,e=>{"use strict";async function t(e,t){let r=Array(e.length),i=0;async function n(){for(;i<e.length;){let t=i++;try{r[t]={status:"fulfilled",value:await e[t]()}}catch(e){r[t]={status:"rejected",reason:e}}}}let a=Array.from({length:Math.min(t,e.length)},()=>n());return await Promise.all(a),r}e.s(["batchAll",0,t])},28557,e=>{"use strict";e.s(["formatDate",0,function(e){return new Intl.DateTimeFormat("en-US",{month:"short",day:"numeric",year:"numeric",hour:"numeric",minute:"2-digit",hour12:!0}).format(e)}])},54214,67405,e=>{"use strict";var t=e.i(24868),r=e.i(14747),i=e.i(81580),n=e.i(56936);async function a(e,i,n,a){let o=`agent-${a}.jsonl`;for(let a of[(0,r.join)(e,i,o),(0,r.join)(e,i,n,o),(0,r.join)(e,i,n,"subagents",o)])if(!(0,r.relative)(e,a).startsWith(".."))try{return await (0,t.access)(a),a}catch(e){if("ENOENT"===e.code)continue;break}return null}var o=e.i(83534),s=e.i(71809),l=e.i(28557);function u(e){if(e<1e3)return`${e}ms`;let t=Math.round(e/100);if(t<600)return`${(t/10).toFixed(1)}s`;let r=Math.round(e/1e3);if(r<3600){let e=Math.floor(r/60);return`${e}m ${r%60}s`}let i=Math.round(e/6e4),n=Math.floor(i/60);return`${n}h ${i%60}m`}function c(e){let t=(0,l.formatDate)(e),r=e.getMilliseconds().toString().padStart(3,"0");return`${t}.${r}`}function f(e,t,r,i){return{_source:i,uuid:e.uuid||"",parentUuid:e.parentUuid??null,timestamp:t,timestampMs:r.getTime(),timestampFormatted:c(r)}}async function m(e,t){let r=e.split("\n").filter(e=>""!==e.trim()),i=new Map,n=[],a=[],o=new Set,s=!1;for(let e=0;e<r.length;e++){let l;e>0&&e%200==0&&await new Promise(e=>setImmediate(e));let u=r[e];try{l=JSON.parse(u)}catch{continue}let c={...l,_source:t};a.push(c);let m=l.type,d=l.timestamp;if(!d)continue;let p=new Date(d),g=p.getTime();if("user"===m){let e=l.message;if(Array.isArray(e?.content)){let t=e.content;if(t.some(e=>"tool_result"===e.type)){let e=l.toolUseResult,r="string"==typeof e?.agentId?e.agentId:void 0;for(let e of(r&&/^[a-f0-9]+$/.test(r)&&o.add(r),t)){if("tool_result"!==e.type)continue;let t=e.tool_use_id;if(!t)continue;let{text:n,images:a}=function(e){let t=e.content;if("string"==typeof t)return{text:t};if(Array.isArray(t)){let e=t.filter(e=>"text"===e.type).map(e=>e.text),r=t.filter(e=>"image"===e.type).map(e=>{let t=e.source;return{base64:t.data,mediaType:t.media_type}}).filter(e=>e.base64&&e.mediaType);return{text:e.length>0?e.join("\n"):void 0,images:r.length>0?r:void 0}}return{}}(e);i.set(t,{timestamp:d,timestampMs:g,content:n,images:a,agentId:r})}continue}}let r="string"==typeof e?.content?e.content:"";n.push({type:"user",...f(l,d,p,t),message:{role:"user",content:r}});continue}if("assistant"===m){let e=l.message,r=[];if(Array.isArray(e?.content)&&(r=e.content.filter(e=>["text","tool_use","thinking"].includes(e.type)).map(e=>{if("text"===e.type)return{type:"text",text:e.text};if("tool_use"===e.type){let t=e.input;return{type:"tool_use",id:e.id,name:e.name,input:e.input??{},..."Task"===e.name&&t?{subagentType:t.subagent_type,subagentDescription:t.description}:{}}}return{type:"thinking",thinking:e.thinking,signature:e.signature}})),0===r.length)continue;n.push({type:"assistant",...f(l,d,p,t),message:{role:"assistant",content:r,model:e?.model}});continue}if("file-history-snapshot"===m||"progress"===m||"system"===m){n.push({type:m,...f(l,d,p,t),raw:{...l}});continue}if("queue-operation"===m){let e=s?"Session Resumed":"Session Started";s=!0,n.push({type:"queue-operation",...f(l,d,p,t),label:e});continue}}let l=0;for(let e of n)if("assistant"===e.type)for(let t of(++l%200==0&&await new Promise(e=>setImmediate(e)),e.message.content)){if("tool_use"!==t.type)continue;let r=i.get(t.id);if(!r)continue;let n=new Date(r.timestamp),a=Math.max(0,r.timestampMs-e.timestampMs);t.result={timestamp:r.timestamp,timestampFormatted:c(n),content:r.content,images:r.images,durationMs:a,durationFormatted:u(a)},r.agentId&&(t.subagentId=r.agentId)}return n.length>500&&await new Promise(e=>setImmediate(e)),n.sort((e,t)=>e.timestampMs-t.timestampMs),{entries:n,rawLines:a,subagentIds:Array.from(o)}}async function d(e,t="session"){return(await m(e,t)).entries}async function p(e,o){let l=(0,n.resolveProjectPath)(e),u=(0,i.getClaudeProjectsPath)(),c=(0,r.join)(l,`${o}.jsonl`),f=await (0,t.readFile)(c,"utf-8"),{entries:d,rawLines:p,subagentIds:g}=await m(f,"session");if(0===g.length)return{entries:d,rawLines:p,subagentIds:[]};let h=await (0,s.batchAll)(g.map(r=>async()=>{let i=`agent-${r}`,n=await a(u,e,o,r);if(!n)return null;let s=await (0,t.readFile)(n,"utf-8"),{entries:l,rawLines:c}=await m(s,i);return{entries:l,rawLines:c}}),4),y=[...d],w=[...p];for(let e of h)"fulfilled"===e.status&&e.value&&(y.push(...e.value.entries),w.push(...e.value.rawLines));return y.length>500&&await new Promise(e=>setImmediate(e)),y.sort((e,t)=>e.timestampMs-t.timestampMs),{entries:y,rawLines:w,subagentIds:g}}e.s(["formatDuration",0,u],67405),(0,o.runtimeCache)((e,t)=>p(e,t),60,{maxSize:50}),e.s(["baseEntry",0,f,"formatTimestamp",0,c,"parseLogContent",0,d,"parseRawLines",0,function(e,t){return e.split("\n").filter(e=>""!==e.trim()).flatMap(e=>{try{let r=JSON.parse(e);return void 0!==t&&(r._source=t),[r]}catch{return[]}})}],54214)},40911,e=>{"use strict";let t={info:0,warn:1,error:2};function r(e){return t[e]>=t.warn}function i(e){return`[failproofai${new Date().toISOString()}] ${e}`}e.s(["logActivity",0,function(e,t,n){if(!r("info"))return;let a=[`user=${e}`,`action=${t}`];n&&a.push(n),console.log(i("ACTIVITY"),a.join(" "))},"logError",0,function(e,t){void 0!==t?console.error(i("ERROR"),e,t):console.error(i("ERROR"),e)},"logWarn",0,function(e,t){r("warn")&&(void 0!==t?console.warn(i("WARN"),e,t):console.warn(i("WARN"),e))}])},81580,e=>{"use strict";var t=e.i(46786),r=e.i(14747);e.s(["decodeFolderName",0,function(e){return/^[A-Za-z]--/.test(e)?e[0]+":/"+e.slice(3).replace(/-/g,"/"):e.replace(/-/g,"/")},"encodeFolderName",0,function(e){let t=/^([A-Za-z]):[\\/](.*)$/.exec(e);return t?t[1]+"--"+t[2].replace(/[\\/]/g,"-"):e.replace(/[\\/]/g,"-")},"getClaudeProjectsPath",0,function(){let e=process.env.CLAUDE_PROJECTS_PATH;return e||(0,r.join)((0,t.homedir)(),".claude","projects")}])},56936,e=>{"use strict";var t=e.i(12714),r=e.i(50227),i=e.i(81580),n=e.i(83534),a=e.i(71809),o=e.i(40911),s=e.i(28557);let l=/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/;async function u(e,r){try{return(await (0,t.stat)(e)).mtime}catch(e){return(0,o.logWarn)(`Failed to stat ${r}:`,e),new Date(0)}}async function c(e){try{if(!(await (0,t.stat)(e)).isDirectory())return null;return await (0,t.readdir)(e,{withFileTypes:!0})}catch{return null}}async function f(){try{let e=(0,i.getClaudeProjectsPath)(),t=await c(e);if(!t)return[];let n=(await (0,a.batchAll)(t.filter(e=>e.isDirectory()).map(t=>async()=>{let i=(0,r.join)(e,t.name),n=await u(i,t.name);return{name:t.name,path:i,isDirectory:!0,lastModified:n,lastModifiedFormatted:(0,s.formatDate)(n),cli:["claude"]}}),16)).filter(e=>"fulfilled"===e.status).map(e=>e.value);return n.sort((e,t)=>t.lastModified.getTime()-e.lastModified.getTime()),n}catch(e){return(0,o.logError)("Error reading Claude project folders:",e),[]}}async function m(){let[{getCodexProjects:t},{getCopilotProjects:r},{getCursorProjects:i},{getOpenCodeProjects:n},{getPiProjects:a},{getHermesProjects:s},{getOpenClawProjects:l},{getFactoryProjects:u},{getDevinProjects:c},{getAntigravityProjects:m},{getGooseProjects:d}]=await Promise.all([e.A(37352),e.A(5807),e.A(97452),e.A(82978),e.A(45093),e.A(67347),e.A(38978),e.A(62998),e.A(52400),e.A(91301),e.A(31854)]),[p,g,h,y,w,E,j,M,A,v,x,P]=await Promise.all([f(),t().catch(e=>((0,o.logError)("Error reading Codex projects:",e),[])),r().catch(e=>((0,o.logError)("Error reading Copilot projects:",e),[])),i().catch(e=>((0,o.logError)("Error reading Cursor projects:",e),[])),n().catch(e=>((0,o.logError)("Error reading OpenCode projects:",e),[])),a().catch(e=>((0,o.logError)("Error reading Pi projects:",e),[])),s().catch(e=>((0,o.logError)("Error reading Hermes projects:",e),[])),l().catch(e=>((0,o.logError)("Error reading OpenClaw projects:",e),[])),u().catch(e=>((0,o.logError)("Error reading Factory projects:",e),[])),c().catch(e=>((0,o.logError)("Error reading Devin projects:",e),[])),m().catch(e=>((0,o.logError)("Error reading Antigravity projects:",e),[])),d().catch(e=>((0,o.logError)("Error reading Goose projects:",e),[]))]);return function(...e){let t=new Map;for(let r of e)for(let e of r){let r=t.get(e.name);if(!r){t.set(e.name,{...e,cli:[...e.cli]});continue}let i=[...r.cli];for(let t of e.cli)i.includes(t)||i.push(t);let n=e.lastModified.getTime()>r.lastModified.getTime()?e:r;t.set(e.name,{...r,cli:i,lastModified:n.lastModified,lastModifiedFormatted:n.lastModifiedFormatted,sessionCount:void 0===r.sessionCount&&void 0===e.sessionCount?void 0:(r.sessionCount??0)+(e.sessionCount??0)})}let r=Array.from(t.values());return r.sort((e,t)=>t.lastModified.getTime()-e.lastModified.getTime()),r}(p,g,h,y,w,E,j,M,A,v,x,P)}function d(e){if(!e)throw RangeError("Empty project name");if(/^[/\\]/.test(e))throw RangeError("Absolute project name");let t=(0,r.resolve)((0,i.getClaudeProjectsPath)()),n=(0,r.resolve)((0,r.join)(t,e));if(!n.startsWith(t+r.sep))throw RangeError("Project path escapes root");return n}function p(e){let t=e.match(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/i);return t?t[0]:void 0}async function g(e){try{let t=await c(e);if(!t)return[];let i=t.filter(e=>e.isFile()&&e.name.endsWith(".jsonl")&&p(e.name)),n=(await (0,a.batchAll)(i.map(t=>async()=>{let i=(0,r.join)(e,t.name),n=await u(i,t.name);return{name:t.name,path:i,lastModified:n,lastModifiedFormatted:(0,s.formatDate)(n),sessionId:p(t.name),cli:"claude"}}),16)).filter(e=>"fulfilled"===e.status).map(e=>e.value);return n.sort((e,t)=>t.lastModified.getTime()-e.lastModified.getTime()),n}catch(e){return(0,o.logError)("Error reading session files:",e),[]}}(0,n.runtimeCache)(m,30),(0,n.runtimeCache)(e=>g(e),30),e.s(["UUID_RE",0,l,"resolveProjectPath",0,d,"resolveSessionFilePath",0,function(e,t){if(!l.test(t))throw RangeError("Invalid session ID");let i=d(e);return(0,r.join)(i,`${t}.jsonl`)}])},83534,e=>{"use strict";e.s(["runtimeCache",0,function(e,t,r){let i=new Map,n=new Map,a=r?.maxSize;return async(...r)=>{let o=JSON.stringify(r),s=i.get(o);if(s&&Date.now()<s.expiry)return s.data;let l=n.get(o);if(l)return l;let u=e(...r).then(e=>{if(n.delete(o),a&&i.size>=a){let e=i.keys().next().value;i.delete(e)}return i.set(o,{data:e,expiry:Date.now()+1e3*t}),e},e=>{throw n.delete(o),e});return n.set(o,u),u}}])}];
2
-
3
- //# sourceMappingURL=%5Broot-of-the-server%5D__0cuho4x._.js.map