failproofai 1.0.7-beta.1 → 1.0.7-beta.2

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 (324) 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.nft.json +1 -1
  7. package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  8. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  9. package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
  10. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +6 -6
  11. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
  12. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  13. package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  14. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  15. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  16. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  17. package/.next/standalone/.next/server/app/_not-found.rsc +15 -15
  18. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +15 -15
  19. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +14 -14
  20. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  21. package/.next/standalone/.next/server/app/api/audit/invite/route.js.nft.json +1 -1
  22. package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -1
  23. package/.next/standalone/.next/server/app/api/audit/status/route.js.nft.json +1 -1
  24. package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -1
  25. package/.next/standalone/.next/server/app/api/auth/login-verify/route.js.nft.json +1 -1
  26. package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
  27. package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -1
  28. package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
  29. package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +2 -2
  30. package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -1
  31. package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
  32. package/.next/standalone/.next/server/app/index.html +1 -1
  33. package/.next/standalone/.next/server/app/index.rsc +15 -15
  34. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +14 -14
  35. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +15 -15
  36. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  37. package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
  38. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  39. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  40. package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +14 -14
  41. package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
  42. package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
  43. package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
  44. package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
  45. package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
  46. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
  47. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
  48. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
  49. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
  50. package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
  51. package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
  52. package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  53. package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +7 -7
  54. package/.next/standalone/.next/server/app/settings/page.js +2 -2
  55. package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
  56. package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  57. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0l3yhx4._.js +2 -2
  58. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0o07qi9._.js +1 -1
  59. package/.next/standalone/.next/server/chunks/_0tovk6q._.js +1 -1
  60. package/.next/standalone/.next/server/chunks/_0trp3yc._.js +1 -1
  61. package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_09z9-p7._.js +1 -1
  62. package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
  63. package/.next/standalone/.next/server/chunks/src_hooks_18qtd42._.js +1 -1
  64. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__04usis8._.js +2 -2
  65. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__056wjo4._.js +2 -2
  66. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0yxwl6j._.js → [root-of-the-server]__0l44ual._.js} +2 -2
  67. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0n0xg95._.js +2 -2
  68. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0rwtwpm._.js +2 -2
  69. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0s_yomn._.js +2 -2
  70. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__11mayhe._.js +2 -2
  71. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1pprgri._.js +2 -2
  72. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1q4p5b8._.js +2 -2
  73. package/.next/standalone/.next/server/chunks/ssr/_042cgl1._.js +1 -1
  74. package/.next/standalone/.next/server/chunks/ssr/_08x1r5t._.js +1 -1
  75. package/.next/standalone/.next/server/chunks/ssr/_0bqoto4._.js +1 -1
  76. package/.next/standalone/.next/server/chunks/ssr/{_214wgrp._.js → _1mel6y1._.js} +2 -2
  77. package/.next/standalone/.next/server/chunks/ssr/{_0bn2oo8._.js → _1v-jvrv._.js} +1 -1
  78. package/.next/standalone/.next/server/chunks/ssr/_1zopuov._.js +1 -1
  79. package/.next/standalone/.next/server/chunks/ssr/_next-internal_server_app_policies_page_actions_1sp2-yo.js +2 -2
  80. package/.next/standalone/.next/server/chunks/ssr/app_actions_get-scheduled-audit_ts_0ei9sni._.js +1 -1
  81. package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +1 -1
  82. package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
  83. package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +1 -1
  84. package/.next/standalone/.next/server/chunks/ssr/app_settings_02tf1h4._.js +1 -1
  85. package/.next/standalone/.next/server/chunks/ssr/src_hooks_15t8kqj._.js +1 -1
  86. package/.next/standalone/.next/server/chunks/ssr/src_hooks_1fm2w5z._.js +1 -1
  87. package/.next/standalone/.next/server/chunks/ssr/src_hooks_1j0zy3v._.js +1 -1
  88. package/.next/standalone/.next/server/chunks/ssr/src_hooks_builtin-policies_ts_09j2ndl._.js +1 -1
  89. package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
  90. package/.next/standalone/.next/server/pages/404.html +1 -1
  91. package/.next/standalone/.next/server/pages/500.html +1 -1
  92. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  93. package/.next/standalone/.next/server/server-reference-manifest.json +22 -22
  94. package/.next/standalone/.next/static/chunks/043j99m8ykg__.css +2 -0
  95. package/.next/standalone/.next/static/chunks/0fqd7m_u81mi5.js +1 -0
  96. package/.next/standalone/.next/static/chunks/129ag2bw93bdh.js +1 -0
  97. package/.next/standalone/.next/static/chunks/{29fql3nbnfc9q.js → 1qd741hzlmjbo.js} +1 -1
  98. package/.next/standalone/.next/static/chunks/{0vmd180qfntfb.js → 2_pltstd8-xgs.js} +1 -1
  99. package/.next/standalone/.next/static/chunks/{1u5zsejmgrir_.js → 2c8j9l6j_b1ci.js} +1 -1
  100. package/.next/standalone/.next/static/chunks/3-k569wzcli8q.js +1 -0
  101. package/.next/standalone/.next/static/chunks/{258668t68du6b.js → 3brze37td_wnc.js} +1 -1
  102. package/.next/standalone/.next/static/chunks/3otmypm6j_xfo.js +6 -0
  103. package/.next/standalone/.next/static/chunks/{12tvm75t5ffui.js → 3ugmd_7dyn0id.js} +1 -1
  104. package/.next/standalone/.next/static/chunks/3yxro_r2_o9ad.js +69 -0
  105. package/.next/standalone/PROBE-FOLLOWUP.md +186 -0
  106. package/.next/standalone/app/actions/get-jev-config.ts +38 -23
  107. package/.next/standalone/app/actions/update-jev-config.ts +1 -1
  108. package/.next/standalone/app/settings/jev-panel.tsx +33 -29
  109. package/.next/standalone/package.json +10 -10
  110. package/.next/standalone/sdk/python/skill/SKILL.md +60 -14
  111. package/.next/standalone/sdk/python/skill/agents/openai.yaml +2 -1
  112. package/.next/standalone/sdk/python/skill/references/evaluator.md +255 -0
  113. package/.next/standalone/sdk/python/skill/references/events.md +17 -8
  114. package/.next/standalone/sdk/python/skill/references/frameworks.md +3 -0
  115. package/.next/standalone/sdk/python/skill/references/install.md +3 -0
  116. package/.next/standalone/sdk/python/skill/references/integration.md +6 -2
  117. package/.next/standalone/sdk/python/skill/references/typescript.md +568 -0
  118. package/.next/standalone/sdk/typescript/CHANGELOG.md +119 -0
  119. package/.next/standalone/sdk/typescript/LICENSE +42 -0
  120. package/.next/standalone/sdk/typescript/README.md +552 -0
  121. package/.next/standalone/sdk/typescript/eslint.config.mjs +59 -0
  122. package/.next/standalone/sdk/typescript/examples/research-agent.ts +197 -0
  123. package/.next/standalone/sdk/typescript/integration/ai.test.ts +920 -0
  124. package/.next/standalone/sdk/typescript/integration/fixtures/ai-4/agent.ts +337 -0
  125. package/.next/standalone/sdk/typescript/integration/fixtures/ai-4/package-lock.json +281 -0
  126. package/.next/standalone/sdk/typescript/integration/fixtures/ai-4/package.json +13 -0
  127. package/.next/standalone/sdk/typescript/integration/fixtures/ai-4/surfaces.ts +605 -0
  128. package/.next/standalone/sdk/typescript/integration/fixtures/ai-4/tsconfig.json +12 -0
  129. package/.next/standalone/sdk/typescript/integration/fixtures/ai-4/tsconfig.surfaces.json +4 -0
  130. package/.next/standalone/sdk/typescript/integration/fixtures/ai-5/agent.ts +342 -0
  131. package/.next/standalone/sdk/typescript/integration/fixtures/ai-5/package-lock.json +168 -0
  132. package/.next/standalone/sdk/typescript/integration/fixtures/ai-5/package.json +13 -0
  133. package/.next/standalone/sdk/typescript/integration/fixtures/ai-5/surfaces.ts +628 -0
  134. package/.next/standalone/sdk/typescript/integration/fixtures/ai-5/tsconfig.json +12 -0
  135. package/.next/standalone/sdk/typescript/integration/fixtures/ai-5/tsconfig.surfaces.json +4 -0
  136. package/.next/standalone/sdk/typescript/integration/fixtures/ai-6/agent.ts +346 -0
  137. package/.next/standalone/sdk/typescript/integration/fixtures/ai-6/package-lock.json +156 -0
  138. package/.next/standalone/sdk/typescript/integration/fixtures/ai-6/package.json +13 -0
  139. package/.next/standalone/sdk/typescript/integration/fixtures/ai-6/surfaces.ts +651 -0
  140. package/.next/standalone/sdk/typescript/integration/fixtures/ai-6/tsconfig.json +12 -0
  141. package/.next/standalone/sdk/typescript/integration/fixtures/ai-6/tsconfig.surfaces.json +4 -0
  142. package/.next/standalone/sdk/typescript/integration/fixtures/ai-7/agent.ts +350 -0
  143. package/.next/standalone/sdk/typescript/integration/fixtures/ai-7/package-lock.json +153 -0
  144. package/.next/standalone/sdk/typescript/integration/fixtures/ai-7/package.json +13 -0
  145. package/.next/standalone/sdk/typescript/integration/fixtures/ai-7/surfaces.ts +651 -0
  146. package/.next/standalone/sdk/typescript/integration/fixtures/ai-7/tsconfig.json +12 -0
  147. package/.next/standalone/sdk/typescript/integration/fixtures/ai-7/tsconfig.surfaces.json +4 -0
  148. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-0.3/agent.ts +623 -0
  149. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-0.3/package-lock.json +463 -0
  150. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-0.3/package.json +15 -0
  151. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-0.3/tsconfig.json +12 -0
  152. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-1/agent-v1.ts +99 -0
  153. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-1/agent.ts +623 -0
  154. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-1/package-lock.json +336 -0
  155. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-1/package.json +15 -0
  156. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-1/tsconfig.json +12 -0
  157. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-dup-core/agent.ts +96 -0
  158. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-dup-core/package-lock.json +579 -0
  159. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-dup-core/package.json +15 -0
  160. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-dup-core/tsconfig.json +12 -0
  161. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-dup-core/vendor/lc-weather-provider/index.cjs +53 -0
  162. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-dup-core/vendor/lc-weather-provider/index.mjs +55 -0
  163. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-dup-core/vendor/lc-weather-provider/package.json +18 -0
  164. package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.11/agent.ts +659 -0
  165. package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.11/package-lock.json +635 -0
  166. package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.11/package.json +15 -0
  167. package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.11/tsconfig.json +12 -0
  168. package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.12/agent.ts +659 -0
  169. package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.12/package-lock.json +553 -0
  170. package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.12/package.json +15 -0
  171. package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.12/tsconfig.json +12 -0
  172. package/.next/standalone/sdk/typescript/integration/fixtures/mastra-0/agent.ts +877 -0
  173. package/.next/standalone/sdk/typescript/integration/fixtures/mastra-0/mcp-server.mjs +66 -0
  174. package/.next/standalone/sdk/typescript/integration/fixtures/mastra-0/package-lock.json +6417 -0
  175. package/.next/standalone/sdk/typescript/integration/fixtures/mastra-0/package.json +15 -0
  176. package/.next/standalone/sdk/typescript/integration/fixtures/mastra-0/tsconfig.json +12 -0
  177. package/.next/standalone/sdk/typescript/integration/fixtures/mastra-1/agent.ts +872 -0
  178. package/.next/standalone/sdk/typescript/integration/fixtures/mastra-1/mcp-server.mjs +66 -0
  179. package/.next/standalone/sdk/typescript/integration/fixtures/mastra-1/package-lock.json +2540 -0
  180. package/.next/standalone/sdk/typescript/integration/fixtures/mastra-1/package.json +15 -0
  181. package/.next/standalone/sdk/typescript/integration/fixtures/mastra-1/tsconfig.json +12 -0
  182. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/app/actions.ts +18 -0
  183. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/app/api/ai/route.ts +42 -0
  184. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/app/api/edge/route.ts +29 -0
  185. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/app/api/langgraph/route.ts +21 -0
  186. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/app/api/llamaindex/route.ts +11 -0
  187. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/app/api/mastra/route.ts +19 -0
  188. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/app/api/status/route.ts +7 -0
  189. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/app/layout.tsx +9 -0
  190. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/app/page.tsx +15 -0
  191. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/instrumentation.ts +15 -0
  192. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/lib/ai.ts +61 -0
  193. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/lib/langgraph.ts +68 -0
  194. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/lib/llamaindex.ts +98 -0
  195. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/lib/mastra.ts +90 -0
  196. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/next.config.ts +52 -0
  197. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/package-lock.json +4343 -0
  198. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/package.json +28 -0
  199. package/.next/standalone/sdk/typescript/integration/fixtures/runtimes/agent.ts +51 -0
  200. package/.next/standalone/sdk/typescript/integration/fixtures/runtimes/deno-npm.ts +76 -0
  201. package/.next/standalone/sdk/typescript/integration/fixtures/runtimes/package-lock.json +484 -0
  202. package/.next/standalone/sdk/typescript/integration/fixtures/runtimes/package.json +15 -0
  203. package/.next/standalone/sdk/typescript/integration/fixtures/types/agent.ts +79 -0
  204. package/.next/standalone/sdk/typescript/integration/fixtures/types/package-lock.json +740 -0
  205. package/.next/standalone/sdk/typescript/integration/fixtures/types/package.json +11 -0
  206. package/.next/standalone/sdk/typescript/integration/fixtures/vanilla/agent.ts +197 -0
  207. package/.next/standalone/sdk/typescript/integration/fixtures/vanilla/package-lock.json +70 -0
  208. package/.next/standalone/sdk/typescript/integration/fixtures/vanilla/package.json +12 -0
  209. package/.next/standalone/sdk/typescript/integration/fixtures/vanilla/tsconfig.json +12 -0
  210. package/.next/standalone/sdk/typescript/integration/global-setup.ts +29 -0
  211. package/.next/standalone/sdk/typescript/integration/harness.ts +451 -0
  212. package/.next/standalone/sdk/typescript/integration/langchain.test.ts +682 -0
  213. package/.next/standalone/sdk/typescript/integration/llamaindex.test.ts +709 -0
  214. package/.next/standalone/sdk/typescript/integration/mastra-coverage.test.ts +386 -0
  215. package/.next/standalone/sdk/typescript/integration/mastra.test.ts +311 -0
  216. package/.next/standalone/sdk/typescript/integration/nextjs.test.ts +341 -0
  217. package/.next/standalone/sdk/typescript/integration/runtime-parity.ts +180 -0
  218. package/.next/standalone/sdk/typescript/integration/runtimes.bun.test.ts +15 -0
  219. package/.next/standalone/sdk/typescript/integration/runtimes.core.test.ts +113 -0
  220. package/.next/standalone/sdk/typescript/integration/runtimes.deno.test.ts +19 -0
  221. package/.next/standalone/sdk/typescript/integration/types.test.ts +141 -0
  222. package/.next/standalone/sdk/typescript/integration/vanilla.test.ts +255 -0
  223. package/.next/standalone/sdk/typescript/package-lock.json +2640 -0
  224. package/.next/standalone/sdk/typescript/package.json +401 -0
  225. package/.next/standalone/sdk/typescript/scripts/finalize-build.mjs +123 -0
  226. package/.next/standalone/sdk/typescript/scripts/release.mjs +177 -0
  227. package/.next/standalone/sdk/typescript/src/clock.ts +58 -0
  228. package/.next/standalone/sdk/typescript/src/context.ts +214 -0
  229. package/.next/standalone/sdk/typescript/src/edge/adapter.ts +18 -0
  230. package/.next/standalone/sdk/typescript/src/edge/ai.ts +116 -0
  231. package/.next/standalone/sdk/typescript/src/edge/index.ts +238 -0
  232. package/.next/standalone/sdk/typescript/src/edge/langchain.ts +18 -0
  233. package/.next/standalone/sdk/typescript/src/edge/llamaindex.ts +12 -0
  234. package/.next/standalone/sdk/typescript/src/edge/mastra.ts +17 -0
  235. package/.next/standalone/sdk/typescript/src/edge/notice.ts +33 -0
  236. package/.next/standalone/sdk/typescript/src/environment.ts +75 -0
  237. package/.next/standalone/sdk/typescript/src/evaluator/authoring.ts +480 -0
  238. package/.next/standalone/sdk/typescript/src/evaluator/cli.ts +96 -0
  239. package/.next/standalone/sdk/typescript/src/evaluator/client.ts +421 -0
  240. package/.next/standalone/sdk/typescript/src/evaluator/expression.ts +1292 -0
  241. package/.next/standalone/sdk/typescript/src/evaluator/index.ts +144 -0
  242. package/.next/standalone/sdk/typescript/src/evaluator/protocol.ts +747 -0
  243. package/.next/standalone/sdk/typescript/src/evaluator/runtime.ts +930 -0
  244. package/.next/standalone/sdk/typescript/src/evaluator/sandbox-worker.ts +171 -0
  245. package/.next/standalone/sdk/typescript/src/evaluator/source-limits.ts +27 -0
  246. package/.next/standalone/sdk/typescript/src/evaluator/source.ts +509 -0
  247. package/.next/standalone/sdk/typescript/src/events.ts +879 -0
  248. package/.next/standalone/sdk/typescript/src/exit.ts +117 -0
  249. package/.next/standalone/sdk/typescript/src/index.ts +186 -0
  250. package/.next/standalone/sdk/typescript/src/integrations/ai.ts +1566 -0
  251. package/.next/standalone/sdk/typescript/src/integrations/compat.ts +322 -0
  252. package/.next/standalone/sdk/typescript/src/integrations/core.ts +1321 -0
  253. package/.next/standalone/sdk/typescript/src/integrations/index.ts +355 -0
  254. package/.next/standalone/sdk/typescript/src/integrations/langchain.ts +2340 -0
  255. package/.next/standalone/sdk/typescript/src/integrations/llamaindex.ts +2111 -0
  256. package/.next/standalone/sdk/typescript/src/integrations/mastra.ts +1802 -0
  257. package/.next/standalone/sdk/typescript/src/logger.ts +98 -0
  258. package/.next/standalone/sdk/typescript/src/next.ts +115 -0
  259. package/.next/standalone/sdk/typescript/src/node-require.ts +446 -0
  260. package/.next/standalone/sdk/typescript/src/redact.ts +305 -0
  261. package/.next/standalone/sdk/typescript/src/resolver.ts +120 -0
  262. package/.next/standalone/sdk/typescript/src/runtime.ts +29 -0
  263. package/.next/standalone/sdk/typescript/src/schema.ts +410 -0
  264. package/.next/standalone/sdk/typescript/src/scopes.ts +701 -0
  265. package/.next/standalone/sdk/typescript/src/shared.ts +33 -0
  266. package/.next/standalone/sdk/typescript/src/version.ts +5 -0
  267. package/.next/standalone/sdk/typescript/src/writer.ts +934 -0
  268. package/.next/standalone/sdk/typescript/test/adapters.test.ts +397 -0
  269. package/.next/standalone/sdk/typescript/test/ai.test.ts +1076 -0
  270. package/.next/standalone/sdk/typescript/test/copies.test.ts +204 -0
  271. package/.next/standalone/sdk/typescript/test/edge.test.ts +183 -0
  272. package/.next/standalone/sdk/typescript/test/evaluator-client.test.ts +234 -0
  273. package/.next/standalone/sdk/typescript/test/evaluator-protocol.test.ts +225 -0
  274. package/.next/standalone/sdk/typescript/test/events.test.ts +193 -0
  275. package/.next/standalone/sdk/typescript/test/expression.test.ts +181 -0
  276. package/.next/standalone/sdk/typescript/test/global-setup.ts +26 -0
  277. package/.next/standalone/sdk/typescript/test/helpers.ts +130 -0
  278. package/.next/standalone/sdk/typescript/test/integrations.test.ts +369 -0
  279. package/.next/standalone/sdk/typescript/test/langchain-copies.test.ts +204 -0
  280. package/.next/standalone/sdk/typescript/test/langchain.test.ts +999 -0
  281. package/.next/standalone/sdk/typescript/test/llamaindex.test.ts +1760 -0
  282. package/.next/standalone/sdk/typescript/test/mastra-coverage.test.ts +501 -0
  283. package/.next/standalone/sdk/typescript/test/mastra-lifecycle.test.ts +479 -0
  284. package/.next/standalone/sdk/typescript/test/mastra.test.ts +285 -0
  285. package/.next/standalone/sdk/typescript/test/next.test.ts +109 -0
  286. package/.next/standalone/sdk/typescript/test/packaging.test.ts +312 -0
  287. package/.next/standalone/sdk/typescript/test/redaction.test.ts +171 -0
  288. package/.next/standalone/sdk/typescript/test/runtimes.test.ts +101 -0
  289. package/.next/standalone/sdk/typescript/test/sandbox.test.ts +189 -0
  290. package/.next/standalone/sdk/typescript/test/scopes.test.ts +271 -0
  291. package/.next/standalone/sdk/typescript/test/setup.ts +19 -0
  292. package/.next/standalone/sdk/typescript/test/skill-snippets.test.ts +73 -0
  293. package/.next/standalone/sdk/typescript/test/spool-contract.test.ts +124 -0
  294. package/.next/standalone/sdk/typescript/test/tracker-bounds.test.ts +191 -0
  295. package/.next/standalone/sdk/typescript/test/wire-format.test.ts +214 -0
  296. package/.next/standalone/sdk/typescript/test/writer.test.ts +407 -0
  297. package/.next/standalone/sdk/typescript/tsconfig.build.json +15 -0
  298. package/.next/standalone/sdk/typescript/tsconfig.cjs.json +19 -0
  299. package/.next/standalone/sdk/typescript/tsconfig.json +28 -0
  300. package/.next/standalone/sdk/typescript/vitest.config.ts +33 -0
  301. package/.next/standalone/sdk/typescript/vitest.integration.config.ts +23 -0
  302. package/.next/standalone/server.js +1 -1
  303. package/README.md +2 -2
  304. package/dist/cli.mjs +208 -27
  305. package/dist/worker.mjs +120 -14
  306. package/package.json +10 -10
  307. package/scripts/build-policy-pack.mjs +14 -0
  308. package/src/audit/features.ts +3 -2
  309. package/src/hooks/builtin-policies.ts +156 -5
  310. package/src/hooks/jev-cli.ts +57 -1
  311. package/src/hooks/manager.ts +1 -1
  312. package/src/hooks/pack-cli.ts +150 -18
  313. package/src/hooks/pack-store.ts +1 -1
  314. package/src/hooks/policy-catalog.ts +148 -9
  315. package/src/hooks/types.ts +1 -1
  316. package/.next/standalone/.next/static/chunks/0cd-_8-c-m1ea.js +0 -6
  317. package/.next/standalone/.next/static/chunks/0qrbdkv9qmvli.js +0 -69
  318. package/.next/standalone/.next/static/chunks/0uldbut9y2-e8.js +0 -1
  319. package/.next/standalone/.next/static/chunks/285spx855h_3r.css +0 -2
  320. package/.next/standalone/.next/static/chunks/2vkvu9-opa_1z.js +0 -1
  321. package/.next/standalone/.next/static/chunks/37lhv7wa3ywt6.js +0 -1
  322. /package/.next/standalone/.next/static/{T8YAYM9h_64fKv705vug7 → gbEOjBgZAxF2UIUwZVHNu}/_buildManifest.js +0 -0
  323. /package/.next/standalone/.next/static/{T8YAYM9h_64fKv705vug7 → gbEOjBgZAxF2UIUwZVHNu}/_clientMiddlewareManifest.js +0 -0
  324. /package/.next/standalone/.next/static/{T8YAYM9h_64fKv705vug7 → gbEOjBgZAxF2UIUwZVHNu}/_ssgManifest.js +0 -0
@@ -0,0 +1,407 @@
1
+ import { statSync } from "node:fs";
2
+ import { join } from "node:path";
3
+
4
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
5
+
6
+ import { setLogger } from "../src/logger.js";
7
+ import { runtime } from "../src/runtime.js";
8
+ import {
9
+ EventWriter,
10
+ approxSize,
11
+ capFields,
12
+ encodeEntry,
13
+ roll,
14
+ sanitize,
15
+ scrubSurrogates,
16
+ validatedInterval,
17
+ } from "../src/writer.js";
18
+ import { indexUrl, runNode, useSpool } from "./helpers.js";
19
+ import type { Spool } from "./helpers.js";
20
+
21
+ let spool: Spool;
22
+
23
+ beforeEach(() => {
24
+ spool = useSpool();
25
+ });
26
+ afterEach(async () => {
27
+ await spool.cleanup();
28
+ setLogger(null);
29
+ });
30
+
31
+ describe("flush interval validation", () => {
32
+ it("refuses a value the timer cannot run on, at the boundary", () => {
33
+ for (const bad of [0, -1, Number.NaN, Number.POSITIVE_INFINITY]) {
34
+ expect(() => validatedInterval(bad)).toThrow(/finite number greater than zero/);
35
+ }
36
+ expect(validatedInterval(0.25)).toBe(0.25);
37
+ });
38
+
39
+ it("leaves the writer on its old interval when a new one is rejected", () => {
40
+ const writer = new EventWriter(0.5);
41
+ try {
42
+ expect(() => writer.setFlushInterval(-1)).toThrow();
43
+ expect(writer.getFlushInterval()).toBe(0.5);
44
+ } finally {
45
+ writer.close();
46
+ }
47
+ });
48
+ });
49
+
50
+ describe("durability", () => {
51
+ it("publishes .jsonl files, never leaving a .tmp behind", async () => {
52
+ runtime.event.agentStart({ sessionId: "s" });
53
+ await runtime.writer.flushNow();
54
+ expect(spool.files()).toHaveLength(1);
55
+ expect(spool.files()[0]).toMatch(/^event-.*-\d+-\d+\.jsonl$/);
56
+ });
57
+
58
+ it("names each batch uniquely, so two in the same millisecond cannot overwrite", async () => {
59
+ runtime.event.agentStart({ sessionId: "s" });
60
+ await runtime.writer.flushNow();
61
+ runtime.event.agentStart({ sessionId: "s" });
62
+ await runtime.writer.flushNow();
63
+ const files = spool.files();
64
+ expect(new Set(files).size).toBe(2);
65
+ // The pid is in the stem so unrelated processes sharing one spool root
66
+ // cannot collide either.
67
+ for (const name of files) expect(name).toContain(`-${process.pid}-`);
68
+ });
69
+
70
+ it("writes 0600 batches inside a 0700 directory", async () => {
71
+ runtime.event.agentStart({ sessionId: "s" });
72
+ await runtime.writer.flushNow();
73
+ const eventsDir = join(spool.dir, "events");
74
+ expect(statSync(eventsDir).mode & 0o777).toBe(0o700);
75
+ expect(statSync(join(eventsDir, spool.files()[0]!)).mode & 0o777).toBe(0o600);
76
+ });
77
+
78
+ it("flushNow() writes an event emitted while another flush was already writing", async () => {
79
+ // The interval timer (or a second caller) can be mid-write when you call
80
+ // `flush()`. That flush drained the queue BEFORE this event arrived, so
81
+ // returning it — what flushNow() used to do — resolved with the newest
82
+ // event still in memory, breaking "resolves once your events are on disk"
83
+ // for exactly the emit-flush-exit script it exists for.
84
+ runtime.event.agentStart({ sessionId: "s" });
85
+ const alreadyWriting = runtime.writer.flushNow();
86
+ runtime.event.agentEnd({ sessionId: "s" });
87
+ await runtime.writer.flushNow();
88
+ expect(spool.events().map((e) => e.type)).toEqual(["agent_start", "agent_end"]);
89
+ await alreadyWriting;
90
+ });
91
+
92
+ it("ends every batch file with a newline, as the collector's line reader expects", async () => {
93
+ runtime.event.agentStart({ sessionId: "s" });
94
+ await runtime.writer.flushNow();
95
+ const raw = spool.lines();
96
+ expect(raw).toHaveLength(1);
97
+ expect(JSON.parse(raw[0]!)).toMatchObject({ type: "agent_start" });
98
+ });
99
+ });
100
+
101
+ describe("encoding isolation", () => {
102
+ it("drops ONE unencodable event rather than the batch around it", async () => {
103
+ const circular: Record<string, unknown> = { name: "loop" };
104
+ circular.self = circular;
105
+ setLogger({ debug: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn() });
106
+
107
+ runtime.event.agentStart({ sessionId: "s", fw_before: 1 });
108
+ runtime.event.agentStart({ sessionId: "s", fw_cycle: circular });
109
+ runtime.event.agentStart({ sessionId: "s", fw_after: 1 });
110
+ await runtime.writer.flushNow();
111
+
112
+ const events = spool.events();
113
+ expect(events).toHaveLength(3);
114
+ // The cyclic one is still published — sanitized, not dropped.
115
+ expect(events[1]!.fw_cycle).toEqual({ name: "loop", self: "<circular reference>" });
116
+ });
117
+
118
+ it("sanitizes a cycle rather than failing the event", () => {
119
+ const node: Record<string, unknown> = { a: 1 };
120
+ node.self = node;
121
+ expect(sanitize(node, new Set())).toEqual({ a: 1, self: "<circular reference>" });
122
+ });
123
+
124
+ it("does not mistake a DAG for a cycle", () => {
125
+ const shared = { value: 1 };
126
+ expect(sanitize({ left: shared, right: shared }, new Set())).toEqual({
127
+ left: { value: 1 },
128
+ right: { value: 1 },
129
+ });
130
+ });
131
+
132
+ it("makes a lone surrogate inert, which ingest would otherwise skip at 200 OK", () => {
133
+ expect(scrubSurrogates("ok\ud800bad")).toBe("ok\\ud800bad");
134
+ // A well-formed pair is left alone.
135
+ expect(scrubSurrogates("emoji \u{1F600}")).toBe("emoji \u{1F600}");
136
+ });
137
+
138
+ it("scrubs a lone surrogate in a KEY as well as a value", () => {
139
+ // An unscrubbed key reaches the wire as a JSON lone-surrogate escape, ingest
140
+ // answers 200 with `{"accepted":0,"skipped":1}`, and the uploader parks that
141
+ // batch and poisons it after three retries — so one bad key loses every
142
+ // event batched with it. A filesystem path, the realistic source, is most
143
+ // naturally a key.
144
+ const encoded = encodeEntry({ type: "t", ["path\udcff"]: "x", value: "v\udcff" })!;
145
+ // No RAW surrogate survives anywhere in the line...
146
+ expect(/[\uD800-\uDFFF]/.test(encoded)).toBe(false);
147
+ // ...and both the key and the value carry the byte visibly instead.
148
+ const parsed = JSON.parse(encoded) as Record<string, unknown>;
149
+ expect(Object.keys(parsed)).toContain(String.raw`path\udcff`);
150
+ expect(parsed.value).toBe(String.raw`v\udcff`);
151
+ });
152
+
153
+ it("writes a non-finite number as null rather than invalid JSON", () => {
154
+ const encoded = encodeEntry({ type: "t", value: Number.NaN, other: Number.POSITIVE_INFINITY })!;
155
+ expect(JSON.parse(encoded)).toEqual({ type: "t", value: null, other: null });
156
+ });
157
+
158
+ it("encodes the values JSON.stringify refuses", () => {
159
+ const encoded = encodeEntry({
160
+ type: "t",
161
+ big: 1n,
162
+ set: new Set([1, 2]),
163
+ map: new Map([["a", 1]]),
164
+ when: new Date("2026-01-01T00:00:00Z"),
165
+ })!;
166
+ expect(JSON.parse(encoded)).toEqual({
167
+ type: "t",
168
+ big: "1",
169
+ set: [1, 2],
170
+ map: { a: 1 },
171
+ when: "2026-01-01T00:00:00.000Z",
172
+ });
173
+ });
174
+
175
+ it("never lets a throwing getter escape the encoder", () => {
176
+ const hostile = {
177
+ type: "t",
178
+ get boom(): never {
179
+ throw new Error("from the caller's own code");
180
+ },
181
+ };
182
+ setLogger({ debug: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn() });
183
+ expect(() => encodeEntry(hostile)).not.toThrow();
184
+ });
185
+ });
186
+
187
+ describe("size bounds", () => {
188
+ it("caps an oversized event's fields so the collector can still deliver the batch", () => {
189
+ const huge = "x".repeat(5 * 1024 * 1024);
190
+ const encoded = encodeEntry({ type: "tool_result", output: huge })!;
191
+ expect(Buffer.byteLength(encoded, "utf8")).toBeLessThan(4 * 1024 * 1024);
192
+ expect(JSON.parse(encoded).output).toContain("…[truncated]");
193
+ });
194
+
195
+ it("never splits a surrogate pair when it truncates", () => {
196
+ const capped = capFields("\u{1F600}".repeat(10), 5) as string;
197
+ expect(capped.endsWith("…[truncated]")).toBe(true);
198
+ expect(/[\uD800-\uDBFF](?![\uDC00-\uDFFF])/.test(capped)).toBe(false);
199
+ });
200
+
201
+ it("rolls lines into batches that each stay under the limit", () => {
202
+ const lines = Array.from({ length: 5 }, () => ({ text: "x".repeat(40), bytes: 40 }));
203
+ const chunks = roll(lines, 100);
204
+ expect(chunks.map((chunk) => chunk.length)).toEqual([2, 2, 1]);
205
+ });
206
+
207
+ it("emits an over-limit line alone rather than dropping it", () => {
208
+ const chunks = roll(
209
+ [
210
+ { text: "a", bytes: 1 },
211
+ { text: "b", bytes: 500 },
212
+ ],
213
+ 100,
214
+ );
215
+ expect(chunks).toHaveLength(2);
216
+ expect(chunks[1]![0]!.bytes).toBe(500);
217
+ });
218
+
219
+ it("sizes a value by walking nodes, not characters", () => {
220
+ expect(approxSize("abcd")).toBe(4);
221
+ expect(approxSize({ a: "bb" })).toBe(3);
222
+ expect(approxSize([1, 2, 3])).toBe(24);
223
+ });
224
+ });
225
+
226
+ describe("queue bounds", () => {
227
+ it("discards the OLDEST events when the queue stops draining, and says so once", () => {
228
+ const warn = vi.fn();
229
+ setLogger({ debug: vi.fn(), info: vi.fn(), warn, error: vi.fn() });
230
+ const writer = new EventWriter(3600);
231
+ try {
232
+ for (let i = 0; i < 10_050; i += 1) writer.submit({ type: "t", index: i });
233
+ const stats = writer.stats();
234
+ expect(stats.queued).toBeLessThanOrEqual(10_000);
235
+ expect(stats.dropped).toBeGreaterThan(0);
236
+ expect(warn).toHaveBeenCalledWith(expect.stringContaining("queue is full"));
237
+ } finally {
238
+ writer.close();
239
+ }
240
+ });
241
+
242
+ it("bounds by BYTES as well as by count, because a count is not a memory bound", () => {
243
+ const writer = new EventWriter(3600);
244
+ try {
245
+ const chunk = "x".repeat(2 * 1024 * 1024);
246
+ for (let i = 0; i < 64; i += 1) writer.submit({ type: "t", blob: chunk });
247
+ // 64 x 2 MiB is 128 MiB, well past the 64 MiB ceiling, and far under the
248
+ // 10,000-event count cap — so only the byte bound can have stopped it.
249
+ expect(writer.stats().queuedBytes).toBeLessThanOrEqual(64 * 1024 * 1024);
250
+ expect(writer.stats().dropped).toBeGreaterThan(0);
251
+ } finally {
252
+ writer.close();
253
+ }
254
+ });
255
+ });
256
+
257
+ describe("process lifetime", () => {
258
+ it("lets a script that merely imports it exit, and flushes on the way out", async () => {
259
+ // The flush interval MUST be unref'd. Without that, importing this SDK
260
+ // stops every script that uses it from ever exiting — the most visible bug
261
+ // a telemetry library can ship, and one no in-process assertion can catch,
262
+ // because the test runner keeps the loop alive by itself.
263
+ const child = await runNode(`
264
+ const fp = await import(${JSON.stringify(indexUrl())});
265
+ fp.configure({ baseDir: ${JSON.stringify(spool.dir)}, flushInterval: 3600 });
266
+ fp.event.agentStart({ sessionId: "exit-test" });
267
+ console.log("emitted");
268
+ `);
269
+ expect(child.code).toBe(0);
270
+ expect(child.stdout.trim()).toBe("emitted");
271
+ // The exit hook is the only thing that can have written this: the interval
272
+ // was set to an hour.
273
+ expect(spool.events().map((event) => event.session_id)).toEqual(["exit-test"]);
274
+ });
275
+
276
+ it("closes the runs a SIGTERM abandons, so none renders as running forever", async () => {
277
+ // The documented shutdown recipe, killed mid-tool. It used to leave an
278
+ // agent_start with no agent_end and a tool_use with no tool_result, and
279
+ // exit 0 — every deploy stranded the runs it interrupted.
280
+ const child = await runNode(`
281
+ const fp = await import(${JSON.stringify(indexUrl())});
282
+ fp.configure({ baseDir: ${JSON.stringify(spool.dir)}, flushInterval: 3600 });
283
+ for (const signal of ["SIGINT", "SIGTERM"]) {
284
+ process.once(signal, () => { fp.flushSync(); process.exit(0); });
285
+ }
286
+ setInterval(() => {}, 1000); // a service's server keeps the loop alive
287
+ setTimeout(() => process.kill(process.pid, "SIGTERM"), 50);
288
+ await fp.agent("svc", { sessionId: "term-test" }, async () => {
289
+ await fp.agent("writer", async () => {
290
+ await fp.toolCall("slow", { toolCallId: "t1" }, () => new Promise(() => {}));
291
+ });
292
+ });
293
+ `);
294
+ expect(child.code).toBe(0);
295
+ const events = spool.events();
296
+ expect(events.map((e) => [e.agent_id, e.type])).toEqual([
297
+ ["svc", "agent_start"],
298
+ ["writer", "agent_start"],
299
+ ["writer", "tool_use"],
300
+ ["writer", "tool_result"],
301
+ ["writer", "error"],
302
+ ["writer", "agent_end"],
303
+ ["svc", "error"],
304
+ ["svc", "agent_end"],
305
+ ]);
306
+ const result = events.find((e) => e.type === "tool_result")!;
307
+ expect(result.tool_call_id).toBe("t1");
308
+ expect(result.error).toMatch(/^ProcessExit: the process exited \(code 0\) while tool "slow"/);
309
+ for (const end of events.filter((e) => e.type === "agent_end")) expect(end.outcome).toBe("failed");
310
+ expect(events.find((e) => e.type === "error")!.error_type).toBe("ProcessExit");
311
+ });
312
+
313
+ it("closes a hand-written model call left open by a SIGTERM", async () => {
314
+ // The no-framework recipe: modelRequest before the provider call,
315
+ // modelResponse after. Killed in between, the request had no response and
316
+ // rendered as running forever.
317
+ const child = await runNode(`
318
+ const fp = await import(${JSON.stringify(indexUrl())});
319
+ fp.configure({ baseDir: ${JSON.stringify(spool.dir)}, flushInterval: 3600 });
320
+ process.once("SIGTERM", () => { fp.flushSync(); process.exit(143); });
321
+ setInterval(() => {}, 1000);
322
+ setTimeout(() => process.kill(process.pid, "SIGTERM"), 50);
323
+ await fp.agent("planner", { sessionId: "model-term" }, async () => {
324
+ fp.event.modelRequest({ model: "m", requestId: "r1" });
325
+ await new Promise(() => {});
326
+ });
327
+ `);
328
+ expect(child.code).toBe(143);
329
+ const events = spool.events();
330
+ expect(events.map((e) => e.type)).toEqual(["agent_start", "model_request", "model_response", "error", "agent_end"]);
331
+ const response = events[2]!;
332
+ expect(response.request_id).toBe("r1");
333
+ expect(response.stop_reason).toBe("error");
334
+ expect(response.error).toMatch(/^ProcessExit: the process exited \(code 143\) while the model call/);
335
+ // Timed like the tools and hooks closed beside it.
336
+ expect(typeof response.duration_ms).toBe("number");
337
+ });
338
+
339
+ it("names the uncaught exception a crash exited on, in what it closes", async () => {
340
+ // A timer throwing mid-run used to leave only "the process exited (code 1)"
341
+ // in the trace — the exception itself was nowhere.
342
+ const child = await runNode(`
343
+ const fp = await import(${JSON.stringify(indexUrl())});
344
+ fp.configure({ baseDir: ${JSON.stringify(spool.dir)}, flushInterval: 3600 });
345
+ setInterval(() => {}, 1000);
346
+ class QuotaError extends Error {}
347
+ setTimeout(() => { throw new QuotaError("boom from a timer"); }, 50);
348
+ await fp.agent("svc", { sessionId: "crash" }, async () => {
349
+ await fp.toolCall("slow", { toolCallId: "t1" }, () => new Promise(() => {}));
350
+ });
351
+ `);
352
+ expect(child.code).toBe(1);
353
+ expect(child.stderr).toContain("boom from a timer"); // still crashes as it would have
354
+ const events = spool.events();
355
+ expect(events.map((e) => e.type)).toEqual(["agent_start", "tool_use", "tool_result", "error", "agent_end"]);
356
+ expect(events[2]!.error).toMatch(/\(code 1\) on an uncaught QuotaError: boom from a timer while tool "slow"/);
357
+ expect(events[3]!.message).toMatch(/on an uncaught QuotaError: boom from a timer/);
358
+ });
359
+
360
+ it("closes a nested run most-recent-first: a sub-agent ends before the tool that started it", async () => {
361
+ // Live: a planner's delegate tool ran a writer sub-agent, killed during the
362
+ // writer's model call. Closing all tools before all agents showed the
363
+ // delegate tool finishing while the writer it started was still running.
364
+ const child = await runNode(`
365
+ const fp = await import(${JSON.stringify(indexUrl())});
366
+ fp.configure({ baseDir: ${JSON.stringify(spool.dir)}, flushInterval: 3600 });
367
+ process.once("SIGTERM", () => { fp.flushSync(); process.exit(143); });
368
+ setInterval(() => {}, 1000);
369
+ setTimeout(() => process.kill(process.pid, "SIGTERM"), 50);
370
+ await fp.agent("planner", { sessionId: "nested-term" }, async () => {
371
+ await fp.toolCall("delegate_writer", { toolCallId: "d1" }, async () => {
372
+ await fp.agent("writer", async () => {
373
+ fp.event.modelRequest({ model: "m", requestId: "w1" });
374
+ await new Promise(() => {});
375
+ });
376
+ });
377
+ });
378
+ `);
379
+ expect(child.code).toBe(143);
380
+ const closing = spool.events().slice(4); // planner start, tool_use, writer start, model_request
381
+ expect(closing.map((e) => [e.agent_id, e.type])).toEqual([
382
+ ["writer", "model_response"],
383
+ ["writer", "error"],
384
+ ["writer", "agent_end"],
385
+ ["planner", "tool_result"],
386
+ ["planner", "error"],
387
+ ["planner", "agent_end"],
388
+ ]);
389
+ expect(closing.find((e) => e.type === "error")!.traceback).toBeUndefined();
390
+ });
391
+
392
+ it("closes nothing on a flushSync() while the process carries on", async () => {
393
+ const child = await runNode(`
394
+ const fp = await import(${JSON.stringify(indexUrl())});
395
+ fp.configure({ baseDir: ${JSON.stringify(spool.dir)}, flushInterval: 3600 });
396
+ await fp.agent("svc", { sessionId: "flush-test" }, async () => {
397
+ fp.flushSync();
398
+ await new Promise((r) => setTimeout(r, 10));
399
+ });
400
+ `);
401
+ expect(child.code).toBe(0);
402
+ expect(spool.events().map((e) => [e.type, e.outcome ?? null])).toEqual([
403
+ ["agent_start", null],
404
+ ["agent_end", "success"],
405
+ ]);
406
+ });
407
+ });
@@ -0,0 +1,15 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "rootDir": "src",
5
+ "outDir": "dist/esm",
6
+ "module": "NodeNext",
7
+ "moduleResolution": "NodeNext",
8
+ "noEmit": false,
9
+ // `@internal` exports (test hooks such as `_stats`, `_internals`,
10
+ // `attach`) stay out of the published declarations: a name in a `.d.ts`
11
+ // is a name a customer can come to depend on.
12
+ "stripInternal": true
13
+ },
14
+ "include": ["src/**/*.ts"]
15
+ }
@@ -0,0 +1,19 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ // Declarations are emitted here too, and `exports[*].require.types` points
4
+ // at them. Under dist/cjs's `"type": "commonjs"` they ARE CommonJS
5
+ // declarations; handing `require` the ESM ones instead is what made every
6
+ // CommonJS project on `module: node16` fail with TS1479.
7
+ "compilerOptions": {
8
+ "rootDir": "src",
9
+ "outDir": "dist/cjs",
10
+ "module": "CommonJS",
11
+ "moduleResolution": "Node10",
12
+ "noEmit": false,
13
+ // `@internal` exports (test hooks such as `_stats`, `_internals`,
14
+ // `attach`) stay out of the published declarations: a name in a `.d.ts`
15
+ // is a name a customer can come to depend on.
16
+ "stripInternal": true
17
+ },
18
+ "include": ["src/**/*.ts"]
19
+ }
@@ -0,0 +1,28 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "lib": ["ES2023", "ESNext.Disposable"],
5
+ "module": "NodeNext",
6
+ "moduleResolution": "NodeNext",
7
+ "types": ["node"],
8
+
9
+ "strict": true,
10
+ "noUncheckedIndexedAccess": true,
11
+ "exactOptionalPropertyTypes": false,
12
+ "noImplicitOverride": true,
13
+ "noFallthroughCasesInSwitch": true,
14
+ "noUnusedLocals": true,
15
+ "noUnusedParameters": true,
16
+ "useUnknownInCatchVariables": true,
17
+ "verbatimModuleSyntax": false,
18
+
19
+ "declaration": true,
20
+ "declarationMap": true,
21
+ "sourceMap": true,
22
+ "esModuleInterop": true,
23
+ "forceConsistentCasingInFileNames": true,
24
+ "skipLibCheck": true,
25
+ "isolatedModules": true
26
+ },
27
+ "include": ["src/**/*.ts", "test/**/*.ts", "integration/*.ts", "scripts/**/*.mjs", "*.ts", "*.mts"]
28
+ }
@@ -0,0 +1,33 @@
1
+ import { defineConfig } from "vitest/config";
2
+
3
+ export default defineConfig({
4
+ // Vite searches UPWARD from the project root for a PostCSS config, and this
5
+ // package sits inside a monorepo whose root has one — which requires
6
+ // `@tailwindcss/postcss`, a root devDependency that is deliberately not in
7
+ // this package's isolated `node_modules`. Vite then dies before a single test
8
+ // runs.
9
+ //
10
+ // It only fails where the isolation is real: locally the root's
11
+ // `node_modules` is present and Node's resolution walks up into it, so the
12
+ // search succeeds and nothing looks wrong. In CI, where this package is
13
+ // installed on its own, it is fatal.
14
+ //
15
+ // An inline (empty) config turns the search off. This package has no CSS at
16
+ // all, so there is nothing to configure — the only thing that search can do
17
+ // here is find somebody else's tooling.
18
+ css: { postcss: {} },
19
+ test: {
20
+ include: ["test/**/*.test.ts"],
21
+ environment: "node",
22
+ globalSetup: ["./test/global-setup.ts"],
23
+ setupFiles: ["./test/setup.ts"],
24
+ // The writer, the sandbox and the adapters all reach for process-wide state
25
+ // (an exit hook, a patched prototype, a spool directory). Running files one
26
+ // at a time keeps a test from observing another file's patch, and keeps the
27
+ // sandbox suite from competing with itself for the concurrency semaphore.
28
+ pool: "forks",
29
+ fileParallelism: false,
30
+ testTimeout: 30_000,
31
+ hookTimeout: 30_000,
32
+ },
33
+ });
@@ -0,0 +1,23 @@
1
+ import { defineConfig } from "vitest/config";
2
+
3
+ /**
4
+ * The real-framework suite (`integration/`). Separate from `vitest.config.ts`
5
+ * because it installs real frameworks from the registry and spawns real Node
6
+ * processes against the PACKED artifact — minutes, not seconds, and it needs
7
+ * the network the unit suite deliberately does not.
8
+ */
9
+ export default defineConfig({
10
+ // Same reason as vitest.config.ts: stop Vite finding the monorepo root's
11
+ // PostCSS config, which needs a package this isolated install does not have.
12
+ css: { postcss: {} },
13
+ test: {
14
+ include: ["integration/**/*.test.ts"],
15
+ environment: "node",
16
+ globalSetup: ["./integration/global-setup.ts"],
17
+ // Every case is its own child process with its own spool, so files are
18
+ // independent and can run side by side.
19
+ fileParallelism: true,
20
+ testTimeout: 120_000,
21
+ hookTimeout: 900_000,
22
+ },
23
+ });
@@ -9,7 +9,7 @@ const currentPort = parseInt(process.env.PORT, 10) || 3000
9
9
  const hostname = process.env.HOSTNAME || '0.0.0.0'
10
10
 
11
11
  let keepAliveTimeout = parseInt(process.env.KEEP_ALIVE_TIMEOUT, 10)
12
- const nextConfig = {"env":{"NEXT_PUBLIC_APP_VERSION":"1.0.7-beta.1"},"typescript":{"ignoreBuildErrors":false},"typedRoutes":false,"distDir":"./.next","cleanDistDir":true,"assetPrefix":"","cacheMaxMemorySize":52428800,"configOrigin":"next.config.ts","useFileSystemPublicRoutes":true,"generateEtags":true,"pageExtensions":["tsx","ts","jsx","js"],"instrumentationClientInject":[],"poweredByHeader":true,"compress":true,"images":{"deviceSizes":[640,750,828,1080,1200,1920,2048,3840],"imageSizes":[32,48,64,96,128,256,384],"path":"/_next/image","loader":"default","loaderFile":"","domains":[],"disableStaticImages":false,"minimumCacheTTL":14400,"formats":["image/webp"],"maximumRedirects":3,"maximumResponseBody":50000000,"dangerouslyAllowLocalIP":false,"dangerouslyAllowSVG":false,"contentSecurityPolicy":"script-src 'none'; frame-src 'none'; sandbox;","contentDispositionType":"attachment","localPatterns":[{"pathname":"**","search":""}],"remotePatterns":[],"qualities":[75],"unoptimized":true,"customCacheHandler":false},"devIndicators":{"position":"bottom-left"},"onDemandEntries":{"maxInactiveAge":60000,"pagesBufferLength":5},"basePath":"","sassOptions":{},"trailingSlash":false,"i18n":null,"productionBrowserSourceMaps":false,"excludeDefaultMomentLocales":true,"reactProductionProfiling":false,"reactStrictMode":null,"reactMaxHeadersLength":6000,"httpAgentOptions":{"keepAlive":true},"logging":{"serverFunctions":true,"browserToTerminal":"warn"},"compiler":{},"expireTime":31536000,"staticPageGenerationTimeout":60,"output":"standalone","modularizeImports":{"@mui/icons-material":{"transform":"@mui/icons-material/{{member}}"},"lodash":{"transform":"lodash/{{member}}"}},"outputFileTracingRoot":"/home/runner/work/failproofai/failproofai","enablePrerenderSourceMaps":true,"cacheComponents":false,"cacheLife":{"default":{"stale":300,"revalidate":900,"expire":4294967294},"seconds":{"stale":30,"revalidate":1,"expire":60},"minutes":{"stale":300,"revalidate":60,"expire":3600},"hours":{"stale":300,"revalidate":3600,"expire":86400},"days":{"stale":300,"revalidate":86400,"expire":604800},"weeks":{"stale":300,"revalidate":604800,"expire":2592000},"max":{"stale":300,"revalidate":2592000,"expire":31536000}},"cacheHandlers":{},"experimental":{"appNewScrollHandler":true,"coldCacheBadge":false,"devValidationWorker":true,"useSkewCookie":false,"cssChunking":true,"multiZoneDraftMode":false,"appNavFailHandling":false,"prerenderEarlyExit":true,"serverMinification":true,"linkNoTouchStart":false,"caseSensitiveRoutes":false,"cachedNavigations":false,"dynamicOnHover":false,"useOffline":false,"varyParams":true,"optimisticRouting":true,"instrumentationClientRouterTransitionEvents":false,"prefetchInlining":{"maxSize":2048,"maxBundleSize":10240},"preloadEntriesOnStart":true,"clientRouterFilter":true,"clientRouterFilterRedirects":false,"fetchCacheKeyPrefix":"","proxyPrefetch":"flexible","optimisticClientCache":true,"manualClientBasePath":false,"cpus":3,"memoryBasedWorkersCount":false,"imgOptConcurrency":null,"imgOptOperationCache":null,"imgOptTimeoutInSeconds":7,"imgOptMaxInputPixels":268402689,"imgOptSequentialRead":null,"isrFlushToDisk":true,"workerThreads":false,"optimizeCss":false,"nextScriptWorkers":false,"scrollRestoration":false,"externalDir":false,"devMemoryThresholdRestart":true,"disableOptimizedLoading":false,"gzipSize":true,"craCompat":false,"esmExternals":true,"fullySpecified":false,"swcTraceProfiling":false,"forceSwcTransforms":false,"requestInsights":false,"largePageDataBytes":128000,"typedEnv":false,"parallelServerCompiles":false,"parallelServerBuildTraces":false,"ppr":false,"authInterrupts":false,"webpackMemoryOptimizations":false,"optimizeServerReact":true,"strictRouteTypes":false,"useTypeScriptCli":true,"removeUncaughtErrorAndRejectionListeners":false,"validateRSCRequestHeaders":true,"staleTimes":{"dynamic":0,"static":300},"reactDebugChannel":true,"serverComponentsHmrCache":true,"serverComponentsHmrCancellation":false,"staticGenerationMaxConcurrency":8,"staticGenerationMinPagesPerWorker":25,"transitionIndicator":false,"gestureTransition":false,"inlineCss":false,"useCache":false,"globalNotFound":false,"browserDebugInfoInTerminal":"warn","lockDistDir":true,"proxyClientMaxBodySize":10485760,"hideLogsAfterAbort":false,"mcpServer":true,"turbopackFileSystemCacheForDev":true,"turbopackFileSystemCacheForBuild":true,"turbopackInferModuleSideEffects":true,"turbopackPluginRuntimeStrategy":"childProcesses","turbopackMemoryEvictionMode":"auto","optimizePackageImports":["lucide-react","date-fns","lodash-es","ramda","antd","react-bootstrap","ahooks","@ant-design/icons","@headlessui/react","@headlessui-float/react","@heroicons/react/20/solid","@heroicons/react/24/solid","@heroicons/react/24/outline","@visx/visx","@tremor/react","rxjs","@mui/material","@mui/icons-material","recharts","react-use","effect","@effect/schema","@effect/platform","@effect/platform-node","@effect/platform-browser","@effect/platform-bun","@effect/sql","@effect/sql-mssql","@effect/sql-mysql2","@effect/sql-pg","@effect/sql-sqlite-node","@effect/sql-sqlite-bun","@effect/sql-sqlite-wasm","@effect/sql-sqlite-react-native","@effect/rpc","@effect/rpc-http","@effect/typeclass","@effect/experimental","@effect/opentelemetry","@material-ui/core","@material-ui/icons","@tabler/icons-react","mui-core","react-icons/ai","react-icons/bi","react-icons/bs","react-icons/cg","react-icons/ci","react-icons/di","react-icons/fa","react-icons/fa6","react-icons/fc","react-icons/fi","react-icons/gi","react-icons/go","react-icons/gr","react-icons/hi","react-icons/hi2","react-icons/im","react-icons/io","react-icons/io5","react-icons/lia","react-icons/lib","react-icons/lu","react-icons/md","react-icons/pi","react-icons/ri","react-icons/rx","react-icons/si","react-icons/sl","react-icons/tb","react-icons/tfi","react-icons/ti","react-icons/vsc","react-icons/wi"],"useCacheTimeout":54,"instantInsights":{"validationLevel":"warning"},"trustHostHeader":false,"isExperimentalCompile":false},"htmlLimitedBots":"[\\w-]+-Google|Google-[\\w-]+|Chrome-Lighthouse|Slurp|DuckDuckBot|baiduspider|yandex|sogou|bitlybot|tumblr|vkShare|quora link preview|redditbot|ia_archiver|Bingbot|BingPreview|applebot|facebookexternalhit|facebookcatalog|Twitterbot|LinkedInBot|Slackbot|Discordbot|WhatsApp|SkypeUriPreview|Yeti|googleweblight","bundlePagesRouterDependencies":false,"configFileName":"next.config.ts","outputFileTracingExcludes":{"*":["node_modules/@img/**","node_modules/sharp/**"]},"turbopack":{"root":"/home/runner/work/failproofai/failproofai"},"repoRoot":"/home/runner/work/failproofai/failproofai","distDirRoot":".next"}
12
+ const nextConfig = {"env":{"NEXT_PUBLIC_APP_VERSION":"1.0.7-beta.2"},"typescript":{"ignoreBuildErrors":false},"typedRoutes":false,"distDir":"./.next","cleanDistDir":true,"assetPrefix":"","cacheMaxMemorySize":52428800,"configOrigin":"next.config.ts","useFileSystemPublicRoutes":true,"generateEtags":true,"pageExtensions":["tsx","ts","jsx","js"],"instrumentationClientInject":[],"poweredByHeader":true,"compress":true,"images":{"deviceSizes":[640,750,828,1080,1200,1920,2048,3840],"imageSizes":[32,48,64,96,128,256,384],"path":"/_next/image","loader":"default","loaderFile":"","domains":[],"disableStaticImages":false,"minimumCacheTTL":14400,"formats":["image/webp"],"maximumRedirects":3,"maximumResponseBody":50000000,"dangerouslyAllowLocalIP":false,"dangerouslyAllowSVG":false,"contentSecurityPolicy":"script-src 'none'; frame-src 'none'; sandbox;","contentDispositionType":"attachment","localPatterns":[{"pathname":"**","search":""}],"remotePatterns":[],"qualities":[75],"unoptimized":true,"customCacheHandler":false},"devIndicators":{"position":"bottom-left"},"onDemandEntries":{"maxInactiveAge":60000,"pagesBufferLength":5},"basePath":"","sassOptions":{},"trailingSlash":false,"i18n":null,"productionBrowserSourceMaps":false,"excludeDefaultMomentLocales":true,"reactProductionProfiling":false,"reactStrictMode":null,"reactMaxHeadersLength":6000,"httpAgentOptions":{"keepAlive":true},"logging":{"serverFunctions":true,"browserToTerminal":"warn"},"compiler":{},"expireTime":31536000,"staticPageGenerationTimeout":60,"output":"standalone","modularizeImports":{"@mui/icons-material":{"transform":"@mui/icons-material/{{member}}"},"lodash":{"transform":"lodash/{{member}}"}},"outputFileTracingRoot":"/home/runner/work/failproofai/failproofai","enablePrerenderSourceMaps":true,"cacheComponents":false,"cacheLife":{"default":{"stale":300,"revalidate":900,"expire":4294967294},"seconds":{"stale":30,"revalidate":1,"expire":60},"minutes":{"stale":300,"revalidate":60,"expire":3600},"hours":{"stale":300,"revalidate":3600,"expire":86400},"days":{"stale":300,"revalidate":86400,"expire":604800},"weeks":{"stale":300,"revalidate":604800,"expire":2592000},"max":{"stale":300,"revalidate":2592000,"expire":31536000}},"cacheHandlers":{},"experimental":{"appNewScrollHandler":true,"coldCacheBadge":false,"devValidationWorker":true,"useSkewCookie":false,"cssChunking":true,"multiZoneDraftMode":false,"appNavFailHandling":false,"prerenderEarlyExit":true,"serverMinification":true,"linkNoTouchStart":false,"caseSensitiveRoutes":false,"cachedNavigations":false,"dynamicOnHover":false,"useOffline":false,"varyParams":true,"optimisticRouting":true,"instrumentationClientRouterTransitionEvents":false,"prefetchInlining":{"maxSize":2048,"maxBundleSize":10240},"preloadEntriesOnStart":true,"clientRouterFilter":true,"clientRouterFilterRedirects":false,"fetchCacheKeyPrefix":"","proxyPrefetch":"flexible","optimisticClientCache":true,"manualClientBasePath":false,"cpus":3,"memoryBasedWorkersCount":false,"imgOptConcurrency":null,"imgOptOperationCache":null,"imgOptTimeoutInSeconds":7,"imgOptMaxInputPixels":268402689,"imgOptSequentialRead":null,"isrFlushToDisk":true,"workerThreads":false,"optimizeCss":false,"nextScriptWorkers":false,"scrollRestoration":false,"externalDir":false,"devMemoryThresholdRestart":true,"disableOptimizedLoading":false,"gzipSize":true,"craCompat":false,"esmExternals":true,"fullySpecified":false,"swcTraceProfiling":false,"forceSwcTransforms":false,"requestInsights":false,"largePageDataBytes":128000,"typedEnv":false,"parallelServerCompiles":false,"parallelServerBuildTraces":false,"ppr":false,"authInterrupts":false,"webpackMemoryOptimizations":false,"optimizeServerReact":true,"strictRouteTypes":false,"useTypeScriptCli":true,"removeUncaughtErrorAndRejectionListeners":false,"validateRSCRequestHeaders":true,"staleTimes":{"dynamic":0,"static":300},"reactDebugChannel":true,"serverComponentsHmrCache":true,"serverComponentsHmrCancellation":false,"staticGenerationMaxConcurrency":8,"staticGenerationMinPagesPerWorker":25,"transitionIndicator":false,"gestureTransition":false,"inlineCss":false,"useCache":false,"globalNotFound":false,"browserDebugInfoInTerminal":"warn","lockDistDir":true,"proxyClientMaxBodySize":10485760,"hideLogsAfterAbort":false,"mcpServer":true,"turbopackFileSystemCacheForDev":true,"turbopackFileSystemCacheForBuild":true,"turbopackInferModuleSideEffects":true,"turbopackPluginRuntimeStrategy":"childProcesses","turbopackMemoryEvictionMode":"auto","optimizePackageImports":["lucide-react","date-fns","lodash-es","ramda","antd","react-bootstrap","ahooks","@ant-design/icons","@headlessui/react","@headlessui-float/react","@heroicons/react/20/solid","@heroicons/react/24/solid","@heroicons/react/24/outline","@visx/visx","@tremor/react","rxjs","@mui/material","@mui/icons-material","recharts","react-use","effect","@effect/schema","@effect/platform","@effect/platform-node","@effect/platform-browser","@effect/platform-bun","@effect/sql","@effect/sql-mssql","@effect/sql-mysql2","@effect/sql-pg","@effect/sql-sqlite-node","@effect/sql-sqlite-bun","@effect/sql-sqlite-wasm","@effect/sql-sqlite-react-native","@effect/rpc","@effect/rpc-http","@effect/typeclass","@effect/experimental","@effect/opentelemetry","@material-ui/core","@material-ui/icons","@tabler/icons-react","mui-core","react-icons/ai","react-icons/bi","react-icons/bs","react-icons/cg","react-icons/ci","react-icons/di","react-icons/fa","react-icons/fa6","react-icons/fc","react-icons/fi","react-icons/gi","react-icons/go","react-icons/gr","react-icons/hi","react-icons/hi2","react-icons/im","react-icons/io","react-icons/io5","react-icons/lia","react-icons/lib","react-icons/lu","react-icons/md","react-icons/pi","react-icons/ri","react-icons/rx","react-icons/si","react-icons/sl","react-icons/tb","react-icons/tfi","react-icons/ti","react-icons/vsc","react-icons/wi"],"useCacheTimeout":54,"instantInsights":{"validationLevel":"warning"},"trustHostHeader":false,"isExperimentalCompile":false},"htmlLimitedBots":"[\\w-]+-Google|Google-[\\w-]+|Chrome-Lighthouse|Slurp|DuckDuckBot|baiduspider|yandex|sogou|bitlybot|tumblr|vkShare|quora link preview|redditbot|ia_archiver|Bingbot|BingPreview|applebot|facebookexternalhit|facebookcatalog|Twitterbot|LinkedInBot|Slackbot|Discordbot|WhatsApp|SkypeUriPreview|Yeti|googleweblight","bundlePagesRouterDependencies":false,"configFileName":"next.config.ts","outputFileTracingExcludes":{"*":["node_modules/@img/**","node_modules/sharp/**"]},"turbopack":{"root":"/home/runner/work/failproofai/failproofai"},"repoRoot":"/home/runner/work/failproofai/failproofai","distDirRoot":".next"}
13
13
 
14
14
  process.env.__NEXT_PRIVATE_STANDALONE_CONFIG = JSON.stringify(nextConfig)
15
15
 
package/README.md CHANGED
@@ -18,7 +18,7 @@
18
18
  Wherever your agents run, we see it — and we can say no. Failproof hooks 12 agent
19
19
  harnesses — coding CLIs like Claude Code and Codex, chat gateways like Hermes,
20
20
  self-hosted assistants like OpenClaw — capturing every run and blocking dangerous
21
- tool calls before they execute. 39 built-in policies. Zero latency. Runs locally.
21
+ tool calls before they execute. 40 built-in policies. Zero latency. Runs locally.
22
22
 
23
23
  </div>
24
24
 
@@ -176,7 +176,7 @@ three are the developer favourites — coding CLIs are the harness class we cove
176
176
  deepest. The `sanitize-*` family is separate: it runs after a tool returns, so
177
177
  it reports a secret in tool output rather than keeping it out of the context.
178
178
 
179
- → [All 39 built-in policies](https://docs.befailproof.ai/policies/packs)
179
+ → [All 40 built-in policies](https://docs.befailproof.ai/policies/packs)
180
180
 
181
181
  ---
182
182