failproofai 1.0.1 → 1.0.2-beta.1
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]__0l4748x._.js +3 -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]__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/_08x1r5t._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_0bwu160._.js +23 -0
- package/.next/standalone/.next/server/chunks/ssr/{_0u5zauv._.js → _0ns6k3a._.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/{3c808qrfcq0im.js → 01u1cf8js2yd6.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0k5050ezjvv49.js → 0izgu7nqh2zp-.js} +1 -1
- package/.next/standalone/.next/static/chunks/0u4-org_e7zde.js +1 -0
- package/.next/standalone/.next/static/chunks/1mfzsja6ftim5.css +2 -0
- package/.next/standalone/.next/static/chunks/{2zpp1we2jv6tb.js → 1tynnrrh711lr.js} +1 -1
- package/.next/standalone/.next/static/chunks/{1ide1wl2f7zi1.js → 22rqvlr7p_1mv.js} +13 -13
- package/.next/standalone/.next/static/chunks/{31s1smp-g7gks.js → 2whxqyskpirbk.js} +1 -1
- package/.next/standalone/.next/static/chunks/31mwk8k0q3_3g.js +6 -0
- package/.next/standalone/.next/static/chunks/3ms6gxfm82t6s.js +1 -0
- package/.next/standalone/.next/static/chunks/{37fcpc36x9gpe.js → 3tbbs_d8xrvyp.js} +1 -1
- package/.next/standalone/.next/static/chunks/43nlc236oo898.js +1 -0
- 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 +163 -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 -15
- 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 +27 -21
- 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 +579 -306
- package/dist/cli.mjs +6499 -3662
- package/dist/index.js +5 -5
- package/dist/worker.mjs +2390 -1978
- package/package.json +27 -21
- 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 +56 -369
- package/src/hooks/custom-hooks-loader.ts +89 -6
- package/src/hooks/fp-home.ts +92 -4
- package/src/hooks/fp-reset.ts +34 -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 +424 -172
- package/src/hooks/migrations.ts +2 -2
- package/src/hooks/pack-cli.ts +885 -0
- package/src/hooks/pack-failclosed.ts +189 -0
- package/src/hooks/pack-manifest.ts +352 -0
- package/src/hooks/pack-store.ts +891 -0
- package/src/hooks/policy-catalog.ts +535 -0
- package/src/hooks/policy-evaluator.ts +24 -16
- 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 +695 -39
- 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]__07tbbf3._.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/server/chunks/ssr/_0lvyuv4._.js +0 -23
- package/.next/standalone/.next/static/chunks/2_2lhuojq2xop.js +0 -1
- package/.next/standalone/.next/static/chunks/36fw6yk1s6x_f.js +0 -1
- package/.next/standalone/.next/static/chunks/3k7mxbp9hiom0.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/src/hooks/policy-presets.ts +0 -135
- /package/.next/standalone/.next/static/{ZklXxyA5ygsWSQz2u_zii → I5kEb9kSgYS63j4iqfVLO}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{ZklXxyA5ygsWSQz2u_zii → I5kEb9kSgYS63j4iqfVLO}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{ZklXxyA5ygsWSQz2u_zii → I5kEb9kSgYS63j4iqfVLO}/_ssgManifest.js +0 -0
package/bin/failproofai.mjs
CHANGED
|
@@ -34,8 +34,35 @@ if (!process.env.FAILPROOFAI_DIST_PATH) {
|
|
|
34
34
|
|
|
35
35
|
const args = process.argv.slice(2);
|
|
36
36
|
|
|
37
|
-
//
|
|
38
|
-
|
|
37
|
+
// ── one noun for policies ──────────────────────────────────────────────────
|
|
38
|
+
// `policies`, `policy` and `pack` were three commands for one idea, two of them
|
|
39
|
+
// a single letter apart and doing unrelated things. They are now three
|
|
40
|
+
// spellings of the same command. Rewritten HERE, above SUBCOMMANDS and every
|
|
41
|
+
// dispatch below, so the rest of this file mentions only the canonical name and
|
|
42
|
+
// no branch has to remember the aliases.
|
|
43
|
+
//
|
|
44
|
+
// Nothing anybody has typed before stops working — the old spellings are
|
|
45
|
+
// translated, not rejected — which matters because they are printed in shipped
|
|
46
|
+
// help output, in this repo's docs, and in the release notes of every pack
|
|
47
|
+
// published so far.
|
|
48
|
+
if (args[0] === "p" || args[0] === "policy") args[0] = "policies";
|
|
49
|
+
if (args[0] === "pack") {
|
|
50
|
+
args[0] = "policies";
|
|
51
|
+
if (args[1] === "list") {
|
|
52
|
+
// `pack list` was two commands wearing one name: bare it listed what is
|
|
53
|
+
// installed here, with an argument it previewed a pack that is not. Those
|
|
54
|
+
// are different questions, so they are different words now — the bare form
|
|
55
|
+
// and `show`.
|
|
56
|
+
const hasSource = args[2] && !args[2].startsWith("-");
|
|
57
|
+
if (hasSource) args.splice(1, 1, "show");
|
|
58
|
+
else args.splice(1, 1);
|
|
59
|
+
} else if (args[1] === "build") {
|
|
60
|
+
// `pack build` produced the release assets and stopped. That is exactly
|
|
61
|
+
// `publish` with nowhere to publish to, so it IS publish — the local half
|
|
62
|
+
// of it. `publish` with no --repo does the same thing and says so.
|
|
63
|
+
args.splice(0, 2, "publish");
|
|
64
|
+
}
|
|
65
|
+
}
|
|
39
66
|
// Normalize 'configure' / 'setup' → 'config' (aliases), so every later check
|
|
40
67
|
// (SUBCOMMANDS, dispatch) mentions only the canonical name.
|
|
41
68
|
if (args[0] === "configure" || args[0] === "setup") args[0] = "config";
|
|
@@ -271,148 +298,109 @@ if (hookIdx >= 0) {
|
|
|
271
298
|
*/
|
|
272
299
|
async function runCli() {
|
|
273
300
|
// --help / -h (only when not inside a subcommand that handles its own --help)
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
301
|
+
// `update` and `migrate` were missing here, so `failproofai update --help`
|
|
302
|
+
// exited 1 with "Unexpected argument" — both commands had no reachable help
|
|
303
|
+
// at all, only the paragraph in the top-level dump that this rewrite moved.
|
|
304
|
+
// `help` and `publish` are new. `policy` and `pack` are canonicalized to
|
|
305
|
+
// `policies` above and never reach this list.
|
|
306
|
+
const SUBCOMMANDS = ["policies", "audit", "config", "uninstall", "backfill", "flush", "harness", "publish", "update", "migrate", "help"];
|
|
307
|
+
// ── help ─────────────────────────────────────────────────────────────────
|
|
308
|
+
//
|
|
309
|
+
// The index and the reference manual used to be the same document: 152 lines,
|
|
310
|
+
// six screens at 80x24, with every flag of every command inlined. That is a
|
|
311
|
+
// help tier collapse — the thing you read to find a command was the thing you
|
|
312
|
+
// read to use one — and the cost fell on the person who knew least.
|
|
313
|
+
//
|
|
314
|
+
// Now: ONE screen of what exists, and `help <command>` for everything else.
|
|
315
|
+
// `help <command>` is literally `<command> --help`, dispatched below, so there
|
|
316
|
+
// is exactly one copy of each command's documentation and the two spellings
|
|
317
|
+
// cannot drift.
|
|
318
|
+
const helpTopic = args[0] === "help" ? args[1] : undefined;
|
|
319
|
+
if (args[0] === "help" && helpTopic) {
|
|
320
|
+
// `--hook` is the entry point an agent CLI spawns per tool call. It is
|
|
321
|
+
// documented in NO help output — only a module docblock and one error
|
|
322
|
+
// string — so it gets a topic here rather than a line on the index, where a
|
|
323
|
+
// machine-facing flag would only take space from the human-facing commands.
|
|
324
|
+
if (helpTopic === "hook") {
|
|
325
|
+
console.log(`
|
|
326
|
+
failproofai --hook <event> [--cli <name>]
|
|
327
|
+
|
|
328
|
+
The entry point your agent CLI spawns, once per tool call. You do not run this;
|
|
329
|
+
\`failproofai config\` writes it into each CLI's hook configuration for you.
|
|
330
|
+
|
|
331
|
+
--hook <event> PreToolUse, PostToolUse, UserPromptSubmit, Stop,
|
|
332
|
+
SubagentStop, SessionStart, SessionEnd, PreCompact,
|
|
333
|
+
Notification, PermissionRequest
|
|
334
|
+
--cli <name> claude, codex, copilot, cursor, opencode, pi, hermes,
|
|
335
|
+
openclaw, factory, devin, antigravity, goose.
|
|
336
|
+
Defaults to claude. It selects which payload shape to
|
|
337
|
+
expect: each CLI names its events and tool arguments
|
|
338
|
+
differently, and failproofai canonicalizes them.
|
|
339
|
+
|
|
340
|
+
It reads the event as JSON on stdin and answers on stdout, in whatever shape
|
|
341
|
+
that CLI honours. Exit codes and response shapes differ per CLI by necessity —
|
|
342
|
+
see docs.befailproof.ai. Denials are reported to the agent, never to you.
|
|
343
|
+
`.trimStart());
|
|
344
|
+
process.exit(0);
|
|
345
|
+
}
|
|
346
|
+
// Canonicalize the topic the same way a typed command is canonicalized, so
|
|
347
|
+
// `help pack` and `help policy` answer instead of erroring.
|
|
348
|
+
const canonical =
|
|
349
|
+
helpTopic === "p" || helpTopic === "policy" || helpTopic === "pack"
|
|
350
|
+
? "policies"
|
|
351
|
+
: helpTopic === "configure" || helpTopic === "setup"
|
|
352
|
+
? "config"
|
|
353
|
+
: helpTopic;
|
|
354
|
+
if (!SUBCOMMANDS.includes(canonical)) {
|
|
355
|
+
throw new CliError(
|
|
356
|
+
`No help for: ${helpTopic}\n` +
|
|
357
|
+
`Run \`failproofai help\` to see every command.`,
|
|
358
|
+
);
|
|
359
|
+
}
|
|
360
|
+
// `policies add|remove|show` has its own help, distinct from the listing's.
|
|
361
|
+
args.splice(0, 2, canonical, ...(canonical === "policies" && !args[2] ? [] : []), "--help");
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
if (
|
|
365
|
+
args[0] === "help" ||
|
|
366
|
+
((args.includes("--help") || args.includes("-h")) && !SUBCOMMANDS.includes(args[0]))
|
|
367
|
+
) {
|
|
368
|
+
const extraArgs = args.filter((a) => a !== "--help" && a !== "-h" && a !== "help");
|
|
277
369
|
if (extraArgs.length > 0) {
|
|
278
|
-
throw new CliError(`Unexpected argument: ${extraArgs[0]}\nRun \`failproofai
|
|
370
|
+
throw new CliError(`Unexpected argument: ${extraArgs[0]}\nRun \`failproofai help\` for usage.`);
|
|
279
371
|
}
|
|
280
372
|
console.log(`
|
|
281
|
-
failproofai v${version}
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
--scope user|project|local Config scope to write to (default: user)
|
|
308
|
-
(Codex / Copilot / Cursor / OpenCode / Pi support user|project only)
|
|
309
|
-
--beta Include beta policies
|
|
310
|
-
--custom, -c <path> Custom policy file (repeat for multiple files)
|
|
311
|
-
|
|
312
|
-
policies --uninstall, -u Disable policies or remove hooks
|
|
313
|
-
[names...] Specific policy names to disable
|
|
314
|
-
--cli claude|codex|copilot|cursor|opencode|pi|hermes|openclaw|factory|devin|antigravity|goose
|
|
315
|
-
Agent CLI(s) to uninstall from
|
|
316
|
-
--scope user|project|local|all Config scope to remove from (default: user)
|
|
317
|
-
--beta Remove only beta policies
|
|
318
|
-
--custom, -c Clear all explicit custom policy paths
|
|
319
|
-
|
|
320
|
-
policies --help, -h Show this help for the policies command
|
|
321
|
-
|
|
322
|
-
harness list Show extra capture paths per agent CLI
|
|
323
|
-
harness add-path <h> <path> Also capture sessions from <path> for harness
|
|
324
|
-
<h>. Accepts \`<label>=<path>\`; the label
|
|
325
|
-
namespaces agent ids so two copies of one
|
|
326
|
-
project stay distinct.
|
|
327
|
-
harness remove-path <h> <p> Stop capturing that path
|
|
328
|
-
harness --help, -h Show this help for the harness command
|
|
329
|
-
|
|
330
|
-
audit Audit your agent's behavior, then open the
|
|
331
|
-
dashboard at http://localhost:8020/audit
|
|
332
|
-
audit --schedule [days] Audit on a timer (default 7 days) and email you
|
|
333
|
-
what it finds. Signs you in the first time;
|
|
334
|
-
--email <address> skips that question
|
|
335
|
-
audit --no-schedule Stop auditing on a timer
|
|
336
|
-
audit --status Whether scheduling is on, where reports go, and
|
|
337
|
-
when the next scan is due
|
|
338
|
-
audit --help, -h Show this help for the audit command
|
|
339
|
-
|
|
340
|
-
backfill Re-send history the collector already read past
|
|
341
|
-
— after clearing the dashboard, re-enrolling a
|
|
342
|
-
machine, or connecting later than the work
|
|
343
|
-
--since <when> How far back: 30d, 6m, or YYYY-MM-DD
|
|
344
|
-
(default: 30 days)
|
|
345
|
-
--dry-run Report what would be re-read, change nothing
|
|
346
|
-
|
|
347
|
-
flush Deliver everything already spooled, now,
|
|
348
|
-
instead of waiting for the next sweep
|
|
349
|
-
--wait Block until the spool drains (or --timeout)
|
|
350
|
-
--timeout <secs> How long to wait with --wait (default: 60)
|
|
351
|
-
|
|
352
|
-
update Finish an upgrade npm cannot: migrate
|
|
353
|
-
~/.failproofai to this version's layout, put the
|
|
354
|
-
matching daemon binary in place, restart it.
|
|
355
|
-
Run after \`npm install -g failproofai@latest\`.
|
|
356
|
-
--no-daemon Migrate the home only
|
|
357
|
-
|
|
358
|
-
migrate Run pending layout migrations on their own,
|
|
359
|
-
keyed on the layout in ~/.failproofai/VERSION
|
|
360
|
-
(not the npm version, so skipping releases with
|
|
361
|
-
no layout change runs nothing)
|
|
362
|
-
--dry-run Print the steps and change nothing
|
|
363
|
-
|
|
364
|
-
uninstall Remove failproofai from this machine: hook
|
|
365
|
-
entries from every agent CLI, and the daemon
|
|
366
|
-
service. Run this BEFORE \`npm rm -g failproofai\`
|
|
367
|
-
— npm runs no uninstall script, so removing the
|
|
368
|
-
package alone leaves both behind.
|
|
369
|
-
--purge Also delete ~/.failproofai (settings,
|
|
370
|
-
credentials, audit history, daemon binary)
|
|
371
|
-
--dry-run Show what would be removed, change nothing
|
|
372
|
-
--yes, -y Skip the confirmation prompt
|
|
373
|
-
|
|
374
|
-
--version, -v Print version and exit
|
|
375
|
-
--help, -h Show this help message
|
|
376
|
-
|
|
377
|
-
CONVENTION POLICIES
|
|
378
|
-
Drop *policies.{js,mjs,ts} files into .failproofai/policies/ for auto-loading.
|
|
379
|
-
Works at project level (.failproofai/policies/) and user level (~/.failproofai/policies/).
|
|
380
|
-
No --custom flag or config changes needed — just drop files and they're picked up.
|
|
381
|
-
|
|
382
|
-
EXAMPLES
|
|
383
|
-
failproofai policies
|
|
384
|
-
failproofai policies --install
|
|
385
|
-
failproofai policies --install block-sudo sanitize-api-keys --scope project
|
|
386
|
-
failproofai policies --install --cli codex --scope project
|
|
387
|
-
failproofai policies --install --cli copilot --scope project
|
|
388
|
-
failproofai policies --install --cli cursor --scope project
|
|
389
|
-
failproofai policies --install --cli opencode --scope project
|
|
390
|
-
failproofai policies --install --cli pi --scope project
|
|
391
|
-
failproofai policies --install --cli factory --scope project
|
|
392
|
-
failproofai policies --install --cli devin --scope project
|
|
393
|
-
failproofai policies --install --cli claude codex copilot cursor opencode pi hermes openclaw factory devin antigravity goose
|
|
394
|
-
failproofai policies --install --custom ./my-policies.js
|
|
395
|
-
failproofai policies -i -c ./my-policies.js
|
|
396
|
-
failproofai policies --uninstall block-sudo
|
|
397
|
-
failproofai policies --uninstall --cli codex
|
|
398
|
-
failproofai policies --uninstall --cli copilot
|
|
399
|
-
failproofai policies --uninstall --cli cursor
|
|
400
|
-
failproofai policies --uninstall --cli opencode
|
|
401
|
-
failproofai policies --uninstall --cli pi
|
|
402
|
-
failproofai policies --uninstall --custom
|
|
403
|
-
failproofai backfill --since 6m
|
|
404
|
-
failproofai backfill --dry-run
|
|
405
|
-
failproofai flush --wait
|
|
406
|
-
failproofai config --status
|
|
407
|
-
|
|
408
|
-
LINKS
|
|
409
|
-
⭐ Star us: https://github.com/failproofai/failproofai
|
|
410
|
-
📖 Docs: https://docs.befailproof.ai/introduction
|
|
411
|
-
💬 Discord: https://discord.befailproof.ai/
|
|
373
|
+
failproofai v${version} -v version -h this screen
|
|
374
|
+
Usage failproofai <command> [options] Detail failproofai help <command>
|
|
375
|
+
── 1 GET IT RUNNING ───────────────────────────────────────────────────────
|
|
376
|
+
config, setup Interactive setup: agents, daemon, cloud
|
|
377
|
+
update Finish an npm upgrade: migrate home, match daemon
|
|
378
|
+
── 2 CHOOSE WHAT IT ENFORCES ──────────────────────────────────────────────
|
|
379
|
+
policies Every policy on this machine, and whether it is on
|
|
380
|
+
policies add Pick from a list, or name one: <policy> or <owner>/<repo>
|
|
381
|
+
policies remove Turn one policy off, or uninstall a whole pack
|
|
382
|
+
policies show What a pack contains, before you install it
|
|
383
|
+
policies -i / -u Wire failproofai into your agent CLIs
|
|
384
|
+
publish Ship your own policies as a pack anyone can install
|
|
385
|
+
── 3 SEE WHAT IT CAUGHT ───────────────────────────────────────────────────
|
|
386
|
+
(no args) Open the policy dashboard on localhost:8020
|
|
387
|
+
audit Scan your agents' history, then open the audit view
|
|
388
|
+
config --status Cloud connection, daemon version, pause state
|
|
389
|
+
harness Extra paths to capture agent sessions from
|
|
390
|
+
── 4 PUT IT RIGHT ─────────────────────────────────────────────────────────
|
|
391
|
+
config --pause Pause enforcement for one session (30m; max 8h)
|
|
392
|
+
flush Deliver everything already spooled, right now
|
|
393
|
+
backfill Re-send history the collector already read past
|
|
394
|
+
migrate Run pending ~/.failproofai layout migrations
|
|
395
|
+
uninstall Remove hooks and daemon, BEFORE npm rm -g failproofai
|
|
396
|
+
|
|
397
|
+
Docs docs.befailproof.ai Code github.com/failproofai/failproofai
|
|
398
|
+
Chat discord.befailproof.ai Forum reddit.com/r/failproofai
|
|
412
399
|
`.trimStart());
|
|
413
400
|
process.exit(0);
|
|
414
401
|
}
|
|
415
402
|
|
|
403
|
+
|
|
416
404
|
// --version / -v
|
|
417
405
|
if ((args.includes("--version") || args.includes("-v")) && !SUBCOMMANDS.includes(args[0])) {
|
|
418
406
|
const extraArgs = args.filter((a) => a !== "--version" && a !== "-v");
|
|
@@ -697,6 +685,88 @@ OPTIONS
|
|
|
697
685
|
// nothing else — no root, no daemon call — so it works on a machine whose
|
|
698
686
|
// daemon is stopped, which is when someone is most likely to be fixing what
|
|
699
687
|
// it captures.
|
|
688
|
+
// pack list | add | remove
|
|
689
|
+
//
|
|
690
|
+
// Policies that did not ship compiled into this build. Fetches over the
|
|
691
|
+
// network, so it is a CLI command only and is never reachable from the hook
|
|
692
|
+
// path.
|
|
693
|
+
if (args[0] === "pack") {
|
|
694
|
+
const subArgs = args.slice(1);
|
|
695
|
+
if (subArgs.includes("--help") || subArgs.includes("-h")) {
|
|
696
|
+
console.log(`
|
|
697
|
+
failproofai pack — install policy packs published as GitHub releases
|
|
698
|
+
|
|
699
|
+
Usage:
|
|
700
|
+
failproofai pack add core the Failproof AI policies
|
|
701
|
+
failproofai pack add core --policy <a,b> just these
|
|
702
|
+
failproofai pack add core --category <x,y> whole categories
|
|
703
|
+
failproofai pack add core --all everything in it
|
|
704
|
+
failproofai pack list packs installed here
|
|
705
|
+
failproofai pack list <source> what a pack out there contains
|
|
706
|
+
failproofai pack add <source> [--policy <a,b>] [--category <x,y>] [--all]
|
|
707
|
+
failproofai pack remove <publisher/name>
|
|
708
|
+
failproofai pack build <entry.mjs> --id <publisher/name> --version <v>
|
|
709
|
+
|
|
710
|
+
A pack is one entry artifact plus a manifest, verified against the release's
|
|
711
|
+
SHA256SUMS at install time. The digest is recorded, and re-verified before every
|
|
712
|
+
import — so a pack cannot change under this machine after you installed it.
|
|
713
|
+
|
|
714
|
+
<source> is core for the Failproof AI policies, or any of these:
|
|
715
|
+
acme/support-agent newest release, pinned to its exact tag
|
|
716
|
+
acme/support-agent@v2.1.0 that release
|
|
717
|
+
github:acme/support-agent@v2.1.0 same, explicit
|
|
718
|
+
https://github.com/acme/support-agent/releases/tag/v2.1.0
|
|
719
|
+
|
|
720
|
+
Naming no tag installs the newest release AND pins it, so what gets recorded
|
|
721
|
+
always names one version — running the same command later can install something
|
|
722
|
+
different, and it will tell you the tag it chose.
|
|
723
|
+
|
|
724
|
+
By default you get the pack's OWN defaults — the policies its author marked
|
|
725
|
+
safe to switch on unattended — not everything it contains. Take more, or less:
|
|
726
|
+
|
|
727
|
+
--category x,y Take whole categories (see: failproofai pack list)
|
|
728
|
+
--only a,b Take exactly these policies
|
|
729
|
+
--all Take everything the pack contains
|
|
730
|
+
|
|
731
|
+
Re-adding at a newer version keeps whatever you chose rather than switching the
|
|
732
|
+
rest back on.
|
|
733
|
+
|
|
734
|
+
Examples:
|
|
735
|
+
failproofai pack add FailproofAI/policies
|
|
736
|
+
failproofai pack add core --category sanitize,git
|
|
737
|
+
failproofai pack add github:acme/support-agent@v2.1.0 --only block-refunds
|
|
738
|
+
failproofai pack remove acme/support-agent
|
|
739
|
+
|
|
740
|
+
Publishing: pack build writes failproofai-pack.json, failproofai-pack.mjs and
|
|
741
|
+
SHA256SUMS. Attach all three to a GitHub release; anyone then runs
|
|
742
|
+
failproofai pack add <owner>/<repo>
|
|
743
|
+
|
|
744
|
+
Offline: FAILPROOFAI_NO_DOWNLOAD=1 refuses to fetch, while packs already
|
|
745
|
+
installed keep enforcing. FAILPROOFAI_PACK_BASE_URL points the whole thing at a
|
|
746
|
+
mirror instead of github.com.
|
|
747
|
+
`.trimStart());
|
|
748
|
+
process.exit(0);
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
lastSubcommand = "pack";
|
|
752
|
+
const { runPackCommand } = await import("../src/hooks/pack-cli");
|
|
753
|
+
const result = await runPackCommand(subArgs);
|
|
754
|
+
for (const line of result.lines) {
|
|
755
|
+
if (result.exitCode === 0) console.log(line);
|
|
756
|
+
else console.error(line);
|
|
757
|
+
}
|
|
758
|
+
await track("cli_pack", {
|
|
759
|
+
ok: result.exitCode === 0,
|
|
760
|
+
// The subcommand only — never the pack id, source or policy names. A pack
|
|
761
|
+
// source is a value the user typed, and a third-party pack name is a
|
|
762
|
+
// publisher-controlled string; we send shape, never value.
|
|
763
|
+
sub: ["list", "add", "remove"].includes(subArgs[0]) ? subArgs[0] : "unknown",
|
|
764
|
+
});
|
|
765
|
+
lastSubcommand = null;
|
|
766
|
+
await exitAfterFlush(result.exitCode);
|
|
767
|
+
return;
|
|
768
|
+
}
|
|
769
|
+
|
|
700
770
|
if (args[0] === "harness") {
|
|
701
771
|
const subArgs = args.slice(1);
|
|
702
772
|
if (subArgs.length === 0 || subArgs.includes("--help") || subArgs.includes("-h")) {
|
|
@@ -1115,6 +1185,328 @@ WHY THIS EXISTS
|
|
|
1115
1185
|
return;
|
|
1116
1186
|
}
|
|
1117
1187
|
|
|
1188
|
+
// publish — build the release assets AND put them on a GitHub release.
|
|
1189
|
+
//
|
|
1190
|
+
// Top level rather than under `policies`, because it is a PRODUCER verb: the
|
|
1191
|
+
// four consumer words are what every user reads, and almost none of them will
|
|
1192
|
+
// ever ship a pack. `pack build` is canonicalized into this above.
|
|
1193
|
+
if (args[0] === "publish") {
|
|
1194
|
+
const subArgs = args.slice(1);
|
|
1195
|
+
if (subArgs.includes("--help") || subArgs.includes("-h") || subArgs.length === 0) {
|
|
1196
|
+
console.log(`
|
|
1197
|
+
failproofai publish — ship your policies as a pack anyone can install
|
|
1198
|
+
|
|
1199
|
+
USAGE
|
|
1200
|
+
failproofai publish <entry.mjs> --repo <owner>/<repo> --version <version>
|
|
1201
|
+
|
|
1202
|
+
WHAT IT DOES
|
|
1203
|
+
Validates the file with the loader's own rules, writes the three release
|
|
1204
|
+
assets, creates (or reuses) the release, and attaches them. One command.
|
|
1205
|
+
|
|
1206
|
+
Only the release matters. Installs read
|
|
1207
|
+
releases/download/<tag>/<asset> and never touch your git tree — pushing the
|
|
1208
|
+
source is for humans reading it, not for the install to work.
|
|
1209
|
+
|
|
1210
|
+
OPTIONS
|
|
1211
|
+
--repo <owner>/<repo> Where to release it. Omit to build the assets only.
|
|
1212
|
+
--version <version> The pack version. Also the tag, unless --tag says otherwise.
|
|
1213
|
+
--id <publisher/name> The pack's id. Defaults to --repo.
|
|
1214
|
+
--tag <tag> Release tag. Defaults to --version; a leading v is fine.
|
|
1215
|
+
--notes <text> Release notes.
|
|
1216
|
+
--out <dir> Where to write the assets (default: dist-pack)
|
|
1217
|
+
--effect enforce|observe observe records and blocks nothing (default: enforce)
|
|
1218
|
+
--dry-run Build the assets, publish nothing.
|
|
1219
|
+
|
|
1220
|
+
CREDENTIAL
|
|
1221
|
+
GITHUB_TOKEN or GH_TOKEN, else whatever \`gh auth login\` stored. It needs
|
|
1222
|
+
write access to releases on that repository and nothing else. The token is
|
|
1223
|
+
never printed.
|
|
1224
|
+
|
|
1225
|
+
THE REPO MUST BE PUBLIC
|
|
1226
|
+
Installs are anonymous HTTPS with no credential to offer, so a private
|
|
1227
|
+
repository publishes to nobody. This warns you if it is.
|
|
1228
|
+
|
|
1229
|
+
YOUR ENTRY FILE
|
|
1230
|
+
One file, no relative imports — only the entry is digest-pinned, so a pack
|
|
1231
|
+
importing siblings could not honestly claim to be verified. Bundle first
|
|
1232
|
+
(esbuild, bun build, rollup) if yours is split. Each policy may carry
|
|
1233
|
+
\`category\` and \`defaultEnabled\` alongside the usual fields.
|
|
1234
|
+
|
|
1235
|
+
EXAMPLES
|
|
1236
|
+
failproofai publish ./deploy-guard.mjs --repo me/deploy-guard --version 1.0.0
|
|
1237
|
+
failproofai publish ./deploy-guard.mjs --version 1.0.1 --dry-run
|
|
1238
|
+
failproofai publish ./x.mjs --repo me/x --version 2.0.0 --effect observe
|
|
1239
|
+
`.trimStart());
|
|
1240
|
+
process.exit(0);
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
lastSubcommand = "publish";
|
|
1244
|
+
const { runPublishCommand } = await import("../src/hooks/pack-cli");
|
|
1245
|
+
const result = await runPublishCommand(subArgs);
|
|
1246
|
+
for (const line of result.lines) {
|
|
1247
|
+
if (result.exitCode === 0) console.log(line);
|
|
1248
|
+
else console.error(line);
|
|
1249
|
+
}
|
|
1250
|
+
// Shape, never value: whether it published and whether it worked. Never the
|
|
1251
|
+
// repo, the pack id or the entry path — all three are things the user typed.
|
|
1252
|
+
await track("cli_publish", { ok: result.exitCode === 0, dry_run: subArgs.includes("--dry-run") });
|
|
1253
|
+
lastSubcommand = null;
|
|
1254
|
+
await exitAfterFlush(result.exitCode);
|
|
1255
|
+
return;
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1258
|
+
// policies add | remove | show — one noun for policies.
|
|
1259
|
+
//
|
|
1260
|
+
// `policies`, `policy` and `pack` were three commands for one idea. They are
|
|
1261
|
+
// one now, and `add`/`remove` take EITHER a policy name or a pack source,
|
|
1262
|
+
// told apart by a SLASH: a policy name matches /^[A-Za-z0-9._-]+$/, so a
|
|
1263
|
+
// slash is already illegal in one and unambiguous in the other. That is the
|
|
1264
|
+
// rule npm and docker use, and it means nobody has to discover a flag before
|
|
1265
|
+
// they can install somebody else's policies.
|
|
1266
|
+
//
|
|
1267
|
+
// Honors the same --cli / --scope / --beta flags as `policies --install`.
|
|
1268
|
+
if (
|
|
1269
|
+
args[0] === "policies" &&
|
|
1270
|
+
(args[1] === "add" || args[1] === "remove" || args[1] === "show")
|
|
1271
|
+
) {
|
|
1272
|
+
lastSubcommand = "policy";
|
|
1273
|
+
const subArgs = args.slice(1);
|
|
1274
|
+
|
|
1275
|
+
if (subArgs.length === 0 || subArgs.includes("--help") || subArgs.includes("-h")) {
|
|
1276
|
+
console.log(`
|
|
1277
|
+
failproofai policies add|remove|show — choose what your agents may do
|
|
1278
|
+
|
|
1279
|
+
USAGE
|
|
1280
|
+
failproofai policies add Pick from what is installed here
|
|
1281
|
+
failproofai policies add <name> Turn one policy on
|
|
1282
|
+
failproofai policies add <owner>/<repo> Install someone's pack
|
|
1283
|
+
failproofai policies add core Our pack, from this package, offline
|
|
1284
|
+
failproofai policies remove <name> Turn one policy off
|
|
1285
|
+
failproofai policies remove <pack-id> Uninstall a pack
|
|
1286
|
+
failproofai policies show <owner>/<repo> What a pack contains, before you take it
|
|
1287
|
+
|
|
1288
|
+
A NAME OR A SOURCE
|
|
1289
|
+
Anything with a slash is a pack source; anything without is a policy name.
|
|
1290
|
+
Policy names cannot contain a slash, so there is nothing to guess at.
|
|
1291
|
+
|
|
1292
|
+
block-sudo a policy
|
|
1293
|
+
acme/deploy-guard a pack, newest release, pinned
|
|
1294
|
+
acme/deploy-guard@v2.1.0 that release
|
|
1295
|
+
github:acme/deploy-guard@v2.1.0 same, explicit
|
|
1296
|
+
https://github.com/acme/x/releases/tag/v2 the URL you copied
|
|
1297
|
+
|
|
1298
|
+
CHOOSING PART OF A PACK
|
|
1299
|
+
With no flags you get the pack's own defaults and are shown the rest.
|
|
1300
|
+
--policy a,b exactly these
|
|
1301
|
+
--category x,y whole categories (see: failproofai policies show <source>)
|
|
1302
|
+
--all everything it contains
|
|
1303
|
+
Re-adding at a newer version keeps what you chose.
|
|
1304
|
+
|
|
1305
|
+
OPTIONS (policy names only)
|
|
1306
|
+
--cli claude|codex|copilot|cursor|opencode|pi|hermes|openclaw|factory|devin|antigravity|goose
|
|
1307
|
+
Agent CLI(s) to apply to; space-separated or repeated.
|
|
1308
|
+
Omit to detect installed CLIs and prompt.
|
|
1309
|
+
--scope user|project|local Config scope (default: user)
|
|
1310
|
+
--beta Allow beta policies
|
|
1311
|
+
|
|
1312
|
+
EXAMPLES
|
|
1313
|
+
failproofai policies add
|
|
1314
|
+
failproofai policies add block-sudo
|
|
1315
|
+
failproofai policies add sanitize-api-keys --scope project
|
|
1316
|
+
failproofai policies add core --category sanitize,git
|
|
1317
|
+
failproofai policies add acme/deploy-guard --policy block-prod-deploy
|
|
1318
|
+
failproofai policies show acme/deploy-guard
|
|
1319
|
+
failproofai policies remove block-sudo
|
|
1320
|
+
|
|
1321
|
+
Publishing your own: failproofai publish --help
|
|
1322
|
+
Offline: FAILPROOFAI_NO_DOWNLOAD=1 refuses to fetch; packs already installed
|
|
1323
|
+
keep enforcing. FAILPROOFAI_PACK_BASE_URL points it all at a mirror.
|
|
1324
|
+
`.trimStart());
|
|
1325
|
+
process.exit(0);
|
|
1326
|
+
}
|
|
1327
|
+
|
|
1328
|
+
const action = subArgs[0];
|
|
1329
|
+
const rest = subArgs.slice(1);
|
|
1330
|
+
|
|
1331
|
+
// A policy name matches /^[A-Za-z0-9._-]+$/ (pack-manifest.ts owns that
|
|
1332
|
+
// rule), so a slash can only ever mean a pack. `core` is the one name
|
|
1333
|
+
// without a slash that is still a source — it is the short spelling of our
|
|
1334
|
+
// own pack, and is checked by the pack lane itself rather than duplicated
|
|
1335
|
+
// here.
|
|
1336
|
+
const firstPositional = rest.find((a) => !a.startsWith("-"));
|
|
1337
|
+
let looksLikeSource =
|
|
1338
|
+
!!firstPositional &&
|
|
1339
|
+
(firstPositional.includes("/") || firstPositional.startsWith("github:"));
|
|
1340
|
+
if (!looksLikeSource && firstPositional) {
|
|
1341
|
+
// `core` is the one sourcey word with no slash in it. Read the alias set
|
|
1342
|
+
// from the layer that OWNS it rather than restating it here, where the
|
|
1343
|
+
// copy would drift the first time an alias is added — that exact drift
|
|
1344
|
+
// already shipped once, when the dashboard could not resolve a name the
|
|
1345
|
+
// CLI could.
|
|
1346
|
+
const { CORE_ALIASES } = await import("../src/hooks/pack-store");
|
|
1347
|
+
looksLikeSource = CORE_ALIASES.has(firstPositional.toLowerCase());
|
|
1348
|
+
}
|
|
1349
|
+
|
|
1350
|
+
if (action === "show" || looksLikeSource) {
|
|
1351
|
+
if (action === "show" && !firstPositional) {
|
|
1352
|
+
throw new CliError(
|
|
1353
|
+
"Usage: failproofai policies show <owner>/<repo>\n" +
|
|
1354
|
+
"Run `failproofai policies` to see what is already installed here.",
|
|
1355
|
+
);
|
|
1356
|
+
}
|
|
1357
|
+
// One lane, one implementation. `show` is the pack lane's remote preview,
|
|
1358
|
+
// and add/remove of a source are its add/remove — routed by translating
|
|
1359
|
+
// the words rather than by growing a second copy of either.
|
|
1360
|
+
const packArgs =
|
|
1361
|
+
action === "show" ? ["list", ...rest] : [action, ...rest];
|
|
1362
|
+
const { runPackCommand } = await import("../src/hooks/pack-cli");
|
|
1363
|
+
const result = await runPackCommand(packArgs);
|
|
1364
|
+
for (const line of result.lines) {
|
|
1365
|
+
if (result.exitCode === 0) console.log(line);
|
|
1366
|
+
else console.error(line);
|
|
1367
|
+
}
|
|
1368
|
+
await track("cli_pack", {
|
|
1369
|
+
ok: result.exitCode === 0,
|
|
1370
|
+
// The subcommand only — never the pack id, source or policy names. A
|
|
1371
|
+
// pack source is a value the user typed and a third-party pack name is
|
|
1372
|
+
// a publisher-controlled string; we send shape, never value.
|
|
1373
|
+
sub: action,
|
|
1374
|
+
});
|
|
1375
|
+
lastSubcommand = null;
|
|
1376
|
+
await exitAfterFlush(result.exitCode);
|
|
1377
|
+
return;
|
|
1378
|
+
}
|
|
1379
|
+
|
|
1380
|
+
if (action !== "add" && action !== "remove") {
|
|
1381
|
+
throw new CliError(
|
|
1382
|
+
`Unknown policies subcommand: ${action}\n` +
|
|
1383
|
+
`Run \`failproofai policies --help\` for usage.`,
|
|
1384
|
+
);
|
|
1385
|
+
}
|
|
1386
|
+
|
|
1387
|
+
const scopeIdx = rest.indexOf("--scope");
|
|
1388
|
+
const scope = scopeIdx >= 0 ? rest[scopeIdx + 1] : "user";
|
|
1389
|
+
if (scopeIdx >= 0 && (!scope || scope.startsWith("-"))) {
|
|
1390
|
+
throw new CliError("Missing value for --scope. Valid values: user, project, local");
|
|
1391
|
+
}
|
|
1392
|
+
const validScopes = action === "remove"
|
|
1393
|
+
? ["user", "project", "local", "all"]
|
|
1394
|
+
: ["user", "project", "local"];
|
|
1395
|
+
if (scopeIdx >= 0 && !validScopes.includes(scope)) {
|
|
1396
|
+
throw new CliError(`Invalid scope: ${scope}. Valid values: ${validScopes.join(", ")}`);
|
|
1397
|
+
}
|
|
1398
|
+
|
|
1399
|
+
// --cli accepts one or more space-separated values, optionally repeated.
|
|
1400
|
+
const VALID_CLIS = new Set(["claude", "codex", "copilot", "cursor", "opencode", "pi", "hermes", "openclaw", "factory", "devin", "antigravity", "goose"]);
|
|
1401
|
+
const cliFlagValues = [];
|
|
1402
|
+
const cliConsumedIdxs = new Set();
|
|
1403
|
+
const cliFlagIdxs = rest.map((a, i) => (a === "--cli" ? i : -1)).filter((i) => i >= 0);
|
|
1404
|
+
for (const idx of cliFlagIdxs) {
|
|
1405
|
+
let consumed = 0;
|
|
1406
|
+
for (let j = idx + 1; j < rest.length; j++) {
|
|
1407
|
+
const v = rest[j];
|
|
1408
|
+
if (v.startsWith("-")) break;
|
|
1409
|
+
if (!VALID_CLIS.has(v)) break;
|
|
1410
|
+
cliFlagValues.push(v);
|
|
1411
|
+
cliConsumedIdxs.add(j);
|
|
1412
|
+
consumed++;
|
|
1413
|
+
}
|
|
1414
|
+
if (consumed === 0) {
|
|
1415
|
+
throw new CliError("Missing value(s) for --cli. Usage: --cli claude codex copilot cursor opencode pi hermes openclaw (or any subset)");
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
1418
|
+
|
|
1419
|
+
const includeBeta = rest.includes("--beta");
|
|
1420
|
+
|
|
1421
|
+
// Reject unknown flags.
|
|
1422
|
+
const knownFlags = new Set(["--scope", "--cli", "--beta"]);
|
|
1423
|
+
const unknownFlag = rest.find((a) => a.startsWith("-") && !knownFlags.has(a));
|
|
1424
|
+
if (unknownFlag) {
|
|
1425
|
+
throw new CliError(`Unknown flag: ${unknownFlag}\nRun \`failproofai policy --help\` for usage.`);
|
|
1426
|
+
}
|
|
1427
|
+
|
|
1428
|
+
// Positional policy names = anything not consumed by --scope / --cli.
|
|
1429
|
+
const consumedIdxs = new Set();
|
|
1430
|
+
if (scopeIdx >= 0) consumedIdxs.add(scopeIdx + 1);
|
|
1431
|
+
for (const i of cliConsumedIdxs) consumedIdxs.add(i);
|
|
1432
|
+
const positional = rest.filter(
|
|
1433
|
+
(a, idx) => !a.startsWith("-") && !consumedIdxs.has(idx),
|
|
1434
|
+
);
|
|
1435
|
+
|
|
1436
|
+
if (positional.length === 0) {
|
|
1437
|
+
// Naming nothing is a question, not a mistake. It used to be an error
|
|
1438
|
+
// telling you to go and read a list somewhere else and come back — so
|
|
1439
|
+
// the answer is to SHOW the list, here, with what is already on ticked.
|
|
1440
|
+
const { runPolicyPicker } = await import("../src/hooks/pack-cli");
|
|
1441
|
+
const result = await runPolicyPicker(action, { stdin: process.stdin, stdout: process.stdout });
|
|
1442
|
+
for (const line of result.lines) {
|
|
1443
|
+
if (result.exitCode === 0) console.log(line);
|
|
1444
|
+
else console.error(line);
|
|
1445
|
+
}
|
|
1446
|
+
await track("cli_policy_picker", { ok: result.exitCode === 0, action });
|
|
1447
|
+
lastSubcommand = null;
|
|
1448
|
+
await exitAfterFlush(result.exitCode);
|
|
1449
|
+
return;
|
|
1450
|
+
}
|
|
1451
|
+
if (positional.length > 1) {
|
|
1452
|
+
throw new CliError(
|
|
1453
|
+
`\`policy ${action}\` takes exactly one policy name (got ${positional.length}).\n` +
|
|
1454
|
+
`For multiple policies use \`failproofai policies --${action === "add" ? "install" : "uninstall"} ${positional.join(" ")}\`.`,
|
|
1455
|
+
);
|
|
1456
|
+
}
|
|
1457
|
+
const policyName = positional[0];
|
|
1458
|
+
|
|
1459
|
+
const { resolveTargetClis } = await import("../src/hooks/install-prompt");
|
|
1460
|
+
const cli = await resolveTargetClis(
|
|
1461
|
+
cliFlagValues.length > 0 ? cliFlagValues : undefined,
|
|
1462
|
+
action === "add" ? "install" : "uninstall",
|
|
1463
|
+
);
|
|
1464
|
+
|
|
1465
|
+
lastPolicyAction = action;
|
|
1466
|
+
if (action === "add") {
|
|
1467
|
+
const { installHooks } = await import("../src/hooks/manager");
|
|
1468
|
+
await installHooks(
|
|
1469
|
+
[policyName],
|
|
1470
|
+
scope,
|
|
1471
|
+
undefined,
|
|
1472
|
+
includeBeta,
|
|
1473
|
+
undefined,
|
|
1474
|
+
undefined,
|
|
1475
|
+
false,
|
|
1476
|
+
cli,
|
|
1477
|
+
);
|
|
1478
|
+
await track("cli_policy_add_success", {
|
|
1479
|
+
scope,
|
|
1480
|
+
cli,
|
|
1481
|
+
cli_count: cli.length,
|
|
1482
|
+
policy_name: policyName,
|
|
1483
|
+
include_beta: includeBeta,
|
|
1484
|
+
});
|
|
1485
|
+
} else {
|
|
1486
|
+
// `policy remove <name>` always removes the named policy regardless
|
|
1487
|
+
// of whether it's beta or not — passing `betaOnly: includeBeta`
|
|
1488
|
+
// here was a mislabel that only affected the telemetry field, not
|
|
1489
|
+
// the actual remove. Drop the `--beta` semantic for remove and
|
|
1490
|
+
// emit beta_only: false unconditionally so dashboards don't see
|
|
1491
|
+
// ghost "beta removal" events.
|
|
1492
|
+
const { removeHooks } = await import("../src/hooks/manager");
|
|
1493
|
+
await removeHooks(
|
|
1494
|
+
[policyName],
|
|
1495
|
+
scope,
|
|
1496
|
+
undefined,
|
|
1497
|
+
{ betaOnly: false, removeCustomHooks: false, cli },
|
|
1498
|
+
);
|
|
1499
|
+
await track("cli_policy_remove_success", {
|
|
1500
|
+
scope,
|
|
1501
|
+
cli,
|
|
1502
|
+
cli_count: cli.length,
|
|
1503
|
+
policy_name: policyName,
|
|
1504
|
+
beta_only: false,
|
|
1505
|
+
});
|
|
1506
|
+
}
|
|
1507
|
+
lastPolicyAction = null;
|
|
1508
|
+
process.exit(0);
|
|
1509
|
+
}
|
|
1118
1510
|
// policies [--install|-i|--uninstall|-u|--help|-h] [names...] [--scope] [--beta] [--custom|-c <path>]
|
|
1119
1511
|
if (args[0] === "policies") {
|
|
1120
1512
|
const subArgs = args.slice(1);
|
|
@@ -1129,8 +1521,14 @@ failproofai policies — manage Failproof AI policies
|
|
|
1129
1521
|
|
|
1130
1522
|
USAGE
|
|
1131
1523
|
failproofai policies List all policies and their status
|
|
1132
|
-
failproofai policies
|
|
1133
|
-
failproofai policies
|
|
1524
|
+
failproofai policies add [what] Turn one on, take a pack, or pick
|
|
1525
|
+
failproofai policies remove <what> Turn one off, or uninstall a pack
|
|
1526
|
+
failproofai policies show <owner>/<repo> What a pack holds, before you take it
|
|
1527
|
+
failproofai policies --install, -i Wire policies into your agent CLIs
|
|
1528
|
+
failproofai policies --uninstall, -u Unwire them, or strip the hooks
|
|
1529
|
+
|
|
1530
|
+
policy, pack and p are all spellings of policies.
|
|
1531
|
+
Detail on the first three: failproofai policies add --help
|
|
1134
1532
|
|
|
1135
1533
|
OPTIONS (install)
|
|
1136
1534
|
[names...] Specific policy names to enable (omit for interactive)
|
|
@@ -1176,6 +1574,10 @@ EXAMPLES
|
|
|
1176
1574
|
failproofai policies --uninstall --cli pi
|
|
1177
1575
|
failproofai policies -u
|
|
1178
1576
|
failproofai policies --uninstall --custom
|
|
1577
|
+
failproofai pack add core
|
|
1578
|
+
failproofai pack add core --category git,database
|
|
1579
|
+
failproofai pack list acme/support-agent
|
|
1580
|
+
failproofai pack build ./my-policies.mjs --id acme/support --version 1.0.0
|
|
1179
1581
|
`.trimStart());
|
|
1180
1582
|
process.exit(0);
|
|
1181
1583
|
}
|
|
@@ -1391,163 +1793,6 @@ EXAMPLES
|
|
|
1391
1793
|
return;
|
|
1392
1794
|
}
|
|
1393
1795
|
|
|
1394
|
-
// policy — single-policy shortcut over `policies --install <name>`.
|
|
1395
|
-
// failproofai policy add <name> enable one policy (defaults: claude/user)
|
|
1396
|
-
// failproofai policy remove <name> disable one policy
|
|
1397
|
-
// Honors the same --cli / --scope / --beta flags as `policies --install`.
|
|
1398
|
-
if (args[0] === "policy") {
|
|
1399
|
-
lastSubcommand = "policy";
|
|
1400
|
-
const subArgs = args.slice(1);
|
|
1401
|
-
|
|
1402
|
-
if (subArgs.length === 0 || subArgs.includes("--help") || subArgs.includes("-h")) {
|
|
1403
|
-
console.log(`
|
|
1404
|
-
failproofai policy — manage a single FailproofAI policy
|
|
1405
|
-
|
|
1406
|
-
USAGE
|
|
1407
|
-
failproofai policy add <name> Enable one policy
|
|
1408
|
-
failproofai policy remove <name> Disable one policy
|
|
1409
|
-
|
|
1410
|
-
OPTIONS
|
|
1411
|
-
--cli claude|codex|copilot|cursor|opencode|pi|hermes|openclaw|factory|devin|antigravity|goose
|
|
1412
|
-
Agent CLI(s) to apply to; space-separated or repeated.
|
|
1413
|
-
Omit to detect installed CLIs and prompt.
|
|
1414
|
-
--scope user|project|local Config scope (default: user)
|
|
1415
|
-
--beta Allow beta policies
|
|
1416
|
-
|
|
1417
|
-
EXAMPLES
|
|
1418
|
-
failproofai policy add block-sudo
|
|
1419
|
-
failproofai policy add sanitize-api-keys --scope project
|
|
1420
|
-
failproofai policy add block-force-push --cli claude codex
|
|
1421
|
-
failproofai policy remove block-sudo
|
|
1422
|
-
`.trimStart());
|
|
1423
|
-
process.exit(0);
|
|
1424
|
-
}
|
|
1425
|
-
|
|
1426
|
-
const action = subArgs[0];
|
|
1427
|
-
if (action !== "add" && action !== "remove") {
|
|
1428
|
-
throw new CliError(
|
|
1429
|
-
`Unknown policy subcommand: ${action}\n` +
|
|
1430
|
-
`Run \`failproofai policy --help\` for usage.`,
|
|
1431
|
-
);
|
|
1432
|
-
}
|
|
1433
|
-
|
|
1434
|
-
const rest = subArgs.slice(1);
|
|
1435
|
-
|
|
1436
|
-
const scopeIdx = rest.indexOf("--scope");
|
|
1437
|
-
const scope = scopeIdx >= 0 ? rest[scopeIdx + 1] : "user";
|
|
1438
|
-
if (scopeIdx >= 0 && (!scope || scope.startsWith("-"))) {
|
|
1439
|
-
throw new CliError("Missing value for --scope. Valid values: user, project, local");
|
|
1440
|
-
}
|
|
1441
|
-
const validScopes = action === "remove"
|
|
1442
|
-
? ["user", "project", "local", "all"]
|
|
1443
|
-
: ["user", "project", "local"];
|
|
1444
|
-
if (scopeIdx >= 0 && !validScopes.includes(scope)) {
|
|
1445
|
-
throw new CliError(`Invalid scope: ${scope}. Valid values: ${validScopes.join(", ")}`);
|
|
1446
|
-
}
|
|
1447
|
-
|
|
1448
|
-
// --cli accepts one or more space-separated values, optionally repeated.
|
|
1449
|
-
const VALID_CLIS = new Set(["claude", "codex", "copilot", "cursor", "opencode", "pi", "hermes", "openclaw", "factory", "devin", "antigravity", "goose"]);
|
|
1450
|
-
const cliFlagValues = [];
|
|
1451
|
-
const cliConsumedIdxs = new Set();
|
|
1452
|
-
const cliFlagIdxs = rest.map((a, i) => (a === "--cli" ? i : -1)).filter((i) => i >= 0);
|
|
1453
|
-
for (const idx of cliFlagIdxs) {
|
|
1454
|
-
let consumed = 0;
|
|
1455
|
-
for (let j = idx + 1; j < rest.length; j++) {
|
|
1456
|
-
const v = rest[j];
|
|
1457
|
-
if (v.startsWith("-")) break;
|
|
1458
|
-
if (!VALID_CLIS.has(v)) break;
|
|
1459
|
-
cliFlagValues.push(v);
|
|
1460
|
-
cliConsumedIdxs.add(j);
|
|
1461
|
-
consumed++;
|
|
1462
|
-
}
|
|
1463
|
-
if (consumed === 0) {
|
|
1464
|
-
throw new CliError("Missing value(s) for --cli. Usage: --cli claude codex copilot cursor opencode pi hermes openclaw (or any subset)");
|
|
1465
|
-
}
|
|
1466
|
-
}
|
|
1467
|
-
|
|
1468
|
-
const includeBeta = rest.includes("--beta");
|
|
1469
|
-
|
|
1470
|
-
// Reject unknown flags.
|
|
1471
|
-
const knownFlags = new Set(["--scope", "--cli", "--beta"]);
|
|
1472
|
-
const unknownFlag = rest.find((a) => a.startsWith("-") && !knownFlags.has(a));
|
|
1473
|
-
if (unknownFlag) {
|
|
1474
|
-
throw new CliError(`Unknown flag: ${unknownFlag}\nRun \`failproofai policy --help\` for usage.`);
|
|
1475
|
-
}
|
|
1476
|
-
|
|
1477
|
-
// Positional policy names = anything not consumed by --scope / --cli.
|
|
1478
|
-
const consumedIdxs = new Set();
|
|
1479
|
-
if (scopeIdx >= 0) consumedIdxs.add(scopeIdx + 1);
|
|
1480
|
-
for (const i of cliConsumedIdxs) consumedIdxs.add(i);
|
|
1481
|
-
const positional = rest.filter(
|
|
1482
|
-
(a, idx) => !a.startsWith("-") && !consumedIdxs.has(idx),
|
|
1483
|
-
);
|
|
1484
|
-
|
|
1485
|
-
if (positional.length === 0) {
|
|
1486
|
-
throw new CliError(
|
|
1487
|
-
`Missing policy name.\n` +
|
|
1488
|
-
`Usage: failproofai policy ${action} <name>\n` +
|
|
1489
|
-
`Run \`failproofai policies\` to see available names.`,
|
|
1490
|
-
);
|
|
1491
|
-
}
|
|
1492
|
-
if (positional.length > 1) {
|
|
1493
|
-
throw new CliError(
|
|
1494
|
-
`\`policy ${action}\` takes exactly one policy name (got ${positional.length}).\n` +
|
|
1495
|
-
`For multiple policies use \`failproofai policies --${action === "add" ? "install" : "uninstall"} ${positional.join(" ")}\`.`,
|
|
1496
|
-
);
|
|
1497
|
-
}
|
|
1498
|
-
const policyName = positional[0];
|
|
1499
|
-
|
|
1500
|
-
const { resolveTargetClis } = await import("../src/hooks/install-prompt");
|
|
1501
|
-
const cli = await resolveTargetClis(
|
|
1502
|
-
cliFlagValues.length > 0 ? cliFlagValues : undefined,
|
|
1503
|
-
action === "add" ? "install" : "uninstall",
|
|
1504
|
-
);
|
|
1505
|
-
|
|
1506
|
-
lastPolicyAction = action;
|
|
1507
|
-
if (action === "add") {
|
|
1508
|
-
const { installHooks } = await import("../src/hooks/manager");
|
|
1509
|
-
await installHooks(
|
|
1510
|
-
[policyName],
|
|
1511
|
-
scope,
|
|
1512
|
-
undefined,
|
|
1513
|
-
includeBeta,
|
|
1514
|
-
undefined,
|
|
1515
|
-
undefined,
|
|
1516
|
-
false,
|
|
1517
|
-
cli,
|
|
1518
|
-
);
|
|
1519
|
-
await track("cli_policy_add_success", {
|
|
1520
|
-
scope,
|
|
1521
|
-
cli,
|
|
1522
|
-
cli_count: cli.length,
|
|
1523
|
-
policy_name: policyName,
|
|
1524
|
-
include_beta: includeBeta,
|
|
1525
|
-
});
|
|
1526
|
-
} else {
|
|
1527
|
-
// `policy remove <name>` always removes the named policy regardless
|
|
1528
|
-
// of whether it's beta or not — passing `betaOnly: includeBeta`
|
|
1529
|
-
// here was a mislabel that only affected the telemetry field, not
|
|
1530
|
-
// the actual remove. Drop the `--beta` semantic for remove and
|
|
1531
|
-
// emit beta_only: false unconditionally so dashboards don't see
|
|
1532
|
-
// ghost "beta removal" events.
|
|
1533
|
-
const { removeHooks } = await import("../src/hooks/manager");
|
|
1534
|
-
await removeHooks(
|
|
1535
|
-
[policyName],
|
|
1536
|
-
scope,
|
|
1537
|
-
undefined,
|
|
1538
|
-
{ betaOnly: false, removeCustomHooks: false, cli },
|
|
1539
|
-
);
|
|
1540
|
-
await track("cli_policy_remove_success", {
|
|
1541
|
-
scope,
|
|
1542
|
-
cli,
|
|
1543
|
-
cli_count: cli.length,
|
|
1544
|
-
policy_name: policyName,
|
|
1545
|
-
beta_only: false,
|
|
1546
|
-
});
|
|
1547
|
-
}
|
|
1548
|
-
lastPolicyAction = null;
|
|
1549
|
-
process.exit(0);
|
|
1550
|
-
}
|
|
1551
1796
|
|
|
1552
1797
|
// config — the interactive setup launcher (scope, agents, policies).
|
|
1553
1798
|
// `configure` and `setup` are canonicalized to "config" up top. Running it
|
|
@@ -1709,16 +1954,44 @@ PAUSING ENFORCEMENT (one session, always time-boxed)
|
|
|
1709
1954
|
// `--status` answers "what is this machine's state?", which is both
|
|
1710
1955
|
// halves: whether enforcement is paused AND whether cloud is connected.
|
|
1711
1956
|
if (wantsStatus) {
|
|
1712
|
-
const {
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1957
|
+
const { connectionStatusReport, versionStatusLines } = await import(
|
|
1958
|
+
"../src/hooks/cloud-enrollment-cli"
|
|
1959
|
+
);
|
|
1960
|
+
const { optsFor, printBlock, rows, stack, title, warning } = await import(
|
|
1961
|
+
"../src/hooks/tui"
|
|
1962
|
+
);
|
|
1963
|
+
const opts = optsFor(process.stdout);
|
|
1964
|
+
const report = connectionStatusReport();
|
|
1965
|
+
// The version line was written to be "the only place a user can find out
|
|
1966
|
+
// which daemon they are running" and then never called from anywhere. It
|
|
1967
|
+
// is the right thing for the heading to carry, and it retires a heading
|
|
1968
|
+
// that would otherwise have said the word "status" back to someone who
|
|
1969
|
+
// just typed it.
|
|
1970
|
+
printBlock(
|
|
1971
|
+
process.stdout,
|
|
1972
|
+
stack(
|
|
1973
|
+
title("failproofai config", versionStatusLines()[0], opts),
|
|
1974
|
+
// ONE rows() call over both blocks, so the connection facts and the
|
|
1975
|
+
// enforcement state share a label column. Rendered separately they
|
|
1976
|
+
// computed one column each and the window read as two commands'
|
|
1977
|
+
// output stacked up.
|
|
1978
|
+
//
|
|
1979
|
+
// Always printed, including where reports can never work: "why am I
|
|
1980
|
+
// not getting them?" is the question --status exists to answer, and
|
|
1981
|
+
// an omitted line answers it with silence.
|
|
1982
|
+
rows([...report.rows, ...(result.rows ?? [])], opts),
|
|
1983
|
+
report.warnings.length > 0 ? warning(report.warnings, opts) : null,
|
|
1984
|
+
// The trailer is not rows — it is the note and the resume command.
|
|
1985
|
+
// Rendering only `rows` dropped the one line that tells a paused
|
|
1986
|
+
// user how to get unpaused.
|
|
1987
|
+
result.rows ? (result.trailer ?? null) : result.lines,
|
|
1988
|
+
),
|
|
1989
|
+
);
|
|
1990
|
+
} else {
|
|
1991
|
+
for (const line of result.lines) {
|
|
1992
|
+
if (result.exitCode === 0) console.log(line);
|
|
1993
|
+
else console.error(line);
|
|
1994
|
+
}
|
|
1722
1995
|
}
|
|
1723
1996
|
await track("cli_pause_invoked", {
|
|
1724
1997
|
action: pauseIdx >= 0 ? "pause" : wantsResume ? "resume" : "status",
|