failproofai 1.0.4-beta.1 → 1.0.4-beta.4
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 +5 -5
- package/.next/standalone/.next/prerender-manifest.json +5 -5
- 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 +6 -6
- package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
- package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found/page/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/_not-found/__PAGE__.segment.rsc +14 -14
- package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/api/audit/invite/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/audit/invite/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/audit/run/route.js +4 -4
- package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/audit/run/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/audit/status/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/audit/status/route_client-reference-manifest.js +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-request/route_client-reference-manifest.js +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/login-verify/route_client-reference-manifest.js +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/logout/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/status/route_client-reference-manifest.js +1 -1
- 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/api/download/[project]/[session]/route_client-reference-manifest.js +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 +37 -4
- package/.next/standalone/.next/server/app/audit/page.js +2 -2
- package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/index.html +1 -1
- package/.next/standalone/.next/server/app/index.rsc +15 -15
- package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +14 -14
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +15 -15
- package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/page/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 +14 -14
- 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 -3
- 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 +2 -2
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/projects/page/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/app/settings/page/build-manifest.json +2 -2
- package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +4 -4
- package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/chunks/{[externals]__1zndo1i._.js → [externals]__0v1hz15._.js} +1 -1
- package/.next/standalone/.next/server/chunks/{[externals]__0_gzk8q._.js → [externals]__1nb206a._.js} +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0--lkk6._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__08dchfu._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0cuho4x._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0o07qi9._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0q0qzx1._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1adacul._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1le9jqc._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1p-qi2t._.js +5 -0
- package/.next/standalone/.next/server/chunks/_09dz7xv._.js +1 -1
- package/.next/standalone/.next/server/chunks/_0otft92._.js +3 -0
- package/.next/standalone/.next/server/chunks/_0tovk6q._.js +1 -1
- package/.next/standalone/.next/server/chunks/_0trp3yc._.js +1 -1
- package/.next/standalone/.next/server/chunks/_1ek68ln._.js +14 -21
- package/.next/standalone/.next/server/chunks/_1vslkoe._.js +1 -1
- package/.next/standalone/.next/server/chunks/lib_factory-projects_ts_1eo_bk-._.js +1 -1
- package/.next/standalone/.next/server/chunks/lib_telemetry_ts_0dctyyw._.js +1 -1
- package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_01r25oi._.js +2 -2
- package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_09z9-p7._.js +2 -2
- package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
- package/.next/standalone/.next/server/chunks/src_hooks_0iu54mz._.js +1 -1
- package/.next/standalone/.next/server/chunks/src_hooks_fp-home_ts_09kv0bn._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__00-s7h8._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__013jr2b._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__01wy8d-._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__02npjtd._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0da85px._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ftmoxc._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0wvusu0._.js → [root-of-the-server]__0n_lxhg._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0oa1lav._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0p-5p8u._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0s740oi._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__16gamwq._.js → [root-of-the-server]__0yl9wb5._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__190won8._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1ctpynv._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1p2otjt._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1qapotl._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1sc84bb._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1zl_r0t._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_0-yi74u._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_08x1r5t._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{_1byck5v._.js → _0guxnh-._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/_0l2hi_d._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_0oq1dh6._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_0wso5d3._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_1_ozgif._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_1es2j7i._.js +61 -168
- package/.next/standalone/.next/server/chunks/ssr/{_08f0jd2._.js → _1if9ixi._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_1u8-lu2._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_next-internal_server_app_policies_page_actions_1sp2-yo.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +1 -69
- package/.next/standalone/.next/server/chunks/ssr/app_audit__components_rerun-button_tsx_0blihgw._.js +3 -0
- 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/app_settings_settings-client_tsx_20lq-mq._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/node_modules_13n822a._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/node_modules_posthog-node_dist_entrypoints_index_node_mjs_11bnuzn._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_builtin-policies_ts_09j2ndl._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_fp-config_ts_04t589g._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_fp-home_ts_0je3xkv._.js +1 -1
- package/.next/standalone/.next/server/middleware-build-manifest.js +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 +54 -21
- package/.next/standalone/.next/static/chunks/04o5zfl7p5lhx.js +1 -0
- package/.next/standalone/.next/static/chunks/{29-iqnp9v_axt.css → 0jpd8dv2vk930.css} +1 -1
- package/.next/standalone/.next/static/chunks/{1po3lirgk2riw.js → 0po8n4tyotjf2.js} +1 -1
- package/.next/standalone/.next/static/chunks/0qmsunv04x4na.css +2 -0
- package/.next/standalone/.next/static/chunks/0qx7gav1c2_vu.js +1 -0
- package/.next/standalone/.next/static/chunks/17tfki9x5rd_7.js +1 -0
- package/.next/standalone/.next/static/chunks/{1_bxotmf9qngs.js → 1i-i0pxg9q_8y.js} +1 -1
- package/.next/standalone/.next/static/chunks/{1_2jsatfuthrw.js → 2bxr2_2h4kaqq.js} +1 -1
- package/.next/standalone/.next/static/chunks/{01hvwwrhvbzyh.js → 2zafgs90r_leq.js} +1 -1
- package/.next/standalone/.next/static/chunks/{00gv0v91mycm-.js → 323cyb3a2s06y.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0qn9khv0oo9ex.js → 364cqbpeg1y5i.js} +1 -1
- package/.next/standalone/.next/static/chunks/{2bvwsyu6x__ia.js → 38dqur43qthrl.js} +1 -1
- package/.next/standalone/.next/static/chunks/{3_--3ibia6ba1.js → 3l36d73kj18zw.js} +1 -1
- package/.next/standalone/.next/static/chunks/{2k9f4tyv04809.css → 3uyhmm01g64k4.css} +1 -0
- package/.next/standalone/.next/static/chunks/{2bnf_4pgyk1rq.js → 40lpt2o2b283e.js} +1 -1
- package/.next/standalone/.next/static/chunks/42gwu2bsz4ske.js +6 -0
- package/.next/standalone/.next/static/chunks/{turbopack-18qf4jodtft6b.js → turbopack-3s3c-u_u_l0u9.js} +1 -1
- package/.next/standalone/.opencode/plugins/failproofai.mjs +51 -27
- package/.next/standalone/app/actions/get-leaks.ts +109 -0
- package/.next/standalone/app/audit/_components/audit-dashboard.tsx +140 -34
- package/.next/standalone/app/audit/_components/audit-poster.tsx +29 -10
- package/.next/standalone/app/audit/_components/come-back-better-section.tsx +6 -1
- package/.next/standalone/app/audit/_components/empty-state.tsx +4 -1
- package/.next/standalone/app/audit/_components/how-to-improve-section.tsx +19 -5
- package/.next/standalone/app/audit/_components/leak-section.tsx +192 -0
- package/.next/standalone/app/audit/_components/share-templates.ts +110 -44
- package/.next/standalone/app/audit/audit-styles.css +132 -1
- package/.next/standalone/app/project/[name]/page.tsx +4 -24
- package/.next/standalone/fp-cloud-cli/CHANGELOG.md +26 -3
- package/.next/standalone/fp-cloud-cli/fp_cli/_click_compat.py +31 -8
- package/.next/standalone/fp-cloud-cli/fp_cli/permissions.py +1 -0
- package/.next/standalone/fp-cloud-cli/pyproject.toml +9 -2
- package/.next/standalone/fp-cloud-cli/tests/test_click_compat.py +54 -0
- package/.next/standalone/fp-cloud-cli/uv.lock +9 -12
- package/.next/standalone/lib/auth/api-server-client.ts +28 -0
- package/.next/standalone/lib/claude-sessions.ts +101 -27
- package/.next/standalone/lib/cli-registry.ts +1 -33
- package/.next/standalone/lib/download-session.ts +0 -37
- package/.next/standalone/lib/projects.ts +3 -27
- package/.next/standalone/lib/sqlite-reader.ts +78 -1
- package/.next/standalone/node_modules/@next/env/package.json +1 -1
- package/.next/standalone/node_modules/next/dist/build/swc/index.js +1 -1
- package/.next/standalone/node_modules/next/dist/compiled/next-server/pages-turbo.runtime.prod.js +1 -1
- package/.next/standalone/node_modules/next/dist/experimental/testmode/fetch.js +10 -2
- package/.next/standalone/node_modules/next/dist/lib/patch-incorrect-lockfile.js +3 -3
- package/.next/standalone/node_modules/next/dist/lib/typescript/runTypeScriptCli.js +2 -2
- package/.next/standalone/node_modules/next/dist/lib/verify-typescript-setup.js +3 -1
- 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/image-optimizer.js +2 -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/start-server.js +1 -1
- 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 +11 -11
- package/.next/standalone/package.json +15 -14
- package/.next/standalone/sdk/python/CHANGELOG.md +155 -0
- package/.next/standalone/sdk/python/README.md +8 -0
- package/.next/standalone/sdk/python/examples/evaluator_worker.py +121 -0
- package/.next/standalone/sdk/python/failproofai_sdk/_version.py +1 -1
- package/.next/standalone/sdk/python/failproofai_sdk/evaluator/__init__.py +101 -0
- package/.next/standalone/sdk/python/failproofai_sdk/evaluator/__main__.py +49 -0
- package/.next/standalone/sdk/python/failproofai_sdk/evaluator/_sandbox_runner.py +63 -0
- package/.next/standalone/sdk/python/failproofai_sdk/evaluator/authoring.py +404 -0
- package/.next/standalone/sdk/python/failproofai_sdk/evaluator/client.py +299 -0
- package/.next/standalone/sdk/python/failproofai_sdk/evaluator/protocol.py +754 -0
- package/.next/standalone/sdk/python/failproofai_sdk/evaluator/runtime.py +936 -0
- package/.next/standalone/sdk/python/failproofai_sdk/evaluator/source.py +684 -0
- package/.next/standalone/sdk/python/tests/fixtures/evaluator_v2/README.md +28 -0
- package/.next/standalone/sdk/python/tests/fixtures/evaluator_v2/contract.json +252 -0
- package/.next/standalone/sdk/python/tests/test_evaluator_authoring.py +124 -0
- package/.next/standalone/sdk/python/tests/test_evaluator_client.py +253 -0
- package/.next/standalone/sdk/python/tests/test_evaluator_example.py +35 -0
- package/.next/standalone/sdk/python/tests/test_evaluator_http_e2e.py +636 -0
- package/.next/standalone/sdk/python/tests/test_evaluator_main.py +47 -0
- package/.next/standalone/sdk/python/tests/test_evaluator_protocol.py +246 -0
- package/.next/standalone/sdk/python/tests/test_evaluator_review_fixes.py +164 -0
- package/.next/standalone/sdk/python/tests/test_evaluator_runtime.py +1103 -0
- package/.next/standalone/sdk/python/tests/test_evaluator_source.py +430 -0
- package/.next/standalone/sdk/python/tests/test_zero_dependencies.py +17 -0
- package/.next/standalone/sdk/python/uv.lock +18 -18
- package/.next/standalone/server.js +1 -1
- package/README.md +19 -95
- package/bin/failproofai.mjs +8 -25
- package/dist/cli.mjs +20091 -25864
- package/dist/worker.mjs +4881 -6361
- package/lib/auth/api-server-client.ts +28 -0
- package/lib/claude-sessions.ts +101 -27
- package/lib/cli-registry.ts +1 -33
- package/lib/download-session.ts +0 -37
- package/lib/projects.ts +3 -27
- package/lib/sqlite-reader.ts +78 -1
- package/package.json +15 -14
- package/pi-extension/index.ts +61 -8
- package/scripts/changelog-open.py +115 -0
- package/src/audit/cache.ts +6 -0
- package/src/audit/cli-adapters/claude.ts +13 -0
- package/src/audit/cli-adapters/index.ts +0 -24
- package/src/audit/cli-login.ts +4 -1
- package/src/audit/cli.ts +164 -5
- package/src/audit/desktop-notify.ts +420 -0
- package/src/audit/harm-report.ts +101 -0
- package/src/audit/index.ts +284 -15
- package/src/audit/leak-fingerprint.ts +200 -0
- package/src/audit/leak-notice.ts +259 -0
- package/src/audit/leak-record.ts +232 -0
- package/src/audit/leak-scan.ts +268 -0
- package/src/audit/leak-store.ts +265 -0
- package/src/audit/macos-notifier.ts +310 -0
- package/src/audit/redact-example.ts +322 -15
- package/src/audit/report-harm.ts +12 -1
- package/src/audit/report.ts +6 -3
- package/src/audit/schedule-cli.ts +37 -0
- package/src/audit/scoring.ts +49 -0
- package/src/audit/types.ts +47 -0
- package/src/hooks/builtin-policies.ts +71 -8
- package/src/hooks/configure-wizard.ts +20 -0
- package/src/hooks/enforcement-capability.ts +0 -97
- package/src/hooks/fp-config.ts +71 -11
- package/src/hooks/fp-home.ts +27 -0
- package/src/hooks/handler.ts +84 -62
- package/src/hooks/harness-cli.ts +1 -3
- package/src/hooks/integrations.ts +63 -769
- package/src/hooks/normalize-cli-payload.ts +0 -126
- package/src/hooks/notice.ts +191 -0
- package/src/hooks/policy-evaluator.ts +6 -297
- package/src/hooks/resolve-transcript-path.ts +0 -10
- package/src/hooks/tool-name-canonicalize.ts +0 -64
- package/src/hooks/types.ts +2 -533
- package/src/hooks/uninstall-cli.ts +15 -0
- package/.next/standalone/.grok/hooks/failproofai.json +0 -172
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__07hor7h._.js +0 -5
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0elsuli._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0gnj_qa._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ljuzm_._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0w23bpg._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0x5c7sh._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0yik9_w._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1jg6s9m._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1s6qci9._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1xfm05z._.js +0 -3
- package/.next/standalone/.next/server/chunks/_0tdy_6l._.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_grok-projects_ts_1i2epl_._.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_qwen-projects_ts_0wu_a8e._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0_4gcz8._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0d--wmy._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0qqrlf_._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0s11fx1._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1bbk-si._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1c3ybxr._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1izi7zn._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__21bj7uw._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_00z5uuq._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_1ylae7o._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_1zopuov._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/lib_cline-projects_ts_13_hbdd._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/lib_grok-projects_ts_0rc-d0o._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/lib_ori-projects_ts_04tofqo._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/lib_qwen-projects_ts_0w3i9o7._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/node_modules_html-to-image_es_index_1ao30b1.js +0 -3
- package/.next/standalone/.next/static/chunks/0hzmxwb2pvk5p.js +0 -6
- package/.next/standalone/.next/static/chunks/0j884dwnwtyrt.js +0 -1
- package/.next/standalone/.next/static/chunks/0mr9dg3bnloa1.js +0 -1
- package/.next/standalone/.next/static/chunks/0u64yey446k4f.css +0 -1
- package/.next/standalone/.next/static/chunks/3gf1jg-5m-u1t.css +0 -2
- package/.next/standalone/.next/static/chunks/3qfoeqhy5l10x.js +0 -1
- package/.next/standalone/.next/static/chunks/3ws7eljkq25wg.js +0 -69
- package/.next/standalone/.next/static/chunks/3zkg2s2vzxc3d.js +0 -1
- package/.next/standalone/.qwen/settings.json +0 -251
- package/.next/standalone/assets/logos/cline.png +0 -0
- package/.next/standalone/assets/logos/grok-dark.svg +0 -1
- package/.next/standalone/assets/logos/grok-light.svg +0 -1
- package/.next/standalone/assets/logos/ori-dark.svg +0 -1
- package/.next/standalone/assets/logos/ori-light.svg +0 -1
- package/.next/standalone/assets/logos/qwen.svg +0 -1
- package/.next/standalone/lib/cline-projects.ts +0 -155
- package/.next/standalone/lib/cline-sessions.ts +0 -268
- package/.next/standalone/lib/grok-projects.ts +0 -123
- package/.next/standalone/lib/grok-sessions.ts +0 -355
- package/.next/standalone/lib/ori-projects.ts +0 -141
- package/.next/standalone/lib/ori-sessions.ts +0 -221
- package/.next/standalone/lib/qwen-projects.ts +0 -106
- package/.next/standalone/lib/qwen-sessions.ts +0 -313
- package/lib/cline-projects.ts +0 -155
- package/lib/cline-sessions.ts +0 -268
- package/lib/grok-projects.ts +0 -123
- package/lib/grok-sessions.ts +0 -355
- package/lib/ori-projects.ts +0 -141
- package/lib/ori-sessions.ts +0 -221
- package/lib/qwen-projects.ts +0 -106
- package/lib/qwen-sessions.ts +0 -313
- package/src/audit/cli-adapters/cline.ts +0 -50
- package/src/audit/cli-adapters/grok.ts +0 -70
- package/src/audit/cli-adapters/ori.ts +0 -55
- package/src/audit/cli-adapters/qwen.ts +0 -71
- package/src/hooks/batch-expand.ts +0 -380
- package/src/hooks/batch-fanout.ts +0 -142
- package/src/hooks/risk-patterns.ts +0 -26
- /package/.next/standalone/.next/static/{qJx3mbOQV-5ElrcRb4Sp7 → P6icI2V2PvVuePJrqjHCr}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{qJx3mbOQV-5ElrcRb4Sp7 → P6icI2V2PvVuePJrqjHCr}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{qJx3mbOQV-5ElrcRb4Sp7 → P6icI2V2PvVuePJrqjHCr}/_ssgManifest.js +0 -0
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
// • src/hooks/integrations.ts (buildOpenCodePluginShim production template)
|
|
19
19
|
// When #337 landed, this dev shim drifted and `block-read-outside-cwd`
|
|
20
20
|
// silently no-op'd on every opencode `read` call inside this repo.
|
|
21
|
-
import {
|
|
21
|
+
import { spawn } from "node:child_process";
|
|
22
22
|
import { resolveDevSpawn } from "../../scripts/dev-hook.mjs";
|
|
23
23
|
|
|
24
24
|
const BUS_EVENT_MAP = {
|
|
@@ -70,34 +70,58 @@ function canonicalizeToolInput(canonicalToolName, args) {
|
|
|
70
70
|
return out;
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
73
|
+
/**
|
|
74
|
+
* Run failproofai for one event WITHOUT blocking opencode's event loop.
|
|
75
|
+
*
|
|
76
|
+
* This was `spawnSync`, and opencode loads the plugin in-process in the TUI —
|
|
77
|
+
* so every hook froze rendering and input for the subprocess's full duration,
|
|
78
|
+
* with a 60s ceiling. The verdicts are unchanged: every caller already `await`s
|
|
79
|
+
* `applyDecision`, so the deny still lands before the tool runs. What changes
|
|
80
|
+
* is that the wait is now a promise rather than a blocked thread, and the TUI
|
|
81
|
+
* keeps painting while it happens.
|
|
82
|
+
*
|
|
83
|
+
* Fail-open on spawn error, and on the timeout — a policy that never ran must
|
|
84
|
+
* not read as a deny.
|
|
85
|
+
*/
|
|
86
|
+
async function runFailproofai(eventName, payload, directory) {
|
|
87
|
+
const resolved = resolveDevSpawn();
|
|
88
|
+
if (!resolved) {
|
|
79
89
|
process.stderr.write(
|
|
80
90
|
"[failproofai-dev] bun not found — opencode policies are NOT enforcing. " +
|
|
81
91
|
"Install bun: curl -fsSL https://bun.sh/install | bash\n",
|
|
82
92
|
);
|
|
83
93
|
return { exitCode: 0, stdout: "", stderr: "" };
|
|
84
94
|
}
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
95
|
+
const cmd = resolved.cmd;
|
|
96
|
+
const args = [...resolved.args, "--hook", eventName, "--cli", "opencode"];
|
|
97
|
+
return await new Promise((resolveRun) => {
|
|
98
|
+
let child;
|
|
99
|
+
try {
|
|
100
|
+
child = spawn(cmd, args, { cwd: directory });
|
|
101
|
+
} catch {
|
|
102
|
+
resolveRun({ exitCode: 0, stdout: "", stderr: "" });
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
let stdout = "";
|
|
106
|
+
let stderr = "";
|
|
107
|
+
let settled = false;
|
|
108
|
+
const finish = (exitCode) => {
|
|
109
|
+
if (settled) return;
|
|
110
|
+
settled = true;
|
|
111
|
+
clearTimeout(timer);
|
|
112
|
+
resolveRun({ exitCode, stdout, stderr });
|
|
113
|
+
};
|
|
114
|
+
const timer = setTimeout(() => {
|
|
115
|
+
try { child.kill("SIGKILL"); } catch { /* already gone */ }
|
|
116
|
+
finish(0);
|
|
117
|
+
}, 60_000);
|
|
118
|
+
child.stdout.on("data", (d) => { stdout += d; });
|
|
119
|
+
child.stderr.on("data", (d) => { stderr += d; });
|
|
120
|
+
child.on("error", () => finish(0));
|
|
121
|
+
child.on("close", (code) => finish(code ?? 0));
|
|
122
|
+
child.stdin.on("error", () => {});
|
|
123
|
+
child.stdin.end(JSON.stringify(payload));
|
|
90
124
|
});
|
|
91
|
-
// `r.status` is null when the spawn never ran (ENOENT) or the child was
|
|
92
|
-
// killed. Coercing that to 0 reports "allowed" for a policy that never got
|
|
93
|
-
// to run, so say so on stderr rather than failing open in silence.
|
|
94
|
-
if (r.status === null) {
|
|
95
|
-
process.stderr.write(
|
|
96
|
-
`[failproofai-dev] ${eventName} hook did not run (${r.error?.code ?? r.signal ?? "unknown"}) — not enforcing\n`,
|
|
97
|
-
);
|
|
98
|
-
return { exitCode: 0, stdout: "", stderr: "" };
|
|
99
|
-
}
|
|
100
|
-
return { exitCode: r.status, stdout: r.stdout ?? "", stderr: r.stderr ?? "" };
|
|
101
125
|
}
|
|
102
126
|
|
|
103
127
|
async function applyDecision(result, ctx, eventName) {
|
|
@@ -150,7 +174,7 @@ export default async function failproofaiPlugin({ client, directory }) {
|
|
|
150
174
|
}
|
|
151
175
|
}
|
|
152
176
|
if (!prompt) prompt = (info.text || info.content || props.text || "").toString();
|
|
153
|
-
const r = runFailproofai("UserPromptSubmit", {
|
|
177
|
+
const r = await runFailproofai("UserPromptSubmit", {
|
|
154
178
|
session_id: sessionID, cwd: directory, hook_event_name: "UserPromptSubmit", prompt,
|
|
155
179
|
}, directory);
|
|
156
180
|
await applyDecision(r, { client, sessionID }, "UserPromptSubmit");
|
|
@@ -160,7 +184,7 @@ export default async function failproofaiPlugin({ client, directory }) {
|
|
|
160
184
|
if (!claudeEvent) return;
|
|
161
185
|
const props = event.properties || {};
|
|
162
186
|
const sessionID = props.sessionID || (props.session && props.session.id) || props.id;
|
|
163
|
-
const r = runFailproofai(claudeEvent, {
|
|
187
|
+
const r = await runFailproofai(claudeEvent, {
|
|
164
188
|
session_id: sessionID, cwd: directory, hook_event_name: claudeEvent,
|
|
165
189
|
}, directory);
|
|
166
190
|
await applyDecision(r, { client, sessionID }, claudeEvent);
|
|
@@ -168,7 +192,7 @@ export default async function failproofaiPlugin({ client, directory }) {
|
|
|
168
192
|
|
|
169
193
|
"tool.execute.before": async (input, output) => {
|
|
170
194
|
const canonicalTool = canonicalizeTool(input.tool);
|
|
171
|
-
const r = runFailproofai("PreToolUse", {
|
|
195
|
+
const r = await runFailproofai("PreToolUse", {
|
|
172
196
|
session_id: input.sessionID,
|
|
173
197
|
cwd: directory,
|
|
174
198
|
tool_name: canonicalTool,
|
|
@@ -180,7 +204,7 @@ export default async function failproofaiPlugin({ client, directory }) {
|
|
|
180
204
|
|
|
181
205
|
"tool.execute.after": async (input, output) => {
|
|
182
206
|
const canonicalTool = canonicalizeTool(input.tool);
|
|
183
|
-
const r = runFailproofai("PostToolUse", {
|
|
207
|
+
const r = await runFailproofai("PostToolUse", {
|
|
184
208
|
session_id: input.sessionID,
|
|
185
209
|
cwd: directory,
|
|
186
210
|
tool_name: canonicalTool,
|
|
@@ -193,7 +217,7 @@ export default async function failproofaiPlugin({ client, directory }) {
|
|
|
193
217
|
|
|
194
218
|
"permission.ask": async (input, output) => {
|
|
195
219
|
const canonicalTool = canonicalizeTool(input.tool);
|
|
196
|
-
const r = runFailproofai("PermissionRequest", {
|
|
220
|
+
const r = await runFailproofai("PermissionRequest", {
|
|
197
221
|
session_id: input.sessionID,
|
|
198
222
|
cwd: directory,
|
|
199
223
|
tool_name: canonicalTool || input.command || "permission",
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"use server";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
activeFindings,
|
|
5
|
+
dismissFinding,
|
|
6
|
+
markLeakReportViewed,
|
|
7
|
+
readLeakRecord,
|
|
8
|
+
} from "@/src/audit/leak-store";
|
|
9
|
+
import { readConfig, updateConfig } from "@/src/hooks/fp-config";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* One credential, flattened for the report table.
|
|
13
|
+
*
|
|
14
|
+
* A separate shape from `LeakFinding` on purpose: this crosses into a client
|
|
15
|
+
* component, so it carries only what is drawn. The finding's raw sightings, its
|
|
16
|
+
* rule and its salt stay on the server side of the boundary — not because any
|
|
17
|
+
* of them is a secret (the record holds no secret by construction), but because
|
|
18
|
+
* a display type that mirrors the storage type drifts into rendering whatever
|
|
19
|
+
* gets added to storage next.
|
|
20
|
+
*/
|
|
21
|
+
export interface LeakRow {
|
|
22
|
+
id: string;
|
|
23
|
+
/** WHAT — `ghp_••••••••4f2a`. Never the value; there is no value to send. */
|
|
24
|
+
display: string;
|
|
25
|
+
label: string;
|
|
26
|
+
length: number;
|
|
27
|
+
/** False means no console to revoke at — the advice changes completely. */
|
|
28
|
+
attributed: boolean;
|
|
29
|
+
/** The identifier it was assigned to, when there was one. */
|
|
30
|
+
name: string | null;
|
|
31
|
+
/** WHO — the harness whose transcript carried it. */
|
|
32
|
+
cli: string;
|
|
33
|
+
/** WHERE — home-shortened project path. */
|
|
34
|
+
project: string;
|
|
35
|
+
/** WHEN — ISO, formatted client-side so it lands in the reader's timezone. */
|
|
36
|
+
lastSeen: string;
|
|
37
|
+
firstSeen: string;
|
|
38
|
+
/** HOW — "read from ~/…/.env". */
|
|
39
|
+
mechanism: string;
|
|
40
|
+
/** WHY IT MATTERS — an input the agent sent can be denied next time; a
|
|
41
|
+
* result it received cannot be un-received. */
|
|
42
|
+
direction: "input" | "result";
|
|
43
|
+
occurrences: number;
|
|
44
|
+
sessions: number;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface LeaksPayload {
|
|
48
|
+
rows: LeakRow[];
|
|
49
|
+
/** Whether this machine may raise a desktop notification. Drawn as a toggle
|
|
50
|
+
* beside the table, because the table is where somebody decides the banner
|
|
51
|
+
* was worth it or not. */
|
|
52
|
+
notify: boolean;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export async function getLeaksAction(): Promise<LeaksPayload> {
|
|
56
|
+
const findings = activeFindings(readLeakRecord());
|
|
57
|
+
// Opening the report is the one signal worth silencing the in-CLI notice on.
|
|
58
|
+
// Recorded here rather than on a button, because reading it is the action —
|
|
59
|
+
// there is nothing further for the user to do to say "I have seen this".
|
|
60
|
+
markLeakReportViewed();
|
|
61
|
+
const rows: LeakRow[] = findings.map((f) => {
|
|
62
|
+
// The most recent sighting: where the key is now, not where it debuted.
|
|
63
|
+
const seen = f.sightings?.[f.sightings.length - 1];
|
|
64
|
+
return {
|
|
65
|
+
id: f.id,
|
|
66
|
+
display: f.fingerprint?.display ?? "[credential]",
|
|
67
|
+
label: f.fingerprint?.label ?? "secret",
|
|
68
|
+
length: f.fingerprint?.length ?? 0,
|
|
69
|
+
attributed: f.fingerprint?.attributed === true,
|
|
70
|
+
name: f.name,
|
|
71
|
+
cli: seen?.cli ?? "unknown",
|
|
72
|
+
project: seen?.cwd ?? "unknown",
|
|
73
|
+
lastSeen: f.lastSeen,
|
|
74
|
+
firstSeen: f.firstSeen,
|
|
75
|
+
mechanism: seen?.mechanism?.summary ?? "seen in a transcript",
|
|
76
|
+
direction: seen?.mechanism?.direction ?? "result",
|
|
77
|
+
occurrences: f.occurrences,
|
|
78
|
+
sessions: new Set((f.sightings ?? []).map((s) => s.sessionId)).size,
|
|
79
|
+
};
|
|
80
|
+
});
|
|
81
|
+
rows.sort((a, b) => Date.parse(b.lastSeen) - Date.parse(a.lastSeen));
|
|
82
|
+
return { rows, notify: readConfig().audit.notify };
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Mark one finding as not-a-secret.
|
|
87
|
+
*
|
|
88
|
+
* The finding is RETAINED, not deleted — deleting it would let the next scan
|
|
89
|
+
* rediscover the same value and alert again, which is the one outcome that
|
|
90
|
+
* teaches a user the dismiss button does not work.
|
|
91
|
+
*/
|
|
92
|
+
export async function dismissLeakAction(id: string): Promise<boolean> {
|
|
93
|
+
return dismissFinding(id);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Turn the desktop banner on or off.
|
|
98
|
+
*
|
|
99
|
+
* Writes the same `audit.notify` key `failproofai config` writes and the daemon's
|
|
100
|
+
* audit child reads, so the dashboard and the CLI cannot disagree about it.
|
|
101
|
+
*/
|
|
102
|
+
export async function setLeakNotifyAction(notify: boolean): Promise<boolean> {
|
|
103
|
+
try {
|
|
104
|
+
updateConfig({ audit: { notify } });
|
|
105
|
+
return true;
|
|
106
|
+
} catch {
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* Top-level client wrapper for /audit.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
6
|
+
* The old five-section personality report is SWITCHED OFF and being rebuilt
|
|
7
|
+
* bottom-up around leak detection. What it used to compose:
|
|
8
8
|
*
|
|
9
9
|
* 01 AuditPoster — single-screen shareable poster
|
|
10
10
|
* 02 StrengthsSection — what it's great at
|
|
@@ -12,23 +12,36 @@
|
|
|
12
12
|
* 04 HowToImproveSection — install / configure
|
|
13
13
|
* 05 ComeBackBetterSection — spread the audit (invite)
|
|
14
14
|
*
|
|
15
|
+
* Every one of those components, and the score / persona / strengths / findings
|
|
16
|
+
* modules behind them, is intact and still unit-tested — only the renders and
|
|
17
|
+
* the imports here are commented out, so restoring any of it is deleting a pair
|
|
18
|
+
* of comment markers. See the header of `src/audit/scoring.ts` for why.
|
|
19
|
+
*
|
|
20
|
+
* What this page renders now is `AuditReportPlaceholder`: the scan's own
|
|
21
|
+
* numbers. The scan, the 12-CLI transcript reader and the emailed digest all
|
|
22
|
+
* still run.
|
|
23
|
+
*
|
|
15
24
|
* Empty / running states fall back to EmptyState and RunProgress.
|
|
16
25
|
*/
|
|
17
26
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
18
27
|
import { getAuditResultAction } from "@/app/actions/get-audit-result";
|
|
19
28
|
import type { AuditResult, RunAuditOptions } from "@/src/audit/types";
|
|
20
|
-
import { classifyAgent } from "@/src/audit/archetypes";
|
|
21
|
-
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
29
|
+
// import { classifyAgent } from "@/src/audit/archetypes";
|
|
30
|
+
// Score switched off — see the header of `src/audit/scoring.ts`.
|
|
31
|
+
// import { deriveScore, gradeFor, projectedScore } from "@/src/audit/scoring";
|
|
32
|
+
// import { deriveStrengths } from "@/src/audit/strengths";
|
|
33
|
+
// import { deriveFindings } from "@/src/audit/findings";
|
|
24
34
|
import { usePostHog } from "@/contexts/PostHogContext";
|
|
25
35
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
import {
|
|
29
|
-
import {
|
|
30
|
-
import {
|
|
36
|
+
// The old report's five sections — switched off, not deleted. Each component
|
|
37
|
+
// file and its tests are untouched; only this render is commented out.
|
|
38
|
+
// import { AuditPoster } from "./audit-poster";
|
|
39
|
+
// import { StrengthsSection } from "./strengths-section";
|
|
40
|
+
// import { QuirksSection } from "./quirks-section";
|
|
41
|
+
// import { HowToImproveSection } from "./how-to-improve-section";
|
|
42
|
+
// import { ComeBackBetterSection } from "./come-back-better-section";
|
|
31
43
|
import { ReportFooter } from "./report-footer";
|
|
44
|
+
import { LeakSection } from "./leak-section";
|
|
32
45
|
import { EmptyState } from "./empty-state";
|
|
33
46
|
import { RunProgress } from "./run-progress";
|
|
34
47
|
import { AuditProgressStrip, type RerunStatus } from "./audit-progress-strip";
|
|
@@ -46,7 +59,9 @@ type Initial =
|
|
|
46
59
|
/** Tag passed to the shared `startRerun()` handler so PostHog can tell
|
|
47
60
|
* whether the click came from the bottom return-section button or the
|
|
48
61
|
* empty-state CTA. */
|
|
49
|
-
|
|
62
|
+
// `scan_header` is the button in section 01 — the only re-scan control the
|
|
63
|
+
// page has now that the old report's sections are switched off.
|
|
64
|
+
export type RerunSource = "return_section" | "empty_state" | "scan_header";
|
|
50
65
|
|
|
51
66
|
interface Props {
|
|
52
67
|
initial: Initial;
|
|
@@ -59,6 +74,9 @@ interface Props {
|
|
|
59
74
|
totalCatalogSize: number;
|
|
60
75
|
}
|
|
61
76
|
|
|
77
|
+
/* Switched off with the persona layer — this named the project that seeded the
|
|
78
|
+
archetype classifier and the leaderboard row. Restore alongside
|
|
79
|
+
`classifyAgent` in this file.
|
|
62
80
|
function inferProjectName(result: AuditResult, override?: string): string {
|
|
63
81
|
if (override && override.trim()) return override;
|
|
64
82
|
// Pick the cwd that appears in the most examples — proxy for "your
|
|
@@ -81,6 +99,7 @@ function inferProjectName(result: AuditResult, override?: string): string {
|
|
|
81
99
|
if (segs.length >= 2) return `${segs[segs.length - 2]} / ${segs[segs.length - 1]}`;
|
|
82
100
|
return segs[segs.length - 1] ?? "your agent";
|
|
83
101
|
}
|
|
102
|
+
*/
|
|
84
103
|
|
|
85
104
|
export function AuditDashboard({ initial, projectFromUrl, totalCatalogSize }: Props) {
|
|
86
105
|
const [cache, setCache] = useState<Initial>(initial);
|
|
@@ -279,16 +298,22 @@ function MainReport({
|
|
|
279
298
|
onDismissRerun,
|
|
280
299
|
}: MainReportProps) {
|
|
281
300
|
const { capture } = usePostHog();
|
|
282
|
-
|
|
301
|
+
// Only fed the persona classifier, which is switched off with it.
|
|
302
|
+
// const project = useMemo(() => inferProjectName(result, projectFromUrl), [result, projectFromUrl]);
|
|
283
303
|
// Seed classification with the project name so the behaviour fingerprint
|
|
284
304
|
// (used for tie-breaks + copy variants) is stable per project.
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
const
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
const
|
|
305
|
+
// Persona classification is switched off with the rest of the old report. Its
|
|
306
|
+
// last live use was two telemetry properties describing a persona the product
|
|
307
|
+
// no longer shows anyone.
|
|
308
|
+
// const classification = useMemo(() => classifyAgent(result, project), [result, project]);
|
|
309
|
+
// Score switched off — see the header of `src/audit/scoring.ts`. The four
|
|
310
|
+
// functions are intact and still unit-tested; nothing calls them.
|
|
311
|
+
// const score = useMemo(() => deriveScore(result), [result]);
|
|
312
|
+
// const projected = useMemo(() => projectedScore(result, score), [result, score]);
|
|
313
|
+
// const grade = gradeFor(score);
|
|
314
|
+
// const projectedGrade = gradeFor(projected);
|
|
315
|
+
// const strengths = useMemo(() => deriveStrengths(result), [result]);
|
|
316
|
+
// const findings = useMemo(() => deriveFindings(result), [result]);
|
|
292
317
|
|
|
293
318
|
// One pass over result.results: detectors triggered + missing prescribed
|
|
294
319
|
// policies. Both feed PostHog instrumentation; `missing` also feeds the
|
|
@@ -310,10 +335,13 @@ function MainReport({
|
|
|
310
335
|
if (dashboardViewedRef.current) return;
|
|
311
336
|
dashboardViewedRef.current = true;
|
|
312
337
|
capture("audit_dashboard_viewed", {
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
338
|
+
// Score switched off — see `src/audit/scoring.ts`. `missing` is the
|
|
339
|
+
// prescription's denominator and is unaffected, so the copy→install
|
|
340
|
+
// funnel keeps both of its ends.
|
|
341
|
+
// score,
|
|
342
|
+
// grade,
|
|
343
|
+
// archetype: classification.archetype,
|
|
344
|
+
// secondary: classification.secondary ?? null,
|
|
317
345
|
missing,
|
|
318
346
|
transcripts_scanned: result.transcripts.scanned,
|
|
319
347
|
results_count: result.results.length,
|
|
@@ -321,10 +349,6 @@ function MainReport({
|
|
|
321
349
|
});
|
|
322
350
|
}, [
|
|
323
351
|
capture,
|
|
324
|
-
score,
|
|
325
|
-
grade,
|
|
326
|
-
classification.archetype,
|
|
327
|
-
classification.secondary,
|
|
328
352
|
missing,
|
|
329
353
|
result.transcripts.scanned,
|
|
330
354
|
result.results.length,
|
|
@@ -332,19 +356,43 @@ function MainReport({
|
|
|
332
356
|
]);
|
|
333
357
|
|
|
334
358
|
/** Poster ref — captured to PNG by the poster's share buttons. */
|
|
335
|
-
const posterRef = useRef<HTMLDivElement>(null);
|
|
359
|
+
// const posterRef = useRef<HTMLDivElement>(null);
|
|
336
360
|
|
|
337
361
|
return (
|
|
338
362
|
<div className="app">
|
|
339
363
|
<AuditProgressStrip status={rerunStatus} onDismiss={onDismissRerun} />
|
|
340
364
|
<div className="app-shell">
|
|
341
365
|
<div className="report">
|
|
366
|
+
<AuditReportPlaceholder
|
|
367
|
+
transcripts={result.transcripts.scanned}
|
|
368
|
+
events={result.eventsScanned ?? 0}
|
|
369
|
+
projects={result.projectsScanned.length}
|
|
370
|
+
isRunning={isRunning || rerunStatus.kind === "running"}
|
|
371
|
+
onRerun={() => onRerun("scan_header")}
|
|
372
|
+
/>
|
|
373
|
+
{/* The rebuilt report. It reads the leak record rather than this
|
|
374
|
+
scan's result, deliberately: a credential found last month and
|
|
375
|
+
not touched by today's transcripts is still a credential to
|
|
376
|
+
rotate, and a report that showed only the current scan's findings
|
|
377
|
+
would go quiet on exactly those. */}
|
|
378
|
+
<LeakSection />
|
|
379
|
+
{/* The whole old report is switched off — the persona poster, the
|
|
380
|
+
strengths and quirks sections, the punch-list with its install-all
|
|
381
|
+
funnel, and the invite section. It is being rebuilt bottom-up
|
|
382
|
+
around leak detection; see the header of `src/audit/scoring.ts`
|
|
383
|
+
for the reasoning and `~/Desktop/failproofai-leak-detection-
|
|
384
|
+
verdict-2026-09-07.md` for the measurements behind it.
|
|
385
|
+
|
|
386
|
+
Every component below is intact and still unit-tested — only the
|
|
387
|
+
render is commented — so restoring any one of them is deleting a
|
|
388
|
+
pair of comment markers.
|
|
389
|
+
|
|
342
390
|
<AuditPoster
|
|
343
391
|
ref={posterRef}
|
|
344
392
|
archetypeKey={classification.archetype}
|
|
345
393
|
seed={classification.variantSeed}
|
|
346
|
-
score={score}
|
|
347
|
-
grade={grade}
|
|
394
|
+
// score={score}
|
|
395
|
+
// grade={grade}
|
|
348
396
|
missing={missing}
|
|
349
397
|
auditedAt={cachedAt ?? new Date().toISOString()}
|
|
350
398
|
/>
|
|
@@ -352,10 +400,11 @@ function MainReport({
|
|
|
352
400
|
<QuirksSection findings={findings} />
|
|
353
401
|
<HowToImproveSection
|
|
354
402
|
result={result}
|
|
355
|
-
|
|
356
|
-
|
|
403
|
+
// projected={projected}
|
|
404
|
+
// projectedGrade={projectedGrade}
|
|
357
405
|
/>
|
|
358
|
-
<ComeBackBetterSection
|
|
406
|
+
<ComeBackBetterSection />
|
|
407
|
+
*/}
|
|
359
408
|
</div>
|
|
360
409
|
<ReportFooter cachedAt={cachedAt} />
|
|
361
410
|
</div>
|
|
@@ -363,6 +412,63 @@ function MainReport({
|
|
|
363
412
|
);
|
|
364
413
|
}
|
|
365
414
|
|
|
415
|
+
/**
|
|
416
|
+
* What `/audit` shows while the report is being rebuilt.
|
|
417
|
+
*
|
|
418
|
+
* Deliberately states the scan's own numbers rather than nothing at all: the
|
|
419
|
+
* scan still runs, still walks every transcript across all 12 CLIs, and still
|
|
420
|
+
* feeds the emailed digest. Saying so is the difference between "this page is
|
|
421
|
+
* under construction" and "this product is broken".
|
|
422
|
+
*/
|
|
423
|
+
function AuditReportPlaceholder(
|
|
424
|
+
{
|
|
425
|
+
transcripts,
|
|
426
|
+
events,
|
|
427
|
+
projects,
|
|
428
|
+
isRunning,
|
|
429
|
+
onRerun,
|
|
430
|
+
}: {
|
|
431
|
+
transcripts: number;
|
|
432
|
+
events: number;
|
|
433
|
+
projects: number;
|
|
434
|
+
isRunning: boolean;
|
|
435
|
+
onRerun: () => void;
|
|
436
|
+
},
|
|
437
|
+
) {
|
|
438
|
+
const n = (x: number) => x.toLocaleString();
|
|
439
|
+
return (
|
|
440
|
+
<section className="audit-sec" data-screen-label="01 Scan">
|
|
441
|
+
<div className="audit-sec-head">
|
|
442
|
+
<span className="audit-sec-eyebrow">
|
|
443
|
+
<span className="ix">01</span>{"// scan"}
|
|
444
|
+
</span>
|
|
445
|
+
{/* The re-scan control. It lived in the old report's sections and went
|
|
446
|
+
dormant when they were commented out, which left the page with no way
|
|
447
|
+
to run an audit again at all — you had to go back to the terminal. */}
|
|
448
|
+
<button
|
|
449
|
+
type="button"
|
|
450
|
+
className="scan-rerun"
|
|
451
|
+
onClick={onRerun}
|
|
452
|
+
disabled={isRunning}
|
|
453
|
+
>
|
|
454
|
+
{isRunning ? "scanning…" : "run again"}
|
|
455
|
+
</button>
|
|
456
|
+
</div>
|
|
457
|
+
<h2 className="audit-sec-title">scan complete</h2>
|
|
458
|
+
<div className="audit-sec-sub">
|
|
459
|
+
{n(events)} tool call{events === 1 ? "" : "s"} across {n(transcripts)}{" "}
|
|
460
|
+
transcript{transcripts === 1 ? "" : "s"}
|
|
461
|
+
{projects > 0 ? ` · ${n(projects)} project${projects === 1 ? "" : "s"}` : ""}
|
|
462
|
+
</div>
|
|
463
|
+
<div className="audit-sec-sub">
|
|
464
|
+
{"// the report is being rebuilt around leak detection. the scan, the"}
|
|
465
|
+
<br />
|
|
466
|
+
{"// 12-CLI transcript reader and the emailed digest are unaffected."}
|
|
467
|
+
</div>
|
|
468
|
+
</section>
|
|
469
|
+
);
|
|
470
|
+
}
|
|
471
|
+
|
|
366
472
|
interface ShellEmptyProps {
|
|
367
473
|
running: boolean;
|
|
368
474
|
mode?: "no-cache" | "zero-sessions";
|
|
@@ -24,7 +24,12 @@
|
|
|
24
24
|
import React, { forwardRef, useMemo, useState } from "react";
|
|
25
25
|
import { pickArchetypeVariant, type ArchetypeKey } from "@/src/audit/archetypes";
|
|
26
26
|
import { type Grade } from "@/src/audit/scoring";
|
|
27
|
-
|
|
27
|
+
// Archetype rarity switched off — the percentages are eight hardcoded integers
|
|
28
|
+
// ("Seeded with snapshot values; swap for live aggregates once that pipeline
|
|
29
|
+
// lands"), and this is the ONLY surface that rendered them: baked by
|
|
30
|
+
// html-to-image into the PNG people post publicly. A fabricated population
|
|
31
|
+
// statistic on a shared card is a claim we cannot support.
|
|
32
|
+
// import { getArchetypeRarityPct } from "@/src/audit/social-proof";
|
|
28
33
|
import { copyOrDownloadCard, downloadCard, shareCardNative, shareCardToastMessage } from "@/lib/share-card";
|
|
29
34
|
import { toast } from "@/app/components/toast";
|
|
30
35
|
import { usePostHog } from "@/contexts/PostHogContext";
|
|
@@ -45,8 +50,11 @@ interface Props {
|
|
|
45
50
|
archetypeKey: ArchetypeKey;
|
|
46
51
|
/** Stable seed for variant selection (project name is the natural fit). */
|
|
47
52
|
seed: string;
|
|
48
|
-
score
|
|
49
|
-
|
|
53
|
+
/** The score is switched off (see `src/audit/scoring.ts`). Kept as optional
|
|
54
|
+
* props rather than removed, so restoring is un-commenting rather than
|
|
55
|
+
* re-threading: the dashboard simply stops passing them. */
|
|
56
|
+
score?: number;
|
|
57
|
+
grade?: Grade;
|
|
50
58
|
/** Count of unenabled prescribed policies — passed to the share-text
|
|
51
59
|
* templates, not rendered on the poster itself. */
|
|
52
60
|
missing: number;
|
|
@@ -63,7 +71,7 @@ export const AuditPoster = forwardRef<HTMLDivElement, Props>(function AuditPoste
|
|
|
63
71
|
() => pickArchetypeVariant(archetypeKey, seed),
|
|
64
72
|
[archetypeKey, seed],
|
|
65
73
|
);
|
|
66
|
-
const rarityPct = getArchetypeRarityPct(archetypeKey);
|
|
74
|
+
// const rarityPct = getArchetypeRarityPct(archetypeKey);
|
|
67
75
|
const indexLabel = String(archetype.index).padStart(2, "0");
|
|
68
76
|
const auditedDate = useMemo(() => formatAuditedDate(auditedAt), [auditedAt]);
|
|
69
77
|
|
|
@@ -134,8 +142,11 @@ export const AuditPoster = forwardRef<HTMLDivElement, Props>(function AuditPoste
|
|
|
134
142
|
}
|
|
135
143
|
};
|
|
136
144
|
|
|
145
|
+
// Score switched off — the filename is keyed on the archetype instead, which
|
|
146
|
+
// is what the card now actually shows. Original:
|
|
147
|
+
// `failproofai-${channel}-${grade.toLowerCase()}-${score}.png`
|
|
137
148
|
const filenameFor = (channel: "x" | "linkedin" | "download") =>
|
|
138
|
-
`failproofai-${channel}-${
|
|
149
|
+
`failproofai-${channel}-${archetypeKey}.png`;
|
|
139
150
|
|
|
140
151
|
const handleShare = async (channel: "x" | "linkedin" | "download") => {
|
|
141
152
|
if (busy) return;
|
|
@@ -143,8 +154,11 @@ export const AuditPoster = forwardRef<HTMLDivElement, Props>(function AuditPoste
|
|
|
143
154
|
capture("audit_card_share_clicked", {
|
|
144
155
|
channel,
|
|
145
156
|
source: "poster",
|
|
146
|
-
|
|
147
|
-
|
|
157
|
+
// Score switched off — see `src/audit/scoring.ts`. Note for whoever reads
|
|
158
|
+
// the funnel: these two properties stop appearing from this release, so a
|
|
159
|
+
// dashboard keyed on them breaks rather than reading zero.
|
|
160
|
+
// score,
|
|
161
|
+
// grade,
|
|
148
162
|
missing_policies: missing,
|
|
149
163
|
});
|
|
150
164
|
try {
|
|
@@ -174,10 +188,10 @@ export const AuditPoster = forwardRef<HTMLDivElement, Props>(function AuditPoste
|
|
|
174
188
|
}
|
|
175
189
|
|
|
176
190
|
const shareCtx: ShareCtx = {
|
|
177
|
-
score,
|
|
178
191
|
arch: archetype.name.toLowerCase(),
|
|
179
|
-
grade,
|
|
180
192
|
missing,
|
|
193
|
+
// score,
|
|
194
|
+
// grade,
|
|
181
195
|
};
|
|
182
196
|
const shareText = channel === "x"
|
|
183
197
|
? pickTemplate(X_TEMPLATES, seed, shareCtx)
|
|
@@ -248,6 +262,7 @@ export const AuditPoster = forwardRef<HTMLDivElement, Props>(function AuditPoste
|
|
|
248
262
|
</React.Fragment>
|
|
249
263
|
))}
|
|
250
264
|
</div>
|
|
265
|
+
{/* Rarity switched off — see the import above.
|
|
251
266
|
{typeof rarityPct === "number" && (
|
|
252
267
|
<div className="persona-rarity">
|
|
253
268
|
<span className="lbl">{"// only"}</span>{" "}
|
|
@@ -255,13 +270,17 @@ export const AuditPoster = forwardRef<HTMLDivElement, Props>(function AuditPoste
|
|
|
255
270
|
<span className="lbl">of agents are this archetype</span>
|
|
256
271
|
</div>
|
|
257
272
|
)}
|
|
273
|
+
*/}
|
|
258
274
|
</div>
|
|
259
275
|
|
|
260
|
-
{/* Score block — heroic number, centered in the card
|
|
276
|
+
{/* Score block — heroic number, centered in the card. Switched off;
|
|
277
|
+
see `src/audit/scoring.ts` for why. The archetype is the card's
|
|
278
|
+
headline now.
|
|
261
279
|
<div className="poster-score">
|
|
262
280
|
<span className="score-n">{score}</span>
|
|
263
281
|
<span className="score-of">/100</span>
|
|
264
282
|
</div>
|
|
283
|
+
*/}
|
|
265
284
|
</div>
|
|
266
285
|
|
|
267
286
|
<footer className="poster-foot">
|
|
@@ -21,7 +21,12 @@ import { AuthDialog, type AuthedUser } from "./auth-dialog";
|
|
|
21
21
|
import { InviteDialog } from "./invite-dialog";
|
|
22
22
|
|
|
23
23
|
interface Props {
|
|
24
|
-
/** Current audit score (0–100), forwarded into the invite email body.
|
|
24
|
+
/** Current audit score (0–100), forwarded into the invite email body.
|
|
25
|
+
*
|
|
26
|
+
* Always undefined while the score is switched off (see
|
|
27
|
+
* `src/audit/scoring.ts`) — the dashboard no longer passes it. Nothing
|
|
28
|
+
* breaks: `/api/audit/invite` already treats it as optional and simply
|
|
29
|
+
* leaves it out of the email body when it is not a finite number. */
|
|
25
30
|
score?: number;
|
|
26
31
|
}
|
|
27
32
|
|
|
@@ -74,7 +74,10 @@ export function EmptyState({ mode, running, onStarted, onCompleted }: Props) {
|
|
|
74
74
|
<p className="empty-sub">
|
|
75
75
|
we'll walk every transcript across your installed CLIs — Claude Code,
|
|
76
76
|
Codex, Copilot, Cursor, OpenCode, Pi — and count every wasteful
|
|
77
|
-
|
|
77
|
+
{/* Was "a tier, a score, and a punch-list" — the tier was never
|
|
78
|
+
rendered and the score is switched off, so this promised two
|
|
79
|
+
things the page did not show. */}
|
|
80
|
+
or risky action. you'll get your agent's archetype and a punch-list.
|
|
78
81
|
</p>
|
|
79
82
|
|
|
80
83
|
<div className="empty-actions">
|