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
package/src/hooks/manager.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Install/remove/list failproofai hooks for one or more agent
|
|
2
|
+
* Install/remove/list failproofai hooks for one or more agent harnesses.
|
|
3
3
|
*
|
|
4
4
|
* Per-CLI path resolution and settings I/O live in `./integrations` (one
|
|
5
5
|
* `Integration` impl per CLI). This module orchestrates: validation, policy
|
|
@@ -26,6 +26,23 @@ import { CliError } from "../cli-error";
|
|
|
26
26
|
import { hookLogWarn } from "./hook-logger";
|
|
27
27
|
import { customPoliciesDir, globalPolicyConfigFile } from "./fp-home";
|
|
28
28
|
import { readActiveCloudManagedPolicies } from "./cloud-managed-policies";
|
|
29
|
+
import { installBundledPack, setPackPolicyEnabled } from "./pack-store";
|
|
30
|
+
import type { ResolvedPack } from "./pack-manifest";
|
|
31
|
+
import { hasInstalledPacks, readInstalledPacks } from "./pack-manifest";
|
|
32
|
+
import {
|
|
33
|
+
chip,
|
|
34
|
+
note,
|
|
35
|
+
nextStep,
|
|
36
|
+
optsFor,
|
|
37
|
+
printBlock,
|
|
38
|
+
rule,
|
|
39
|
+
stack,
|
|
40
|
+
table,
|
|
41
|
+
title,
|
|
42
|
+
warning,
|
|
43
|
+
type ChipState,
|
|
44
|
+
type TableRow,
|
|
45
|
+
} from "./tui";
|
|
29
46
|
|
|
30
47
|
const VALID_POLICY_NAMES = new Set(BUILTIN_POLICIES.map((p) => p.name));
|
|
31
48
|
|
|
@@ -63,13 +80,167 @@ function resolveFailproofaiBinary(): string {
|
|
|
63
80
|
}
|
|
64
81
|
}
|
|
65
82
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
83
|
+
/** One policy of one installed pack, resolved from a name the user typed. */
|
|
84
|
+
interface PackPolicyRef {
|
|
85
|
+
packId: string;
|
|
86
|
+
packVersion: string;
|
|
87
|
+
name: string;
|
|
88
|
+
/** The `disabledCustomPolicies` entry the dashboard writes for it. */
|
|
89
|
+
disabledKey: string;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Split names the user typed into builtins and installed-pack policies.
|
|
94
|
+
*
|
|
95
|
+
* Without this, every name went through `validatePolicyNames`, whose set is the
|
|
96
|
+
* compiled builtins — so `policies --disable block-big-refund` on a pack the
|
|
97
|
+
* user had just installed answered "Unknown policy name" and listed 39 names
|
|
98
|
+
* that were not the one they meant. A pack could be installed and then not
|
|
99
|
+
* managed at all.
|
|
100
|
+
*
|
|
101
|
+
* A builtin wins a bare name, because that is the name people have typed for a
|
|
102
|
+
* year and a third-party pack must not be able to capture it. Two packs
|
|
103
|
+
* declaring the same name is the one case that cannot be guessed, so it is
|
|
104
|
+
* refused with the qualified `<pack-id>:<name>` form spelled out.
|
|
105
|
+
*/
|
|
106
|
+
function resolvePolicyNames(names: string[]): { builtins: string[]; packs: PackPolicyRef[] } {
|
|
107
|
+
const builtins: string[] = [];
|
|
108
|
+
const packs: PackPolicyRef[] = [];
|
|
109
|
+
const unknown: string[] = [];
|
|
110
|
+
|
|
111
|
+
let installed: ResolvedPack[] = [];
|
|
112
|
+
try {
|
|
113
|
+
installed = readInstalledPacks().packs;
|
|
114
|
+
} catch {
|
|
115
|
+
// No packs, or an unreadable manifest: names simply resolve as builtins and
|
|
116
|
+
// an unknown one gets the ordinary error. A listing-adjacent command must
|
|
117
|
+
// not fail because a pack manifest is corrupt.
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const refsFor = (packId: string | null, policyName: string): PackPolicyRef[] =>
|
|
121
|
+
installed
|
|
122
|
+
.filter((pack) => (packId === null || pack.id === packId))
|
|
123
|
+
.filter((pack) => pack.policies.some((p) => p.name === policyName))
|
|
124
|
+
.map((pack) => ({
|
|
125
|
+
packId: pack.id,
|
|
126
|
+
packVersion: pack.version,
|
|
127
|
+
name: policyName,
|
|
128
|
+
disabledKey: `pack:${pack.id}@${pack.version}:${policyName}`,
|
|
129
|
+
}));
|
|
130
|
+
|
|
131
|
+
for (const raw of names) {
|
|
132
|
+
// A PACK first, then the compiled set. This order is the whole fix for
|
|
133
|
+
// `policy remove block-sudo` printing "Disabled 0" while `block-sudo` kept
|
|
134
|
+
// denying: the name resolved to a builtin, the command edited
|
|
135
|
+
// `enabledPolicies`, and `enabledPolicies` stopped deciding anything when
|
|
136
|
+
// this build stopped registering builtins. The pack is where the switch is.
|
|
137
|
+
const direct = refsFor(null, raw);
|
|
138
|
+
if (direct.length === 1) {
|
|
139
|
+
packs.push(direct[0]);
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
if (direct.length > 1) {
|
|
143
|
+
throw new CliError(
|
|
144
|
+
`"${raw}" is declared by ${direct.length} installed packs.\n` +
|
|
145
|
+
`Name the one you mean:\n` +
|
|
146
|
+
direct.map((m) => ` ${m.packId}:${m.name}`).join("\n"),
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
// No pack carries it. Falls back to the compiled name set, which is what a
|
|
150
|
+
// machine still running on the migration shim has.
|
|
151
|
+
if (VALID_POLICY_NAMES.has(raw)) {
|
|
152
|
+
builtins.push(raw);
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
// `acme/finance:block-big-refund` — a pack id holds a slash, never a colon,
|
|
156
|
+
// so the last colon separates them unambiguously.
|
|
157
|
+
const colon = raw.lastIndexOf(":");
|
|
158
|
+
const qualified = colon > 0
|
|
159
|
+
? { packId: raw.slice(0, colon), name: raw.slice(colon + 1) }
|
|
160
|
+
: null;
|
|
161
|
+
const matches = qualified
|
|
162
|
+
? refsFor(qualified.packId, qualified.name)
|
|
163
|
+
: refsFor(null, raw);
|
|
164
|
+
|
|
165
|
+
if (matches.length === 1) {
|
|
166
|
+
packs.push(matches[0]);
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
if (matches.length > 1) {
|
|
170
|
+
throw new CliError(
|
|
171
|
+
`"${raw}" is declared by ${matches.length} installed packs.\n` +
|
|
172
|
+
`Name the one you mean:\n` +
|
|
173
|
+
matches.map((m) => ` ${m.packId}:${m.name}`).join("\n"),
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
unknown.push(raw);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (unknown.length > 0) {
|
|
180
|
+
const packNames = installed.flatMap((pack) =>
|
|
181
|
+
pack.policies.map((p) => `${pack.id}:${p.name}`),
|
|
182
|
+
);
|
|
183
|
+
throw new CliError(
|
|
184
|
+
`Unknown policy name(s): ${unknown.join(", ")}\n` +
|
|
185
|
+
`Valid policies: ${[...VALID_POLICY_NAMES].join(", ")}` +
|
|
186
|
+
(packNames.length > 0 ? `\nFrom installed packs: ${packNames.join(", ")}` : ""),
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
return { builtins, packs };
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/** Turn pack policies on or off, and say what happened. */
|
|
193
|
+
function applyPackPolicies(
|
|
194
|
+
refs: PackPolicyRef[],
|
|
195
|
+
on: boolean,
|
|
196
|
+
scope: HookScope,
|
|
197
|
+
cwd?: string,
|
|
198
|
+
): void {
|
|
199
|
+
if (refs.length === 0) return;
|
|
200
|
+
for (const ref of refs) {
|
|
201
|
+
const result = setPackPolicyEnabled(ref.packId, ref.name, on);
|
|
202
|
+
if (!result.ok) {
|
|
203
|
+
throw new CliError(`Could not ${on ? "enable" : "disable"} ${ref.name}: ${result.reason}`);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
if (on) {
|
|
207
|
+
// Clearing the dashboard's key too. The selection and the disabled key are
|
|
208
|
+
// two different switches for one policy, and leaving the second one set
|
|
209
|
+
// would report the policy enabled while it stayed off.
|
|
210
|
+
const config = readScopedHooksConfig(scope, cwd);
|
|
211
|
+
const keys = new Set(refs.map((r) => r.disabledKey));
|
|
212
|
+
const remaining = (config.disabledCustomPolicies ?? []).filter((k) => !keys.has(k));
|
|
213
|
+
if (remaining.length !== (config.disabledCustomPolicies ?? []).length) {
|
|
214
|
+
const next: HooksConfig = { ...config, disabledCustomPolicies: remaining };
|
|
215
|
+
if (remaining.length === 0) delete next.disabledCustomPolicies;
|
|
216
|
+
writeScopedHooksConfig(next, scope, cwd);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
for (const ref of refs) {
|
|
220
|
+
console.log(
|
|
221
|
+
`${on ? "Enabled" : "Disabled"} ${ref.name} from pack ${ref.packId}@${ref.packVersion}.`,
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Refuse to "disable" a policy that will register anyway.
|
|
228
|
+
*
|
|
229
|
+
* Removing an `alwaysOn` name from `enabledPolicies` succeeds at the file level
|
|
230
|
+
* and changes nothing at the enforcement level, so without this the CLI reports
|
|
231
|
+
* a policy disabled while it keeps denying — the operator's mental model and the
|
|
232
|
+
* machine's behaviour diverge silently, which is the failure this policy exists
|
|
233
|
+
* to prevent in the first place.
|
|
234
|
+
*/
|
|
235
|
+
function rejectAlwaysOnPolicies(names: string[]): void {
|
|
236
|
+
const alwaysOn = new Set(BUILTIN_POLICIES.filter((p) => p.alwaysOn).map((p) => p.name));
|
|
237
|
+
const refused = names.filter((n) => alwaysOn.has(n));
|
|
238
|
+
if (refused.length > 0) {
|
|
70
239
|
throw new CliError(
|
|
71
|
-
`
|
|
72
|
-
`
|
|
240
|
+
`Cannot disable: ${refused.join(", ")}\n` +
|
|
241
|
+
`This policy stops an agent from switching off failproofai itself, so it ` +
|
|
242
|
+
`is always on and ships with the package. A guard the agent can disable ` +
|
|
243
|
+
`by the means it is meant to prevent is not a guard.`
|
|
73
244
|
);
|
|
74
245
|
}
|
|
75
246
|
}
|
|
@@ -151,8 +322,21 @@ async function installHooksImpl(
|
|
|
151
322
|
// Validate user input first before any system checks
|
|
152
323
|
if (policyNames !== undefined && policyNames.length > 0) {
|
|
153
324
|
const nonAllNames = policyNames.filter((n) => n !== "all");
|
|
154
|
-
// Check unknown names first (most actionable error for the user)
|
|
155
|
-
|
|
325
|
+
// Check unknown names first (most actionable error for the user). Pack
|
|
326
|
+
// policies are applied here and taken out of the list: the rest of this
|
|
327
|
+
// function writes `enabledPolicies`, which is a builtin-only set.
|
|
328
|
+
if (nonAllNames.length > 0) {
|
|
329
|
+
const resolved = resolvePolicyNames(nonAllNames);
|
|
330
|
+
applyPackPolicies(resolved.packs, true, scope, cwd);
|
|
331
|
+
if (resolved.packs.length > 0) {
|
|
332
|
+
policyNames = policyNames.filter((n) => n === "all" || resolved.builtins.includes(n));
|
|
333
|
+
// Named ONLY pack policies: the work is done. Carrying on would resolve
|
|
334
|
+
// the failproofai binary and rewrite every CLI's settings to enable a
|
|
335
|
+
// set of builtins nobody asked about — and would fail outright on a
|
|
336
|
+
// machine where the binary is not on PATH, AFTER the pack change landed.
|
|
337
|
+
if (policyNames.length === 0) return;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
156
340
|
// Then check if "all" is mixed with valid specific names
|
|
157
341
|
if (policyNames.includes("all") && nonAllNames.length > 0) {
|
|
158
342
|
throw new CliError(
|
|
@@ -290,6 +474,49 @@ async function installHooksImpl(
|
|
|
290
474
|
}
|
|
291
475
|
}
|
|
292
476
|
writeScopedHooksConfig(configToWrite, scope, cwd);
|
|
477
|
+
|
|
478
|
+
// Choosing policies IS selecting from the pack now. Nothing registers these
|
|
479
|
+
// names from this build any more, so writing `enabledPolicies` and stopping
|
|
480
|
+
// would leave a freshly set-up machine enforcing nothing at all — which is
|
|
481
|
+
// the failure mode this whole product exists to prevent.
|
|
482
|
+
//
|
|
483
|
+
// Installed from the copy vendored in the package: no network, so setup
|
|
484
|
+
// cannot fail behind a proxy, and the machine is guarded the moment it is
|
|
485
|
+
// configured rather than the moment it next reaches github.com.
|
|
486
|
+
// The always-on guard is excluded: a pack may not declare `alwaysOn`, so the
|
|
487
|
+
// pack does not carry it and asking for it by name is a selection the pack
|
|
488
|
+
// cannot satisfy. It ships compiled in and registers regardless.
|
|
489
|
+
const alwaysOnNames = new Set(BUILTIN_POLICIES.filter((p) => p.alwaysOn).map((p) => p.name));
|
|
490
|
+
const fromPack = selectedPolicies.filter((name) => !alwaysOnNames.has(name));
|
|
491
|
+
if (fromPack.length > 0) {
|
|
492
|
+
// ONLY when there is no pack yet. Installing the bundled pack with
|
|
493
|
+
// `only: <selection>` REPLACES whatever the machine had chosen, and
|
|
494
|
+
// `selectedPolicies` is derived from `enabledPolicies` — which is empty on a
|
|
495
|
+
// machine whose pack came from `pack add core`. `policy add block-rm-rf`
|
|
496
|
+
// therefore took a machine from ten guards to one, silently, and nine
|
|
497
|
+
// policies went from denying to allowing.
|
|
498
|
+
//
|
|
499
|
+
// With a pack already installed the names are switched on individually
|
|
500
|
+
// instead, which is additive and touches nothing else.
|
|
501
|
+
if (!hasInstalledPacks()) {
|
|
502
|
+
const bundled = installBundledPack({ only: fromPack });
|
|
503
|
+
if (!bundled.installed) {
|
|
504
|
+
console.log(
|
|
505
|
+
`\nWarning: could not install the policy pack (${bundled.reason}).\n` +
|
|
506
|
+
`Nothing is enforcing yet — run \`failproofai pack add core\` once that is fixed.`,
|
|
507
|
+
);
|
|
508
|
+
}
|
|
509
|
+
} else {
|
|
510
|
+
for (const name of fromPack) {
|
|
511
|
+
for (const pack of readInstalledPacks().packs) {
|
|
512
|
+
if (pack.policies.some((p) => p.name === name)) {
|
|
513
|
+
setPackPolicyEnabled(pack.id, name, true);
|
|
514
|
+
break;
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
}
|
|
293
520
|
console.log(`\nEnabled ${selectedPolicies.length} policy(ies): ${selectedPolicies.join(", ")}\n`);
|
|
294
521
|
if (removeCustomHooks) {
|
|
295
522
|
console.log("Custom hooks path cleared.");
|
|
@@ -434,7 +661,18 @@ export async function removeHooks(policyNames?: string[], scope: HookScope | "al
|
|
|
434
661
|
|
|
435
662
|
// Remove specific policies from config (keep hooks installed)
|
|
436
663
|
if (policyNames && policyNames.length > 0 && !(policyNames.length === 1 && policyNames[0] === "all")) {
|
|
437
|
-
|
|
664
|
+
const resolved = resolvePolicyNames(policyNames);
|
|
665
|
+
applyPackPolicies(resolved.packs, false, configScope, cwd);
|
|
666
|
+
policyNames = resolved.builtins;
|
|
667
|
+
rejectAlwaysOnPolicies(policyNames);
|
|
668
|
+
// Named ONLY pack policies: they are off now and there is nothing else to
|
|
669
|
+
// do. Falling through would reach the hook-removal path below with an empty
|
|
670
|
+
// name list, which is the "remove failproofai from every CLI" branch — so
|
|
671
|
+
// `--uninstall <a-pack-policy>` would have torn out every hook on the
|
|
672
|
+
// machine.
|
|
673
|
+
if (resolved.packs.length > 0 && policyNames.length === 0) return;
|
|
674
|
+
}
|
|
675
|
+
if (policyNames && policyNames.length > 0 && !(policyNames.length === 1 && policyNames[0] === "all")) {
|
|
438
676
|
const config = readScopedHooksConfig(configScope, cwd);
|
|
439
677
|
const removeSet = new Set(policyNames);
|
|
440
678
|
const remaining = config.enabledPolicies.filter((p) => !removeSet.has(p));
|
|
@@ -593,135 +831,88 @@ export async function removeHooks(policyNames?: string[], scope: HookScope | "al
|
|
|
593
831
|
*/
|
|
594
832
|
export async function listHooks(cwd?: string): Promise<void> {
|
|
595
833
|
const config = readMergedHooksConfig(cwd);
|
|
596
|
-
const enabledSet = new Set(config.enabledPolicies);
|
|
597
834
|
const disabledCustomSet = new Set(config.disabledCustomPolicies ?? []);
|
|
835
|
+
const opts = optsFor(process.stdout);
|
|
598
836
|
|
|
599
837
|
// Determine which scopes have hooks installed (deduplicate when paths overlap, e.g. cwd === home)
|
|
600
838
|
const uniqueScopes = deduplicateScopes(HOOK_SCOPES, cwd);
|
|
601
839
|
const installedScopes = uniqueScopes.filter((s) => hooksInstalledInSettings(s, cwd));
|
|
602
840
|
|
|
603
|
-
//
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
// All known builtin policy names (for unknown policyParams key detection)
|
|
611
|
-
const builtinPolicyNames = new Set(BUILTIN_POLICIES.map((p) => p.name));
|
|
612
|
-
|
|
613
|
-
// Helper: print params summary lines beneath a policy row
|
|
614
|
-
const printParamsSummary = (policyName: string, indent: string) => {
|
|
615
|
-
const params = config.policyParams?.[policyName];
|
|
616
|
-
if (!params) return;
|
|
617
|
-
for (const [key, val] of Object.entries(params)) {
|
|
618
|
-
console.log(`${indent} ${key}: ${JSON.stringify(val)}`);
|
|
841
|
+
// Names a `policyParams` key may legitimately use: every policy an installed
|
|
842
|
+
// pack carries. Previously the compiled catalog, which no longer describes
|
|
843
|
+
// what runs.
|
|
844
|
+
const knownPolicyNames = new Set<string>();
|
|
845
|
+
try {
|
|
846
|
+
for (const pack of readInstalledPacks().packs) {
|
|
847
|
+
for (const policy of pack.policies) knownPolicyNames.add(policy.name);
|
|
619
848
|
}
|
|
620
|
-
}
|
|
849
|
+
} catch {
|
|
850
|
+
// Unreadable manifest: skip the typo warning rather than invent one.
|
|
851
|
+
}
|
|
621
852
|
|
|
622
|
-
const
|
|
623
|
-
const
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
for (const policy of betaPolicies) printRow(policy);
|
|
853
|
+
const groups: Array<string[] | null> = [];
|
|
854
|
+
const packCount = (() => {
|
|
855
|
+
try {
|
|
856
|
+
return readInstalledPacks().packs.reduce(
|
|
857
|
+
(n, pack) => n + (pack.enabled ?? pack.policies.map((p) => p.name)).length,
|
|
858
|
+
0,
|
|
859
|
+
);
|
|
860
|
+
} catch {
|
|
861
|
+
return 0;
|
|
632
862
|
}
|
|
633
|
-
};
|
|
863
|
+
})();
|
|
864
|
+
groups.push(
|
|
865
|
+
title(
|
|
866
|
+
"failproofai policies",
|
|
867
|
+
installedScopes.length === 0
|
|
868
|
+
? "not installed"
|
|
869
|
+
: `${installedScopes.join(" + ")} · ${packCount} on`,
|
|
870
|
+
opts,
|
|
871
|
+
),
|
|
872
|
+
);
|
|
634
873
|
|
|
635
874
|
if (installedScopes.length === 0) {
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
console.log(`\n Config: ${globalPolicyConfigFile()}\n`);
|
|
663
|
-
} else {
|
|
664
|
-
// State C: Multiple scopes — column table
|
|
665
|
-
const COL = 9;
|
|
666
|
-
const scopeLabelMap: Record<HookScope, string> = {
|
|
667
|
-
user: "User",
|
|
668
|
-
project: "Project",
|
|
669
|
-
local: "Local",
|
|
670
|
-
};
|
|
671
|
-
|
|
672
|
-
console.log("\nFailproof AI Hook Policies\n");
|
|
673
|
-
|
|
674
|
-
// Header with only installed scope columns + separator
|
|
675
|
-
const buildScopePrefix = () => {
|
|
676
|
-
let s = " ";
|
|
677
|
-
for (const sc of installedScopes) s += scopeLabelMap[sc].padEnd(COL);
|
|
678
|
-
return s;
|
|
679
|
-
};
|
|
680
|
-
const scopeHeaderWidth = installedScopes.length * COL;
|
|
681
|
-
console.log(`${buildScopePrefix()}${"Name".padEnd(nameColWidth)}Description`);
|
|
682
|
-
console.log(` ${"\u2500".repeat(scopeHeaderWidth)}${"\u2500".repeat(nameColWidth)}${"\u2500".repeat(38)}`);
|
|
683
|
-
|
|
684
|
-
const printMultiScopeRow = (policy: { name: string; description: string }) => {
|
|
685
|
-
const enabled = enabledSet.has(policy.name);
|
|
686
|
-
let row = " ";
|
|
687
|
-
for (const _scope of installedScopes) {
|
|
688
|
-
if (enabled) {
|
|
689
|
-
row += `\x1B[32m\u2713 ON\x1B[0m` + " ".repeat(COL - 4);
|
|
690
|
-
} else {
|
|
691
|
-
row += " OFF" + " ".repeat(COL - 5);
|
|
692
|
-
}
|
|
693
|
-
}
|
|
694
|
-
row += policy.name.padEnd(nameColWidth) + policy.description;
|
|
695
|
-
console.log(row);
|
|
696
|
-
printParamsSummary(policy.name, ` ${" ".repeat(scopeHeaderWidth)}`);
|
|
697
|
-
};
|
|
698
|
-
|
|
699
|
-
for (const policy of regularPolicies) printMultiScopeRow(policy);
|
|
700
|
-
|
|
701
|
-
if (betaPolicies.length > 0) {
|
|
702
|
-
console.log(`\n \x1B[2m\u2500\u2500 Beta \u2500\u2500\x1B[0m`);
|
|
703
|
-
for (const policy of betaPolicies) printMultiScopeRow(policy);
|
|
704
|
-
}
|
|
705
|
-
|
|
706
|
-
console.log(`\n Config: ${globalPolicyConfigFile()}`);
|
|
707
|
-
|
|
708
|
-
// Multi-scope warning
|
|
709
|
-
const scopeNames = installedScopes.join(", ");
|
|
710
|
-
console.log();
|
|
711
|
-
console.log(`\x1B[33m\u26A0 Hooks in multiple scopes (${scopeNames}).\x1B[0m`);
|
|
712
|
-
console.log(" Consider keeping one. Remove with: failproofai policies --uninstall --scope <scope>\n");
|
|
875
|
+
groups.push(
|
|
876
|
+
nextStep(
|
|
877
|
+
"failproofai policies --install",
|
|
878
|
+
config.enabledPolicies.length > 0
|
|
879
|
+
? "These are configured but NOT installed — no hook is running them:"
|
|
880
|
+
: "Nothing is installed yet. Get started with:",
|
|
881
|
+
opts,
|
|
882
|
+
),
|
|
883
|
+
);
|
|
884
|
+
}
|
|
885
|
+
// Held back to the end rather than printed here. Everything below this point
|
|
886
|
+
// is another section of the same listing, and a footer in the middle of it
|
|
887
|
+
// reads as the end of the output — while a warning at the very end is the one
|
|
888
|
+
// a reader scrolling back from their prompt actually sees.
|
|
889
|
+
const footer: Array<string[] | null> = [note(`Config: ${globalPolicyConfigFile()}`, opts)];
|
|
890
|
+
|
|
891
|
+
if (installedScopes.length > 1) {
|
|
892
|
+
footer.push(
|
|
893
|
+
warning(
|
|
894
|
+
[
|
|
895
|
+
`Hooks in multiple scopes (${installedScopes.join(", ")}).`,
|
|
896
|
+
"Consider keeping one. Remove with: failproofai policies --uninstall --scope <scope>",
|
|
897
|
+
],
|
|
898
|
+
opts,
|
|
899
|
+
),
|
|
900
|
+
);
|
|
713
901
|
}
|
|
714
902
|
|
|
715
903
|
// Warn about unknown policyParams keys
|
|
716
904
|
if (config.policyParams) {
|
|
717
905
|
const unknownKeys: string[] = [];
|
|
718
906
|
for (const key of Object.keys(config.policyParams)) {
|
|
719
|
-
if (!
|
|
720
|
-
console.log(` \x1B[33mWarning: unknown policyParams key "${key}" — possible typo\x1B[0m`);
|
|
721
|
-
unknownKeys.push(key);
|
|
722
|
-
}
|
|
907
|
+
if (knownPolicyNames.size > 0 && !knownPolicyNames.has(key)) unknownKeys.push(key);
|
|
723
908
|
}
|
|
724
909
|
if (unknownKeys.length > 0) {
|
|
910
|
+
footer.push(
|
|
911
|
+
warning(
|
|
912
|
+
unknownKeys.map((key) => `unknown policyParams key "${key}" — possible typo`),
|
|
913
|
+
opts,
|
|
914
|
+
),
|
|
915
|
+
);
|
|
725
916
|
try {
|
|
726
917
|
await trackHookEvent(getInstanceId(), "policy_params_validation_warning", {
|
|
727
918
|
unknown_keys_count: unknownKeys.length,
|
|
@@ -734,30 +925,38 @@ export async function listHooks(cwd?: string): Promise<void> {
|
|
|
734
925
|
// Explicit Custom Policies section
|
|
735
926
|
const explicitPaths = configuredCustomPolicyPaths(config);
|
|
736
927
|
if (explicitPaths.length > 0) {
|
|
737
|
-
|
|
928
|
+
groups.push(rule("Custom Policies", opts));
|
|
738
929
|
for (const path of explicitPaths) {
|
|
739
930
|
// Enforcement resolves configured paths from the project config root.
|
|
740
931
|
// Use the same canonical path here so the ID checked by the CLI exactly
|
|
741
932
|
// matches the ID written by the dashboard.
|
|
742
933
|
const absPath = resolve(findProjectConfigDir(cwd ?? process.cwd()), path);
|
|
743
|
-
|
|
934
|
+
groups.push(note(absPath, opts));
|
|
744
935
|
if (!existsSync(absPath)) {
|
|
745
|
-
|
|
936
|
+
groups.push(warning([`file not found: ${absPath}`], opts));
|
|
746
937
|
continue;
|
|
747
938
|
}
|
|
748
939
|
const hooks = await loadCustomHooks(absPath);
|
|
749
940
|
if (hooks.length === 0) {
|
|
750
|
-
|
|
941
|
+
groups.push(
|
|
942
|
+
warning(["failed to load (check ~/.failproofai/logs/hooks.log)"], opts),
|
|
943
|
+
);
|
|
751
944
|
} else {
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
945
|
+
groups.push(
|
|
946
|
+
table(
|
|
947
|
+
{
|
|
948
|
+
head: ["", "Name", "Description"],
|
|
949
|
+
rows: hooks.map((hook) => [
|
|
950
|
+
chip(disabledCustomSet.has(`custom:${absPath}:${hook.name}`) ? "off" : "on", opts),
|
|
951
|
+
hook.name,
|
|
952
|
+
hook.description ?? "",
|
|
953
|
+
]),
|
|
954
|
+
},
|
|
955
|
+
opts,
|
|
956
|
+
),
|
|
957
|
+
);
|
|
758
958
|
}
|
|
759
959
|
}
|
|
760
|
-
console.log();
|
|
761
960
|
}
|
|
762
961
|
|
|
763
962
|
// Convention Policies section (.failproofai/policies/*policies.{js,mjs,ts})
|
|
@@ -801,43 +1000,82 @@ export async function listHooks(cwd?: string): Promise<void> {
|
|
|
801
1000
|
for (const t of targets) discovered[t].push({ file, hooks });
|
|
802
1001
|
};
|
|
803
1002
|
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
// straight into the filename with no space
|
|
808
|
-
// (`enforce-bengaluru-event-links-policies.mjs1 hook(s)`). Widen to fit the
|
|
809
|
-
// files actually being printed, keeping a two-space gutter.
|
|
810
|
-
const colWidth = Math.max(nameColWidth, ...files.map((f) => basename(f).length + 2));
|
|
1003
|
+
groups.push(rule(`Convention Policies — ${label}`, opts));
|
|
1004
|
+
groups.push(note(dir, opts));
|
|
1005
|
+
const rows: TableRow[] = [];
|
|
811
1006
|
for (const file of files) {
|
|
1007
|
+
const filename = basename(file);
|
|
812
1008
|
try {
|
|
813
1009
|
const hooks = await loadCustomHooks(file);
|
|
814
|
-
const filename = basename(file);
|
|
815
1010
|
record(filename, hooks.map((h) => h.name));
|
|
816
1011
|
if (hooks.length === 0) {
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
const hookStates = hooks.map((hook) => ({
|
|
820
|
-
hook,
|
|
821
|
-
disabled: disabledCustomSet.has(`convention:${policyScope}:${filename}:${hook.name}`),
|
|
822
|
-
}));
|
|
823
|
-
const disabledCount = hookStates.filter((entry) => entry.disabled).length;
|
|
824
|
-
const status = disabledCount === 0
|
|
825
|
-
? "\x1B[32m\u2713 ON\x1B[0m"
|
|
826
|
-
: disabledCount === hooks.length
|
|
827
|
-
? "\x1B[2m OFF\x1B[0m"
|
|
828
|
-
: "\x1B[33m\u25D0 MIXED\x1B[0m";
|
|
829
|
-
const hookSummary = hookStates
|
|
830
|
-
.map(({ hook, disabled }) => `${hook.name}${disabled ? " (OFF)" : ""}`)
|
|
831
|
-
.join(", ");
|
|
832
|
-
console.log(` ${status} ${filename.padEnd(colWidth)}${hooks.length} hook(s): ${hookSummary}`);
|
|
1012
|
+
rows.push({ cells: [chip("failed", opts), filename, "failed to load"] });
|
|
1013
|
+
continue;
|
|
833
1014
|
}
|
|
1015
|
+
const hookStates = hooks.map((hook) => ({
|
|
1016
|
+
hook,
|
|
1017
|
+
disabled: disabledCustomSet.has(`convention:${policyScope}:${filename}:${hook.name}`),
|
|
1018
|
+
}));
|
|
1019
|
+
const disabledCount = hookStates.filter((entry) => entry.disabled).length;
|
|
1020
|
+
const state: ChipState =
|
|
1021
|
+
disabledCount === 0 ? "on" : disabledCount === hooks.length ? "off" : "mixed";
|
|
1022
|
+
const hookSummary = hookStates
|
|
1023
|
+
.map(({ hook, disabled }) => `${hook.name}${disabled ? " (OFF)" : ""}`)
|
|
1024
|
+
.join(", ");
|
|
1025
|
+
rows.push({
|
|
1026
|
+
cells: [chip(state, opts), filename, `${hooks.length} hook(s): ${hookSummary}`],
|
|
1027
|
+
});
|
|
834
1028
|
} catch {
|
|
835
|
-
const filename = basename(file);
|
|
836
1029
|
record(filename, []);
|
|
837
|
-
|
|
1030
|
+
rows.push({ cells: [chip("failed", opts), filename, "error"] });
|
|
838
1031
|
}
|
|
839
1032
|
}
|
|
840
|
-
|
|
1033
|
+
groups.push(table({ head: ["", "File", "Hooks"], rows }, opts));
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
// Installed packs. They enforce on this machine exactly like every section
|
|
1037
|
+
// above, and until now the only way to see one was `failproofai pack list` —
|
|
1038
|
+
// so the command that answers "what is enforcing here?" answered it with a
|
|
1039
|
+
// subset, for the one source a person had to go out of their way to install.
|
|
1040
|
+
try {
|
|
1041
|
+
const { packs, errors } = readInstalledPacks();
|
|
1042
|
+
for (const pack of packs) {
|
|
1043
|
+
const taken = pack.enabled ?? pack.policies.map((p) => p.name);
|
|
1044
|
+
groups.push(rule(`Pack — ${pack.id}@${pack.version}`, opts));
|
|
1045
|
+
groups.push(
|
|
1046
|
+
table(
|
|
1047
|
+
{
|
|
1048
|
+
head: ["", "Name", "Description"],
|
|
1049
|
+
rows: pack.policies.map((policy) => {
|
|
1050
|
+
const disabled = disabledCustomSet.has(
|
|
1051
|
+
`pack:${pack.id}@${pack.version}:${policy.name}`,
|
|
1052
|
+
);
|
|
1053
|
+
// `observe` evaluates and discards its verdict, so a row reading
|
|
1054
|
+
// ON would claim enforcement the pack deliberately is not doing.
|
|
1055
|
+
const state: ChipState =
|
|
1056
|
+
pack.effect === "observe"
|
|
1057
|
+
? "observe"
|
|
1058
|
+
: !taken.includes(policy.name) || disabled
|
|
1059
|
+
? "off"
|
|
1060
|
+
: "pack";
|
|
1061
|
+
return [chip(state, opts), policy.name, policy.description];
|
|
1062
|
+
}),
|
|
1063
|
+
},
|
|
1064
|
+
opts,
|
|
1065
|
+
),
|
|
1066
|
+
);
|
|
1067
|
+
}
|
|
1068
|
+
if (errors.length > 0) {
|
|
1069
|
+
groups.push(
|
|
1070
|
+
warning(
|
|
1071
|
+
errors.map((err) => `pack ${err.id ?? "(unnamed)"} will not load: ${err.reason}`),
|
|
1072
|
+
opts,
|
|
1073
|
+
),
|
|
1074
|
+
);
|
|
1075
|
+
}
|
|
1076
|
+
} catch {
|
|
1077
|
+
// Same rule as the cloud section below: a listing must not be the thing
|
|
1078
|
+
// that turns an unreadable manifest into a broken command.
|
|
841
1079
|
}
|
|
842
1080
|
|
|
843
1081
|
// Cloud-managed policies. These enforce on this machine exactly like the two
|
|
@@ -852,21 +1090,27 @@ export async function listHooks(cwd?: string): Promise<void> {
|
|
|
852
1090
|
try {
|
|
853
1091
|
const cloud = readActiveCloudManagedPolicies();
|
|
854
1092
|
if (cloud.length > 0) {
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
1093
|
+
groups.push(rule(`Cloud-managed — deployment ${cloud[0].deployment}`, opts));
|
|
1094
|
+
groups.push(
|
|
1095
|
+
table(
|
|
1096
|
+
{
|
|
1097
|
+
head: ["", "Policy", "Version"],
|
|
1098
|
+
rows: cloud.map((artifact) => [
|
|
1099
|
+
// `observe` is evaluated and then has its verdict discarded, so a
|
|
1100
|
+
// row that read "ON" would claim enforcement this policy
|
|
1101
|
+
// deliberately is not doing.
|
|
1102
|
+
chip(artifact.effect === "observe" ? "observe" : "cloud", opts),
|
|
1103
|
+
artifact.id,
|
|
1104
|
+
`v${artifact.version}`,
|
|
1105
|
+
]),
|
|
1106
|
+
flex: 1,
|
|
1107
|
+
},
|
|
1108
|
+
opts,
|
|
1109
|
+
),
|
|
1110
|
+
);
|
|
1111
|
+
groups.push(
|
|
1112
|
+
note("Managed from the dashboard — not switchable with `failproofai policies`.", opts),
|
|
858
1113
|
);
|
|
859
|
-
const colWidth = Math.max(nameColWidth, ...cloud.map((c) => c.id.length + 2));
|
|
860
|
-
for (const artifact of cloud) {
|
|
861
|
-
// `observe` is evaluated and then has its verdict discarded, so a row
|
|
862
|
-
// that read "ON" would claim enforcement this policy deliberately is
|
|
863
|
-
// not doing.
|
|
864
|
-
const status =
|
|
865
|
-
artifact.effect === "observe" ? "\x1B[33m\u25D0 OBS\x1B[0m" : "\x1B[32m\u2713 ON\x1B[0m";
|
|
866
|
-
console.log(` ${status} ${artifact.id.padEnd(colWidth)}v${artifact.version}`);
|
|
867
|
-
}
|
|
868
|
-
console.log("\n Managed from the dashboard \u2014 not switchable with `failproofai policies`.");
|
|
869
|
-
console.log();
|
|
870
1114
|
}
|
|
871
1115
|
} catch {
|
|
872
1116
|
// A machine with no deployment, or an unreadable manifest, simply has no
|
|
@@ -874,6 +1118,8 @@ export async function listHooks(cwd?: string): Promise<void> {
|
|
|
874
1118
|
// the thing that turns a bad manifest into a broken command.
|
|
875
1119
|
}
|
|
876
1120
|
|
|
1121
|
+
printBlock(process.stdout, stack(...groups, ...footer));
|
|
1122
|
+
|
|
877
1123
|
// Mirror what was just listed into the USER config. Safe here because
|
|
878
1124
|
// `failproofai policies` is a one-shot command — never do this on the hook
|
|
879
1125
|
// path (see the HooksConfig.conventionPolicies doc comment).
|