failproofai 1.0.0 → 1.0.1-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/app-path-routes-manifest.json +0 -1
- package/.next/standalone/.next/build-manifest.json +3 -3
- package/.next/standalone/.next/prerender-manifest.json +5 -5
- package/.next/standalone/.next/required-server-files.json +1 -1
- package/.next/standalone/.next/routes-manifest.json +0 -6
- package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page.js +4 -3
- package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_global-error.html +1 -1
- package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
- package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +6 -6
- package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
- package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/_not-found/page.js +4 -3
- 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 +2 -2
- package/.next/standalone/.next/server/app/api/audit/invite/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/audit/run/route.js +3 -3
- package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/audit/status/route.js +2 -2
- package/.next/standalone/.next/server/app/api/audit/status/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/login-request/route.js +4 -3
- package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/login-verify/route.js +2 -2
- package/.next/standalone/.next/server/app/api/auth/login-verify/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/logout/route.js +3 -2
- package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/status/route.js +4 -3
- package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +2 -2
- package/.next/standalone/.next/server/app/audit/page.js +5 -3
- package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/index.html +1 -1
- package/.next/standalone/.next/server/app/index.rsc +15 -15
- package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +14 -14
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +15 -15
- package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/page.js +4 -3
- package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +10 -10
- package/.next/standalone/.next/server/app/policies/page.js +6 -5
- package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page.js +5 -4
- package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/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 +6 -4
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/projects/page.js +5 -4
- package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +4 -4
- package/.next/standalone/.next/server/app/settings/page.js +6 -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/app-paths-manifest.json +0 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__05ja_05._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0agdw2a._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0d1u_na._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0nne229._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ny9q5d._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0oy4kxb._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0zf034w._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__17g9wh7._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1hstmft._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1p8poxd._.js +3 -0
- package/.next/standalone/.next/server/chunks/_0lxbzdq._.js +1 -1
- package/.next/standalone/.next/server/chunks/_1ek68ln._.js +1 -1
- package/.next/standalone/.next/server/chunks/_1zuiiy3._.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_0jx6cp6._.js → node_modules_posthog-node_dist_entrypoints_index_node_mjs_0f-x2b0._.js} +1 -1
- package/.next/standalone/.next/server/chunks/{node_modules_posthog-node_dist_entrypoints_index_node_mjs_1f290jp._.js → node_modules_posthog-node_dist_entrypoints_index_node_mjs_0hwvl7e._.js} +1 -1
- package/.next/standalone/.next/server/chunks/{node_modules_posthog-node_dist_entrypoints_index_node_mjs_1g2ji1t._.js → node_modules_posthog-node_dist_entrypoints_index_node_mjs_1ctjdzl._.js} +1 -1
- package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
- package/.next/standalone/.next/server/chunks/src_hooks_fp-home_ts_09kv0bn._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__03eykvd._.js +5 -0
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__07175vb._.js → [root-of-the-server]__07oh8b5._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0cxe_2_._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0kgy9da._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0m98kzy._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0oa1lav._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0sjzdjg._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0spkm68._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0v5_91z._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1-a3135._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1hvwiw8._.js → [root-of-the-server]__11z_299._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1apc90t._.js → [root-of-the-server]__15c_z97._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1wmno1q._.js → [root-of-the-server]__17d_ffl._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1_dfocn._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1e5g_ur._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1hmqefd._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1jiwfsj._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1kzapg5._.js +6 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1zvtylo._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_04j57fb._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_08x1r5t._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_0hom1s1._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_0qk91ba._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_1q7j05x._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_1wboum1._.js +23 -0
- package/.next/standalone/.next/server/chunks/ssr/_1ylae7o._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/app_settings_settings-client_tsx_20lq-mq._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_1n3w9lb._.js +1 -1
- 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 +4 -0
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_fp-home_ts_0je3xkv._.js +3 -0
- package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
- 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 +15 -15
- package/.next/standalone/.next/static/chunks/{2676v-lyzgo91.js → 01b0vu6t3wtfh.js} +1 -1
- package/.next/standalone/.next/static/chunks/0u64yey446k4f.css +1 -0
- package/.next/standalone/.next/static/chunks/0w-2enf8raksk.js +1 -0
- package/.next/standalone/.next/static/chunks/{2kopjq_or743g.js → 13pe0rgzztjxa.js} +2 -2
- package/.next/standalone/.next/static/chunks/{3xvtgz6arztp_.js → 1cn6xl9lfp3ei.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0zi8zjav5a4rq.js → 1e_2h_-zvxnke.js} +1 -1
- package/.next/standalone/.next/static/chunks/1eyl7fzkmnkf_.js +1 -0
- package/.next/standalone/.next/static/chunks/{0zm3_8jpqitxy.js → 1x9238y5kw9vi.js} +22 -22
- package/.next/standalone/.next/static/chunks/1xajksrefvav8.js +1 -0
- package/.next/standalone/.next/static/chunks/{1hfocb0sdl85c.js → 25c48grb44a-n.js} +1 -1
- package/.next/standalone/.next/static/chunks/{2ouq44jv_0x04.js → 28bdm54bngvc7.js} +1 -1
- package/.next/standalone/.next/static/chunks/29-iqnp9v_axt.css +1 -0
- package/.next/standalone/.next/static/chunks/{31k3yxpy57_fy.js → 2hhselnqeo4ll.js} +1 -1
- package/.next/standalone/.next/static/chunks/2k9f4tyv04809.css +1 -0
- package/.next/standalone/.next/static/chunks/3qfoeqhy5l10x.js +1 -0
- package/.next/standalone/.next/static/chunks/{0km-jn9o5xyqs.css → 3wq9x0c-7ld5d.css} +1 -1
- package/.next/standalone/app/actions/get-scheduled-audit.ts +65 -6
- package/.next/standalone/app/actions/update-scheduled-audit.ts +90 -17
- package/.next/standalone/app/api/auth/status/route.ts +7 -17
- package/.next/standalone/app/audit/_components/audit-dashboard.tsx +2 -6
- package/.next/standalone/app/audit/_components/come-back-better-section.tsx +101 -281
- package/.next/standalone/app/audit/_components/empty-state.tsx +2 -2
- package/.next/standalone/app/audit/_components/run-progress.tsx +1 -1
- package/.next/standalone/app/audit/audit-styles.css +150 -26
- package/.next/standalone/app/globals.css +39 -1
- package/.next/standalone/app/settings/page.tsx +38 -21
- package/.next/standalone/app/settings/settings-client.tsx +583 -392
- package/.next/standalone/app/settings/settings.css +354 -0
- package/.next/standalone/components/navbar.tsx +33 -4
- package/.next/standalone/lib/auth/api-server-client.ts +51 -29
- package/.next/standalone/lib/auth/auth-store.ts +44 -59
- package/.next/standalone/lib/telemetry.ts +45 -40
- package/.next/standalone/package.json +12 -10
- package/.next/standalone/server.js +1 -1
- package/bin/failproofai.mjs +6 -0
- package/bin/failproofaid-shim.mjs +0 -0
- package/dist/cli.mjs +1915 -472
- package/dist/worker.mjs +27 -5
- package/lib/auth/api-server-client.ts +51 -29
- package/lib/auth/auth-store.ts +44 -59
- package/lib/telemetry.ts +45 -40
- package/package.json +12 -10
- package/scripts/docs-audit.ts +493 -0
- package/scripts/translate-docs/cli.ts +16 -2
- package/scripts/translate-docs/mdx-translator.ts +6 -1
- package/scripts/translate-docs/readme-translator.ts +4 -2
- package/src/audit/cli-login.ts +330 -0
- package/src/audit/cli.ts +164 -31
- package/src/audit/dashboard-cache.ts +44 -8
- package/src/audit/harm-report.ts +260 -0
- package/src/audit/machine-store.ts +120 -0
- package/src/audit/redact-example.ts +312 -0
- package/src/audit/report-harm.ts +167 -0
- package/src/audit/schedule-cli.ts +352 -0
- package/src/hooks/builtin-policies.ts +26 -0
- package/src/hooks/daemon-service.ts +76 -0
- package/src/hooks/fp-config.ts +96 -5
- package/src/hooks/fp-home.ts +118 -8
- package/src/hooks/fp-reset.ts +79 -9
- package/src/hooks/hook-telemetry.ts +3 -2
- package/src/hooks/migrations.ts +241 -4
- package/src/hooks/tui.ts +61 -3
- package/.next/standalone/.next/server/app/api/auth/reminder/route/app-paths-manifest.json +0 -3
- package/.next/standalone/.next/server/app/api/auth/reminder/route/build-manifest.json +0 -12
- package/.next/standalone/.next/server/app/api/auth/reminder/route/server-reference-manifest.json +0 -4
- package/.next/standalone/.next/server/app/api/auth/reminder/route.js +0 -9
- package/.next/standalone/.next/server/app/api/auth/reminder/route.js.map +0 -5
- package/.next/standalone/.next/server/app/api/auth/reminder/route.js.nft.json +0 -1
- package/.next/standalone/.next/server/app/api/auth/reminder/route_client-reference-manifest.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0-xggru._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__00ds05_._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__094p1f1._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1dxagv_._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1fgqj1_._.js +0 -3
- package/.next/standalone/.next/server/chunks/_084toou._.js +0 -3
- package/.next/standalone/.next/server/chunks/_0g4t8c9._.js +0 -3
- package/.next/standalone/.next/server/chunks/_0km521a._.js +0 -3
- package/.next/standalone/.next/server/chunks/_0t8kefc._.js +0 -3
- package/.next/standalone/.next/server/chunks/_16dwkfn._.js +0 -3
- package/.next/standalone/.next/server/chunks/_1phm9ui._.js +0 -3
- package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_auth_reminder_route_actions_1kjgxf8.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0dk8r_l._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0kviq2m._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ogyhu0._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1-rfu32._.js +0 -5
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1mmefsr._.js +0 -5
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1t62w37._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_032wo7w._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_08840em._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_0gl2ujp._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_0j0ggkc._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_0kbv5-q._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_0r1jgvp._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_0t5xq1b._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_0w_be0g._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_15gba46._.js +0 -5
- package/.next/standalone/.next/server/chunks/ssr/_1qyhb9r._.js +0 -23
- package/.next/standalone/.next/server/chunks/ssr/_1vel2ey._.js +0 -3
- package/.next/standalone/.next/static/chunks/0wd503tv801gy.js +0 -1
- package/.next/standalone/.next/static/chunks/1v1gqvpjk62jm.js +0 -1
- package/.next/standalone/.next/static/chunks/2uvhw57mf9lg_.css +0 -2
- package/.next/standalone/.next/static/chunks/2ynl0-6aqng_b.js +0 -1
- package/.next/standalone/app/api/auth/reminder/route.ts +0 -213
- /package/.next/standalone/.next/static/{Aulh3DRWwRfwh2POCvZR_ → zMC0Yqypg3GF82-3KN6ul}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{Aulh3DRWwRfwh2POCvZR_ → zMC0Yqypg3GF82-3KN6ul}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{Aulh3DRWwRfwh2POCvZR_ → zMC0Yqypg3GF82-3KN6ul}/_ssgManifest.js +0 -0
package/dist/worker.mjs
CHANGED
|
@@ -370,7 +370,7 @@ function failproofaiHome(home) {
|
|
|
370
370
|
return resolve(home, ".failproofai");
|
|
371
371
|
return process.env.FAILPROOFAI_HOME || resolve(homedir(), ".failproofai");
|
|
372
372
|
}
|
|
373
|
-
var LAYOUT_VERSION =
|
|
373
|
+
var LAYOUT_VERSION = 4, at = (...parts) => resolve(failproofaiHome(), ...parts), atHome = (home, ...parts) => home ? resolve(failproofaiHome(home), ...parts) : at(...parts), versionFile = (home) => atHome(home, "VERSION"), configFile = (home) => atHome(home, "config.json"), policiesDir = (home) => atHome(home, "policies"), customPoliciesDir, globalPolicyConfigFile = (home) => atHome(home, "policies-config.json"), cloudPoliciesDir = (home) => resolve(policiesDir(home), "cloud-policies"), hookActivityDir = (home) => atHome(home, "hook-activity"), stateDir = (home) => atHome(home, "state"), shimsDir = (home) => resolve(stateDir(home), "shims"), sessionPauseDir = () => resolve(stateDir(), "sessions"), telemetryIdFile = (home) => resolve(stateDir(home), "telemetry-id"), codexSessionPathsFile = (home) => resolve(stateDir(home), "codex-session-paths.json"), logsDir = (home) => atHome(home, "logs"), legacy;
|
|
374
374
|
var init_fp_home = __esm(() => {
|
|
375
375
|
customPoliciesDir = policiesDir;
|
|
376
376
|
legacy = {
|
|
@@ -386,6 +386,10 @@ var init_fp_home = __esm(() => {
|
|
|
386
386
|
launcherMarker: () => at(".launcher-configured"),
|
|
387
387
|
lastVersion: () => at("last-version"),
|
|
388
388
|
auditDashboard: () => at("audit-dashboard.json"),
|
|
389
|
+
authJson: () => at("auth.json"),
|
|
390
|
+
nextAudit: () => at("next-audit.json"),
|
|
391
|
+
auditReminder: () => at("audit", "reminder.json"),
|
|
392
|
+
auditSchedule: () => at("state", "audit-schedule.json"),
|
|
389
393
|
cacheDir: () => at("cache"),
|
|
390
394
|
hookActivityDir: () => at("cache", "hook-activity"),
|
|
391
395
|
auditCacheDir: () => at("cache", "audit"),
|
|
@@ -1831,7 +1835,7 @@ function registerBuiltinPolicies(enabledNames) {
|
|
|
1831
1835
|
}
|
|
1832
1836
|
}
|
|
1833
1837
|
}
|
|
1834
|
-
var isClaudeInternalPath, isClaudeSettingsFile, SHELL_OPERATORS, SHELL_METACHAR_RE, JWT_RE, API_KEY_PATTERNS, CONNECTION_STRING_RE, PRIVATE_KEY_RE, BEARER_TOKEN_RE, SQL_TOOL_RE, DESTRUCTIVE_SQL_RE, DELETE_NO_WHERE_RE, SQL_WHERE_RE, SCHEMA_ALTER_RE, PUBLISH_CMD_RE, ENV_PRINTENV_RE, ECHO_ENV_RE, EXPORT_RE, PS_ENV_VAR_RE, PS_CHILDITEM_ENV_RE, DOTNET_GETENV_RE, CMD_ECHO_ENV_RE, ENV_FILE_PATH_RE, ENV_CMD_RE, PS_ELEVATION_RE, RUNAS_RE, CURL_PIPE_SH_RE, SEGMENT_SEPARATORS, COMMAND_PREFIX_TOKENS, SELF_BINARY_TOKEN_RE, CONFIG_SUBCOMMAND_RE, PAUSE_FLAG_RE, ENV_ASSIGNMENT_RE, RUNNER_OPERAND_RE, PS_WEB_PIPE_RE, SHORT_FLAG_BUNDLE_RE, SAFE_FORCE_PREFIXES, SECRET_FILE_RE, SECRET_FILE_ID_RSA_RE, SECRET_FILE_CREDENTIALS_RE, GIT_COMMIT_MERGE_RE, FAILPROOFAI_CLI_RE, FAILPROOFAI_UNINSTALL_RE, GIT_AMEND_RE, GIT_STASH_DROP_RE, GIT_ADD_ALL_RE, NPM_GLOBAL_RE, YARN_GLOBAL_RE, PNPM_GLOBAL_RE, BUN_GLOBAL_RE, CARGO_INSTALL_RE, PIP_SYSTEM_RE, PKG_MANAGER_DETECTORS, NOHUP_RE, SCREEN_DETACH_RE, TMUX_DETACH_RE, DISOWN_RE, BACKGROUND_AMPERSAND_RE, KUBECTL_RE, TERRAFORM_RE, AWS_CLI_RE, GCLOUD_RE, AZ_CLI_RE, HELM_RE, GH_PIPELINE_RE, gitBranchCache, GIT_BRANCH_CACHE_MAX_ENTRIES = 500, EVAL_FLAG_RE, HOME_PREFIX_RE, RM_CMD_RE, FIND_CMD_RE, FIND_EXEC_RE, FIND_GLOBAL_OPT_RE, FIND_EXPR_START_RE, SCRATCH_ROOTS, CATASTROPHIC_DEPTH = 2, READ_LIKE_CMDS, TOOL_CALL_TRACKER_MAX_BYTES = 65536, SEGMENT_SPLIT_RE, BUILTIN_POLICIES;
|
|
1838
|
+
var isClaudeInternalPath, isClaudeSettingsFile, SHELL_OPERATORS, SHELL_METACHAR_RE, JWT_RE, API_KEY_PATTERNS, CONNECTION_STRING_RE, PRIVATE_KEY_RE, BEARER_TOKEN_RE, SECRET_PATTERNS, SQL_TOOL_RE, DESTRUCTIVE_SQL_RE, DELETE_NO_WHERE_RE, SQL_WHERE_RE, SCHEMA_ALTER_RE, PUBLISH_CMD_RE, ENV_PRINTENV_RE, ECHO_ENV_RE, EXPORT_RE, PS_ENV_VAR_RE, PS_CHILDITEM_ENV_RE, DOTNET_GETENV_RE, CMD_ECHO_ENV_RE, ENV_FILE_PATH_RE, ENV_CMD_RE, PS_ELEVATION_RE, RUNAS_RE, CURL_PIPE_SH_RE, SEGMENT_SEPARATORS, COMMAND_PREFIX_TOKENS, SELF_BINARY_TOKEN_RE, CONFIG_SUBCOMMAND_RE, PAUSE_FLAG_RE, ENV_ASSIGNMENT_RE, RUNNER_OPERAND_RE, PS_WEB_PIPE_RE, SHORT_FLAG_BUNDLE_RE, SAFE_FORCE_PREFIXES, SECRET_FILE_RE, SECRET_FILE_ID_RSA_RE, SECRET_FILE_CREDENTIALS_RE, GIT_COMMIT_MERGE_RE, FAILPROOFAI_CLI_RE, FAILPROOFAI_UNINSTALL_RE, GIT_AMEND_RE, GIT_STASH_DROP_RE, GIT_ADD_ALL_RE, NPM_GLOBAL_RE, YARN_GLOBAL_RE, PNPM_GLOBAL_RE, BUN_GLOBAL_RE, CARGO_INSTALL_RE, PIP_SYSTEM_RE, PKG_MANAGER_DETECTORS, NOHUP_RE, SCREEN_DETACH_RE, TMUX_DETACH_RE, DISOWN_RE, BACKGROUND_AMPERSAND_RE, KUBECTL_RE, TERRAFORM_RE, AWS_CLI_RE, GCLOUD_RE, AZ_CLI_RE, HELM_RE, GH_PIPELINE_RE, gitBranchCache, GIT_BRANCH_CACHE_MAX_ENTRIES = 500, EVAL_FLAG_RE, HOME_PREFIX_RE, RM_CMD_RE, FIND_CMD_RE, FIND_EXEC_RE, FIND_GLOBAL_OPT_RE, FIND_EXPR_START_RE, SCRATCH_ROOTS, CATASTROPHIC_DEPTH = 2, READ_LIKE_CMDS, TOOL_CALL_TRACKER_MAX_BYTES = 65536, SEGMENT_SPLIT_RE, BUILTIN_POLICIES;
|
|
1835
1839
|
var init_builtin_policies = __esm(() => {
|
|
1836
1840
|
init_hook_logger();
|
|
1837
1841
|
isClaudeInternalPath = isAgentInternalPath;
|
|
@@ -1853,6 +1857,13 @@ var init_builtin_policies = __esm(() => {
|
|
|
1853
1857
|
CONNECTION_STRING_RE = /(?:postgresql|postgres|mysql|mongodb(?:\+srv)?|redis|amqps?|smtps?):\/\/[^@\s]+@/;
|
|
1854
1858
|
PRIVATE_KEY_RE = /-----BEGIN (?:[A-Z]+ )?PRIVATE KEY-----/;
|
|
1855
1859
|
BEARER_TOKEN_RE = /Authorization:\s*Bearer\s+[A-Za-z0-9\-._~+/]{20,}/i;
|
|
1860
|
+
SECRET_PATTERNS = [
|
|
1861
|
+
[PRIVATE_KEY_RE, "private key"],
|
|
1862
|
+
[JWT_RE, "JWT"],
|
|
1863
|
+
[BEARER_TOKEN_RE, "bearer token"],
|
|
1864
|
+
[CONNECTION_STRING_RE, "database credentials"],
|
|
1865
|
+
...API_KEY_PATTERNS
|
|
1866
|
+
];
|
|
1856
1867
|
SQL_TOOL_RE = /\b(?:psql|mysql|sqlite3|pgcli|clickhouse-client)\b/;
|
|
1857
1868
|
DESTRUCTIVE_SQL_RE = /\b(?:DROP\s+(?:TABLE|DATABASE|SCHEMA)|TRUNCATE\b)/i;
|
|
1858
1869
|
DELETE_NO_WHERE_RE = /\bDELETE\s+FROM\b/i;
|
|
@@ -2511,7 +2522,7 @@ var init_builtin_policies = __esm(() => {
|
|
|
2511
2522
|
});
|
|
2512
2523
|
|
|
2513
2524
|
// package.json
|
|
2514
|
-
var version = "1.0.
|
|
2525
|
+
var version = "1.0.1-beta.1";
|
|
2515
2526
|
var init_package = () => {};
|
|
2516
2527
|
|
|
2517
2528
|
// src/posthog-key.ts
|
|
@@ -2527,10 +2538,17 @@ function detectLayout() {
|
|
|
2527
2538
|
return raw.layout > LAYOUT_VERSION ? { kind: "future", found: raw.layout } : { kind: "stale", found: raw.layout };
|
|
2528
2539
|
}
|
|
2529
2540
|
if (existsSync3(configFile())) {
|
|
2541
|
+
const layoutThreePositions = [
|
|
2542
|
+
legacy.authJson(),
|
|
2543
|
+
legacy.nextAudit(),
|
|
2544
|
+
legacy.auditSchedule()
|
|
2545
|
+
];
|
|
2546
|
+
if (layoutThreePositions.some((p) => existsSync3(p)))
|
|
2547
|
+
return { kind: "stale", found: 3 };
|
|
2530
2548
|
return { kind: "current", version: { layout: LAYOUT_VERSION, cli: "" }, inferred: true };
|
|
2531
2549
|
}
|
|
2532
2550
|
if (existsSync3(legacy.configToml()))
|
|
2533
|
-
return { kind: "stale", found:
|
|
2551
|
+
return { kind: "stale", found: 2 };
|
|
2534
2552
|
const layoutOneMarkers = [
|
|
2535
2553
|
legacy.policyConfig(),
|
|
2536
2554
|
legacy.cacheDir(),
|
|
@@ -2622,7 +2640,11 @@ function projectConfig(parsed) {
|
|
|
2622
2640
|
sources: readSources(collector.sources)
|
|
2623
2641
|
},
|
|
2624
2642
|
telemetry: { enabled: telemetry.enabled !== false },
|
|
2625
|
-
audit: {
|
|
2643
|
+
audit: {
|
|
2644
|
+
auto: audit.auto === true,
|
|
2645
|
+
intervalDays: readIntervalDays(audit.interval_days),
|
|
2646
|
+
reportsConsentedAt: typeof audit.reports_consented_at === "number" && Number.isFinite(audit.reports_consented_at) ? audit.reports_consented_at : undefined
|
|
2647
|
+
}
|
|
2626
2648
|
};
|
|
2627
2649
|
}
|
|
2628
2650
|
}
|
|
@@ -107,7 +107,7 @@ async function parseError(res: Response): Promise<AuthApiError> {
|
|
|
107
107
|
return new AuthApiError(res.status, code, message, retryAfterSecs);
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
-
/** Hard cap on every auth/
|
|
110
|
+
/** Hard cap on every auth/report HTTP call. Without this, a wedged DNS
|
|
111
111
|
* resolver or a hung server keeps the CLI / dashboard route stuck forever. */
|
|
112
112
|
const REQUEST_TIMEOUT_MS = 10_000;
|
|
113
113
|
|
|
@@ -210,34 +210,6 @@ export async function fetchMe(accessToken: string): Promise<MeResponse> {
|
|
|
210
210
|
return getJson<MeResponse>("/v0/auth/me", accessToken);
|
|
211
211
|
}
|
|
212
212
|
|
|
213
|
-
export interface ServerReminder {
|
|
214
|
-
user_id: string;
|
|
215
|
-
email: string;
|
|
216
|
-
fire_at: number; // unix seconds
|
|
217
|
-
set_at: number; // unix seconds
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
export async function scheduleReminder(
|
|
221
|
-
accessToken: string,
|
|
222
|
-
body: { in_days?: number; at?: number },
|
|
223
|
-
): Promise<ServerReminder> {
|
|
224
|
-
const res = await postJson<{ reminder: ServerReminder }>(
|
|
225
|
-
"/v0/reminders",
|
|
226
|
-
body,
|
|
227
|
-
{ accessToken },
|
|
228
|
-
);
|
|
229
|
-
return res.reminder;
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
export async function cancelReminder(accessToken: string): Promise<void> {
|
|
233
|
-
const res = await fetchWithTimeout(`${getApiBase()}/v0/reminders`, {
|
|
234
|
-
method: "DELETE",
|
|
235
|
-
headers: { authorization: `Bearer ${accessToken}` },
|
|
236
|
-
});
|
|
237
|
-
if (res.status === 204 || res.ok) return;
|
|
238
|
-
throw await parseError(res);
|
|
239
|
-
}
|
|
240
|
-
|
|
241
213
|
export interface InviteSendResult {
|
|
242
214
|
/** Recipients that were dispatched successfully. */
|
|
243
215
|
sent: string[];
|
|
@@ -266,6 +238,56 @@ export async function sendInvites(
|
|
|
266
238
|
);
|
|
267
239
|
}
|
|
268
240
|
|
|
241
|
+
export interface AuditReportBody {
|
|
242
|
+
machine_id: string;
|
|
243
|
+
label?: string;
|
|
244
|
+
platform?: string;
|
|
245
|
+
window_from?: string;
|
|
246
|
+
window_to: string;
|
|
247
|
+
harmful: {
|
|
248
|
+
policy: string;
|
|
249
|
+
category: string;
|
|
250
|
+
title: string;
|
|
251
|
+
hits: number;
|
|
252
|
+
first_seen?: string;
|
|
253
|
+
last_seen?: string;
|
|
254
|
+
examples: string[];
|
|
255
|
+
}[];
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
export interface AuditReportResult {
|
|
259
|
+
report_id: string;
|
|
260
|
+
/** Whether this report produced an email. */
|
|
261
|
+
emailed: boolean;
|
|
262
|
+
/** `below_threshold`, `cooldown`, `send_failed`, or null when mail went out. */
|
|
263
|
+
reason: string | null;
|
|
264
|
+
/**
|
|
265
|
+
* Where the next window starts, per the SERVER.
|
|
266
|
+
*
|
|
267
|
+
* Persisted verbatim rather than computed locally. The server anchors it on
|
|
268
|
+
* the last DELIVERED digest, so a report held by the cooldown — or one whose
|
|
269
|
+
* send failed — correctly leaves the watermark where it was, and its findings
|
|
270
|
+
* turn up in the next digest instead of falling into a gap. A machine that
|
|
271
|
+
* lost `machine.json` also resyncs here rather than re-reporting from the
|
|
272
|
+
* beginning of time.
|
|
273
|
+
*/
|
|
274
|
+
next_window_from: string;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Submit one scheduled scan's harmful findings.
|
|
279
|
+
*
|
|
280
|
+
* Called only by the audit child, and only on `--scheduled`. The destination
|
|
281
|
+
* address is never sent: the api-server takes it from the access-token claims,
|
|
282
|
+
* so a report cannot name where its digest goes.
|
|
283
|
+
*/
|
|
284
|
+
export async function submitAuditReport(
|
|
285
|
+
accessToken: string,
|
|
286
|
+
body: AuditReportBody,
|
|
287
|
+
): Promise<AuditReportResult> {
|
|
288
|
+
return postJson<AuditReportResult>("/v0/audit-reports", body, { accessToken });
|
|
289
|
+
}
|
|
290
|
+
|
|
269
291
|
interface JwtClaims {
|
|
270
292
|
sub: string;
|
|
271
293
|
email: string;
|
package/lib/auth/auth-store.ts
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Persistence layer for the
|
|
2
|
+
* Persistence layer for the signed-in session.
|
|
3
3
|
*
|
|
4
|
-
* Tokens live at
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Tokens live at `~/.failproofai/audit/session.json` with mode 0600 (layout 4;
|
|
5
|
+
* `auth.json` at the home root before that). The dashboard's Next.js API routes
|
|
6
|
+
* and the audit child both read and write through here, so a session survives
|
|
7
|
+
* across dashboard runs and is the same one a scheduled report uses.
|
|
7
8
|
*/
|
|
8
9
|
|
|
9
|
-
import { existsSync, readFileSync, rmSync } from "node:fs";
|
|
10
|
-
import { join } from "node:path";
|
|
10
|
+
import { existsSync, readFileSync, readdirSync, rmSync } from "node:fs";
|
|
11
|
+
import { join, resolve } from "node:path";
|
|
11
12
|
|
|
12
13
|
import { writeJsonAtomically } from "../atomic-write";
|
|
13
|
-
import {
|
|
14
|
+
import { auditDir, auditSessionFile, migrationsDir } from "../../src/hooks/fp-home";
|
|
14
15
|
import {
|
|
15
16
|
AuthApiError,
|
|
16
17
|
decodeJwt,
|
|
@@ -27,62 +28,24 @@ export interface StoredAuth {
|
|
|
27
28
|
user: { id: string; email: string };
|
|
28
29
|
}
|
|
29
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Where the session file lives.
|
|
33
|
+
*
|
|
34
|
+
* `FAILPROOFAI_AUTH_DIR` overrides it OUTRIGHT — the override names the
|
|
35
|
+
* directory the two files sit in directly, with no `audit/` beneath it, which is
|
|
36
|
+
* the contract it has always had and what every test using it expects. Without
|
|
37
|
+
* the override the paths come from `fp-home.ts`, which as of layout 4 puts them
|
|
38
|
+
* under `audit/` with the rest of what the audit owns.
|
|
39
|
+
*/
|
|
30
40
|
export function getAuthDir(): string {
|
|
31
41
|
const override = process.env.FAILPROOFAI_AUTH_DIR;
|
|
32
42
|
if (override) return override;
|
|
33
|
-
return
|
|
43
|
+
return auditDir();
|
|
34
44
|
}
|
|
35
45
|
|
|
36
46
|
export function getAuthFilePath(): string {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
/** Location of the persisted re-audit reminder (separate from auth.json so
|
|
41
|
-
* the reminder survives unrelated session refreshes). */
|
|
42
|
-
export function getReminderFilePath(): string {
|
|
43
|
-
return join(getAuthDir(), "next-audit.json");
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export interface StoredReminder {
|
|
47
|
-
/** Unix seconds. */
|
|
48
|
-
next_audit_at: number;
|
|
49
|
-
/** Email the reminder was set for. Used to invalidate the reminder if the
|
|
50
|
-
* active session belongs to a different user. */
|
|
51
|
-
user_email: string;
|
|
52
|
-
/** Unix seconds. */
|
|
53
|
-
set_at: number;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export function readReminder(): StoredReminder | null {
|
|
57
|
-
const p = getReminderFilePath();
|
|
58
|
-
if (!existsSync(p)) return null;
|
|
59
|
-
try {
|
|
60
|
-
const raw = readFileSync(p, "utf-8");
|
|
61
|
-
const parsed = JSON.parse(raw) as Partial<StoredReminder>;
|
|
62
|
-
if (
|
|
63
|
-
typeof parsed.next_audit_at !== "number" ||
|
|
64
|
-
typeof parsed.user_email !== "string" ||
|
|
65
|
-
typeof parsed.set_at !== "number"
|
|
66
|
-
) {
|
|
67
|
-
return null;
|
|
68
|
-
}
|
|
69
|
-
return {
|
|
70
|
-
next_audit_at: parsed.next_audit_at,
|
|
71
|
-
user_email: parsed.user_email,
|
|
72
|
-
set_at: parsed.set_at,
|
|
73
|
-
};
|
|
74
|
-
} catch {
|
|
75
|
-
return null;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
export function writeReminder(reminder: StoredReminder): void {
|
|
80
|
-
writeJsonAtomically(getReminderFilePath(), reminder);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
export function deleteReminder(): void {
|
|
84
|
-
const p = getReminderFilePath();
|
|
85
|
-
if (existsSync(p)) rmSync(p, { force: true });
|
|
47
|
+
const override = process.env.FAILPROOFAI_AUTH_DIR;
|
|
48
|
+
return override ? join(override, "session.json") : auditSessionFile();
|
|
86
49
|
}
|
|
87
50
|
|
|
88
51
|
export function readAuth(): StoredAuth | null {
|
|
@@ -127,6 +90,28 @@ export function writeAuth(auth: StoredAuth): void {
|
|
|
127
90
|
export function deleteAuth(): void {
|
|
128
91
|
const p = getAuthFilePath();
|
|
129
92
|
if (existsSync(p)) rmSync(p, { force: true });
|
|
93
|
+
|
|
94
|
+
// Also any copy a migration took and could not clean up.
|
|
95
|
+
//
|
|
96
|
+
// The layout-4 step backs `auth.json` up before moving it, and a chain that
|
|
97
|
+
// FAILED deliberately keeps that copy — it is the only insurance against a
|
|
98
|
+
// half-moved credential. But "sign me out" has to mean the token is off this
|
|
99
|
+
// machine, and `migrationsDir` is classed `identity`, so nothing else will
|
|
100
|
+
// ever remove it: without this sweep a dashboard sign-out, a 401 auto-delete
|
|
101
|
+
// and `failproofai reset` all left a live bearer and refresh token on disk,
|
|
102
|
+
// to be carried into every dotfile backup and container image after it.
|
|
103
|
+
try {
|
|
104
|
+
const root = migrationsDir();
|
|
105
|
+
if (!existsSync(root)) return;
|
|
106
|
+
for (const entry of readdirSync(root)) {
|
|
107
|
+
if (!entry.startsWith("backup-layout")) continue;
|
|
108
|
+
const copy = resolve(root, entry, "auth.json");
|
|
109
|
+
if (existsSync(copy)) rmSync(copy, { force: true });
|
|
110
|
+
}
|
|
111
|
+
} catch {
|
|
112
|
+
// Sign-out must succeed even if the sweep cannot. The live token — the one
|
|
113
|
+
// that actually authenticates a request — is already gone above.
|
|
114
|
+
}
|
|
130
115
|
}
|
|
131
116
|
|
|
132
117
|
/** Convert verify/refresh response into the on-disk shape. */
|
|
@@ -161,8 +146,8 @@ const REFRESH_LEEWAY_SECS = 60;
|
|
|
161
146
|
|
|
162
147
|
/**
|
|
163
148
|
* In-flight refresh dedup. Without this, two concurrent callers (e.g.
|
|
164
|
-
* the dashboard's `/api/auth/status` poll and a
|
|
165
|
-
*
|
|
149
|
+
* the dashboard's `/api/auth/status` poll and a scheduled audit's report
|
|
150
|
+
* in flight) both observe the same expired access token, both call
|
|
166
151
|
* `refreshAccessToken(auth.refresh_token)` with the same refresh token,
|
|
167
152
|
* and the api-server treats the second call as token-replay and revokes
|
|
168
153
|
* every session for that user — a silent logout. Keying on the refresh
|
package/lib/telemetry.ts
CHANGED
|
@@ -38,41 +38,6 @@ interface PostHogOptions {
|
|
|
38
38
|
requestTimeout?: number;
|
|
39
39
|
fetchRetryCount?: number;
|
|
40
40
|
fetchRetryDelay?: number;
|
|
41
|
-
fetch?: (url: string, options: Record<string, unknown>) => Promise<Response>;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Wraps native fetch with retry logic and silent failure for non-critical telemetry.
|
|
46
|
-
* Prevents posthog-node's internal console.error from firing on network errors.
|
|
47
|
-
*/
|
|
48
|
-
async function resilientFetch(
|
|
49
|
-
url: string,
|
|
50
|
-
options: Record<string, unknown>,
|
|
51
|
-
): Promise<Response> {
|
|
52
|
-
const MAX_ATTEMPTS = 5;
|
|
53
|
-
const BASE_DELAY_MS = 1000;
|
|
54
|
-
const TIMEOUT_MS = 5000;
|
|
55
|
-
|
|
56
|
-
for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {
|
|
57
|
-
try {
|
|
58
|
-
const { signal: _, ...rest } = options;
|
|
59
|
-
const res = await fetch(url, {
|
|
60
|
-
...(rest as RequestInit),
|
|
61
|
-
signal: AbortSignal.timeout(TIMEOUT_MS),
|
|
62
|
-
});
|
|
63
|
-
if (res.ok) return res;
|
|
64
|
-
// Non-2xx (e.g. 502) — treat like a transient failure and retry
|
|
65
|
-
} catch {
|
|
66
|
-
// Network error (ETIMEDOUT, etc.) — retry
|
|
67
|
-
}
|
|
68
|
-
if (attempt < MAX_ATTEMPTS) {
|
|
69
|
-
const delay = Math.min(BASE_DELAY_MS * 2 ** (attempt - 1), 8000);
|
|
70
|
-
await new Promise((r) => setTimeout(r, delay));
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
// All attempts failed — return fake OK so PostHog doesn't log errors.
|
|
74
|
-
// This is anonymous telemetry; silently dropping events is acceptable.
|
|
75
|
-
return new Response("{}", { status: 200 });
|
|
76
41
|
}
|
|
77
42
|
|
|
78
43
|
/**
|
|
@@ -101,17 +66,57 @@ export async function initTelemetry(): Promise<void> {
|
|
|
101
66
|
await import("posthog-node");
|
|
102
67
|
const apiKey = process.env.FAILPROOFAI_POSTHOG_KEY ?? DEFAULT_API_KEY;
|
|
103
68
|
const host = process.env.FAILPROOFAI_POSTHOG_HOST ?? DEFAULT_HOST;
|
|
69
|
+
// Delivery-critical options. Every one of these was previously set to a
|
|
70
|
+
// value that lost events; see __tests__/lib/telemetry-delivery.test.ts,
|
|
71
|
+
// which pins the contract against the REAL library rather than a mock.
|
|
72
|
+
//
|
|
73
|
+
// No custom `fetch`. There used to be a `resilientFetch` wrapper here that
|
|
74
|
+
// retried five times over ~40s and then returned a synthetic 200 so
|
|
75
|
+
// posthog-node would never log a network error. It could not work: the
|
|
76
|
+
// library does not merely hand its abort signal to an injected fetch, it
|
|
77
|
+
// *races* that fetch against its own `requestTimeout` deadline
|
|
78
|
+
// (`Promise.race([fetchPromise, deadline])`) precisely because an injected
|
|
79
|
+
// fetch may ignore the signal — which ours did, by stripping it. With a
|
|
80
|
+
// ~40s budget racing a 5s deadline the wrapper could never return in time,
|
|
81
|
+
// so the synthetic 200 was unreachable, the `console.error` it existed to
|
|
82
|
+
// prevent fired anyway, and its retries ran on detached from the client that
|
|
83
|
+
// had already given up. Plain global fetch is what the library expects.
|
|
84
|
+
//
|
|
85
|
+
// `fetchRetryCount` was 0, which disabled retries entirely and left the
|
|
86
|
+
// wrapper above as the only thing retrying — the wrong layer. The library
|
|
87
|
+
// retries inside a single flush, knows which errors are retryable, and
|
|
88
|
+
// keeps its queue coherent while doing it.
|
|
89
|
+
//
|
|
90
|
+
// `flushInterval` was 0, which is falsy and therefore disables the flush
|
|
91
|
+
// timer completely. That is the one that actually stranded events: on a
|
|
92
|
+
// network error posthog-node deliberately does NOT dequeue the batch (it
|
|
93
|
+
// treats the failure as transient and keeps it for a later attempt), so
|
|
94
|
+
// with no timer armed those retained events had nothing scheduled to
|
|
95
|
+
// resend them and sat in memory until an unrelated later event happened to
|
|
96
|
+
// trigger a flush.
|
|
97
|
+
//
|
|
98
|
+
// `flushAt: 1` is deliberate and stays. Volume here is a handful of events
|
|
99
|
+
// per process, so batching buys nothing, and posthog-node's queue is
|
|
100
|
+
// memory-only (`PostHogMemoryStorage`) — anything still queued when the
|
|
101
|
+
// process dies is gone. Sending immediately is the best available defense.
|
|
104
102
|
globalThis.__FAILPROOFAI_POSTHOG__ = new mod.PostHog(apiKey, {
|
|
105
103
|
host,
|
|
106
104
|
flushAt: 1,
|
|
107
|
-
flushInterval:
|
|
108
|
-
requestTimeout:
|
|
109
|
-
fetchRetryCount:
|
|
110
|
-
|
|
105
|
+
flushInterval: 10_000,
|
|
106
|
+
requestTimeout: 10_000,
|
|
107
|
+
fetchRetryCount: 3,
|
|
108
|
+
fetchRetryDelay: 3_000,
|
|
111
109
|
});
|
|
112
110
|
|
|
113
|
-
// Flush pending events when the process exits
|
|
111
|
+
// Flush pending events when the process exits. This drain is the last line
|
|
112
|
+
// of defense for the memory-only queue, so it must not fight itself:
|
|
113
|
+
// `beforeExit` re-fires every time a handler schedules more async work, and
|
|
114
|
+
// an unguarded handler starts a fresh `shutdown()` — each with its own 30s
|
|
115
|
+
// budget — on every one of those passes.
|
|
116
|
+
let draining = false;
|
|
114
117
|
const onExit = () => {
|
|
118
|
+
if (draining) return;
|
|
119
|
+
draining = true;
|
|
115
120
|
globalThis.__FAILPROOFAI_POSTHOG__?.shutdown().catch(() => {});
|
|
116
121
|
};
|
|
117
122
|
process.on("beforeExit", onExit);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "failproofai",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1-beta.1",
|
|
4
4
|
"description": "The easiest way to manage policies that keep your AI agents reliable, on-task, and running autonomously — for Claude Code & the Agents SDK",
|
|
5
5
|
"bin": {
|
|
6
6
|
"failproofai": "./dist/cli.mjs",
|
|
@@ -40,7 +40,8 @@
|
|
|
40
40
|
"translate:docs": "bun scripts/translate-docs/cli.ts --docs-only",
|
|
41
41
|
"translate:dry-run": "bun scripts/translate-docs/cli.ts --dry-run",
|
|
42
42
|
"translate:validate": "bun scripts/translate-docs/cli.ts --validate",
|
|
43
|
-
"validate:mdx": "bun scripts/validate-mdx.ts"
|
|
43
|
+
"validate:mdx": "bun scripts/validate-mdx.ts",
|
|
44
|
+
"docs:audit": "bun scripts/docs-audit.ts"
|
|
44
45
|
},
|
|
45
46
|
"keywords": [
|
|
46
47
|
"claude",
|
|
@@ -104,6 +105,7 @@
|
|
|
104
105
|
"yaml": "^2.9.0"
|
|
105
106
|
},
|
|
106
107
|
"overrides": {
|
|
108
|
+
"nanoid": "3.3.18",
|
|
107
109
|
"postcss": "8.5.26",
|
|
108
110
|
"eslint-plugin-react-hooks": "7.0.1",
|
|
109
111
|
"vite": "8.0.16",
|
|
@@ -112,15 +114,15 @@
|
|
|
112
114
|
"sharp": "0.35.0"
|
|
113
115
|
},
|
|
114
116
|
"optionalDependencies": {
|
|
115
|
-
"@failproofai/failproofaid-linux-x64": "1.0.
|
|
116
|
-
"@failproofai/failproofaid-linux-arm64": "1.0.
|
|
117
|
-
"@failproofai/failproofaid-darwin-x64": "1.0.
|
|
118
|
-
"@failproofai/failproofaid-darwin-arm64": "1.0.
|
|
117
|
+
"@failproofai/failproofaid-linux-x64": "1.0.1-beta.1",
|
|
118
|
+
"@failproofai/failproofaid-linux-arm64": "1.0.1-beta.1",
|
|
119
|
+
"@failproofai/failproofaid-darwin-x64": "1.0.1-beta.1",
|
|
120
|
+
"@failproofai/failproofaid-darwin-arm64": "1.0.1-beta.1"
|
|
119
121
|
},
|
|
120
122
|
"failproofaidBinaries": {
|
|
121
|
-
"linux-x64": "
|
|
122
|
-
"linux-arm64": "
|
|
123
|
-
"darwin-x64": "
|
|
124
|
-
"darwin-arm64": "
|
|
123
|
+
"linux-x64": "cf623441aa67363e423a1dba7db734d3e9243f0abff5e63a9ed7ddc096213e51",
|
|
124
|
+
"linux-arm64": "339281280ae8e60d03415da88a372ff4d3fb356c375f0e1f9eea17063233d52b",
|
|
125
|
+
"darwin-x64": "b972c37a9ca83b085d11d1312b3fa8487dead09dbc81e1e115000d2614051248",
|
|
126
|
+
"darwin-arm64": "597cbdae5f564fd0c7c917b2b0b94a91ba8465e568487da0d1cac0508b94cee5"
|
|
125
127
|
}
|
|
126
128
|
}
|