failproofai 1.0.0 → 1.0.1-beta.0
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 +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0g2rg69._.js +3 -0
- 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/_04j57fb._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_05enntk._.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/_1nq-35m._.js +23 -0
- package/.next/standalone/.next/server/chunks/ssr/_1q7j05x._.js +3 -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/00q6cfzuzpc85.js +1 -0
- package/.next/standalone/.next/static/chunks/{0zm3_8jpqitxy.js → 054eg7y_cjyf9.js} +22 -22
- package/.next/standalone/.next/static/chunks/{2ouq44jv_0x04.js → 0mjufa_0xxz75.js} +1 -1
- package/.next/standalone/.next/static/chunks/0u64yey446k4f.css +1 -0
- package/.next/standalone/.next/static/chunks/{0zi8zjav5a4rq.js → 1-oz4co31nvc5.js} +1 -1
- package/.next/standalone/.next/static/chunks/13--2yvqek_s1.js +1 -0
- package/.next/standalone/.next/static/chunks/136ldjmzxhush.js +1 -0
- package/.next/standalone/.next/static/chunks/18fqy3doo2ial.js +6 -0
- package/.next/standalone/.next/static/chunks/1eyl7fzkmnkf_.js +1 -0
- package/.next/standalone/.next/static/chunks/{31k3yxpy57_fy.js → 1o5sxp_mdaoci.js} +1 -1
- package/.next/standalone/.next/static/chunks/29-iqnp9v_axt.css +1 -0
- package/.next/standalone/.next/static/chunks/{2676v-lyzgo91.js → 2es4z1ei90vsv.js} +1 -1
- package/.next/standalone/.next/static/chunks/2k9f4tyv04809.css +1 -0
- package/.next/standalone/.next/static/chunks/3peix2vxzj7eh.js +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/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 +1889 -426
- package/dist/worker.mjs +27 -5
- package/lib/auth/api-server-client.ts +51 -29
- package/lib/auth/auth-store.ts +44 -59
- 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 +124 -6
- 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/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/1hfocb0sdl85c.js +0 -1
- package/.next/standalone/.next/static/chunks/1v1gqvpjk62jm.js +0 -1
- package/.next/standalone/.next/static/chunks/2kopjq_or743g.js +0 -6
- 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/.next/static/chunks/3xvtgz6arztp_.js +0 -1
- package/.next/standalone/app/api/auth/reminder/route.ts +0 -213
- /package/.next/standalone/.next/static/{Aulh3DRWwRfwh2POCvZR_ → jSKB7CQQSNTX-uSbY2bUs}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{Aulh3DRWwRfwh2POCvZR_ → jSKB7CQQSNTX-uSbY2bUs}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{Aulh3DRWwRfwh2POCvZR_ → jSKB7CQQSNTX-uSbY2bUs}/_ssgManifest.js +0 -0
package/dist/cli.mjs
CHANGED
|
@@ -19,7 +19,7 @@ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
|
19
19
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
20
20
|
|
|
21
21
|
// package.json
|
|
22
|
-
var version2 = "1.0.0", package_default;
|
|
22
|
+
var version2 = "1.0.1-beta.0", package_default;
|
|
23
23
|
var init_package = __esm(() => {
|
|
24
24
|
package_default = {
|
|
25
25
|
name: "failproofai",
|
|
@@ -63,7 +63,8 @@ var init_package = __esm(() => {
|
|
|
63
63
|
"translate:docs": "bun scripts/translate-docs/cli.ts --docs-only",
|
|
64
64
|
"translate:dry-run": "bun scripts/translate-docs/cli.ts --dry-run",
|
|
65
65
|
"translate:validate": "bun scripts/translate-docs/cli.ts --validate",
|
|
66
|
-
"validate:mdx": "bun scripts/validate-mdx.ts"
|
|
66
|
+
"validate:mdx": "bun scripts/validate-mdx.ts",
|
|
67
|
+
"docs:audit": "bun scripts/docs-audit.ts"
|
|
67
68
|
},
|
|
68
69
|
keywords: [
|
|
69
70
|
"claude",
|
|
@@ -127,6 +128,7 @@ var init_package = __esm(() => {
|
|
|
127
128
|
yaml: "^2.9.0"
|
|
128
129
|
},
|
|
129
130
|
overrides: {
|
|
131
|
+
nanoid: "3.3.18",
|
|
130
132
|
postcss: "8.5.26",
|
|
131
133
|
"eslint-plugin-react-hooks": "7.0.1",
|
|
132
134
|
vite: "8.0.16",
|
|
@@ -135,16 +137,16 @@ var init_package = __esm(() => {
|
|
|
135
137
|
sharp: "0.35.0"
|
|
136
138
|
},
|
|
137
139
|
optionalDependencies: {
|
|
138
|
-
"@failproofai/failproofaid-linux-x64": "1.0.0",
|
|
139
|
-
"@failproofai/failproofaid-linux-arm64": "1.0.0",
|
|
140
|
-
"@failproofai/failproofaid-darwin-x64": "1.0.0",
|
|
141
|
-
"@failproofai/failproofaid-darwin-arm64": "1.0.0"
|
|
140
|
+
"@failproofai/failproofaid-linux-x64": "1.0.1-beta.0",
|
|
141
|
+
"@failproofai/failproofaid-linux-arm64": "1.0.1-beta.0",
|
|
142
|
+
"@failproofai/failproofaid-darwin-x64": "1.0.1-beta.0",
|
|
143
|
+
"@failproofai/failproofaid-darwin-arm64": "1.0.1-beta.0"
|
|
142
144
|
},
|
|
143
145
|
failproofaidBinaries: {
|
|
144
|
-
"linux-x64": "
|
|
145
|
-
"linux-arm64": "
|
|
146
|
-
"darwin-x64": "
|
|
147
|
-
"darwin-arm64": "
|
|
146
|
+
"linux-x64": "8259a934de6ae1302e49a7e7d81e7caac533fa8437167fddc2a9b36d05745ce2",
|
|
147
|
+
"linux-arm64": "c9a4e90c94c23c78973ddb26740f39ab4d3368da5567cebe475e805049c158e9",
|
|
148
|
+
"darwin-x64": "cf0c70a0dab9f737a9ffde27b3ab3fb18ef159b851656ef778ed193a0a72a476",
|
|
149
|
+
"darwin-arm64": "f4d4e300339acc7557251a96500c24e8d675f934febc9d587560cf0544d3eef1"
|
|
148
150
|
}
|
|
149
151
|
};
|
|
150
152
|
});
|
|
@@ -175,6 +177,7 @@ function retiredLayoutPaths() {
|
|
|
175
177
|
legacy.lastVersion(),
|
|
176
178
|
legacy.auditDashboard(),
|
|
177
179
|
legacy.auditCacheDir(),
|
|
180
|
+
legacy.auditReminder(),
|
|
178
181
|
legacy.codexSessionPaths(),
|
|
179
182
|
legacy.spoolDir(),
|
|
180
183
|
legacy.failedDir(),
|
|
@@ -186,7 +189,7 @@ function retiredLayoutPaths() {
|
|
|
186
189
|
legacy.localPoliciesDir()
|
|
187
190
|
];
|
|
188
191
|
}
|
|
189
|
-
var LAYOUT_VERSION =
|
|
192
|
+
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"), credentialsFile = (home) => atHome(home, "credentials.json"), binDir = (home) => atHome(home, "bin"), policiesDir = (home) => atHome(home, "policies"), customPoliciesDir, globalPolicyConfigFile = (home) => atHome(home, "policies-config.json"), cloudPoliciesDir = (home) => resolve(policiesDir(home), "cloud-policies"), cursorsDir = (source, home) => source ? resolve(atHome(home, "cursors"), source) : atHome(home, "cursors"), customAgentsDir = (home) => atHome(home, "custom-agents"), auditDir = (home) => atHome(home, "audit"), auditDashboardFile = (home) => resolve(auditDir(home), "dashboard.json"), auditCacheDir = (home) => resolve(auditDir(home), "cache"), auditSessionFile = (home) => resolve(auditDir(home), "session.json"), auditMachineFile = (home) => resolve(auditDir(home), "machine.json"), hookActivityDir = (home) => atHome(home, "hook-activity"), runDir = (home) => atHome(home, "run"), daemonSocket = () => process.env.FAILPROOFAI_DAEMON_SOCKET || resolve(runDir(), "failproofaid.sock"), auditLockFile = (home) => resolve(runDir(home), "audit.lock"), stateDir = (home) => atHome(home, "state"), shimsDir = (home) => resolve(stateDir(home), "shims"), spoolDir = (home) => resolve(stateDir(home), "spool"), failedDir = (home) => resolve(stateDir(home), "failed"), collectorHealthFile = (home) => resolve(stateDir(home), "collector-health.json"), sessionPauseDir = () => resolve(stateDir(), "sessions"), auditScheduleFile = (home) => resolve(auditDir(home), "schedule.json"), telemetryIdFile = (home) => resolve(stateDir(home), "telemetry-id"), launcherMarker = (home) => resolve(stateDir(home), "launcher-configured"), onboardingAttemptFile = (home) => resolve(stateDir(home), "onboarding-attempt.json"), lastVersionFile = (home) => resolve(stateDir(home), "last-version"), onboardingLockFile = (home) => resolve(stateDir(home), "onboarding.lock"), codexSessionPathsFile = (home) => resolve(stateDir(home), "codex-session-paths.json"), logsDir = (home) => atHome(home, "logs"), migrationsDir = (home) => atHome(home, "migrations"), migrationLedgerFile = (home) => resolve(migrationsDir(home), "applied.json"), migrationBackupDir = (layout, home) => resolve(migrationsDir(home), `backup-layout${layout}`), HOME_CLASSES, legacy;
|
|
190
193
|
var init_fp_home = __esm(() => {
|
|
191
194
|
customPoliciesDir = policiesDir;
|
|
192
195
|
HOME_CLASSES = [
|
|
@@ -194,6 +197,7 @@ var init_fp_home = __esm(() => {
|
|
|
194
197
|
{ path: configFile, class: "user-typed" },
|
|
195
198
|
{ path: globalPolicyConfigFile, class: "user-typed" },
|
|
196
199
|
{ path: policiesDir, class: "user-typed" },
|
|
200
|
+
{ path: auditSessionFile, class: "user-typed" },
|
|
197
201
|
{ path: spoolDir, class: "undelivered" },
|
|
198
202
|
{ path: failedDir, class: "undelivered" },
|
|
199
203
|
{ path: customAgentsDir, class: "undelivered" },
|
|
@@ -205,9 +209,11 @@ var init_fp_home = __esm(() => {
|
|
|
205
209
|
{ path: (home) => resolve(stateDir(home), "daemon-telemetry-id"), class: "identity" },
|
|
206
210
|
{ path: versionFile, class: "identity" },
|
|
207
211
|
{ path: migrationsDir, class: "identity" },
|
|
208
|
-
{ path:
|
|
209
|
-
{ path:
|
|
212
|
+
{ path: auditMachineFile, class: "identity" },
|
|
213
|
+
{ path: auditDashboardFile, class: "derived" },
|
|
214
|
+
{ path: auditCacheDir, class: "derived" },
|
|
210
215
|
{ path: auditScheduleFile, class: "derived" },
|
|
216
|
+
{ path: collectorHealthFile, class: "derived" },
|
|
211
217
|
{ path: codexSessionPathsFile, class: "derived" },
|
|
212
218
|
{ path: shimsDir, class: "derived" },
|
|
213
219
|
{ path: sessionPauseDir, class: "derived" },
|
|
@@ -233,6 +239,10 @@ var init_fp_home = __esm(() => {
|
|
|
233
239
|
launcherMarker: () => at(".launcher-configured"),
|
|
234
240
|
lastVersion: () => at("last-version"),
|
|
235
241
|
auditDashboard: () => at("audit-dashboard.json"),
|
|
242
|
+
authJson: () => at("auth.json"),
|
|
243
|
+
nextAudit: () => at("next-audit.json"),
|
|
244
|
+
auditReminder: () => at("audit", "reminder.json"),
|
|
245
|
+
auditSchedule: () => at("state", "audit-schedule.json"),
|
|
236
246
|
cacheDir: () => at("cache"),
|
|
237
247
|
hookActivityDir: () => at("cache", "hook-activity"),
|
|
238
248
|
auditCacheDir: () => at("cache", "audit"),
|
|
@@ -257,10 +267,17 @@ function detectLayout() {
|
|
|
257
267
|
return raw.layout > LAYOUT_VERSION ? { kind: "future", found: raw.layout } : { kind: "stale", found: raw.layout };
|
|
258
268
|
}
|
|
259
269
|
if (existsSync(configFile())) {
|
|
270
|
+
const layoutThreePositions = [
|
|
271
|
+
legacy.authJson(),
|
|
272
|
+
legacy.nextAudit(),
|
|
273
|
+
legacy.auditSchedule()
|
|
274
|
+
];
|
|
275
|
+
if (layoutThreePositions.some((p) => existsSync(p)))
|
|
276
|
+
return { kind: "stale", found: 3 };
|
|
260
277
|
return { kind: "current", version: { layout: LAYOUT_VERSION, cli: "" }, inferred: true };
|
|
261
278
|
}
|
|
262
279
|
if (existsSync(legacy.configToml()))
|
|
263
|
-
return { kind: "stale", found:
|
|
280
|
+
return { kind: "stale", found: 2 };
|
|
264
281
|
const layoutOneMarkers = [
|
|
265
282
|
legacy.policyConfig(),
|
|
266
283
|
legacy.cacheDir(),
|
|
@@ -303,7 +320,7 @@ function readVersionFile() {
|
|
|
303
320
|
function writeVersionFile(v = {}) {
|
|
304
321
|
const existing = readVersionFile();
|
|
305
322
|
const next = {
|
|
306
|
-
layout: LAYOUT_VERSION,
|
|
323
|
+
layout: v.layout ?? LAYOUT_VERSION,
|
|
307
324
|
cli: v.cli ?? version2,
|
|
308
325
|
daemon: v.clearDaemon ? undefined : v.daemon ?? existing?.daemon
|
|
309
326
|
};
|
|
@@ -372,7 +389,11 @@ function projectConfig(parsed) {
|
|
|
372
389
|
sources: readSources(collector.sources)
|
|
373
390
|
},
|
|
374
391
|
telemetry: { enabled: telemetry.enabled !== false },
|
|
375
|
-
audit: {
|
|
392
|
+
audit: {
|
|
393
|
+
auto: audit.auto === true,
|
|
394
|
+
intervalDays: readIntervalDays(audit.interval_days),
|
|
395
|
+
reportsConsentedAt: typeof audit.reports_consented_at === "number" && Number.isFinite(audit.reports_consented_at) ? audit.reports_consented_at : undefined
|
|
396
|
+
}
|
|
376
397
|
};
|
|
377
398
|
}
|
|
378
399
|
}
|
|
@@ -421,7 +442,11 @@ function writeConfig(config, raw) {
|
|
|
421
442
|
} : {}
|
|
422
443
|
},
|
|
423
444
|
...config.telemetry.enabled ? {} : { telemetry: { enabled: false } },
|
|
424
|
-
audit: {
|
|
445
|
+
audit: {
|
|
446
|
+
auto: config.audit.auto,
|
|
447
|
+
interval_days: config.audit.intervalDays,
|
|
448
|
+
...config.audit.reportsConsentedAt === undefined ? {} : { reports_consented_at: config.audit.reportsConsentedAt }
|
|
449
|
+
}
|
|
425
450
|
};
|
|
426
451
|
const merged = structuredClone(raw ?? readConfigRaw().raw);
|
|
427
452
|
for (const path of OWNED_CONFIG_KEYS)
|
|
@@ -567,7 +592,8 @@ var init_fp_config = __esm(() => {
|
|
|
567
592
|
["collector", "sources", "*", "extra_paths"],
|
|
568
593
|
["telemetry", "enabled"],
|
|
569
594
|
["audit", "auto"],
|
|
570
|
-
["audit", "interval_days"]
|
|
595
|
+
["audit", "interval_days"],
|
|
596
|
+
["audit", "reports_consented_at"]
|
|
571
597
|
];
|
|
572
598
|
OWNED_CREDENTIAL_KEYS = [
|
|
573
599
|
["cloud", "url"],
|
|
@@ -2910,7 +2936,7 @@ function registerBuiltinPolicies(enabledNames) {
|
|
|
2910
2936
|
}
|
|
2911
2937
|
}
|
|
2912
2938
|
}
|
|
2913
|
-
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;
|
|
2939
|
+
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;
|
|
2914
2940
|
var init_builtin_policies = __esm(() => {
|
|
2915
2941
|
init_hook_logger();
|
|
2916
2942
|
isClaudeInternalPath = isAgentInternalPath;
|
|
@@ -2932,6 +2958,13 @@ var init_builtin_policies = __esm(() => {
|
|
|
2932
2958
|
CONNECTION_STRING_RE = /(?:postgresql|postgres|mysql|mongodb(?:\+srv)?|redis|amqps?|smtps?):\/\/[^@\s]+@/;
|
|
2933
2959
|
PRIVATE_KEY_RE = /-----BEGIN (?:[A-Z]+ )?PRIVATE KEY-----/;
|
|
2934
2960
|
BEARER_TOKEN_RE = /Authorization:\s*Bearer\s+[A-Za-z0-9\-._~+/]{20,}/i;
|
|
2961
|
+
SECRET_PATTERNS = [
|
|
2962
|
+
[PRIVATE_KEY_RE, "private key"],
|
|
2963
|
+
[JWT_RE, "JWT"],
|
|
2964
|
+
[BEARER_TOKEN_RE, "bearer token"],
|
|
2965
|
+
[CONNECTION_STRING_RE, "database credentials"],
|
|
2966
|
+
...API_KEY_PATTERNS
|
|
2967
|
+
];
|
|
2935
2968
|
SQL_TOOL_RE = /\b(?:psql|mysql|sqlite3|pgcli|clickhouse-client)\b/;
|
|
2936
2969
|
DESTRUCTIVE_SQL_RE = /\b(?:DROP\s+(?:TABLE|DATABASE|SCHEMA)|TRUNCATE\b)/i;
|
|
2937
2970
|
DELETE_NO_WHERE_RE = /\bDELETE\s+FROM\b/i;
|
|
@@ -11432,7 +11465,7 @@ function readCarriedLegacyCredentials() {
|
|
|
11432
11465
|
const creds = projectCredentials(raw);
|
|
11433
11466
|
return Object.keys(creds).length > 0 ? creds : null;
|
|
11434
11467
|
}
|
|
11435
|
-
function resetHome(from) {
|
|
11468
|
+
function resetHome(from, to = LAYOUT_VERSION) {
|
|
11436
11469
|
const migrated = migrateConventionPolicies();
|
|
11437
11470
|
const activity = migrateHookActivity();
|
|
11438
11471
|
const pendingPolicyConfig = readCarriedPolicyConfig();
|
|
@@ -11457,7 +11490,7 @@ function resetHome(from) {
|
|
|
11457
11490
|
writeConfig(pendingConfig);
|
|
11458
11491
|
if (telemetryOptOut)
|
|
11459
11492
|
updateConfig({ telemetry: { enabled: false } });
|
|
11460
|
-
writeVersionFile();
|
|
11493
|
+
writeVersionFile({ layout: to });
|
|
11461
11494
|
return { removed, migrated, activity, policyConfig, spooled, from };
|
|
11462
11495
|
}
|
|
11463
11496
|
function layoutWarningForHook() {
|
|
@@ -12033,14 +12066,71 @@ __export(exports_migrations, {
|
|
|
12033
12066
|
runMigrations: () => runMigrations,
|
|
12034
12067
|
restoreBackup: () => restoreBackup,
|
|
12035
12068
|
readLedger: () => readLedger,
|
|
12069
|
+
pruneMigratedCredentials: () => pruneMigratedCredentials,
|
|
12036
12070
|
planMigration: () => planMigration,
|
|
12037
12071
|
migrationCoverageGap: () => migrationCoverageGap,
|
|
12038
12072
|
describePlan: () => describePlan,
|
|
12039
12073
|
backupBeforeMigrating: () => backupBeforeMigrating,
|
|
12040
12074
|
MIGRATIONS: () => MIGRATIONS
|
|
12041
12075
|
});
|
|
12042
|
-
import {
|
|
12043
|
-
|
|
12076
|
+
import {
|
|
12077
|
+
chmodSync as chmodSync4,
|
|
12078
|
+
copyFileSync as copyFileSync2,
|
|
12079
|
+
existsSync as existsSync21,
|
|
12080
|
+
mkdirSync as mkdirSync12,
|
|
12081
|
+
readFileSync as readFileSync16,
|
|
12082
|
+
renameSync as renameSync6,
|
|
12083
|
+
rmSync as rmSync7,
|
|
12084
|
+
writeFileSync as writeFileSync10
|
|
12085
|
+
} from "node:fs";
|
|
12086
|
+
import { basename as basename4, dirname as dirname10, join as join29, resolve as resolve16 } from "node:path";
|
|
12087
|
+
function migrateToLayout4() {
|
|
12088
|
+
const moves = [
|
|
12089
|
+
{ from: legacy.authJson(), to: auditSessionFile() },
|
|
12090
|
+
{ from: legacy.nextAudit(), to: legacy.auditReminder() },
|
|
12091
|
+
{ from: legacy.auditSchedule(), to: auditScheduleFile() }
|
|
12092
|
+
];
|
|
12093
|
+
const authDirOverride = process.env.FAILPROOFAI_AUTH_DIR;
|
|
12094
|
+
if (authDirOverride) {
|
|
12095
|
+
moves.push({ from: join29(authDirOverride, "auth.json"), to: join29(authDirOverride, "session.json") }, {
|
|
12096
|
+
from: join29(authDirOverride, "next-audit.json"),
|
|
12097
|
+
to: join29(authDirOverride, "reminder.json")
|
|
12098
|
+
});
|
|
12099
|
+
}
|
|
12100
|
+
const migrated = [];
|
|
12101
|
+
for (const { from, to } of moves) {
|
|
12102
|
+
if (!existsSync21(from))
|
|
12103
|
+
continue;
|
|
12104
|
+
if (existsSync21(to)) {
|
|
12105
|
+
rmSync7(from, { force: true });
|
|
12106
|
+
continue;
|
|
12107
|
+
}
|
|
12108
|
+
mkdirSync12(dirname10(to), { recursive: true });
|
|
12109
|
+
try {
|
|
12110
|
+
renameSync6(from, to);
|
|
12111
|
+
} catch {
|
|
12112
|
+
try {
|
|
12113
|
+
copyFileSync2(from, to);
|
|
12114
|
+
} catch (err) {
|
|
12115
|
+
try {
|
|
12116
|
+
rmSync7(to, { force: true });
|
|
12117
|
+
} catch {}
|
|
12118
|
+
throw err;
|
|
12119
|
+
}
|
|
12120
|
+
rmSync7(from, { force: true });
|
|
12121
|
+
}
|
|
12122
|
+
migrated.push(`${basename4(from)} → audit/${basename4(to)}`);
|
|
12123
|
+
}
|
|
12124
|
+
for (const secret of [auditSessionFile()]) {
|
|
12125
|
+
if (!existsSync21(secret))
|
|
12126
|
+
continue;
|
|
12127
|
+
try {
|
|
12128
|
+
chmodSync4(secret, 384);
|
|
12129
|
+
} catch {}
|
|
12130
|
+
}
|
|
12131
|
+
writeVersionFile({ layout: 4 });
|
|
12132
|
+
return { removed: [], migrated, activity: [], policyConfig: [], spooled: [], from: 3 };
|
|
12133
|
+
}
|
|
12044
12134
|
function planMigration(from, registry = MIGRATIONS) {
|
|
12045
12135
|
if (from >= LAYOUT_VERSION)
|
|
12046
12136
|
return [];
|
|
@@ -12095,6 +12185,23 @@ function appendLedger(entry) {
|
|
|
12095
12185
|
function backupNameOf(f) {
|
|
12096
12186
|
return f.as ?? basename4(f.at());
|
|
12097
12187
|
}
|
|
12188
|
+
function pruneMigratedCredentials(from) {
|
|
12189
|
+
const pruned = [];
|
|
12190
|
+
for (let layout = from;layout < LAYOUT_VERSION; layout++) {
|
|
12191
|
+
for (const { as, landsAt } of PRUNED_AFTER_SUCCESS) {
|
|
12192
|
+
try {
|
|
12193
|
+
if (!existsSync21(landsAt()))
|
|
12194
|
+
continue;
|
|
12195
|
+
const copy = resolve16(migrationBackupDir(layout), as);
|
|
12196
|
+
if (!existsSync21(copy))
|
|
12197
|
+
continue;
|
|
12198
|
+
rmSync7(copy, { force: true });
|
|
12199
|
+
pruned.push(as);
|
|
12200
|
+
} catch {}
|
|
12201
|
+
}
|
|
12202
|
+
}
|
|
12203
|
+
return pruned;
|
|
12204
|
+
}
|
|
12098
12205
|
function filesToBackUp() {
|
|
12099
12206
|
const seen = new Map;
|
|
12100
12207
|
for (const f of [...BACKED_UP, ...BACKED_UP_LEGACY]) {
|
|
@@ -12156,6 +12263,11 @@ function runMigrations(from, chain = planMigration(from)) {
|
|
|
12156
12263
|
});
|
|
12157
12264
|
} catch (err) {
|
|
12158
12265
|
steps.push({ from: step.from, to: step.to, ok: false });
|
|
12266
|
+
try {
|
|
12267
|
+
const marker = readVersionFile();
|
|
12268
|
+
if (marker && marker.layout >= LAYOUT_VERSION)
|
|
12269
|
+
writeVersionFile({ layout: step.from });
|
|
12270
|
+
} catch {}
|
|
12159
12271
|
failed = {
|
|
12160
12272
|
from: step.from,
|
|
12161
12273
|
to: step.to,
|
|
@@ -12172,6 +12284,8 @@ function runMigrations(from, chain = planMigration(from)) {
|
|
|
12172
12284
|
break;
|
|
12173
12285
|
}
|
|
12174
12286
|
}
|
|
12287
|
+
if (!failed)
|
|
12288
|
+
pruneMigratedCredentials(from);
|
|
12175
12289
|
return { from, steps, backedUp, outcome, failed };
|
|
12176
12290
|
}
|
|
12177
12291
|
function describePlan(from) {
|
|
@@ -12214,23 +12328,30 @@ function restoreBackup(layout) {
|
|
|
12214
12328
|
}
|
|
12215
12329
|
return restored.sort((a, b) => a.localeCompare(b));
|
|
12216
12330
|
}
|
|
12217
|
-
var MIGRATIONS, BACKED_UP, BACKED_UP_LEGACY;
|
|
12331
|
+
var MIGRATIONS, BACKED_UP, BACKED_UP_LEGACY, PRUNED_AFTER_SUCCESS;
|
|
12218
12332
|
var init_migrations = __esm(() => {
|
|
12219
12333
|
init_package();
|
|
12220
12334
|
init_fp_home();
|
|
12335
|
+
init_fp_config();
|
|
12221
12336
|
init_fp_reset();
|
|
12222
12337
|
MIGRATIONS = [
|
|
12223
12338
|
{
|
|
12224
12339
|
from: 1,
|
|
12225
12340
|
to: 3,
|
|
12226
12341
|
describe: "layout 1 → 3: carry the decision log out of cache/, keep the policy config in place, drop the layout-1 credential files",
|
|
12227
|
-
run: () => resetHome(1)
|
|
12342
|
+
run: () => resetHome(1, 3)
|
|
12228
12343
|
},
|
|
12229
12344
|
{
|
|
12230
12345
|
from: 2,
|
|
12231
12346
|
to: 3,
|
|
12232
12347
|
describe: "layout 2 → 3: carry config.toml and credentials.toml into JSON, move custom-policies/ back up into policies/, nest the policy config at the root",
|
|
12233
|
-
run: () => resetHome(2)
|
|
12348
|
+
run: () => resetHome(2, 3)
|
|
12349
|
+
},
|
|
12350
|
+
{
|
|
12351
|
+
from: 3,
|
|
12352
|
+
to: 4,
|
|
12353
|
+
describe: "layout 3 → 4: gather the audit's files under audit/ — auth.json becomes audit/session.json, next-audit.json becomes audit/reminder.json, state/audit-schedule.json becomes audit/schedule.json",
|
|
12354
|
+
run: migrateToLayout4
|
|
12234
12355
|
}
|
|
12235
12356
|
];
|
|
12236
12357
|
BACKED_UP = [
|
|
@@ -12245,7 +12366,13 @@ var init_migrations = __esm(() => {
|
|
|
12245
12366
|
{ at: legacy.policyConfig },
|
|
12246
12367
|
{ at: legacy.localPolicyConfig, as: "local-policies-policies-config.json" },
|
|
12247
12368
|
{ at: legacy.cloudCredentials },
|
|
12248
|
-
{ at: legacy.ingestCredentials }
|
|
12369
|
+
{ at: legacy.ingestCredentials },
|
|
12370
|
+
{ at: legacy.authJson },
|
|
12371
|
+
{ at: legacy.nextAudit },
|
|
12372
|
+
{ at: legacy.auditSchedule }
|
|
12373
|
+
];
|
|
12374
|
+
PRUNED_AFTER_SUCCESS = [
|
|
12375
|
+
{ as: basename4(legacy.authJson()), landsAt: auditSessionFile }
|
|
12249
12376
|
];
|
|
12250
12377
|
});
|
|
12251
12378
|
|
|
@@ -12272,7 +12399,7 @@ import {
|
|
|
12272
12399
|
mkdirSync as mkdirSync13,
|
|
12273
12400
|
readFileSync as readFileSync17,
|
|
12274
12401
|
readdirSync as readdirSync16,
|
|
12275
|
-
renameSync as
|
|
12402
|
+
renameSync as renameSync7,
|
|
12276
12403
|
rmSync as rmSync8,
|
|
12277
12404
|
rmdirSync as rmdirSync2,
|
|
12278
12405
|
statSync as statSync17,
|
|
@@ -12304,7 +12431,7 @@ function migrateConventionPolicies2() {
|
|
|
12304
12431
|
const name = `${prefix}${entry.name}`;
|
|
12305
12432
|
if (!existsSync22(target)) {
|
|
12306
12433
|
try {
|
|
12307
|
-
|
|
12434
|
+
renameSync7(source, target);
|
|
12308
12435
|
moved.push(name);
|
|
12309
12436
|
} catch {}
|
|
12310
12437
|
continue;
|
|
@@ -12341,7 +12468,7 @@ function migrateLegacySpool2() {
|
|
|
12341
12468
|
while (existsSync22(resolve17(to, name)))
|
|
12342
12469
|
name = `legacy-${n++}-${entry.name}`;
|
|
12343
12470
|
try {
|
|
12344
|
-
|
|
12471
|
+
renameSync7(resolve17(from, entry.name), resolve17(to, name));
|
|
12345
12472
|
moved.push(name);
|
|
12346
12473
|
} catch {
|
|
12347
12474
|
try {
|
|
@@ -12376,7 +12503,7 @@ function migrateHookActivity2() {
|
|
|
12376
12503
|
target = resolve17(to, name);
|
|
12377
12504
|
}
|
|
12378
12505
|
try {
|
|
12379
|
-
|
|
12506
|
+
renameSync7(source, target);
|
|
12380
12507
|
moved.push(name);
|
|
12381
12508
|
} catch {
|
|
12382
12509
|
try {
|
|
@@ -12584,7 +12711,7 @@ function readCarriedLegacyCredentials2() {
|
|
|
12584
12711
|
const creds = projectCredentials(raw);
|
|
12585
12712
|
return Object.keys(creds).length > 0 ? creds : null;
|
|
12586
12713
|
}
|
|
12587
|
-
function resetHome2(from) {
|
|
12714
|
+
function resetHome2(from, to = LAYOUT_VERSION) {
|
|
12588
12715
|
const migrated = migrateConventionPolicies2();
|
|
12589
12716
|
const activity = migrateHookActivity2();
|
|
12590
12717
|
const pendingPolicyConfig = readCarriedPolicyConfig2();
|
|
@@ -12609,7 +12736,7 @@ function resetHome2(from) {
|
|
|
12609
12736
|
writeConfig(pendingConfig);
|
|
12610
12737
|
if (telemetryOptOut)
|
|
12611
12738
|
updateConfig({ telemetry: { enabled: false } });
|
|
12612
|
-
writeVersionFile();
|
|
12739
|
+
writeVersionFile({ layout: to });
|
|
12613
12740
|
return { removed, migrated, activity, policyConfig, spooled, from };
|
|
12614
12741
|
}
|
|
12615
12742
|
async function drainSpoolAfterMigrating() {
|
|
@@ -12647,6 +12774,7 @@ async function checkLayoutForCli() {
|
|
|
12647
12774
|
const run = runMigrations2(state.found);
|
|
12648
12775
|
const { removed, migrated, activity } = run.outcome;
|
|
12649
12776
|
const pending3 = await drainSpoolAfterMigrating();
|
|
12777
|
+
const daemonHint = staleDaemonHint();
|
|
12650
12778
|
return {
|
|
12651
12779
|
state,
|
|
12652
12780
|
fatal: false,
|
|
@@ -12678,7 +12806,8 @@ async function checkLayoutForCli() {
|
|
|
12678
12806
|
`Step ${run.failed.from} → ${run.failed.to} did not finish: ${run.failed.error}`,
|
|
12679
12807
|
`The home is still marked layout ${state.found} and will be retried. Copies of`,
|
|
12680
12808
|
`your settings and enrolment were saved first, in ${migrationBackupDir(state.found)}.`
|
|
12681
|
-
] : []
|
|
12809
|
+
] : [],
|
|
12810
|
+
...daemonHint.length > 0 ? ["", ...daemonHint] : []
|
|
12682
12811
|
]
|
|
12683
12812
|
};
|
|
12684
12813
|
}
|
|
@@ -12743,8 +12872,23 @@ function staleDaemonHint() {
|
|
|
12743
12872
|
const skew = daemonVersionSkew();
|
|
12744
12873
|
if (!skew)
|
|
12745
12874
|
return [];
|
|
12875
|
+
let requiresDaemon = false;
|
|
12876
|
+
try {
|
|
12877
|
+
requiresDaemon = readConfig().daemon.configured;
|
|
12878
|
+
} catch {}
|
|
12879
|
+
if (requiresDaemon) {
|
|
12880
|
+
return [
|
|
12881
|
+
`[failproofai] daemon is ${skew.installed}, CLI is ${skew.expected}.`,
|
|
12882
|
+
`This machine is configured to REQUIRE the daemon. A daemon built against a`,
|
|
12883
|
+
`different on-disk layout refuses to start, and this version moved it — so the`,
|
|
12884
|
+
`next reboot or restart can leave the service down, which denies every tool`,
|
|
12885
|
+
`call until it is fixed.`,
|
|
12886
|
+
`Run \`failproofai update\` now to bring the daemon in line.`,
|
|
12887
|
+
``
|
|
12888
|
+
];
|
|
12889
|
+
}
|
|
12746
12890
|
return [
|
|
12747
|
-
`[failproofai] daemon is ${skew.installed}, CLI is ${skew.expected} — ` + `run \`failproofai
|
|
12891
|
+
`[failproofai] daemon is ${skew.installed}, CLI is ${skew.expected} — ` + `run \`failproofai update\` to update it.`,
|
|
12748
12892
|
``
|
|
12749
12893
|
];
|
|
12750
12894
|
} catch {
|
|
@@ -12785,13 +12929,13 @@ import { createHmac, randomUUID as randomUUID2 } from "node:crypto";
|
|
|
12785
12929
|
import { execSync as execSync4 } from "node:child_process";
|
|
12786
12930
|
import { readFileSync as readFileSync18, writeFileSync as writeFileSync12, mkdirSync as mkdirSync14 } from "node:fs";
|
|
12787
12931
|
import { homedir as homedir20, platform, arch, hostname, cpus } from "node:os";
|
|
12788
|
-
import { join as
|
|
12932
|
+
import { join as join30 } from "node:path";
|
|
12789
12933
|
function hashToId3(raw) {
|
|
12790
12934
|
return createHmac("sha256", NAMESPACE3).update(raw).digest("hex");
|
|
12791
12935
|
}
|
|
12792
12936
|
function getInstanceId3() {
|
|
12793
|
-
const idDir =
|
|
12794
|
-
const idFile =
|
|
12937
|
+
const idDir = join30(homedir20(), ".failproofai");
|
|
12938
|
+
const idFile = join30(idDir, "instance-id");
|
|
12795
12939
|
try {
|
|
12796
12940
|
const existing = readFileSync18(idFile, "utf-8").trim();
|
|
12797
12941
|
if (existing)
|
|
@@ -13187,6 +13331,27 @@ function renderLaunchBanner(version3, stdout = process.stdout) {
|
|
|
13187
13331
|
""
|
|
13188
13332
|
];
|
|
13189
13333
|
}
|
|
13334
|
+
function step(message, summary, stdout = process.stdout) {
|
|
13335
|
+
const c = paint(colorsEnabled(stdout));
|
|
13336
|
+
const rows = summary === undefined ? [] : Array.isArray(summary) ? summary : [summary];
|
|
13337
|
+
if (!stdout.isTTY) {
|
|
13338
|
+
if (rows.length)
|
|
13339
|
+
stdout.write(`${message}: ${rows.join(" ")}
|
|
13340
|
+
`);
|
|
13341
|
+
return;
|
|
13342
|
+
}
|
|
13343
|
+
const cols = stdout.columns || 80;
|
|
13344
|
+
const lines = [c.dim(BAR), truncate(`${c.dim(STEP_DONE)} ${message}`, cols - 1)];
|
|
13345
|
+
for (const r of rows)
|
|
13346
|
+
lines.push(truncate(`${c.dim(BAR)} ${c.dim(r)}`, cols - 1));
|
|
13347
|
+
writeLines(stdout, lines);
|
|
13348
|
+
}
|
|
13349
|
+
function stepOpen(message, stdout = process.stdout) {
|
|
13350
|
+
const c = paint(colorsEnabled(stdout));
|
|
13351
|
+
if (!stdout.isTTY)
|
|
13352
|
+
return;
|
|
13353
|
+
writeLines(stdout, [c.dim(BAR), `${c.guide(STEP_ACTIVE)} ${c.bold(message)}`]);
|
|
13354
|
+
}
|
|
13190
13355
|
function outro(message, opts = {}, stdout = process.stdout) {
|
|
13191
13356
|
const c = paint(colorsEnabled(stdout));
|
|
13192
13357
|
const ok = opts.ok !== false;
|
|
@@ -13449,10 +13614,10 @@ function promptText(opts) {
|
|
|
13449
13614
|
const draw = (error) => {
|
|
13450
13615
|
const cols = stdout.columns || 80;
|
|
13451
13616
|
const shown = opts.mask ? "•".repeat(value.length) : value;
|
|
13452
|
-
const hint = opts.hint ? ` ${c.dim(opts.hint)}` : "";
|
|
13453
|
-
const line = truncate(`${c.bold(opts.message)} ${shown}${hint}`, cols - 1);
|
|
13617
|
+
const hint = opts.hint && value.length === 0 ? ` ${c.dim(opts.hint)}` : "";
|
|
13618
|
+
const line = truncate(`${opts.prefix ?? ""}${c.bold(opts.message)} ${shown}${hint}`, cols - 1);
|
|
13454
13619
|
const err = error ? `
|
|
13455
|
-
${truncate(c.warn(error), cols - 3)}` : "";
|
|
13620
|
+
${opts.prefix ?? " "}${truncate(c.warn(error), cols - 3)}` : "";
|
|
13456
13621
|
stdout.write(`\r\x1B[2K${line}${err}`);
|
|
13457
13622
|
if (err)
|
|
13458
13623
|
stdout.write("\x1B[1A");
|
|
@@ -23469,7 +23634,7 @@ var init_onboarding_lock = __esm(() => {
|
|
|
23469
23634
|
|
|
23470
23635
|
// lib/claude-sessions.ts
|
|
23471
23636
|
import { readdirSync as readdirSync17, statSync as statSync19, existsSync as existsSync29 } from "node:fs";
|
|
23472
|
-
import { join as
|
|
23637
|
+
import { join as join31, basename as basename6 } from "node:path";
|
|
23473
23638
|
function getClaudeProjectsRoot() {
|
|
23474
23639
|
return getClaudeProjectsPath();
|
|
23475
23640
|
}
|
|
@@ -23484,7 +23649,7 @@ function listClaudeProjects() {
|
|
|
23484
23649
|
return entries.filter((e) => e.isDirectory()).map((e) => ({
|
|
23485
23650
|
name: e.name,
|
|
23486
23651
|
cwd: decodeFolderName(e.name),
|
|
23487
|
-
path:
|
|
23652
|
+
path: join31(root, e.name)
|
|
23488
23653
|
}));
|
|
23489
23654
|
}
|
|
23490
23655
|
function listClaudeTranscripts(project) {
|
|
@@ -23500,7 +23665,7 @@ function listClaudeTranscripts(project) {
|
|
|
23500
23665
|
const sessionId = entry.name.slice(0, -".jsonl".length);
|
|
23501
23666
|
if (!UUID_RE2.test(sessionId))
|
|
23502
23667
|
continue;
|
|
23503
|
-
const transcriptPath =
|
|
23668
|
+
const transcriptPath = join31(project.path, entry.name);
|
|
23504
23669
|
try {
|
|
23505
23670
|
const s = statSync19(transcriptPath);
|
|
23506
23671
|
out.push({
|
|
@@ -23514,7 +23679,7 @@ function listClaudeTranscripts(project) {
|
|
|
23514
23679
|
});
|
|
23515
23680
|
} catch {}
|
|
23516
23681
|
} else if (entry.isDirectory() && UUID_RE2.test(entry.name)) {
|
|
23517
|
-
const subDir =
|
|
23682
|
+
const subDir = join31(project.path, entry.name, "subagents");
|
|
23518
23683
|
if (!existsSync29(subDir))
|
|
23519
23684
|
continue;
|
|
23520
23685
|
let subEntries;
|
|
@@ -23527,7 +23692,7 @@ function listClaudeTranscripts(project) {
|
|
|
23527
23692
|
if (!sub.isFile() || !sub.name.endsWith(".jsonl"))
|
|
23528
23693
|
continue;
|
|
23529
23694
|
const agentId = sub.name.slice(0, -".jsonl".length);
|
|
23530
|
-
const transcriptPath =
|
|
23695
|
+
const transcriptPath = join31(subDir, sub.name);
|
|
23531
23696
|
try {
|
|
23532
23697
|
const s = statSync19(transcriptPath);
|
|
23533
23698
|
out.push({
|
|
@@ -24790,8 +24955,8 @@ var init_features = __esm(() => {
|
|
|
24790
24955
|
|
|
24791
24956
|
// src/audit/cache.ts
|
|
24792
24957
|
import { createHash as createHash6 } from "node:crypto";
|
|
24793
|
-
import { existsSync as existsSync30, mkdirSync as mkdirSync19, readFileSync as readFileSync24, writeFileSync as writeFileSync17, chmodSync as
|
|
24794
|
-
import { join as
|
|
24958
|
+
import { existsSync as existsSync30, mkdirSync as mkdirSync19, readFileSync as readFileSync24, writeFileSync as writeFileSync17, chmodSync as chmodSync5 } from "node:fs";
|
|
24959
|
+
import { join as join32 } from "node:path";
|
|
24795
24960
|
function getEngineVersion() {
|
|
24796
24961
|
if (cachedEngineVersion)
|
|
24797
24962
|
return cachedEngineVersion;
|
|
@@ -24811,7 +24976,7 @@ function getDetectorVersion() {
|
|
|
24811
24976
|
function getCachePathFor(transcriptPath) {
|
|
24812
24977
|
const root = auditCacheDir();
|
|
24813
24978
|
const key = createHash6("sha1").update(transcriptPath).digest("hex");
|
|
24814
|
-
return
|
|
24979
|
+
return join32(root, `${key}.json`);
|
|
24815
24980
|
}
|
|
24816
24981
|
function readCachedTranscriptResult(transcriptPath, mtimeMs, sizeBytes) {
|
|
24817
24982
|
if (sizeBytes === 0)
|
|
@@ -24856,7 +25021,7 @@ function writeCachedTranscriptResult(transcriptPath, mtimeMs, sizeBytes, result)
|
|
|
24856
25021
|
};
|
|
24857
25022
|
writeFileSync17(cachePath, JSON.stringify(entry), { encoding: "utf-8", mode: 384 });
|
|
24858
25023
|
try {
|
|
24859
|
-
|
|
25024
|
+
chmodSync5(cachePath, 384);
|
|
24860
25025
|
} catch {}
|
|
24861
25026
|
} catch {}
|
|
24862
25027
|
}
|
|
@@ -25343,6 +25508,7 @@ var init_audit_lock = __esm(() => {
|
|
|
25343
25508
|
});
|
|
25344
25509
|
|
|
25345
25510
|
// src/audit/dashboard-cache.ts
|
|
25511
|
+
import { existsSync as existsSync31, readFileSync as readFileSync26 } from "node:fs";
|
|
25346
25512
|
function getCachePath() {
|
|
25347
25513
|
return auditDashboardFile();
|
|
25348
25514
|
}
|
|
@@ -25360,6 +25526,27 @@ function writeDashboardCache(params, result) {
|
|
|
25360
25526
|
return false;
|
|
25361
25527
|
}
|
|
25362
25528
|
}
|
|
25529
|
+
function readDashboardCacheMeta() {
|
|
25530
|
+
const cachePath = getCachePath();
|
|
25531
|
+
if (!existsSync31(cachePath))
|
|
25532
|
+
return null;
|
|
25533
|
+
try {
|
|
25534
|
+
const raw = readFileSync26(cachePath, "utf-8");
|
|
25535
|
+
const entry = JSON.parse(raw);
|
|
25536
|
+
if (!entry || entry.schemaVersion !== DASHBOARD_CACHE_SCHEMA_VERSION || typeof entry.cachedAt !== "string" || Number.isNaN(new Date(entry.cachedAt).getTime()))
|
|
25537
|
+
return null;
|
|
25538
|
+
const result = entry.result;
|
|
25539
|
+
const count = (v) => typeof v === "number" && Number.isFinite(v) ? v : null;
|
|
25540
|
+
return {
|
|
25541
|
+
cachedAt: entry.cachedAt,
|
|
25542
|
+
findings: count(result?.totals?.hits),
|
|
25543
|
+
sessionsScanned: count(result?.transcripts?.scanned),
|
|
25544
|
+
eventsScanned: count(result?.eventsScanned)
|
|
25545
|
+
};
|
|
25546
|
+
} catch {
|
|
25547
|
+
return null;
|
|
25548
|
+
}
|
|
25549
|
+
}
|
|
25363
25550
|
var DASHBOARD_CACHE_TTL_MINUTES, DASHBOARD_CACHE_SCHEMA_VERSION = 2;
|
|
25364
25551
|
var init_dashboard_cache = __esm(() => {
|
|
25365
25552
|
init_atomic_write();
|
|
@@ -25434,160 +25621,1095 @@ function openWhenReady(port, path3) {
|
|
|
25434
25621
|
var POLL_INTERVAL_MS = 150, POLL_TIMEOUT_MS = 30000;
|
|
25435
25622
|
var init_open_browser = () => {};
|
|
25436
25623
|
|
|
25437
|
-
//
|
|
25438
|
-
|
|
25439
|
-
|
|
25440
|
-
|
|
25441
|
-
|
|
25442
|
-
|
|
25443
|
-
|
|
25444
|
-
|
|
25445
|
-
|
|
25446
|
-
|
|
25624
|
+
// lib/telemetry.ts
|
|
25625
|
+
function trackEvent(name, properties) {
|
|
25626
|
+
if (!isTelemetryEnabled())
|
|
25627
|
+
return;
|
|
25628
|
+
const client = globalThis.__FAILPROOFAI_POSTHOG__;
|
|
25629
|
+
if (!client)
|
|
25630
|
+
return;
|
|
25631
|
+
client.capture({
|
|
25632
|
+
distinctId: getInstanceId2(),
|
|
25633
|
+
event: name,
|
|
25634
|
+
properties: { ...properties, $lib: "failproofai", failproofai_version: version2, product: POSTHOG_PRODUCT }
|
|
25635
|
+
});
|
|
25447
25636
|
}
|
|
25448
|
-
|
|
25449
|
-
|
|
25450
|
-
|
|
25451
|
-
|
|
25452
|
-
|
|
25453
|
-
|
|
25454
|
-
|
|
25455
|
-
|
|
25456
|
-
|
|
25457
|
-
|
|
25458
|
-
|
|
25459
|
-
|
|
25460
|
-
|
|
25461
|
-
|
|
25462
|
-
|
|
25463
|
-
|
|
25464
|
-
|
|
25465
|
-
|
|
25466
|
-
|
|
25467
|
-
|
|
25468
|
-
|
|
25469
|
-
|
|
25470
|
-
|
|
25471
|
-
|
|
25472
|
-
|
|
25473
|
-
continue;
|
|
25474
|
-
}
|
|
25475
|
-
if (flag === "--disable-telemetry") {
|
|
25476
|
-
disableTelemetry = true;
|
|
25477
|
-
args.splice(i, 1);
|
|
25478
|
-
i--;
|
|
25479
|
-
continue;
|
|
25480
|
-
}
|
|
25481
|
-
if (flag === "--allowed-origins") {
|
|
25482
|
-
const { value, spliceCount } = parseStringFlag(flag, "a comma-separated list of origins", inlineValue, args, i);
|
|
25483
|
-
allowedDevOrigins = value.split(",").map((s) => s.trim()).filter(Boolean);
|
|
25484
|
-
args.splice(i, spliceCount);
|
|
25485
|
-
i--;
|
|
25486
|
-
continue;
|
|
25637
|
+
var init_telemetry = __esm(() => {
|
|
25638
|
+
init_telemetry_id2();
|
|
25639
|
+
init_telemetry_enabled();
|
|
25640
|
+
init_package();
|
|
25641
|
+
});
|
|
25642
|
+
|
|
25643
|
+
// lib/auth/api-server-client.ts
|
|
25644
|
+
function getApiBase() {
|
|
25645
|
+
const raw = process.env.FAILPROOF_API_URL ?? process.env.FAILPROOFAI_API_URL ?? DEFAULT_API_BASE;
|
|
25646
|
+
return raw.replace(/\/+$/, "");
|
|
25647
|
+
}
|
|
25648
|
+
async function parseError(res) {
|
|
25649
|
+
let body = {};
|
|
25650
|
+
try {
|
|
25651
|
+
body = await res.json();
|
|
25652
|
+
} catch {}
|
|
25653
|
+
const code = body.code ?? `http_${res.status}`;
|
|
25654
|
+
const message = body.message ?? body.detail ?? res.statusText ?? "request failed";
|
|
25655
|
+
let retryAfterSecs = body.retry_after_secs;
|
|
25656
|
+
if (retryAfterSecs === undefined) {
|
|
25657
|
+
const h = res.headers.get("retry-after");
|
|
25658
|
+
if (h) {
|
|
25659
|
+
const n = Number(h);
|
|
25660
|
+
if (Number.isFinite(n))
|
|
25661
|
+
retryAfterSecs = n;
|
|
25487
25662
|
}
|
|
25488
|
-
|
|
25489
|
-
|
|
25490
|
-
|
|
25491
|
-
|
|
25492
|
-
|
|
25493
|
-
|
|
25663
|
+
}
|
|
25664
|
+
if (retryAfterSecs !== undefined) {
|
|
25665
|
+
retryAfterSecs = Math.max(0, Math.min(86400, retryAfterSecs));
|
|
25666
|
+
}
|
|
25667
|
+
return new AuthApiError(res.status, code, message, retryAfterSecs);
|
|
25668
|
+
}
|
|
25669
|
+
function timeoutSignal(extra) {
|
|
25670
|
+
const t = AbortSignal.timeout(REQUEST_TIMEOUT_MS);
|
|
25671
|
+
if (!extra)
|
|
25672
|
+
return t;
|
|
25673
|
+
const anyFn = AbortSignal.any;
|
|
25674
|
+
if (anyFn)
|
|
25675
|
+
return anyFn([t, extra]);
|
|
25676
|
+
const composed = new AbortController;
|
|
25677
|
+
const onAbort = (s) => composed.abort(s.reason);
|
|
25678
|
+
if (t.aborted)
|
|
25679
|
+
onAbort(t);
|
|
25680
|
+
else
|
|
25681
|
+
t.addEventListener("abort", () => onAbort(t), { once: true });
|
|
25682
|
+
if (extra.aborted)
|
|
25683
|
+
onAbort(extra);
|
|
25684
|
+
else
|
|
25685
|
+
extra.addEventListener("abort", () => onAbort(extra), { once: true });
|
|
25686
|
+
return composed.signal;
|
|
25687
|
+
}
|
|
25688
|
+
function pathFromUrl(url) {
|
|
25689
|
+
try {
|
|
25690
|
+
return new URL(url).pathname;
|
|
25691
|
+
} catch {
|
|
25692
|
+
return url;
|
|
25693
|
+
}
|
|
25694
|
+
}
|
|
25695
|
+
async function fetchWithTimeout2(url, init) {
|
|
25696
|
+
try {
|
|
25697
|
+
return await fetch(url, { ...init, signal: timeoutSignal(init.signal ?? undefined) });
|
|
25698
|
+
} catch (err) {
|
|
25699
|
+
const isTimeout = isAbortError(err);
|
|
25700
|
+
trackEvent("api_server_unreachable", {
|
|
25701
|
+
kind: isTimeout ? "timeout" : "network",
|
|
25702
|
+
path: pathFromUrl(url),
|
|
25703
|
+
method: typeof init.method === "string" ? init.method : "GET"
|
|
25704
|
+
});
|
|
25705
|
+
if (isTimeout) {
|
|
25706
|
+
throw new AuthApiError(0, "timeout", `request to ${url} timed out after ${REQUEST_TIMEOUT_MS}ms`);
|
|
25494
25707
|
}
|
|
25708
|
+
throw err;
|
|
25495
25709
|
}
|
|
25496
|
-
return { loggingLevel, disableTelemetry, allowedDevOrigins, host, remainingArgs: args };
|
|
25497
25710
|
}
|
|
25498
|
-
|
|
25711
|
+
async function postJson(path3, body, init) {
|
|
25712
|
+
const headers = { "content-type": "application/json" };
|
|
25713
|
+
if (init?.accessToken)
|
|
25714
|
+
headers["authorization"] = `Bearer ${init.accessToken}`;
|
|
25715
|
+
const res = await fetchWithTimeout2(`${getApiBase()}${path3}`, {
|
|
25716
|
+
method: "POST",
|
|
25717
|
+
headers,
|
|
25718
|
+
body: JSON.stringify(body)
|
|
25719
|
+
});
|
|
25720
|
+
if (res.status === 204)
|
|
25721
|
+
return;
|
|
25722
|
+
if (!res.ok)
|
|
25723
|
+
throw await parseError(res);
|
|
25724
|
+
return await res.json();
|
|
25725
|
+
}
|
|
25726
|
+
async function requestLoginCode(email) {
|
|
25727
|
+
return postJson("/v0/auth/login/request", { email });
|
|
25728
|
+
}
|
|
25729
|
+
async function verifyLoginCode(email, code) {
|
|
25730
|
+
return postJson("/v0/auth/login/verify", { email, code });
|
|
25731
|
+
}
|
|
25732
|
+
async function refreshAccessToken(refreshToken) {
|
|
25733
|
+
return postJson("/v0/auth/token/refresh", {
|
|
25734
|
+
refresh_token: refreshToken
|
|
25735
|
+
});
|
|
25736
|
+
}
|
|
25737
|
+
async function submitAuditReport(accessToken, body) {
|
|
25738
|
+
return postJson("/v0/audit-reports", body, { accessToken });
|
|
25739
|
+
}
|
|
25740
|
+
var DEFAULT_API_BASE = "https://api.befailproof.ai", AuthApiError, REQUEST_TIMEOUT_MS = 1e4;
|
|
25741
|
+
var init_api_server_client = __esm(() => {
|
|
25742
|
+
init_telemetry();
|
|
25743
|
+
AuthApiError = class AuthApiError extends Error {
|
|
25744
|
+
status;
|
|
25745
|
+
code;
|
|
25746
|
+
retryAfterSecs;
|
|
25747
|
+
constructor(status, code, message, retryAfterSecs) {
|
|
25748
|
+
super(message);
|
|
25749
|
+
this.status = status;
|
|
25750
|
+
this.code = code;
|
|
25751
|
+
this.retryAfterSecs = retryAfterSecs;
|
|
25752
|
+
this.name = "AuthApiError";
|
|
25753
|
+
}
|
|
25754
|
+
};
|
|
25755
|
+
});
|
|
25499
25756
|
|
|
25500
|
-
//
|
|
25501
|
-
import { existsSync as
|
|
25502
|
-
import {
|
|
25503
|
-
|
|
25504
|
-
|
|
25505
|
-
|
|
25757
|
+
// lib/auth/auth-store.ts
|
|
25758
|
+
import { existsSync as existsSync32, readFileSync as readFileSync27, readdirSync as readdirSync18, rmSync as rmSync12 } from "node:fs";
|
|
25759
|
+
import { join as join33, resolve as resolve22 } from "node:path";
|
|
25760
|
+
function getAuthFilePath() {
|
|
25761
|
+
const override = process.env.FAILPROOFAI_AUTH_DIR;
|
|
25762
|
+
return override ? join33(override, "session.json") : auditSessionFile();
|
|
25763
|
+
}
|
|
25764
|
+
function readAuth() {
|
|
25765
|
+
const p = getAuthFilePath();
|
|
25766
|
+
if (!existsSync32(p))
|
|
25767
|
+
return null;
|
|
25506
25768
|
try {
|
|
25507
|
-
|
|
25508
|
-
|
|
25509
|
-
|
|
25769
|
+
const raw = readFileSync27(p, "utf-8");
|
|
25770
|
+
const parsed = JSON.parse(raw);
|
|
25771
|
+
if (typeof parsed.access_token !== "string" || typeof parsed.refresh_token !== "string" || typeof parsed.access_expires_at !== "number" || typeof parsed.user !== "object" || !parsed.user || typeof parsed.user.id !== "string" || typeof parsed.user.email !== "string") {
|
|
25772
|
+
return null;
|
|
25510
25773
|
}
|
|
25511
|
-
|
|
25512
|
-
|
|
25513
|
-
|
|
25514
|
-
|
|
25515
|
-
|
|
25516
|
-
|
|
25517
|
-
|
|
25518
|
-
|
|
25774
|
+
return {
|
|
25775
|
+
access_token: parsed.access_token,
|
|
25776
|
+
refresh_token: parsed.refresh_token,
|
|
25777
|
+
access_expires_at: parsed.access_expires_at,
|
|
25778
|
+
refresh_expires_at: typeof parsed.refresh_expires_at === "number" ? parsed.refresh_expires_at : parsed.access_expires_at,
|
|
25779
|
+
user: {
|
|
25780
|
+
id: parsed.user.id,
|
|
25781
|
+
email: parsed.user.email
|
|
25519
25782
|
}
|
|
25520
|
-
|
|
25521
|
-
if (parent === dir)
|
|
25522
|
-
return null;
|
|
25523
|
-
dir = parent;
|
|
25524
|
-
}
|
|
25783
|
+
};
|
|
25525
25784
|
} catch {
|
|
25526
25785
|
return null;
|
|
25527
25786
|
}
|
|
25528
25787
|
}
|
|
25529
|
-
function
|
|
25530
|
-
|
|
25531
|
-
|
|
25788
|
+
function writeAuth(auth) {
|
|
25789
|
+
writeJsonAtomically(getAuthFilePath(), auth);
|
|
25790
|
+
}
|
|
25791
|
+
function deleteAuth() {
|
|
25792
|
+
const p = getAuthFilePath();
|
|
25793
|
+
if (existsSync32(p))
|
|
25794
|
+
rmSync12(p, { force: true });
|
|
25532
25795
|
try {
|
|
25533
|
-
const
|
|
25534
|
-
|
|
25535
|
-
|
|
25536
|
-
|
|
25796
|
+
const root = migrationsDir();
|
|
25797
|
+
if (!existsSync32(root))
|
|
25798
|
+
return;
|
|
25799
|
+
for (const entry of readdirSync18(root)) {
|
|
25800
|
+
if (!entry.startsWith("backup-layout"))
|
|
25801
|
+
continue;
|
|
25802
|
+
const copy = resolve22(root, entry, "auth.json");
|
|
25803
|
+
if (existsSync32(copy))
|
|
25804
|
+
rmSync12(copy, { force: true });
|
|
25805
|
+
}
|
|
25806
|
+
} catch {}
|
|
25807
|
+
}
|
|
25808
|
+
function authFromTokenResponse(token, existingUser) {
|
|
25809
|
+
const now = Math.floor(Date.now() / 1000);
|
|
25810
|
+
const user = token.user ?? existingUser;
|
|
25811
|
+
if (!user) {
|
|
25812
|
+
throw new Error("authFromTokenResponse: missing user identity");
|
|
25537
25813
|
}
|
|
25814
|
+
return {
|
|
25815
|
+
access_token: token.access_token,
|
|
25816
|
+
refresh_token: token.refresh_token,
|
|
25817
|
+
access_expires_at: now + token.access_expires_in,
|
|
25818
|
+
refresh_expires_at: now + token.refresh_expires_in,
|
|
25819
|
+
user
|
|
25820
|
+
};
|
|
25538
25821
|
}
|
|
25539
|
-
function
|
|
25822
|
+
async function dedupedRefresh(auth) {
|
|
25823
|
+
const existing = inFlightRefreshes.get(auth.refresh_token);
|
|
25824
|
+
if (existing)
|
|
25825
|
+
return existing;
|
|
25826
|
+
const p = (async () => {
|
|
25827
|
+
const refreshed = await refreshAccessToken(auth.refresh_token);
|
|
25828
|
+
const next = authFromTokenResponse(refreshed, auth.user);
|
|
25829
|
+
writeAuth(next);
|
|
25830
|
+
return next;
|
|
25831
|
+
})();
|
|
25832
|
+
inFlightRefreshes.set(auth.refresh_token, p);
|
|
25540
25833
|
try {
|
|
25541
|
-
|
|
25542
|
-
|
|
25543
|
-
|
|
25544
|
-
return null;
|
|
25545
|
-
const first = (res.stdout || "").split(/\r?\n/).find((l) => l.trim().length > 0);
|
|
25546
|
-
return first ? first.trim() : null;
|
|
25547
|
-
} catch {
|
|
25548
|
-
return null;
|
|
25834
|
+
return await p;
|
|
25835
|
+
} finally {
|
|
25836
|
+
inFlightRefreshes.delete(auth.refresh_token);
|
|
25549
25837
|
}
|
|
25550
25838
|
}
|
|
25551
|
-
function
|
|
25839
|
+
async function getValidAccessToken() {
|
|
25840
|
+
const auth = readAuth();
|
|
25841
|
+
if (!auth)
|
|
25842
|
+
return null;
|
|
25843
|
+
const now = Math.floor(Date.now() / 1000);
|
|
25844
|
+
if (auth.access_expires_at - now > REFRESH_LEEWAY_SECS)
|
|
25845
|
+
return auth;
|
|
25552
25846
|
try {
|
|
25553
|
-
|
|
25554
|
-
|
|
25555
|
-
|
|
25556
|
-
|
|
25557
|
-
if (!root)
|
|
25847
|
+
return await dedupedRefresh(auth);
|
|
25848
|
+
} catch (err) {
|
|
25849
|
+
if (err instanceof AuthApiError && err.status === 401) {
|
|
25850
|
+
deleteAuth();
|
|
25558
25851
|
return null;
|
|
25559
|
-
|
|
25560
|
-
return existsSync31(resolve23(candidate, "package.json")) ? candidate : null;
|
|
25561
|
-
} catch {
|
|
25852
|
+
}
|
|
25562
25853
|
return null;
|
|
25563
25854
|
}
|
|
25564
25855
|
}
|
|
25565
|
-
|
|
25566
|
-
|
|
25567
|
-
|
|
25568
|
-
|
|
25569
|
-
|
|
25570
|
-
|
|
25856
|
+
var REFRESH_LEEWAY_SECS = 60, inFlightRefreshes;
|
|
25857
|
+
var init_auth_store = __esm(() => {
|
|
25858
|
+
init_atomic_write();
|
|
25859
|
+
init_fp_home();
|
|
25860
|
+
init_api_server_client();
|
|
25861
|
+
inFlightRefreshes = new Map;
|
|
25862
|
+
});
|
|
25863
|
+
|
|
25864
|
+
// src/audit/redact-example.ts
|
|
25865
|
+
import { homedir as homedir25 } from "node:os";
|
|
25866
|
+
function maskTruncatedSecret(input) {
|
|
25867
|
+
for (const [pattern, label] of SECRET_PREFIXES) {
|
|
25868
|
+
if (pattern.test(input)) {
|
|
25869
|
+
return input.replace(pattern, `[REDACTED: ${label}]`);
|
|
25870
|
+
}
|
|
25571
25871
|
}
|
|
25872
|
+
return input;
|
|
25572
25873
|
}
|
|
25573
|
-
function
|
|
25574
|
-
|
|
25575
|
-
|
|
25576
|
-
|
|
25577
|
-
|
|
25578
|
-
|
|
25579
|
-
|
|
25580
|
-
|
|
25874
|
+
function isSecretName(name) {
|
|
25875
|
+
const upper = name.toUpperCase();
|
|
25876
|
+
if (SECRET_NAME_SUBSTRINGS.some((word) => upper.includes(word)))
|
|
25877
|
+
return true;
|
|
25878
|
+
return upper.split("_").some((part) => SECRET_NAME_COMPONENTS.includes(part));
|
|
25879
|
+
}
|
|
25880
|
+
function maskAssignedSecrets(input) {
|
|
25881
|
+
let out = input.replace(ASSIGNMENT_RE, (match, name, value) => {
|
|
25882
|
+
if (!isSecretName(name))
|
|
25883
|
+
return match;
|
|
25884
|
+
if (value.startsWith("[REDACTED"))
|
|
25885
|
+
return match;
|
|
25886
|
+
return `${name}=[REDACTED: assigned secret]`;
|
|
25887
|
+
});
|
|
25888
|
+
out = out.replace(URL_CREDENTIALS_RE, "$1[REDACTED: URL credentials]@");
|
|
25889
|
+
out = out.replace(BASIC_AUTH_FLAG_RE, "$1[REDACTED: basic auth]");
|
|
25890
|
+
return out;
|
|
25891
|
+
}
|
|
25892
|
+
function maskSecrets(input) {
|
|
25893
|
+
let out = input;
|
|
25894
|
+
for (const [pattern, label] of SECRET_PATTERNS) {
|
|
25895
|
+
const global = new RegExp(pattern.source, pattern.flags.includes("g") ? pattern.flags : `${pattern.flags}g`);
|
|
25896
|
+
out = out.replace(global, `[REDACTED: ${label}]`);
|
|
25581
25897
|
}
|
|
25582
|
-
return
|
|
25898
|
+
return out;
|
|
25583
25899
|
}
|
|
25584
|
-
function
|
|
25585
|
-
const
|
|
25586
|
-
|
|
25587
|
-
|
|
25588
|
-
|
|
25589
|
-
|
|
25590
|
-
|
|
25900
|
+
function shortenPaths(input, home = homedir25()) {
|
|
25901
|
+
const homeRoot = home.replace(/\/+$/, "");
|
|
25902
|
+
return input.replace(ABSOLUTE_PATH_RE, (match, offset, whole) => {
|
|
25903
|
+
if (PUBLIC_PATH_ROOTS.some((root2) => match.startsWith(root2)))
|
|
25904
|
+
return match;
|
|
25905
|
+
if (offset > 0 && whole[offset - 1] === "/" && /[a-z][a-z0-9+.\-]*:$/i.test(whole.slice(0, offset - 1))) {
|
|
25906
|
+
const urlSegments = match.split("/").filter(Boolean);
|
|
25907
|
+
if (urlSegments.length <= 1)
|
|
25908
|
+
return match;
|
|
25909
|
+
const host = urlSegments[0];
|
|
25910
|
+
const leaf = urlSegments[urlSegments.length - 1];
|
|
25911
|
+
const elided = urlSegments.length > 2 ? "/…" : "";
|
|
25912
|
+
return `/${host}${elided}/${leaf}${match.endsWith("/") ? "/" : ""}`;
|
|
25913
|
+
}
|
|
25914
|
+
const trailingSlash = match.endsWith("/");
|
|
25915
|
+
const segments = match.split("/").filter(Boolean);
|
|
25916
|
+
if (segments.length === 0)
|
|
25917
|
+
return match;
|
|
25918
|
+
const basename7 = segments[segments.length - 1];
|
|
25919
|
+
const kept = segments.slice(Math.max(0, segments.length - 1 - KEPT_PARENT_SEGMENTS), segments.length - 1);
|
|
25920
|
+
const matchRoot = match.replace(/\/+$/, "");
|
|
25921
|
+
const underHome = homeRoot.length > 0 && (matchRoot === homeRoot || matchRoot.startsWith(`${homeRoot}/`));
|
|
25922
|
+
if (matchRoot === homeRoot && homeRoot.length > 0) {
|
|
25923
|
+
return trailingSlash ? "~/" : "~";
|
|
25924
|
+
}
|
|
25925
|
+
const root = underHome ? "~" : "";
|
|
25926
|
+
const middle = segments.length - kept.length - 1 > 0 ? "/…" : "";
|
|
25927
|
+
const tail = [...kept, basename7].join("/");
|
|
25928
|
+
return `${root}${middle}/${tail}${trailingSlash ? "/" : ""}`;
|
|
25929
|
+
});
|
|
25930
|
+
}
|
|
25931
|
+
function redactExample(input, home = homedir25()) {
|
|
25932
|
+
const masked = maskAssignedSecrets(maskTruncatedSecret(maskSecrets(input)));
|
|
25933
|
+
const shortened = shortenPaths(masked, home);
|
|
25934
|
+
const collapsed = shortened.replace(/\s+/g, " ").trim();
|
|
25935
|
+
return collapsed.length > REDACTED_EXAMPLE_MAX_CHARS ? `${collapsed.slice(0, REDACTED_EXAMPLE_MAX_CHARS - 1)}…` : collapsed;
|
|
25936
|
+
}
|
|
25937
|
+
var REDACTED_EXAMPLE_MAX_CHARS = 160, KEPT_PARENT_SEGMENTS = 0, ABSOLUTE_PATH_RE, PUBLIC_PATH_ROOTS, SECRET_PREFIXES, SECRET_NAME_SUBSTRINGS, SECRET_NAME_COMPONENTS, ASSIGNMENT_RE, URL_CREDENTIALS_RE, BASIC_AUTH_FLAG_RE;
|
|
25938
|
+
var init_redact_example = __esm(() => {
|
|
25939
|
+
init_builtin_policies();
|
|
25940
|
+
ABSOLUTE_PATH_RE = /(?:\/[\w.\-@+]+){2,}\/?/g;
|
|
25941
|
+
PUBLIC_PATH_ROOTS = ["/dev/", "/proc/", "/sys/"];
|
|
25942
|
+
SECRET_PREFIXES = [
|
|
25943
|
+
[/(?<!\w)(?:Authorization:\s*)?Bearer\s+\S*$/i, "bearer token"],
|
|
25944
|
+
[/(?<!\w)sk-ant-\S*$/, "Anthropic API key"],
|
|
25945
|
+
[/(?<!\w)sk-proj-\S*$/, "OpenAI project API key"],
|
|
25946
|
+
[/(?<!\w)sk-\S*$/, "OpenAI API key"],
|
|
25947
|
+
[/(?<!\w)ghp_\S*$/, "GitHub personal access token"],
|
|
25948
|
+
[/(?<!\w)github_pat_\S*$/, "GitHub fine-grained token"],
|
|
25949
|
+
[/(?<!\w)AKIA\S*$/, "AWS access key ID"],
|
|
25950
|
+
[/(?<!\w)sk_live_\S*$/, "Stripe live secret key"],
|
|
25951
|
+
[/(?<!\w)sk_test_\S*$/, "Stripe test secret key"],
|
|
25952
|
+
[/(?<!\w)AIza\S*$/, "Google API key"],
|
|
25953
|
+
[/-----BEGIN\s[A-Z ]*$/, "private key"]
|
|
25954
|
+
];
|
|
25955
|
+
SECRET_NAME_SUBSTRINGS = [
|
|
25956
|
+
"TOKEN",
|
|
25957
|
+
"SECRET",
|
|
25958
|
+
"PASSWORD",
|
|
25959
|
+
"PASSWD",
|
|
25960
|
+
"CREDENTIAL",
|
|
25961
|
+
"APIKEY",
|
|
25962
|
+
"PRIVATEKEY"
|
|
25963
|
+
];
|
|
25964
|
+
SECRET_NAME_COMPONENTS = ["KEY", "PASS", "AUTH", "PAT", "SIG", "SIGNATURE", "SESSION", "COOKIE"];
|
|
25965
|
+
ASSIGNMENT_RE = /\b([A-Za-z_][A-Za-z0-9_]*)=("[^"]*"|'[^']*'|[^\s;|&"']+)/g;
|
|
25966
|
+
URL_CREDENTIALS_RE = /([a-z][a-z0-9+.\-]*:\/\/)[^\s/:@]+:[^\s/@]+@/gi;
|
|
25967
|
+
BASIC_AUTH_FLAG_RE = /((?:^|\s)(?:-u|--user)[\s=])\S+:\S+/g;
|
|
25968
|
+
});
|
|
25969
|
+
|
|
25970
|
+
// src/audit/harm-report.ts
|
|
25971
|
+
function shortName2(name) {
|
|
25972
|
+
const slash = name.indexOf("/");
|
|
25973
|
+
return slash === -1 ? name : name.slice(slash + 1);
|
|
25974
|
+
}
|
|
25975
|
+
function isHarmful(count) {
|
|
25976
|
+
if (count.source !== "builtin")
|
|
25977
|
+
return false;
|
|
25978
|
+
const short = shortName2(count.name);
|
|
25979
|
+
return HARMFUL_SEVERITIES.has(count.severity) || ALSO_HARMFUL.has(short);
|
|
25980
|
+
}
|
|
25981
|
+
function ts(value) {
|
|
25982
|
+
if (!value)
|
|
25983
|
+
return null;
|
|
25984
|
+
const n = Date.parse(value);
|
|
25985
|
+
return Number.isFinite(n) ? n : null;
|
|
25986
|
+
}
|
|
25987
|
+
function selectHarmful(result, from, to, opts = {}) {
|
|
25988
|
+
const includeUnplaceable = opts.includeUnplaceable ?? from === undefined;
|
|
25989
|
+
const fromMs = from ? from.getTime() : null;
|
|
25990
|
+
const toMs2 = to.getTime();
|
|
25991
|
+
const out = [];
|
|
25992
|
+
for (const count of result.results) {
|
|
25993
|
+
if (!isHarmful(count))
|
|
25994
|
+
continue;
|
|
25995
|
+
const last = ts(count.lastSeen);
|
|
25996
|
+
const first = ts(count.firstSeen);
|
|
25997
|
+
if (fromMs !== null && last !== null && last <= fromMs)
|
|
25998
|
+
continue;
|
|
25999
|
+
if (first !== null && first > toMs2)
|
|
26000
|
+
continue;
|
|
26001
|
+
const inWindow = count.examples.filter((e) => {
|
|
26002
|
+
const at2 = ts(e.timestamp);
|
|
26003
|
+
if (at2 === null)
|
|
26004
|
+
return includeUnplaceable;
|
|
26005
|
+
if (fromMs !== null && at2 <= fromMs)
|
|
26006
|
+
return false;
|
|
26007
|
+
return at2 <= toMs2;
|
|
26008
|
+
});
|
|
26009
|
+
const unplaceable = last === null && first === null;
|
|
26010
|
+
if (unplaceable && !includeUnplaceable)
|
|
26011
|
+
continue;
|
|
26012
|
+
const afterLowerEdge = fromMs === null || first !== null && first > fromMs;
|
|
26013
|
+
const beforeUpperEdge = last !== null && last <= toMs2;
|
|
26014
|
+
const wholly = unplaceable || afterLowerEdge && beforeUpperEdge;
|
|
26015
|
+
const floor = beforeUpperEdge ? 1 : 0;
|
|
26016
|
+
const hits = wholly ? count.hits : Math.max(inWindow.length, floor);
|
|
26017
|
+
if (hits <= 0)
|
|
26018
|
+
continue;
|
|
26019
|
+
out.push({
|
|
26020
|
+
policy: shortName2(count.name),
|
|
26021
|
+
category: count.category,
|
|
26022
|
+
title: count.displayTitle ?? "",
|
|
26023
|
+
hits,
|
|
26024
|
+
first_seen: count.firstSeen,
|
|
26025
|
+
last_seen: count.lastSeen,
|
|
26026
|
+
examples: inWindow.map((e) => redactExample(e.example)).filter((e) => e.length > 0)
|
|
26027
|
+
});
|
|
26028
|
+
}
|
|
26029
|
+
out.sort((a, b) => b.hits - a.hits);
|
|
26030
|
+
return out;
|
|
26031
|
+
}
|
|
26032
|
+
function buildHarmReport(result, lastReportedAt, intervalDays) {
|
|
26033
|
+
const to = new Date(Date.parse(result.scannedAt));
|
|
26034
|
+
const windowTo = Number.isFinite(to.getTime()) ? to : new Date;
|
|
26035
|
+
const watermark = ts(lastReportedAt);
|
|
26036
|
+
const isFirstReport = watermark === null;
|
|
26037
|
+
const oneInterval = Math.max(1, intervalDays) * 86400000;
|
|
26038
|
+
const fallbackFrom = windowTo.getTime() - oneInterval;
|
|
26039
|
+
const from = new Date(isFirstReport || watermark >= windowTo.getTime() ? fallbackFrom : watermark);
|
|
26040
|
+
return {
|
|
26041
|
+
window_from: from.toISOString(),
|
|
26042
|
+
window_to: windowTo.toISOString(),
|
|
26043
|
+
harmful: selectHarmful(result, from, windowTo, { includeUnplaceable: isFirstReport })
|
|
26044
|
+
};
|
|
26045
|
+
}
|
|
26046
|
+
var HARMFUL_SEVERITIES, ALSO_HARMFUL;
|
|
26047
|
+
var init_harm_report = __esm(() => {
|
|
26048
|
+
init_redact_example();
|
|
26049
|
+
HARMFUL_SEVERITIES = new Set(["deny", "sanitize"]);
|
|
26050
|
+
ALSO_HARMFUL = new Set(["protect-env-vars"]);
|
|
26051
|
+
});
|
|
26052
|
+
|
|
26053
|
+
// src/audit/machine-store.ts
|
|
26054
|
+
import { existsSync as existsSync33, readFileSync as readFileSync28, rmSync as rmSync13 } from "node:fs";
|
|
26055
|
+
import { hostname as hostname5 } from "node:os";
|
|
26056
|
+
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
26057
|
+
function readMachineIdentity(home) {
|
|
26058
|
+
const path3 = auditMachineFile(home);
|
|
26059
|
+
if (!existsSync33(path3))
|
|
26060
|
+
return null;
|
|
26061
|
+
try {
|
|
26062
|
+
const parsed = JSON.parse(readFileSync28(path3, "utf8"));
|
|
26063
|
+
if (typeof parsed.machine_id !== "string" || !parsed.machine_id)
|
|
26064
|
+
return null;
|
|
26065
|
+
return {
|
|
26066
|
+
machine_id: parsed.machine_id,
|
|
26067
|
+
last_reported_at: typeof parsed.last_reported_at === "string" ? parsed.last_reported_at : undefined,
|
|
26068
|
+
created_at: typeof parsed.created_at === "string" ? parsed.created_at : new Date(0).toISOString()
|
|
26069
|
+
};
|
|
26070
|
+
} catch {
|
|
26071
|
+
return null;
|
|
26072
|
+
}
|
|
26073
|
+
}
|
|
26074
|
+
function ensureMachineIdentity(home) {
|
|
26075
|
+
const existing = readMachineIdentity(home);
|
|
26076
|
+
if (existing)
|
|
26077
|
+
return existing;
|
|
26078
|
+
const fresh = {
|
|
26079
|
+
machine_id: randomUUID4(),
|
|
26080
|
+
created_at: new Date().toISOString()
|
|
26081
|
+
};
|
|
26082
|
+
writeJsonAtomically(auditMachineFile(home), fresh);
|
|
26083
|
+
return fresh;
|
|
26084
|
+
}
|
|
26085
|
+
function recordReportWatermark(nextWindowFrom, home) {
|
|
26086
|
+
const current = ensureMachineIdentity(home);
|
|
26087
|
+
writeJsonAtomically(auditMachineFile(home), {
|
|
26088
|
+
...current,
|
|
26089
|
+
last_reported_at: nextWindowFrom
|
|
26090
|
+
});
|
|
26091
|
+
}
|
|
26092
|
+
function machineLabel() {
|
|
26093
|
+
try {
|
|
26094
|
+
const h = hostname5().trim();
|
|
26095
|
+
return h.length > 0 ? h : undefined;
|
|
26096
|
+
} catch {
|
|
26097
|
+
return;
|
|
26098
|
+
}
|
|
26099
|
+
}
|
|
26100
|
+
var init_machine_store = __esm(() => {
|
|
26101
|
+
init_atomic_write();
|
|
26102
|
+
init_fp_home();
|
|
26103
|
+
});
|
|
26104
|
+
|
|
26105
|
+
// src/audit/report-harm.ts
|
|
26106
|
+
async function reportHarm(result) {
|
|
26107
|
+
let auto = false;
|
|
26108
|
+
let consentedAt;
|
|
26109
|
+
let intervalDays = 7;
|
|
26110
|
+
try {
|
|
26111
|
+
const config = readConfig();
|
|
26112
|
+
auto = config.audit.auto;
|
|
26113
|
+
consentedAt = config.audit.reportsConsentedAt;
|
|
26114
|
+
intervalDays = config.audit.intervalDays;
|
|
26115
|
+
} catch {
|
|
26116
|
+
return { kind: "disabled" };
|
|
26117
|
+
}
|
|
26118
|
+
if (!auto)
|
|
26119
|
+
return { kind: "disabled" };
|
|
26120
|
+
if (consentedAt === undefined)
|
|
26121
|
+
return { kind: "consent-required" };
|
|
26122
|
+
const auth = await getValidAccessToken();
|
|
26123
|
+
if (!auth) {
|
|
26124
|
+
return { kind: "signed-out" };
|
|
26125
|
+
}
|
|
26126
|
+
let identity2;
|
|
26127
|
+
try {
|
|
26128
|
+
identity2 = ensureMachineIdentity();
|
|
26129
|
+
} catch (err) {
|
|
26130
|
+
return { kind: "failed", error: err instanceof Error ? err.message : String(err) };
|
|
26131
|
+
}
|
|
26132
|
+
const report = buildHarmReport(result, identity2.last_reported_at, intervalDays);
|
|
26133
|
+
const hits = report.harmful.reduce((n, p) => n + p.hits, 0);
|
|
26134
|
+
try {
|
|
26135
|
+
const res = await submitAuditReport(auth.access_token, {
|
|
26136
|
+
machine_id: identity2.machine_id,
|
|
26137
|
+
label: machineLabel(),
|
|
26138
|
+
platform: process.platform,
|
|
26139
|
+
window_from: report.window_from,
|
|
26140
|
+
window_to: report.window_to,
|
|
26141
|
+
harmful: report.harmful
|
|
26142
|
+
});
|
|
26143
|
+
try {
|
|
26144
|
+
recordReportWatermark(res.next_window_from);
|
|
26145
|
+
} catch {}
|
|
26146
|
+
return res.emailed ? { kind: "sent", hits } : { kind: "held", hits, reason: res.reason ?? "not_sent" };
|
|
26147
|
+
} catch (err) {
|
|
26148
|
+
const error = err instanceof AuthApiError ? `${err.code}: ${err.message}` : err instanceof Error ? err.message : String(err);
|
|
26149
|
+
return { kind: "failed", error };
|
|
26150
|
+
}
|
|
26151
|
+
}
|
|
26152
|
+
function describeOutcome2(outcome) {
|
|
26153
|
+
switch (outcome.kind) {
|
|
26154
|
+
case "disabled":
|
|
26155
|
+
return null;
|
|
26156
|
+
case "consent-required":
|
|
26157
|
+
return "failproofai: scheduled scans are on, but emailing what they find needs a fresh opt-in — run `failproofai audit --schedule` (or visit /settings) to turn digests on";
|
|
26158
|
+
case "signed-out":
|
|
26159
|
+
return "failproofai: emailed reports are on but this machine is signed out — run `failproofai audit --schedule` or visit /settings to resume them";
|
|
26160
|
+
case "sent":
|
|
26161
|
+
return `failproofai: emailed a harm digest (${outcome.hits} finding${outcome.hits === 1 ? "" : "s"})`;
|
|
26162
|
+
case "held":
|
|
26163
|
+
return `failproofai: ${outcome.hits} finding${outcome.hits === 1 ? "" : "s"} reported, no email (${outcome.reason})`;
|
|
26164
|
+
case "failed":
|
|
26165
|
+
return `failproofai: could not send the harm report: ${outcome.error}`;
|
|
26166
|
+
}
|
|
26167
|
+
}
|
|
26168
|
+
var init_report_harm = __esm(() => {
|
|
26169
|
+
init_auth_store();
|
|
26170
|
+
init_api_server_client();
|
|
26171
|
+
init_fp_config();
|
|
26172
|
+
init_harm_report();
|
|
26173
|
+
init_machine_store();
|
|
26174
|
+
});
|
|
26175
|
+
|
|
26176
|
+
// src/audit/audit-schedule.ts
|
|
26177
|
+
import { readFileSync as readFileSync29 } from "node:fs";
|
|
26178
|
+
function readAuditSchedule(home) {
|
|
26179
|
+
let raw;
|
|
26180
|
+
try {
|
|
26181
|
+
raw = readFileSync29(auditScheduleFile(home), "utf8");
|
|
26182
|
+
} catch {
|
|
26183
|
+
return null;
|
|
26184
|
+
}
|
|
26185
|
+
let parsed;
|
|
26186
|
+
try {
|
|
26187
|
+
parsed = JSON.parse(raw);
|
|
26188
|
+
} catch {
|
|
26189
|
+
return null;
|
|
26190
|
+
}
|
|
26191
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
26192
|
+
return null;
|
|
26193
|
+
const obj = parsed;
|
|
26194
|
+
const num = (v) => typeof v === "number" && Number.isFinite(v) ? v : null;
|
|
26195
|
+
const schema = num(obj.schema);
|
|
26196
|
+
return {
|
|
26197
|
+
schema,
|
|
26198
|
+
nextDueAtMs: num(obj.next_due_at_ms),
|
|
26199
|
+
lastAttemptAtMs: num(obj.last_attempt_at_ms),
|
|
26200
|
+
lastRunAtMs: num(obj.last_run_at_ms),
|
|
26201
|
+
lastExitCode: num(obj.last_exit_code),
|
|
26202
|
+
schemaAhead: schema !== null && schema > AUDIT_SCHEDULE_SCHEMA
|
|
26203
|
+
};
|
|
26204
|
+
}
|
|
26205
|
+
var AUDIT_SCHEDULE_SCHEMA = 1;
|
|
26206
|
+
var init_audit_schedule = __esm(() => {
|
|
26207
|
+
init_fp_home();
|
|
26208
|
+
});
|
|
26209
|
+
|
|
26210
|
+
// src/audit/cli-login.ts
|
|
26211
|
+
var exports_cli_login = {};
|
|
26212
|
+
__export(exports_cli_login, {
|
|
26213
|
+
runLogin: () => runLogin,
|
|
26214
|
+
invalidEmail: () => invalidEmail,
|
|
26215
|
+
extractCode: () => extractCode,
|
|
26216
|
+
ensureSignedIn: () => ensureSignedIn,
|
|
26217
|
+
canPrompt: () => canPrompt,
|
|
26218
|
+
LoginError: () => LoginError
|
|
26219
|
+
});
|
|
26220
|
+
function spine() {
|
|
26221
|
+
return colorsEnabled(process.stdout) ? `${ANSI_DIM_BAR}${BAR}${ANSI_RESET} ` : "";
|
|
26222
|
+
}
|
|
26223
|
+
function extractCode(raw) {
|
|
26224
|
+
const trimmed = raw.trim();
|
|
26225
|
+
if (/^\d+$/.test(trimmed))
|
|
26226
|
+
return trimmed;
|
|
26227
|
+
const runs = trimmed.match(/\d+/g) ?? [];
|
|
26228
|
+
if (runs.length === 0)
|
|
26229
|
+
return trimmed;
|
|
26230
|
+
const whole = runs.find((run) => run.length >= CODE_MIN);
|
|
26231
|
+
if (whole)
|
|
26232
|
+
return whole;
|
|
26233
|
+
return runs.join("");
|
|
26234
|
+
}
|
|
26235
|
+
function canPrompt() {
|
|
26236
|
+
return Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
26237
|
+
}
|
|
26238
|
+
function sessionStillValid(auth) {
|
|
26239
|
+
if (!auth)
|
|
26240
|
+
return null;
|
|
26241
|
+
return auth.refresh_expires_at * 1000 > Date.now() ? auth : null;
|
|
26242
|
+
}
|
|
26243
|
+
async function ensureSignedIn(preset) {
|
|
26244
|
+
const existing = sessionStillValid(readAuth());
|
|
26245
|
+
if (existing) {
|
|
26246
|
+
if (preset && !sameAddress(preset, existing.user.email)) {
|
|
26247
|
+
throw new LoginError(`This machine is already signed in as ${existing.user.email}.
|
|
26248
|
+
` + `To report as ${preset.trim().toLowerCase()} instead, sign out first — ` + `from the dashboard, or by removing ~/.failproofai/audit/session.json.`);
|
|
26249
|
+
}
|
|
26250
|
+
return { user: existing.user, prompted: false };
|
|
26251
|
+
}
|
|
26252
|
+
if (!canPrompt()) {
|
|
26253
|
+
throw new LoginError(`Signing in needs an interactive terminal, and this one is not.
|
|
26254
|
+
` + "Run `failproofai audit --schedule` from a shell you are sitting at,\n" + "or sign in from the dashboard — both write the same session file.");
|
|
26255
|
+
}
|
|
26256
|
+
return { user: await runLogin(preset), prompted: true };
|
|
26257
|
+
}
|
|
26258
|
+
function sameAddress(a, b) {
|
|
26259
|
+
return a.trim().toLowerCase() === b.trim().toLowerCase();
|
|
26260
|
+
}
|
|
26261
|
+
function invalidEmail(address) {
|
|
26262
|
+
return EMAIL_RE.test(address.trim()) ? null : `\`--email\` needs an email address (got: ${address}).`;
|
|
26263
|
+
}
|
|
26264
|
+
async function runLogin(preset) {
|
|
26265
|
+
intro("scheduled audits need somewhere to send the report");
|
|
26266
|
+
let address;
|
|
26267
|
+
if (preset) {
|
|
26268
|
+
address = preset.trim().toLowerCase();
|
|
26269
|
+
step("your email", address);
|
|
26270
|
+
} else {
|
|
26271
|
+
const email = await promptText({
|
|
26272
|
+
prefix: spine(),
|
|
26273
|
+
message: "your email",
|
|
26274
|
+
hint: "you@yourdomain.com",
|
|
26275
|
+
validate: (v) => EMAIL_RE.test(v.trim()) ? null : "that doesn't look like an email"
|
|
26276
|
+
});
|
|
26277
|
+
if (email === null) {
|
|
26278
|
+
outro("Cancelled — nothing was changed.", { ok: false });
|
|
26279
|
+
throw new LoginError("Cancelled.");
|
|
26280
|
+
}
|
|
26281
|
+
address = email.trim().toLowerCase();
|
|
26282
|
+
}
|
|
26283
|
+
let expiresInMin = 10;
|
|
26284
|
+
try {
|
|
26285
|
+
const sent = await requestLoginCode(address);
|
|
26286
|
+
expiresInMin = Math.max(1, Math.ceil(sent.expires_in / 60));
|
|
26287
|
+
} catch (err) {
|
|
26288
|
+
outro("Could not send a login code.", { ok: false });
|
|
26289
|
+
throw new LoginError(describeAuthError(err, "Could not send a login code"));
|
|
26290
|
+
}
|
|
26291
|
+
step("code sent", `to ${address} · expires in ${expiresInMin} min`);
|
|
26292
|
+
const ATTEMPTS = 3;
|
|
26293
|
+
for (let attempt = 1;attempt <= ATTEMPTS; attempt += 1) {
|
|
26294
|
+
stepOpen(attempt === 1 ? "the code from that email" : "try that code again");
|
|
26295
|
+
const typed = await promptText({
|
|
26296
|
+
prefix: spine(),
|
|
26297
|
+
message: "code",
|
|
26298
|
+
hint: attempt === 1 ? "123456 · paste the whole line if you like" : `attempt ${attempt} of ${ATTEMPTS}`,
|
|
26299
|
+
validate: (v) => {
|
|
26300
|
+
if (!/\d/.test(v))
|
|
26301
|
+
return "a code is digits — paste the line from the email";
|
|
26302
|
+
const code = extractCode(v);
|
|
26303
|
+
if (code.length < CODE_MIN)
|
|
26304
|
+
return "that looks too short to be the code";
|
|
26305
|
+
if (code.length > CODE_MAX)
|
|
26306
|
+
return "that looks too long — paste just the code";
|
|
26307
|
+
return null;
|
|
26308
|
+
}
|
|
26309
|
+
});
|
|
26310
|
+
if (typed === null) {
|
|
26311
|
+
outro("Cancelled — nothing was changed.", { ok: false });
|
|
26312
|
+
throw new LoginError("Cancelled.");
|
|
26313
|
+
}
|
|
26314
|
+
try {
|
|
26315
|
+
const tokens = await verifyLoginCode(address, extractCode(typed));
|
|
26316
|
+
writeAuth(authFromTokenResponse(tokens));
|
|
26317
|
+
step("signed in", tokens.user.email);
|
|
26318
|
+
return { id: tokens.user.id, email: tokens.user.email };
|
|
26319
|
+
} catch (err) {
|
|
26320
|
+
const wrongCode = err instanceof AuthApiError && err.code === "invalid_code";
|
|
26321
|
+
if (wrongCode && attempt < ATTEMPTS) {
|
|
26322
|
+
step("that code was wrong or expired", `${ATTEMPTS - attempt} more ${ATTEMPTS - attempt === 1 ? "try" : "tries"} before it asks for a new one`);
|
|
26323
|
+
continue;
|
|
26324
|
+
}
|
|
26325
|
+
outro("Could not verify that code.", { ok: false });
|
|
26326
|
+
throw new LoginError(describeAuthError(err, "Could not verify that code"));
|
|
26327
|
+
}
|
|
26328
|
+
}
|
|
26329
|
+
outro("Too many wrong codes.", { ok: false });
|
|
26330
|
+
throw new LoginError("Too many wrong codes. Run the command again for a fresh one.");
|
|
26331
|
+
}
|
|
26332
|
+
function describeAuthError(err, prefix) {
|
|
26333
|
+
if (err instanceof AuthApiError) {
|
|
26334
|
+
if (err.code === "rate_limited") {
|
|
26335
|
+
const wait = err.retryAfterSecs;
|
|
26336
|
+
return `${prefix}: too many attempts.${wait ? ` Try again in ${wait}s.` : ""}`;
|
|
26337
|
+
}
|
|
26338
|
+
if (err.status === 0 || err.code === "timeout") {
|
|
26339
|
+
return `${prefix}: the api-server did not respond.
|
|
26340
|
+
` + `It is at ${apiBaseForMessage()} — check that it is running,
|
|
26341
|
+
` + `or set FAILPROOF_API_URL to point somewhere else.`;
|
|
26342
|
+
}
|
|
26343
|
+
return `${prefix}: ${err.message}`;
|
|
26344
|
+
}
|
|
26345
|
+
return `${prefix}: ${err instanceof Error ? err.message : String(err)}`;
|
|
26346
|
+
}
|
|
26347
|
+
function apiBaseForMessage() {
|
|
26348
|
+
return process.env.FAILPROOF_API_URL ?? process.env.FAILPROOFAI_API_URL ?? "https://api.befailproof.ai";
|
|
26349
|
+
}
|
|
26350
|
+
var EMAIL_RE, CODE_MIN = 4, CODE_MAX = 12, ANSI_DIM_BAR = "\x1B[2m", LoginError;
|
|
26351
|
+
var init_cli_login = __esm(() => {
|
|
26352
|
+
init_api_server_client();
|
|
26353
|
+
init_auth_store();
|
|
26354
|
+
init_tui();
|
|
26355
|
+
EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
26356
|
+
LoginError = class LoginError extends Error {
|
|
26357
|
+
};
|
|
26358
|
+
});
|
|
26359
|
+
|
|
26360
|
+
// src/audit/schedule-cli.ts
|
|
26361
|
+
var exports_schedule_cli = {};
|
|
26362
|
+
__export(exports_schedule_cli, {
|
|
26363
|
+
runScheduleStatus: () => runScheduleStatus,
|
|
26364
|
+
runScheduleOn: () => runScheduleOn,
|
|
26365
|
+
runScheduleOff: () => runScheduleOff,
|
|
26366
|
+
asScheduleError: () => asScheduleError,
|
|
26367
|
+
ScheduleCliError: () => ScheduleCliError
|
|
26368
|
+
});
|
|
26369
|
+
function row(label, value, note) {
|
|
26370
|
+
const gap = " ".repeat(Math.max(1, LABEL_WIDTH - label.length));
|
|
26371
|
+
return `${rail()} ${dim(label)}${gap}${value}${note ? ` ${dim(note)}` : ""}`;
|
|
26372
|
+
}
|
|
26373
|
+
async function runScheduleOn(daysArg, emailArg) {
|
|
26374
|
+
let days;
|
|
26375
|
+
if (daysArg !== undefined) {
|
|
26376
|
+
const parsed = Number(daysArg);
|
|
26377
|
+
if (!Number.isFinite(parsed) || !Number.isInteger(parsed)) {
|
|
26378
|
+
throw new ScheduleCliError(`\`--schedule\` takes a whole number of days (got: ${daysArg}).`);
|
|
26379
|
+
}
|
|
26380
|
+
if (parsed < MIN_DAYS || parsed > MAX_DAYS) {
|
|
26381
|
+
throw new ScheduleCliError(`\`--schedule\` must be between ${MIN_DAYS} and ${MAX_DAYS} days (got: ${parsed}).`);
|
|
26382
|
+
}
|
|
26383
|
+
days = parsed;
|
|
26384
|
+
}
|
|
26385
|
+
if (emailArg !== undefined) {
|
|
26386
|
+
const bad = invalidEmail(emailArg);
|
|
26387
|
+
if (bad)
|
|
26388
|
+
throw new ScheduleCliError(bad);
|
|
26389
|
+
}
|
|
26390
|
+
const { user, prompted } = await ensureSignedIn(emailArg);
|
|
26391
|
+
const next = updateConfig({
|
|
26392
|
+
audit: {
|
|
26393
|
+
auto: true,
|
|
26394
|
+
reportsConsentedAt: Date.now(),
|
|
26395
|
+
...days !== undefined ? { intervalDays: days } : {}
|
|
26396
|
+
}
|
|
26397
|
+
});
|
|
26398
|
+
const interval = next.audit.intervalDays;
|
|
26399
|
+
const summary = [
|
|
26400
|
+
`every ${interval} day${interval === 1 ? "" : "s"} · reports to ${user.email}`,
|
|
26401
|
+
"you only hear from it when a scan finds something harmful",
|
|
26402
|
+
"each report sends: finding counts, redacted example commands, this machine's name"
|
|
26403
|
+
];
|
|
26404
|
+
if (prompted) {
|
|
26405
|
+
step("scheduled audits are on", summary);
|
|
26406
|
+
} else {
|
|
26407
|
+
process.stdout.write(`
|
|
26408
|
+
${green("✓")} ${bold("scheduled audits are on")}
|
|
26409
|
+
` + summary.map((r) => ` ${dim(r)}
|
|
26410
|
+
`).join(""));
|
|
26411
|
+
}
|
|
26412
|
+
warnIfDaemonWontRun();
|
|
26413
|
+
if (prompted) {
|
|
26414
|
+
outro("failproofai audit --status · when the next scan is due");
|
|
26415
|
+
} else {
|
|
26416
|
+
process.stdout.write(dim(`
|
|
26417
|
+
failproofai audit --status when the next scan is due
|
|
26418
|
+
|
|
26419
|
+
`));
|
|
26420
|
+
}
|
|
26421
|
+
}
|
|
26422
|
+
function runScheduleOff() {
|
|
26423
|
+
const before = readConfig().audit.auto;
|
|
26424
|
+
const next = updateConfig({ audit: { auto: false } });
|
|
26425
|
+
if (next.audit.auto) {
|
|
26426
|
+
process.stdout.write(`Could not turn scheduled audits off.
|
|
26427
|
+
`);
|
|
26428
|
+
return;
|
|
26429
|
+
}
|
|
26430
|
+
if (!before) {
|
|
26431
|
+
process.stdout.write(dim(`
|
|
26432
|
+
Scheduled audits were already off.
|
|
26433
|
+
|
|
26434
|
+
`));
|
|
26435
|
+
return;
|
|
26436
|
+
}
|
|
26437
|
+
process.stdout.write(`
|
|
26438
|
+
${green("✓")} ${bold("scheduled audits are off")}
|
|
26439
|
+
` + ` ${dim("nothing runs on a timer and nothing is sent")}
|
|
26440
|
+
` + ` ${dim("your session is untouched — sign out from the dashboard for that")}
|
|
26441
|
+
|
|
26442
|
+
`);
|
|
26443
|
+
}
|
|
26444
|
+
function runScheduleStatus() {
|
|
26445
|
+
const config = readConfig();
|
|
26446
|
+
const auth = readAuth();
|
|
26447
|
+
const sched = readAuditSchedule();
|
|
26448
|
+
const meta = readDashboardCacheMeta();
|
|
26449
|
+
const machine = readMachineIdentity();
|
|
26450
|
+
const daemon = daemonServiceStatus();
|
|
26451
|
+
const on = config.audit.auto;
|
|
26452
|
+
const out = [""];
|
|
26453
|
+
out.push(`${rail()} ${bold("scheduled audit")} ${on ? green("on") : dim("off")}` + (on ? dim(` every ${config.audit.intervalDays} days`) : ""));
|
|
26454
|
+
out.push(rail());
|
|
26455
|
+
const live = auth && auth.refresh_expires_at * 1000 > Date.now() ? auth : null;
|
|
26456
|
+
out.push(row("reports to", live ? live.user.email : dim("— signed out")));
|
|
26457
|
+
if (on && !live) {
|
|
26458
|
+
out.push(row("", pink("scans continue; digests are paused until you sign in")));
|
|
26459
|
+
} else if (on && config.audit.reportsConsentedAt === undefined) {
|
|
26460
|
+
out.push(row("", pink("scans continue; digests need a fresh opt-in — run `--schedule` to turn them on")));
|
|
26461
|
+
}
|
|
26462
|
+
out.push(row("daemon", describeDaemon(daemon)));
|
|
26463
|
+
if (sched?.nextDueAtMs != null && on) {
|
|
26464
|
+
out.push(row("next scan", untilPhrase(sched.nextDueAtMs)));
|
|
26465
|
+
}
|
|
26466
|
+
if (sched?.lastRunAtMs != null) {
|
|
26467
|
+
const exit = sched.lastExitCode;
|
|
26468
|
+
out.push(row("last scheduled", agoPhrase(sched.lastRunAtMs), exit != null && exit !== 0 && exit !== 75 ? pink(`exit ${exit}`) : undefined));
|
|
26469
|
+
}
|
|
26470
|
+
out.push(row("last result", meta?.cachedAt ? agoPhrase(Date.parse(meta.cachedAt)) : dim("none yet")));
|
|
26471
|
+
if (machine?.last_reported_at) {
|
|
26472
|
+
out.push(row("last reported", agoPhrase(Date.parse(machine.last_reported_at))));
|
|
26473
|
+
}
|
|
26474
|
+
out.push("");
|
|
26475
|
+
process.stdout.write(out.join(`
|
|
26476
|
+
`));
|
|
26477
|
+
}
|
|
26478
|
+
function describeDaemon(status) {
|
|
26479
|
+
switch (status) {
|
|
26480
|
+
case "running":
|
|
26481
|
+
return green("running");
|
|
26482
|
+
case "stopped":
|
|
26483
|
+
return pink("stopped — run `failproofai config` to repair it");
|
|
26484
|
+
case "not-installed":
|
|
26485
|
+
return pink("not installed — run `failproofai config`");
|
|
26486
|
+
case "condition-failed":
|
|
26487
|
+
return pink("installed but its binary is missing — run `failproofai config`");
|
|
26488
|
+
default:
|
|
26489
|
+
return isDaemonSupportedPlatform() ? dim(String(status)) : dim("unavailable on this platform");
|
|
26490
|
+
}
|
|
26491
|
+
}
|
|
26492
|
+
function warnIfDaemonWontRun() {
|
|
26493
|
+
const status = daemonServiceStatus();
|
|
26494
|
+
if (status === "running")
|
|
26495
|
+
return;
|
|
26496
|
+
if (status === "unknown")
|
|
26497
|
+
return;
|
|
26498
|
+
if (!isDaemonSupportedPlatform()) {
|
|
26499
|
+
process.stderr.write(`
|
|
26500
|
+
${pink("!")} The background service is not available on this platform,
|
|
26501
|
+
` + ` so nothing will run on the timer here. \`failproofai audit\` still works.
|
|
26502
|
+
`);
|
|
26503
|
+
return;
|
|
26504
|
+
}
|
|
26505
|
+
process.stderr.write(`
|
|
26506
|
+
${pink("!")} The background service is ${status.replace("-", " ")}, ` + `so nothing will run on the timer yet.
|
|
26507
|
+
` + ` Run \`failproofai config\` to install or repair it.
|
|
26508
|
+
`);
|
|
26509
|
+
}
|
|
26510
|
+
function untilPhrase(ms) {
|
|
26511
|
+
const diff = ms - Date.now();
|
|
26512
|
+
if (diff <= 0)
|
|
26513
|
+
return "due now";
|
|
26514
|
+
const d = Math.floor(diff / 86400000);
|
|
26515
|
+
const h = Math.floor(diff % 86400000 / 3600000);
|
|
26516
|
+
if (d > 0)
|
|
26517
|
+
return `in ${d}d${h > 0 ? ` ${h}h` : ""}`;
|
|
26518
|
+
if (h > 0)
|
|
26519
|
+
return `in ${h}h`;
|
|
26520
|
+
return `in ${Math.max(1, Math.floor(diff / 60000))}m`;
|
|
26521
|
+
}
|
|
26522
|
+
function agoPhrase(ms) {
|
|
26523
|
+
if (!Number.isFinite(ms))
|
|
26524
|
+
return "unknown";
|
|
26525
|
+
const diff = Date.now() - ms;
|
|
26526
|
+
if (diff < 0)
|
|
26527
|
+
return "just now";
|
|
26528
|
+
const d = Math.floor(diff / 86400000);
|
|
26529
|
+
const h = Math.floor(diff / 3600000);
|
|
26530
|
+
const m = Math.floor(diff / 60000);
|
|
26531
|
+
if (d > 0)
|
|
26532
|
+
return `${d}d ago`;
|
|
26533
|
+
if (h > 0)
|
|
26534
|
+
return `${h}h ago`;
|
|
26535
|
+
if (m > 0)
|
|
26536
|
+
return `${m}m ago`;
|
|
26537
|
+
return "just now";
|
|
26538
|
+
}
|
|
26539
|
+
function asScheduleError(err) {
|
|
26540
|
+
if (err instanceof LoginError || err instanceof ScheduleCliError) {
|
|
26541
|
+
throw new ScheduleCliError(err.message);
|
|
26542
|
+
}
|
|
26543
|
+
throw err;
|
|
26544
|
+
}
|
|
26545
|
+
var MIN_DAYS = 1, MAX_DAYS = 90, ScheduleCliError, styled = () => colorsEnabled(process.stdout), wrap = (open2, s) => styled() ? `${open2}${s}${ANSI_RESET}` : s, pink = (s) => wrap(brandAnsi("pink"), s), green = (s) => wrap(brandAnsi("guide"), s), dim = (s) => wrap(ANSI_DIM, s), bold = (s) => wrap(ANSI_BOLD, s), rail = () => " ", LABEL_WIDTH = 15;
|
|
26546
|
+
var init_schedule_cli = __esm(() => {
|
|
26547
|
+
init_fp_config();
|
|
26548
|
+
init_daemon_service();
|
|
26549
|
+
init_auth_store();
|
|
26550
|
+
init_audit_schedule();
|
|
26551
|
+
init_dashboard_cache();
|
|
26552
|
+
init_machine_store();
|
|
26553
|
+
init_cli_login();
|
|
26554
|
+
init_tui();
|
|
26555
|
+
ScheduleCliError = class ScheduleCliError extends Error {
|
|
26556
|
+
};
|
|
26557
|
+
});
|
|
26558
|
+
|
|
26559
|
+
// scripts/parse-script-args.ts
|
|
26560
|
+
import { resolve as resolve23 } from "path";
|
|
26561
|
+
function parseStringFlag(flagName, errorLabel, inlineValue, args, index, options) {
|
|
26562
|
+
const raw = inlineValue ?? args[index + 1];
|
|
26563
|
+
if (raw === undefined || inlineValue === null && raw.startsWith("-")) {
|
|
26564
|
+
console.error(`Error: ${flagName} requires ${errorLabel}`);
|
|
26565
|
+
process.exit(1);
|
|
26566
|
+
}
|
|
26567
|
+
const value = options?.resolve ? resolve23(raw) : raw;
|
|
26568
|
+
return { value, spliceCount: inlineValue !== null ? 1 : 2 };
|
|
26569
|
+
}
|
|
26570
|
+
function parseScriptArgs(argv) {
|
|
26571
|
+
const args = [...argv];
|
|
26572
|
+
let loggingLevel;
|
|
26573
|
+
let disableTelemetry = false;
|
|
26574
|
+
let allowedDevOrigins;
|
|
26575
|
+
let host;
|
|
26576
|
+
for (let i = 0;i < args.length; i++) {
|
|
26577
|
+
const arg = args[i];
|
|
26578
|
+
const eqIdx = arg.indexOf("=");
|
|
26579
|
+
const flag = eqIdx >= 0 ? arg.slice(0, eqIdx) : arg;
|
|
26580
|
+
const inlineValue = eqIdx >= 0 ? arg.slice(eqIdx + 1) : null;
|
|
26581
|
+
if (flag === "--logging") {
|
|
26582
|
+
const raw = inlineValue ?? args[i + 1];
|
|
26583
|
+
if (raw === undefined || inlineValue === null && raw.startsWith("-")) {
|
|
26584
|
+
console.error("Error: --logging requires a level (info, warn, error)");
|
|
26585
|
+
process.exit(1);
|
|
26586
|
+
}
|
|
26587
|
+
const val = raw.toLowerCase();
|
|
26588
|
+
if (val !== "info" && val !== "warn" && val !== "error") {
|
|
26589
|
+
console.error("Error: --logging must be one of: info, warn, error");
|
|
26590
|
+
process.exit(1);
|
|
26591
|
+
}
|
|
26592
|
+
loggingLevel = val;
|
|
26593
|
+
args.splice(i, inlineValue !== null ? 1 : 2);
|
|
26594
|
+
i--;
|
|
26595
|
+
continue;
|
|
26596
|
+
}
|
|
26597
|
+
if (flag === "--disable-telemetry") {
|
|
26598
|
+
disableTelemetry = true;
|
|
26599
|
+
args.splice(i, 1);
|
|
26600
|
+
i--;
|
|
26601
|
+
continue;
|
|
26602
|
+
}
|
|
26603
|
+
if (flag === "--allowed-origins") {
|
|
26604
|
+
const { value, spliceCount } = parseStringFlag(flag, "a comma-separated list of origins", inlineValue, args, i);
|
|
26605
|
+
allowedDevOrigins = value.split(",").map((s) => s.trim()).filter(Boolean);
|
|
26606
|
+
args.splice(i, spliceCount);
|
|
26607
|
+
i--;
|
|
26608
|
+
continue;
|
|
26609
|
+
}
|
|
26610
|
+
if (flag === "--host" || flag === "-H" || flag === "--hostname") {
|
|
26611
|
+
const { value, spliceCount } = parseStringFlag(flag, "an address to bind (e.g. 127.0.0.1)", inlineValue, args, i);
|
|
26612
|
+
host = value;
|
|
26613
|
+
args.splice(i, spliceCount);
|
|
26614
|
+
i--;
|
|
26615
|
+
continue;
|
|
26616
|
+
}
|
|
26617
|
+
}
|
|
26618
|
+
return { loggingLevel, disableTelemetry, allowedDevOrigins, host, remainingArgs: args };
|
|
26619
|
+
}
|
|
26620
|
+
var init_parse_script_args = () => {};
|
|
26621
|
+
|
|
26622
|
+
// scripts/install-diagnosis.mjs
|
|
26623
|
+
import { existsSync as existsSync34, readFileSync as readFileSync30, realpathSync as realpathSync3 } from "node:fs";
|
|
26624
|
+
import { dirname as dirname16, resolve as resolve24 } from "node:path";
|
|
26625
|
+
import { homedir as homedir26, platform as platform4 } from "node:os";
|
|
26626
|
+
import { spawnSync } from "node:child_process";
|
|
26627
|
+
function findPackageRoot(start) {
|
|
26628
|
+
try {
|
|
26629
|
+
let dir = realpathSync3(start);
|
|
26630
|
+
if (existsSync34(dir) && !existsSync34(resolve24(dir, "package.json"))) {
|
|
26631
|
+
dir = dirname16(dir);
|
|
26632
|
+
}
|
|
26633
|
+
while (true) {
|
|
26634
|
+
const pkgPath = resolve24(dir, "package.json");
|
|
26635
|
+
if (existsSync34(pkgPath)) {
|
|
26636
|
+
try {
|
|
26637
|
+
const pkg = JSON.parse(readFileSync30(pkgPath, "utf8"));
|
|
26638
|
+
if (pkg.name === PKG_NAME)
|
|
26639
|
+
return dir;
|
|
26640
|
+
} catch {}
|
|
26641
|
+
}
|
|
26642
|
+
const parent = dirname16(dir);
|
|
26643
|
+
if (parent === dir)
|
|
26644
|
+
return null;
|
|
26645
|
+
dir = parent;
|
|
26646
|
+
}
|
|
26647
|
+
} catch {
|
|
26648
|
+
return null;
|
|
26649
|
+
}
|
|
26650
|
+
}
|
|
26651
|
+
function readPackageVersion(packageRoot) {
|
|
26652
|
+
if (!packageRoot)
|
|
26653
|
+
return null;
|
|
26654
|
+
try {
|
|
26655
|
+
const pkg = JSON.parse(readFileSync30(resolve24(packageRoot, "package.json"), "utf8"));
|
|
26656
|
+
return typeof pkg.version === "string" ? pkg.version : null;
|
|
26657
|
+
} catch {
|
|
26658
|
+
return null;
|
|
26659
|
+
}
|
|
26660
|
+
}
|
|
26661
|
+
function resolvePathFirstBinary() {
|
|
26662
|
+
try {
|
|
26663
|
+
const isWin = platform4() === "win32";
|
|
26664
|
+
const res = isWin ? spawnSync("where", [PKG_NAME], { encoding: "utf8" }) : spawnSync("sh", ["-c", `command -v ${PKG_NAME}`], { encoding: "utf8" });
|
|
26665
|
+
if (res.status !== 0)
|
|
26666
|
+
return null;
|
|
26667
|
+
const first = (res.stdout || "").split(/\r?\n/).find((l) => l.trim().length > 0);
|
|
26668
|
+
return first ? first.trim() : null;
|
|
26669
|
+
} catch {
|
|
26670
|
+
return null;
|
|
26671
|
+
}
|
|
26672
|
+
}
|
|
26673
|
+
function locateNpmGlobal() {
|
|
26674
|
+
try {
|
|
26675
|
+
const res = spawnSync("npm", ["root", "-g"], { encoding: "utf8" });
|
|
26676
|
+
if (res.status !== 0)
|
|
26677
|
+
return null;
|
|
26678
|
+
const root = (res.stdout || "").trim();
|
|
26679
|
+
if (!root)
|
|
26680
|
+
return null;
|
|
26681
|
+
const candidate = resolve24(root, PKG_NAME);
|
|
26682
|
+
return existsSync34(resolve24(candidate, "package.json")) ? candidate : null;
|
|
26683
|
+
} catch {
|
|
26684
|
+
return null;
|
|
26685
|
+
}
|
|
26686
|
+
}
|
|
26687
|
+
function locateBunGlobal() {
|
|
26688
|
+
try {
|
|
26689
|
+
const candidate = resolve24(homedir26(), ".bun", "install", "global", "node_modules", PKG_NAME);
|
|
26690
|
+
return existsSync34(resolve24(candidate, "package.json")) ? candidate : null;
|
|
26691
|
+
} catch {
|
|
26692
|
+
return null;
|
|
26693
|
+
}
|
|
26694
|
+
}
|
|
26695
|
+
function buildRecommendation(pathFirstBin) {
|
|
26696
|
+
if (!pathFirstBin)
|
|
26697
|
+
return null;
|
|
26698
|
+
const bunBinPrefix = resolve24(homedir26(), ".bun", "bin") + "/";
|
|
26699
|
+
const bunGlobalPrefix = resolve24(homedir26(), ".bun", "install", "global") + "/";
|
|
26700
|
+
const isBun = pathFirstBin.startsWith(bunBinPrefix) || pathFirstBin.startsWith(bunGlobalPrefix);
|
|
26701
|
+
if (isBun) {
|
|
26702
|
+
return `rm -f ~/.bun/bin/${PKG_NAME} && rm -rf ~/.bun/install/global/node_modules/${PKG_NAME}`;
|
|
26703
|
+
}
|
|
26704
|
+
return `npm rm -g ${PKG_NAME}`;
|
|
26705
|
+
}
|
|
26706
|
+
function diagnoseShadow(self) {
|
|
26707
|
+
const selfPackageRoot = (() => {
|
|
26708
|
+
try {
|
|
26709
|
+
return self?.selfPackageRoot ? realpathSync3(self.selfPackageRoot) : null;
|
|
26710
|
+
} catch {
|
|
26711
|
+
return self?.selfPackageRoot ?? null;
|
|
26712
|
+
}
|
|
25591
26713
|
})();
|
|
25592
26714
|
const selfVersion = self?.selfVersion ?? null;
|
|
25593
26715
|
const pathFirstBin = resolvePathFirstBinary();
|
|
@@ -25649,8 +26771,8 @@ function makeSkewLogFilter() {
|
|
|
25649
26771
|
}
|
|
25650
26772
|
|
|
25651
26773
|
// lib/dashboard-host.ts
|
|
25652
|
-
function isLoopbackHostname(
|
|
25653
|
-
const h =
|
|
26774
|
+
function isLoopbackHostname(hostname6) {
|
|
26775
|
+
const h = hostname6.trim().toLowerCase();
|
|
25654
26776
|
if (!h)
|
|
25655
26777
|
return false;
|
|
25656
26778
|
if (LOOPBACK_HOSTNAMES.has(h))
|
|
@@ -25672,8 +26794,8 @@ __export(exports_launch, {
|
|
|
25672
26794
|
launch: () => launch
|
|
25673
26795
|
});
|
|
25674
26796
|
import { spawn as spawn2 } from "child_process";
|
|
25675
|
-
import { realpathSync as realpathSync4, existsSync as
|
|
25676
|
-
import { resolve as
|
|
26797
|
+
import { realpathSync as realpathSync4, existsSync as existsSync35 } from "node:fs";
|
|
26798
|
+
import { resolve as resolve25, dirname as dirname17 } from "node:path";
|
|
25677
26799
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
25678
26800
|
import { createInterface } from "node:readline";
|
|
25679
26801
|
function launch(mode) {
|
|
@@ -25697,9 +26819,9 @@ function launch(mode) {
|
|
|
25697
26819
|
process.env.PORT = port;
|
|
25698
26820
|
process.env.HOSTNAME = bindHost;
|
|
25699
26821
|
cmd = "node";
|
|
25700
|
-
const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT ??
|
|
25701
|
-
const serverJsPath =
|
|
25702
|
-
if (!
|
|
26822
|
+
const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT ?? resolve25(dirname17(realpathSync4(fileURLToPath2(import.meta.url))), "..");
|
|
26823
|
+
const serverJsPath = resolve25(packageRoot, ".next/standalone/server.js");
|
|
26824
|
+
if (!existsSync35(serverJsPath)) {
|
|
25703
26825
|
let shadowMessage = null;
|
|
25704
26826
|
try {
|
|
25705
26827
|
const diag = diagnoseShadow({ selfPackageRoot: packageRoot, selfVersion: version2 });
|
|
@@ -25961,6 +27083,13 @@ async function runScheduledAudit() {
|
|
|
25961
27083
|
}
|
|
25962
27084
|
process.stdout.write(`failproofai: audit complete — ${num(result.eventsScanned)} tool calls across ` + `${num(result.transcripts.scanned)} sessions, ${num(result.totals.hits)} hits
|
|
25963
27085
|
`);
|
|
27086
|
+
const outcome = await reportHarm(result);
|
|
27087
|
+
const line = describeOutcome2(outcome);
|
|
27088
|
+
if (line) {
|
|
27089
|
+
const stream = outcome.kind === "sent" ? process.stdout : process.stderr;
|
|
27090
|
+
stream.write(`${line}
|
|
27091
|
+
`);
|
|
27092
|
+
}
|
|
25964
27093
|
return 0;
|
|
25965
27094
|
} finally {
|
|
25966
27095
|
attempt.lock.release();
|
|
@@ -26025,15 +27154,71 @@ async function runAuditCli(args) {
|
|
|
26025
27154
|
die(`\`audit --scheduled\` takes no other arguments (got: ${extra}).`);
|
|
26026
27155
|
process.exit(await runScheduledAudit());
|
|
26027
27156
|
}
|
|
27157
|
+
if (args.includes("--status")) {
|
|
27158
|
+
const extra = args.find((a) => a !== "--status");
|
|
27159
|
+
if (extra)
|
|
27160
|
+
die(`\`audit --status\` takes no other arguments (got: ${extra}).`);
|
|
27161
|
+
const { runScheduleStatus: runScheduleStatus2 } = await Promise.resolve().then(() => (init_schedule_cli(), exports_schedule_cli));
|
|
27162
|
+
runScheduleStatus2();
|
|
27163
|
+
process.exit(0);
|
|
27164
|
+
}
|
|
27165
|
+
if (args.includes("--no-schedule")) {
|
|
27166
|
+
const extra = args.find((a) => a !== "--no-schedule");
|
|
27167
|
+
if (extra)
|
|
27168
|
+
die(`\`audit --no-schedule\` takes no other arguments (got: ${extra}).`);
|
|
27169
|
+
const { runScheduleOff: runScheduleOff2 } = await Promise.resolve().then(() => (init_schedule_cli(), exports_schedule_cli));
|
|
27170
|
+
runScheduleOff2();
|
|
27171
|
+
process.exit(0);
|
|
27172
|
+
}
|
|
27173
|
+
const scheduleAt = args.indexOf("--schedule");
|
|
27174
|
+
if (scheduleAt !== -1) {
|
|
27175
|
+
let days;
|
|
27176
|
+
let email;
|
|
27177
|
+
for (let i = 0;i < args.length; i += 1) {
|
|
27178
|
+
const a = args[i];
|
|
27179
|
+
if (a === "--schedule") {
|
|
27180
|
+
const next = args[i + 1];
|
|
27181
|
+
if (next !== undefined && !next.startsWith("-")) {
|
|
27182
|
+
days = next;
|
|
27183
|
+
i += 1;
|
|
27184
|
+
}
|
|
27185
|
+
continue;
|
|
27186
|
+
}
|
|
27187
|
+
if (a === "--email" || a.startsWith("--email=")) {
|
|
27188
|
+
if (a.startsWith("--email=")) {
|
|
27189
|
+
email = a.slice("--email=".length);
|
|
27190
|
+
} else {
|
|
27191
|
+
email = args[i + 1];
|
|
27192
|
+
i += 1;
|
|
27193
|
+
}
|
|
27194
|
+
if (email === undefined || email.length === 0 || email.startsWith("-")) {
|
|
27195
|
+
die("`--email` needs an address, e.g. `--email you@yourdomain.com`.");
|
|
27196
|
+
}
|
|
27197
|
+
continue;
|
|
27198
|
+
}
|
|
27199
|
+
die(`\`audit --schedule\` does not take ${a}.`);
|
|
27200
|
+
}
|
|
27201
|
+
const { runScheduleOn: runScheduleOn2, ScheduleCliError: ScheduleCliError2 } = await Promise.resolve().then(() => (init_schedule_cli(), exports_schedule_cli));
|
|
27202
|
+
const { LoginError: LoginError2 } = await Promise.resolve().then(() => (init_cli_login(), exports_cli_login));
|
|
27203
|
+
try {
|
|
27204
|
+
await runScheduleOn2(days, email);
|
|
27205
|
+
} catch (err) {
|
|
27206
|
+
if (err instanceof ScheduleCliError2 || err instanceof LoginError2)
|
|
27207
|
+
die(err.message);
|
|
27208
|
+
throw err;
|
|
27209
|
+
}
|
|
27210
|
+
process.exit(0);
|
|
27211
|
+
}
|
|
26028
27212
|
const stray = args.find((a) => a !== "--help" && a !== "-h");
|
|
26029
27213
|
if (stray) {
|
|
26030
|
-
die(`\`audit\`
|
|
26031
|
-
|
|
27214
|
+
die(`\`audit\` does not take ${stray}.
|
|
27215
|
+
Run \`failproofai audit\` to scan your history and open the dashboard,
|
|
27216
|
+
or \`failproofai audit --help\` for the scheduling commands.`);
|
|
26032
27217
|
}
|
|
26033
27218
|
const attempt = acquireAuditLock("cli");
|
|
26034
27219
|
if (!attempt.ok) {
|
|
26035
27220
|
process.stderr.write(`Error: ${heldByLine(attempt.heldBy)}.
|
|
26036
|
-
|
|
27221
|
+
Two audits write the same cache files, so this one won't start. Try again shortly.
|
|
26037
27222
|
`);
|
|
26038
27223
|
process.exit(EXIT_AUDIT_ALREADY_RUNNING);
|
|
26039
27224
|
}
|
|
@@ -26057,7 +27242,7 @@ async function runAuditCli(args) {
|
|
|
26057
27242
|
if (result.eventsScanned === 0) {
|
|
26058
27243
|
process.stdout.write(`
|
|
26059
27244
|
${c(DIM, "no agent sessions found yet.")}
|
|
26060
|
-
|
|
27245
|
+
install hooks with ${c(CYAN, "failproofai policies --install")} ${c(DIM, "and come back after using your agent.")}
|
|
26061
27246
|
|
|
26062
27247
|
`);
|
|
26063
27248
|
process.exit(0);
|
|
@@ -26072,8 +27257,8 @@ async function runAuditCli(args) {
|
|
|
26072
27257
|
const url = `http://localhost:${DASHBOARD_PORT}/audit`;
|
|
26073
27258
|
process.stdout.write(`
|
|
26074
27259
|
${c(DIM, "starting the dashboard…")}
|
|
26075
|
-
|
|
26076
|
-
|
|
27260
|
+
${c(PINK, "✦")} ${c(BOLD, "here's your audit")} ${c(DIM, "→")} ${c(CYAN, url)}
|
|
27261
|
+
${c(DIM, "(opening in your browser — press Ctrl+C to stop the server)")}
|
|
26077
27262
|
|
|
26078
27263
|
`);
|
|
26079
27264
|
openWhenReady(DASHBOARD_PORT, "/audit");
|
|
@@ -26089,6 +27274,7 @@ var init_cli = __esm(() => {
|
|
|
26089
27274
|
init_telemetry_id2();
|
|
26090
27275
|
init_telemetry_sanitize();
|
|
26091
27276
|
init_open_browser();
|
|
27277
|
+
init_report_harm();
|
|
26092
27278
|
init_tui();
|
|
26093
27279
|
AUDIT_STAGES = [
|
|
26094
27280
|
{ label: "discovering transcripts", detail: "walking ~/.claude, ~/.codex, ~/.cursor, …" },
|
|
@@ -26110,14 +27296,34 @@ USAGE
|
|
|
26110
27296
|
server. This is what a scheduled audit runs; exit
|
|
26111
27297
|
75 means another audit already had the lock.
|
|
26112
27298
|
|
|
27299
|
+
SCHEDULING
|
|
27300
|
+
failproofai audit --schedule [days] [--email you@yourdomain.com]
|
|
27301
|
+
Scan on a timer in the background (default 7 days,
|
|
27302
|
+
1-90), and email you when a scan finds something
|
|
27303
|
+
harmful. Signs you in the first time — the report
|
|
27304
|
+
has to go somewhere. Pass --email to answer that
|
|
27305
|
+
up front and go straight to entering the code.
|
|
27306
|
+
failproofai audit --no-schedule
|
|
27307
|
+
Stop scanning on a timer. Leaves you signed in.
|
|
27308
|
+
failproofai audit --status
|
|
27309
|
+
What this machine is doing: whether scheduling is
|
|
27310
|
+
on, where reports go, the daemon's state, and when
|
|
27311
|
+
the next scan is due.
|
|
27312
|
+
|
|
27313
|
+
These write the same ~/.failproofai/config.json the dashboard's settings page
|
|
27314
|
+
writes, through the same function — so the two are always in step.
|
|
27315
|
+
|
|
26113
27316
|
WHAT IT DOES
|
|
26114
27317
|
1. Scans past sessions from every installed agent CLI (Claude, Codex, Cursor,
|
|
26115
27318
|
Copilot, OpenCode, Pi) — entirely on your machine.
|
|
26116
27319
|
2. Starts the local dashboard and opens
|
|
26117
27320
|
http://localhost:${DASHBOARD_PORT}/audit with your results.
|
|
26118
27321
|
|
|
26119
|
-
|
|
26120
|
-
|
|
27322
|
+
A bare "failproofai audit" needs no account, and nothing from your sessions
|
|
27323
|
+
leaves this machine — anonymous usage counts still apply unless you set
|
|
27324
|
+
FAILPROOFAI_TELEMETRY_DISABLED=1. Scheduling is the exception: it emails you
|
|
27325
|
+
what it finds, so it needs an address.
|
|
27326
|
+
Press Ctrl+C to stop the dashboard server when you're done.
|
|
26121
27327
|
`.trimStart();
|
|
26122
27328
|
RESET = ANSI_RESET;
|
|
26123
27329
|
DIM = ANSI_DIM;
|
|
@@ -26147,16 +27353,16 @@ __export(exports_configure_wizard, {
|
|
|
26147
27353
|
buildCompletionSummary: () => buildCompletionSummary,
|
|
26148
27354
|
buildAgentChoices: () => buildAgentChoices
|
|
26149
27355
|
});
|
|
26150
|
-
import { existsSync as
|
|
26151
|
-
import { homedir as
|
|
26152
|
-
import { dirname as dirname18, resolve as
|
|
27356
|
+
import { existsSync as existsSync36, mkdirSync as mkdirSync21, writeFileSync as writeFileSync19, readFileSync as readFileSync31 } from "node:fs";
|
|
27357
|
+
import { homedir as homedir27 } from "node:os";
|
|
27358
|
+
import { dirname as dirname18, resolve as resolve26, sep as sep5 } from "node:path";
|
|
26153
27359
|
async function emit(event, props) {
|
|
26154
27360
|
try {
|
|
26155
27361
|
await trackHookEvent2(getInstanceId2(), event, props);
|
|
26156
27362
|
} catch {}
|
|
26157
27363
|
}
|
|
26158
27364
|
function homeify2(p) {
|
|
26159
|
-
const home =
|
|
27365
|
+
const home = homedir27();
|
|
26160
27366
|
if (p === home)
|
|
26161
27367
|
return "~";
|
|
26162
27368
|
if (p.startsWith(home + sep5))
|
|
@@ -26280,8 +27486,8 @@ function setCustomPoliciesEnabled(scope, cwd, enabled) {
|
|
|
26280
27486
|
const path3 = getConfigPathForScope(scope, cwd);
|
|
26281
27487
|
let config = {};
|
|
26282
27488
|
try {
|
|
26283
|
-
if (
|
|
26284
|
-
config = JSON.parse(
|
|
27489
|
+
if (existsSync36(path3))
|
|
27490
|
+
config = JSON.parse(readFileSync31(path3, "utf8"));
|
|
26285
27491
|
} catch {
|
|
26286
27492
|
return;
|
|
26287
27493
|
}
|
|
@@ -26321,7 +27527,7 @@ function describeCustomPolicies(cwd) {
|
|
|
26321
27527
|
const scopes = [];
|
|
26322
27528
|
let fileCount = 0;
|
|
26323
27529
|
const dirs = [
|
|
26324
|
-
{ dir:
|
|
27530
|
+
{ dir: resolve26(cwd, ".failproofai", "policies"), label: "project" },
|
|
26325
27531
|
{ dir: customPoliciesDir(), label: "global" }
|
|
26326
27532
|
];
|
|
26327
27533
|
for (const { dir, label } of dirs) {
|
|
@@ -26332,7 +27538,7 @@ function describeCustomPolicies(cwd) {
|
|
|
26332
27538
|
fileCount += found.length;
|
|
26333
27539
|
}
|
|
26334
27540
|
for (const name of findSkippedPolicyFiles(dir)) {
|
|
26335
|
-
warnings.push(`! ${homeify2(
|
|
27541
|
+
warnings.push(`! ${homeify2(resolve26(dir, name))} is NOT loaded — rename to ` + `${name.replace(/\.(js|mjs|ts)$/, "-policies.$1")}`);
|
|
26336
27542
|
}
|
|
26337
27543
|
}
|
|
26338
27544
|
return { active, warnings, fileCount, scopes };
|
|
@@ -26438,7 +27644,7 @@ function firstRunMarkerPath() {
|
|
|
26438
27644
|
return launcherMarker();
|
|
26439
27645
|
}
|
|
26440
27646
|
function hasSeenLauncher() {
|
|
26441
|
-
return
|
|
27647
|
+
return existsSync36(firstRunMarkerPath());
|
|
26442
27648
|
}
|
|
26443
27649
|
function markLauncherSeen() {
|
|
26444
27650
|
try {
|
|
@@ -26740,7 +27946,7 @@ refreshed. Re-run \`failproofai config\` once you can use sudo.
|
|
|
26740
27946
|
let url = null;
|
|
26741
27947
|
let token = null;
|
|
26742
27948
|
let machineId = resolveMachineId();
|
|
26743
|
-
let
|
|
27949
|
+
let machineLabel2 = existing?.machineLabel ?? resolveMachineLabel();
|
|
26744
27950
|
if (existing) {
|
|
26745
27951
|
const reuse = await selectOne({
|
|
26746
27952
|
message: `Use this machine's existing connection to ${existing.url}?`,
|
|
@@ -26761,7 +27967,7 @@ refreshed. Re-run \`failproofai config\` once you can use sudo.
|
|
|
26761
27967
|
url = existing.url;
|
|
26762
27968
|
token = existing.token;
|
|
26763
27969
|
machineId = existing.machineId;
|
|
26764
|
-
|
|
27970
|
+
machineLabel2 = existing.machineLabel ?? machineLabel2;
|
|
26765
27971
|
}
|
|
26766
27972
|
}
|
|
26767
27973
|
if (url === null) {
|
|
@@ -26815,13 +28021,13 @@ That did not work: ${probe.reason}
|
|
|
26815
28021
|
if (retry === "skip") {
|
|
26816
28022
|
stdout.write("Staying local. Connect later with `failproofai config --connect`.\n\n");
|
|
26817
28023
|
} else {
|
|
26818
|
-
connect = { url, token, machineId, machineLabel };
|
|
28024
|
+
connect = { url, token, machineId, machineLabel: machineLabel2 };
|
|
26819
28025
|
}
|
|
26820
28026
|
} else {
|
|
26821
28027
|
stdout.write(`looks good.
|
|
26822
28028
|
|
|
26823
28029
|
`);
|
|
26824
|
-
connect = { url, token, machineId, machineLabel };
|
|
28030
|
+
connect = { url, token, machineId, machineLabel: machineLabel2 };
|
|
26825
28031
|
}
|
|
26826
28032
|
}
|
|
26827
28033
|
}
|
|
@@ -27024,17 +28230,17 @@ __export(exports_flush_cli2, {
|
|
|
27024
28230
|
flushRequestPath: () => flushRequestPath2,
|
|
27025
28231
|
DEFAULT_FLUSH_TIMEOUT_SECS: () => DEFAULT_FLUSH_TIMEOUT_SECS2
|
|
27026
28232
|
});
|
|
27027
|
-
import { existsSync as
|
|
27028
|
-
import { dirname as dirname19, join as
|
|
28233
|
+
import { existsSync as existsSync37, mkdirSync as mkdirSync22, writeFileSync as writeFileSync20, readdirSync as readdirSync19 } from "node:fs";
|
|
28234
|
+
import { dirname as dirname19, join as join34 } from "node:path";
|
|
27029
28235
|
function flushRequestPath2(home) {
|
|
27030
|
-
return
|
|
28236
|
+
return join34(failproofaiHome(home), "state", "flush-request.json");
|
|
27031
28237
|
}
|
|
27032
28238
|
function spoolDirs2(home) {
|
|
27033
28239
|
const root = spoolDir(home);
|
|
27034
|
-
if (!
|
|
28240
|
+
if (!existsSync37(root))
|
|
27035
28241
|
return [];
|
|
27036
28242
|
try {
|
|
27037
|
-
return
|
|
28243
|
+
return readdirSync19(root, { withFileTypes: true }).filter((e) => e.isDirectory() && e.name !== "failed").map((e) => join34(root, e.name));
|
|
27038
28244
|
} catch {
|
|
27039
28245
|
return [];
|
|
27040
28246
|
}
|
|
@@ -27043,7 +28249,7 @@ function pendingBatches2(home) {
|
|
|
27043
28249
|
let n = 0;
|
|
27044
28250
|
for (const dir of spoolDirs2(home)) {
|
|
27045
28251
|
try {
|
|
27046
|
-
n +=
|
|
28252
|
+
n += readdirSync19(dir).filter((f) => f.endsWith(".jsonl")).length;
|
|
27047
28253
|
} catch {}
|
|
27048
28254
|
}
|
|
27049
28255
|
return n;
|
|
@@ -27138,16 +28344,16 @@ __export(exports_backfill_cli, {
|
|
|
27138
28344
|
backfillRequestPath: () => backfillRequestPath,
|
|
27139
28345
|
DEFAULT_BACKFILL_DAYS: () => DEFAULT_BACKFILL_DAYS
|
|
27140
28346
|
});
|
|
27141
|
-
import { existsSync as
|
|
27142
|
-
import { dirname as dirname20, join as
|
|
28347
|
+
import { existsSync as existsSync38, mkdirSync as mkdirSync23, writeFileSync as writeFileSync21, readdirSync as readdirSync20, statSync as statSync24 } from "node:fs";
|
|
28348
|
+
import { dirname as dirname20, join as join35 } from "node:path";
|
|
27143
28349
|
function backfillRequestPath(home) {
|
|
27144
|
-
return
|
|
28350
|
+
return join35(failproofaiHome(home), "state", "backfill-request.json");
|
|
27145
28351
|
}
|
|
27146
28352
|
function surveySessions(sinceMs, homeDir) {
|
|
27147
28353
|
const out = [];
|
|
27148
28354
|
for (const { cli, dir } of SESSION_DIRS) {
|
|
27149
|
-
const root =
|
|
27150
|
-
if (!
|
|
28355
|
+
const root = join35(homeDir, dir);
|
|
28356
|
+
if (!existsSync38(root))
|
|
27151
28357
|
continue;
|
|
27152
28358
|
let files = 0;
|
|
27153
28359
|
let newest = 0;
|
|
@@ -27156,12 +28362,12 @@ function surveySessions(sinceMs, homeDir) {
|
|
|
27156
28362
|
return;
|
|
27157
28363
|
let entries;
|
|
27158
28364
|
try {
|
|
27159
|
-
entries =
|
|
28365
|
+
entries = readdirSync20(d, { withFileTypes: true });
|
|
27160
28366
|
} catch {
|
|
27161
28367
|
return;
|
|
27162
28368
|
}
|
|
27163
28369
|
for (const e of entries) {
|
|
27164
|
-
const p =
|
|
28370
|
+
const p = join35(d, e.name);
|
|
27165
28371
|
if (e.isDirectory()) {
|
|
27166
28372
|
walk(p, depth + 1);
|
|
27167
28373
|
continue;
|
|
@@ -27185,7 +28391,7 @@ function runBackfillCommand(opts = {}) {
|
|
|
27185
28391
|
const now = opts.now ?? Date.now();
|
|
27186
28392
|
const sinceMs = opts.sinceMs ?? now - DEFAULT_BACKFILL_DAYS * 24 * 60 * 60 * 1000;
|
|
27187
28393
|
const home = failproofaiHome();
|
|
27188
|
-
if (!
|
|
28394
|
+
if (!existsSync38(home)) {
|
|
27189
28395
|
return {
|
|
27190
28396
|
exitCode: 1,
|
|
27191
28397
|
lines: [`No failproofai home at ${home}. Run \`failproofai config\` first.`]
|
|
@@ -27291,8 +28497,8 @@ __export(exports_harness_cli, {
|
|
|
27291
28497
|
addPath: () => addPath,
|
|
27292
28498
|
HARNESS_KEYS: () => HARNESS_KEYS
|
|
27293
28499
|
});
|
|
27294
|
-
import { homedir as
|
|
27295
|
-
import { resolve as
|
|
28500
|
+
import { homedir as homedir28 } from "node:os";
|
|
28501
|
+
import { resolve as resolve27 } from "node:path";
|
|
27296
28502
|
function unknownHarness(name) {
|
|
27297
28503
|
return fail([
|
|
27298
28504
|
`Unknown harness: ${name}`,
|
|
@@ -27335,8 +28541,8 @@ function comparableLabel(raw) {
|
|
|
27335
28541
|
return raw.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
27336
28542
|
}
|
|
27337
28543
|
function comparablePath(raw) {
|
|
27338
|
-
const home =
|
|
27339
|
-
const expanded = raw === "~" ? home : raw.startsWith("~/") ?
|
|
28544
|
+
const home = homedir28();
|
|
28545
|
+
const expanded = raw === "~" ? home : raw.startsWith("~/") ? resolve27(home, raw.slice(2)) : raw;
|
|
27340
28546
|
return expanded.replace(/\/+$/, "");
|
|
27341
28547
|
}
|
|
27342
28548
|
function effectiveLabel(entry) {
|
|
@@ -27523,7 +28729,7 @@ __export(exports_fp_config, {
|
|
|
27523
28729
|
DEFAULT_CONFIG: () => DEFAULT_CONFIG2,
|
|
27524
28730
|
DEFAULT_AUDIT_INTERVAL_DAYS: () => DEFAULT_AUDIT_INTERVAL_DAYS2
|
|
27525
28731
|
});
|
|
27526
|
-
import { chmodSync as
|
|
28732
|
+
import { chmodSync as chmodSync6, existsSync as existsSync39, mkdirSync as mkdirSync24, readFileSync as readFileSync32, statSync as statSync25, writeFileSync as writeFileSync22 } from "node:fs";
|
|
27527
28733
|
import { dirname as dirname21 } from "node:path";
|
|
27528
28734
|
function detectLayout2() {
|
|
27529
28735
|
const raw = readVersionFile2();
|
|
@@ -27532,11 +28738,18 @@ function detectLayout2() {
|
|
|
27532
28738
|
return { kind: "current", version: raw };
|
|
27533
28739
|
return raw.layout > LAYOUT_VERSION ? { kind: "future", found: raw.layout } : { kind: "stale", found: raw.layout };
|
|
27534
28740
|
}
|
|
27535
|
-
if (
|
|
28741
|
+
if (existsSync39(configFile())) {
|
|
28742
|
+
const layoutThreePositions = [
|
|
28743
|
+
legacy.authJson(),
|
|
28744
|
+
legacy.nextAudit(),
|
|
28745
|
+
legacy.auditSchedule()
|
|
28746
|
+
];
|
|
28747
|
+
if (layoutThreePositions.some((p) => existsSync39(p)))
|
|
28748
|
+
return { kind: "stale", found: 3 };
|
|
27536
28749
|
return { kind: "current", version: { layout: LAYOUT_VERSION, cli: "" }, inferred: true };
|
|
27537
28750
|
}
|
|
27538
|
-
if (
|
|
27539
|
-
return { kind: "stale", found:
|
|
28751
|
+
if (existsSync39(legacy.configToml()))
|
|
28752
|
+
return { kind: "stale", found: 2 };
|
|
27540
28753
|
const layoutOneMarkers = [
|
|
27541
28754
|
legacy.policyConfig(),
|
|
27542
28755
|
legacy.cacheDir(),
|
|
@@ -27546,7 +28759,7 @@ function detectLayout2() {
|
|
|
27546
28759
|
legacy.ingestCredentials(),
|
|
27547
28760
|
legacy.auditDashboard()
|
|
27548
28761
|
];
|
|
27549
|
-
return layoutOneMarkers.some((p) =>
|
|
28762
|
+
return layoutOneMarkers.some((p) => existsSync39(p)) ? { kind: "stale", found: 1 } : { kind: "absent" };
|
|
27550
28763
|
}
|
|
27551
28764
|
function readLegacyTomlVersion2(text) {
|
|
27552
28765
|
const layout = Number(/^\s*layout\s*=\s*(\d+)\s*$/m.exec(text)?.[1]);
|
|
@@ -27558,7 +28771,7 @@ function readLegacyTomlVersion2(text) {
|
|
|
27558
28771
|
function readVersionFile2() {
|
|
27559
28772
|
let text;
|
|
27560
28773
|
try {
|
|
27561
|
-
text =
|
|
28774
|
+
text = readFileSync32(versionFile(), "utf8");
|
|
27562
28775
|
} catch {
|
|
27563
28776
|
return null;
|
|
27564
28777
|
}
|
|
@@ -27579,7 +28792,7 @@ function readVersionFile2() {
|
|
|
27579
28792
|
function writeVersionFile2(v = {}) {
|
|
27580
28793
|
const existing = readVersionFile2();
|
|
27581
28794
|
const next = {
|
|
27582
|
-
layout: LAYOUT_VERSION,
|
|
28795
|
+
layout: v.layout ?? LAYOUT_VERSION,
|
|
27583
28796
|
cli: v.cli ?? version2,
|
|
27584
28797
|
daemon: v.clearDaemon ? undefined : v.daemon ?? existing?.daemon
|
|
27585
28798
|
};
|
|
@@ -27613,7 +28826,7 @@ function readSources2(raw) {
|
|
|
27613
28826
|
function readConfigRaw2() {
|
|
27614
28827
|
let raw = {};
|
|
27615
28828
|
try {
|
|
27616
|
-
const parsed = JSON.parse(
|
|
28829
|
+
const parsed = JSON.parse(readFileSync32(configFile(), "utf8"));
|
|
27617
28830
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
27618
28831
|
raw = parsed;
|
|
27619
28832
|
}
|
|
@@ -27622,7 +28835,7 @@ function readConfigRaw2() {
|
|
|
27622
28835
|
}
|
|
27623
28836
|
function readConfig2() {
|
|
27624
28837
|
try {
|
|
27625
|
-
const parsed = JSON.parse(
|
|
28838
|
+
const parsed = JSON.parse(readFileSync32(configFile(), "utf8"));
|
|
27626
28839
|
return projectConfig2(parsed);
|
|
27627
28840
|
} catch {
|
|
27628
28841
|
return structuredClone(DEFAULT_CONFIG2);
|
|
@@ -27648,7 +28861,11 @@ function projectConfig2(parsed) {
|
|
|
27648
28861
|
sources: readSources2(collector.sources)
|
|
27649
28862
|
},
|
|
27650
28863
|
telemetry: { enabled: telemetry.enabled !== false },
|
|
27651
|
-
audit: {
|
|
28864
|
+
audit: {
|
|
28865
|
+
auto: audit.auto === true,
|
|
28866
|
+
intervalDays: readIntervalDays2(audit.interval_days),
|
|
28867
|
+
reportsConsentedAt: typeof audit.reports_consented_at === "number" && Number.isFinite(audit.reports_consented_at) ? audit.reports_consented_at : undefined
|
|
28868
|
+
}
|
|
27652
28869
|
};
|
|
27653
28870
|
}
|
|
27654
28871
|
}
|
|
@@ -27697,7 +28914,11 @@ function writeConfig2(config, raw) {
|
|
|
27697
28914
|
} : {}
|
|
27698
28915
|
},
|
|
27699
28916
|
...config.telemetry.enabled ? {} : { telemetry: { enabled: false } },
|
|
27700
|
-
audit: {
|
|
28917
|
+
audit: {
|
|
28918
|
+
auto: config.audit.auto,
|
|
28919
|
+
interval_days: config.audit.intervalDays,
|
|
28920
|
+
...config.audit.reportsConsentedAt === undefined ? {} : { reports_consented_at: config.audit.reportsConsentedAt }
|
|
28921
|
+
}
|
|
27701
28922
|
};
|
|
27702
28923
|
const merged = structuredClone(raw ?? readConfigRaw2().raw);
|
|
27703
28924
|
for (const path3 of OWNED_CONFIG_KEYS2)
|
|
@@ -27721,7 +28942,7 @@ function updateConfig2(patch) {
|
|
|
27721
28942
|
function readCredentialsRaw2() {
|
|
27722
28943
|
let raw = {};
|
|
27723
28944
|
try {
|
|
27724
|
-
const parsed = JSON.parse(
|
|
28945
|
+
const parsed = JSON.parse(readFileSync32(credentialsFile(), "utf8"));
|
|
27725
28946
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
27726
28947
|
raw = parsed;
|
|
27727
28948
|
}
|
|
@@ -27730,7 +28951,7 @@ function readCredentialsRaw2() {
|
|
|
27730
28951
|
}
|
|
27731
28952
|
function readCredentials2() {
|
|
27732
28953
|
try {
|
|
27733
|
-
return projectCredentials2(JSON.parse(
|
|
28954
|
+
return projectCredentials2(JSON.parse(readFileSync32(credentialsFile(), "utf8")));
|
|
27734
28955
|
} catch {
|
|
27735
28956
|
return {};
|
|
27736
28957
|
}
|
|
@@ -27742,8 +28963,8 @@ function projectCredentials2(parsed) {
|
|
|
27742
28963
|
const auth = parsed.auth;
|
|
27743
28964
|
const out = {};
|
|
27744
28965
|
if (cloud && typeof cloud.url === "string" && typeof cloud.machine_id === "string" && typeof cloud.token === "string" && cloud.url && cloud.token) {
|
|
27745
|
-
const
|
|
27746
|
-
out.cloud = { url: cloud.url, machineId: cloud.machine_id, token: cloud.token, machineLabel };
|
|
28966
|
+
const machineLabel2 = typeof cloud.machine_label === "string" && cloud.machine_label ? cloud.machine_label : undefined;
|
|
28967
|
+
out.cloud = { url: cloud.url, machineId: cloud.machine_id, token: cloud.token, machineLabel: machineLabel2 };
|
|
27747
28968
|
}
|
|
27748
28969
|
const org = parsed.org;
|
|
27749
28970
|
if (org) {
|
|
@@ -27802,12 +29023,12 @@ function writeCredentials2(creds, raw) {
|
|
|
27802
29023
|
mkdirSync24(home, { recursive: true });
|
|
27803
29024
|
try {
|
|
27804
29025
|
if (statSync25(home).mode & 63)
|
|
27805
|
-
|
|
29026
|
+
chmodSync6(home, 448);
|
|
27806
29027
|
} catch {}
|
|
27807
29028
|
writeFileSync22(credentialsFile(), `${JSON.stringify(merged, null, 2)}
|
|
27808
29029
|
`, { mode: 384 });
|
|
27809
29030
|
try {
|
|
27810
|
-
|
|
29031
|
+
chmodSync6(credentialsFile(), 384);
|
|
27811
29032
|
} catch {}
|
|
27812
29033
|
}
|
|
27813
29034
|
function hasCloudCredentials() {
|
|
@@ -27847,7 +29068,8 @@ var init_fp_config2 = __esm(() => {
|
|
|
27847
29068
|
["collector", "sources", "*", "extra_paths"],
|
|
27848
29069
|
["telemetry", "enabled"],
|
|
27849
29070
|
["audit", "auto"],
|
|
27850
|
-
["audit", "interval_days"]
|
|
29071
|
+
["audit", "interval_days"],
|
|
29072
|
+
["audit", "reports_consented_at"]
|
|
27851
29073
|
];
|
|
27852
29074
|
OWNED_CREDENTIAL_KEYS2 = [
|
|
27853
29075
|
["cloud", "url"],
|
|
@@ -27906,7 +29128,9 @@ __export(exports_fp_home, {
|
|
|
27906
29128
|
codexSessionPathsFile: () => codexSessionPathsFile2,
|
|
27907
29129
|
cloudPoliciesDir: () => cloudPoliciesDir2,
|
|
27908
29130
|
binDir: () => binDir2,
|
|
29131
|
+
auditSessionFile: () => auditSessionFile2,
|
|
27909
29132
|
auditScheduleFile: () => auditScheduleFile2,
|
|
29133
|
+
auditMachineFile: () => auditMachineFile2,
|
|
27910
29134
|
auditLockFile: () => auditLockFile2,
|
|
27911
29135
|
auditDir: () => auditDir2,
|
|
27912
29136
|
auditDashboardFile: () => auditDashboardFile2,
|
|
@@ -27914,12 +29138,12 @@ __export(exports_fp_home, {
|
|
|
27914
29138
|
LAYOUT_VERSION: () => LAYOUT_VERSION2,
|
|
27915
29139
|
HOME_CLASSES: () => HOME_CLASSES2
|
|
27916
29140
|
});
|
|
27917
|
-
import { homedir as
|
|
27918
|
-
import { resolve as
|
|
29141
|
+
import { homedir as homedir29 } from "node:os";
|
|
29142
|
+
import { resolve as resolve28 } from "node:path";
|
|
27919
29143
|
function failproofaiHome2(home) {
|
|
27920
29144
|
if (home)
|
|
27921
|
-
return
|
|
27922
|
-
return process.env.FAILPROOFAI_HOME ||
|
|
29145
|
+
return resolve28(home, ".failproofai");
|
|
29146
|
+
return process.env.FAILPROOFAI_HOME || resolve28(homedir29(), ".failproofai");
|
|
27923
29147
|
}
|
|
27924
29148
|
function resettablePaths2() {
|
|
27925
29149
|
return [
|
|
@@ -27936,6 +29160,7 @@ function retiredLayoutPaths2() {
|
|
|
27936
29160
|
legacy2.lastVersion(),
|
|
27937
29161
|
legacy2.auditDashboard(),
|
|
27938
29162
|
legacy2.auditCacheDir(),
|
|
29163
|
+
legacy2.auditReminder(),
|
|
27939
29164
|
legacy2.codexSessionPaths(),
|
|
27940
29165
|
legacy2.spoolDir(),
|
|
27941
29166
|
legacy2.failedDir(),
|
|
@@ -27947,7 +29172,7 @@ function retiredLayoutPaths2() {
|
|
|
27947
29172
|
legacy2.localPoliciesDir()
|
|
27948
29173
|
];
|
|
27949
29174
|
}
|
|
27950
|
-
var LAYOUT_VERSION2 =
|
|
29175
|
+
var LAYOUT_VERSION2 = 4, at2 = (...parts) => resolve28(failproofaiHome2(), ...parts), atHome2 = (home, ...parts) => home ? resolve28(failproofaiHome2(home), ...parts) : at2(...parts), versionFile2 = (home) => atHome2(home, "VERSION"), configFile2 = (home) => atHome2(home, "config.json"), credentialsFile2 = (home) => atHome2(home, "credentials.json"), binDir2 = (home) => atHome2(home, "bin"), daemonBinary = (version3, home) => resolve28(binDir2(home), `failproofaid-${version3}`), policiesDir2 = (home) => atHome2(home, "policies"), customPoliciesDir2, globalPolicyConfigFile2 = (home) => atHome2(home, "policies-config.json"), cloudPoliciesDir2 = (home) => resolve28(policiesDir2(home), "cloud-policies"), cursorsDir2 = (source, home) => source ? resolve28(atHome2(home, "cursors"), source) : atHome2(home, "cursors"), customAgentsDir2 = (home) => atHome2(home, "custom-agents"), customAgentsEventsDir = (home) => resolve28(customAgentsDir2(home), "events"), customAgentsFailedDir = (home) => resolve28(customAgentsDir2(home), "failed"), auditDir2 = (home) => atHome2(home, "audit"), auditDashboardFile2 = (home) => resolve28(auditDir2(home), "dashboard.json"), auditCacheDir2 = (home) => resolve28(auditDir2(home), "cache"), auditSessionFile2 = (home) => resolve28(auditDir2(home), "session.json"), auditMachineFile2 = (home) => resolve28(auditDir2(home), "machine.json"), hookActivityDir2 = (home) => atHome2(home, "hook-activity"), runDir2 = (home) => atHome2(home, "run"), daemonSocket2 = () => process.env.FAILPROOFAI_DAEMON_SOCKET || resolve28(runDir2(), "failproofaid.sock"), workerSocket = (home) => resolve28(runDir2(home), "worker.sock"), daemonLock = (home) => resolve28(runDir2(home), "failproofaid.lock"), auditLockFile2 = (home) => resolve28(runDir2(home), "audit.lock"), stateDir2 = (home) => atHome2(home, "state"), shimsDir2 = (home) => resolve28(stateDir2(home), "shims"), spoolDir2 = (home) => resolve28(stateDir2(home), "spool"), failedDir2 = (home) => resolve28(stateDir2(home), "failed"), collectorHealthFile2 = (home) => resolve28(stateDir2(home), "collector-health.json"), sessionPauseDir2 = () => resolve28(stateDir2(), "sessions"), auditScheduleFile2 = (home) => resolve28(auditDir2(home), "schedule.json"), telemetryIdFile2 = (home) => resolve28(stateDir2(home), "telemetry-id"), launcherMarker2 = (home) => resolve28(stateDir2(home), "launcher-configured"), onboardingAttemptFile2 = (home) => resolve28(stateDir2(home), "onboarding-attempt.json"), lastVersionFile2 = (home) => resolve28(stateDir2(home), "last-version"), onboardingLockFile2 = (home) => resolve28(stateDir2(home), "onboarding.lock"), codexSessionPathsFile2 = (home) => resolve28(stateDir2(home), "codex-session-paths.json"), logsDir2 = (home) => atHome2(home, "logs"), migrationsDir2 = (home) => atHome2(home, "migrations"), migrationLedgerFile2 = (home) => resolve28(migrationsDir2(home), "applied.json"), migrationBackupDir2 = (layout, home) => resolve28(migrationsDir2(home), `backup-layout${layout}`), HOME_CLASSES2, legacy2;
|
|
27951
29176
|
var init_fp_home2 = __esm(() => {
|
|
27952
29177
|
customPoliciesDir2 = policiesDir2;
|
|
27953
29178
|
HOME_CLASSES2 = [
|
|
@@ -27955,20 +29180,23 @@ var init_fp_home2 = __esm(() => {
|
|
|
27955
29180
|
{ path: configFile2, class: "user-typed" },
|
|
27956
29181
|
{ path: globalPolicyConfigFile2, class: "user-typed" },
|
|
27957
29182
|
{ path: policiesDir2, class: "user-typed" },
|
|
29183
|
+
{ path: auditSessionFile2, class: "user-typed" },
|
|
27958
29184
|
{ path: spoolDir2, class: "undelivered" },
|
|
27959
29185
|
{ path: failedDir2, class: "undelivered" },
|
|
27960
29186
|
{ path: customAgentsDir2, class: "undelivered" },
|
|
27961
29187
|
{ path: hookActivityDir2, class: "undelivered" },
|
|
27962
|
-
{ path: (home) =>
|
|
27963
|
-
{ path: (home) =>
|
|
29188
|
+
{ path: (home) => resolve28(stateDir2(home), "flush-request.json"), class: "undelivered" },
|
|
29189
|
+
{ path: (home) => resolve28(stateDir2(home), "backfill-request.json"), class: "undelivered" },
|
|
27964
29190
|
{ path: cursorsDir2, class: "identity" },
|
|
27965
29191
|
{ path: telemetryIdFile2, class: "identity" },
|
|
27966
|
-
{ path: (home) =>
|
|
29192
|
+
{ path: (home) => resolve28(stateDir2(home), "daemon-telemetry-id"), class: "identity" },
|
|
27967
29193
|
{ path: versionFile2, class: "identity" },
|
|
27968
29194
|
{ path: migrationsDir2, class: "identity" },
|
|
27969
|
-
{ path:
|
|
27970
|
-
{ path:
|
|
29195
|
+
{ path: auditMachineFile2, class: "identity" },
|
|
29196
|
+
{ path: auditDashboardFile2, class: "derived" },
|
|
29197
|
+
{ path: auditCacheDir2, class: "derived" },
|
|
27971
29198
|
{ path: auditScheduleFile2, class: "derived" },
|
|
29199
|
+
{ path: collectorHealthFile2, class: "derived" },
|
|
27972
29200
|
{ path: codexSessionPathsFile2, class: "derived" },
|
|
27973
29201
|
{ path: shimsDir2, class: "derived" },
|
|
27974
29202
|
{ path: sessionPauseDir2, class: "derived" },
|
|
@@ -27994,6 +29222,10 @@ var init_fp_home2 = __esm(() => {
|
|
|
27994
29222
|
launcherMarker: () => at2(".launcher-configured"),
|
|
27995
29223
|
lastVersion: () => at2("last-version"),
|
|
27996
29224
|
auditDashboard: () => at2("audit-dashboard.json"),
|
|
29225
|
+
authJson: () => at2("auth.json"),
|
|
29226
|
+
nextAudit: () => at2("next-audit.json"),
|
|
29227
|
+
auditReminder: () => at2("audit", "reminder.json"),
|
|
29228
|
+
auditSchedule: () => at2("state", "audit-schedule.json"),
|
|
27997
29229
|
cacheDir: () => at2("cache"),
|
|
27998
29230
|
hookActivityDir: () => at2("cache", "hook-activity"),
|
|
27999
29231
|
auditCacheDir: () => at2("cache", "audit"),
|
|
@@ -28013,26 +29245,83 @@ __export(exports_migrations2, {
|
|
|
28013
29245
|
runMigrations: () => runMigrations2,
|
|
28014
29246
|
restoreBackup: () => restoreBackup2,
|
|
28015
29247
|
readLedger: () => readLedger2,
|
|
29248
|
+
pruneMigratedCredentials: () => pruneMigratedCredentials2,
|
|
28016
29249
|
planMigration: () => planMigration2,
|
|
28017
29250
|
migrationCoverageGap: () => migrationCoverageGap2,
|
|
28018
29251
|
describePlan: () => describePlan2,
|
|
28019
29252
|
backupBeforeMigrating: () => backupBeforeMigrating2,
|
|
28020
29253
|
MIGRATIONS: () => MIGRATIONS2
|
|
28021
29254
|
});
|
|
28022
|
-
import {
|
|
28023
|
-
|
|
29255
|
+
import {
|
|
29256
|
+
chmodSync as chmodSync7,
|
|
29257
|
+
copyFileSync as copyFileSync4,
|
|
29258
|
+
existsSync as existsSync40,
|
|
29259
|
+
mkdirSync as mkdirSync25,
|
|
29260
|
+
readFileSync as readFileSync33,
|
|
29261
|
+
renameSync as renameSync8,
|
|
29262
|
+
rmSync as rmSync14,
|
|
29263
|
+
writeFileSync as writeFileSync23
|
|
29264
|
+
} from "node:fs";
|
|
29265
|
+
import { basename as basename7, dirname as dirname22, join as join36, resolve as resolve29 } from "node:path";
|
|
29266
|
+
function migrateToLayout42() {
|
|
29267
|
+
const moves = [
|
|
29268
|
+
{ from: legacy.authJson(), to: auditSessionFile() },
|
|
29269
|
+
{ from: legacy.nextAudit(), to: legacy.auditReminder() },
|
|
29270
|
+
{ from: legacy.auditSchedule(), to: auditScheduleFile() }
|
|
29271
|
+
];
|
|
29272
|
+
const authDirOverride = process.env.FAILPROOFAI_AUTH_DIR;
|
|
29273
|
+
if (authDirOverride) {
|
|
29274
|
+
moves.push({ from: join36(authDirOverride, "auth.json"), to: join36(authDirOverride, "session.json") }, {
|
|
29275
|
+
from: join36(authDirOverride, "next-audit.json"),
|
|
29276
|
+
to: join36(authDirOverride, "reminder.json")
|
|
29277
|
+
});
|
|
29278
|
+
}
|
|
29279
|
+
const migrated = [];
|
|
29280
|
+
for (const { from, to } of moves) {
|
|
29281
|
+
if (!existsSync40(from))
|
|
29282
|
+
continue;
|
|
29283
|
+
if (existsSync40(to)) {
|
|
29284
|
+
rmSync14(from, { force: true });
|
|
29285
|
+
continue;
|
|
29286
|
+
}
|
|
29287
|
+
mkdirSync25(dirname22(to), { recursive: true });
|
|
29288
|
+
try {
|
|
29289
|
+
renameSync8(from, to);
|
|
29290
|
+
} catch {
|
|
29291
|
+
try {
|
|
29292
|
+
copyFileSync4(from, to);
|
|
29293
|
+
} catch (err) {
|
|
29294
|
+
try {
|
|
29295
|
+
rmSync14(to, { force: true });
|
|
29296
|
+
} catch {}
|
|
29297
|
+
throw err;
|
|
29298
|
+
}
|
|
29299
|
+
rmSync14(from, { force: true });
|
|
29300
|
+
}
|
|
29301
|
+
migrated.push(`${basename7(from)} → audit/${basename7(to)}`);
|
|
29302
|
+
}
|
|
29303
|
+
for (const secret of [auditSessionFile()]) {
|
|
29304
|
+
if (!existsSync40(secret))
|
|
29305
|
+
continue;
|
|
29306
|
+
try {
|
|
29307
|
+
chmodSync7(secret, 384);
|
|
29308
|
+
} catch {}
|
|
29309
|
+
}
|
|
29310
|
+
writeVersionFile({ layout: 4 });
|
|
29311
|
+
return { removed: [], migrated, activity: [], policyConfig: [], spooled: [], from: 3 };
|
|
29312
|
+
}
|
|
28024
29313
|
function planMigration2(from, registry = MIGRATIONS2) {
|
|
28025
29314
|
if (from >= LAYOUT_VERSION)
|
|
28026
29315
|
return [];
|
|
28027
29316
|
const chain = [];
|
|
28028
29317
|
let at3 = from;
|
|
28029
29318
|
while (at3 < LAYOUT_VERSION) {
|
|
28030
|
-
const
|
|
28031
|
-
if (!
|
|
29319
|
+
const step2 = registry.find((m) => m.from === at3);
|
|
29320
|
+
if (!step2) {
|
|
28032
29321
|
throw new Error(`no migration from layout ${at3} to ${LAYOUT_VERSION} — this build cannot upgrade that home`);
|
|
28033
29322
|
}
|
|
28034
|
-
chain.push(
|
|
28035
|
-
at3 =
|
|
29323
|
+
chain.push(step2);
|
|
29324
|
+
at3 = step2.to;
|
|
28036
29325
|
}
|
|
28037
29326
|
return chain;
|
|
28038
29327
|
}
|
|
@@ -28058,7 +29347,7 @@ function migrationCoverageGap2(registry = MIGRATIONS2) {
|
|
|
28058
29347
|
}
|
|
28059
29348
|
function readLedger2() {
|
|
28060
29349
|
try {
|
|
28061
|
-
const parsed = JSON.parse(
|
|
29350
|
+
const parsed = JSON.parse(readFileSync33(migrationLedgerFile(), "utf8"));
|
|
28062
29351
|
return Array.isArray(parsed) ? parsed : [];
|
|
28063
29352
|
} catch {
|
|
28064
29353
|
return [];
|
|
@@ -28075,11 +29364,28 @@ function appendLedger2(entry) {
|
|
|
28075
29364
|
function backupNameOf2(f) {
|
|
28076
29365
|
return f.as ?? basename7(f.at());
|
|
28077
29366
|
}
|
|
29367
|
+
function pruneMigratedCredentials2(from) {
|
|
29368
|
+
const pruned = [];
|
|
29369
|
+
for (let layout = from;layout < LAYOUT_VERSION; layout++) {
|
|
29370
|
+
for (const { as, landsAt } of PRUNED_AFTER_SUCCESS2) {
|
|
29371
|
+
try {
|
|
29372
|
+
if (!existsSync40(landsAt()))
|
|
29373
|
+
continue;
|
|
29374
|
+
const copy = resolve29(migrationBackupDir(layout), as);
|
|
29375
|
+
if (!existsSync40(copy))
|
|
29376
|
+
continue;
|
|
29377
|
+
rmSync14(copy, { force: true });
|
|
29378
|
+
pruned.push(as);
|
|
29379
|
+
} catch {}
|
|
29380
|
+
}
|
|
29381
|
+
}
|
|
29382
|
+
return pruned;
|
|
29383
|
+
}
|
|
28078
29384
|
function filesToBackUp2() {
|
|
28079
29385
|
const seen = new Map;
|
|
28080
29386
|
for (const f of [...BACKED_UP2, ...BACKED_UP_LEGACY2]) {
|
|
28081
29387
|
const path3 = f.at();
|
|
28082
|
-
if (
|
|
29388
|
+
if (existsSync40(path3))
|
|
28083
29389
|
seen.set(path3, backupNameOf2(f));
|
|
28084
29390
|
}
|
|
28085
29391
|
return [...seen].map(([path3, as]) => ({ path: path3, as }));
|
|
@@ -28088,14 +29394,14 @@ function backupBeforeMigrating2(from) {
|
|
|
28088
29394
|
const dir = migrationBackupDir(from);
|
|
28089
29395
|
const saved = [];
|
|
28090
29396
|
try {
|
|
28091
|
-
|
|
29397
|
+
rmSync14(dir, { recursive: true, force: true });
|
|
28092
29398
|
mkdirSync25(dir, { recursive: true });
|
|
28093
29399
|
} catch {
|
|
28094
29400
|
return [];
|
|
28095
29401
|
}
|
|
28096
29402
|
for (const { path: source, as } of filesToBackUp2()) {
|
|
28097
29403
|
try {
|
|
28098
|
-
copyFileSync4(source,
|
|
29404
|
+
copyFileSync4(source, resolve29(dir, as));
|
|
28099
29405
|
saved.push(as);
|
|
28100
29406
|
} catch {}
|
|
28101
29407
|
}
|
|
@@ -28113,19 +29419,19 @@ function runMigrations2(from, chain = planMigration2(from)) {
|
|
|
28113
29419
|
from
|
|
28114
29420
|
};
|
|
28115
29421
|
let failed;
|
|
28116
|
-
for (const
|
|
29422
|
+
for (const step2 of chain) {
|
|
28117
29423
|
const startedAt = Date.now();
|
|
28118
29424
|
try {
|
|
28119
|
-
const result =
|
|
29425
|
+
const result = step2.run();
|
|
28120
29426
|
outcome.removed.push(...result.removed);
|
|
28121
29427
|
outcome.migrated.push(...result.migrated);
|
|
28122
29428
|
outcome.activity.push(...result.activity);
|
|
28123
29429
|
outcome.policyConfig.push(...result.policyConfig);
|
|
28124
29430
|
outcome.spooled.push(...result.spooled);
|
|
28125
|
-
steps.push({ from:
|
|
29431
|
+
steps.push({ from: step2.from, to: step2.to, ok: true });
|
|
28126
29432
|
appendLedger2({
|
|
28127
|
-
from:
|
|
28128
|
-
to:
|
|
29433
|
+
from: step2.from,
|
|
29434
|
+
to: step2.to,
|
|
28129
29435
|
cli: version2,
|
|
28130
29436
|
at: new Date(startedAt).toISOString(),
|
|
28131
29437
|
durationMs: Date.now() - startedAt,
|
|
@@ -28135,15 +29441,20 @@ function runMigrations2(from, chain = planMigration2(from)) {
|
|
|
28135
29441
|
activity: result.activity.length
|
|
28136
29442
|
});
|
|
28137
29443
|
} catch (err) {
|
|
28138
|
-
steps.push({ from:
|
|
29444
|
+
steps.push({ from: step2.from, to: step2.to, ok: false });
|
|
29445
|
+
try {
|
|
29446
|
+
const marker = readVersionFile();
|
|
29447
|
+
if (marker && marker.layout >= LAYOUT_VERSION)
|
|
29448
|
+
writeVersionFile({ layout: step2.from });
|
|
29449
|
+
} catch {}
|
|
28139
29450
|
failed = {
|
|
28140
|
-
from:
|
|
28141
|
-
to:
|
|
29451
|
+
from: step2.from,
|
|
29452
|
+
to: step2.to,
|
|
28142
29453
|
error: err instanceof Error ? err.message : String(err)
|
|
28143
29454
|
};
|
|
28144
29455
|
appendLedger2({
|
|
28145
|
-
from:
|
|
28146
|
-
to:
|
|
29456
|
+
from: step2.from,
|
|
29457
|
+
to: step2.to,
|
|
28147
29458
|
cli: version2,
|
|
28148
29459
|
at: new Date(startedAt).toISOString(),
|
|
28149
29460
|
durationMs: Date.now() - startedAt,
|
|
@@ -28152,6 +29463,8 @@ function runMigrations2(from, chain = planMigration2(from)) {
|
|
|
28152
29463
|
break;
|
|
28153
29464
|
}
|
|
28154
29465
|
}
|
|
29466
|
+
if (!failed)
|
|
29467
|
+
pruneMigratedCredentials2(from);
|
|
28155
29468
|
return { from, steps, backedUp, outcome, failed };
|
|
28156
29469
|
}
|
|
28157
29470
|
function describePlan2(from) {
|
|
@@ -28178,13 +29491,13 @@ function describePlan2(from) {
|
|
|
28178
29491
|
}
|
|
28179
29492
|
function restoreBackup2(layout) {
|
|
28180
29493
|
const dir = migrationBackupDir(layout);
|
|
28181
|
-
if (!
|
|
29494
|
+
if (!existsSync40(dir))
|
|
28182
29495
|
return [];
|
|
28183
29496
|
const restored = [];
|
|
28184
29497
|
for (const f of [...BACKED_UP2, ...BACKED_UP_LEGACY2]) {
|
|
28185
29498
|
const target = f.at();
|
|
28186
|
-
const source =
|
|
28187
|
-
if (!
|
|
29499
|
+
const source = resolve29(dir, backupNameOf2(f));
|
|
29500
|
+
if (!existsSync40(source))
|
|
28188
29501
|
continue;
|
|
28189
29502
|
try {
|
|
28190
29503
|
mkdirSync25(dirname22(target), { recursive: true });
|
|
@@ -28194,23 +29507,30 @@ function restoreBackup2(layout) {
|
|
|
28194
29507
|
}
|
|
28195
29508
|
return restored.sort((a, b) => a.localeCompare(b));
|
|
28196
29509
|
}
|
|
28197
|
-
var MIGRATIONS2, BACKED_UP2, BACKED_UP_LEGACY2;
|
|
29510
|
+
var MIGRATIONS2, BACKED_UP2, BACKED_UP_LEGACY2, PRUNED_AFTER_SUCCESS2;
|
|
28198
29511
|
var init_migrations2 = __esm(() => {
|
|
28199
29512
|
init_package();
|
|
28200
29513
|
init_fp_home();
|
|
29514
|
+
init_fp_config();
|
|
28201
29515
|
init_fp_reset();
|
|
28202
29516
|
MIGRATIONS2 = [
|
|
28203
29517
|
{
|
|
28204
29518
|
from: 1,
|
|
28205
29519
|
to: 3,
|
|
28206
29520
|
describe: "layout 1 → 3: carry the decision log out of cache/, keep the policy config in place, drop the layout-1 credential files",
|
|
28207
|
-
run: () => resetHome(1)
|
|
29521
|
+
run: () => resetHome(1, 3)
|
|
28208
29522
|
},
|
|
28209
29523
|
{
|
|
28210
29524
|
from: 2,
|
|
28211
29525
|
to: 3,
|
|
28212
29526
|
describe: "layout 2 → 3: carry config.toml and credentials.toml into JSON, move custom-policies/ back up into policies/, nest the policy config at the root",
|
|
28213
|
-
run: () => resetHome(2)
|
|
29527
|
+
run: () => resetHome(2, 3)
|
|
29528
|
+
},
|
|
29529
|
+
{
|
|
29530
|
+
from: 3,
|
|
29531
|
+
to: 4,
|
|
29532
|
+
describe: "layout 3 → 4: gather the audit's files under audit/ — auth.json becomes audit/session.json, next-audit.json becomes audit/reminder.json, state/audit-schedule.json becomes audit/schedule.json",
|
|
29533
|
+
run: migrateToLayout42
|
|
28214
29534
|
}
|
|
28215
29535
|
];
|
|
28216
29536
|
BACKED_UP2 = [
|
|
@@ -28225,7 +29545,13 @@ var init_migrations2 = __esm(() => {
|
|
|
28225
29545
|
{ at: legacy.policyConfig },
|
|
28226
29546
|
{ at: legacy.localPolicyConfig, as: "local-policies-policies-config.json" },
|
|
28227
29547
|
{ at: legacy.cloudCredentials },
|
|
28228
|
-
{ at: legacy.ingestCredentials }
|
|
29548
|
+
{ at: legacy.ingestCredentials },
|
|
29549
|
+
{ at: legacy.authJson },
|
|
29550
|
+
{ at: legacy.nextAudit },
|
|
29551
|
+
{ at: legacy.auditSchedule }
|
|
29552
|
+
];
|
|
29553
|
+
PRUNED_AFTER_SUCCESS2 = [
|
|
29554
|
+
{ as: basename7(legacy.authJson()), landsAt: auditSessionFile }
|
|
28229
29555
|
];
|
|
28230
29556
|
});
|
|
28231
29557
|
|
|
@@ -28237,6 +29563,7 @@ __export(exports_daemon_service, {
|
|
|
28237
29563
|
upgradedServiceDefinition: () => upgradedServiceDefinition2,
|
|
28238
29564
|
uninstallDaemonService: () => uninstallDaemonService2,
|
|
28239
29565
|
systemdUnitContents: () => systemdUnitContents2,
|
|
29566
|
+
startedAtFromMonotonic: () => startedAtFromMonotonic,
|
|
28240
29567
|
setDaemonConfigured: () => setDaemonConfigured2,
|
|
28241
29568
|
resolveWorkerCommand: () => resolveWorkerCommand2,
|
|
28242
29569
|
resolveFailproofaidBinaryPath: () => resolveFailproofaidBinaryPath2,
|
|
@@ -28253,6 +29580,7 @@ __export(exports_daemon_service, {
|
|
|
28253
29580
|
ensureDaemonServiceCurrent: () => ensureDaemonServiceCurrent2,
|
|
28254
29581
|
daemonVersionSkew: () => daemonVersionSkew2,
|
|
28255
29582
|
daemonStatusCommand: () => daemonStatusCommand2,
|
|
29583
|
+
daemonStartedAtMs: () => daemonStartedAtMs,
|
|
28256
29584
|
daemonServiceStatus: () => daemonServiceStatus2,
|
|
28257
29585
|
daemonServiceNeedsUpgrade: () => daemonServiceNeedsUpgrade2,
|
|
28258
29586
|
daemonServiceFilePath: () => daemonServiceFilePath2,
|
|
@@ -28260,16 +29588,16 @@ __export(exports_daemon_service, {
|
|
|
28260
29588
|
canElevate: () => canElevate2
|
|
28261
29589
|
});
|
|
28262
29590
|
import {
|
|
28263
|
-
existsSync as
|
|
29591
|
+
existsSync as existsSync41,
|
|
28264
29592
|
mkdirSync as mkdirSync26,
|
|
28265
29593
|
mkdtempSync as mkdtempSync2,
|
|
28266
|
-
readFileSync as
|
|
29594
|
+
readFileSync as readFileSync34,
|
|
28267
29595
|
writeFileSync as writeFileSync24,
|
|
28268
29596
|
unlinkSync as unlinkSync5,
|
|
28269
|
-
rmSync as
|
|
29597
|
+
rmSync as rmSync15
|
|
28270
29598
|
} from "node:fs";
|
|
28271
|
-
import { homedir as
|
|
28272
|
-
import { resolve as
|
|
29599
|
+
import { homedir as homedir30, tmpdir as tmpdir3, userInfo as userInfo2 } from "node:os";
|
|
29600
|
+
import { resolve as resolve30 } from "node:path";
|
|
28273
29601
|
import { execFileSync as execFileSync5 } from "node:child_process";
|
|
28274
29602
|
function setDaemonConfigured2(value, installedVersion) {
|
|
28275
29603
|
try {
|
|
@@ -28291,13 +29619,13 @@ function resolveFailproofaidBinaryPath2() {
|
|
|
28291
29619
|
if (process.env.FAILPROOFAI_DAEMON_BINARY)
|
|
28292
29620
|
return process.env.FAILPROOFAI_DAEMON_BINARY;
|
|
28293
29621
|
const downloaded = installedBinaryPath();
|
|
28294
|
-
if (
|
|
29622
|
+
if (existsSync41(downloaded))
|
|
28295
29623
|
return downloaded;
|
|
28296
29624
|
const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT;
|
|
28297
29625
|
if (packageRoot) {
|
|
28298
29626
|
for (const profile of ["release", "debug"]) {
|
|
28299
|
-
const candidate =
|
|
28300
|
-
if (
|
|
29627
|
+
const candidate = resolve30(packageRoot, "target", profile, "failproofaid");
|
|
29628
|
+
if (existsSync41(candidate))
|
|
28301
29629
|
return candidate;
|
|
28302
29630
|
}
|
|
28303
29631
|
}
|
|
@@ -28327,8 +29655,8 @@ function resolveWorkerCommand2() {
|
|
|
28327
29655
|
const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT;
|
|
28328
29656
|
if (!packageRoot)
|
|
28329
29657
|
return null;
|
|
28330
|
-
const workerScript =
|
|
28331
|
-
if (!
|
|
29658
|
+
const workerScript = resolve30(packageRoot, "dist", "worker.mjs");
|
|
29659
|
+
if (!existsSync41(workerScript))
|
|
28332
29660
|
return null;
|
|
28333
29661
|
return `${shellQuote2(process.execPath)} ${shellQuote2(workerScript)}`;
|
|
28334
29662
|
}
|
|
@@ -28338,8 +29666,8 @@ function resolveCliCommand2() {
|
|
|
28338
29666
|
const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT;
|
|
28339
29667
|
if (!packageRoot)
|
|
28340
29668
|
return null;
|
|
28341
|
-
const cliScript =
|
|
28342
|
-
if (!
|
|
29669
|
+
const cliScript = resolve30(packageRoot, "dist", "cli.mjs");
|
|
29670
|
+
if (!existsSync41(cliScript))
|
|
28343
29671
|
return null;
|
|
28344
29672
|
return `${shellQuote2(process.execPath)} ${shellQuote2(cliScript)}`;
|
|
28345
29673
|
}
|
|
@@ -28352,8 +29680,8 @@ function workerScriptPath2() {
|
|
|
28352
29680
|
const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT;
|
|
28353
29681
|
if (!packageRoot)
|
|
28354
29682
|
return null;
|
|
28355
|
-
const workerScript =
|
|
28356
|
-
return
|
|
29683
|
+
const workerScript = resolve30(packageRoot, "dist", "worker.mjs");
|
|
29684
|
+
return existsSync41(workerScript) ? workerScript : null;
|
|
28357
29685
|
}
|
|
28358
29686
|
function assertUnitSafe2(value, field) {
|
|
28359
29687
|
if (UNIT_UNSAFE_RE2.test(value)) {
|
|
@@ -28379,10 +29707,10 @@ function systemdUnitDir2() {
|
|
|
28379
29707
|
return process.env.FAILPROOFAI_SYSTEMD_DIR || "/etc/systemd/system";
|
|
28380
29708
|
}
|
|
28381
29709
|
function systemdUnitPath2(user = serviceUser2()) {
|
|
28382
|
-
return
|
|
29710
|
+
return resolve30(systemdUnitDir2(), systemdUnitName2(user));
|
|
28383
29711
|
}
|
|
28384
29712
|
function legacySystemdUserUnitPath2() {
|
|
28385
|
-
return
|
|
29713
|
+
return resolve30(homedir30(), ".config", "systemd", "user", "failproofaid.service");
|
|
28386
29714
|
}
|
|
28387
29715
|
function launchdLabel2(user = serviceUser2()) {
|
|
28388
29716
|
return `ai.failproof.failproofaid.${user}`;
|
|
@@ -28391,7 +29719,7 @@ function launchdPlistPath2(user = serviceUser2()) {
|
|
|
28391
29719
|
return `/Library/LaunchDaemons/${launchdLabel2(user)}.plist`;
|
|
28392
29720
|
}
|
|
28393
29721
|
function legacyLaunchAgentPlistPath2() {
|
|
28394
|
-
return
|
|
29722
|
+
return resolve30(homedir30(), "Library", "LaunchAgents", "ai.failproof.failproofaid.plist");
|
|
28395
29723
|
}
|
|
28396
29724
|
function legacySharedLaunchDaemonPath2() {
|
|
28397
29725
|
return "/Library/LaunchDaemons/ai.failproof.failproofaid.plist";
|
|
@@ -28439,20 +29767,20 @@ function runPrivileged2(command, args) {
|
|
|
28439
29767
|
execFileSync5(cmd, argv, { stdio: "ignore", timeout: SERVICE_CMD_TIMEOUT_MS2 });
|
|
28440
29768
|
}
|
|
28441
29769
|
function writePrivilegedFile2(destination, contents, mode = "0644") {
|
|
28442
|
-
const stagingDir = mkdtempSync2(
|
|
28443
|
-
const staging =
|
|
29770
|
+
const stagingDir = mkdtempSync2(resolve30(tmpdir3(), "failproofaid-stage-"));
|
|
29771
|
+
const staging = resolve30(stagingDir, "service-definition");
|
|
28444
29772
|
try {
|
|
28445
29773
|
writeFileSync24(staging, contents, "utf8");
|
|
28446
29774
|
runPrivileged2("install", ["-m", mode, staging, destination]);
|
|
28447
29775
|
} finally {
|
|
28448
|
-
|
|
29776
|
+
rmSync15(stagingDir, { recursive: true, force: true });
|
|
28449
29777
|
}
|
|
28450
29778
|
}
|
|
28451
29779
|
function removeLegacyUserService2() {
|
|
28452
29780
|
try {
|
|
28453
29781
|
if (process.platform === "linux") {
|
|
28454
29782
|
const legacy3 = legacySystemdUserUnitPath2();
|
|
28455
|
-
if (!
|
|
29783
|
+
if (!existsSync41(legacy3))
|
|
28456
29784
|
return;
|
|
28457
29785
|
try {
|
|
28458
29786
|
execFileSync5("systemctl", ["--user", "disable", "--now", "failproofaid.service"], {
|
|
@@ -28469,7 +29797,7 @@ function removeLegacyUserService2() {
|
|
|
28469
29797
|
} catch {}
|
|
28470
29798
|
} else {
|
|
28471
29799
|
const legacyAgent = legacyLaunchAgentPlistPath2();
|
|
28472
|
-
if (
|
|
29800
|
+
if (existsSync41(legacyAgent)) {
|
|
28473
29801
|
try {
|
|
28474
29802
|
execFileSync5("launchctl", ["unload", "-w", legacyAgent], {
|
|
28475
29803
|
stdio: "ignore",
|
|
@@ -28479,7 +29807,7 @@ function removeLegacyUserService2() {
|
|
|
28479
29807
|
unlinkSync5(legacyAgent);
|
|
28480
29808
|
}
|
|
28481
29809
|
const legacyDaemon = legacySharedLaunchDaemonPath2();
|
|
28482
|
-
if (
|
|
29810
|
+
if (existsSync41(legacyDaemon)) {
|
|
28483
29811
|
try {
|
|
28484
29812
|
runPrivileged2("launchctl", ["unload", "-w", legacyDaemon]);
|
|
28485
29813
|
} catch {}
|
|
@@ -28495,8 +29823,8 @@ function systemdUnitContents2(binaryPath, workerCmd, cliCmd = null) {
|
|
|
28495
29823
|
`).join("");
|
|
28496
29824
|
const user = assertUnitSafe2(serviceUser2(), "User");
|
|
28497
29825
|
assertUnitSafe2(binaryPath, "ExecStart");
|
|
28498
|
-
assertUnitSafe2(
|
|
28499
|
-
const conditionPaths = [binaryPath, workerScriptPath2()].filter((p) => typeof p === "string" &&
|
|
29826
|
+
assertUnitSafe2(homedir30(), "HOME");
|
|
29827
|
+
const conditionPaths = [binaryPath, workerScriptPath2()].filter((p) => typeof p === "string" && existsSync41(p));
|
|
28500
29828
|
const conditionLines = conditionPaths.map((p) => `ConditionPathExists=${assertUnitSafe2(p, "ConditionPathExists")}
|
|
28501
29829
|
`).join("");
|
|
28502
29830
|
return `[Unit]
|
|
@@ -28509,7 +29837,7 @@ User=${user}
|
|
|
28509
29837
|
# Set explicitly rather than relying on systemd deriving it from User=:
|
|
28510
29838
|
# failproofaid stores per-user state and refuses to start without HOME, so this
|
|
28511
29839
|
# required variable is not left to a version-dependent default.
|
|
28512
|
-
Environment="HOME=${
|
|
29840
|
+
Environment="HOME=${homedir30()}"
|
|
28513
29841
|
${envLines}ExecStart=${binaryPath}
|
|
28514
29842
|
Restart=on-failure
|
|
28515
29843
|
RestartSec=2
|
|
@@ -28557,9 +29885,9 @@ ${env.map(([key, value]) => ` <key>${key}</key>
|
|
|
28557
29885
|
<key>UserName</key>
|
|
28558
29886
|
<string>${escapeXml2(serviceUser2())}</string>
|
|
28559
29887
|
${envBlock} <key>StandardOutPath</key>
|
|
28560
|
-
<string>${escapeXml2(
|
|
29888
|
+
<string>${escapeXml2(resolve30(logDir2, "failproofaid.log"))}</string>
|
|
28561
29889
|
<key>StandardErrorPath</key>
|
|
28562
|
-
<string>${escapeXml2(
|
|
29890
|
+
<string>${escapeXml2(resolve30(logDir2, "failproofaid.err.log"))}</string>
|
|
28563
29891
|
</dict>
|
|
28564
29892
|
</plist>
|
|
28565
29893
|
`;
|
|
@@ -28691,10 +30019,10 @@ function readInstalledServiceDefinition2() {
|
|
|
28691
30019
|
if (!isDaemonSupportedPlatform2())
|
|
28692
30020
|
return null;
|
|
28693
30021
|
const path3 = daemonServiceFilePath2();
|
|
28694
|
-
if (!path3 || !
|
|
30022
|
+
if (!path3 || !existsSync41(path3))
|
|
28695
30023
|
return null;
|
|
28696
30024
|
try {
|
|
28697
|
-
return
|
|
30025
|
+
return readFileSync34(path3, "utf8");
|
|
28698
30026
|
} catch {
|
|
28699
30027
|
return null;
|
|
28700
30028
|
}
|
|
@@ -28855,7 +30183,7 @@ async function uninstallDaemonService2() {
|
|
|
28855
30183
|
try {
|
|
28856
30184
|
if (process.platform === "linux") {
|
|
28857
30185
|
const unitPath = systemdUnitPath2();
|
|
28858
|
-
if (!
|
|
30186
|
+
if (!existsSync41(unitPath))
|
|
28859
30187
|
return;
|
|
28860
30188
|
try {
|
|
28861
30189
|
runPrivileged2("systemctl", ["disable", "--now", systemdUnitName2()]);
|
|
@@ -28866,7 +30194,7 @@ async function uninstallDaemonService2() {
|
|
|
28866
30194
|
} catch {}
|
|
28867
30195
|
} else {
|
|
28868
30196
|
const plistPath = launchdPlistPath2();
|
|
28869
|
-
if (!
|
|
30197
|
+
if (!existsSync41(plistPath))
|
|
28870
30198
|
return;
|
|
28871
30199
|
try {
|
|
28872
30200
|
runPrivileged2("launchctl", ["unload", "-w", plistPath]);
|
|
@@ -28883,7 +30211,7 @@ function daemonVersionSkew2() {
|
|
|
28883
30211
|
const recorded = readVersionFile()?.daemon;
|
|
28884
30212
|
if (!recorded)
|
|
28885
30213
|
return null;
|
|
28886
|
-
if (!
|
|
30214
|
+
if (!existsSync41(installedBinaryPath(recorded)))
|
|
28887
30215
|
return null;
|
|
28888
30216
|
return recorded === version2 ? null : { installed: recorded, expected: version2 };
|
|
28889
30217
|
}
|
|
@@ -28901,7 +30229,7 @@ function daemonServiceStatus2() {
|
|
|
28901
30229
|
if (!isDaemonSupportedPlatform2())
|
|
28902
30230
|
return "unsupported-platform";
|
|
28903
30231
|
if (process.platform === "linux") {
|
|
28904
|
-
if (!
|
|
30232
|
+
if (!existsSync41(systemdUnitPath2()))
|
|
28905
30233
|
return "not-installed";
|
|
28906
30234
|
try {
|
|
28907
30235
|
const out = execFileSync5("systemctl", ["is-active", systemdUnitName2()], {
|
|
@@ -28914,7 +30242,7 @@ function daemonServiceStatus2() {
|
|
|
28914
30242
|
}
|
|
28915
30243
|
}
|
|
28916
30244
|
const plistPath = launchdPlistPath2();
|
|
28917
|
-
if (!
|
|
30245
|
+
if (!existsSync41(plistPath))
|
|
28918
30246
|
return "not-installed";
|
|
28919
30247
|
try {
|
|
28920
30248
|
const root = typeof process.getuid === "function" && process.getuid() === 0;
|
|
@@ -28933,6 +30261,28 @@ function daemonServiceStatus2() {
|
|
|
28933
30261
|
return "stopped";
|
|
28934
30262
|
}
|
|
28935
30263
|
}
|
|
30264
|
+
function daemonStartedAtMs() {
|
|
30265
|
+
if (process.platform !== "linux")
|
|
30266
|
+
return null;
|
|
30267
|
+
if (!existsSync41(systemdUnitPath2()))
|
|
30268
|
+
return null;
|
|
30269
|
+
try {
|
|
30270
|
+
const raw = execFileSync5("systemctl", ["show", systemdUnitName2(), "-p", "ActiveEnterTimestampMonotonic", "--value"], { stdio: ["ignore", "pipe", "ignore"], timeout: SERVICE_CMD_TIMEOUT_MS2 }).toString().trim();
|
|
30271
|
+
return startedAtFromMonotonic(Number(raw), Math.floor(Number(process.hrtime.bigint()) / 1000), Date.now());
|
|
30272
|
+
} catch {
|
|
30273
|
+
return null;
|
|
30274
|
+
}
|
|
30275
|
+
}
|
|
30276
|
+
function startedAtFromMonotonic(activeEnterMonotonicUs, monotonicNowUs, nowMs) {
|
|
30277
|
+
if (!Number.isFinite(activeEnterMonotonicUs) || activeEnterMonotonicUs <= 0)
|
|
30278
|
+
return null;
|
|
30279
|
+
if (!Number.isFinite(monotonicNowUs) || monotonicNowUs <= 0)
|
|
30280
|
+
return null;
|
|
30281
|
+
const activeForMs = (monotonicNowUs - activeEnterMonotonicUs) / 1000;
|
|
30282
|
+
if (activeForMs < 0)
|
|
30283
|
+
return null;
|
|
30284
|
+
return Math.round(nowMs - activeForMs);
|
|
30285
|
+
}
|
|
28936
30286
|
var SERVICE_CMD_TIMEOUT_MS2 = 1e4, SERVICE_START_TIMEOUT_MS2 = 5000, SERVICE_START_POLL_MS2 = 100, SERVICE_SETTLE_MS2 = 750, SUDO_PROMPT_TIMEOUT_MS2 = 120000, UNIT_UNSAFE_RE2, DAEMON_PROBE_TIMEOUT_MS2 = 5000, DAEMON_PROBE_READY_TIMEOUT_MS2 = 1e4, DAEMON_PROBE_RETRY_MS2 = 150;
|
|
28937
30287
|
var init_daemon_service2 = __esm(() => {
|
|
28938
30288
|
init_hook_logger();
|
|
@@ -28949,7 +30299,7 @@ __export(exports_uninstall_cli, {
|
|
|
28949
30299
|
serviceStateLabel: () => serviceStateLabel,
|
|
28950
30300
|
runUninstallCommand: () => runUninstallCommand
|
|
28951
30301
|
});
|
|
28952
|
-
import { existsSync as
|
|
30302
|
+
import { existsSync as existsSync42, rmSync as rmSync16 } from "node:fs";
|
|
28953
30303
|
function survey(cwd) {
|
|
28954
30304
|
const clis = [];
|
|
28955
30305
|
for (const id of listInstallableIds()) {
|
|
@@ -28970,9 +30320,9 @@ function survey(cwd) {
|
|
|
28970
30320
|
return {
|
|
28971
30321
|
clis,
|
|
28972
30322
|
servicePath,
|
|
28973
|
-
serviceInstalled: !!servicePath &&
|
|
30323
|
+
serviceInstalled: !!servicePath && existsSync42(servicePath),
|
|
28974
30324
|
daemonConfigured,
|
|
28975
|
-
homeExists:
|
|
30325
|
+
homeExists: existsSync42(failproofaiHome())
|
|
28976
30326
|
};
|
|
28977
30327
|
}
|
|
28978
30328
|
async function runUninstallCommand(opts = {}) {
|
|
@@ -29070,7 +30420,7 @@ async function runUninstallCommand(opts = {}) {
|
|
|
29070
30420
|
} catch {}
|
|
29071
30421
|
try {
|
|
29072
30422
|
await uninstallDaemonService();
|
|
29073
|
-
if (found.servicePath &&
|
|
30423
|
+
if (found.servicePath && existsSync42(found.servicePath)) {
|
|
29074
30424
|
failures.push(`the service at ${found.servicePath} is still there (most often: no sudo). ` + `Remove it with the commands below.`);
|
|
29075
30425
|
} else {
|
|
29076
30426
|
lines.push(`✓ stopped and removed the daemon service`);
|
|
@@ -29082,7 +30432,7 @@ async function runUninstallCommand(opts = {}) {
|
|
|
29082
30432
|
}
|
|
29083
30433
|
if (opts.purge && found.homeExists) {
|
|
29084
30434
|
try {
|
|
29085
|
-
|
|
30435
|
+
rmSync16(failproofaiHome(), { recursive: true, force: true });
|
|
29086
30436
|
purged = true;
|
|
29087
30437
|
lines.push(`✓ deleted ${failproofaiHome()}`);
|
|
29088
30438
|
} catch (err) {
|
|
@@ -29093,7 +30443,7 @@ async function runUninstallCommand(opts = {}) {
|
|
|
29093
30443
|
lines.push(``, `Not everything could be removed:`);
|
|
29094
30444
|
for (const f of failures)
|
|
29095
30445
|
lines.push(` ✗ ${f}`);
|
|
29096
|
-
if (found.servicePath &&
|
|
30446
|
+
if (found.servicePath && existsSync42(found.servicePath)) {
|
|
29097
30447
|
lines.push(``, `To remove the service by hand:`, ...manualServiceRemoval(found.servicePath), ``, `(\`${daemonStatusCommand()}\` shows its current state.)`);
|
|
29098
30448
|
}
|
|
29099
30449
|
return { exitCode: 1, lines, planLines, purged };
|
|
@@ -29136,6 +30486,8 @@ var exports_tui = {};
|
|
|
29136
30486
|
__export(exports_tui, {
|
|
29137
30487
|
truncate: () => truncate2,
|
|
29138
30488
|
summarize: () => summarize2,
|
|
30489
|
+
stepOpen: () => stepOpen2,
|
|
30490
|
+
step: () => step2,
|
|
29139
30491
|
selectOne: () => selectOne2,
|
|
29140
30492
|
renderLaunchBanner: () => renderLaunchBanner2,
|
|
29141
30493
|
renderBrandLogo: () => renderBrandLogo2,
|
|
@@ -29172,11 +30524,11 @@ function truecolorEnabled2() {
|
|
|
29172
30524
|
}
|
|
29173
30525
|
function paint2(on) {
|
|
29174
30526
|
const tc = on && truecolorEnabled2();
|
|
29175
|
-
const mk = (h,
|
|
30527
|
+
const mk = (h, bold2 = false) => (s) => {
|
|
29176
30528
|
if (!on)
|
|
29177
30529
|
return s;
|
|
29178
30530
|
const code = tc ? `38;2;${h.rgb[0]};${h.rgb[1]};${h.rgb[2]}` : h.basic;
|
|
29179
|
-
return `${ESC2}[${
|
|
30531
|
+
return `${ESC2}[${bold2 ? "1;" : ""}${code}m${s}${ESC2}[0m`;
|
|
29180
30532
|
};
|
|
29181
30533
|
return {
|
|
29182
30534
|
bold: (s) => on ? `${ESC2}[1m${s}${ESC2}[0m` : s,
|
|
@@ -29282,19 +30634,40 @@ function intro2(message, stdout = process.stdout) {
|
|
|
29282
30634
|
}
|
|
29283
30635
|
function renderLaunchBanner2(version3, stdout = process.stdout) {
|
|
29284
30636
|
const c2 = paint2(colorsEnabled2(stdout));
|
|
29285
|
-
const
|
|
30637
|
+
const row2 = (label, value) => ` ${c2.guide(label.padEnd(9))}${value}`;
|
|
29286
30638
|
const header = stdout.isTTY ? renderBrandLogo2(stdout) : [" failproof ai", ` ${TAGLINE2}`];
|
|
29287
30639
|
return [
|
|
29288
30640
|
"",
|
|
29289
30641
|
...header,
|
|
29290
30642
|
"",
|
|
29291
|
-
|
|
29292
|
-
|
|
29293
|
-
|
|
29294
|
-
|
|
30643
|
+
row2("version", c2.pink(version3)),
|
|
30644
|
+
row2("star", c2.dim("https://github.com/failproofai/failproofai")),
|
|
30645
|
+
row2("docs", c2.dim("https://docs.befailproof.ai/introduction")),
|
|
30646
|
+
row2("discord", c2.dim("https://discord.befailproof.ai/")),
|
|
29295
30647
|
""
|
|
29296
30648
|
];
|
|
29297
30649
|
}
|
|
30650
|
+
function step2(message, summary, stdout = process.stdout) {
|
|
30651
|
+
const c2 = paint2(colorsEnabled2(stdout));
|
|
30652
|
+
const rows = summary === undefined ? [] : Array.isArray(summary) ? summary : [summary];
|
|
30653
|
+
if (!stdout.isTTY) {
|
|
30654
|
+
if (rows.length)
|
|
30655
|
+
stdout.write(`${message}: ${rows.join(" ")}
|
|
30656
|
+
`);
|
|
30657
|
+
return;
|
|
30658
|
+
}
|
|
30659
|
+
const cols = stdout.columns || 80;
|
|
30660
|
+
const lines = [c2.dim(BAR2), truncate2(`${c2.dim(STEP_DONE2)} ${message}`, cols - 1)];
|
|
30661
|
+
for (const r of rows)
|
|
30662
|
+
lines.push(truncate2(`${c2.dim(BAR2)} ${c2.dim(r)}`, cols - 1));
|
|
30663
|
+
writeLines2(stdout, lines);
|
|
30664
|
+
}
|
|
30665
|
+
function stepOpen2(message, stdout = process.stdout) {
|
|
30666
|
+
const c2 = paint2(colorsEnabled2(stdout));
|
|
30667
|
+
if (!stdout.isTTY)
|
|
30668
|
+
return;
|
|
30669
|
+
writeLines2(stdout, [c2.dim(BAR2), `${c2.guide(STEP_ACTIVE2)} ${c2.bold(message)}`]);
|
|
30670
|
+
}
|
|
29298
30671
|
function outro2(message, opts = {}, stdout = process.stdout) {
|
|
29299
30672
|
const c2 = paint2(colorsEnabled2(stdout));
|
|
29300
30673
|
const ok2 = opts.ok !== false;
|
|
@@ -29364,11 +30737,11 @@ function runPrompt2(p) {
|
|
|
29364
30737
|
lines.push(`${c2.dim(BAR2)} ${c2.dim(`↑ ${above} more`)}`);
|
|
29365
30738
|
const budget = Math.max(6, cols - nameCol - 10);
|
|
29366
30739
|
for (let ri = start;ri < end; ri++) {
|
|
29367
|
-
const
|
|
29368
|
-
if (
|
|
29369
|
-
lines.push(`${c2.dim(BAR2)} ${c2.dim(
|
|
30740
|
+
const row2 = rows[ri];
|
|
30741
|
+
if (row2.kind === "header") {
|
|
30742
|
+
lines.push(`${c2.dim(BAR2)} ${c2.dim(row2.text)}`);
|
|
29370
30743
|
} else {
|
|
29371
|
-
lines.push(`${c2.dim(BAR2)} ${p.renderRow(
|
|
30744
|
+
lines.push(`${c2.dim(BAR2)} ${p.renderRow(row2.index, row2.index === cursor2, budget)}`);
|
|
29372
30745
|
}
|
|
29373
30746
|
}
|
|
29374
30747
|
if (below > 0)
|
|
@@ -29387,7 +30760,7 @@ function runPrompt2(p) {
|
|
|
29387
30760
|
`${c2.dim(BAR2)} ${c2.dim(summary)}`
|
|
29388
30761
|
]);
|
|
29389
30762
|
};
|
|
29390
|
-
return new Promise((
|
|
30763
|
+
return new Promise((resolve31) => {
|
|
29391
30764
|
hideCursor2(stdout);
|
|
29392
30765
|
repaint2(stdout, region, build());
|
|
29393
30766
|
readline3.emitKeypressEvents(stdin);
|
|
@@ -29403,7 +30776,7 @@ function runPrompt2(p) {
|
|
|
29403
30776
|
const finish = (result) => {
|
|
29404
30777
|
cleanup();
|
|
29405
30778
|
collapse(result);
|
|
29406
|
-
|
|
30779
|
+
resolve31(result);
|
|
29407
30780
|
};
|
|
29408
30781
|
function onKey(_s, key) {
|
|
29409
30782
|
if (!key)
|
|
@@ -29533,7 +30906,7 @@ function promptText2(opts) {
|
|
|
29533
30906
|
return error ? { ok: false, error } : { ok: true, value };
|
|
29534
30907
|
};
|
|
29535
30908
|
if (!stdin.isTTY) {
|
|
29536
|
-
return new Promise((
|
|
30909
|
+
return new Promise((resolve31) => {
|
|
29537
30910
|
let buf = "";
|
|
29538
30911
|
const onData = (chunk) => {
|
|
29539
30912
|
buf += String(chunk);
|
|
@@ -29546,21 +30919,21 @@ function promptText2(opts) {
|
|
|
29546
30919
|
stdin.removeListener("end", done);
|
|
29547
30920
|
const r = accept(buf.split(`
|
|
29548
30921
|
`)[0] ?? "");
|
|
29549
|
-
|
|
30922
|
+
resolve31(r.ok ? r.value : null);
|
|
29550
30923
|
};
|
|
29551
30924
|
stdin.on("data", onData);
|
|
29552
30925
|
stdin.on("end", done);
|
|
29553
30926
|
});
|
|
29554
30927
|
}
|
|
29555
|
-
return new Promise((
|
|
30928
|
+
return new Promise((resolve31) => {
|
|
29556
30929
|
let value = "";
|
|
29557
30930
|
const draw = (error) => {
|
|
29558
30931
|
const cols = stdout.columns || 80;
|
|
29559
30932
|
const shown = opts.mask ? "•".repeat(value.length) : value;
|
|
29560
|
-
const hint = opts.hint ? ` ${c2.dim(opts.hint)}` : "";
|
|
29561
|
-
const line = truncate2(`${c2.bold(opts.message)} ${shown}${hint}`, cols - 1);
|
|
30933
|
+
const hint = opts.hint && value.length === 0 ? ` ${c2.dim(opts.hint)}` : "";
|
|
30934
|
+
const line = truncate2(`${opts.prefix ?? ""}${c2.bold(opts.message)} ${shown}${hint}`, cols - 1);
|
|
29562
30935
|
const err = error ? `
|
|
29563
|
-
${truncate2(c2.warn(error), cols - 3)}` : "";
|
|
30936
|
+
${opts.prefix ?? " "}${truncate2(c2.warn(error), cols - 3)}` : "";
|
|
29564
30937
|
stdout.write(`\r\x1B[2K${line}${err}`);
|
|
29565
30938
|
if (err)
|
|
29566
30939
|
stdout.write("\x1B[1A");
|
|
@@ -29582,14 +30955,14 @@ function promptText2(opts) {
|
|
|
29582
30955
|
return;
|
|
29583
30956
|
if (key.ctrl && (key.name === "c" || key.name === "d") || key.name === "escape") {
|
|
29584
30957
|
cleanup();
|
|
29585
|
-
|
|
30958
|
+
resolve31(null);
|
|
29586
30959
|
return;
|
|
29587
30960
|
}
|
|
29588
30961
|
if (key.name === "return" || key.name === "enter") {
|
|
29589
30962
|
const r = accept(value);
|
|
29590
30963
|
if (r.ok) {
|
|
29591
30964
|
cleanup();
|
|
29592
|
-
|
|
30965
|
+
resolve31(r.value);
|
|
29593
30966
|
} else {
|
|
29594
30967
|
draw(r.error);
|
|
29595
30968
|
}
|
|
@@ -29657,9 +31030,9 @@ __export(exports_manager, {
|
|
|
29657
31030
|
getSettingsPath: () => getSettingsPath2
|
|
29658
31031
|
});
|
|
29659
31032
|
import { execSync as execSync7 } from "node:child_process";
|
|
29660
|
-
import { existsSync as
|
|
29661
|
-
import { resolve as
|
|
29662
|
-
import { platform as platform5, arch as arch4, release as release3, hostname as
|
|
31033
|
+
import { existsSync as existsSync43 } from "node:fs";
|
|
31034
|
+
import { resolve as resolve31, basename as basename8 } from "node:path";
|
|
31035
|
+
import { platform as platform5, arch as arch4, release as release3, hostname as hostname6 } from "node:os";
|
|
29663
31036
|
function getSettingsPath2(scope, cwd) {
|
|
29664
31037
|
return claudeCode.getSettingsPath(scope, cwd);
|
|
29665
31038
|
}
|
|
@@ -29766,9 +31139,9 @@ async function installHooksImpl2(policyNames, scope = "user", cwd, includeBeta =
|
|
|
29766
31139
|
delete configToWrite.customPoliciesPath;
|
|
29767
31140
|
delete configToWrite.customPoliciesPaths;
|
|
29768
31141
|
} else if (customPoliciesPath && (typeof customPoliciesPath === "string" || customPoliciesPath.length > 0)) {
|
|
29769
|
-
const incoming = (typeof customPoliciesPath === "string" ? [customPoliciesPath] : customPoliciesPath).map((path3) =>
|
|
29770
|
-
const carried = (previousConfig.customPoliciesPaths ?? (previousConfig.customPoliciesPath ? [previousConfig.customPoliciesPath] : [])).map((path3) =>
|
|
29771
|
-
if (
|
|
31142
|
+
const incoming = (typeof customPoliciesPath === "string" ? [customPoliciesPath] : customPoliciesPath).map((path3) => resolve31(path3));
|
|
31143
|
+
const carried = (previousConfig.customPoliciesPaths ?? (previousConfig.customPoliciesPath ? [previousConfig.customPoliciesPath] : [])).map((path3) => resolve31(path3)).filter((path3) => {
|
|
31144
|
+
if (existsSync43(path3))
|
|
29772
31145
|
return true;
|
|
29773
31146
|
console.log(`Dropping custom policies path (file no longer exists): ${path3}`);
|
|
29774
31147
|
return false;
|
|
@@ -29854,7 +31227,7 @@ Enabled ${selectedPolicies.length} policy(ies): ${selectedPolicies.join(", ")}
|
|
|
29854
31227
|
platform: platform5(),
|
|
29855
31228
|
arch: arch4(),
|
|
29856
31229
|
os_release: release3(),
|
|
29857
|
-
hostname_hash: hashToId2(
|
|
31230
|
+
hostname_hash: hashToId2(hostname6()),
|
|
29858
31231
|
has_custom_hooks_path: !!(configToWrite.customPoliciesPaths?.length || configToWrite.customPoliciesPath),
|
|
29859
31232
|
has_policy_params: !!(configToWrite.policyParams && Object.keys(configToWrite.policyParams).length > 0),
|
|
29860
31233
|
param_policy_names: configToWrite.policyParams ? Object.keys(configToWrite.policyParams) : [],
|
|
@@ -29945,7 +31318,7 @@ async function removeHooks2(policyNames, scope = "user", cwd, opts) {
|
|
|
29945
31318
|
platform: platform5(),
|
|
29946
31319
|
arch: arch4(),
|
|
29947
31320
|
os_release: release3(),
|
|
29948
|
-
hostname_hash: hashToId2(
|
|
31321
|
+
hostname_hash: hashToId2(hostname6())
|
|
29949
31322
|
});
|
|
29950
31323
|
} catch {}
|
|
29951
31324
|
console.log(`Disabled ${policyNames.length - notEnabled.length} policy(ies).`);
|
|
@@ -29960,7 +31333,7 @@ async function removeHooks2(policyNames, scope = "user", cwd, opts) {
|
|
|
29960
31333
|
const scopesToRemove = scope === "all" ? [...integration.scopes] : integration.scopes.includes(scope) ? [scope] : [];
|
|
29961
31334
|
for (const s of scopesToRemove) {
|
|
29962
31335
|
const settingsPaths = settingsPathsFor(integration, s, cwd);
|
|
29963
|
-
const existing = settingsPaths.filter((p) =>
|
|
31336
|
+
const existing = settingsPaths.filter((p) => existsSync43(p));
|
|
29964
31337
|
if (existing.length === 0) {
|
|
29965
31338
|
if (scope !== "all" && selectedClis.length === 1) {
|
|
29966
31339
|
console.log("No settings file found. Nothing to remove.");
|
|
@@ -30010,7 +31383,7 @@ async function removeHooks2(policyNames, scope = "user", cwd, opts) {
|
|
|
30010
31383
|
platform: platform5(),
|
|
30011
31384
|
arch: arch4(),
|
|
30012
31385
|
os_release: release3(),
|
|
30013
|
-
hostname_hash: hashToId2(
|
|
31386
|
+
hostname_hash: hashToId2(hostname6())
|
|
30014
31387
|
});
|
|
30015
31388
|
} catch {}
|
|
30016
31389
|
if (scope === "all") {
|
|
@@ -30109,16 +31482,16 @@ Failproof AI Hook Policies
|
|
|
30109
31482
|
console.log(` ${"─".repeat(scopeHeaderWidth)}${"─".repeat(nameColWidth)}${"─".repeat(38)}`);
|
|
30110
31483
|
const printMultiScopeRow = (policy) => {
|
|
30111
31484
|
const enabled = enabledSet.has(policy.name);
|
|
30112
|
-
let
|
|
31485
|
+
let row2 = " ";
|
|
30113
31486
|
for (const _scope of installedScopes) {
|
|
30114
31487
|
if (enabled) {
|
|
30115
|
-
|
|
31488
|
+
row2 += `\x1B[32m✓ ON\x1B[0m` + " ".repeat(COL - 4);
|
|
30116
31489
|
} else {
|
|
30117
|
-
|
|
31490
|
+
row2 += " OFF" + " ".repeat(COL - 5);
|
|
30118
31491
|
}
|
|
30119
31492
|
}
|
|
30120
|
-
|
|
30121
|
-
console.log(
|
|
31493
|
+
row2 += policy.name.padEnd(nameColWidth) + policy.description;
|
|
31494
|
+
console.log(row2);
|
|
30122
31495
|
printParamsSummary(policy.name, ` ${" ".repeat(scopeHeaderWidth)}`);
|
|
30123
31496
|
};
|
|
30124
31497
|
for (const policy of regularPolicies)
|
|
@@ -30159,9 +31532,9 @@ Failproof AI Hook Policies
|
|
|
30159
31532
|
console.log(`
|
|
30160
31533
|
── Custom Policies ───────────────────────`);
|
|
30161
31534
|
for (const path3 of explicitPaths) {
|
|
30162
|
-
const absPath =
|
|
31535
|
+
const absPath = resolve31(findProjectConfigDir(cwd ?? process.cwd()), path3);
|
|
30163
31536
|
console.log(` ${absPath}`);
|
|
30164
|
-
if (!
|
|
31537
|
+
if (!existsSync43(absPath)) {
|
|
30165
31538
|
console.log(` \x1B[31m✗ File not found: ${absPath}\x1B[0m`);
|
|
30166
31539
|
continue;
|
|
30167
31540
|
}
|
|
@@ -30180,7 +31553,7 @@ Failproof AI Hook Policies
|
|
|
30180
31553
|
console.log();
|
|
30181
31554
|
}
|
|
30182
31555
|
const base = findProjectConfigDir(cwd ?? process.cwd());
|
|
30183
|
-
const projectDir =
|
|
31556
|
+
const projectDir = resolve31(base, ".failproofai", "policies");
|
|
30184
31557
|
const userDir = customPoliciesDir();
|
|
30185
31558
|
const sameDir = userDir === projectDir;
|
|
30186
31559
|
const conventionDirs = [
|
|
@@ -30393,32 +31766,32 @@ async function promptCliTargetSelection(detected, action = "install") {
|
|
|
30393
31766
|
cursorHidden = false;
|
|
30394
31767
|
}
|
|
30395
31768
|
}
|
|
30396
|
-
const { dim, bold, guide: teal, pink, pinkBold } = paint(!process.env.NO_COLOR);
|
|
31769
|
+
const { dim: dim2, bold: bold2, guide: teal, pink: pink2, pinkBold } = paint(!process.env.NO_COLOR);
|
|
30397
31770
|
const heading = action === "uninstall" ? "Remove failproofai hooks" : "Install failproofai hooks";
|
|
30398
31771
|
function render() {
|
|
30399
31772
|
const cols = process.stdout.columns || 100;
|
|
30400
31773
|
hideCursor3();
|
|
30401
|
-
const g =
|
|
30402
|
-
const lines = [g, `${teal(STEP_ACTIVE)} ${
|
|
30403
|
-
for (const
|
|
30404
|
-
if (
|
|
31774
|
+
const g = dim2(BAR);
|
|
31775
|
+
const lines = [g, `${teal(STEP_ACTIVE)} ${bold2(heading)}`];
|
|
31776
|
+
for (const row2 of buildDisplayRows()) {
|
|
31777
|
+
if (row2.kind === "blank") {
|
|
30405
31778
|
lines.push(g);
|
|
30406
31779
|
continue;
|
|
30407
31780
|
}
|
|
30408
|
-
if (
|
|
30409
|
-
const hint =
|
|
30410
|
-
lines.push(`${g} ${
|
|
31781
|
+
if (row2.kind === "header") {
|
|
31782
|
+
const hint = row2.hint ? ` ${dim2("· " + row2.hint)}` : "";
|
|
31783
|
+
lines.push(`${g} ${dim2(row2.title)}${hint}`);
|
|
30411
31784
|
continue;
|
|
30412
31785
|
}
|
|
30413
|
-
const opt =
|
|
30414
|
-
const isActive =
|
|
30415
|
-
const caret = isActive ?
|
|
30416
|
-
const marker = opt.isAll ? teal("★") : opt.detected ?
|
|
30417
|
-
const label = isActive ? pinkBold(opt.label) : opt.detected ? opt.label :
|
|
31786
|
+
const opt = row2.option;
|
|
31787
|
+
const isActive = row2.itemIndex === cursor2;
|
|
31788
|
+
const caret = isActive ? pink2("❯") : " ";
|
|
31789
|
+
const marker = opt.isAll ? teal("★") : opt.detected ? pink2("●") : dim2("○");
|
|
31790
|
+
const label = isActive ? pinkBold(opt.label) : opt.detected ? opt.label : dim2(opt.label);
|
|
30418
31791
|
lines.push(`${g} ${caret} ${marker} ${label}`);
|
|
30419
31792
|
}
|
|
30420
31793
|
lines.push(g);
|
|
30421
|
-
lines.push(`${g} ${
|
|
31794
|
+
lines.push(`${g} ${dim2("↑/↓ move · ↵ select · esc cancel")}`);
|
|
30422
31795
|
if (lastLineCount > 0) {
|
|
30423
31796
|
process.stdout.write(`\x1B[${lastLineCount}A\x1B[J`);
|
|
30424
31797
|
}
|
|
@@ -30428,7 +31801,7 @@ async function promptCliTargetSelection(detected, action = "install") {
|
|
|
30428
31801
|
lastLineCount = lines.length;
|
|
30429
31802
|
}
|
|
30430
31803
|
const itemCount = options.length;
|
|
30431
|
-
return new Promise((
|
|
31804
|
+
return new Promise((resolve32) => {
|
|
30432
31805
|
render();
|
|
30433
31806
|
readline4.emitKeypressEvents(process.stdin);
|
|
30434
31807
|
const wasRaw = process.stdin.isRaw;
|
|
@@ -30461,7 +31834,7 @@ async function promptCliTargetSelection(detected, action = "install") {
|
|
|
30461
31834
|
cleanup();
|
|
30462
31835
|
process.stdout.write(`
|
|
30463
31836
|
`);
|
|
30464
|
-
|
|
31837
|
+
resolve32(options[cursor2].value);
|
|
30465
31838
|
}
|
|
30466
31839
|
}
|
|
30467
31840
|
process.stdin.on("keypress", onKey);
|
|
@@ -30487,7 +31860,7 @@ async function promptPolicySelection2(preSelected, options = {}) {
|
|
|
30487
31860
|
const WINDOW_SIZE = 10;
|
|
30488
31861
|
const useColor = !process.env.NO_COLOR;
|
|
30489
31862
|
const c2 = paint(useColor);
|
|
30490
|
-
const { dim, bold } = c2;
|
|
31863
|
+
const { dim: dim2, bold: bold2 } = c2;
|
|
30491
31864
|
const stepMark = c2.guide;
|
|
30492
31865
|
const activeName = c2.pinkBold;
|
|
30493
31866
|
const selectedMark = c2.pink;
|
|
@@ -30556,24 +31929,24 @@ async function promptPolicySelection2(preSelected, options = {}) {
|
|
|
30556
31929
|
if (shown > 0 && cursor2 >= shown)
|
|
30557
31930
|
cursor2 = shown - 1;
|
|
30558
31931
|
const selectedCount = items.filter((i) => i.selected).length;
|
|
30559
|
-
const g =
|
|
31932
|
+
const g = dim2(BAR);
|
|
30560
31933
|
const lines = [];
|
|
30561
31934
|
lines.push(g);
|
|
30562
|
-
lines.push(`${stepMark(STEP_ACTIVE)} ${
|
|
31935
|
+
lines.push(`${stepMark(STEP_ACTIVE)} ${bold2("Choose the policies to enable")} ${dim2("·")} ` + `${stepMark(String(selectedCount))} ${dim2("selected")}`);
|
|
30563
31936
|
const blockCursor = useColor ? "\x1B[7m \x1B[0m" : "_";
|
|
30564
|
-
const countLabel = search ?
|
|
30565
|
-
lines.push(`${g} ${
|
|
31937
|
+
const countLabel = search ? dim2(`${shown}/${total} shown`) : dim2(`${total} policies`);
|
|
31938
|
+
lines.push(`${g} ${dim2("filter ›")} ${search}${blockCursor} ${countLabel}`);
|
|
30566
31939
|
lines.push(g);
|
|
30567
31940
|
if (shown === 0) {
|
|
30568
|
-
lines.push(`${g} ${
|
|
31941
|
+
lines.push(`${g} ${dim2(`no policies match “${search}”`)}`);
|
|
30569
31942
|
for (let i = 0;i < WINDOW_SIZE + 1; i++)
|
|
30570
31943
|
lines.push(g);
|
|
30571
31944
|
} else {
|
|
30572
31945
|
const displayRows3 = buildDisplayRows(filtered);
|
|
30573
31946
|
let cursorDisplayRow = 0;
|
|
30574
31947
|
for (let i = 0;i < displayRows3.length; i++) {
|
|
30575
|
-
const
|
|
30576
|
-
if (
|
|
31948
|
+
const row2 = displayRows3[i];
|
|
31949
|
+
if (row2.kind === "item" && row2.filteredIndex === cursor2) {
|
|
30577
31950
|
cursorDisplayRow = i;
|
|
30578
31951
|
break;
|
|
30579
31952
|
}
|
|
@@ -30583,30 +31956,30 @@ async function promptPolicySelection2(preSelected, options = {}) {
|
|
|
30583
31956
|
windowStart = Math.min(windowStart, Math.max(0, displayRows3.length - WINDOW_SIZE));
|
|
30584
31957
|
const windowEnd = Math.min(displayRows3.length, windowStart + WINDOW_SIZE);
|
|
30585
31958
|
const aboveItems = displayRows3.slice(0, windowStart).filter((r) => r.kind === "item").length;
|
|
30586
|
-
lines.push(aboveItems > 0 ? `${g} ${
|
|
31959
|
+
lines.push(aboveItems > 0 ? `${g} ${dim2(`↑ ${aboveItems} more`)}` : g);
|
|
30587
31960
|
for (let i = windowStart;i < windowEnd; i++) {
|
|
30588
|
-
const
|
|
30589
|
-
if (
|
|
30590
|
-
lines.push(`${g} ${
|
|
31961
|
+
const row2 = displayRows3[i];
|
|
31962
|
+
if (row2.kind === "header") {
|
|
31963
|
+
lines.push(`${g} ${dim2(row2.category.toUpperCase())} ${dim2(`${row2.enabledCount}/${row2.totalCount}`)}`);
|
|
30591
31964
|
} else {
|
|
30592
|
-
const item =
|
|
30593
|
-
const active =
|
|
30594
|
-
const box = item.selected ? selectedMark(CHECK_ON) :
|
|
31965
|
+
const item = row2.item;
|
|
31966
|
+
const active = row2.filteredIndex === cursor2;
|
|
31967
|
+
const box = item.selected ? selectedMark(CHECK_ON) : dim2(CHECK_OFF);
|
|
30595
31968
|
const rawName = item.name.padEnd(NAME_COL);
|
|
30596
|
-
const name = active ? activeName(rawName) : item.selected ? rawName :
|
|
31969
|
+
const name = active ? activeName(rawName) : item.selected ? rawName : dim2(rawName);
|
|
30597
31970
|
const beta = item.beta ? ` ${betaTag("beta")}` : "";
|
|
30598
31971
|
const descWidth = Math.max(8, cols - NAME_COL - 8 - (item.beta ? 5 : 0));
|
|
30599
|
-
const desc =
|
|
31972
|
+
const desc = dim2(truncate(item.description, descWidth));
|
|
30600
31973
|
lines.push(`${g} ${box} ${name}${beta} ${desc}`);
|
|
30601
31974
|
}
|
|
30602
31975
|
}
|
|
30603
31976
|
for (let i = windowEnd - windowStart;i < WINDOW_SIZE; i++)
|
|
30604
31977
|
lines.push(g);
|
|
30605
31978
|
const belowItems = displayRows3.slice(windowEnd).filter((r) => r.kind === "item").length;
|
|
30606
|
-
lines.push(belowItems > 0 ? `${g} ${
|
|
31979
|
+
lines.push(belowItems > 0 ? `${g} ${dim2(`↓ ${belowItems} more`)}` : g);
|
|
30607
31980
|
}
|
|
30608
31981
|
lines.push(g);
|
|
30609
|
-
lines.push(`${g} ${
|
|
31982
|
+
lines.push(`${g} ${dim2("↑/↓ move · space select · ctrl+a all · ↵ save · type to filter · esc clear")}`);
|
|
30610
31983
|
if (lastLineCount > 0)
|
|
30611
31984
|
process.stdout.write(`\x1B[${lastLineCount}A\x1B[J`);
|
|
30612
31985
|
process.stdout.write(lines.map((l) => truncate(l, cols)).join(`
|
|
@@ -30614,7 +31987,7 @@ async function promptPolicySelection2(preSelected, options = {}) {
|
|
|
30614
31987
|
`);
|
|
30615
31988
|
lastLineCount = lines.length;
|
|
30616
31989
|
}
|
|
30617
|
-
return new Promise((
|
|
31990
|
+
return new Promise((resolve32) => {
|
|
30618
31991
|
render();
|
|
30619
31992
|
process.stdin.setRawMode(true);
|
|
30620
31993
|
process.stdin.resume();
|
|
@@ -30647,11 +32020,11 @@ async function promptPolicySelection2(preSelected, options = {}) {
|
|
|
30647
32020
|
const selected = items.filter((i) => i.selected).map((i) => i.name);
|
|
30648
32021
|
if (lastLineCount > 0)
|
|
30649
32022
|
process.stdout.write(`\x1B[${lastLineCount}A\x1B[J`);
|
|
30650
|
-
process.stdout.write(`${
|
|
30651
|
-
${
|
|
30652
|
-
${
|
|
32023
|
+
process.stdout.write(`${dim2(BAR)}
|
|
32024
|
+
${dim2(STEP_DONE)} Policies
|
|
32025
|
+
${dim2(BAR)} ${dim2(`${selected.length} selected`)}
|
|
30653
32026
|
`);
|
|
30654
|
-
|
|
32027
|
+
resolve32(selected);
|
|
30655
32028
|
} else if (key.name === "escape") {
|
|
30656
32029
|
search = "";
|
|
30657
32030
|
cursor2 = 0;
|
|
@@ -30874,6 +32247,13 @@ async function runScheduledAudit2() {
|
|
|
30874
32247
|
}
|
|
30875
32248
|
process.stdout.write(`failproofai: audit complete — ${num2(result.eventsScanned)} tool calls across ` + `${num2(result.transcripts.scanned)} sessions, ${num2(result.totals.hits)} hits
|
|
30876
32249
|
`);
|
|
32250
|
+
const outcome = await reportHarm(result);
|
|
32251
|
+
const line = describeOutcome2(outcome);
|
|
32252
|
+
if (line) {
|
|
32253
|
+
const stream = outcome.kind === "sent" ? process.stdout : process.stderr;
|
|
32254
|
+
stream.write(`${line}
|
|
32255
|
+
`);
|
|
32256
|
+
}
|
|
30877
32257
|
return 0;
|
|
30878
32258
|
} finally {
|
|
30879
32259
|
attempt.lock.release();
|
|
@@ -30938,15 +32318,71 @@ async function runAuditCli2(args) {
|
|
|
30938
32318
|
die2(`\`audit --scheduled\` takes no other arguments (got: ${extra}).`);
|
|
30939
32319
|
process.exit(await runScheduledAudit2());
|
|
30940
32320
|
}
|
|
32321
|
+
if (args.includes("--status")) {
|
|
32322
|
+
const extra = args.find((a) => a !== "--status");
|
|
32323
|
+
if (extra)
|
|
32324
|
+
die2(`\`audit --status\` takes no other arguments (got: ${extra}).`);
|
|
32325
|
+
const { runScheduleStatus: runScheduleStatus2 } = await Promise.resolve().then(() => (init_schedule_cli(), exports_schedule_cli));
|
|
32326
|
+
runScheduleStatus2();
|
|
32327
|
+
process.exit(0);
|
|
32328
|
+
}
|
|
32329
|
+
if (args.includes("--no-schedule")) {
|
|
32330
|
+
const extra = args.find((a) => a !== "--no-schedule");
|
|
32331
|
+
if (extra)
|
|
32332
|
+
die2(`\`audit --no-schedule\` takes no other arguments (got: ${extra}).`);
|
|
32333
|
+
const { runScheduleOff: runScheduleOff2 } = await Promise.resolve().then(() => (init_schedule_cli(), exports_schedule_cli));
|
|
32334
|
+
runScheduleOff2();
|
|
32335
|
+
process.exit(0);
|
|
32336
|
+
}
|
|
32337
|
+
const scheduleAt = args.indexOf("--schedule");
|
|
32338
|
+
if (scheduleAt !== -1) {
|
|
32339
|
+
let days;
|
|
32340
|
+
let email;
|
|
32341
|
+
for (let i = 0;i < args.length; i += 1) {
|
|
32342
|
+
const a = args[i];
|
|
32343
|
+
if (a === "--schedule") {
|
|
32344
|
+
const next = args[i + 1];
|
|
32345
|
+
if (next !== undefined && !next.startsWith("-")) {
|
|
32346
|
+
days = next;
|
|
32347
|
+
i += 1;
|
|
32348
|
+
}
|
|
32349
|
+
continue;
|
|
32350
|
+
}
|
|
32351
|
+
if (a === "--email" || a.startsWith("--email=")) {
|
|
32352
|
+
if (a.startsWith("--email=")) {
|
|
32353
|
+
email = a.slice("--email=".length);
|
|
32354
|
+
} else {
|
|
32355
|
+
email = args[i + 1];
|
|
32356
|
+
i += 1;
|
|
32357
|
+
}
|
|
32358
|
+
if (email === undefined || email.length === 0 || email.startsWith("-")) {
|
|
32359
|
+
die2("`--email` needs an address, e.g. `--email you@yourdomain.com`.");
|
|
32360
|
+
}
|
|
32361
|
+
continue;
|
|
32362
|
+
}
|
|
32363
|
+
die2(`\`audit --schedule\` does not take ${a}.`);
|
|
32364
|
+
}
|
|
32365
|
+
const { runScheduleOn: runScheduleOn2, ScheduleCliError: ScheduleCliError2 } = await Promise.resolve().then(() => (init_schedule_cli(), exports_schedule_cli));
|
|
32366
|
+
const { LoginError: LoginError2 } = await Promise.resolve().then(() => (init_cli_login(), exports_cli_login));
|
|
32367
|
+
try {
|
|
32368
|
+
await runScheduleOn2(days, email);
|
|
32369
|
+
} catch (err) {
|
|
32370
|
+
if (err instanceof ScheduleCliError2 || err instanceof LoginError2)
|
|
32371
|
+
die2(err.message);
|
|
32372
|
+
throw err;
|
|
32373
|
+
}
|
|
32374
|
+
process.exit(0);
|
|
32375
|
+
}
|
|
30941
32376
|
const stray = args.find((a) => a !== "--help" && a !== "-h");
|
|
30942
32377
|
if (stray) {
|
|
30943
|
-
die2(`\`audit\`
|
|
30944
|
-
|
|
32378
|
+
die2(`\`audit\` does not take ${stray}.
|
|
32379
|
+
Run \`failproofai audit\` to scan your history and open the dashboard,
|
|
32380
|
+
or \`failproofai audit --help\` for the scheduling commands.`);
|
|
30945
32381
|
}
|
|
30946
32382
|
const attempt = acquireAuditLock("cli");
|
|
30947
32383
|
if (!attempt.ok) {
|
|
30948
32384
|
process.stderr.write(`Error: ${heldByLine2(attempt.heldBy)}.
|
|
30949
|
-
|
|
32385
|
+
Two audits write the same cache files, so this one won't start. Try again shortly.
|
|
30950
32386
|
`);
|
|
30951
32387
|
process.exit(EXIT_AUDIT_ALREADY_RUNNING2);
|
|
30952
32388
|
}
|
|
@@ -30970,7 +32406,7 @@ async function runAuditCli2(args) {
|
|
|
30970
32406
|
if (result.eventsScanned === 0) {
|
|
30971
32407
|
process.stdout.write(`
|
|
30972
32408
|
${c2(DIM2, "no agent sessions found yet.")}
|
|
30973
|
-
|
|
32409
|
+
install hooks with ${c2(CYAN2, "failproofai policies --install")} ${c2(DIM2, "and come back after using your agent.")}
|
|
30974
32410
|
|
|
30975
32411
|
`);
|
|
30976
32412
|
process.exit(0);
|
|
@@ -30985,8 +32421,8 @@ async function runAuditCli2(args) {
|
|
|
30985
32421
|
const url = `http://localhost:${DASHBOARD_PORT2}/audit`;
|
|
30986
32422
|
process.stdout.write(`
|
|
30987
32423
|
${c2(DIM2, "starting the dashboard…")}
|
|
30988
|
-
|
|
30989
|
-
|
|
32424
|
+
${c2(PINK2, "✦")} ${c2(BOLD2, "here's your audit")} ${c2(DIM2, "→")} ${c2(CYAN2, url)}
|
|
32425
|
+
${c2(DIM2, "(opening in your browser — press Ctrl+C to stop the server)")}
|
|
30990
32426
|
|
|
30991
32427
|
`);
|
|
30992
32428
|
openWhenReady(DASHBOARD_PORT2, "/audit");
|
|
@@ -31002,6 +32438,7 @@ var init_cli2 = __esm(() => {
|
|
|
31002
32438
|
init_telemetry_id2();
|
|
31003
32439
|
init_telemetry_sanitize();
|
|
31004
32440
|
init_open_browser();
|
|
32441
|
+
init_report_harm();
|
|
31005
32442
|
init_tui();
|
|
31006
32443
|
AUDIT_STAGES2 = [
|
|
31007
32444
|
{ label: "discovering transcripts", detail: "walking ~/.claude, ~/.codex, ~/.cursor, …" },
|
|
@@ -31023,14 +32460,34 @@ USAGE
|
|
|
31023
32460
|
server. This is what a scheduled audit runs; exit
|
|
31024
32461
|
75 means another audit already had the lock.
|
|
31025
32462
|
|
|
32463
|
+
SCHEDULING
|
|
32464
|
+
failproofai audit --schedule [days] [--email you@yourdomain.com]
|
|
32465
|
+
Scan on a timer in the background (default 7 days,
|
|
32466
|
+
1-90), and email you when a scan finds something
|
|
32467
|
+
harmful. Signs you in the first time — the report
|
|
32468
|
+
has to go somewhere. Pass --email to answer that
|
|
32469
|
+
up front and go straight to entering the code.
|
|
32470
|
+
failproofai audit --no-schedule
|
|
32471
|
+
Stop scanning on a timer. Leaves you signed in.
|
|
32472
|
+
failproofai audit --status
|
|
32473
|
+
What this machine is doing: whether scheduling is
|
|
32474
|
+
on, where reports go, the daemon's state, and when
|
|
32475
|
+
the next scan is due.
|
|
32476
|
+
|
|
32477
|
+
These write the same ~/.failproofai/config.json the dashboard's settings page
|
|
32478
|
+
writes, through the same function — so the two are always in step.
|
|
32479
|
+
|
|
31026
32480
|
WHAT IT DOES
|
|
31027
32481
|
1. Scans past sessions from every installed agent CLI (Claude, Codex, Cursor,
|
|
31028
32482
|
Copilot, OpenCode, Pi) — entirely on your machine.
|
|
31029
32483
|
2. Starts the local dashboard and opens
|
|
31030
32484
|
http://localhost:${DASHBOARD_PORT2}/audit with your results.
|
|
31031
32485
|
|
|
31032
|
-
|
|
31033
|
-
|
|
32486
|
+
A bare "failproofai audit" needs no account, and nothing from your sessions
|
|
32487
|
+
leaves this machine — anonymous usage counts still apply unless you set
|
|
32488
|
+
FAILPROOFAI_TELEMETRY_DISABLED=1. Scheduling is the exception: it emails you
|
|
32489
|
+
what it finds, so it needs an address.
|
|
32490
|
+
Press Ctrl+C to stop the dashboard server when you're done.
|
|
31034
32491
|
`.trimStart();
|
|
31035
32492
|
RESET2 = ANSI_RESET;
|
|
31036
32493
|
DIM2 = ANSI_DIM;
|
|
@@ -31051,10 +32508,10 @@ __export(exports_cloud_enrollment_cli, {
|
|
|
31051
32508
|
describeMachine: () => describeMachine,
|
|
31052
32509
|
connectionStatusLines: () => connectionStatusLines
|
|
31053
32510
|
});
|
|
31054
|
-
function describeMachine(machineId,
|
|
31055
|
-
if (!
|
|
32511
|
+
function describeMachine(machineId, machineLabel2, full = false) {
|
|
32512
|
+
if (!machineLabel2 || machineLabel2 === machineId)
|
|
31056
32513
|
return machineId;
|
|
31057
|
-
return full ? `${
|
|
32514
|
+
return full ? `${machineLabel2} (${machineId})` : `${machineLabel2} (${machineId.slice(0, 8)})`;
|
|
31058
32515
|
}
|
|
31059
32516
|
function daemonWarning(status) {
|
|
31060
32517
|
if (status === "running")
|
|
@@ -31113,13 +32570,13 @@ async function runConnectCommand(opts) {
|
|
|
31113
32570
|
if (!validated.ok)
|
|
31114
32571
|
return { exitCode: 1, lines: [validated.reason] };
|
|
31115
32572
|
const machineId = resolveMachineId(opts.machineId);
|
|
31116
|
-
const
|
|
31117
|
-
const shownAs = describeMachine(machineId,
|
|
32573
|
+
const machineLabel2 = resolveMachineLabel(opts.machineLabel ?? opts.defaultMachineId);
|
|
32574
|
+
const shownAs = describeMachine(machineId, machineLabel2);
|
|
31118
32575
|
const outcome = await connectToCloud({
|
|
31119
32576
|
url: validated.url,
|
|
31120
32577
|
token: opts.token,
|
|
31121
32578
|
machineId,
|
|
31122
|
-
machineLabel,
|
|
32579
|
+
machineLabel: machineLabel2,
|
|
31123
32580
|
sessions: opts.sessions,
|
|
31124
32581
|
environment: opts.environment,
|
|
31125
32582
|
verifyPolicy: opts.verify,
|
|
@@ -31365,8 +32822,8 @@ __export(exports_launch2, {
|
|
|
31365
32822
|
launch: () => launch2
|
|
31366
32823
|
});
|
|
31367
32824
|
import { spawn as spawn3 } from "child_process";
|
|
31368
|
-
import { realpathSync as realpathSync5, existsSync as
|
|
31369
|
-
import { resolve as
|
|
32825
|
+
import { realpathSync as realpathSync5, existsSync as existsSync44 } from "node:fs";
|
|
32826
|
+
import { resolve as resolve32, dirname as dirname23 } from "node:path";
|
|
31370
32827
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
31371
32828
|
import { createInterface as createInterface2 } from "node:readline";
|
|
31372
32829
|
function launch2(mode) {
|
|
@@ -31390,9 +32847,9 @@ function launch2(mode) {
|
|
|
31390
32847
|
process.env.PORT = port;
|
|
31391
32848
|
process.env.HOSTNAME = bindHost;
|
|
31392
32849
|
cmd = "node";
|
|
31393
|
-
const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT ??
|
|
31394
|
-
const serverJsPath =
|
|
31395
|
-
if (!
|
|
32850
|
+
const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT ?? resolve32(dirname23(realpathSync5(fileURLToPath3(import.meta.url))), "..");
|
|
32851
|
+
const serverJsPath = resolve32(packageRoot, ".next/standalone/server.js");
|
|
32852
|
+
if (!existsSync44(serverJsPath)) {
|
|
31396
32853
|
let shadowMessage = null;
|
|
31397
32854
|
try {
|
|
31398
32855
|
const diag = diagnoseShadow({ selfPackageRoot: packageRoot, selfVersion: version2 });
|
|
@@ -31489,17 +32946,17 @@ var init_cli_error2 = __esm(() => {
|
|
|
31489
32946
|
|
|
31490
32947
|
// bin/failproofai.mjs
|
|
31491
32948
|
import { realpathSync as realpathSync6 } from "fs";
|
|
31492
|
-
import { dirname as dirname24, resolve as
|
|
32949
|
+
import { dirname as dirname24, resolve as resolve33 } from "path";
|
|
31493
32950
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
31494
32951
|
// package.json
|
|
31495
|
-
var version = "1.0.0";
|
|
32952
|
+
var version = "1.0.1-beta.0";
|
|
31496
32953
|
|
|
31497
32954
|
// bin/failproofai.mjs
|
|
31498
32955
|
if (!process.env.FAILPROOFAI_PACKAGE_ROOT) {
|
|
31499
|
-
process.env.FAILPROOFAI_PACKAGE_ROOT =
|
|
32956
|
+
process.env.FAILPROOFAI_PACKAGE_ROOT = resolve33(dirname24(realpathSync6(fileURLToPath4(import.meta.url))), "..");
|
|
31500
32957
|
}
|
|
31501
32958
|
if (!process.env.FAILPROOFAI_DIST_PATH) {
|
|
31502
|
-
process.env.FAILPROOFAI_DIST_PATH =
|
|
32959
|
+
process.env.FAILPROOFAI_DIST_PATH = resolve33(dirname24(realpathSync6(fileURLToPath4(import.meta.url))), "..", "dist");
|
|
31503
32960
|
}
|
|
31504
32961
|
var args = process.argv.slice(2);
|
|
31505
32962
|
if (args[0] === "p")
|
|
@@ -31682,6 +33139,12 @@ COMMANDS
|
|
|
31682
33139
|
|
|
31683
33140
|
audit Audit your agent's behavior, then open the
|
|
31684
33141
|
dashboard at http://localhost:8020/audit
|
|
33142
|
+
audit --schedule [days] Audit on a timer (default 7 days) and email you
|
|
33143
|
+
what it finds. Signs you in the first time;
|
|
33144
|
+
--email <address> skips that question
|
|
33145
|
+
audit --no-schedule Stop auditing on a timer
|
|
33146
|
+
audit --status Whether scheduling is on, where reports go, and
|
|
33147
|
+
when the next scan is due
|
|
31685
33148
|
audit --help, -h Show this help for the audit command
|
|
31686
33149
|
|
|
31687
33150
|
backfill Re-send history the collector already read past
|
|
@@ -32069,8 +33532,8 @@ Run \`failproofai migrate --help\` for usage.`);
|
|
|
32069
33532
|
return;
|
|
32070
33533
|
}
|
|
32071
33534
|
const run = runMigrations3(from);
|
|
32072
|
-
for (const
|
|
32073
|
-
console.log(`${
|
|
33535
|
+
for (const step3 of run.steps) {
|
|
33536
|
+
console.log(`${step3.ok ? "migrated" : "FAILED "} layout ${step3.from} \u2192 ${step3.to}`);
|
|
32074
33537
|
}
|
|
32075
33538
|
if (run.backedUp.length > 0) {
|
|
32076
33539
|
console.log(`Saved first: ${run.backedUp.join(", ")}`);
|
|
@@ -32140,8 +33603,8 @@ Run \`failproofai update --help\` for usage.`);
|
|
|
32140
33603
|
const run = runMigrations3(state.found);
|
|
32141
33604
|
migrationsRan = run.steps.length;
|
|
32142
33605
|
migrationFailed = Boolean(run.failed);
|
|
32143
|
-
for (const
|
|
32144
|
-
console.log(`${
|
|
33606
|
+
for (const step3 of run.steps) {
|
|
33607
|
+
console.log(`${step3.ok ? "migrated" : "FAILED "} layout ${step3.from} \u2192 ${step3.to}`);
|
|
32145
33608
|
}
|
|
32146
33609
|
if (run.backedUp.length > 0)
|
|
32147
33610
|
console.log(`Saved first: ${run.backedUp.join(", ")}`);
|
|
@@ -32678,14 +34141,14 @@ PAUSING ENFORCEMENT (one session, always time-boxed)
|
|
|
32678
34141
|
const { runDisconnectCommand: runDisconnectCommand2 } = await Promise.resolve().then(() => (init_cloud_enrollment_cli(), exports_cloud_enrollment_cli));
|
|
32679
34142
|
result2 = runDisconnectCommand2();
|
|
32680
34143
|
} else {
|
|
32681
|
-
const { hostname:
|
|
34144
|
+
const { hostname: hostname7 } = await import("os");
|
|
32682
34145
|
const { runConnectCommand: runConnectCommand2 } = await Promise.resolve().then(() => (init_cloud_enrollment_cli(), exports_cloud_enrollment_cli));
|
|
32683
34146
|
result2 = await runConnectCommand2({
|
|
32684
34147
|
url: valueAfter("--connect"),
|
|
32685
34148
|
token: valueAfter("--token"),
|
|
32686
34149
|
machineId: valueAfter("--machine-id"),
|
|
32687
34150
|
machineLabel: valueAfter("--machine-label"),
|
|
32688
|
-
defaultMachineId:
|
|
34151
|
+
defaultMachineId: hostname7(),
|
|
32689
34152
|
sessions: !args.includes("--no-transcripts")
|
|
32690
34153
|
});
|
|
32691
34154
|
}
|