failproofai 0.0.10 → 0.0.11-beta.2
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 +7 -7
- 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 +4 -4
- 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 +4 -4
- 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 +4 -4
- package/.next/standalone/.next/server/app/_not-found/page/next-font-manifest.json +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 +4 -4
- 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/download/[project]/[session]/route.js +1 -1
- package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/index.html +1 -1
- package/.next/standalone/.next/server/app/index.rsc +16 -16
- package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +16 -16
- 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 +3 -3
- package/.next/standalone/.next/server/app/page/build-manifest.json +4 -4
- package/.next/standalone/.next/server/app/page/next-font-manifest.json +1 -1
- package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/page.js +4 -4
- 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 +4 -4
- package/.next/standalone/.next/server/app/policies/page/next-font-manifest.json +1 -1
- package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +8 -8
- package/.next/standalone/.next/server/app/policies/page.js +4 -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/build-manifest.json +4 -4
- package/.next/standalone/.next/server/app/project/[name]/page/next-font-manifest.json +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 +4 -4
- 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 +4 -4
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/next-font-manifest.json +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 +4 -4
- 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 +4 -4
- package/.next/standalone/.next/server/app/projects/page/next-font-manifest.json +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 +4 -4
- 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]__0d_ob4n._.js +1 -1
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__044xt9.._.js → [root-of-the-server]__0fwb7ao._.js} +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0g48iv.._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0j8-xkl._.js +1 -1
- package/.next/standalone/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_0bdfoky.js +1 -1
- package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_05pz9._._.js +1 -1
- package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_0z7w.hh._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0-wn51s._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__01as125._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__098zro9._.js +19 -0
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__02r.cjq._.js → [root-of-the-server]__09v.ljl._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0agrcb8._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0b7hkr~._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ehh6vp._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0g8l0tu._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0j4l6hl._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0ye1w50._.js → [root-of-the-server]__0k5n2kz._.js} +3 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0lp08ll._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0n0yaqw._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0o21f.o._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0t8juvy._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__10xgshr._.js → [root-of-the-server]__0tcyn68._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ts150~._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0podumr._.js → [root-of-the-server]__0uylufv._.js} +3 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ymlddl._.js +5 -5
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0~03grs._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/app_0cdqd9w._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_0xerkr6._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_0q-m0y-._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/lib_utils_ts_068jk73._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/node_modules_0ttbz1~._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_06u0kr8._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_0h9llsw._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0a_7sdg.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0ef3uwk.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0j79~gv.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0pbja1x.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0r6o0i2.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_11y81~_.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_12or2kf.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/node_modules_posthog-node_dist_entrypoints_index_node_mjs_0mebn66._.js +1 -1
- package/.next/standalone/.next/server/functions-config-manifest.json +2 -2
- package/.next/standalone/.next/server/middleware-build-manifest.js +7 -7
- package/.next/standalone/.next/server/next-font-manifest.js +1 -1
- package/.next/standalone/.next/server/next-font-manifest.json +6 -6
- 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 +9 -9
- package/.next/standalone/.next/static/chunks/07kpqoo7kuckx.js +6 -0
- package/.next/standalone/.next/static/chunks/0a40sy4tk8ioe.js +1 -0
- package/.next/standalone/.next/static/chunks/{12l2t63hkyo2q.js → 0azb~vy9ds_uy.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0j171xiqge4rv.js → 0bke.~atnsbeb.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0lt8ko3lw.5yt.js → 0bv1oyxspkpkb.js} +1 -1
- package/.next/standalone/.next/static/chunks/{179yytvmam0ug.js → 0dvhi-prcsh3~.js} +1 -1
- package/.next/standalone/.next/static/chunks/0f5p9plm.aqlp.css +2 -0
- package/.next/standalone/.next/static/chunks/0ffvlbgzgnlw7.js +2 -0
- package/.next/standalone/.next/static/chunks/{150i0n26fnvso.js → 0n1n67imq.udf.js} +1 -1
- package/.next/standalone/.next/static/chunks/0spktq7xqab9h.js +1 -0
- package/.next/standalone/.next/static/chunks/{14lii11wmo450.js → 118q3uljozd5z.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0pkl..xgo-qox.js → 11w14gnqzprir.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0rnqmir4cd5p9.js → 17mubwtqwijpu.js} +1 -1
- package/.next/standalone/.next/static/chunks/{turbopack-05z7a19q43zfq.js → turbopack-0nh.aopesgj~5.js} +1 -1
- package/.next/standalone/.next/static/media/4fa387ec64143e14-s.0.qu-9752pffj.woff2 +0 -0
- package/.next/standalone/.next/static/media/5ce348bf30bf5439-s.0ee55_hj9qcer.woff2 +0 -0
- package/.next/standalone/.next/static/media/6306c77e7c8268e4-s.0mao5jbfbduzp.woff2 +0 -0
- package/.next/standalone/.next/static/media/797e433ab948586e-s.p.09zddjkbdep5a.woff2 +0 -0
- package/.next/standalone/.next/static/media/7d817b4c03b0c5f1-s.0uzt.a6d44yda.woff2 +0 -0
- package/.next/standalone/.next/static/media/bbc41e54d2fcbd21-s.0mvwgmnhv29no.woff2 +0 -0
- package/.next/standalone/.next/static/{dAuQps6jUwCz9X1Q5FFOO → tGVQM5SE3NvbVu0gbAJm7}/_clientMiddlewareManifest.js +2 -2
- package/.next/standalone/app/policies/hooks-client.tsx +111 -14
- package/.next/standalone/components/navbar.tsx +1 -1
- package/.next/standalone/components/reach-developers.tsx +2 -2
- package/.next/standalone/lib/claude-sessions.ts +181 -0
- package/.next/standalone/node_modules/@next/env/package.json +1 -1
- package/.next/standalone/node_modules/next/dist/build/static-paths/app.js +2 -1
- package/.next/standalone/node_modules/next/dist/build/swc/index.js +1 -1
- package/.next/standalone/node_modules/next/dist/build/utils.js +2 -1
- package/.next/standalone/node_modules/next/dist/client/components/router-reducer/fetch-server-response.js +2 -2
- package/.next/standalone/node_modules/next/dist/client/components/router-reducer/set-cache-busting-search-param.js +8 -2
- package/.next/standalone/node_modules/next/dist/client/route-params.js +23 -6
- package/.next/standalone/node_modules/next/dist/compiled/next-server/app-page-turbo-experimental.runtime.prod.js +13 -13
- package/.next/standalone/node_modules/next/dist/compiled/next-server/app-page-turbo.runtime.prod.js +11 -11
- package/.next/standalone/node_modules/next/dist/compiled/next-server/app-route-turbo.runtime.prod.js +2 -2
- package/.next/standalone/node_modules/next/dist/compiled/next-server/pages-turbo.runtime.prod.js +10 -10
- package/.next/standalone/node_modules/next/dist/lib/patch-incorrect-lockfile.js +3 -3
- package/.next/standalone/node_modules/next/dist/server/app-render/action-handler.js +3 -6
- package/.next/standalone/node_modules/next/dist/server/app-render/app-render.js +62 -9
- package/.next/standalone/node_modules/next/dist/server/app-render/collect-segment-data.js +16 -0
- package/.next/standalone/node_modules/next/dist/server/app-render/create-component-tree.js +49 -19
- package/.next/standalone/node_modules/next/dist/server/app-render/get-script-nonce-from-header.js +8 -20
- package/.next/standalone/node_modules/next/dist/server/app-render/metadata-insertion/create-server-inserted-metadata.js +8 -7
- package/.next/standalone/node_modules/next/dist/server/app-render/use-flight-response.js +2 -2
- package/.next/standalone/node_modules/next/dist/server/async-storage/work-store.js +2 -1
- package/.next/standalone/node_modules/next/dist/server/base-server.js +13 -5
- package/.next/standalone/node_modules/next/dist/server/config.js +1 -1
- package/.next/standalone/node_modules/next/dist/server/dev/hot-reloader-turbopack.js +2 -2
- package/.next/standalone/node_modules/next/dist/server/dev/hot-reloader-webpack.js +1 -1
- package/.next/standalone/node_modules/next/dist/server/dev/static-paths-worker.js +2 -1
- package/.next/standalone/node_modules/next/dist/server/image-optimizer.js +22 -2
- package/.next/standalone/node_modules/next/dist/server/lib/app-info-log.js +1 -1
- package/.next/standalone/node_modules/next/dist/server/lib/is-rsc-request.js +18 -0
- package/.next/standalone/node_modules/next/dist/server/lib/mock-request.js +30 -5
- package/.next/standalone/node_modules/next/dist/server/lib/patch-set-header.js +7 -0
- package/.next/standalone/node_modules/next/dist/server/lib/router-server.js +6 -3
- package/.next/standalone/node_modules/next/dist/server/lib/router-utils/resolve-routes.js +18 -4
- package/.next/standalone/node_modules/next/dist/server/lib/server-ipc/utils.js +3 -1
- package/.next/standalone/node_modules/next/dist/server/lib/start-server.js +1 -1
- package/.next/standalone/node_modules/next/dist/server/next-server.js +1 -1
- package/.next/standalone/node_modules/next/dist/server/request/fallback-params.js +27 -1
- package/.next/standalone/node_modules/next/dist/server/route-modules/app-route/module.js +1 -0
- package/.next/standalone/node_modules/next/dist/server/route-modules/route-module.js +11 -1
- package/.next/standalone/node_modules/next/dist/server/server-utils.js +19 -2
- package/.next/standalone/node_modules/next/dist/server/stream-utils/node-web-streams-helper.js +5 -5
- package/.next/standalone/node_modules/next/dist/server/use-cache/use-cache-wrapper.js +1 -1
- package/.next/standalone/node_modules/next/dist/server/web/adapter.js +4 -1
- package/.next/standalone/node_modules/next/dist/server/web/edge-route-module-wrapper.js +2 -1
- package/.next/standalone/node_modules/next/dist/shared/lib/errors/canary-only-config-error.js +1 -1
- package/.next/standalone/node_modules/next/dist/{server → shared/lib}/htmlescape.js +15 -0
- package/.next/standalone/node_modules/next/dist/shared/lib/router/routes/app.js +13 -1
- package/.next/standalone/node_modules/next/dist/shared/lib/router/utils/cache-busting-search-param.js +56 -10
- package/.next/standalone/node_modules/next/dist/telemetry/anonymous-meta.js +1 -1
- package/.next/standalone/node_modules/next/dist/telemetry/events/swc-load-failure.js +1 -1
- package/.next/standalone/node_modules/next/dist/telemetry/events/version.js +2 -2
- package/.next/standalone/node_modules/next/package.json +15 -15
- package/.next/standalone/node_modules/react/cjs/react.development.js +1 -1
- package/.next/standalone/node_modules/react/cjs/react.production.js +1 -1
- package/.next/standalone/node_modules/react/package.json +1 -1
- package/.next/standalone/node_modules/react-dom/cjs/react-dom-server-legacy.browser.production.js +1 -1
- package/.next/standalone/node_modules/react-dom/cjs/react-dom-server-legacy.node.production.js +1 -1
- package/.next/standalone/node_modules/react-dom/cjs/react-dom-server.browser.production.js +3 -3
- package/.next/standalone/node_modules/react-dom/cjs/react-dom-server.edge.production.js +3 -3
- package/.next/standalone/node_modules/react-dom/cjs/react-dom-server.node.production.js +3 -3
- package/.next/standalone/node_modules/react-dom/cjs/react-dom.production.js +1 -1
- package/.next/standalone/node_modules/react-dom/package.json +2 -2
- package/.next/standalone/package.json +5 -5
- package/.next/standalone/proxy.ts +1 -1
- package/.next/standalone/server.js +1 -1
- package/README.md +4 -4
- package/bin/failproofai.mjs +230 -73
- package/dist/cli.mjs +3028 -1453
- package/lib/claude-sessions.ts +181 -0
- package/package.json +5 -5
- package/scripts/launch.ts +1 -1
- package/scripts/postinstall.mjs +89 -1
- package/src/audit/cache.ts +113 -0
- package/src/audit/cli-adapters/claude.ts +97 -0
- package/src/audit/cli-adapters/codex.ts +56 -0
- package/src/audit/cli-adapters/copilot.ts +51 -0
- package/src/audit/cli-adapters/cursor.ts +51 -0
- package/src/audit/cli-adapters/gemini.ts +51 -0
- package/src/audit/cli-adapters/index.ts +70 -0
- package/src/audit/cli-adapters/opencode.ts +52 -0
- package/src/audit/cli-adapters/pi.ts +51 -0
- package/src/audit/cli-adapters/shared.ts +85 -0
- package/src/audit/detectors/find-from-root.ts +27 -0
- package/src/audit/detectors/git-commit-no-verify.ts +22 -0
- package/src/audit/detectors/index.ts +33 -0
- package/src/audit/detectors/prefer-edit-over-read-cat.ts +31 -0
- package/src/audit/detectors/prefer-edit-over-sed-awk.ts +27 -0
- package/src/audit/detectors/prefer-write-over-heredoc.ts +36 -0
- package/src/audit/detectors/redundant-cd-cwd.ts +28 -0
- package/src/audit/detectors/reread-after-edit.ts +58 -0
- package/src/audit/detectors/sleep-polling-loop.ts +34 -0
- package/src/audit/index.ts +369 -0
- package/src/audit/replay.ts +121 -0
- package/src/audit/report.ts +349 -0
- package/src/audit/telemetry.ts +113 -0
- package/src/audit/types.ts +193 -0
- package/src/hooks/builtin-policies.ts +79 -1
- package/src/hooks/custom-hooks-loader.ts +19 -3
- package/src/hooks/first-run-nudge.ts +146 -0
- package/src/hooks/handler.ts +21 -102
- package/src/hooks/install-prompt.ts +34 -4
- package/src/hooks/manager.ts +72 -5
- package/src/hooks/policy-evaluator.ts +19 -4
- package/src/hooks/policy-registry.ts +1 -1
- package/src/hooks/policy-types.ts +9 -0
- package/src/hooks/tool-name-canonicalize.ts +65 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0609ezh._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__07_-mkc._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__09z7o2x._.js +0 -19
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0_sh2n0._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0e9o9ri._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0l6swv1._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0logebz._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0mi5ejy._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0odijkc._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0rkxer-._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0rl2kwi._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0vg0uey._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0x5limi._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__10._f0s._.js +0 -4
- package/.next/standalone/.next/static/chunks/01q52wg_amm60.js +0 -2
- package/.next/standalone/.next/static/chunks/0kqar56yl~41o.js +0 -6
- package/.next/standalone/.next/static/chunks/0ml1.ck_5t36i.js +0 -1
- package/.next/standalone/.next/static/chunks/0zig0fh30t6ou.js +0 -1
- package/.next/standalone/.next/static/chunks/17rm86uz2nd5a.css +0 -2
- package/.next/standalone/.next/static/media/4fa387ec64143e14-s.0q3udbd2bu5yp.woff2 +0 -0
- package/.next/standalone/.next/static/media/797e433ab948586e-s.p.0.q-h669a_dqa.woff2 +0 -0
- package/.next/standalone/.next/static/media/bbc41e54d2fcbd21-s.0gw~uztddq1df.woff2 +0 -0
- package/src/auth/login.ts +0 -104
- package/src/auth/logout.ts +0 -50
- package/src/auth/token-store.ts +0 -64
- package/src/relay/daemon.ts +0 -362
- package/src/relay/pid.ts +0 -76
- package/src/relay/queue.ts +0 -225
- /package/.next/standalone/.next/static/{dAuQps6jUwCz9X1Q5FFOO → tGVQM5SE3NvbVu0gbAJm7}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{dAuQps6jUwCz9X1Q5FFOO → tGVQM5SE3NvbVu0gbAJm7}/_ssgManifest.js +0 -0
|
@@ -1502,6 +1502,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
|
|
|
1502
1502
|
{
|
|
1503
1503
|
name: "sanitize-jwt",
|
|
1504
1504
|
description: "Stop Claude from reading JWTs in tool responses",
|
|
1505
|
+
displayTitle: "Redacted JWT tokens from tool output",
|
|
1506
|
+
impact: "Stops the agent from echoing auth tokens it saw in command output.",
|
|
1505
1507
|
fn: sanitizeJwt,
|
|
1506
1508
|
match: { events: ["PostToolUse"] },
|
|
1507
1509
|
defaultEnabled: true,
|
|
@@ -1510,6 +1512,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
|
|
|
1510
1512
|
{
|
|
1511
1513
|
name: "sanitize-api-keys",
|
|
1512
1514
|
description: "Stop Claude from reading API keys (OpenAI, Anthropic, GitHub, AWS, Stripe, Google) in tool responses",
|
|
1515
|
+
displayTitle: "Redacted API keys from tool output",
|
|
1516
|
+
impact: "Catches OpenAI / Anthropic / GitHub / AWS / Stripe / Google keys before the model sees them.",
|
|
1513
1517
|
fn: sanitizeApiKeys,
|
|
1514
1518
|
match: { events: ["PostToolUse"] },
|
|
1515
1519
|
defaultEnabled: true,
|
|
@@ -1525,6 +1529,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
|
|
|
1525
1529
|
{
|
|
1526
1530
|
name: "sanitize-connection-strings",
|
|
1527
1531
|
description: "Stop Claude from reading database connection strings with embedded credentials in tool responses",
|
|
1532
|
+
displayTitle: "Redacted database connection strings from tool output",
|
|
1533
|
+
impact: "Strips embedded DB credentials before they reach the model context.",
|
|
1528
1534
|
fn: sanitizeConnectionStrings,
|
|
1529
1535
|
match: { events: ["PostToolUse"] },
|
|
1530
1536
|
defaultEnabled: true,
|
|
@@ -1533,6 +1539,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
|
|
|
1533
1539
|
{
|
|
1534
1540
|
name: "sanitize-private-key-content",
|
|
1535
1541
|
description: "Stop Claude from reading PEM private key content in tool responses",
|
|
1542
|
+
displayTitle: "Redacted PEM private keys from tool output",
|
|
1543
|
+
impact: "Prevents private key bodies from being echoed into chat context.",
|
|
1536
1544
|
fn: sanitizePrivateKeyContent,
|
|
1537
1545
|
match: { events: ["PostToolUse"] },
|
|
1538
1546
|
defaultEnabled: true,
|
|
@@ -1540,6 +1548,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
|
|
|
1540
1548
|
},
|
|
1541
1549
|
{
|
|
1542
1550
|
name: "sanitize-bearer-tokens",
|
|
1551
|
+
displayTitle: "Redacted bearer tokens from tool output",
|
|
1552
|
+
impact: "Strips Authorization: Bearer values before they hit the model.",
|
|
1543
1553
|
description: "Stop Claude from reading Authorization Bearer tokens in tool responses",
|
|
1544
1554
|
fn: sanitizeBearerTokens,
|
|
1545
1555
|
match: { events: ["PostToolUse"] },
|
|
@@ -1548,6 +1558,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
|
|
|
1548
1558
|
},
|
|
1549
1559
|
{
|
|
1550
1560
|
name: "protect-env-vars",
|
|
1561
|
+
displayTitle: "Tried to dump environment variables to chat",
|
|
1562
|
+
impact: "Env vars often contain secrets; blocking `env` / `printenv` keeps them out of the model context.",
|
|
1551
1563
|
description: "Prevent commands that read environment variables",
|
|
1552
1564
|
fn: protectEnvVars,
|
|
1553
1565
|
match: { events: ["PreToolUse"], toolNames: ["Bash"] },
|
|
@@ -1556,6 +1568,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
|
|
|
1556
1568
|
},
|
|
1557
1569
|
{
|
|
1558
1570
|
name: "block-env-files",
|
|
1571
|
+
displayTitle: "Tried to read or write a .env file",
|
|
1572
|
+
impact: "`.env` files routinely contain API keys and DB credentials.",
|
|
1559
1573
|
description: "Block reading/writing .env files",
|
|
1560
1574
|
fn: blockEnvFiles,
|
|
1561
1575
|
match: { events: ["PreToolUse"] },
|
|
@@ -1564,6 +1578,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
|
|
|
1564
1578
|
},
|
|
1565
1579
|
{
|
|
1566
1580
|
name: "block-read-outside-cwd",
|
|
1581
|
+
displayTitle: "Tried to read files outside your project directory",
|
|
1582
|
+
impact: "Stops the agent from peeking at neighboring repos or your home directory.",
|
|
1567
1583
|
description: "Block file reads outside the session working directory",
|
|
1568
1584
|
fn: blockReadOutsideCwd,
|
|
1569
1585
|
match: { events: ["PreToolUse"], toolNames: ["Read", "Glob", "Grep", "Bash"] },
|
|
@@ -1579,6 +1595,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
|
|
|
1579
1595
|
},
|
|
1580
1596
|
{
|
|
1581
1597
|
name: "block-sudo",
|
|
1598
|
+
displayTitle: "Tried to run a command with sudo",
|
|
1599
|
+
impact: "Sudo gives the agent root — blocked unless explicitly allow-listed.",
|
|
1582
1600
|
description: "Block sudo commands",
|
|
1583
1601
|
fn: blockSudo,
|
|
1584
1602
|
// PermissionRequest is Codex's escalation-approval event; fire the same
|
|
@@ -1596,6 +1614,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
|
|
|
1596
1614
|
},
|
|
1597
1615
|
{
|
|
1598
1616
|
name: "block-curl-pipe-sh",
|
|
1617
|
+
displayTitle: "Tried to pipe a downloaded script straight to a shell",
|
|
1618
|
+
impact: "`curl ... | sh` runs unverified remote code on your machine.",
|
|
1599
1619
|
description: "Block piping downloads to shell",
|
|
1600
1620
|
fn: blockCurlPipeSh,
|
|
1601
1621
|
match: { events: ["PreToolUse"], toolNames: ["Bash"] },
|
|
@@ -1604,6 +1624,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
|
|
|
1604
1624
|
},
|
|
1605
1625
|
{
|
|
1606
1626
|
name: "block-rm-rf",
|
|
1627
|
+
displayTitle: "Tried to recursively delete a system path",
|
|
1628
|
+
impact: "Catches catastrophic `rm -rf /` and Windows equivalents.",
|
|
1607
1629
|
description: "Prevent catastrophic deletions",
|
|
1608
1630
|
fn: blockRmRf,
|
|
1609
1631
|
match: { events: ["PreToolUse"], toolNames: ["Bash"] },
|
|
@@ -1619,6 +1641,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
|
|
|
1619
1641
|
},
|
|
1620
1642
|
{
|
|
1621
1643
|
name: "block-failproofai-commands",
|
|
1644
|
+
displayTitle: "Tried to disable or modify failproofai itself",
|
|
1645
|
+
impact: "Prevents the agent from turning off the policies that protect you.",
|
|
1622
1646
|
description: "Block failproofai CLI commands and uninstallation",
|
|
1623
1647
|
fn: blockFailproofaiCommands,
|
|
1624
1648
|
match: { events: ["PreToolUse"], toolNames: ["Bash"] },
|
|
@@ -1627,6 +1651,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
|
|
|
1627
1651
|
},
|
|
1628
1652
|
{
|
|
1629
1653
|
name: "block-kubectl",
|
|
1654
|
+
displayTitle: "Tried to run a Kubernetes command",
|
|
1655
|
+
impact: "kubectl can change live cluster state — gated unless allow-listed.",
|
|
1630
1656
|
description: "Block kubectl commands (Kubernetes cluster mutations)",
|
|
1631
1657
|
fn: blockKubectl,
|
|
1632
1658
|
match: { events: ["PreToolUse"], toolNames: ["Bash"] },
|
|
@@ -1642,6 +1668,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
|
|
|
1642
1668
|
},
|
|
1643
1669
|
{
|
|
1644
1670
|
name: "block-terraform",
|
|
1671
|
+
displayTitle: "Tried to run a Terraform/OpenTofu command",
|
|
1672
|
+
impact: "Terraform mutates real infrastructure — gated unless allow-listed.",
|
|
1645
1673
|
description: "Block terraform and tofu (OpenTofu) commands",
|
|
1646
1674
|
fn: blockTerraform,
|
|
1647
1675
|
match: { events: ["PreToolUse"], toolNames: ["Bash"] },
|
|
@@ -1657,6 +1685,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
|
|
|
1657
1685
|
},
|
|
1658
1686
|
{
|
|
1659
1687
|
name: "block-aws-cli",
|
|
1688
|
+
displayTitle: "Tried to run an AWS CLI command",
|
|
1689
|
+
impact: "AWS CLI can spend money or break prod — gated.",
|
|
1660
1690
|
description: "Block aws CLI commands",
|
|
1661
1691
|
fn: blockAwsCli,
|
|
1662
1692
|
match: { events: ["PreToolUse"], toolNames: ["Bash"] },
|
|
@@ -1672,6 +1702,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
|
|
|
1672
1702
|
},
|
|
1673
1703
|
{
|
|
1674
1704
|
name: "block-gcloud",
|
|
1705
|
+
displayTitle: "Tried to run a Google Cloud command",
|
|
1706
|
+
impact: "gcloud can spend money or break prod — gated.",
|
|
1675
1707
|
description: "Block gcloud (Google Cloud) CLI commands",
|
|
1676
1708
|
fn: blockGcloud,
|
|
1677
1709
|
match: { events: ["PreToolUse"], toolNames: ["Bash"] },
|
|
@@ -1687,6 +1719,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
|
|
|
1687
1719
|
},
|
|
1688
1720
|
{
|
|
1689
1721
|
name: "block-az-cli",
|
|
1722
|
+
displayTitle: "Tried to run an Azure CLI command",
|
|
1723
|
+
impact: "az can spend money or break prod — gated.",
|
|
1690
1724
|
description: "Block az (Azure) CLI commands",
|
|
1691
1725
|
fn: blockAzCli,
|
|
1692
1726
|
match: { events: ["PreToolUse"], toolNames: ["Bash"] },
|
|
@@ -1702,6 +1736,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
|
|
|
1702
1736
|
},
|
|
1703
1737
|
{
|
|
1704
1738
|
name: "block-helm",
|
|
1739
|
+
displayTitle: "Tried to run a Helm command",
|
|
1740
|
+
impact: "Helm releases mutate cluster state — gated.",
|
|
1705
1741
|
description: "Block helm commands",
|
|
1706
1742
|
fn: blockHelm,
|
|
1707
1743
|
match: { events: ["PreToolUse"], toolNames: ["Bash"] },
|
|
@@ -1717,6 +1753,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
|
|
|
1717
1753
|
},
|
|
1718
1754
|
{
|
|
1719
1755
|
name: "block-gh-pipeline",
|
|
1756
|
+
displayTitle: "Tried to run a privileged GitHub CLI pipeline command",
|
|
1757
|
+
impact: "Catches `gh workflow run`, `gh pr merge`, `gh secret set`, etc.",
|
|
1720
1758
|
description: "Block gh CLI pipeline-trigger subcommands (workflow run, run rerun/cancel, pr merge, release create/delete, cache delete, secret set/delete)",
|
|
1721
1759
|
fn: blockGhPipeline,
|
|
1722
1760
|
match: { events: ["PreToolUse"], toolNames: ["Bash"] },
|
|
@@ -1732,6 +1770,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
|
|
|
1732
1770
|
},
|
|
1733
1771
|
{
|
|
1734
1772
|
name: "block-secrets-write",
|
|
1773
|
+
displayTitle: "Tried to write a secret-key file",
|
|
1774
|
+
impact: "Stops the agent from creating `.pem`, `id_rsa`, `credentials.json`, etc.",
|
|
1735
1775
|
description: "Block writing secret key files",
|
|
1736
1776
|
fn: blockSecretsWrite,
|
|
1737
1777
|
match: { events: ["PreToolUse"], toolNames: ["Write"] },
|
|
@@ -1747,6 +1787,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
|
|
|
1747
1787
|
},
|
|
1748
1788
|
{
|
|
1749
1789
|
name: "block-push-master",
|
|
1790
|
+
displayTitle: "Tried to push directly to main/master",
|
|
1791
|
+
impact: "Direct pushes to a protected branch bypass review.",
|
|
1750
1792
|
description: "Block pushing to main/master",
|
|
1751
1793
|
fn: blockPushMaster,
|
|
1752
1794
|
match: { events: ["PreToolUse"], toolNames: ["Bash"] },
|
|
@@ -1762,6 +1804,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
|
|
|
1762
1804
|
},
|
|
1763
1805
|
{
|
|
1764
1806
|
name: "block-force-push",
|
|
1807
|
+
displayTitle: "Tried to force-push",
|
|
1808
|
+
impact: "Force-pushes rewrite history and can clobber teammates' work.",
|
|
1765
1809
|
description: "Prevent force-pushing to any branch",
|
|
1766
1810
|
fn: blockForcePush,
|
|
1767
1811
|
match: { events: ["PreToolUse"], toolNames: ["Bash"] },
|
|
@@ -1770,6 +1814,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
|
|
|
1770
1814
|
},
|
|
1771
1815
|
{
|
|
1772
1816
|
name: "block-work-on-main",
|
|
1817
|
+
displayTitle: "Tried to commit or merge on main/master",
|
|
1818
|
+
impact: "Work should land via PR — direct commits skip review.",
|
|
1773
1819
|
description: "Block git commits and merges on main/master branch",
|
|
1774
1820
|
fn: blockWorkOnMain,
|
|
1775
1821
|
match: { events: ["PreToolUse"], toolNames: ["Bash"] },
|
|
@@ -1785,6 +1831,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
|
|
|
1785
1831
|
},
|
|
1786
1832
|
{
|
|
1787
1833
|
name: "warn-git-amend",
|
|
1834
|
+
displayTitle: "Used git commit --amend",
|
|
1835
|
+
impact: "Amending after a push rewrites history that others may have pulled.",
|
|
1788
1836
|
description: "Warns before amending git commits, which rewrites history",
|
|
1789
1837
|
fn: warnGitAmend,
|
|
1790
1838
|
match: { events: ["PreToolUse"], toolNames: ["Bash"] },
|
|
@@ -1793,6 +1841,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
|
|
|
1793
1841
|
},
|
|
1794
1842
|
{
|
|
1795
1843
|
name: "warn-git-stash-drop",
|
|
1844
|
+
displayTitle: "Tried to drop or clear git stash",
|
|
1845
|
+
impact: "Stash deletions are permanent and silent.",
|
|
1796
1846
|
description: "Warns before permanently deleting stashed changes",
|
|
1797
1847
|
fn: warnGitStashDrop,
|
|
1798
1848
|
match: { events: ["PreToolUse"], toolNames: ["Bash"] },
|
|
@@ -1801,6 +1851,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
|
|
|
1801
1851
|
},
|
|
1802
1852
|
{
|
|
1803
1853
|
name: "warn-all-files-staged",
|
|
1854
|
+
displayTitle: "Staged all files with git add -A / .",
|
|
1855
|
+
impact: "Wide stages routinely catch generated files or secrets you didn't intend to commit.",
|
|
1804
1856
|
description: "Warns before staging all working tree files with git add -A / . / --all",
|
|
1805
1857
|
fn: warnAllFilesStaged,
|
|
1806
1858
|
match: { events: ["PreToolUse"], toolNames: ["Bash"] },
|
|
@@ -1809,6 +1861,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
|
|
|
1809
1861
|
},
|
|
1810
1862
|
{
|
|
1811
1863
|
name: "warn-destructive-sql",
|
|
1864
|
+
displayTitle: "Ran destructive SQL (DROP / TRUNCATE / DELETE without WHERE)",
|
|
1865
|
+
impact: "Easy way to wipe a table by accident.",
|
|
1812
1866
|
description: "Warn before executing destructive SQL (DROP/TRUNCATE/DELETE without WHERE) via database clients",
|
|
1813
1867
|
fn: warnDestructiveSql,
|
|
1814
1868
|
match: { events: ["PreToolUse"], toolNames: ["Bash"] },
|
|
@@ -1817,6 +1871,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
|
|
|
1817
1871
|
},
|
|
1818
1872
|
{
|
|
1819
1873
|
name: "warn-schema-alteration",
|
|
1874
|
+
displayTitle: "Altered a database schema column",
|
|
1875
|
+
impact: "ALTER TABLE operations can lock tables and break readers.",
|
|
1820
1876
|
description: "Warns before SQL schema changes (ALTER TABLE with column or rename operations)",
|
|
1821
1877
|
fn: warnSchemaAlteration,
|
|
1822
1878
|
match: { events: ["PreToolUse"], toolNames: ["Bash"] },
|
|
@@ -1825,6 +1881,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
|
|
|
1825
1881
|
},
|
|
1826
1882
|
{
|
|
1827
1883
|
name: "warn-package-publish",
|
|
1884
|
+
displayTitle: "Tried to publish a package",
|
|
1885
|
+
impact: "Publishes are irreversible — `npm publish` / `cargo publish` shouldn't happen without intent.",
|
|
1828
1886
|
description: "Warn before publishing packages to public registries (npm, PyPI, crates.io, RubyGems, etc.)",
|
|
1829
1887
|
fn: warnPackagePublish,
|
|
1830
1888
|
match: { events: ["PreToolUse"], toolNames: ["Bash"] },
|
|
@@ -1833,6 +1891,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
|
|
|
1833
1891
|
},
|
|
1834
1892
|
{
|
|
1835
1893
|
name: "warn-global-package-install",
|
|
1894
|
+
displayTitle: "Installed a package globally",
|
|
1895
|
+
impact: "`npm i -g`, `cargo install`, `pip --user` pollute your machine outside the project.",
|
|
1836
1896
|
description: "Warns before installing packages globally (npm -g, cargo install, etc.)",
|
|
1837
1897
|
fn: warnGlobalPackageInstall,
|
|
1838
1898
|
match: { events: ["PreToolUse"], toolNames: ["Bash"] },
|
|
@@ -1841,6 +1901,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
|
|
|
1841
1901
|
},
|
|
1842
1902
|
{
|
|
1843
1903
|
name: "prefer-package-manager",
|
|
1904
|
+
displayTitle: "Used a non-preferred package manager",
|
|
1905
|
+
impact: "Mixing package managers creates lockfile churn for your team.",
|
|
1844
1906
|
description: "Blocks non-preferred package managers and tells Claude to use an allowed one (e.g., uv instead of pip)",
|
|
1845
1907
|
fn: preferPackageManager,
|
|
1846
1908
|
match: { events: ["PreToolUse"], toolNames: ["Bash"] },
|
|
@@ -1861,6 +1923,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
|
|
|
1861
1923
|
},
|
|
1862
1924
|
{
|
|
1863
1925
|
name: "warn-large-file-write",
|
|
1926
|
+
displayTitle: "Wrote a file larger than the configured threshold",
|
|
1927
|
+
impact: "Catches accidentally large file writes (logs, binaries, model dumps).",
|
|
1864
1928
|
description: "Warn before writing files larger than 1MB (configurable via thresholdKb param)",
|
|
1865
1929
|
fn: warnLargeFileWrite,
|
|
1866
1930
|
match: { events: ["PreToolUse"], toolNames: ["Write"] },
|
|
@@ -1876,6 +1940,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
|
|
|
1876
1940
|
},
|
|
1877
1941
|
{
|
|
1878
1942
|
name: "warn-background-process",
|
|
1943
|
+
displayTitle: "Started a long-lived background process",
|
|
1944
|
+
impact: "Catches `nohup` / `&` / `screen` / `tmux` / `disown` patterns that the agent often forgets to clean up.",
|
|
1879
1945
|
description: "Warns before starting detached or background processes",
|
|
1880
1946
|
fn: warnBackgroundProcess,
|
|
1881
1947
|
match: { events: ["PreToolUse"], toolNames: ["Bash"] },
|
|
@@ -1884,6 +1950,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
|
|
|
1884
1950
|
},
|
|
1885
1951
|
{
|
|
1886
1952
|
name: "warn-repeated-tool-calls",
|
|
1953
|
+
displayTitle: "Called the same tool 3+ times with identical arguments",
|
|
1954
|
+
impact: "Usually a sign of a stuck loop burning tokens.",
|
|
1887
1955
|
description: "Warn when the same tool is called 3+ times with identical parameters",
|
|
1888
1956
|
fn: warnRepeatedToolCalls,
|
|
1889
1957
|
match: { events: ["PreToolUse"] },
|
|
@@ -1892,6 +1960,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
|
|
|
1892
1960
|
},
|
|
1893
1961
|
{
|
|
1894
1962
|
name: "require-commit-before-stop",
|
|
1963
|
+
displayTitle: "Stopped with uncommitted changes",
|
|
1964
|
+
impact: "Work not in a commit is invisible to teammates and easy to lose.",
|
|
1895
1965
|
description: "Require all changes to be committed before Claude stops",
|
|
1896
1966
|
fn: requireCommitBeforeStop,
|
|
1897
1967
|
match: { events: ["Stop"] },
|
|
@@ -1900,6 +1970,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
|
|
|
1900
1970
|
},
|
|
1901
1971
|
{
|
|
1902
1972
|
name: "require-push-before-stop",
|
|
1973
|
+
displayTitle: "Stopped with unpushed commits",
|
|
1974
|
+
impact: "Local-only commits won't trigger CI or be reviewable.",
|
|
1903
1975
|
description: "Require all commits to be pushed to remote before Claude stops",
|
|
1904
1976
|
fn: requirePushBeforeStop,
|
|
1905
1977
|
match: { events: ["Stop"] },
|
|
@@ -1920,6 +1992,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
|
|
|
1920
1992
|
},
|
|
1921
1993
|
{
|
|
1922
1994
|
name: "require-pr-before-stop",
|
|
1995
|
+
displayTitle: "Stopped without a PR for the branch",
|
|
1996
|
+
impact: "Branches without PRs don't get reviewed.",
|
|
1923
1997
|
description: "Require a pull request to exist for the current branch before Claude stops",
|
|
1924
1998
|
fn: requirePrBeforeStop,
|
|
1925
1999
|
match: { events: ["Stop"] },
|
|
@@ -1935,6 +2009,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
|
|
|
1935
2009
|
},
|
|
1936
2010
|
{
|
|
1937
2011
|
name: "require-no-conflicts-before-stop",
|
|
2012
|
+
displayTitle: "Stopped with a branch that conflicts with main",
|
|
2013
|
+
impact: "Conflicting branches can't merge — surface them early.",
|
|
1938
2014
|
description: "Require the current branch to merge cleanly with the base branch before Claude stops",
|
|
1939
2015
|
fn: requireNoConflictsBeforeStop,
|
|
1940
2016
|
match: { events: ["Stop"] },
|
|
@@ -1950,6 +2026,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
|
|
|
1950
2026
|
},
|
|
1951
2027
|
{
|
|
1952
2028
|
name: "require-ci-green-before-stop",
|
|
2029
|
+
displayTitle: "Stopped with failing CI",
|
|
2030
|
+
impact: "Failing CI blocks deploy.",
|
|
1953
2031
|
description: "Require CI checks to pass on the current HEAD commit before Claude stops (ignores stale runs on prior commits)",
|
|
1954
2032
|
fn: requireCiGreenBeforeStop,
|
|
1955
2033
|
match: { events: ["Stop"] },
|
|
@@ -1959,7 +2037,7 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
|
|
|
1959
2037
|
];
|
|
1960
2038
|
|
|
1961
2039
|
export function registerBuiltinPolicies(enabledNames: string[]): void {
|
|
1962
|
-
// Tolerate both flat ("sanitize-jwt") and qualified ("
|
|
2040
|
+
// Tolerate both flat ("sanitize-jwt") and qualified ("failproofai/sanitize-jwt")
|
|
1963
2041
|
// forms in the user's enabledPolicies config — canonicalize both sides.
|
|
1964
2042
|
const enabledSet = new Set(enabledNames.map(normalizePolicyName));
|
|
1965
2043
|
for (const policy of BUILTIN_POLICIES) {
|
|
@@ -18,6 +18,8 @@ import { hookLogWarn, hookLogError, hookLogInfo } from "./hook-logger";
|
|
|
18
18
|
import { getCustomHooks, clearCustomHooks } from "./custom-hooks-registry";
|
|
19
19
|
import { findDistIndex, rewriteFileTree, TMP_SUFFIX, cleanupTmpFiles } from "./loader-utils";
|
|
20
20
|
import { findProjectConfigDir } from "./hooks-config";
|
|
21
|
+
import { trackHookEvent } from "./hook-telemetry";
|
|
22
|
+
import { getInstanceId } from "../../lib/telemetry-id";
|
|
21
23
|
import type { CustomHook } from "./policy-types";
|
|
22
24
|
|
|
23
25
|
const LOADING_KEY = "__FAILPROOFAI_LOADING_HOOKS__";
|
|
@@ -46,7 +48,10 @@ export function discoverPolicyFiles(dir: string): string[] {
|
|
|
46
48
|
* Load a single policy file into the globalThis custom hooks registry.
|
|
47
49
|
* Does NOT clear the registry — caller is responsible for that.
|
|
48
50
|
*/
|
|
49
|
-
async function loadSingleFile(
|
|
51
|
+
async function loadSingleFile(
|
|
52
|
+
absPath: string,
|
|
53
|
+
opts?: { strict?: boolean; conventionScope?: "project" | "user" },
|
|
54
|
+
): Promise<void> {
|
|
50
55
|
const g = globalThis as Record<string, unknown>;
|
|
51
56
|
g[LOADING_KEY] = true;
|
|
52
57
|
|
|
@@ -62,6 +67,17 @@ async function loadSingleFile(absPath: string, opts?: { strict?: boolean }): Pro
|
|
|
62
67
|
await import(/* webpackIgnore: true */ fileUrl);
|
|
63
68
|
} catch (err) {
|
|
64
69
|
const msg = err instanceof Error ? err.message : String(err);
|
|
70
|
+
const errorType = /Cannot find module|MODULE_NOT_FOUND|ENOENT/i.test(msg)
|
|
71
|
+
? "module_not_found"
|
|
72
|
+
: /SyntaxError|Unexpected token/i.test(msg)
|
|
73
|
+
? "syntax_error"
|
|
74
|
+
: "runtime_error";
|
|
75
|
+
void trackHookEvent(getInstanceId(), "custom_hooks_load_error", {
|
|
76
|
+
error_type: errorType,
|
|
77
|
+
is_convention: !!opts?.conventionScope,
|
|
78
|
+
convention_scope: opts?.conventionScope ?? null,
|
|
79
|
+
file_basename: basename(absPath),
|
|
80
|
+
});
|
|
65
81
|
if (opts?.strict) throw new Error(`Failed to load custom hooks from ${absPath}: ${msg}`);
|
|
66
82
|
hookLogError(`failed to load custom hooks from ${absPath}: ${msg}`);
|
|
67
83
|
} finally {
|
|
@@ -148,7 +164,7 @@ export async function loadAllCustomHooks(
|
|
|
148
164
|
const projectFiles = discoverPolicyFiles(projectDir);
|
|
149
165
|
for (const file of projectFiles) {
|
|
150
166
|
const hooksBefore = getCustomHooks().length;
|
|
151
|
-
await loadSingleFile(file);
|
|
167
|
+
await loadSingleFile(file, { conventionScope: "project" });
|
|
152
168
|
const newHooks = getCustomHooks().slice(hooksBefore);
|
|
153
169
|
if (newHooks.length > 0) {
|
|
154
170
|
conventionSources.push({
|
|
@@ -164,7 +180,7 @@ export async function loadAllCustomHooks(
|
|
|
164
180
|
const userFiles = discoverPolicyFiles(userDir);
|
|
165
181
|
for (const file of userFiles) {
|
|
166
182
|
const hooksBefore = getCustomHooks().length;
|
|
167
|
-
await loadSingleFile(file);
|
|
183
|
+
await loadSingleFile(file, { conventionScope: "user" });
|
|
168
184
|
const newHooks = getCustomHooks().slice(hooksBefore);
|
|
169
185
|
if (newHooks.length > 0) {
|
|
170
186
|
conventionSources.push({
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* First-run nudge for `failproofai` (no-args invocation).
|
|
3
|
+
*
|
|
4
|
+
* Fires when a user runs the bare CLI without having installed any policies on
|
|
5
|
+
* any detected agent CLI. PostHog data showed only ~10% of npm-installed users
|
|
6
|
+
* ran `failproofai policies --install`; this prompt closes the awareness gap
|
|
7
|
+
* by offering to run that install inline.
|
|
8
|
+
*
|
|
9
|
+
* The hooks themselves are the sentinel — if any are installed for any
|
|
10
|
+
* detected CLI, we never prompt again. No separate state file needed.
|
|
11
|
+
*
|
|
12
|
+
* Honors `FAILPROOFAI_NO_FIRST_RUN=1` for opt-out, falls back to a short
|
|
13
|
+
* stderr hint in non-TTY contexts (CI, piped invocations).
|
|
14
|
+
*/
|
|
15
|
+
import * as readline from "node:readline";
|
|
16
|
+
|
|
17
|
+
import { detectInstalledClis, getIntegration } from "./integrations";
|
|
18
|
+
import { installHooks } from "./manager";
|
|
19
|
+
import { trackHookEvent } from "./hook-telemetry";
|
|
20
|
+
import { getInstanceId } from "../../lib/telemetry-id";
|
|
21
|
+
import type { IntegrationType } from "./types";
|
|
22
|
+
|
|
23
|
+
type TTYIn = NodeJS.ReadableStream & { isTTY?: boolean };
|
|
24
|
+
type TTYOut = NodeJS.WritableStream & { isTTY?: boolean };
|
|
25
|
+
|
|
26
|
+
export interface FirstRunNudgeOptions {
|
|
27
|
+
stdin?: TTYIn;
|
|
28
|
+
stdout?: TTYOut;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async function emit(event: string, props: Record<string, unknown>): Promise<void> {
|
|
32
|
+
try {
|
|
33
|
+
await trackHookEvent(getInstanceId(), event, props);
|
|
34
|
+
} catch {
|
|
35
|
+
// Telemetry must never break first-run UX.
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function anyHooksInstalled(detected: IntegrationType[]): boolean {
|
|
40
|
+
for (const id of detected) {
|
|
41
|
+
const integration = getIntegration(id);
|
|
42
|
+
for (const scope of integration.scopes) {
|
|
43
|
+
try {
|
|
44
|
+
if (integration.hooksInstalledInSettings(scope)) return true;
|
|
45
|
+
} catch {
|
|
46
|
+
// A broken settings file shouldn't suppress the nudge.
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function clisLabel(detected: IntegrationType[]): string {
|
|
54
|
+
return detected.map((id) => getIntegration(id).displayName).join(", ");
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async function promptYesNo(
|
|
58
|
+
stdin: TTYIn,
|
|
59
|
+
stdout: TTYOut,
|
|
60
|
+
): Promise<"yes" | "no" | "sigint"> {
|
|
61
|
+
return new Promise((resolve) => {
|
|
62
|
+
const rl = readline.createInterface({ input: stdin, output: stdout });
|
|
63
|
+
let settled = false;
|
|
64
|
+
const finish = (answer: "yes" | "no" | "sigint") => {
|
|
65
|
+
if (settled) return;
|
|
66
|
+
settled = true;
|
|
67
|
+
rl.close();
|
|
68
|
+
resolve(answer);
|
|
69
|
+
};
|
|
70
|
+
rl.on("SIGINT", () => finish("sigint"));
|
|
71
|
+
rl.question("Install policies now? [Y/n] ", (raw) => {
|
|
72
|
+
const a = (raw ?? "").trim().toLowerCase();
|
|
73
|
+
if (a === "" || a === "y" || a === "yes") finish("yes");
|
|
74
|
+
else finish("no");
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export async function maybeRunFirstRunNudge(opts: FirstRunNudgeOptions = {}): Promise<void> {
|
|
80
|
+
if (process.env.FAILPROOFAI_NO_FIRST_RUN === "1") return;
|
|
81
|
+
|
|
82
|
+
const stdin: TTYIn = opts.stdin ?? process.stdin;
|
|
83
|
+
const stdout: TTYOut = opts.stdout ?? process.stdout;
|
|
84
|
+
|
|
85
|
+
let detected: IntegrationType[];
|
|
86
|
+
try {
|
|
87
|
+
detected = detectInstalledClis();
|
|
88
|
+
} catch {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
if (detected.length === 0) return;
|
|
92
|
+
|
|
93
|
+
if (anyHooksInstalled(detected)) return;
|
|
94
|
+
|
|
95
|
+
const detectedProps = { detected_clis: detected, detected_count: detected.length };
|
|
96
|
+
|
|
97
|
+
if (!stdin.isTTY || !stdout.isTTY) {
|
|
98
|
+
stdout.write(
|
|
99
|
+
`\n[failproofai] No policies are installed. Run \`failproofai policies --install\` to set them up.\n` +
|
|
100
|
+
`[failproofai] Launching dashboard…\n\n`,
|
|
101
|
+
);
|
|
102
|
+
await emit("first_run_nudge_skipped_noninteractive", detectedProps);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
stdout.write(
|
|
107
|
+
`\n┌─ Failproof AI — first-run setup ────────────────────────────────────\n` +
|
|
108
|
+
`│ Detected agent CLI(s): ${clisLabel(detected)}\n` +
|
|
109
|
+
`│ Policies block unsafe actions (sudo, rm -rf /, secret leaks, …)\n` +
|
|
110
|
+
`│ before your agent runs them. Nothing is installed yet.\n` +
|
|
111
|
+
`└──────────────────────────────────────────────────────────────────────\n\n` +
|
|
112
|
+
` Disable this prompt anytime: FAILPROOFAI_NO_FIRST_RUN=1\n\n`,
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
await emit("first_run_nudge_shown", detectedProps);
|
|
116
|
+
|
|
117
|
+
const answer = await promptYesNo(stdin, stdout);
|
|
118
|
+
|
|
119
|
+
if (answer === "sigint") {
|
|
120
|
+
await emit("first_run_nudge_declined", { ...detectedProps, reason: "sigint" });
|
|
121
|
+
process.exit(130);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (answer === "no") {
|
|
125
|
+
await emit("first_run_nudge_declined", { ...detectedProps, reason: "user_no" });
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
await emit("first_run_nudge_accepted", {
|
|
130
|
+
...detectedProps,
|
|
131
|
+
target_scope: "user",
|
|
132
|
+
source: "first-run-nudge",
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
await installHooks(
|
|
136
|
+
undefined,
|
|
137
|
+
"user",
|
|
138
|
+
undefined,
|
|
139
|
+
false,
|
|
140
|
+
"first-run-nudge",
|
|
141
|
+
undefined,
|
|
142
|
+
false,
|
|
143
|
+
detected,
|
|
144
|
+
);
|
|
145
|
+
process.exit(0);
|
|
146
|
+
}
|