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
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Getting a notification onto a Mac's screen from a process that has no screen.
|
|
3
|
+
*
|
|
4
|
+
* On Linux the scheduled audit talks to the session bus directly and is done
|
|
5
|
+
* (`desktop-notify.ts`). macOS has no equivalent shortcut, and the reason is
|
|
6
|
+
* structural rather than a missing permission: launchd has two domains, and
|
|
7
|
+
* Notification Center lives in only one of them. `failproofaid` is installed as
|
|
8
|
+
* a **LaunchDaemon** — that is what makes it start at boot and survive logout,
|
|
9
|
+
* the property the whole daemon design turns on — so it and every child it
|
|
10
|
+
* spawns run in the *system* domain, outside the logged-in user's GUI session.
|
|
11
|
+
* A `display notification` from there posts into nothing. Apple's TN2083 draws
|
|
12
|
+
* exactly this line, and Time Machine ships the same split: a privileged daemon
|
|
13
|
+
* doing the work, an agent in the user's session doing the talking.
|
|
14
|
+
*
|
|
15
|
+
* So this module installs the second half — a **LaunchAgent**, which launchd
|
|
16
|
+
* starts inside the Aqua session, where Notification Center is reachable.
|
|
17
|
+
*
|
|
18
|
+
* ## Three choices worth stating, because the obvious alternative is wrong
|
|
19
|
+
*
|
|
20
|
+
* **`~/Library/LaunchAgents`, not `/Library/LaunchAgents`.** The per-user
|
|
21
|
+
* directory is owned by the user and writable without elevation, so installing
|
|
22
|
+
* this asks for nothing — no password, no second sudo prompt in a wizard that
|
|
23
|
+
* already spent its one. The system-wide agent directory would need admin and
|
|
24
|
+
* would install for every account on the box, which is not what a per-user
|
|
25
|
+
* notification is.
|
|
26
|
+
*
|
|
27
|
+
* **An app bundle, not a bare `osascript -e 'display notification'`.** A raw
|
|
28
|
+
* osascript notification is attributed to whatever host ran it — in practice
|
|
29
|
+
* "Script Editor" — so it inherits Script Editor's notification permission,
|
|
30
|
+
* appears under Script Editor in System Settings, and is indistinguishable from
|
|
31
|
+
* any other script on the machine. Compiling a tiny applet with `osacompile`
|
|
32
|
+
* gives it its own bundle identifier, so the banner says failproofai, and the
|
|
33
|
+
* user gets a real entry they can allow, silence or deny like any other app.
|
|
34
|
+
*
|
|
35
|
+
* **A watched drop directory, not a resident process.** The agent is not a
|
|
36
|
+
* daemon: `WatchPaths` makes launchd start it only when a file appears, and it
|
|
37
|
+
* exits as soon as the directory is empty. Nothing is resident, nothing polls,
|
|
38
|
+
* and a machine that never leaks a credential never runs it at all.
|
|
39
|
+
*
|
|
40
|
+
* ## What this does NOT claim
|
|
41
|
+
*
|
|
42
|
+
* That the user saw it. macOS can be in Do Not Disturb, the display can be
|
|
43
|
+
* asleep, and the user can deny the bundle in System Settings — none of which
|
|
44
|
+
* is visible from here. The banner is a prompt to look; the record on disk is
|
|
45
|
+
* the thing that lasts.
|
|
46
|
+
*/
|
|
47
|
+
import { execFileSync } from "node:child_process";
|
|
48
|
+
import { existsSync, mkdirSync, readdirSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
49
|
+
import { homedir } from "node:os";
|
|
50
|
+
import { resolve } from "node:path";
|
|
51
|
+
|
|
52
|
+
import { runDir } from "../hooks/fp-home";
|
|
53
|
+
import { isFindingId } from "./leak-fingerprint";
|
|
54
|
+
|
|
55
|
+
/** The bundle identifier the banner is attributed to, and the agent's label. */
|
|
56
|
+
export const MAC_NOTIFIER_LABEL = "ai.failproof.notifier";
|
|
57
|
+
|
|
58
|
+
/** Where a queued notification waits for the agent to pick it up. */
|
|
59
|
+
export const macNotifyDir = (home?: string) => resolve(runDir(home), "notify");
|
|
60
|
+
|
|
61
|
+
/** The compiled applet. Under `~/.failproofai` rather than `/Applications`,
|
|
62
|
+
* because it is a delivery mechanism, not something to launch. */
|
|
63
|
+
export function macNotifierAppPath(home?: string): string {
|
|
64
|
+
return resolve(runDir(home), "..", "bin", "FailproofAI Notifier.app");
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function macNotifierPlistPath(): string {
|
|
68
|
+
return resolve(homedir(), "Library", "LaunchAgents", `${MAC_NOTIFIER_LABEL}.plist`);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function escapeXml(s: string): string {
|
|
72
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* The AppleScript the applet runs: drain the directory, say each line, exit.
|
|
77
|
+
*
|
|
78
|
+
* Payload format is two lines — title, then body — chosen over JSON because
|
|
79
|
+
* AppleScript has no JSON parser and shelling out to one would put a second
|
|
80
|
+
* interpreter in the path of a two-field message.
|
|
81
|
+
*
|
|
82
|
+
* The file is REMOVED BEFORE the notification is posted, and that order is
|
|
83
|
+
* deliberate: `WatchPaths` fires on every change to the directory, so a file
|
|
84
|
+
* that cannot be displayed and is not removed would wake this agent forever.
|
|
85
|
+
* At-most-once is the right failure here because the caller has already claimed
|
|
86
|
+
* the finding on disk — a dropped banner costs one silent finding, a wake loop
|
|
87
|
+
* costs the machine.
|
|
88
|
+
*/
|
|
89
|
+
export function notifierScript(home?: string): string {
|
|
90
|
+
const dir = macNotifyDir(home);
|
|
91
|
+
return `on run
|
|
92
|
+
set dropDir to ${JSON.stringify(dir + "/")}
|
|
93
|
+
set listing to ""
|
|
94
|
+
try
|
|
95
|
+
set listing to do shell script "ls -1 " & quoted form of dropDir & " 2>/dev/null"
|
|
96
|
+
end try
|
|
97
|
+
repeat with entryName in paragraphs of listing
|
|
98
|
+
set entryPath to dropDir & (entryName as string)
|
|
99
|
+
if (entryName as string) is not "" then
|
|
100
|
+
try
|
|
101
|
+
set payload to do shell script "cat " & quoted form of entryPath & " 2>/dev/null"
|
|
102
|
+
do shell script "rm -f " & quoted form of entryPath
|
|
103
|
+
set lines_ to paragraphs of payload
|
|
104
|
+
if (count of lines_) is greater than 1 then
|
|
105
|
+
set noteTitle to item 1 of lines_
|
|
106
|
+
set noteBody to ""
|
|
107
|
+
repeat with i from 2 to (count of lines_)
|
|
108
|
+
if noteBody is not "" then set noteBody to noteBody & " "
|
|
109
|
+
set noteBody to noteBody & (item i of lines_)
|
|
110
|
+
end repeat
|
|
111
|
+
display notification noteBody with title noteTitle
|
|
112
|
+
end if
|
|
113
|
+
end try
|
|
114
|
+
end if
|
|
115
|
+
end repeat
|
|
116
|
+
end run
|
|
117
|
+
`;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Exported for the same reason `launchdPlistContents` is: it is the only way to
|
|
122
|
+
* assert this file's shape from a Linux CI runner, which is every CI runner we
|
|
123
|
+
* have.
|
|
124
|
+
*/
|
|
125
|
+
export function notifierPlistContents(appPath: string, watchDir: string): string {
|
|
126
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
127
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
128
|
+
<plist version="1.0">
|
|
129
|
+
<dict>
|
|
130
|
+
<key>Label</key>
|
|
131
|
+
<string>${escapeXml(MAC_NOTIFIER_LABEL)}</string>
|
|
132
|
+
<key>ProgramArguments</key>
|
|
133
|
+
<array>
|
|
134
|
+
<string>${escapeXml(resolve(appPath, "Contents", "MacOS", "applet"))}</string>
|
|
135
|
+
</array>
|
|
136
|
+
<!-- Started only when something is queued, and it exits when the queue is
|
|
137
|
+
empty. RunAtLoad would fire it once at login with nothing to say. -->
|
|
138
|
+
<key>WatchPaths</key>
|
|
139
|
+
<array>
|
|
140
|
+
<string>${escapeXml(watchDir)}</string>
|
|
141
|
+
</array>
|
|
142
|
+
<key>RunAtLoad</key>
|
|
143
|
+
<false/>
|
|
144
|
+
<!-- Not a service: it does one pass and exits, and launchd must not treat
|
|
145
|
+
that as a crash to restart. -->
|
|
146
|
+
<key>KeepAlive</key>
|
|
147
|
+
<false/>
|
|
148
|
+
<key>ProcessType</key>
|
|
149
|
+
<string>Interactive</string>
|
|
150
|
+
</dict>
|
|
151
|
+
</plist>
|
|
152
|
+
`;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export interface MacNotifierResult {
|
|
156
|
+
installed: boolean;
|
|
157
|
+
reason?: string;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/** Bounded, and never inherits a TTY — this runs from inside a wizard. */
|
|
161
|
+
function run(cmd: string, args: string[]): void {
|
|
162
|
+
execFileSync(cmd, args, { stdio: "ignore", timeout: 20_000 });
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Install the notifier, silently.
|
|
167
|
+
*
|
|
168
|
+
* Silent on purpose. An earlier draft printed "installing a small helper so we
|
|
169
|
+
* can notify you about leaks (macOS only)" during setup, which reads as an
|
|
170
|
+
* apology for something the user already asked for by running setup — every
|
|
171
|
+
* other app that can raise a notification installs its delivery path without
|
|
172
|
+
* narrating it. What the user is asked is the thing that matters (does this
|
|
173
|
+
* machine scan, and may it interrupt), and both of those are real settings.
|
|
174
|
+
*
|
|
175
|
+
* Returns rather than throws. Notifications are one channel of several, and a
|
|
176
|
+
* Mac that cannot compile an applet must still finish setting up its daemon,
|
|
177
|
+
* its hooks and its policies — the parts that actually enforce anything.
|
|
178
|
+
*/
|
|
179
|
+
export function installMacNotifier(home?: string): MacNotifierResult {
|
|
180
|
+
if (process.platform !== "darwin") return { installed: false, reason: "not macOS" };
|
|
181
|
+
try {
|
|
182
|
+
const app = macNotifierAppPath(home);
|
|
183
|
+
const watch = macNotifyDir(home);
|
|
184
|
+
mkdirSync(watch, { recursive: true, mode: 0o700 });
|
|
185
|
+
mkdirSync(resolve(app, ".."), { recursive: true });
|
|
186
|
+
|
|
187
|
+
const scriptPath = resolve(watch, "..", "notifier.applescript");
|
|
188
|
+
writeFileSync(scriptPath, notifierScript(home), { mode: 0o600 });
|
|
189
|
+
// osacompile refuses to overwrite an existing bundle, so a reinstall (a
|
|
190
|
+
// second `failproofai config`, or an upgrade) has to clear it first.
|
|
191
|
+
rmSync(app, { recursive: true, force: true });
|
|
192
|
+
run("osacompile", ["-o", app, scriptPath]);
|
|
193
|
+
rmSync(scriptPath, { force: true });
|
|
194
|
+
|
|
195
|
+
// Give the bundle its own identity, so the banner is attributed to
|
|
196
|
+
// failproofai instead of to whatever compiled it, and so the user gets one
|
|
197
|
+
// entry in System Settings > Notifications they can turn off themselves.
|
|
198
|
+
const plist = resolve(app, "Contents", "Info.plist");
|
|
199
|
+
run("defaults", ["write", plist, "CFBundleIdentifier", MAC_NOTIFIER_LABEL]);
|
|
200
|
+
run("defaults", ["write", plist, "CFBundleName", "failproofai"]);
|
|
201
|
+
// `defaults write` leaves the file 0600 and owned by us but in binary
|
|
202
|
+
// format; launchd and LaunchServices both read either, so no conversion.
|
|
203
|
+
|
|
204
|
+
mkdirSync(resolve(macNotifierPlistPath(), ".."), { recursive: true });
|
|
205
|
+
writeFileSync(macNotifierPlistPath(), notifierPlistContents(app, watch), { mode: 0o644 });
|
|
206
|
+
|
|
207
|
+
const target = `gui/${process.getuid?.() ?? 0}`;
|
|
208
|
+
// bootout first: bootstrap fails outright on an already-loaded label, and
|
|
209
|
+
// a reinstall must land the NEW plist rather than leave the old one live.
|
|
210
|
+
try {
|
|
211
|
+
run("launchctl", ["bootout", `${target}/${MAC_NOTIFIER_LABEL}`]);
|
|
212
|
+
} catch {
|
|
213
|
+
// Not loaded. That is the normal first-install case.
|
|
214
|
+
}
|
|
215
|
+
run("launchctl", ["bootstrap", target, macNotifierPlistPath()]);
|
|
216
|
+
return { installed: true };
|
|
217
|
+
} catch (err) {
|
|
218
|
+
return { installed: false, reason: err instanceof Error ? err.message : String(err) };
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Remove the agent and the bundle.
|
|
224
|
+
*
|
|
225
|
+
* Called from `failproofai uninstall --purge`. Unconditional and quiet: an
|
|
226
|
+
* agent left behind after an uninstall is a plist launchd keeps trying to start
|
|
227
|
+
* from a path that no longer exists, which shows up in the user's log forever
|
|
228
|
+
* and is the exact class of leftover an uninstall exists to prevent.
|
|
229
|
+
*/
|
|
230
|
+
export function uninstallMacNotifier(home?: string): void {
|
|
231
|
+
if (process.platform !== "darwin") return;
|
|
232
|
+
try {
|
|
233
|
+
run("launchctl", ["bootout", `gui/${process.getuid?.() ?? 0}/${MAC_NOTIFIER_LABEL}`]);
|
|
234
|
+
} catch {
|
|
235
|
+
// Already gone, or never loaded.
|
|
236
|
+
}
|
|
237
|
+
rmSync(macNotifierPlistPath(), { force: true });
|
|
238
|
+
rmSync(macNotifierAppPath(home), { recursive: true, force: true });
|
|
239
|
+
rmSync(macNotifyDir(home), { recursive: true, force: true });
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Queue one notification for the agent to deliver.
|
|
244
|
+
*
|
|
245
|
+
* Written to a sibling directory and RENAMED in, so the watcher never observes
|
|
246
|
+
* a half-written file: `WatchPaths` fires on the first byte, and a partial read
|
|
247
|
+
* would be a truncated banner that the agent then deletes.
|
|
248
|
+
*
|
|
249
|
+
* Returns whether the file landed — not whether anything was shown, which this
|
|
250
|
+
* side cannot know and does not claim.
|
|
251
|
+
*/
|
|
252
|
+
export function queueMacNotification(
|
|
253
|
+
id: string,
|
|
254
|
+
title: string,
|
|
255
|
+
body: string,
|
|
256
|
+
home?: string,
|
|
257
|
+
): boolean {
|
|
258
|
+
// The id becomes a filename in a watched directory. Same guard, same reason
|
|
259
|
+
// as `markLeakNoticeDelivered` — see `isFindingId`.
|
|
260
|
+
if (!isFindingId(id)) return false;
|
|
261
|
+
const dir = macNotifyDir(home);
|
|
262
|
+
const tmp = resolve(dir, "..", `notify-${id}.tmp`);
|
|
263
|
+
try {
|
|
264
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
265
|
+
// One line each. Newlines inside either field would be read as extra body
|
|
266
|
+
// lines by the applet, so they are flattened here rather than there.
|
|
267
|
+
const payload = `${title.replace(/\s+/g, " ")}\n${body.replace(/\s+/g, " ")}\n`;
|
|
268
|
+
writeFileSync(tmp, payload, { mode: 0o600 });
|
|
269
|
+
renameSync(tmp, resolve(dir, id));
|
|
270
|
+
return true;
|
|
271
|
+
} catch {
|
|
272
|
+
// Clean up the staging file. Without this, every failed queue attempt left
|
|
273
|
+
// a `notify-*.tmp` beside the watched directory forever — invisible to the
|
|
274
|
+
// agent, which only reads inside it, and never collected by anything.
|
|
275
|
+
try {
|
|
276
|
+
rmSync(tmp, { force: true });
|
|
277
|
+
} catch { /* nothing left to do */ }
|
|
278
|
+
return false;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/** True when an agent is installed and could pick a queued file up. */
|
|
283
|
+
export function macNotifierInstalled(home?: string): boolean {
|
|
284
|
+
return existsSync(macNotifierPlistPath()) && existsSync(macNotifierAppPath(home));
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Drop anything the agent never collected.
|
|
289
|
+
*
|
|
290
|
+
* A machine that queued a banner while logged out, or with the agent removed,
|
|
291
|
+
* would otherwise show a pile of stale findings at the next login — "we found
|
|
292
|
+
* this key" for keys already rotated weeks ago.
|
|
293
|
+
*/
|
|
294
|
+
export function pruneMacNotifyQueue(home?: string, maxAgeMs = 7 * 86_400_000): void {
|
|
295
|
+
try {
|
|
296
|
+
const dir = macNotifyDir(home);
|
|
297
|
+
if (!existsSync(dir)) return;
|
|
298
|
+
const { statSync } = require("node:fs") as typeof import("node:fs");
|
|
299
|
+
for (const name of readdirSync(dir)) {
|
|
300
|
+
const path = resolve(dir, name);
|
|
301
|
+
try {
|
|
302
|
+
if (Date.now() - statSync(path).mtimeMs > maxAgeMs) rmSync(path, { force: true });
|
|
303
|
+
} catch {
|
|
304
|
+
// Raced with the agent collecting it. Nothing to do.
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
} catch {
|
|
308
|
+
// Housekeeping only.
|
|
309
|
+
}
|
|
310
|
+
}
|