failproofai 1.0.1 → 1.0.2-beta.0
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.
- package/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/build-manifest.json +3 -3
- package/.next/standalone/.next/prerender-manifest.json +6 -6
- package/.next/standalone/.next/required-server-files.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page.js +2 -2
- package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_global-error.html +1 -1
- package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
- package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +6 -6
- package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
- package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/_not-found/page.js +2 -2
- package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_not-found.html +1 -1
- package/.next/standalone/.next/server/app/_not-found.rsc +15 -15
- package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +15 -15
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +14 -14
- package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/api/audit/invite/route.js +3 -2
- package/.next/standalone/.next/server/app/api/audit/invite/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/audit/run/route.js +5 -4
- package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/audit/status/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/login-request/route.js +2 -2
- package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/login-verify/route.js +4 -3
- package/.next/standalone/.next/server/app/api/auth/login-verify/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/logout/route.js +4 -4
- package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/status/route.js +4 -4
- package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +2 -2
- package/.next/standalone/.next/server/app/audit/page.js +2 -2
- package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/index.html +1 -1
- package/.next/standalone/.next/server/app/index.rsc +15 -15
- package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +14 -14
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +15 -15
- package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/page.js +2 -2
- package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +66 -22
- package/.next/standalone/.next/server/app/policies/page.js +5 -4
- package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page.js +2 -2
- package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js +2 -2
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/projects/page.js +2 -2
- package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +4 -4
- package/.next/standalone/.next/server/app/settings/page.js +1 -1
- package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/chunks/{[externals]__1qzqcio._.js → [externals]__0e32-7c._.js} +1 -1
- package/.next/standalone/.next/server/chunks/[externals]__1s462yl._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__01eqny5._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0_0xu5z._.js +1 -1
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__1p8poxd._.js → [root-of-the-server]__0igxt32._.js} +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0neqlu-._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0o07qi9._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0t9oqnn._.js +3 -0
- package/.next/standalone/.next/server/chunks/_0bs-v8p._.js +3 -0
- package/.next/standalone/.next/server/chunks/_0tovk6q._.js +3 -0
- package/.next/standalone/.next/server/chunks/_0trp3yc._.js +3 -0
- package/.next/standalone/.next/server/chunks/_185gyk9._.js +3 -0
- package/.next/standalone/.next/server/chunks/_1ek68ln._.js +5 -6
- package/.next/standalone/.next/server/chunks/lib_telemetry-id_ts_1k8gj9o._.js +3 -0
- package/.next/standalone/.next/server/chunks/{node_modules_posthog-node_dist_entrypoints_index_node_mjs_09d5c79._.js → node_modules_posthog-node_dist_entrypoints_index_node_mjs_04op_ou._.js} +1 -1
- package/.next/standalone/.next/server/chunks/{node_modules_posthog-node_dist_entrypoints_index_node_mjs_1d2g73o._.js → node_modules_posthog-node_dist_entrypoints_index_node_mjs_0dr20uz._.js} +1 -1
- package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
- package/.next/standalone/.next/server/chunks/src_hooks_0xbw3bu._.js +12 -0
- package/.next/standalone/.next/server/chunks/src_hooks_fp-home_ts_09kv0bn._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__013jr2b._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__01wy8d-._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__02npjtd._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0spkm68._.js → [root-of-the-server]__07gm3zl._.js} +21 -20
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0da85px._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ftmoxc._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0oa1lav._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0p-5p8u._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0s740oi._.js +6 -0
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__07tbbf3._.js → [root-of-the-server]__0zig5sv._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__192nhvh._.js +5 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1p2otjt._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/{_0lvyuv4._.js → _00e9tnf._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/_08x1r5t._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{_0u5zauv._.js → _12l4a_k._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_1u8-lu2._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_1zopuov._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +13 -13
- package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/app_settings_settings-client_tsx_20lq-mq._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_08o7bqo._.js +10 -0
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_builtin-policies_ts_09j2ndl._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_fp-home_ts_0je3xkv._.js +1 -1
- package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
- package/.next/standalone/.next/server/middleware.js +1 -1
- package/.next/standalone/.next/server/pages/404.html +1 -1
- package/.next/standalone/.next/server/pages/500.html +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.json +71 -27
- package/.next/standalone/.next/static/chunks/{37fcpc36x9gpe.js → 0eqky-7n7dgdm.js} +1 -1
- package/.next/standalone/.next/static/chunks/{1ide1wl2f7zi1.js → 0sa9v5mhc8861.js} +13 -13
- package/.next/standalone/.next/static/chunks/1mfzsja6ftim5.css +2 -0
- package/.next/standalone/.next/static/chunks/{3k7mxbp9hiom0.js → 1nuqytbta44af.js} +1 -1
- package/.next/standalone/.next/static/chunks/1sl2xmn9inx3y.js +6 -0
- package/.next/standalone/.next/static/chunks/{2_2lhuojq2xop.js → 2aawsjld9ied_.js} +1 -1
- package/.next/standalone/.next/static/chunks/2gn7ut4svofm2.js +1 -0
- package/.next/standalone/.next/static/chunks/{31s1smp-g7gks.js → 2hs7ycvsav7v2.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0k5050ezjvv49.js → 2i2yt3hzjredm.js} +1 -1
- package/.next/standalone/.next/static/chunks/{3c808qrfcq0im.js → 35xg6retpe6rp.js} +1 -1
- package/.next/standalone/.next/static/chunks/{2zpp1we2jv6tb.js → 3y54nw0i7dsjl.js} +1 -1
- package/.next/standalone/SECURITY.md +5 -4
- package/.next/standalone/app/actions/get-hooks-config.ts +108 -17
- package/.next/standalone/app/actions/pack-actions.ts +153 -0
- package/.next/standalone/app/audit/_components/run-progress.tsx +1 -1
- package/.next/standalone/app/audit/_components/share-templates.ts +13 -13
- package/.next/standalone/app/policies/hooks-client.tsx +320 -14
- package/.next/standalone/components/navbar.tsx +2 -28
- package/.next/standalone/components/reach-developers.tsx +8 -1
- package/.next/standalone/docs-old/agenteye/python-sdk-skill.mdx +1 -1
- package/.next/standalone/docs-old/agenteye/python-sdk.mdx +59 -35
- package/.next/standalone/docs-old/i18n/README.ar.md +1 -0
- package/.next/standalone/docs-old/i18n/README.de.md +1 -0
- package/.next/standalone/docs-old/i18n/README.es.md +1 -0
- package/.next/standalone/docs-old/i18n/README.fr.md +1 -0
- package/.next/standalone/docs-old/i18n/README.he.md +1 -0
- package/.next/standalone/docs-old/i18n/README.hi.md +1 -0
- package/.next/standalone/docs-old/i18n/README.it.md +1 -0
- package/.next/standalone/docs-old/i18n/README.ja.md +1 -0
- package/.next/standalone/docs-old/i18n/README.ko.md +1 -0
- package/.next/standalone/docs-old/i18n/README.pt-br.md +1 -0
- package/.next/standalone/docs-old/i18n/README.ru.md +1 -0
- package/.next/standalone/docs-old/i18n/README.tr.md +1 -0
- package/.next/standalone/docs-old/i18n/README.vi.md +1 -0
- package/.next/standalone/docs-old/i18n/README.zh.md +1 -0
- package/.next/standalone/fp-cloud-cli/CHANGELOG.md +431 -0
- package/.next/standalone/fp-cloud-cli/LICENSE +42 -0
- package/.next/standalone/fp-cloud-cli/MANIFEST.in +10 -0
- package/.next/standalone/fp-cloud-cli/README.md +259 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/__init__.py +10 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/__main__.py +4 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/_click_compat.py +64 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/_context.py +332 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/_version.py +1 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/analytics.py +432 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/analytics_config.py +77 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/analytics_registry.py +83 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/app.py +492 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/auth.py +160 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/client.py +1694 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/__init__.py +0 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/_write.py +214 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/agent_cmds.py +407 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/alerts_cmds.py +445 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/audits_cmds.py +1054 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/auth_cmds.py +512 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/errors_cmds.py +190 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/evals_cmds.py +161 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/events_cmds.py +159 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/fleet_cmds.py +416 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/guardrails_cmds.py +148 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/incidents_cmds.py +472 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/keys_cmds.py +407 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/list_cmds.py +63 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/orgs_cmds.py +319 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/policies_cmds.py +499 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/queries_cmds.py +378 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/sessions_cmds.py +151 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/settings_cmds.py +150 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/usage_cmds.py +35 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/users_cmds.py +404 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/config.py +330 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/dates.py +78 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/enforcement.py +345 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/errors.py +98 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/models.py +891 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/orgs.py +30 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/output.py +6593 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/permissions.py +208 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/policy_check.py +290 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/py.typed +0 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/select.py +322 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/theme.py +53 -0
- package/.next/standalone/fp-cloud-cli/pyproject.toml +106 -0
- package/.next/standalone/fp-cloud-cli/skill/SKILL.md +302 -0
- package/.next/standalone/fp-cloud-cli/skill/agents/openai.yaml +8 -0
- package/.next/standalone/fp-cloud-cli/skill/references/commands.md +254 -0
- package/.next/standalone/fp-cloud-cli/tests/__init__.py +0 -0
- package/.next/standalone/fp-cloud-cli/tests/conftest.py +92 -0
- package/.next/standalone/fp-cloud-cli/tests/test_alerting.py +644 -0
- package/.next/standalone/fp-cloud-cli/tests/test_analytics.py +385 -0
- package/.next/standalone/fp-cloud-cli/tests/test_audits.py +950 -0
- package/.next/standalone/fp-cloud-cli/tests/test_auth.py +98 -0
- package/.next/standalone/fp-cloud-cli/tests/test_auth_mode.py +272 -0
- package/.next/standalone/fp-cloud-cli/tests/test_click_compat.py +118 -0
- package/.next/standalone/fp-cloud-cli/tests/test_client.py +299 -0
- package/.next/standalone/fp-cloud-cli/tests/test_commands.py +814 -0
- package/.next/standalone/fp-cloud-cli/tests/test_config.py +99 -0
- package/.next/standalone/fp-cloud-cli/tests/test_dashboards_agent.py +340 -0
- package/.next/standalone/fp-cloud-cli/tests/test_dates.py +76 -0
- package/.next/standalone/fp-cloud-cli/tests/test_enforcement_logic.py +481 -0
- package/.next/standalone/fp-cloud-cli/tests/test_facets.py +170 -0
- package/.next/standalone/fp-cloud-cli/tests/test_failproofai_home.py +722 -0
- package/.next/standalone/fp-cloud-cli/tests/test_fp_home_contract.py +198 -0
- package/.next/standalone/fp-cloud-cli/tests/test_hardening.py +186 -0
- package/.next/standalone/fp-cloud-cli/tests/test_help_table_coverage.py +127 -0
- package/.next/standalone/fp-cloud-cli/tests/test_keys_queries.py +496 -0
- package/.next/standalone/fp-cloud-cli/tests/test_list.py +59 -0
- package/.next/standalone/fp-cloud-cli/tests/test_multivalue.py +183 -0
- package/.next/standalone/fp-cloud-cli/tests/test_no_customer_identifiers.py +168 -0
- package/.next/standalone/fp-cloud-cli/tests/test_operator.py +492 -0
- package/.next/standalone/fp-cloud-cli/tests/test_orgs.py +692 -0
- package/.next/standalone/fp-cloud-cli/tests/test_output.py +1732 -0
- package/.next/standalone/fp-cloud-cli/tests/test_policy_check.py +191 -0
- package/.next/standalone/fp-cloud-cli/tests/test_readme_matches_reality.py +125 -0
- package/.next/standalone/fp-cloud-cli/tests/test_review_fixes.py +161 -0
- package/.next/standalone/fp-cloud-cli/tests/test_telemetry_completeness.py +90 -0
- package/.next/standalone/fp-cloud-cli/tests/test_usage.py +115 -0
- package/.next/standalone/fp-cloud-cli/tests/test_v1_origin_diagnostic.py +70 -0
- package/.next/standalone/fp-cloud-cli/tests/test_v1_routing.py +214 -0
- package/.next/standalone/fp-cloud-cli/tests/test_whoami.py +104 -0
- package/.next/standalone/fp-cloud-cli/uv.lock +552 -0
- package/.next/standalone/package.json +29 -22
- package/.next/standalone/sdk/python/CHANGELOG.md +70 -0
- package/.next/standalone/sdk/python/LICENSE +42 -0
- package/.next/standalone/sdk/python/MANIFEST.in +21 -0
- package/.next/standalone/sdk/python/README.md +466 -0
- package/.next/standalone/sdk/python/docs/README.md +249 -0
- package/.next/standalone/sdk/python/docs/_shared/README.md +43 -0
- package/.next/standalone/sdk/python/docs/_shared/__init__.py +195 -0
- package/.next/standalone/sdk/python/docs/crewai/README.md +328 -0
- package/.next/standalone/sdk/python/docs/crewai/examples/quickstart.py +61 -0
- package/.next/standalone/sdk/python/docs/crewai/examples/research_crew.py +92 -0
- package/.next/standalone/sdk/python/docs/langgraph/README.md +481 -0
- package/.next/standalone/sdk/python/docs/langgraph/examples/quickstart.py +51 -0
- package/.next/standalone/sdk/python/docs/langgraph/examples/research_agent.py +86 -0
- package/.next/standalone/sdk/python/docs/langgraph/examples/supervisor_handoff.py +83 -0
- package/.next/standalone/sdk/python/docs/llama_index/README.md +332 -0
- package/.next/standalone/sdk/python/docs/llama_index/examples/quickstart.py +62 -0
- package/.next/standalone/sdk/python/docs/llama_index/examples/research_agent.py +93 -0
- package/.next/standalone/sdk/python/docs/manual/README.md +491 -0
- package/.next/standalone/sdk/python/docs/manual/examples/quickstart.py +57 -0
- package/.next/standalone/sdk/python/docs/manual/examples/research_agent.py +133 -0
- package/.next/standalone/sdk/python/docs/pydantic_ai/README.md +323 -0
- package/.next/standalone/sdk/python/docs/pydantic_ai/examples/quickstart.py +48 -0
- package/.next/standalone/sdk/python/docs/pydantic_ai/examples/research_agent.py +94 -0
- package/.next/standalone/sdk/python/failproofai_sdk/__init__.py +131 -0
- package/.next/standalone/sdk/python/failproofai_sdk/_context.py +218 -0
- package/.next/standalone/sdk/python/failproofai_sdk/_environment.py +78 -0
- package/.next/standalone/sdk/python/failproofai_sdk/_events.py +752 -0
- package/.next/standalone/sdk/python/failproofai_sdk/_resolver.py +118 -0
- package/.next/standalone/sdk/python/failproofai_sdk/_runtime.py +21 -0
- package/.next/standalone/sdk/python/failproofai_sdk/_schema.py +317 -0
- package/.next/standalone/sdk/python/failproofai_sdk/_scopes.py +422 -0
- package/.next/standalone/sdk/python/failproofai_sdk/_version.py +1 -0
- package/.next/standalone/sdk/python/failproofai_sdk/_writer.py +750 -0
- package/.next/standalone/sdk/python/failproofai_sdk/integrations/__init__.py +274 -0
- package/.next/standalone/sdk/python/failproofai_sdk/integrations/_compat.py +247 -0
- package/.next/standalone/sdk/python/failproofai_sdk/integrations/_core.py +1076 -0
- package/.next/standalone/sdk/python/failproofai_sdk/integrations/crewai.py +1669 -0
- package/.next/standalone/sdk/python/failproofai_sdk/integrations/langchain.py +2151 -0
- package/.next/standalone/sdk/python/failproofai_sdk/integrations/llama_index.py +1588 -0
- package/.next/standalone/sdk/python/failproofai_sdk/integrations/pydantic_ai.py +977 -0
- package/.next/standalone/sdk/python/failproofai_sdk/py.typed +0 -0
- package/.next/standalone/sdk/python/pyproject.toml +92 -0
- package/.next/standalone/sdk/python/skill/SKILL.md +399 -0
- package/.next/standalone/sdk/python/skill/agents/openai.yaml +8 -0
- package/.next/standalone/sdk/python/skill/references/events.md +234 -0
- package/.next/standalone/sdk/python/skill/references/frameworks.md +314 -0
- package/.next/standalone/sdk/python/skill/references/install.md +100 -0
- package/.next/standalone/sdk/python/skill/references/integration.md +352 -0
- package/.next/standalone/sdk/python/tests/__init__.py +0 -0
- package/.next/standalone/sdk/python/tests/conftest.py +169 -0
- package/.next/standalone/sdk/python/tests/integrations/__init__.py +6 -0
- package/.next/standalone/sdk/python/tests/integrations/test_crewai.py +1299 -0
- package/.next/standalone/sdk/python/tests/integrations/test_langchain.py +2338 -0
- package/.next/standalone/sdk/python/tests/integrations/test_llama_index.py +1576 -0
- package/.next/standalone/sdk/python/tests/integrations/test_pydantic_ai.py +1102 -0
- package/.next/standalone/sdk/python/tests/test_context.py +410 -0
- package/.next/standalone/sdk/python/tests/test_docs.py +411 -0
- package/.next/standalone/sdk/python/tests/test_durability.py +1352 -0
- package/.next/standalone/sdk/python/tests/test_encoding.py +571 -0
- package/.next/standalone/sdk/python/tests/test_integrations.py +1127 -0
- package/.next/standalone/sdk/python/tests/test_no_customer_identifiers.py +214 -0
- package/.next/standalone/sdk/python/tests/test_packaging.py +185 -0
- package/.next/standalone/sdk/python/tests/test_resolver_umbrella.py +178 -0
- package/.next/standalone/sdk/python/tests/test_scopes.py +487 -0
- package/.next/standalone/sdk/python/tests/test_sdk.py +923 -0
- package/.next/standalone/sdk/python/tests/test_server_contract.py +650 -0
- package/.next/standalone/sdk/python/tests/test_site_docs.py +371 -0
- package/.next/standalone/sdk/python/tests/test_skill_snippets.py +165 -0
- package/.next/standalone/sdk/python/tests/test_spool_contract.py +287 -0
- package/.next/standalone/sdk/python/tests/test_spool_creation.py +360 -0
- package/.next/standalone/sdk/python/tests/test_wire_format.py +279 -0
- package/.next/standalone/sdk/python/tests/test_zero_dependencies.py +378 -0
- package/.next/standalone/sdk/python/uv.lock +6005 -0
- package/.next/standalone/server.js +1 -1
- package/README.md +77 -21
- package/bin/failproofai.mjs +145 -11
- package/dist/cli.mjs +4482 -2205
- package/dist/index.js +5 -5
- package/dist/worker.mjs +2399 -1978
- package/package.json +29 -22
- package/policy-pack/SHA256SUMS +2 -0
- package/policy-pack/failproofai-pack.json +732 -0
- package/policy-pack/failproofai-pack.mjs +2017 -0
- package/scripts/build-policy-pack.mjs +121 -0
- package/scripts/changelog-section.py +77 -0
- package/scripts/prune-standalone.mjs +3 -0
- package/scripts/python-version.py +232 -0
- package/scripts/translate-docs/cli.ts +21 -0
- package/scripts/translate-docs/mintlify-nav.ts +85 -13
- package/scripts/translate-docs/translator.ts +66 -11
- package/src/audit/cache.ts +40 -3
- package/src/audit/cli.ts +1 -1
- package/src/audit/index.ts +1 -1
- package/src/audit/replay.ts +89 -3
- package/src/audit/report.ts +5 -5
- package/src/audit/schedule-cli.ts +49 -53
- package/src/hooks/builtin-policies.ts +217 -579
- package/src/hooks/cloud-enrollment-cli.ts +66 -27
- package/src/hooks/cloud-managed-policies.ts +6 -1
- package/src/hooks/configure-wizard.ts +1 -1
- package/src/hooks/custom-hooks-loader.ts +89 -6
- package/src/hooks/fp-home.ts +92 -4
- package/src/hooks/fp-reset.ts +26 -2
- package/src/hooks/handler.ts +181 -11
- package/src/hooks/harness-cli.ts +79 -25
- package/src/hooks/hook-activity-store.ts +13 -3
- package/src/hooks/install-prompt.ts +25 -3
- package/src/hooks/manager.ts +418 -172
- package/src/hooks/migrations.ts +2 -2
- package/src/hooks/pack-cli.ts +505 -0
- package/src/hooks/pack-failclosed.ts +189 -0
- package/src/hooks/pack-manifest.ts +344 -0
- package/src/hooks/pack-store.ts +930 -0
- package/src/hooks/policy-catalog.ts +535 -0
- package/src/hooks/policy-evaluator.ts +24 -16
- package/src/hooks/policy-presets.ts +4 -2
- package/src/hooks/policy-registry.ts +8 -2
- package/src/hooks/policy-types.ts +26 -0
- package/src/hooks/session-pause-cli.ts +33 -9
- package/src/hooks/tui.ts +570 -0
- package/src/hooks/types.ts +15 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0_usx0j._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0_zk340._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0agdw2a._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0d1u_na._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0oy4kxb._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0zf034w._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1tvn4wf._.js +0 -3
- package/.next/standalone/.next/server/chunks/_0lxbzdq._.js +0 -3
- package/.next/standalone/.next/server/chunks/_1ger0a2._.js +0 -3
- package/.next/standalone/.next/server/chunks/_1zuiiy3._.js +0 -3
- package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_1iiwm5e._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0kc8_v5._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0kgy9da._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0mhqk5a._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0pltpn8._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0qkcyf-._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0w0x_ok._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1_dfocn._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1bfex62._.js +0 -5
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1kzapg5._.js +0 -6
- package/.next/standalone/.next/static/chunks/36fw6yk1s6x_f.js +0 -1
- package/.next/standalone/.next/static/chunks/3tzq0260n17ae.js +0 -6
- package/.next/standalone/.next/static/chunks/3wq9x0c-7ld5d.css +0 -2
- /package/.next/standalone/.next/static/{ZklXxyA5ygsWSQz2u_zii → nwbyWT06Ud0XdXOrVJyvS}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{ZklXxyA5ygsWSQz2u_zii → nwbyWT06Ud0XdXOrVJyvS}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{ZklXxyA5ygsWSQz2u_zii → nwbyWT06Ud0XdXOrVJyvS}/_ssgManifest.js +0 -0
|
@@ -44,6 +44,24 @@ const MAX_ATTEMPTS =
|
|
|
44
44
|
? parsedMaxAttempts
|
|
45
45
|
: 3;
|
|
46
46
|
|
|
47
|
+
// How far past the source an output may run before a max_tokens stop reads as a
|
|
48
|
+
// repetition loop rather than a large page. Translations of the verbose targets
|
|
49
|
+
// (hi, vi, ja) sit near 2x the source's token estimate; 6x is far outside that
|
|
50
|
+
// band and was ~16x in the observed failure.
|
|
51
|
+
// Validated the same way MAX_TOKENS and MAX_ATTEMPTS above are, and for a
|
|
52
|
+
// sharper reason: `parseInt(...) || 6` accepts a NEGATIVE, and a negative ratio
|
|
53
|
+
// makes `output > source * ratio` true for every response — so a genuinely
|
|
54
|
+
// oversized page would be classified as a runaway and burn all three attempts
|
|
55
|
+
// to arrive exactly where it started.
|
|
56
|
+
const parsedRunawayRatio = Number.parseInt(
|
|
57
|
+
process.env.TRANSLATE_RUNAWAY_RATIO ?? "",
|
|
58
|
+
10,
|
|
59
|
+
);
|
|
60
|
+
const RUNAWAY_RATIO =
|
|
61
|
+
Number.isInteger(parsedRunawayRatio) && parsedRunawayRatio > 0
|
|
62
|
+
? parsedRunawayRatio
|
|
63
|
+
: 6;
|
|
64
|
+
|
|
47
65
|
function getClient(): Anthropic {
|
|
48
66
|
if (!client) {
|
|
49
67
|
// Default 5 retries (up from SDK default of 2) so transient
|
|
@@ -151,10 +169,32 @@ export async function translateContent(
|
|
|
151
169
|
// consolidate publish step. If a page ever legitimately needs more than
|
|
152
170
|
// MAX_TOKENS, raise TRANSLATE_MAX_TOKENS or split the source.
|
|
153
171
|
if (response.stop_reason === "max_tokens") {
|
|
154
|
-
|
|
172
|
+
// TWO different failures wear this stop_reason, and only one of them is
|
|
173
|
+
// "the page is too big". A 16 KB source whose Vietnamese translation
|
|
174
|
+
// emitted 64 000 output tokens — observed on the box, 2026-08-18,
|
|
175
|
+
// reference/cloud-cli.mdx [vi] — is a DEGENERATE SAMPLE: the model fell
|
|
176
|
+
// into a repetition loop. Resampling fixes that; splitting the source does
|
|
177
|
+
// not, and treating it as a size problem sent one page's hiccup on to fail
|
|
178
|
+
// the whole nightly run.
|
|
179
|
+
//
|
|
180
|
+
// The tell is the ratio. Source bytes / 4 is a rough token count, and a
|
|
181
|
+
// faithful translation lands within a small multiple of it — even for the
|
|
182
|
+
// verbose target languages. Far beyond that is the model talking to
|
|
183
|
+
// itself, so the error is marked RETRYABLE and translateValidated spends
|
|
184
|
+
// an attempt on it. A source that genuinely approaches the ceiling keeps
|
|
185
|
+
// the old fail-loud behaviour, because retrying it would burn the budget
|
|
186
|
+
// three times to reach the same place.
|
|
187
|
+
const sourceTokensApprox = Math.max(1, Math.ceil(content.length / 4));
|
|
188
|
+
const runaway = response.usage.output_tokens > sourceTokensApprox * RUNAWAY_RATIO;
|
|
189
|
+
const err = new Error(
|
|
155
190
|
`translation truncated at max_tokens=${MAX_TOKENS} ` +
|
|
156
|
-
`(output ${response.usage.output_tokens} tokens
|
|
191
|
+
`(output ${response.usage.output_tokens} tokens, source ~${sourceTokensApprox}) — ` +
|
|
192
|
+
(runaway
|
|
193
|
+
? "output dwarfs the source, which is a runaway sample rather than an oversized page"
|
|
194
|
+
: "source too large to translate in one request"),
|
|
157
195
|
);
|
|
196
|
+
(err as Error & { retryable?: boolean }).retryable = runaway;
|
|
197
|
+
throw err;
|
|
158
198
|
}
|
|
159
199
|
|
|
160
200
|
const translated =
|
|
@@ -211,15 +251,30 @@ export async function translateValidated(opts: {
|
|
|
211
251
|
? { attempt, maxAttempts: MAX_ATTEMPTS, error: lastError }
|
|
212
252
|
: undefined;
|
|
213
253
|
|
|
214
|
-
//
|
|
215
|
-
//
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
254
|
+
// Transport/auth throws still propagate untouched — they are not validity
|
|
255
|
+
// failures and must never be silently retried as one. The ONE exception is
|
|
256
|
+
// a truncation flagged `retryable` (a runaway sample, see translateContent):
|
|
257
|
+
// that is a bad draw, and a bad draw is exactly what this loop is for.
|
|
258
|
+
let result: Awaited<ReturnType<typeof translateContent>>;
|
|
259
|
+
try {
|
|
260
|
+
result = await translateContent(
|
|
261
|
+
opts.source,
|
|
262
|
+
opts.lang,
|
|
263
|
+
opts.langName,
|
|
264
|
+
opts.model,
|
|
265
|
+
feedback,
|
|
266
|
+
);
|
|
267
|
+
} catch (e) {
|
|
268
|
+
const err = e as Error & { retryable?: boolean };
|
|
269
|
+
if (!err.retryable || attempt === MAX_ATTEMPTS) throw err;
|
|
270
|
+
lastError =
|
|
271
|
+
"The previous attempt ran past the output limit by repeating itself. " +
|
|
272
|
+
"Translate the document once, completely, and stop.";
|
|
273
|
+
console.warn(
|
|
274
|
+
` ${opts.label} -> attempt ${attempt}/${MAX_ATTEMPTS} overran the output limit; retrying`,
|
|
275
|
+
);
|
|
276
|
+
continue;
|
|
277
|
+
}
|
|
223
278
|
inputTokens += result.inputTokens;
|
|
224
279
|
outputTokens += result.outputTokens;
|
|
225
280
|
|
package/src/audit/cache.ts
CHANGED
|
@@ -13,6 +13,7 @@ import { createHash } from "node:crypto";
|
|
|
13
13
|
import { existsSync, mkdirSync, readFileSync, writeFileSync, chmodSync } from "node:fs";
|
|
14
14
|
import { join } from "node:path";
|
|
15
15
|
import { BUILTIN_POLICIES } from "../hooks/builtin-policies";
|
|
16
|
+
import { readInstalledPacks } from "../hooks/pack-manifest";
|
|
16
17
|
import { AUDIT_DETECTORS } from "./detectors";
|
|
17
18
|
import type { TranscriptAuditResult } from "./types";
|
|
18
19
|
import { auditCacheDir } from "../hooks/fp-home";
|
|
@@ -20,14 +21,43 @@ import { auditCacheDir } from "../hooks/fp-home";
|
|
|
20
21
|
let cachedEngineVersion: string | null = null;
|
|
21
22
|
let cachedDetectorVersion: string | null = null;
|
|
22
23
|
|
|
23
|
-
/**
|
|
24
|
-
*
|
|
24
|
+
/**
|
|
25
|
+
* Hash of every builtin policy's name + function body, PLUS the identity of every
|
|
26
|
+
* installed pack. Changes when policy code changes, invalidating downstream
|
|
27
|
+
* caches.
|
|
28
|
+
*
|
|
29
|
+
* Packs belong in this key because they change what a machine would have caught,
|
|
30
|
+
* which is exactly what a cached audit result claims to know. They are folded in
|
|
31
|
+
* by `id|version|sha256` rather than by source text: the pack's bytes are already
|
|
32
|
+
* digest-pinned, and hashing the loaded source instead would drag in the
|
|
33
|
+
* per-load temporary filename the loader rewrites into every import specifier —
|
|
34
|
+
* which changes on every single run and would cold-rescan the whole history each
|
|
35
|
+
* time.
|
|
36
|
+
*
|
|
37
|
+
* **A machine with no packs must hash byte-identically to a build with no pack
|
|
38
|
+
* support at all.** Otherwise merely shipping this feature invalidates every
|
|
39
|
+
* user's audit cache and forces a ~104-second cold rescan on upgrade, for a
|
|
40
|
+
* capability they are not using. Hence the empty pack set contributes nothing —
|
|
41
|
+
* not an empty line, not a separator.
|
|
42
|
+
*/
|
|
25
43
|
function getEngineVersion(): string {
|
|
26
44
|
if (cachedEngineVersion) return cachedEngineVersion;
|
|
27
|
-
const
|
|
45
|
+
const builtinBlob = BUILTIN_POLICIES
|
|
28
46
|
.map((p) => `${p.name}|${p.fn.toString()}`)
|
|
29
47
|
.sort()
|
|
30
48
|
.join("\n");
|
|
49
|
+
// Never throws by contract, but this runs inside the audit's own try/catch-free
|
|
50
|
+
// path and a cache key is not worth taking the run down for.
|
|
51
|
+
let packBlob = "";
|
|
52
|
+
try {
|
|
53
|
+
packBlob = readInstalledPacks()
|
|
54
|
+
.packs.map((pack) => `${pack.id}|${pack.version}|${pack.sha256}`)
|
|
55
|
+
.sort()
|
|
56
|
+
.join("\n");
|
|
57
|
+
} catch {
|
|
58
|
+
packBlob = "";
|
|
59
|
+
}
|
|
60
|
+
const blob = packBlob ? `${builtinBlob}\n${packBlob}` : builtinBlob;
|
|
31
61
|
cachedEngineVersion = createHash("sha1").update(blob).digest("hex").slice(0, 16);
|
|
32
62
|
return cachedEngineVersion;
|
|
33
63
|
}
|
|
@@ -43,6 +73,13 @@ function getDetectorVersion(): string {
|
|
|
43
73
|
return cachedDetectorVersion;
|
|
44
74
|
}
|
|
45
75
|
|
|
76
|
+
/** Exposed for `engine-version-packs.test.ts`, which pins the upgrade-cost
|
|
77
|
+
* guarantee: a machine with no packs must hash exactly as it did before packs
|
|
78
|
+
* existed. Nothing else should call this. */
|
|
79
|
+
export function getEngineVersionForTest(): string {
|
|
80
|
+
return getEngineVersion();
|
|
81
|
+
}
|
|
82
|
+
|
|
46
83
|
function getCachePathFor(transcriptPath: string): string {
|
|
47
84
|
const root = auditCacheDir();
|
|
48
85
|
const key = createHash("sha1").update(transcriptPath).digest("hex");
|
package/src/audit/cli.ts
CHANGED
|
@@ -58,7 +58,7 @@ export const EXIT_AUDIT_ALREADY_RUNNING = 75;
|
|
|
58
58
|
export const AUDIT_STAGES: ReadonlyArray<{ label: string; detail: string }> = [
|
|
59
59
|
{ label: "discovering transcripts", detail: "walking ~/.claude, ~/.codex, ~/.cursor, …" },
|
|
60
60
|
{ label: "parsing session logs", detail: "reading JSONL + sqlite session stores" },
|
|
61
|
-
{ label: "running policy checks", detail: "replaying
|
|
61
|
+
{ label: "running policy checks", detail: "replaying every policy against each tool call" },
|
|
62
62
|
{ label: "aggregating results", detail: "counting hits, ranking by frequency" },
|
|
63
63
|
];
|
|
64
64
|
|
package/src/audit/index.ts
CHANGED
|
@@ -261,7 +261,7 @@ function aggregateResults(
|
|
|
261
261
|
|
|
262
262
|
export async function runAudit(opts: RunAuditOptions = {}): Promise<AuditResult> {
|
|
263
263
|
const startedAt = Date.now();
|
|
264
|
-
initReplay();
|
|
264
|
+
await initReplay();
|
|
265
265
|
try {
|
|
266
266
|
return await runAuditInner(opts, startedAt);
|
|
267
267
|
} finally {
|
package/src/audit/replay.ts
CHANGED
|
@@ -13,13 +13,19 @@
|
|
|
13
13
|
* execSync against live git, so they never fire on PreToolUse/PostToolUse
|
|
14
14
|
* replay — no explicit skip needed.
|
|
15
15
|
*/
|
|
16
|
+
import { resolve } from "node:path";
|
|
17
|
+
import { existsSync } from "node:fs";
|
|
16
18
|
import type { EvaluationResult } from "../hooks/policy-evaluator";
|
|
17
19
|
import { evaluatePolicies } from "../hooks/policy-evaluator";
|
|
18
20
|
import { BUILTIN_POLICIES, registerBuiltinPolicies } from "../hooks/builtin-policies";
|
|
21
|
+
import { PACK_ENTRY_ASSET, bundledPackDir } from "../hooks/pack-store";
|
|
22
|
+
import { loadCustomHooks } from "../hooks/custom-hooks-loader";
|
|
23
|
+
import { clearCustomHooks } from "../hooks/custom-hooks-registry";
|
|
19
24
|
import {
|
|
20
25
|
clearPolicies,
|
|
21
26
|
getAllPolicies,
|
|
22
27
|
normalizePolicyName,
|
|
28
|
+
registerPolicy,
|
|
23
29
|
setAllPolicies,
|
|
24
30
|
} from "../hooks/policy-registry";
|
|
25
31
|
import type { RegisteredPolicy } from "../hooks/policy-types";
|
|
@@ -44,17 +50,97 @@ let savedSnapshot: RegisteredPolicy[] | null = null;
|
|
|
44
50
|
* shows what *could* be caught, not just what's currently enabled. Called
|
|
45
51
|
* once per `runAudit` invocation. Snapshots the existing registry so it can
|
|
46
52
|
* be restored by `restoreReplay()` once the audit is done. */
|
|
47
|
-
export function initReplay(): void {
|
|
53
|
+
export async function initReplay(): Promise<void> {
|
|
48
54
|
if (initialized) return;
|
|
49
55
|
savedSnapshot = getAllPolicies();
|
|
50
56
|
clearPolicies();
|
|
51
57
|
const enabled = BUILTIN_POLICIES
|
|
52
58
|
.map((p) => p.name)
|
|
53
59
|
.filter((n) => !SKIP_POLICIES.has(normalizePolicyName(n)));
|
|
54
|
-
registerBuiltinPolicies(enabled);
|
|
60
|
+
if (!(await registerFromVendoredPack(enabled))) registerBuiltinPolicies(enabled);
|
|
55
61
|
initialized = true;
|
|
56
62
|
}
|
|
57
63
|
|
|
64
|
+
/**
|
|
65
|
+
* Register the audit's policies from the pack that ships inside the package,
|
|
66
|
+
* rather than from implementations compiled into this build.
|
|
67
|
+
*
|
|
68
|
+
* The audit scores by RUNNING the policies — three of its four penalty buckets
|
|
69
|
+
* are replay hits — so the day the builtins stop being compiled in, this is
|
|
70
|
+
* what keeps `failproofai audit` reporting the same findings and the same score
|
|
71
|
+
* for the same transcripts. The pack carries the identical functions:
|
|
72
|
+
* `builtin-pack-conformance.test.ts` replays a corpus through both and asserts
|
|
73
|
+
* the verdicts do not diverge.
|
|
74
|
+
*
|
|
75
|
+
* Two things it must get right, or the audit quietly changes:
|
|
76
|
+
*
|
|
77
|
+
* - The pack cannot carry `block-failproofai-commands`, because `alwaysOn` is
|
|
78
|
+
* refused by the pack loader by design — a downloaded file that no local
|
|
79
|
+
* command can switch off. It is registered from the compiled side, so the
|
|
80
|
+
* replayed set is the same 39 either way.
|
|
81
|
+
* - The skip list still applies. `warn-repeated-tool-calls` writes a per-session
|
|
82
|
+
* sidecar into the user's real transcript directory on every evaluation.
|
|
83
|
+
*
|
|
84
|
+
* Returns false when there is no vendored pack to read — a source checkout that
|
|
85
|
+
* has not run `build:pack`, or a tarball packed without it — and the caller
|
|
86
|
+
* falls back to the compiled implementations. An audit that silently scored on
|
|
87
|
+
* fewer policies would be worse than either.
|
|
88
|
+
*/
|
|
89
|
+
async function registerFromVendoredPack(enabled: string[]): Promise<boolean> {
|
|
90
|
+
const dir = bundledPackDir();
|
|
91
|
+
if (!dir) return false;
|
|
92
|
+
const entry = resolve(dir, PACK_ENTRY_ASSET);
|
|
93
|
+
if (!existsSync(entry)) return false;
|
|
94
|
+
|
|
95
|
+
const wanted = new Set(enabled);
|
|
96
|
+
let hooks;
|
|
97
|
+
try {
|
|
98
|
+
clearCustomHooks();
|
|
99
|
+
hooks = await loadCustomHooks(entry, { strict: true });
|
|
100
|
+
} catch {
|
|
101
|
+
return false;
|
|
102
|
+
} finally {
|
|
103
|
+
clearCustomHooks();
|
|
104
|
+
}
|
|
105
|
+
if (hooks.length === 0) return false;
|
|
106
|
+
const fromPack = new Map(hooks.map((hook) => [hook.name, hook]));
|
|
107
|
+
|
|
108
|
+
// Registered in CATALOG ORDER, taking the pack's function where it has one and
|
|
109
|
+
// the compiled one for the guard the pack may not carry.
|
|
110
|
+
//
|
|
111
|
+
// Order is not cosmetic here. `getPoliciesForEvent` sorts by priority only and
|
|
112
|
+
// V8's sort is stable, so registration order decides EVALUATION order, and
|
|
113
|
+
// `evaluatePolicies` stops at the first deny — which means the order decides
|
|
114
|
+
// which policy is CREDITED for a hit. Appending the always-on guard after the
|
|
115
|
+
// pack instead of at its catalog position moved it from index 11 to last, and
|
|
116
|
+
// re-attributed 3 events in a 23,477-event corpus: 456 -> 453 for the guard,
|
|
117
|
+
// with the denies it used to shadow surfacing as block-force-push and
|
|
118
|
+
// block-gh-pipeline. The audit's per-policy counts are what a user reads, so
|
|
119
|
+
// that is a changed audit, not a changed internal.
|
|
120
|
+
let registered = 0;
|
|
121
|
+
for (const policy of BUILTIN_POLICIES) {
|
|
122
|
+
if (!wanted.has(policy.name)) continue;
|
|
123
|
+
const packHook = fromPack.get(policy.name);
|
|
124
|
+
if (policy.alwaysOn || !packHook) {
|
|
125
|
+
registerPolicy(policy.name, policy.description, policy.fn, policy.match, 0, policy.params);
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
registerPolicy(
|
|
129
|
+
packHook.name,
|
|
130
|
+
packHook.description ?? policy.description,
|
|
131
|
+
packHook.fn,
|
|
132
|
+
packHook.match ?? policy.match,
|
|
133
|
+
0,
|
|
134
|
+
policy.params,
|
|
135
|
+
);
|
|
136
|
+
registered += 1;
|
|
137
|
+
}
|
|
138
|
+
// Nothing came from the pack: it loaded but carried none of the names the
|
|
139
|
+
// audit replays. Falling back is more honest than scoring on the compiled set
|
|
140
|
+
// while claiming the pack lane ran.
|
|
141
|
+
return registered > 0;
|
|
142
|
+
}
|
|
143
|
+
|
|
58
144
|
/** Restore the registry to whatever was there before `initReplay()`. Safe to
|
|
59
145
|
* call when not initialized (no-op). Always paired with `initReplay()` in a
|
|
60
146
|
* try/finally inside `runAudit()`. */
|
|
@@ -87,7 +173,7 @@ export interface ReplayHit {
|
|
|
87
173
|
* is reported too, so sanitize policies that emit informational notes still
|
|
88
174
|
* surface in the audit. */
|
|
89
175
|
export async function replayEvent(event: NormalizedToolEvent): Promise<ReplayHit[]> {
|
|
90
|
-
if (!initialized) initReplay();
|
|
176
|
+
if (!initialized) await initReplay();
|
|
91
177
|
|
|
92
178
|
const session: SessionMetadata = {
|
|
93
179
|
sessionId: event.sessionId,
|
package/src/audit/report.ts
CHANGED
|
@@ -263,16 +263,16 @@ export function formatMarkdown(result: AuditResult): string {
|
|
|
263
263
|
out.push("## TL;DR");
|
|
264
264
|
out.push("");
|
|
265
265
|
if (totalHits === 0) {
|
|
266
|
-
out.push("Clean run — the
|
|
266
|
+
out.push("Clean run — the agent didn't do anything `failproofai` catches in this window.");
|
|
267
267
|
} else {
|
|
268
268
|
out.push(
|
|
269
|
-
`Over ${result.transcripts.scanned} sessions, my
|
|
270
|
-
`${totalProtected} were
|
|
271
|
-
`**${totalSlipping} slipped through**
|
|
269
|
+
`Over ${result.transcripts.scanned} sessions, my agent did **${totalHits} things \`failproofai\` caught**: ` +
|
|
270
|
+
`${totalProtected} were blocked in real time by my current config; ` +
|
|
271
|
+
`**${totalSlipping} slipped through** and were only caught by the audit.`,
|
|
272
272
|
);
|
|
273
273
|
}
|
|
274
274
|
out.push("");
|
|
275
|
-
out.push("> [failproofai](https://github.com/FailproofAI/failproofai) is a hook-based policy engine for
|
|
275
|
+
out.push("> [failproofai](https://github.com/FailproofAI/failproofai) is a hook-based policy engine for 12 agent harnesses — coding CLIs, chat gateways, and self-hosted assistants. The `audit` command replays past agent sessions through every builtin policy to surface patterns that were (or could've been) stopped.");
|
|
276
276
|
out.push("");
|
|
277
277
|
|
|
278
278
|
if (totalHits === 0) return out.join("\n");
|
|
@@ -37,8 +37,13 @@ import {
|
|
|
37
37
|
ANSI_RESET,
|
|
38
38
|
brandAnsi,
|
|
39
39
|
colorsEnabled,
|
|
40
|
+
optsFor,
|
|
40
41
|
outro,
|
|
42
|
+
printBlock,
|
|
43
|
+
rows as kitRows,
|
|
44
|
+
stack,
|
|
41
45
|
step,
|
|
46
|
+
title,
|
|
42
47
|
} from "../hooks/tui";
|
|
43
48
|
|
|
44
49
|
/** Mirrors `fp-config`'s own bounds so the error can name them before writing. */
|
|
@@ -62,30 +67,6 @@ const green = (s: string) => wrap(brandAnsi("guide"), s);
|
|
|
62
67
|
const dim = (s: string) => wrap(ANSI_DIM, s);
|
|
63
68
|
const bold = (s: string) => wrap(ANSI_BOLD, s);
|
|
64
69
|
|
|
65
|
-
/**
|
|
66
|
-
* The readout's left margin.
|
|
67
|
-
*
|
|
68
|
-
* Deliberately NOT the `│` spine the sign-in uses. A spine means "a flow is
|
|
69
|
-
* happening, with a beginning and an end"; `--status` is a snapshot of a
|
|
70
|
-
* machine, and hanging one off a frame that never opened reads as an unfinished
|
|
71
|
-
* wizard. Alignment does the work here instead.
|
|
72
|
-
*/
|
|
73
|
-
const rail = () => " ";
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* One labelled row of the `--status` readout.
|
|
77
|
-
*
|
|
78
|
-
* A fixed label column so the values line up into a second column that can be
|
|
79
|
-
* read straight down — the whole point of this command is answering "what is
|
|
80
|
-
* this machine doing" at a glance, and a ragged left edge makes four facts read
|
|
81
|
-
* as four sentences.
|
|
82
|
-
*/
|
|
83
|
-
const LABEL_WIDTH = 15;
|
|
84
|
-
function row(label: string, value: string, note?: string): string {
|
|
85
|
-
const gap = " ".repeat(Math.max(1, LABEL_WIDTH - label.length));
|
|
86
|
-
return `${rail()} ${dim(label)}${gap}${value}${note ? ` ${dim(note)}` : ""}`;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
70
|
/**
|
|
90
71
|
* Turn scheduled audits on, signing in first if needed.
|
|
91
72
|
*
|
|
@@ -219,62 +200,77 @@ export function runScheduleStatus(): void {
|
|
|
219
200
|
const daemon = daemonServiceStatus();
|
|
220
201
|
|
|
221
202
|
const on = config.audit.auto;
|
|
222
|
-
const
|
|
203
|
+
const opts = optsFor(process.stdout);
|
|
204
|
+
const detail: Array<[string, string]> = [];
|
|
223
205
|
|
|
224
|
-
// The state first
|
|
225
|
-
//
|
|
226
|
-
//
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
206
|
+
// The state first, because everything below is detail about a machine that is
|
|
207
|
+
// either doing this or not, and reading the detail first answers a question
|
|
208
|
+
// nobody has asked yet. It is a ROW like the rest, though: the headline used
|
|
209
|
+
// to be hand-padded to a different column than `row()` used, which is why this
|
|
210
|
+
// readout printed its first value at column 21 and every other at 18.
|
|
211
|
+
detail.push([
|
|
212
|
+
"scheduled audit",
|
|
213
|
+
on
|
|
214
|
+
? `${green("on")}${dim(` every ${config.audit.intervalDays} days`)}`
|
|
215
|
+
: dim("off"),
|
|
216
|
+
]);
|
|
232
217
|
|
|
233
218
|
// A session whose refresh window has closed cannot mint another access token,
|
|
234
219
|
// so it is a destination in name only. Showing the address for one would tell
|
|
235
220
|
// somebody their digests are going somewhere they are not.
|
|
236
221
|
const live = auth && auth.refresh_expires_at * 1000 > Date.now() ? auth : null;
|
|
237
|
-
|
|
222
|
+
detail.push(["reports to", live ? live.user.email : dim("— signed out")]);
|
|
238
223
|
if (on && !live) {
|
|
239
224
|
// The state the reporter surfaces as "signed-out". Named here for the same
|
|
240
225
|
// reason the settings panel names it: the scans keep running, so silence
|
|
241
226
|
// about the digests would look like the feature failing.
|
|
242
|
-
|
|
227
|
+
detail.push(["", pink("scans continue; digests are paused until you sign in")]);
|
|
243
228
|
} else if (on && config.audit.reportsConsentedAt === undefined) {
|
|
244
229
|
// Signed in, scheduled, and still not sending: this machine set `audit.auto`
|
|
245
230
|
// when it only meant "scan locally", so nothing has consented to the digest
|
|
246
231
|
// leaving the box. Without this row the status screen would show a healthy
|
|
247
232
|
// schedule and a live address and still mail nothing, with no explanation
|
|
248
233
|
// anywhere the user can see.
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
234
|
+
detail.push([
|
|
235
|
+
"",
|
|
236
|
+
pink("scans continue; digests need a fresh opt-in — run `--schedule` to turn them on"),
|
|
237
|
+
]);
|
|
252
238
|
}
|
|
253
239
|
|
|
254
|
-
|
|
240
|
+
detail.push(["daemon", describeDaemon(daemon)]);
|
|
255
241
|
|
|
256
242
|
if (sched?.nextDueAtMs != null && on) {
|
|
257
|
-
|
|
243
|
+
detail.push(["next scan", untilPhrase(sched.nextDueAtMs)]);
|
|
258
244
|
}
|
|
259
245
|
if (sched?.lastRunAtMs != null) {
|
|
260
246
|
const exit = sched.lastExitCode;
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
),
|
|
267
|
-
);
|
|
247
|
+
const failed = exit != null && exit !== 0 && exit !== 75;
|
|
248
|
+
detail.push([
|
|
249
|
+
"last scheduled",
|
|
250
|
+
agoPhrase(sched.lastRunAtMs) + (failed ? ` ${pink(`exit ${exit}`)}` : ""),
|
|
251
|
+
]);
|
|
268
252
|
}
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
253
|
+
detail.push([
|
|
254
|
+
"last result",
|
|
255
|
+
meta?.cachedAt ? agoPhrase(Date.parse(meta.cachedAt)) : dim("none yet"),
|
|
256
|
+
]);
|
|
272
257
|
if (machine?.last_reported_at) {
|
|
273
|
-
|
|
258
|
+
detail.push(["last reported", agoPhrase(Date.parse(machine.last_reported_at))]);
|
|
274
259
|
}
|
|
275
|
-
out.push("");
|
|
276
260
|
|
|
277
|
-
|
|
261
|
+
printBlock(
|
|
262
|
+
process.stdout,
|
|
263
|
+
stack(
|
|
264
|
+
// The meta carries a fact, not the word "status" — a heading that repeats
|
|
265
|
+
// the command name tells the reader nothing they did not just type.
|
|
266
|
+
title(
|
|
267
|
+
"failproofai audit",
|
|
268
|
+
on ? `scheduled · every ${config.audit.intervalDays} days` : "not scheduled",
|
|
269
|
+
opts,
|
|
270
|
+
),
|
|
271
|
+
kitRows(detail, opts),
|
|
272
|
+
),
|
|
273
|
+
);
|
|
278
274
|
}
|
|
279
275
|
|
|
280
276
|
function describeDaemon(status: ReturnType<typeof daemonServiceStatus>): string {
|