failproofai 0.0.13 → 0.0.14-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/.codex/hooks.json +6 -6
- package/.next/standalone/.cursor/hooks.json +6 -6
- package/.next/standalone/.factory/hooks.json +112 -0
- package/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/build-manifest.json +5 -5
- package/.next/standalone/.next/prerender-manifest.json +3 -3
- package/.next/standalone/.next/required-server-files.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page/build-manifest.json +2 -2
- 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.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 +2 -2
- package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
- package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found/page/build-manifest.json +2 -2
- 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.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/_head.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +10 -10
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
- 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.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/audit/run/route.js +3 -3
- package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -1
- 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.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/reminder/route.js.nft.json +1 -1
- 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 +2 -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/build-manifest.json +2 -2
- package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +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 +2 -2
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +15 -15
- package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +10 -10
- package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/page/build-manifest.json +2 -2
- package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
- 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/build-manifest.json +2 -2
- package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +8 -8
- package/.next/standalone/.next/server/app/policies/page.js +1 -1
- 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/build-manifest.json +2 -2
- 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 +3 -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/build-manifest.json +2 -2
- 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 +5 -3
- 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/build-manifest.json +2 -2
- package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/projects/page.js +1 -1
- 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/chunks/[root-of-the-server]__0--lkk6._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0-219ec._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__04_h-a5._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__06cuf1y._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__08w4wmd._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0g6bbuw._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0jllheg._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0jnjf2t._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0q-v9z2._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0q0qzx1._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0q2nbsl._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0rv7m0k._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__16le-kd._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__17g9wh7._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1d9qen3._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1ffkmds._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1fwl2mz._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1legmza._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1mrihkj._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1myjm-d._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1qb590j._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1qxztj-._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1shcqgr._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1xuedea._.js +3 -0
- package/.next/standalone/.next/server/chunks/{_1z062h5._.js → _1vslkoe._.js} +2 -2
- package/.next/standalone/.next/server/chunks/lib_factory-projects_ts_1eo_bk-._.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_openclaw-projects_ts_0gc-p24._.js +3 -0
- package/.next/standalone/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_17k9e3w.js +24 -12
- package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_01r25oi._.js +1 -1
- package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_09z9-p7._.js +1 -1
- package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__00cz9as._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__015_i4t._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__030k0c6._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__03lv-pe._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__042d3cd._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__05r_17v._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__09q1168._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__108slqn._.js → [root-of-the-server]__0brjczq._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0e2l3c1._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0hci7t3._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0hdsupo._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0p84xee._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0qeuy9c._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0s89hoe._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__07iom4f._.js → [root-of-the-server]__0wp9w6i._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ynf7tx._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__170799-._.js +12 -9
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__17ai7sy._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1d8omgc._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1nq7ivq._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1tkjqka._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/_05whahf._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_0_9_ytf._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_11_p9y8._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{_0ul5rf_._.js → _1_ozgif._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/_1p0-leb._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_087bt9w._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_1fvisnp._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_209u41o._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +2 -2
- 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 +1 -1
- package/.next/standalone/.next/server/chunks/ssr/lib_0xkhw_v._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/lib_antigravity-projects_ts_0_6zf11._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/lib_devin-projects_ts_0a64qdy._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/lib_factory-projects_ts_1uyaahq._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/lib_goose-projects_ts_0zkscri._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/lib_openclaw-projects_ts_0qxq3bp._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/{node_modules_html-to-image_es_index_13p7zob.js → node_modules_html-to-image_es_index_12rjfea.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/node_modules_posthog-node_dist_entrypoints_index_node_mjs_11bnuzn._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_1ezd2jf._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_1tnuifj._.js +1 -1
- package/.next/standalone/.next/server/middleware-build-manifest.js +5 -5
- 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 +10 -10
- package/.next/standalone/.next/static/chunks/{13f1kmjea-0md.js → 02jcotghcxrbu.js} +1 -1
- package/.next/standalone/.next/static/chunks/{30ysv-_8jj052.js → 0d5lypu1zs21r.js} +1 -1
- package/.next/standalone/.next/static/chunks/0emg30_6svycu.js +1 -0
- package/.next/standalone/.next/static/chunks/0o9wpnze1ey8y.js +6 -0
- package/.next/standalone/.next/static/chunks/{05apzuand0c22.js → 1359o5785rmve.js} +2 -2
- package/.next/standalone/.next/static/chunks/20tuctw38jbgw.js +1 -0
- package/.next/standalone/.next/static/chunks/{0vc0eak148vo6.js → 2ldhnaweu9ew3.js} +1 -1
- package/.next/standalone/.next/static/chunks/{23c7v2svx90dp.js → 2vav_x0_336ds.js} +1 -1
- package/.next/standalone/.next/static/chunks/3-ogr79xqbw0h.js +1 -0
- package/.next/standalone/.next/static/chunks/36j05kb2x323i.css +2 -0
- package/.next/standalone/.next/static/chunks/3cg7x0joi2b98.js +1 -0
- package/.next/standalone/.next/static/chunks/{36wdtkgdf0zrd.js → 3k87p-tijud-4.js} +1 -1
- package/.next/standalone/.next/static/chunks/{2cejn75gug3j8.js → 3kmaqcp7rldad.js} +1 -1
- package/.next/standalone/.next/static/chunks/{turbopack-0vavqo2d-tlt3.js → turbopack-10hj8t5pf33tu.js} +1 -1
- package/.next/standalone/.opencode/plugins/failproofai.mjs +30 -11
- package/.next/standalone/app/api/audit/run/route.ts +2 -0
- package/.next/standalone/app/audit/_components/empty-state.tsx +1 -1
- package/.next/standalone/app/components/global-error-listeners.tsx +27 -0
- package/.next/standalone/app/globals.css +25 -1
- package/.next/standalone/app/policies/hooks-client.tsx +2 -4
- package/.next/standalone/app/project/[name]/page.tsx +30 -10
- package/.next/standalone/app/project/[name]/session/[sessionId]/page.tsx +71 -21
- package/.next/standalone/assets/logos/antigravity.svg +1 -0
- package/.next/standalone/assets/logos/devin.svg +1 -0
- package/.next/standalone/assets/logos/factory-dark.png +0 -0
- package/.next/standalone/assets/logos/factory-light.png +0 -0
- package/.next/standalone/assets/logos/goose-dark.svg +1 -0
- package/.next/standalone/assets/logos/goose-light.svg +1 -0
- package/.next/standalone/assets/logos/openclaw.svg +22 -0
- package/.next/standalone/ci/cli-integration/Dockerfile +47 -0
- package/.next/standalone/ci/cli-integration/README.md +69 -0
- package/.next/standalone/ci/cli-integration/canary-policies.mjs +45 -0
- package/.next/standalone/ci/cli-integration/capture-tokens.sh +48 -0
- package/.next/standalone/ci/cli-integration/inject-tokens.sh +44 -0
- package/.next/standalone/ci/cli-integration/install-clis.sh +91 -0
- package/.next/standalone/ci/cli-integration/probe-cli.sh +208 -0
- package/.next/standalone/ci/cli-integration/report.js +74 -0
- package/.next/standalone/ci/cli-integration/run.sh +107 -0
- package/.next/standalone/components/navbar.tsx +5 -11
- package/.next/standalone/components/reach-developers.tsx +2 -2
- package/.next/standalone/docker-hook-sync/Dockerfile +8 -4
- package/.next/standalone/lib/antigravity-projects.ts +224 -0
- package/.next/standalone/lib/antigravity-sessions.ts +283 -0
- package/.next/standalone/lib/cli-registry.ts +26 -6
- package/.next/standalone/lib/devin-projects.ts +141 -0
- package/.next/standalone/lib/devin-sessions.ts +343 -0
- package/.next/standalone/lib/download-session.ts +56 -5
- package/.next/standalone/lib/error-origin.ts +67 -0
- package/.next/standalone/lib/factory-projects.ts +109 -0
- package/.next/standalone/lib/factory-sessions.ts +312 -0
- package/.next/standalone/lib/goose-projects.ts +148 -0
- package/.next/standalone/lib/goose-sessions.ts +296 -0
- package/.next/standalone/lib/install-check.ts +231 -0
- package/.next/standalone/lib/openclaw-projects.ts +182 -0
- package/.next/standalone/lib/openclaw-sessions.ts +284 -0
- package/.next/standalone/lib/projects.ts +33 -9
- package/.next/standalone/lib/telemetry-sanitize.ts +43 -0
- package/.next/standalone/openclaw-plugin/index.js +223 -0
- package/.next/standalone/openclaw-plugin/openclaw.plugin.json +6 -0
- package/.next/standalone/openclaw-plugin/package.json +12 -0
- package/.next/standalone/package.json +2 -3
- package/.next/standalone/server.js +1 -1
- package/README.md +94 -62
- package/bin/failproofai.mjs +98 -30
- package/dist/cli.mjs +12499 -9243
- package/lib/antigravity-projects.ts +224 -0
- package/lib/antigravity-sessions.ts +283 -0
- package/lib/cli-registry.ts +26 -6
- package/lib/devin-projects.ts +141 -0
- package/lib/devin-sessions.ts +343 -0
- package/lib/download-session.ts +56 -5
- package/lib/error-origin.ts +67 -0
- package/lib/factory-projects.ts +109 -0
- package/lib/factory-sessions.ts +312 -0
- package/lib/goose-projects.ts +148 -0
- package/lib/goose-sessions.ts +296 -0
- package/lib/install-check.ts +231 -0
- package/lib/openclaw-projects.ts +182 -0
- package/lib/openclaw-sessions.ts +284 -0
- package/lib/projects.ts +33 -9
- package/lib/telemetry-sanitize.ts +43 -0
- package/openclaw-plugin/index.js +223 -0
- package/openclaw-plugin/openclaw.plugin.json +6 -0
- package/openclaw-plugin/package.json +12 -0
- package/package.json +2 -3
- package/scripts/dev-hook.mjs +292 -0
- package/scripts/install-diagnosis.mjs +5 -8
- package/scripts/install-telemetry.mjs +12 -4
- package/scripts/launch.ts +4 -8
- package/scripts/sync-agent-cli-harnesses-prompt.md +7 -10
- package/scripts/translate-docs/cli.ts +120 -53
- package/scripts/translate-docs/config.ts +57 -13
- package/scripts/translate-docs/mdx-translator.ts +177 -28
- package/scripts/translate-docs/mintlify-nav.ts +91 -10
- package/scripts/translate-docs/readme-translator.ts +13 -5
- package/scripts/translate-docs/translator.ts +38 -2
- package/scripts/translate-docs/types.ts +3 -0
- package/scripts/validate-mdx.ts +12 -4
- package/src/audit/cli-adapters/antigravity.ts +87 -0
- package/src/audit/cli-adapters/devin.ts +53 -0
- package/src/audit/cli-adapters/factory.ts +75 -0
- package/src/audit/cli-adapters/goose.ts +53 -0
- package/src/audit/cli-adapters/index.ts +30 -6
- package/src/audit/cli-adapters/openclaw.ts +56 -0
- package/src/audit/cli.ts +83 -8
- package/src/audit/report.ts +1 -1
- package/src/audit/types.ts +1 -1
- package/src/hooks/builtin-policies.ts +5 -5
- package/src/hooks/configure-wizard.ts +356 -0
- package/src/hooks/handler.ts +283 -218
- package/src/hooks/hook-telemetry.ts +43 -3
- package/src/hooks/install-prompt.ts +92 -173
- package/src/hooks/integrations.ts +739 -138
- package/src/hooks/manager.ts +46 -2
- package/src/hooks/policy-evaluator.ts +301 -121
- package/src/hooks/policy-presets.ts +71 -0
- package/src/hooks/resolve-cwd.ts +1 -1
- package/src/hooks/resolve-permission-mode.ts +1 -5
- package/src/hooks/resolve-transcript-path.ts +25 -7
- package/src/hooks/tool-name-canonicalize.ts +36 -3
- package/src/hooks/tui.ts +578 -0
- package/src/hooks/types.ts +447 -109
- package/.next/standalone/.gemini/settings.json +0 -147
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0cag8qd._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0cefjd9._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ekj92q._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__12v-lma._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__136y39g._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__13h8pzr._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1hgv_75._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__04bqvos._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0dqgs96._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0q5rfxg._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0qukut7._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1ql-mch._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_11v0g3z._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/lib_gemini-projects_ts_1c7bgx-._.js +0 -3
- package/.next/standalone/.next/static/chunks/0fa7j157kg9_d.js +0 -1
- package/.next/standalone/.next/static/chunks/0nrah-qv6smeg.js +0 -6
- package/.next/standalone/.next/static/chunks/0wtagd8a5gwq-.js +0 -1
- package/.next/standalone/.next/static/chunks/1c8i78p7t1i-5.js +0 -1
- package/.next/standalone/.next/static/chunks/25qr0e6ez0ei0.js +0 -1
- package/.next/standalone/.next/static/chunks/25s52un3k_wht.css +0 -2
- package/.next/standalone/assets/logos/gemini-dark.svg +0 -13
- package/.next/standalone/assets/logos/gemini-light.svg +0 -13
- package/.next/standalone/lib/gemini-projects.ts +0 -243
- package/.next/standalone/lib/gemini-sessions.ts +0 -365
- package/lib/gemini-projects.ts +0 -243
- package/lib/gemini-sessions.ts +0 -365
- package/scripts/postinstall.mjs +0 -243
- package/scripts/preuninstall.mjs +0 -131
- package/src/audit/cli-adapters/gemini.ts +0 -51
- package/src/hooks/first-run-nudge.ts +0 -146
- /package/.next/standalone/.next/static/{kmzdjTLVs6LqsfyOaUf69 → LkN-JjmhKGmL-WklH7WVi}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{kmzdjTLVs6LqsfyOaUf69 → LkN-JjmhKGmL-WklH7WVi}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{kmzdjTLVs6LqsfyOaUf69 → LkN-JjmhKGmL-WklH7WVi}/_ssgManifest.js +0 -0
package/src/hooks/manager.ts
CHANGED
|
@@ -86,6 +86,14 @@ export function hooksInstalledInSettings(scope: HookScope, cwd?: string): boolea
|
|
|
86
86
|
return claudeCode.hooksInstalledInSettings(scope, cwd);
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
+
export interface InstallHooksOptions {
|
|
90
|
+
/** Replace the enabled set at this scope instead of unioning (default: additive). */
|
|
91
|
+
replace?: boolean;
|
|
92
|
+
/** Suppress this module's installation logging (for callers that render their
|
|
93
|
+
* own UI, like the configure wizard). Errors still surface via console.error. */
|
|
94
|
+
quiet?: boolean;
|
|
95
|
+
}
|
|
96
|
+
|
|
89
97
|
/**
|
|
90
98
|
* Install hooks into Claude Code settings.
|
|
91
99
|
*
|
|
@@ -104,6 +112,38 @@ export async function installHooks(
|
|
|
104
112
|
customPoliciesPath?: string,
|
|
105
113
|
removeCustomHooks = false,
|
|
106
114
|
cli?: IntegrationType[],
|
|
115
|
+
options: InstallHooksOptions = {},
|
|
116
|
+
): Promise<void> {
|
|
117
|
+
const { replace = false, quiet = false } = options;
|
|
118
|
+
if (!quiet) {
|
|
119
|
+
return installHooksImpl(
|
|
120
|
+
policyNames, scope, cwd, includeBeta, source, customPoliciesPath, removeCustomHooks, cli, replace,
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
// Quiet mode: this module logs exclusively via console.log, so muting it for
|
|
124
|
+
// the duration of the call silences installation output at its owner rather
|
|
125
|
+
// than at every call site. console.error (real failures) still flows.
|
|
126
|
+
const origLog = console.log;
|
|
127
|
+
console.log = () => {};
|
|
128
|
+
try {
|
|
129
|
+
return await installHooksImpl(
|
|
130
|
+
policyNames, scope, cwd, includeBeta, source, customPoliciesPath, removeCustomHooks, cli, replace,
|
|
131
|
+
);
|
|
132
|
+
} finally {
|
|
133
|
+
console.log = origLog;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
async function installHooksImpl(
|
|
138
|
+
policyNames?: string[],
|
|
139
|
+
scope: HookScope = "user",
|
|
140
|
+
cwd?: string,
|
|
141
|
+
includeBeta = false,
|
|
142
|
+
source?: string,
|
|
143
|
+
customPoliciesPath?: string,
|
|
144
|
+
removeCustomHooks = false,
|
|
145
|
+
cli?: IntegrationType[],
|
|
146
|
+
replace = false,
|
|
107
147
|
): Promise<void> {
|
|
108
148
|
// Validate user input first before any system checks
|
|
109
149
|
if (policyNames !== undefined && policyNames.length > 0) {
|
|
@@ -159,8 +199,12 @@ export async function installHooks(
|
|
|
159
199
|
} else {
|
|
160
200
|
incoming = policyNames;
|
|
161
201
|
}
|
|
162
|
-
//
|
|
163
|
-
|
|
202
|
+
// Default is additive (union with whatever was already enabled). The
|
|
203
|
+
// configure wizard passes replace=true so the chosen set becomes the full
|
|
204
|
+
// enabled set at this scope (unticking a policy actually removes it).
|
|
205
|
+
selectedPolicies = replace
|
|
206
|
+
? [...new Set(incoming)]
|
|
207
|
+
: [...new Set([...previousConfig.enabledPolicies, ...incoming])];
|
|
164
208
|
} else {
|
|
165
209
|
// Interactive — pre-load current config if it exists
|
|
166
210
|
const preSelected = previousConfig.enabledPolicies.length > 0 ? previousConfig.enabledPolicies : undefined;
|
|
@@ -164,8 +164,7 @@ export async function evaluatePolicies(
|
|
|
164
164
|
// — that shape is only honored on tool events. The only force-retry
|
|
165
165
|
// channel for Stop/SubagentStop is `{followup_message}` on stdout
|
|
166
166
|
// (exit 0); Cursor auto-submits the text as the next user message
|
|
167
|
-
// (capped at `loop_limit`, default 5). Mirrors the Copilot Stop
|
|
168
|
-
// branch at line ~279 and the Gemini AfterAgent branch at line ~188.
|
|
167
|
+
// (capped at `loop_limit`, default 5). Mirrors the Copilot Stop branch.
|
|
169
168
|
// Without this branch, the 5 `require-*-before-stop` builtins were
|
|
170
169
|
// observation-only on Cursor — the deny was logged but the agent
|
|
171
170
|
// stopped cleanly. Ref: https://cursor.com/docs/hooks
|
|
@@ -202,7 +201,7 @@ export async function evaluatePolicies(
|
|
|
202
201
|
// same flat shape — except Stop, where we emit the MANDATORY ACTION
|
|
203
202
|
// wording so the shim can re-inject it as a system-prompt suffix on
|
|
204
203
|
// the next before_agent_start (Pi cannot veto agent_end directly).
|
|
205
|
-
// Mirrors the Cursor/
|
|
204
|
+
// Mirrors the Cursor/Copilot/OpenCode Stop branches above.
|
|
206
205
|
if (session?.cli === "pi") {
|
|
207
206
|
if (eventType === "Stop") {
|
|
208
207
|
const reasonText = `MANDATORY ACTION REQUIRED from failproofai (policy: ${policy.name}): ${reason}\n\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.`;
|
|
@@ -229,33 +228,6 @@ export async function evaluatePolicies(
|
|
|
229
228
|
};
|
|
230
229
|
}
|
|
231
230
|
|
|
232
|
-
// Gemini CLI: flat `{decision: "deny", reason}` for non-Stop events
|
|
233
|
-
// (preferred per Gemini's "Golden Rule" — exit 0 with structured JSON).
|
|
234
|
-
// For Stop (AfterAgent), use `{decision: "block", reason}` to force-retry,
|
|
235
|
-
// mirroring Claude's exit-2-from-Stop "do this before stopping" semantics.
|
|
236
|
-
// Ref: https://geminicli.com/docs/hooks/
|
|
237
|
-
if (session?.cli === "gemini") {
|
|
238
|
-
if (eventType === "Stop") {
|
|
239
|
-
const reasonText = `MANDATORY ACTION REQUIRED from failproofai (policy: ${policy.name}): ${reason}\n\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.`;
|
|
240
|
-
return {
|
|
241
|
-
exitCode: 0,
|
|
242
|
-
stdout: JSON.stringify({ decision: "block", reason: reasonText }),
|
|
243
|
-
stderr: "",
|
|
244
|
-
policyName: policy.name,
|
|
245
|
-
reason,
|
|
246
|
-
decision: "deny",
|
|
247
|
-
};
|
|
248
|
-
}
|
|
249
|
-
return {
|
|
250
|
-
exitCode: 0,
|
|
251
|
-
stdout: JSON.stringify({ decision: "deny", reason: blockedMessage }),
|
|
252
|
-
stderr: "",
|
|
253
|
-
policyName: policy.name,
|
|
254
|
-
reason,
|
|
255
|
-
decision: "deny",
|
|
256
|
-
};
|
|
257
|
-
}
|
|
258
|
-
|
|
259
231
|
// Hermes: the block contract is `{"decision":"block","reason"}` on stdout;
|
|
260
232
|
// Hermes IGNORES exit codes, so the JSON is the only channel. This one
|
|
261
233
|
// return covers every Hermes event we install (PreToolUse / PostToolUse /
|
|
@@ -275,6 +247,36 @@ export async function evaluatePolicies(
|
|
|
275
247
|
};
|
|
276
248
|
}
|
|
277
249
|
|
|
250
|
+
// OpenClaw: the shipped openclaw-plugin parses a flat {permission, reason}
|
|
251
|
+
// verdict and maps it per plugin-hook — before_tool_call → {block:true,
|
|
252
|
+
// blockReason}; before_agent_run → {outcome:"block", reason};
|
|
253
|
+
// before_agent_finalize (Stop) → {action:"revise", reason}. For Stop we
|
|
254
|
+
// emit the MANDATORY ACTION wording so the revise loop carries the
|
|
255
|
+
// directive. Observation hooks (after_tool_call / session_* /
|
|
256
|
+
// subagent_ended / before_compaction) ignore stdout, so the flat deny is
|
|
257
|
+
// logged but cannot veto — a documented limitation. Mirrors the Pi branch.
|
|
258
|
+
if (session?.cli === "openclaw") {
|
|
259
|
+
if (eventType === "Stop") {
|
|
260
|
+
const reasonText = `MANDATORY ACTION REQUIRED from failproofai (policy: ${policy.name}): ${reason}\n\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.`;
|
|
261
|
+
return {
|
|
262
|
+
exitCode: 0,
|
|
263
|
+
stdout: JSON.stringify({ permission: "deny", reason: reasonText }),
|
|
264
|
+
stderr: "",
|
|
265
|
+
policyName: policy.name,
|
|
266
|
+
reason,
|
|
267
|
+
decision: "deny",
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
return {
|
|
271
|
+
exitCode: 0,
|
|
272
|
+
stdout: JSON.stringify({ permission: "deny", reason: blockedMessage }),
|
|
273
|
+
stderr: "",
|
|
274
|
+
policyName: policy.name,
|
|
275
|
+
reason,
|
|
276
|
+
decision: "deny",
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
|
|
278
280
|
// OpenCode: `session.idle` is a notification-only bus event — by the
|
|
279
281
|
// time the plugin handler fires, OpenCode has already gone idle and
|
|
280
282
|
// throwing from the handler does not force-retry. The only working
|
|
@@ -283,8 +285,8 @@ export async function evaluatePolicies(
|
|
|
283
285
|
// shim already routes `hookSpecificOutput.additionalContext` through
|
|
284
286
|
// that path (see buildOpenCodePluginShim's applyDecision), so we emit
|
|
285
287
|
// the deny reason as additionalContext instead of exit-2. Mirrors the
|
|
286
|
-
// Cursor `followup_message`
|
|
287
|
-
//
|
|
288
|
+
// Cursor `followup_message` and Copilot `{decision:"block"}` Stop
|
|
289
|
+
// branches. SubagentStop is widened in for forward
|
|
288
290
|
// compat — OpenCode doesn't yet expose subagent boundaries to plugins.
|
|
289
291
|
if (session?.cli === "opencode") {
|
|
290
292
|
if (eventType === "Stop" || eventType === "SubagentStop") {
|
|
@@ -303,6 +305,105 @@ export async function evaluatePolicies(
|
|
|
303
305
|
// for tool events.
|
|
304
306
|
}
|
|
305
307
|
|
|
308
|
+
// Factory droid: droid drives tool blocking off EXIT CODE 2 (it ignores a
|
|
309
|
+
// JSON `{decision:…}` on tool events — verified live against droid
|
|
310
|
+
// v0.171.0: `Hook returned exit code 2, throwing ToolExecutionControlError`).
|
|
311
|
+
// The one exception is `Stop`, where droid does NOT honor exit-2
|
|
312
|
+
// force-retry; there it reads `{decision:"block", reason}` on stdout at
|
|
313
|
+
// exit 0 ("if decision is block, Droid does not stop"). So: Stop → JSON
|
|
314
|
+
// block; every other event (PreToolUse / PostToolUse / UserPromptSubmit /
|
|
315
|
+
// SubagentStop / …) → exit 2 + the blocked message on stderr.
|
|
316
|
+
if (session?.cli === "factory") {
|
|
317
|
+
if (eventType === "Stop") {
|
|
318
|
+
const reasonText = `MANDATORY ACTION REQUIRED from failproofai (policy: ${policy.name}): ${reason}\n\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.`;
|
|
319
|
+
return {
|
|
320
|
+
exitCode: 0,
|
|
321
|
+
stdout: JSON.stringify({ decision: "block", reason: reasonText }),
|
|
322
|
+
stderr: "",
|
|
323
|
+
policyName: policy.name,
|
|
324
|
+
reason,
|
|
325
|
+
decision: "deny",
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
return {
|
|
329
|
+
exitCode: 2,
|
|
330
|
+
stdout: "",
|
|
331
|
+
stderr: blockedMessage + "\n",
|
|
332
|
+
policyName: policy.name,
|
|
333
|
+
reason,
|
|
334
|
+
decision: "deny",
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// Devin CLI: a pure Claude-clone that honors `{decision:"block", reason}`
|
|
339
|
+
// on stdout at exit 0 for EVERY event (verified live against devin
|
|
340
|
+
// v3000.1.27 — the block overrode `--permission-mode dangerous`). On Stop
|
|
341
|
+
// the reason carries the MANDATORY-ACTION force-retry wording; on other
|
|
342
|
+
// events it's the plain blocked message. One branch covers all events.
|
|
343
|
+
if (session?.cli === "devin") {
|
|
344
|
+
const reasonText =
|
|
345
|
+
eventType === "Stop"
|
|
346
|
+
? `MANDATORY ACTION REQUIRED from failproofai (policy: ${policy.name}): ${reason}\n\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.`
|
|
347
|
+
: blockedMessage;
|
|
348
|
+
return {
|
|
349
|
+
exitCode: 0,
|
|
350
|
+
stdout: JSON.stringify({ decision: "block", reason: reasonText }),
|
|
351
|
+
stderr: "",
|
|
352
|
+
policyName: policy.name,
|
|
353
|
+
reason,
|
|
354
|
+
decision: "deny",
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// Antigravity CLI: its OWN response shapes (NOT Claude's) — verified live
|
|
359
|
+
// against agy v1.1.2. Tool/prompt events honor `{decision:"deny", reason}`
|
|
360
|
+
// on stdout at exit 0 (hard block). The Stop event has no exit-2 retry;
|
|
361
|
+
// instead `{decision:"continue", reason}` re-enters the loop and injects
|
|
362
|
+
// the reason as a system message — that is how the 5 require-*-before-stop
|
|
363
|
+
// builtins enforce on Antigravity.
|
|
364
|
+
if (session?.cli === "antigravity") {
|
|
365
|
+
if (eventType === "Stop") {
|
|
366
|
+
const reasonText = `MANDATORY ACTION REQUIRED from failproofai (policy: ${policy.name}): ${reason}\n\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.`;
|
|
367
|
+
return {
|
|
368
|
+
exitCode: 0,
|
|
369
|
+
stdout: JSON.stringify({ decision: "continue", reason: reasonText }),
|
|
370
|
+
stderr: "",
|
|
371
|
+
policyName: policy.name,
|
|
372
|
+
reason,
|
|
373
|
+
decision: "deny",
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
return {
|
|
377
|
+
exitCode: 0,
|
|
378
|
+
stdout: JSON.stringify({ decision: "deny", reason: blockedMessage }),
|
|
379
|
+
stderr: "",
|
|
380
|
+
policyName: policy.name,
|
|
381
|
+
reason,
|
|
382
|
+
decision: "deny",
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// Goose: the deny contract is `{"decision":"block","reason"}` on stdout at
|
|
387
|
+
// exit 0, honored on PreToolUse ONLY (shipped goose ≥ v1.37.0, PR
|
|
388
|
+
// block/goose#9304; exit 2 also blocks but JSON carries the reason
|
|
389
|
+
// cleanly). Goose has NO Stop event (the 5 require-*-before-stop builtins
|
|
390
|
+
// never fire for it — see CLAUDE.md) and does NOT honor deny on
|
|
391
|
+
// UserPromptSubmit/PostToolUse (observation) — a block emitted on those
|
|
392
|
+
// events is ignored (fail-open), a documented limitation. PreToolUse fires
|
|
393
|
+
// for the shell tool AND inside delegated subagents, so this one branch
|
|
394
|
+
// covers the entire enforceable surface. Mirrors the Hermes branch (no
|
|
395
|
+
// turn-end event to special-case). Verified live against goose v1.43.0.
|
|
396
|
+
if (session?.cli === "goose") {
|
|
397
|
+
return {
|
|
398
|
+
exitCode: 0,
|
|
399
|
+
stdout: JSON.stringify({ decision: "block", reason: blockedMessage }),
|
|
400
|
+
stderr: "",
|
|
401
|
+
policyName: policy.name,
|
|
402
|
+
reason,
|
|
403
|
+
decision: "deny",
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
|
|
306
407
|
if (eventType === "PreToolUse") {
|
|
307
408
|
const response = {
|
|
308
409
|
hookSpecificOutput: {
|
|
@@ -429,8 +530,8 @@ export async function evaluatePolicies(
|
|
|
429
530
|
// Branch first so the rest of the function only handles Claude-shaped
|
|
430
531
|
// responses. We match both Stop and SubagentStop so custom policies
|
|
431
532
|
// subscribing to SubagentStop on Cursor get the same force-retry
|
|
432
|
-
// semantics — mirrors the cli==="copilot" Stop|SubagentStop widening
|
|
433
|
-
//
|
|
533
|
+
// semantics — mirrors the cli==="copilot" Stop|SubagentStop widening.
|
|
534
|
+
// Ref: https://cursor.com/docs/hooks (Stdout Response Format).
|
|
434
535
|
if (session?.cli === "cursor") {
|
|
435
536
|
if (eventType === "Stop" || eventType === "SubagentStop") {
|
|
436
537
|
const response = {
|
|
@@ -499,15 +600,35 @@ export async function evaluatePolicies(
|
|
|
499
600
|
};
|
|
500
601
|
}
|
|
501
602
|
|
|
502
|
-
//
|
|
503
|
-
//
|
|
504
|
-
//
|
|
505
|
-
//
|
|
506
|
-
//
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
603
|
+
// Hermes: no additional-context channel on any event (the only actionable
|
|
604
|
+
// response is `{"decision":"block"}`). So instruct degrades to allow +
|
|
605
|
+
// log — we emit a non-blocking `{decision:"allow", reason}` (Hermes lets
|
|
606
|
+
// the tool run) and surface the note on stderr for the operator's logs.
|
|
607
|
+
// Documented limitation; there is no Stop event to force-retry into.
|
|
608
|
+
if (session?.cli === "hermes") {
|
|
609
|
+
const stderrMsg = instructEntries
|
|
610
|
+
.map((e) => `[failproofai] ${e.policyName}: ${e.reason}`)
|
|
611
|
+
.join("\n");
|
|
612
|
+
return {
|
|
613
|
+
exitCode: 0,
|
|
614
|
+
stdout: JSON.stringify({
|
|
615
|
+
decision: "allow",
|
|
616
|
+
reason: `Instruction from failproofai: ${combined}`,
|
|
617
|
+
}),
|
|
618
|
+
stderr: stderrMsg + "\n",
|
|
619
|
+
policyName: policyNames[0],
|
|
620
|
+
policyNames,
|
|
621
|
+
reason: combined,
|
|
622
|
+
decision: "instruct",
|
|
623
|
+
};
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
// OpenClaw: Stop (before_agent_finalize) can force a revise, so we emit the
|
|
627
|
+
// MANDATORY ACTION wording as a flat deny — the shim maps it to
|
|
628
|
+
// {action:"revise", reason}. Every other event lacks an additional-context
|
|
629
|
+
// channel (before_tool_call's return is {params,block,blockReason} only), so
|
|
630
|
+
// instruct degrades to allow + stderr note, like Hermes.
|
|
631
|
+
if (session?.cli === "openclaw") {
|
|
511
632
|
if (eventType === "Stop") {
|
|
512
633
|
const policyAttribution = policyNames.length === 1
|
|
513
634
|
? `policy: ${policyNames[0]}`
|
|
@@ -515,7 +636,7 @@ export async function evaluatePolicies(
|
|
|
515
636
|
const reasonText = `MANDATORY ACTION REQUIRED from failproofai (${policyAttribution}): ${combined}\n\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.`;
|
|
516
637
|
return {
|
|
517
638
|
exitCode: 0,
|
|
518
|
-
stdout: JSON.stringify({
|
|
639
|
+
stdout: JSON.stringify({ permission: "deny", reason: reasonText }),
|
|
519
640
|
stderr: "",
|
|
520
641
|
policyName: policyNames[0],
|
|
521
642
|
policyNames,
|
|
@@ -523,31 +644,58 @@ export async function evaluatePolicies(
|
|
|
523
644
|
decision: "instruct",
|
|
524
645
|
};
|
|
525
646
|
}
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
647
|
+
const stderrMsg = instructEntries
|
|
648
|
+
.map((e) => `[failproofai] ${e.policyName}: ${e.reason}`)
|
|
649
|
+
.join("\n");
|
|
650
|
+
return {
|
|
651
|
+
exitCode: 0,
|
|
652
|
+
stdout: JSON.stringify({
|
|
653
|
+
permission: "allow",
|
|
654
|
+
reason: `Instruction from failproofai: ${combined}`,
|
|
655
|
+
}),
|
|
656
|
+
stderr: stderrMsg + "\n",
|
|
657
|
+
policyName: policyNames[0],
|
|
658
|
+
policyNames,
|
|
659
|
+
reason: combined,
|
|
660
|
+
decision: "instruct",
|
|
661
|
+
};
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
// OpenCode: same rationale as the deny branch above — emit
|
|
665
|
+
// additionalContext so the shim submits a follow-up via
|
|
666
|
+
// client.session.prompt instead of throwing into a dead handler.
|
|
667
|
+
if (session?.cli === "opencode") {
|
|
668
|
+
if (eventType === "Stop" || eventType === "SubagentStop") {
|
|
669
|
+
const policyAttribution = policyNames.length === 1
|
|
670
|
+
? `policy: ${policyNames[0]}`
|
|
671
|
+
: `policies: ${policyNames.join(", ")}`;
|
|
672
|
+
const reasonText = `MANDATORY ACTION REQUIRED from failproofai (${policyAttribution}): ${combined}\n\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.`;
|
|
673
|
+
return {
|
|
674
|
+
exitCode: 0,
|
|
675
|
+
stdout: JSON.stringify({ hookSpecificOutput: { additionalContext: reasonText } }),
|
|
676
|
+
stderr: "",
|
|
677
|
+
policyName: policyNames[0],
|
|
678
|
+
policyNames,
|
|
679
|
+
reason: combined,
|
|
680
|
+
decision: "instruct",
|
|
547
681
|
};
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
// Factory droid: on Stop, emit the MANDATORY ACTION wording as a
|
|
686
|
+
// `{decision:"block", reason}` on stdout (exit 0) — droid's only turn-end
|
|
687
|
+
// force-retry channel. Every other event lacks an additional-context
|
|
688
|
+
// channel (droid honors JSON only for the Stop block), so instruct degrades
|
|
689
|
+
// to allow + stderr note, like Hermes.
|
|
690
|
+
if (session?.cli === "factory") {
|
|
691
|
+
if (eventType === "Stop") {
|
|
692
|
+
const policyAttribution = policyNames.length === 1
|
|
693
|
+
? `policy: ${policyNames[0]}`
|
|
694
|
+
: `policies: ${policyNames.join(", ")}`;
|
|
695
|
+
const reasonText = `MANDATORY ACTION REQUIRED from failproofai (${policyAttribution}): ${combined}\n\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.`;
|
|
548
696
|
return {
|
|
549
697
|
exitCode: 0,
|
|
550
|
-
stdout: JSON.stringify(
|
|
698
|
+
stdout: JSON.stringify({ decision: "block", reason: reasonText }),
|
|
551
699
|
stderr: "",
|
|
552
700
|
policyName: policyNames[0],
|
|
553
701
|
policyNames,
|
|
@@ -555,8 +703,6 @@ export async function evaluatePolicies(
|
|
|
555
703
|
decision: "instruct",
|
|
556
704
|
};
|
|
557
705
|
}
|
|
558
|
-
// No context-injection channel for SessionEnd/PreCompress/Notification/
|
|
559
|
-
// BeforeModel/AfterModel/BeforeToolSelection — surface via stderr only.
|
|
560
706
|
const stderrMsg = instructEntries
|
|
561
707
|
.map((e) => `[failproofai] ${e.policyName}: ${e.reason}`)
|
|
562
708
|
.join("\n");
|
|
@@ -571,22 +717,20 @@ export async function evaluatePolicies(
|
|
|
571
717
|
};
|
|
572
718
|
}
|
|
573
719
|
|
|
574
|
-
//
|
|
575
|
-
//
|
|
576
|
-
//
|
|
577
|
-
//
|
|
578
|
-
//
|
|
579
|
-
if (session?.cli === "
|
|
580
|
-
const
|
|
581
|
-
|
|
582
|
-
.join("
|
|
720
|
+
// Devin CLI: a pure Claude-clone. On Stop, emit the MANDATORY ACTION
|
|
721
|
+
// wording as `{decision:"block", reason}` on stdout (exit 0) — Devin's
|
|
722
|
+
// turn-end force-retry channel (its exit-2 is not a force-retry). Every
|
|
723
|
+
// other event falls through to the generic Claude additionalContext path
|
|
724
|
+
// below (Devin honors `hookSpecificOutput.additionalContext`).
|
|
725
|
+
if (session?.cli === "devin" && eventType === "Stop") {
|
|
726
|
+
const policyAttribution = policyNames.length === 1
|
|
727
|
+
? `policy: ${policyNames[0]}`
|
|
728
|
+
: `policies: ${policyNames.join(", ")}`;
|
|
729
|
+
const reasonText = `MANDATORY ACTION REQUIRED from failproofai (${policyAttribution}): ${combined}\n\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.`;
|
|
583
730
|
return {
|
|
584
731
|
exitCode: 0,
|
|
585
|
-
stdout: JSON.stringify({
|
|
586
|
-
|
|
587
|
-
reason: `Instruction from failproofai: ${combined}`,
|
|
588
|
-
}),
|
|
589
|
-
stderr: stderrMsg + "\n",
|
|
732
|
+
stdout: JSON.stringify({ decision: "block", reason: reasonText }),
|
|
733
|
+
stderr: "",
|
|
590
734
|
policyName: policyNames[0],
|
|
591
735
|
policyNames,
|
|
592
736
|
reason: combined,
|
|
@@ -594,18 +738,36 @@ export async function evaluatePolicies(
|
|
|
594
738
|
};
|
|
595
739
|
}
|
|
596
740
|
|
|
597
|
-
//
|
|
598
|
-
//
|
|
599
|
-
//
|
|
600
|
-
|
|
601
|
-
|
|
741
|
+
// Antigravity CLI: its OWN instruct shapes (verified live agy v1.1.2).
|
|
742
|
+
// • UserPromptSubmit (canonical for PreInvocation) → `{injectSteps:[{
|
|
743
|
+
// ephemeralMessage}]}` injects the instruction as a transient system
|
|
744
|
+
// message before the model runs.
|
|
745
|
+
// • Stop → `{decision:"continue", reason}` re-enters the loop with the
|
|
746
|
+
// MANDATORY-ACTION directive (Antigravity's only turn-end channel).
|
|
747
|
+
// • Every other event lacks an additional-context channel → degrade to
|
|
748
|
+
// allow + stderr note, like Hermes.
|
|
749
|
+
if (session?.cli === "antigravity") {
|
|
750
|
+
if (eventType === "UserPromptSubmit") {
|
|
751
|
+
return {
|
|
752
|
+
exitCode: 0,
|
|
753
|
+
stdout: JSON.stringify({
|
|
754
|
+
injectSteps: [{ ephemeralMessage: `Instruction from failproofai: ${combined}` }],
|
|
755
|
+
}),
|
|
756
|
+
stderr: "",
|
|
757
|
+
policyName: policyNames[0],
|
|
758
|
+
policyNames,
|
|
759
|
+
reason: combined,
|
|
760
|
+
decision: "instruct",
|
|
761
|
+
};
|
|
762
|
+
}
|
|
763
|
+
if (eventType === "Stop") {
|
|
602
764
|
const policyAttribution = policyNames.length === 1
|
|
603
765
|
? `policy: ${policyNames[0]}`
|
|
604
766
|
: `policies: ${policyNames.join(", ")}`;
|
|
605
767
|
const reasonText = `MANDATORY ACTION REQUIRED from failproofai (${policyAttribution}): ${combined}\n\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.`;
|
|
606
768
|
return {
|
|
607
769
|
exitCode: 0,
|
|
608
|
-
stdout: JSON.stringify({
|
|
770
|
+
stdout: JSON.stringify({ decision: "continue", reason: reasonText }),
|
|
609
771
|
stderr: "",
|
|
610
772
|
policyName: policyNames[0],
|
|
611
773
|
policyNames,
|
|
@@ -613,6 +775,36 @@ export async function evaluatePolicies(
|
|
|
613
775
|
decision: "instruct",
|
|
614
776
|
};
|
|
615
777
|
}
|
|
778
|
+
const stderrMsg = instructEntries
|
|
779
|
+
.map((e) => `[failproofai] ${e.policyName}: ${e.reason}`)
|
|
780
|
+
.join("\n");
|
|
781
|
+
return {
|
|
782
|
+
exitCode: 0,
|
|
783
|
+
stdout: "",
|
|
784
|
+
stderr: stderrMsg + "\n",
|
|
785
|
+
policyName: policyNames[0],
|
|
786
|
+
policyNames,
|
|
787
|
+
reason: combined,
|
|
788
|
+
decision: "instruct",
|
|
789
|
+
};
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
// Goose: a non-block PreToolUse decision injects nothing (verified live — no
|
|
793
|
+
// additional-context channel), and Goose has no Stop event, so instruct
|
|
794
|
+
// degrades to allow + stderr note, like Hermes / Factory non-Stop events.
|
|
795
|
+
if (session?.cli === "goose") {
|
|
796
|
+
const stderrMsg = instructEntries
|
|
797
|
+
.map((e) => `[failproofai] ${e.policyName}: ${e.reason}`)
|
|
798
|
+
.join("\n");
|
|
799
|
+
return {
|
|
800
|
+
exitCode: 0,
|
|
801
|
+
stdout: "",
|
|
802
|
+
stderr: stderrMsg + "\n",
|
|
803
|
+
policyName: policyNames[0],
|
|
804
|
+
policyNames,
|
|
805
|
+
reason: combined,
|
|
806
|
+
decision: "instruct",
|
|
807
|
+
};
|
|
616
808
|
}
|
|
617
809
|
|
|
618
810
|
if (eventType === "Stop" || eventType === "SubagentStop") {
|
|
@@ -629,7 +821,7 @@ export async function evaluatePolicies(
|
|
|
629
821
|
// `[WARNING] Hook warning: ...` but does NOT trigger retry. The
|
|
630
822
|
// documented retry shape is `{decision: "block", reason}` JSON on
|
|
631
823
|
// stdout (exit 0). Mirrors the cli==="copilot" branch in the deny
|
|
632
|
-
// path
|
|
824
|
+
// path so custom instruct policies enforce on Copilot.
|
|
633
825
|
if (session?.cli === "copilot") {
|
|
634
826
|
return {
|
|
635
827
|
exitCode: 0,
|
|
@@ -715,39 +907,20 @@ export async function evaluatePolicies(
|
|
|
715
907
|
};
|
|
716
908
|
}
|
|
717
909
|
|
|
718
|
-
//
|
|
719
|
-
//
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
eventType === "PreToolUse" ||
|
|
724
|
-
eventType === "PostToolUse" ||
|
|
725
|
-
eventType === "SessionStart";
|
|
910
|
+
// OpenClaw: same flat shape as Pi — {permission:"allow", reason}. The shim
|
|
911
|
+
// returns undefined (no block) for an allow verdict regardless, so the note
|
|
912
|
+
// surfaces via stderr; keeping the flat stdout shape keeps the shim's parse
|
|
913
|
+
// path uniform across every verdict.
|
|
914
|
+
if (session?.cli === "openclaw") {
|
|
726
915
|
const stderrMsg = allowEntries
|
|
727
916
|
.map((e) => `[failproofai] ${e.policyName}: ${e.reason}`)
|
|
728
917
|
.join("\n");
|
|
729
|
-
if (supportsContext) {
|
|
730
|
-
// Same fallback chain as the instruct path above — see comment there.
|
|
731
|
-
const hookEventName = session?.hookEventName ?? session?.rawHookEventName ?? eventType;
|
|
732
|
-
const response = {
|
|
733
|
-
hookSpecificOutput: {
|
|
734
|
-
hookEventName,
|
|
735
|
-
additionalContext: `Note from failproofai: ${combined}`,
|
|
736
|
-
},
|
|
737
|
-
};
|
|
738
|
-
return {
|
|
739
|
-
exitCode: 0,
|
|
740
|
-
stdout: JSON.stringify(response),
|
|
741
|
-
stderr: stderrMsg + "\n",
|
|
742
|
-
policyName: policyNames[0],
|
|
743
|
-
policyNames,
|
|
744
|
-
reason: combined,
|
|
745
|
-
decision: "allow",
|
|
746
|
-
};
|
|
747
|
-
}
|
|
748
918
|
return {
|
|
749
919
|
exitCode: 0,
|
|
750
|
-
stdout:
|
|
920
|
+
stdout: JSON.stringify({
|
|
921
|
+
permission: "allow",
|
|
922
|
+
reason: `Note from failproofai: ${combined}`,
|
|
923
|
+
}),
|
|
751
924
|
stderr: stderrMsg + "\n",
|
|
752
925
|
policyName: policyNames[0],
|
|
753
926
|
policyNames,
|
|
@@ -761,13 +934,20 @@ export async function evaluatePolicies(
|
|
|
761
934
|
eventType === "PostToolUse" ||
|
|
762
935
|
eventType === "UserPromptSubmit" ||
|
|
763
936
|
eventType === "PermissionRequest";
|
|
764
|
-
const response = supportsHookSpecificOutput
|
|
765
|
-
? { hookSpecificOutput: { hookEventName: eventType, additionalContext: `Note from failproofai: ${combined}` } }
|
|
766
|
-
: { reason: combined };
|
|
767
937
|
const stderrMsg = allowEntries
|
|
768
938
|
.map((e) => `[failproofai] ${e.policyName}: ${e.reason}`)
|
|
769
939
|
.join("\n");
|
|
770
|
-
|
|
940
|
+
// Only events with a real additional-context channel carry the allow-note
|
|
941
|
+
// to the agent. Everything else (Stop, SubagentStop, Session*, PreCompact, …)
|
|
942
|
+
// has NO channel, so we keep informational allow-notes OUT of stdout — a
|
|
943
|
+
// bare `{reason}` there is rendered as noise (e.g. droid printing a Stop's
|
|
944
|
+
// "…skipping commit check…skipping PR check…" wall on a perfectly fine turn).
|
|
945
|
+
// The note is still logged to stderr + the activity store for diagnostics.
|
|
946
|
+
if (supportsHookSpecificOutput) {
|
|
947
|
+
const response = { hookSpecificOutput: { hookEventName: eventType, additionalContext: `Note from failproofai: ${combined}` } };
|
|
948
|
+
return { exitCode: 0, stdout: JSON.stringify(response), stderr: stderrMsg + "\n", policyName: policyNames[0], policyNames, reason: combined, decision: "allow" };
|
|
949
|
+
}
|
|
950
|
+
return { exitCode: 0, stdout: "", stderr: stderrMsg + "\n", policyName: policyNames[0], policyNames, reason: combined, decision: "allow" };
|
|
771
951
|
}
|
|
772
952
|
return { exitCode: 0, stdout: "", stderr: "", policyName: null, reason: null, decision: "allow" };
|
|
773
953
|
}
|