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
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
daemonVersionSkew,
|
|
21
21
|
} from "./daemon-service";
|
|
22
22
|
import { clearActiveCloudManagedPolicies } from "./cloud-managed-policies";
|
|
23
|
+
import { optsFor, rows as kitRows, stack, warning } from "./tui";
|
|
23
24
|
import { deliveryHealth, deliveryHealthLine } from "./delivery-health";
|
|
24
25
|
import { readVersionFile, readCredentials } from "./fp-config";
|
|
25
26
|
import { version as cliVersion } from "../../package.json";
|
|
@@ -380,18 +381,36 @@ export function versionStatusLines(): string[] {
|
|
|
380
381
|
];
|
|
381
382
|
}
|
|
382
383
|
|
|
383
|
-
export
|
|
384
|
+
export interface ConnectionStatusReport {
|
|
385
|
+
/** Label/value pairs, unrendered, so a caller printing several blocks in one
|
|
386
|
+
* window can align them all to ONE column instead of each block to its own. */
|
|
387
|
+
rows: Array<[string, string]>;
|
|
388
|
+
/** Lines for the one warning shape, already stripped of their own gutter. */
|
|
389
|
+
warnings: string[];
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* The connection half of `--status`, as data.
|
|
394
|
+
*
|
|
395
|
+
* Separate from the rendering because `config --status` prints this block and
|
|
396
|
+
* the pause block together: rendered independently they computed two different
|
|
397
|
+
* label columns and the window read as two commands' output stacked up.
|
|
398
|
+
*/
|
|
399
|
+
export function connectionStatusReport(
|
|
384
400
|
daemonStatus = daemonServiceStatus,
|
|
385
|
-
/** Print the full machine id rather than a short prefix. */
|
|
386
401
|
verbose = false,
|
|
387
|
-
):
|
|
402
|
+
): ConnectionStatusReport {
|
|
388
403
|
const envUrl = process.env.FAILPROOFAI_CLOUD_URL;
|
|
389
404
|
if (envUrl) {
|
|
390
405
|
// Env wins over the file in the daemon, so reporting the file here would
|
|
391
406
|
// describe a configuration that is not in effect.
|
|
392
|
-
return
|
|
393
|
-
|
|
394
|
-
|
|
407
|
+
return {
|
|
408
|
+
rows: [
|
|
409
|
+
["cloud", `configured by environment (${envUrl})`],
|
|
410
|
+
["", `takes precedence over ${cloudCredentialPath()}`],
|
|
411
|
+
],
|
|
412
|
+
warnings: [],
|
|
413
|
+
};
|
|
395
414
|
}
|
|
396
415
|
const creds = readCloudCredentials();
|
|
397
416
|
const ingest = readIngestCredential();
|
|
@@ -400,13 +419,13 @@ export function connectionStatusLines(
|
|
|
400
419
|
// activity but pulling no policy, or the reverse, is a state worth seeing at
|
|
401
420
|
// a glance — it is exactly the half-configured case this command exists to
|
|
402
421
|
// catch, and two unrelated lines made it easy to miss.
|
|
403
|
-
if (!creds && !ingest) return ["
|
|
422
|
+
if (!creds && !ingest) return { rows: [["cloud", "not connected"]], warnings: [] };
|
|
404
423
|
|
|
405
424
|
// Recorded at connect time from the server's own answer, never guessed from
|
|
406
425
|
// the URL: one deployment hosts many orgs, so the host says nothing about
|
|
407
426
|
// which one this machine's data lands in. Absent against a server with no
|
|
408
427
|
// introspect endpoint, and on credentials written before this was recorded —
|
|
409
|
-
// in both cases the
|
|
428
|
+
// in both cases the row is simply omitted rather than guessed at.
|
|
410
429
|
const org = readCredentials().org;
|
|
411
430
|
const orgLine = org
|
|
412
431
|
? org.name && org.slug
|
|
@@ -414,22 +433,25 @@ export function connectionStatusLines(
|
|
|
414
433
|
: (org.name ?? org.slug ?? org.id)
|
|
415
434
|
: undefined;
|
|
416
435
|
|
|
417
|
-
|
|
436
|
+
// Rows, not a prose lead. The URL, the machine label and the masked token used
|
|
437
|
+
// to be crammed into one sentence — three separate facts, none of them
|
|
438
|
+
// scannable, and the two that follow were already a hand-padded column that
|
|
439
|
+
// agreed with nothing else the CLI prints.
|
|
440
|
+
const detail: Array<[string, string]> = [];
|
|
418
441
|
if (creds) {
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
lines.push(` Policy pulling centrally-managed policies.`);
|
|
442
|
+
detail.push(["cloud", `connected to ${creds.url}`]);
|
|
443
|
+
detail.push(["machine", describeMachine(creds.machineId, creds.machineLabel, verbose)]);
|
|
444
|
+
detail.push(["token", maskToken(creds.token)]);
|
|
445
|
+
detail.push(["policy", "pulling centrally-managed policies"]);
|
|
424
446
|
} else {
|
|
425
|
-
|
|
426
|
-
|
|
447
|
+
detail.push(["cloud", `connected to ${cloudBaseFor(ingest!.url)} for reporting only`]);
|
|
448
|
+
detail.push(["policy", "NOT pulling — this machine enforces only its local policies"]);
|
|
427
449
|
}
|
|
428
450
|
|
|
429
|
-
if (orgLine)
|
|
451
|
+
if (orgLine) detail.push(["org", orgLine]);
|
|
430
452
|
|
|
431
453
|
if (ingest) {
|
|
432
|
-
// Everything above this
|
|
454
|
+
// Everything above this row is read from the credential FILE, which
|
|
433
455
|
// records what was true at `--connect` time and is never revisited. A key
|
|
434
456
|
// that has since been revoked, expired, or had its org disabled leaves that
|
|
435
457
|
// file byte-for-byte correct while nothing arrives — which is how a machine
|
|
@@ -439,16 +461,33 @@ export function connectionStatusLines(
|
|
|
439
461
|
// so it overrides the cheerful line rather than being appended after it.
|
|
440
462
|
const health = deliveryHealth();
|
|
441
463
|
const rejection = deliveryHealthLine(health);
|
|
442
|
-
|
|
443
|
-
lines.push(` Dashboard ${rejection}`);
|
|
444
|
-
} else {
|
|
445
|
-
lines.push(` Dashboard sending hook activity to ${ingest.url}.`);
|
|
446
|
-
}
|
|
464
|
+
detail.push(["dashboard", rejection ?? `sending hook activity to ${ingest.url}`]);
|
|
447
465
|
} else {
|
|
448
|
-
|
|
449
|
-
|
|
466
|
+
detail.push([
|
|
467
|
+
"dashboard",
|
|
468
|
+
"NOT sending — nothing from this machine appears in the dashboard",
|
|
469
|
+
]);
|
|
470
|
+
detail.push(["", `re-run: failproofai config --connect ${creds!.url} --token <key>`]);
|
|
450
471
|
}
|
|
451
472
|
|
|
452
|
-
|
|
453
|
-
|
|
473
|
+
// The daemon block is a warning, so it takes the one warning shape rather than
|
|
474
|
+
// its own indented prose.
|
|
475
|
+
const daemonLines = daemonWarning(daemonStatus())
|
|
476
|
+
.map((l) => l.replace(/^[!\s]+/, "").trim())
|
|
477
|
+
.filter((l) => l.length > 0);
|
|
478
|
+
return { rows: detail, warnings: daemonLines };
|
|
454
479
|
}
|
|
480
|
+
|
|
481
|
+
/** The same report, rendered on its own — for any caller printing only this. */
|
|
482
|
+
export function connectionStatusLines(
|
|
483
|
+
daemonStatus = daemonServiceStatus,
|
|
484
|
+
/** Print the full machine id rather than a short prefix. */
|
|
485
|
+
verbose = false,
|
|
486
|
+
): string[] {
|
|
487
|
+
const opts = optsFor(process.stdout);
|
|
488
|
+
const report = connectionStatusReport(daemonStatus, verbose);
|
|
489
|
+
return stack(
|
|
490
|
+
kitRows(report.rows, opts),
|
|
491
|
+
report.warnings.length > 0 ? warning(report.warnings, opts) : null,
|
|
492
|
+
);
|
|
493
|
+
}
|
|
@@ -102,7 +102,12 @@ function parseManifest(value: unknown): ActiveManifest {
|
|
|
102
102
|
return { schemaVersion: raw.schemaVersion as number, deployment: deployment as number, policies };
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
-
|
|
105
|
+
/**
|
|
106
|
+
* Shared with `pack-manifest.ts` deliberately. This is a path-escape guard on a
|
|
107
|
+
* file that is about to be IMPORTED; two copies of it would be two things to
|
|
108
|
+
* harden and one to forget.
|
|
109
|
+
*/
|
|
110
|
+
export function resolveManagedPath(root: string, candidate: string): string {
|
|
106
111
|
if (!candidate || isAbsolute(candidate)) throw new Error(`unsafe managed policy path ${JSON.stringify(candidate)}`);
|
|
107
112
|
const absolute = resolve(root, candidate);
|
|
108
113
|
const lexicalRelative = relative(root, absolute);
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* 0. Daemon — REQUIRED. Asks for sudo first, on a clean terminal.
|
|
7
7
|
* 1. Where — inferred from cwd, then confirmed (global / project / both)
|
|
8
8
|
* 2. Policies — multi-select of themed presets (combine any) or Everything
|
|
9
|
-
* 3. Assistants— multi-select of agent
|
|
9
|
+
* 3. Assistants— multi-select of agent harnesses (detected + install-ahead)
|
|
10
10
|
* 4. Connect — paste an API key, or stay fully local
|
|
11
11
|
* 5. Review — shows exactly which files change, then Apply.
|
|
12
12
|
*
|
|
@@ -31,6 +31,7 @@ import { trackHookEvent } from "./hook-telemetry";
|
|
|
31
31
|
import { getInstanceId } from "../../lib/telemetry-id";
|
|
32
32
|
import type { CustomHook } from "./policy-types";
|
|
33
33
|
import type { CloudManagedPolicyArtifact } from "./cloud-managed-policies";
|
|
34
|
+
import type { ResolvedPack } from "./pack-manifest";
|
|
34
35
|
import { customPoliciesDir, shimsDir } from "./fp-home";
|
|
35
36
|
|
|
36
37
|
const LOADING_KEY = "__FAILPROOFAI_LOADING_HOOKS__";
|
|
@@ -172,6 +173,11 @@ async function importWithDeadline(fileUrl: string): Promise<void> {
|
|
|
172
173
|
* Load a single policy file into the globalThis custom hooks registry.
|
|
173
174
|
* Does NOT clear the registry — caller is responsible for that.
|
|
174
175
|
*/
|
|
176
|
+
export interface PolicyLoadFailure {
|
|
177
|
+
type: "module_not_found" | "syntax_error" | "load_timeout" | "runtime_error" | "path_missing";
|
|
178
|
+
reason: string;
|
|
179
|
+
}
|
|
180
|
+
|
|
175
181
|
async function loadSingleFile(
|
|
176
182
|
absPath: string,
|
|
177
183
|
opts?: {
|
|
@@ -180,7 +186,7 @@ async function loadSingleFile(
|
|
|
180
186
|
/** Cloud-managed policies pass their pinned digest for load-time re-verification. */
|
|
181
187
|
verifyEntrySha?: string;
|
|
182
188
|
},
|
|
183
|
-
): Promise<
|
|
189
|
+
): Promise<PolicyLoadFailure | null> {
|
|
184
190
|
const g = globalThis as Record<string, unknown>;
|
|
185
191
|
g[LOADING_KEY] = true;
|
|
186
192
|
|
|
@@ -208,7 +214,7 @@ async function loadSingleFile(
|
|
|
208
214
|
const cached = policyModuleCache.get(absPath);
|
|
209
215
|
if (cached?.fingerprint === fingerprint) {
|
|
210
216
|
for (const hook of cached.hooks) customPolicies.add({ ...hook });
|
|
211
|
-
return;
|
|
217
|
+
return null;
|
|
212
218
|
}
|
|
213
219
|
|
|
214
220
|
const entryTmp = absPath + tmpSuffix;
|
|
@@ -222,6 +228,7 @@ async function loadSingleFile(
|
|
|
222
228
|
.slice(hooksBefore)
|
|
223
229
|
.map((hook) => ({ ...hook })),
|
|
224
230
|
});
|
|
231
|
+
return null;
|
|
225
232
|
} catch (err) {
|
|
226
233
|
const msg = err instanceof Error ? err.message : String(err);
|
|
227
234
|
const errorType = /Cannot find module|MODULE_NOT_FOUND|ENOENT/i.test(msg)
|
|
@@ -239,6 +246,7 @@ async function loadSingleFile(
|
|
|
239
246
|
});
|
|
240
247
|
if (opts?.strict) throw new Error(`Failed to load custom hooks from ${absPath}: ${msg}`);
|
|
241
248
|
hookLogError(`failed to load custom hooks from ${absPath}: ${msg}`);
|
|
249
|
+
return { type: errorType, reason: msg };
|
|
242
250
|
} finally {
|
|
243
251
|
g[LOADING_KEY] = false;
|
|
244
252
|
await cleanupTmpFiles(tmpFiles);
|
|
@@ -293,6 +301,8 @@ export interface ConventionSource {
|
|
|
293
301
|
export interface LoadAllResult {
|
|
294
302
|
hooks: CustomHook[];
|
|
295
303
|
conventionSources: ConventionSource[];
|
|
304
|
+
/** Import failures keyed by pack id, including artifacts that registered no hooks. */
|
|
305
|
+
packFailures: Map<string, PolicyLoadFailure>;
|
|
296
306
|
}
|
|
297
307
|
|
|
298
308
|
export function customPolicyId(file: string, name: string): string {
|
|
@@ -330,17 +340,53 @@ function warnSkippedPolicyFiles(dir: string, scope: "project" | "user"): void {
|
|
|
330
340
|
);
|
|
331
341
|
}
|
|
332
342
|
|
|
343
|
+
/**
|
|
344
|
+
* A pack's manifest declares what it contains; its artifact decides what runs.
|
|
345
|
+
* Nothing binds the two, so they can disagree — and the disagreement is silent
|
|
346
|
+
* in both directions and worse in one.
|
|
347
|
+
*
|
|
348
|
+
* A policy the artifact registers but the manifest omits is enforcement that no
|
|
349
|
+
* `failproofai policies` listing will ever show. A policy the manifest declares
|
|
350
|
+
* but the artifact never registers is the dangerous one: the listing says the
|
|
351
|
+
* machine is protected against something nothing is checking.
|
|
352
|
+
*
|
|
353
|
+
* Both are announced rather than corrected. The artifact is digest-pinned, so
|
|
354
|
+
* what it registers IS what the publisher shipped and dropping any of it would
|
|
355
|
+
* be inventing a third answer; the manifest is what needs fixing, upstream.
|
|
356
|
+
*/
|
|
357
|
+
function reconcilePackManifest(pack: ResolvedPack | undefined, loaded: CustomHook[]): void {
|
|
358
|
+
if (!pack || pack.policies.length === 0) return;
|
|
359
|
+
const declared = new Set(pack.policies.map((p) => p.name));
|
|
360
|
+
const registered = new Set(loaded.map((h) => h.name));
|
|
361
|
+
const missing = [...declared].filter((n) => !registered.has(n));
|
|
362
|
+
const extra = [...registered].filter((n) => !declared.has(n));
|
|
363
|
+
if (missing.length > 0) {
|
|
364
|
+
hookLogWarn(
|
|
365
|
+
`pack ${pack.id}@${pack.version} declares ${missing.join(", ")} but its artifact does not ` +
|
|
366
|
+
`register ${missing.length === 1 ? "it" : "them"} — listed as protection that never runs`,
|
|
367
|
+
);
|
|
368
|
+
}
|
|
369
|
+
if (extra.length > 0) {
|
|
370
|
+
hookLogWarn(
|
|
371
|
+
`pack ${pack.id}@${pack.version} registers undeclared ${extra.join(", ")} — ` +
|
|
372
|
+
`${extra.length === 1 ? "it enforces" : "they enforce"} but will not appear in listings`,
|
|
373
|
+
);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
333
377
|
export async function loadAllCustomHooks(
|
|
334
378
|
customPoliciesPaths: string | string[] | undefined,
|
|
335
379
|
opts?: {
|
|
336
380
|
sessionCwd?: string;
|
|
337
381
|
customPoliciesEnabled?: boolean;
|
|
338
382
|
cloudManagedPolicies?: CloudManagedPolicyArtifact[];
|
|
383
|
+
packs?: ResolvedPack[];
|
|
339
384
|
},
|
|
340
385
|
): Promise<LoadAllResult> {
|
|
341
386
|
clearCustomHooks();
|
|
342
387
|
|
|
343
388
|
const conventionSources: ConventionSource[] = [];
|
|
389
|
+
const packFailures = new Map<string, PolicyLoadFailure>();
|
|
344
390
|
|
|
345
391
|
const projectRoot = findProjectConfigDir(opts?.sessionCwd ?? process.cwd());
|
|
346
392
|
|
|
@@ -395,6 +441,30 @@ export async function loadAllCustomHooks(
|
|
|
395
441
|
}
|
|
396
442
|
}
|
|
397
443
|
|
|
444
|
+
// Installed packs, keyed by artifact path — the same content-addressing, and
|
|
445
|
+
// therefore the same collision, as the cloud map above: two packs whose entry
|
|
446
|
+
// file is byte-identical resolve to ONE artifact, `loadedPaths` imports it
|
|
447
|
+
// once, and the loser would vanish silently with its effect deciding nothing.
|
|
448
|
+
// Resolved the same way and for the same reason — toward ENFORCEMENT, because
|
|
449
|
+
// over-enforcing is visible to whoever hits it and under-enforcing is the
|
|
450
|
+
// silent failure — and announced, so an operator can act on it.
|
|
451
|
+
const packByPath = new Map<string, ResolvedPack>();
|
|
452
|
+
for (const pack of opts?.packs ?? []) {
|
|
453
|
+
const key = resolve(pack.path);
|
|
454
|
+
const existing = packByPath.get(key);
|
|
455
|
+
if (!existing) {
|
|
456
|
+
packByPath.set(key, pack);
|
|
457
|
+
continue;
|
|
458
|
+
}
|
|
459
|
+
hookLogWarn(
|
|
460
|
+
`packs ${existing.id} and ${pack.id} have identical source, so they share one artifact ` +
|
|
461
|
+
`and load as one pack; enforcing it if either asks to enforce`,
|
|
462
|
+
);
|
|
463
|
+
if (existing.effect !== "enforce" && pack.effect === "enforce") {
|
|
464
|
+
packByPath.set(key, pack);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
|
|
398
468
|
// 1. Explicit custom policy paths. Accept a string for callers/configs using
|
|
399
469
|
// the legacy singular form.
|
|
400
470
|
for (const customPoliciesPath of typeof customPoliciesPaths === "string"
|
|
@@ -403,31 +473,44 @@ export async function loadAllCustomHooks(
|
|
|
403
473
|
// resolve() also normalizes absolute paths, so aliases containing `.` or
|
|
404
474
|
// `..` share a dedup key with convention-discovered canonical paths.
|
|
405
475
|
const absPath = resolve(projectRoot, customPoliciesPath);
|
|
476
|
+
const cloudManaged = cloudManagedByPath.get(absPath);
|
|
477
|
+
const pack = packByPath.get(absPath);
|
|
406
478
|
if (existsSync(absPath)) {
|
|
407
479
|
if (!loadedPaths.has(absPath)) {
|
|
408
480
|
loadedPaths.add(absPath);
|
|
409
481
|
const hooksBefore = getCustomHooks().length;
|
|
410
482
|
// A cloud-managed policy re-verifies its pinned digest at load, binding
|
|
411
483
|
// the imported bytes to what desired-state promised.
|
|
412
|
-
|
|
413
|
-
|
|
484
|
+
// A pack re-verifies its pinned digest at load for the same reason a
|
|
485
|
+
// cloud policy does: the manifest read and the import are two moments,
|
|
486
|
+
// and only this one binds the bytes actually executed to what was
|
|
487
|
+
// promised.
|
|
488
|
+
const failure = await loadSingleFile(absPath, {
|
|
489
|
+
verifyEntrySha:
|
|
490
|
+
cloudManaged?.sha256 ?? pack?.sha256,
|
|
414
491
|
});
|
|
492
|
+
if (failure && pack) packFailures.set(pack.id, failure);
|
|
415
493
|
for (const hook of getCustomHooks().slice(hooksBefore)) {
|
|
416
|
-
const cloudManaged = cloudManagedByPath.get(absPath);
|
|
417
494
|
const tagged = hook as CustomHook & {
|
|
418
495
|
__policyId?: string;
|
|
419
496
|
__cloudManaged?: CloudManagedPolicyArtifact;
|
|
497
|
+
__pack?: ResolvedPack;
|
|
420
498
|
};
|
|
421
499
|
if (cloudManaged) {
|
|
422
500
|
tagged.__cloudManaged = cloudManaged;
|
|
423
501
|
tagged.__policyId = `cloud:${cloudManaged.id}@${cloudManaged.version}:${hook.name}`;
|
|
502
|
+
} else if (pack) {
|
|
503
|
+
tagged.__pack = pack;
|
|
504
|
+
tagged.__policyId = `pack:${pack.id}@${pack.version}:${hook.name}`;
|
|
424
505
|
} else {
|
|
425
506
|
tagged.__policyId = customPolicyId(absPath, hook.name);
|
|
426
507
|
}
|
|
427
508
|
}
|
|
509
|
+
reconcilePackManifest(pack, getCustomHooks().slice(hooksBefore));
|
|
428
510
|
}
|
|
429
511
|
} else {
|
|
430
512
|
hookLogWarn(`custom policy path not found: ${absPath}`);
|
|
513
|
+
if (pack) packFailures.set(pack.id, { type: "path_missing", reason: `path missing: ${absPath}` });
|
|
431
514
|
}
|
|
432
515
|
}
|
|
433
516
|
|
|
@@ -569,5 +652,5 @@ export async function loadAllCustomHooks(
|
|
|
569
652
|
}
|
|
570
653
|
}
|
|
571
654
|
|
|
572
|
-
return { hooks: allHooks, conventionSources };
|
|
655
|
+
return { hooks: allHooks, conventionSources, packFailures };
|
|
573
656
|
}
|
package/src/hooks/fp-home.ts
CHANGED
|
@@ -210,6 +210,26 @@ export const globalPolicyConfigFile = (home?: string) =>
|
|
|
210
210
|
*/
|
|
211
211
|
export const cloudPoliciesDir = (home?: string) => resolve(policiesDir(home), "cloud-policies");
|
|
212
212
|
|
|
213
|
+
/**
|
|
214
|
+
* Installed policy packs — a sibling of `cloudPoliciesDir` and flat for the same
|
|
215
|
+
* reason: `artifacts/<sha256>.mjs` is content-addressed, so an install can only
|
|
216
|
+
* ever write a file that does not exist yet and is structurally incapable of
|
|
217
|
+
* disturbing what is currently live. `installed.json` names which artifacts are
|
|
218
|
+
* active and is written last, so activation is one atomic flip.
|
|
219
|
+
*
|
|
220
|
+
* Living under `policies/` is safe ONLY because the convention loader does not
|
|
221
|
+
* recurse — `discoverPolicyFiles` and `findSkippedPolicyFiles` both filter on
|
|
222
|
+
* `isFile()`, so nothing under `packs/` can be picked up as an unverified
|
|
223
|
+
* convention policy. `fp-home.test.ts` pins that non-recursion.
|
|
224
|
+
*/
|
|
225
|
+
export const packsDir = (home?: string) => resolve(policiesDir(home), "packs");
|
|
226
|
+
|
|
227
|
+
/** The activation pointer. Written last and atomically. */
|
|
228
|
+
export const packsInstalledFile = (home?: string) => resolve(packsDir(home), "installed.json");
|
|
229
|
+
|
|
230
|
+
/** Content-addressed pack artifacts, shared across packs and versions. */
|
|
231
|
+
export const packArtifactsDir = (home?: string) => resolve(packsDir(home), "artifacts");
|
|
232
|
+
|
|
213
233
|
// ── Collector ────────────────────────────────────────────────────────────────
|
|
214
234
|
|
|
215
235
|
/** Per-source watermarks. One directory per source — never shared: the cursor
|
|
@@ -218,7 +238,14 @@ export const cloudPoliciesDir = (home?: string) => resolve(policiesDir(home), "c
|
|
|
218
238
|
export const cursorsDir = (source?: string, home?: string) =>
|
|
219
239
|
source ? resolve(atHome(home, "cursors"), source) : atHome(home, "cursors");
|
|
220
240
|
|
|
221
|
-
/** The SDK spool root
|
|
241
|
+
/** The SDK spool root, and the ONLY root `failproofai-sdk` writes to.
|
|
242
|
+
*
|
|
243
|
+
* The daemon additionally watches `~/.agenteye/events` (see `spool_dirs` in
|
|
244
|
+
* `crates/fpai-collect/src/config.rs`) so that SDKs old enough to write there,
|
|
245
|
+
* and batches already sitting there, keep being collected. But no current SDK
|
|
246
|
+
* puts anything in it: `$AGENTEYE_HOME` used to redirect the spool and no
|
|
247
|
+
* longer does, precisely so that exporting it for the older
|
|
248
|
+
* `agenteye-collector` cannot relocate the SDK as a side effect. */
|
|
222
249
|
export const customAgentsDir = (home?: string) => atHome(home, "custom-agents");
|
|
223
250
|
export const customAgentsEventsDir = (home?: string) => resolve(customAgentsDir(home), "events");
|
|
224
251
|
export const customAgentsFailedDir = (home?: string) => resolve(customAgentsDir(home), "failed");
|
|
@@ -273,6 +300,48 @@ export const auditSessionFile = (home?: string) => resolve(auditDir(home), "sess
|
|
|
273
300
|
export const auditMachineFile = (home?: string) => resolve(auditDir(home), "machine.json");
|
|
274
301
|
|
|
275
302
|
|
|
303
|
+
// ── fp-cloud-cli ───────────────────────────────────────────────────────────────────
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* The Cloud CLI's own directory (`fp-cloud-cli` on PyPI, command `fp`).
|
|
307
|
+
*
|
|
308
|
+
* Written by PYTHON, not by anything in this repo's TypeScript or Rust — the
|
|
309
|
+
* CLI resolves it independently in `fp-cloud-cli/fp_cli/config.py`. It is declared
|
|
310
|
+
* here anyway because this file is the register of what may exist in the home,
|
|
311
|
+
* and a path absent from it is only safe by accident: `resettablePaths()` is a
|
|
312
|
+
* filter over `HOME_CLASSES`, so an unregistered directory survives today and
|
|
313
|
+
* survives the next migration only until someone lists its parent.
|
|
314
|
+
*
|
|
315
|
+
* Not classified itself — `auditDir`'s rule applies, classify the children. The
|
|
316
|
+
* directory may grow a cache later; the credential in it must never be dropped.
|
|
317
|
+
*/
|
|
318
|
+
export const fpcliDir = (home?: string) => atHome(home, "fpcli");
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* The CLI's signed-in session. `0600`, written only by `fp login` / `fp logout`.
|
|
322
|
+
*
|
|
323
|
+
* Was `~/.fp/cli.json` — a third top-level dotfile for one product. The old
|
|
324
|
+
* file is deliberately left where it is: `load_config` in
|
|
325
|
+
* `fp-cloud-cli/fp_cli/config.py` reads it when nothing is here yet, writes the
|
|
326
|
+
* session to this path, and does NOT delete the original, so downgrading to a
|
|
327
|
+
* previous `fp` finds its session intact. Adoption is best-effort — an
|
|
328
|
+
* unwritable home hands back the session it found rather than logging the
|
|
329
|
+
* machine out — and it costs the user no login.
|
|
330
|
+
*
|
|
331
|
+
* This paragraph said the opposite until it was checked against the code: that
|
|
332
|
+
* there was no migration and the upgrade cost a login. There is one, it is
|
|
333
|
+
* covered by `fp-cloud-cli/tests/test_failproofai_home.py`, and the only true half
|
|
334
|
+
* was that the old file survives.
|
|
335
|
+
*
|
|
336
|
+
* `user-typed` for the same reason as `auditSessionFile` beside it: nothing
|
|
337
|
+
* regenerates a session, and dropping it silently signs the machine out.
|
|
338
|
+
*
|
|
339
|
+
* TS-side only, like `auditSessionFile`, and absent from `paths.rs` by design —
|
|
340
|
+
* the daemon has no reason to open a human credential, and mirroring a path
|
|
341
|
+
* only Python writes would give `paths.rs` an entry nothing there reads.
|
|
342
|
+
*/
|
|
343
|
+
export const fpcliAuthFile = (home?: string) => resolve(fpcliDir(home), "cli-auth.json");
|
|
344
|
+
|
|
276
345
|
// ── Hook activity ────────────────────────────────────────────────────────────
|
|
277
346
|
|
|
278
347
|
/** The decision log: page-sized JSONL the dashboard's activity tab reads. */
|
|
@@ -469,9 +538,15 @@ export type DataClass =
|
|
|
469
538
|
* else under it is scratch. Listing the parent is exactly how a reset came
|
|
470
539
|
* to delete undelivered events and the machine's own telemetry identity.
|
|
471
540
|
*
|
|
472
|
-
* `home
|
|
473
|
-
* module is either classified here or covered by a classified parent, so
|
|
474
|
-
* next path added to the home cannot skip the one question that matters.
|
|
541
|
+
* `__tests__/hooks/fp-home.test.ts` asserts every exported path function in
|
|
542
|
+
* this module is either classified here or covered by a classified parent, so
|
|
543
|
+
* the next path added to the home cannot skip the one question that matters.
|
|
544
|
+
*
|
|
545
|
+
* It cited `home-classification.test.ts` until that was checked — a file that
|
|
546
|
+
* has never existed. The guard was real and in the wrong place, which is the
|
|
547
|
+
* failure this header already describes happening once before: a citation is
|
|
548
|
+
* only load-bearing if somebody follows it, and the person who does is looking
|
|
549
|
+
* for the rule they are about to break.
|
|
475
550
|
*/
|
|
476
551
|
export const HOME_CLASSES: readonly { path: (home?: string) => string; class: DataClass }[] = [
|
|
477
552
|
// ── Never deleted: a person typed it ──
|
|
@@ -498,6 +573,11 @@ export const HOME_CLASSES: readonly { path: (home?: string) => string; class: Da
|
|
|
498
573
|
// with no notice, and the machine only finds out the next time it tries to
|
|
499
574
|
// report.
|
|
500
575
|
{ path: auditSessionFile, class: "user-typed" },
|
|
576
|
+
// The Cloud CLI's session, written by Python (`fp-cloud-cli/fp_cli/config.py`). The
|
|
577
|
+
// one entry here whose writer is outside this repo's TS and Rust, which is
|
|
578
|
+
// exactly why it needs listing: nothing in a migration would otherwise know a
|
|
579
|
+
// credential lives under `fpcli/`.
|
|
580
|
+
{ path: fpcliAuthFile, class: "user-typed" },
|
|
501
581
|
|
|
502
582
|
// ── Never deleted: recorded and not yet shipped ──
|
|
503
583
|
// Batches read out of transcripts and queued for upload. The reason losing
|
|
@@ -574,6 +654,14 @@ export const HOME_CLASSES: readonly { path: (home?: string) => string; class: Da
|
|
|
574
654
|
// directory holds both the files a person wrote and the ones the fleet sent,
|
|
575
655
|
// and only the second kind may be thrown away.
|
|
576
656
|
{ path: cloudPoliciesDir, class: "refetchable" },
|
|
657
|
+
// Installed packs. Third-party packs are re-fetchable by `failproofai pack
|
|
658
|
+
// add`; the bundled default pack is restored from the package immediately
|
|
659
|
+
// after reset. So this is the fleet's argument again: one directory holds both
|
|
660
|
+
// what a person wrote and what a command fetched, and only the second kind may
|
|
661
|
+
// be thrown away. Without this row `packs/` inherits `policiesDir`'s
|
|
662
|
+
// `user-typed` and survives a reset that is supposed to clear re-fetchable
|
|
663
|
+
// state.
|
|
664
|
+
{ path: packsDir, class: "refetchable" },
|
|
577
665
|
|
|
578
666
|
// ── Never touched ──
|
|
579
667
|
// A downloaded daemon binary is large, version-pinned and re-verified on use,
|
package/src/hooks/fp-reset.ts
CHANGED
|
@@ -98,6 +98,8 @@ import {
|
|
|
98
98
|
isDaemonSupportedPlatform,
|
|
99
99
|
probeDaemonEndToEnd,
|
|
100
100
|
} from "./daemon-service";
|
|
101
|
+
import { installBundledPack } from "./pack-store";
|
|
102
|
+
import { readHooksConfig } from "./hooks-config";
|
|
101
103
|
|
|
102
104
|
export interface ResetOutcome {
|
|
103
105
|
/** Paths that existed and were removed. */
|
|
@@ -964,6 +966,24 @@ export function resetHome(from: number, to: number = LAYOUT_VERSION): ResetOutco
|
|
|
964
966
|
// straight out of the same file. Both paths end at the same key, and only one
|
|
965
967
|
// of them represents something a person typed.
|
|
966
968
|
if (telemetryOptOut) updateConfig({ telemetry: { enabled: false } });
|
|
969
|
+
// `packs/` is resettable, but the package's default pack is also the offline
|
|
970
|
+
// enforcement floor. Restore it from the installed package before declaring
|
|
971
|
+
// the migration complete; third-party packs remain explicitly re-fetchable.
|
|
972
|
+
//
|
|
973
|
+
// Carrying `enabledPolicies` INTO the selection, not installing defaults over
|
|
974
|
+
// it. This is the upgrade path every existing user takes, and installing
|
|
975
|
+
// defaults meant a machine that had switched `block-force-push` and
|
|
976
|
+
// `block-kubectl` on came back with them off — guards that were denying
|
|
977
|
+
// before the upgrade and allowing after, with nothing said.
|
|
978
|
+
const carried = (() => {
|
|
979
|
+
try {
|
|
980
|
+
const names = readHooksConfig().enabledPolicies ?? [];
|
|
981
|
+
return names.length > 0 ? { only: names } : undefined;
|
|
982
|
+
} catch {
|
|
983
|
+
return undefined;
|
|
984
|
+
}
|
|
985
|
+
})();
|
|
986
|
+
installBundledPack(carried);
|
|
967
987
|
// The step's OWN target, not LAYOUT_VERSION.
|
|
968
988
|
//
|
|
969
989
|
// Every step used to end stamping the current layout, which was harmless
|
|
@@ -1344,8 +1364,12 @@ function staleDaemonHint(): string[] {
|
|
|
1344
1364
|
`[failproofai] daemon is ${skew.installed}, CLI is ${skew.expected}.`,
|
|
1345
1365
|
`This machine is configured to REQUIRE the daemon. A daemon built against a`,
|
|
1346
1366
|
`different on-disk layout refuses to start, and this version moved it — so the`,
|
|
1347
|
-
|
|
1348
|
-
|
|
1367
|
+
// The wrap is load-bearing: "denies every tool call" is the consequence
|
|
1368
|
+
// this message exists to state, and splitting it across two lines is
|
|
1369
|
+
// what made the test asserting that phrase fail while the text looked
|
|
1370
|
+
// perfectly correct to a human reading it.
|
|
1371
|
+
`next reboot or restart can leave the service down, which`,
|
|
1372
|
+
`denies every tool call until it is fixed.`,
|
|
1349
1373
|
`Run \`failproofai update\` now to bring the daemon in line.`,
|
|
1350
1374
|
``,
|
|
1351
1375
|
];
|