failproofai 1.0.11 → 1.0.12-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/build-manifest.json +23 -23
- package/.next/standalone/.next/prerender-manifest.json +4 -4
- package/.next/standalone/.next/required-server-files.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page/build-manifest.json +3 -3
- 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 +2 -2
- 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 +2 -2
- package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found/page/build-manifest.json +3 -3
- 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 +3 -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 +3 -3
- package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/api/audit/invite/route.js +5 -6
- 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 +24 -24
- 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 -5
- 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 +6 -7
- 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 +6 -7
- 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 +5 -6
- 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 +2 -2
- package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/audit/page/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +2 -2
- package/.next/standalone/.next/server/app/audit/page.js +4 -4
- 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 +3 -3
- package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/page/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/page.js +2 -2
- package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/policies/page/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +14 -14
- package/.next/standalone/.next/server/app/policies/page.js +7 -7
- package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page/build-manifest.json +3 -3
- 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 +7 -7
- package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/build-manifest.json +3 -3
- 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 +8 -8
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/projects/page/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/projects/page.js +3 -3
- package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/settings/page/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +8 -8
- package/.next/standalone/.next/server/app/settings/page.js +10 -10
- package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/chunks/{[externals]__0qkp92tjfvw8r._.js → [externals]__0vt9i6fqinjne._.js} +1 -1
- package/.next/standalone/.next/server/chunks/[externals]__1x24dzcbbq6-g._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__02vous7mpi2xm._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__03i5o4a840guz._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0__a_je8fsn65._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0_hsnj_a2mvl_._.js +3 -0
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__1izwqj_ij_9x_._.js → [root-of-the-server]__0f_4g-vazrvxv._.js} +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0l-oi4gdtmlo5._.js +3 -0
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0swiyzbmvja2d._.js → [root-of-the-server]__0t9ufnv5hi2hq._.js} +5 -5
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0wg9dk8x8bnau._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__12kq3x-h7t7i1._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1a5zkndjwlc13._.js +3 -0
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__1r7kbfkiw2xmu._.js → [root-of-the-server]__1aaw59g-5uty7._.js} +12 -12
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1hqpg6vgmfexv._.js +3 -0
- package/.next/standalone/.next/server/chunks/_09dz7xva4ce_2._.js +1 -1
- package/.next/standalone/.next/server/chunks/_0hf5q4xzyg40j._.js +1 -1
- package/.next/standalone/.next/server/chunks/_0tovk6q0miud6._.js +1 -1
- package/.next/standalone/.next/server/chunks/_0trp3ycqv17cl._.js +1 -1
- package/.next/standalone/.next/server/chunks/_19011-u44143j._.js +1 -1
- package/.next/standalone/.next/server/chunks/_1ek68lnh2daur._.js +1 -1
- package/.next/standalone/.next/server/chunks/_1vslkoe35wok6._.js +1 -1
- package/.next/standalone/.next/server/chunks/{_1ixl-kxq_ctsa._.js → _1y590mjzpkbos._.js} +2 -2
- package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4vkpxxu7._.js +1 -1
- package/.next/standalone/.next/server/chunks/src_hooks_0_em82s16zfym._.js +5 -0
- package/.next/standalone/.next/server/chunks/src_hooks_builtin-policies_ts_1yq5ybgx1v98e._.js +3 -0
- package/.next/standalone/.next/server/chunks/src_hooks_custom-hooks-loader_ts_0lnb3n3h94wnn._.js +1 -1
- package/.next/standalone/.next/server/chunks/src_hooks_daemon-client_ts_0il_yu1zc0291._.js +1 -1
- package/.next/standalone/.next/server/chunks/src_hooks_fp-home_ts_09kv0bn_4twyh._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__01j58mdcdw0vn._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0588st-tpiuia._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__08ch3staq3ejw._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0_a8z2ldp2v3n._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0vcyntk4snf0f._.js → [root-of-the-server]__0b78b0j8iyv6l._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0bigvy9xmv2ka._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ffu2-38y03ic._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0g8b0kyorya-t._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0h86bl2qf0k_o._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1_xbg2kx30wp-._.js → [root-of-the-server]__0naevg4bcoh54._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0pia5h3p8re4c._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__075uro8t92s0_._.js → [root-of-the-server]__0pwj2h2efe5f-._.js} +3 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0zn1d4blhd3bu._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1-ey9fgesfbc0._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__15usvs-ms-0hf._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__16gb3_92zvk5x._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__17r4zrwanhp6r._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1avi2kypusyb_._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1lnfv02ucky7m._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1mc9-zlnh656_._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1r7drlqli-ado._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1s2-ck3k3rsoo._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1l1qgu5mfapkh._.js → [root-of-the-server]__1vx7o8ukefudh._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_0eoura3_9gjb-._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_0pedwblqdoh58._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_128ebxr83nk6g._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_1_ozgifqv1ssi._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{_1gb0ifpkowwub._.js → _1a3tubds7s7ow._.js} +10 -9
- package/.next/standalone/.next/server/chunks/ssr/_1djqs9i27e4kg._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_next-internal_server_app_policies_page_actions_1sp2-yo5_vm5f.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/app_actions_get-scheduled-audit_ts_0ei9snixb5fd-._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47q0xq5w._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x33jqb6._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpcz0uxur._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_settings_02tf1h47jmhhd._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{node_modules_html-to-image_es_index_1f_ymmaonkksc.js → node_modules_html-to-image_es_index_1i8oid1gc7s1f.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/package_json_[json]_cjs_013tntikdft59._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_06kzv9ddabn3_._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_0agdmptetetdt._.js +5 -0
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_0mdwgjisv4fub._.js +5 -0
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_1cv9_c4l1tzrm._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_daemon-client_ts_0k41_i7jg6ndv._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_pack-cli_ts_0t7me658zqmh_._.js +1 -1
- package/.next/standalone/.next/server/middleware-build-manifest.js +23 -23
- package/.next/standalone/.next/server/middleware.js +2 -2
- 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/preview-props.json +3 -3
- package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.json +23 -23
- package/.next/standalone/.next/static/chunks/{0frxv4_m-m2u5.js → 063al_q720fkj.js} +1 -1
- package/.next/standalone/.next/static/chunks/0_zfad4co-t2z.js +1 -0
- package/.next/standalone/.next/static/chunks/0jutamwqz8pg5.js +1 -0
- package/.next/standalone/.next/static/chunks/114hbolvrv94e.js +1 -0
- package/.next/standalone/.next/static/chunks/{37stoe-_yd852.js → 18433qz-8njv3.js} +1 -1
- package/.next/standalone/.next/static/chunks/{1kwj8uqxuv85t.js → 1b32-afqacaen.js} +1 -1
- package/.next/standalone/.next/static/chunks/{44a7k2_62qc-9.js → 1p-hsi58i-6h0.js} +2 -2
- package/.next/standalone/.next/static/chunks/{302llgh97ce6w.js → 2-tf6_7u623kd.js} +1 -1
- package/.next/standalone/.next/static/chunks/{1_c0dc7zqj1n7.js → 24w3x2da9sk49.js} +1 -1
- package/.next/standalone/.next/static/chunks/2tjfp9dirxnku.js +1 -0
- package/.next/standalone/.next/static/chunks/{16z6_d7sp61jm.js → 3-pku9qwv1yfu.js} +1 -1
- package/.next/standalone/.next/static/chunks/{15rm15u5a6dua.js → 42e8zab314654.js} +1 -1
- package/.next/standalone/fp-cloud-cli/CHANGELOG.md +41 -0
- package/.next/standalone/fp-cloud-cli/README.md +42 -1
- package/.next/standalone/fp-cloud-cli/fp_cli/client.py +117 -12
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/fleet_cmds.py +285 -19
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/policies_cmds.py +84 -18
- package/.next/standalone/fp-cloud-cli/fp_cli/enforcement.py +170 -6
- package/.next/standalone/fp-cloud-cli/fp_cli/models.py +89 -6
- package/.next/standalone/fp-cloud-cli/fp_cli/output.py +259 -21
- package/.next/standalone/fp-cloud-cli/fp_cli/policy_check.py +8 -5
- package/.next/standalone/fp-cloud-cli/skill/SKILL.md +2 -2
- package/.next/standalone/fp-cloud-cli/skill/references/commands.md +17 -9
- package/.next/standalone/fp-cloud-cli/tests/test_cloud_jev.py +692 -0
- package/.next/standalone/fp-cloud-cli/tests/test_enforcement_logic.py +46 -0
- package/.next/standalone/fp-cloud-cli/tests/test_output.py +23 -0
- package/.next/standalone/fp-cloud-cli/uv.lock +6 -6
- package/.next/standalone/hermes-plugin/README.md +6 -4
- package/.next/standalone/hermes-plugin/__init__.py +16 -0
- package/.next/standalone/hermes-plugin/client.py +5 -1
- package/.next/standalone/hermes-plugin/plugin.yaml +1 -1
- package/.next/standalone/node_modules/@next/env/package.json +1 -1
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/api/context.js +72 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/api/diag.js +84 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/api/metrics.js +50 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/api/propagation.js +80 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/api/trace.js +70 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/baggage/context-helpers.js +52 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/baggage/internal/baggage-impl.js +44 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/baggage/internal/symbol.js +12 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/baggage/utils.js +41 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/context/NoopContextManager.js +27 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/context/context.js +52 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/context-api.js +16 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/diag/ComponentLogger.js +47 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/diag/consoleLogger.js +73 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/diag/internal/logLevelLogger.js +34 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/diag/types.js +33 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/diag-api.js +20 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/index.js +71 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/internal/global-utils.js +60 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/internal/semver.js +111 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/metrics/Metric.js +18 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/metrics/NoopMeter.js +118 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/metrics/NoopMeterProvider.js +20 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/metrics-api.js +17 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/propagation/NoopTextMapPropagator.js +23 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/propagation/TextMapPropagator.js +36 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/propagation-api.js +17 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/NonRecordingSpan.js +58 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/NoopTracer.js +68 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/NoopTracerProvider.js +21 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/ProxyTracer.js +46 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/ProxyTracerProvider.js +46 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/SamplingResult.js +33 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/context-utils.js +71 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/internal/tracestate-impl.js +94 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/internal/tracestate-validators.js +35 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/internal/utils.js +16 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/invalid-span-constants.js +25 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/span_kind.js +38 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/spancontext-utils.js +66 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/status.js +29 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace/trace_flags.js +18 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/trace-api.js +17 -0
- package/.next/standalone/node_modules/@opentelemetry/api/build/src/version.js +10 -0
- package/.next/standalone/node_modules/@opentelemetry/api/package.json +96 -0
- package/.next/standalone/node_modules/next/dist/build/swc/index.js +1 -1
- package/.next/standalone/node_modules/next/dist/compiled/next-server/app-page-turbo-experimental.runtime.prod.js +2 -2
- package/.next/standalone/node_modules/next/dist/compiled/next-server/app-page-turbo.runtime.prod.js +2 -2
- package/.next/standalone/node_modules/next/dist/compiled/next-server/app-route-turbo.runtime.prod.js +1 -1
- package/.next/standalone/node_modules/next/dist/lib/patch-incorrect-lockfile.js +3 -3
- package/.next/standalone/node_modules/next/dist/server/app-render/async-local-storage.js +1 -1
- package/.next/standalone/node_modules/next/dist/server/config.js +1 -1
- package/.next/standalone/node_modules/next/dist/server/dev/hot-reloader-turbopack.js +2 -2
- package/.next/standalone/node_modules/next/dist/server/dev/hot-reloader-webpack.js +1 -1
- package/.next/standalone/node_modules/next/dist/server/lib/app-info-log.js +1 -1
- package/.next/standalone/node_modules/next/dist/server/lib/generate-agent-files.js +3 -3
- package/.next/standalone/node_modules/next/dist/server/lib/router-server.js +1 -1
- package/.next/standalone/node_modules/next/dist/server/lib/start-server.js +1 -1
- package/.next/standalone/node_modules/next/dist/server/lib/trace/tracer.js +1 -1
- package/.next/standalone/node_modules/next/dist/server/typescript/rules/config.js +2 -2
- package/.next/standalone/node_modules/next/dist/server/use-cache/use-cache-wrapper.js +1 -1
- package/.next/standalone/node_modules/next/dist/telemetry/anonymous-meta.js +1 -1
- package/.next/standalone/node_modules/next/dist/telemetry/events/swc-load-failure.js +1 -1
- package/.next/standalone/node_modules/next/dist/telemetry/events/version.js +2 -2
- package/.next/standalone/node_modules/next/package.json +11 -11
- package/.next/standalone/package.json +11 -11
- package/.next/standalone/sdk/python/CHANGELOG.md +7 -0
- package/.next/standalone/sdk/python/failproofai_sdk/_version.py +1 -1
- package/.next/standalone/sdk/python/pyproject.toml +19 -0
- package/.next/standalone/sdk/python/uv.lock +520 -301
- package/.next/standalone/sdk/typescript/CHANGELOG.md +13 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/mastra-1/package-lock.json +4 -13
- package/.next/standalone/sdk/typescript/integration/fixtures/mastra-1/package.json +2 -1
- package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/package-lock.json +4 -13
- package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/package.json +3 -0
- package/.next/standalone/sdk/typescript/package-lock.json +178 -162
- package/.next/standalone/sdk/typescript/package.json +1 -1
- package/.next/standalone/sdk/typescript/src/version.ts +1 -1
- package/.next/standalone/server.js +1 -1
- package/bin/failproofai.mjs +17 -1
- package/dist/cli.mjs +2866 -1124
- package/dist/worker.mjs +1450 -145
- package/hermes-plugin/README.md +6 -4
- package/hermes-plugin/__init__.py +16 -0
- package/hermes-plugin/client.py +5 -1
- package/hermes-plugin/plugin.yaml +1 -1
- package/package.json +11 -11
- package/src/hooks/agent-roster.ts +172 -0
- package/src/hooks/agent-targets.ts +60 -0
- package/src/hooks/cloud-connection.ts +97 -27
- package/src/hooks/cloud-enrollment-cli.ts +7 -4
- package/src/hooks/cloud-managed-policies.ts +380 -20
- package/src/hooks/cloud-policy-errors.ts +481 -0
- package/src/hooks/config-status.ts +1 -1
- package/src/hooks/custom-hooks-loader.ts +26 -3
- package/src/hooks/daemon-client.ts +9 -4
- package/src/hooks/daemon-service.ts +2 -1
- package/src/hooks/effective-reviewers.ts +22 -1
- package/src/hooks/fp-home.ts +6 -0
- package/src/hooks/handler.ts +235 -18
- package/src/hooks/health-probe.ts +15 -0
- package/src/hooks/integrations.ts +18 -11
- package/src/hooks/jev-cli.ts +197 -0
- package/src/hooks/jev-cloud-connection.ts +92 -0
- package/src/hooks/manager.ts +122 -16
- package/src/hooks/pack-failclosed.ts +2 -0
- package/src/hooks/pack-manifest.ts +8 -1
- package/src/hooks/policy-evaluator.ts +5 -1
- package/src/hooks/policy-registry.ts +3 -2
- package/src/hooks/policy-reviewability.ts +21 -5
- package/src/hooks/semantic/cloud-jev-health.ts +227 -0
- package/src/hooks/semantic/cloud-jev.ts +677 -0
- package/src/hooks/semantic/jev-client.ts +18 -1
- package/src/hooks/semantic/jev-config.ts +173 -3
- package/src/hooks/semantic/jev-review.ts +129 -10
- package/src/hooks/semantic/pack-policies.ts +2 -1
- package/src/hooks/semantic/types.ts +8 -0
- package/src/hooks/session-pause-cli.ts +1 -1
- package/src/hooks/worker-server.ts +5 -1
- package/.next/standalone/.next/server/chunks/[externals]__0hjaw70fchx66._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__07l68zv0hqdiu._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0car70pylmvor._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0u3i025_setk_._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__10a2f6s636yc7._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1qt5u58xrcuk6._.js +0 -3
- package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_077n_4ip5__fu._.js +0 -3
- package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_0mqvvxcn6v0op._.js +0 -3
- package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_0pb7ds5g0vzgn._.js +0 -3
- package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_1gasm5xkeqmm3._.js +0 -3
- package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_1q1heqmkhh8l4._.js +0 -3
- package/.next/standalone/.next/server/chunks/src_hooks_1aveq0uhs2t1b._.js +0 -5
- package/.next/standalone/.next/server/chunks/src_hooks_1eem5a7cyqlb2._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0888k4s6spfmh._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0_bflu046ep5j._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0_lbstb5x2t15._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0fdwgktjfhedo._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0s4deza787asx._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__18qe-hu0gwqm4._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1_p_9xe520fex._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1fmhm8_s9i4re._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1g76awtnmimd1._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1pczevlpk5lxh._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_0dc-of_bn0cim._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_effective-reviewers_ts_1h4wtvo55j16x._.js +0 -5
- package/.next/standalone/.next/static/chunks/0m-tv1y6ghhtk.js +0 -1
- package/.next/standalone/.next/static/chunks/0ol2gj4ntfn56.js +0 -1
- package/.next/standalone/.next/static/chunks/3hj5_7i3nw4zj.js +0 -1
- package/.next/standalone/.next/static/chunks/3iyoapeoq_hup.js +0 -1
- /package/.next/standalone/.next/static/{kEFP3ybXwZdriNEQmWwlH → xq8UgF5yFxty1VWxY2hyn}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{kEFP3ybXwZdriNEQmWwlH → xq8UgF5yFxty1VWxY2hyn}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{kEFP3ybXwZdriNEQmWwlH → xq8UgF5yFxty1VWxY2hyn}/_ssgManifest.js +0 -0
package/dist/worker.mjs
CHANGED
|
@@ -26,8 +26,9 @@ var __esm = (fn, res, err) => () => {
|
|
|
26
26
|
};
|
|
27
27
|
|
|
28
28
|
// src/hooks/types.ts
|
|
29
|
-
var CODEX_EVENT_MAP, CODEX_TOOL_MAP, HERMES_TOOL_MAP, HERMES_TOOL_INPUT_MAP, HERMES_EVENT_MAP, COPILOT_TOOL_MAP, COPILOT_TOOL_INPUT_MAP, CURSOR_EVENT_MAP, CURSOR_TOOL_MAP, OPENCODE_TOOL_MAP, OPENCODE_TOOL_INPUT_MAP, PI_EVENT_MAP, PI_TOOL_MAP, PI_TOOL_INPUT_MAP, OPENCLAW_EVENT_MAP, OPENCLAW_TOOL_MAP, OPENCLAW_TOOL_INPUT_MAP, FACTORY_TOOL_MAP, DEVIN_TOOL_MAP, ANTIGRAVITY_EVENT_MAP, ANTIGRAVITY_TOOL_MAP, ANTIGRAVITY_TOOL_INPUT_MAP, GOOSE_TOOL_MAP, GOOSE_TOOL_INPUT_MAP, HOOK_EVENT_TYPES, CLAUDE_INSTALL_EVENT_TYPES;
|
|
29
|
+
var INTEGRATION_TYPES, CODEX_EVENT_MAP, CODEX_TOOL_MAP, HERMES_TOOL_MAP, HERMES_TOOL_INPUT_MAP, HERMES_EVENT_MAP, COPILOT_TOOL_MAP, COPILOT_TOOL_INPUT_MAP, CURSOR_EVENT_MAP, CURSOR_TOOL_MAP, OPENCODE_TOOL_MAP, OPENCODE_TOOL_INPUT_MAP, PI_EVENT_MAP, PI_TOOL_MAP, PI_TOOL_INPUT_MAP, OPENCLAW_EVENT_MAP, OPENCLAW_TOOL_MAP, OPENCLAW_TOOL_INPUT_MAP, FACTORY_TOOL_MAP, DEVIN_TOOL_MAP, ANTIGRAVITY_EVENT_MAP, ANTIGRAVITY_TOOL_MAP, ANTIGRAVITY_TOOL_INPUT_MAP, GOOSE_TOOL_MAP, GOOSE_TOOL_INPUT_MAP, HOOK_EVENT_TYPES, CLAUDE_INSTALL_EVENT_TYPES;
|
|
30
30
|
var init_types = __esm(() => {
|
|
31
|
+
INTEGRATION_TYPES = ["claude", "codex", "copilot", "cursor", "opencode", "pi", "hermes", "openclaw", "factory", "devin", "antigravity", "goose"];
|
|
31
32
|
CODEX_EVENT_MAP = {
|
|
32
33
|
session_start: "SessionStart",
|
|
33
34
|
pre_tool_use: "PreToolUse",
|
|
@@ -381,7 +382,7 @@ function failproofaiHome(home) {
|
|
|
381
382
|
return resolve(home, ".failproofai");
|
|
382
383
|
return process.env.FAILPROOFAI_HOME || resolve(homedir(), ".failproofai");
|
|
383
384
|
}
|
|
384
|
-
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"), jevConfigFile = (home) => atHome(home, "jev.json"), policiesDir = (home) => atHome(home, "policies"), customPoliciesDir, globalPolicyConfigFile = (home) => atHome(home, "policies-config.json"), cloudPoliciesDir = (home) => resolve(policiesDir(home), "cloud-policies"), packsDir = (home) => resolve(policiesDir(home), "packs"), packsInstalledFile = (home) => resolve(packsDir(home), "installed.json"), hookActivityDir = (home) => atHome(home, "hook-activity"), stateDir = (home) => atHome(home, "state"), shimsDir = (home) => resolve(stateDir(home), "shims"), sessionPauseDir = () => resolve(stateDir(), "sessions"), semanticDir = () => resolve(stateDir(), "semantic"), telemetryIdFile = (home) => resolve(stateDir(home), "telemetry-id"), codexSessionPathsFile = (home) => resolve(stateDir(home), "codex-session-paths.json"), logsDir = (home) => atHome(home, "logs"), legacy;
|
|
385
|
+
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"), jevConfigFile = (home) => atHome(home, "jev.json"), agentRosterFile = (home) => atHome(home, "agents", "roster.json"), policiesDir = (home) => atHome(home, "policies"), customPoliciesDir, globalPolicyConfigFile = (home) => atHome(home, "policies-config.json"), cloudPoliciesDir = (home) => resolve(policiesDir(home), "cloud-policies"), packsDir = (home) => resolve(policiesDir(home), "packs"), packsInstalledFile = (home) => resolve(packsDir(home), "installed.json"), hookActivityDir = (home) => atHome(home, "hook-activity"), stateDir = (home) => atHome(home, "state"), shimsDir = (home) => resolve(stateDir(home), "shims"), sessionPauseDir = () => resolve(stateDir(), "sessions"), semanticDir = () => resolve(stateDir(), "semantic"), telemetryIdFile = (home) => resolve(stateDir(home), "telemetry-id"), codexSessionPathsFile = (home) => resolve(stateDir(home), "codex-session-paths.json"), logsDir = (home) => atHome(home, "logs"), legacy;
|
|
385
386
|
var init_fp_home = __esm(() => {
|
|
386
387
|
customPoliciesDir = policiesDir;
|
|
387
388
|
legacy = {
|
|
@@ -1165,9 +1166,55 @@ function instruct(reason) {
|
|
|
1165
1166
|
}
|
|
1166
1167
|
|
|
1167
1168
|
// package.json
|
|
1168
|
-
var version = "1.0.
|
|
1169
|
+
var version = "1.0.12-beta.1";
|
|
1169
1170
|
var init_package = () => {};
|
|
1170
1171
|
|
|
1172
|
+
// src/hooks/agent-targets.ts
|
|
1173
|
+
function validAgentIdentity(value) {
|
|
1174
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
1175
|
+
return false;
|
|
1176
|
+
const agent = value;
|
|
1177
|
+
return Object.keys(agent).every((key) => key === "integration" || key === "instanceId") && typeof agent.integration === "string" && integrations.has(agent.integration) && typeof agent.instanceId === "string" && INSTANCE_ID_RE.test(agent.instanceId);
|
|
1178
|
+
}
|
|
1179
|
+
function parseAgentTargets(value, schemaVersion) {
|
|
1180
|
+
if (value === undefined || value === null)
|
|
1181
|
+
return;
|
|
1182
|
+
if (schemaVersion < 3 || !Array.isArray(value) || value.length < 1 || value.length > 32) {
|
|
1183
|
+
throw new Error("invalid agentTargets in cloud-managed active manifest");
|
|
1184
|
+
}
|
|
1185
|
+
const seen = new Set;
|
|
1186
|
+
return value.map((raw) => {
|
|
1187
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
1188
|
+
throw new Error("invalid agentTargets in cloud-managed active manifest");
|
|
1189
|
+
}
|
|
1190
|
+
const entry = raw;
|
|
1191
|
+
if (Object.keys(entry).some((key) => key !== "integration" && key !== "instanceId") || typeof entry.integration !== "string" || !integrations.has(entry.integration) || entry.instanceId !== undefined && (typeof entry.instanceId !== "string" || !INSTANCE_ID_RE.test(entry.instanceId))) {
|
|
1192
|
+
throw new Error("invalid agentTargets in cloud-managed active manifest");
|
|
1193
|
+
}
|
|
1194
|
+
const key = `${entry.integration}\x00${entry.instanceId ?? ""}`;
|
|
1195
|
+
if (seen.has(key))
|
|
1196
|
+
throw new Error("duplicate agentTargets in cloud-managed active manifest");
|
|
1197
|
+
seen.add(key);
|
|
1198
|
+
return {
|
|
1199
|
+
integration: entry.integration,
|
|
1200
|
+
...entry.instanceId !== undefined ? { instanceId: entry.instanceId } : {}
|
|
1201
|
+
};
|
|
1202
|
+
});
|
|
1203
|
+
}
|
|
1204
|
+
function agentTargetsMatch(targets, agent) {
|
|
1205
|
+
if (targets === undefined)
|
|
1206
|
+
return true;
|
|
1207
|
+
if (!validAgentIdentity(agent))
|
|
1208
|
+
return false;
|
|
1209
|
+
return targets.some((target) => target.integration === agent.integration && (target.instanceId === undefined || target.instanceId === agent.instanceId));
|
|
1210
|
+
}
|
|
1211
|
+
var INSTANCE_ID_RE, integrations;
|
|
1212
|
+
var init_agent_targets = __esm(() => {
|
|
1213
|
+
init_types();
|
|
1214
|
+
INSTANCE_ID_RE = /^agt_[0-9a-f]{16,32}$/;
|
|
1215
|
+
integrations = new Set(INTEGRATION_TYPES);
|
|
1216
|
+
});
|
|
1217
|
+
|
|
1171
1218
|
// src/hooks/policy-types.ts
|
|
1172
1219
|
function effectiveAuthority(p) {
|
|
1173
1220
|
if (p.alwaysOn === true)
|
|
@@ -1298,11 +1345,22 @@ var init_policy_authority = __esm(() => {
|
|
|
1298
1345
|
|
|
1299
1346
|
// src/hooks/cloud-managed-policies.ts
|
|
1300
1347
|
import { createHash } from "node:crypto";
|
|
1301
|
-
import { existsSync as existsSync4, readFileSync as readFileSync2, realpathSync, rmSync } from "node:fs";
|
|
1348
|
+
import { existsSync as existsSync4, readFileSync as readFileSync2, realpathSync, rmSync, statSync as statSync3 } from "node:fs";
|
|
1302
1349
|
import { isAbsolute, relative, resolve as resolve3 } from "node:path";
|
|
1303
1350
|
function cloudManagedPolicyRoot() {
|
|
1304
1351
|
return process.env.FAILPROOFAI_CLOUD_POLICY_DIR ?? cloudPoliciesDir();
|
|
1305
1352
|
}
|
|
1353
|
+
function disconnectedByConfig() {
|
|
1354
|
+
try {
|
|
1355
|
+
const raw = JSON.parse(readFileSync2(configFile(), "utf8"));
|
|
1356
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw))
|
|
1357
|
+
return false;
|
|
1358
|
+
const mode = raw.mode;
|
|
1359
|
+
return !!mode && typeof mode === "object" && !Array.isArray(mode) && mode.kind === "oss";
|
|
1360
|
+
} catch {
|
|
1361
|
+
return false;
|
|
1362
|
+
}
|
|
1363
|
+
}
|
|
1306
1364
|
function parseManifest(value) {
|
|
1307
1365
|
if (!value || typeof value !== "object")
|
|
1308
1366
|
throw new Error("active manifest is not an object");
|
|
@@ -1338,20 +1396,150 @@ function resolveManagedPath(root, candidate) {
|
|
|
1338
1396
|
}
|
|
1339
1397
|
return realFile;
|
|
1340
1398
|
}
|
|
1341
|
-
function
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1399
|
+
function parseCloudJevMode(raw) {
|
|
1400
|
+
return raw === "off" || raw === "observe" || raw === "enforce" ? raw : null;
|
|
1401
|
+
}
|
|
1402
|
+
function cloudJevAsks(mode) {
|
|
1403
|
+
return mode === "observe" || mode === "enforce";
|
|
1404
|
+
}
|
|
1405
|
+
function fileVersion(path) {
|
|
1406
|
+
try {
|
|
1407
|
+
const s = statSync3(path, { bigint: true });
|
|
1408
|
+
return `${s.dev}:${s.ino}:${s.mode}:${s.size}:${s.mtimeNs}:${s.ctimeNs}`;
|
|
1409
|
+
} catch (err) {
|
|
1410
|
+
const code = err.code;
|
|
1411
|
+
if (code === "ENOENT" || code === "ENOTDIR")
|
|
1412
|
+
return null;
|
|
1413
|
+
throw err;
|
|
1414
|
+
}
|
|
1415
|
+
}
|
|
1416
|
+
function readActiveJson() {
|
|
1417
|
+
if (disconnectedByConfig()) {
|
|
1418
|
+
activeJsonCache = null;
|
|
1419
|
+
return;
|
|
1420
|
+
}
|
|
1421
|
+
const path = resolve3(cloudManagedPolicyRoot(), "active.json");
|
|
1422
|
+
const version = fileVersion(path);
|
|
1423
|
+
if (version === null) {
|
|
1424
|
+
activeJsonCache = null;
|
|
1425
|
+
return;
|
|
1426
|
+
}
|
|
1427
|
+
if (activeJsonCache && activeJsonCache.path === path && activeJsonCache.version === version)
|
|
1428
|
+
return activeJsonCache.value;
|
|
1429
|
+
const value = JSON.parse(readFileSync2(path, "utf8"));
|
|
1430
|
+
activeJsonCache = { path, version, value };
|
|
1431
|
+
return value;
|
|
1432
|
+
}
|
|
1433
|
+
function readActiveRaw() {
|
|
1434
|
+
const raw = readActiveJson();
|
|
1435
|
+
if (raw === undefined)
|
|
1436
|
+
return null;
|
|
1437
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw))
|
|
1438
|
+
throw new Error("active manifest is not an object");
|
|
1439
|
+
const record = raw;
|
|
1440
|
+
if (!ACCEPTED_ACTIVE_SCHEMA_VERSIONS.includes(record.schemaVersion)) {
|
|
1441
|
+
throw new Error(`unsupported active manifest schema ${String(record.schemaVersion)}`);
|
|
1442
|
+
}
|
|
1443
|
+
return record;
|
|
1444
|
+
}
|
|
1445
|
+
function readCloudAgentScopeRequired() {
|
|
1446
|
+
try {
|
|
1447
|
+
return readActiveRaw()?.schemaVersion === 3;
|
|
1448
|
+
} catch {
|
|
1449
|
+
return false;
|
|
1450
|
+
}
|
|
1451
|
+
}
|
|
1452
|
+
function readCloudJevMode() {
|
|
1453
|
+
try {
|
|
1454
|
+
return parseCloudJevMode(readActiveRaw()?.jevMode);
|
|
1455
|
+
} catch {
|
|
1456
|
+
return null;
|
|
1457
|
+
}
|
|
1458
|
+
}
|
|
1459
|
+
function readCloudJevState() {
|
|
1460
|
+
let active;
|
|
1461
|
+
try {
|
|
1462
|
+
active = readActiveRaw();
|
|
1463
|
+
} catch {
|
|
1464
|
+
return noCloudJev();
|
|
1465
|
+
}
|
|
1466
|
+
if (!active)
|
|
1467
|
+
return noCloudJev();
|
|
1468
|
+
const rawMode = active.jevMode;
|
|
1469
|
+
const jevMode = parseCloudJevMode(rawMode);
|
|
1470
|
+
const errors = [];
|
|
1471
|
+
if (rawMode !== undefined && rawMode !== null && jevMode === null) {
|
|
1472
|
+
errors.push({ id: "jevMode", version: null, kind: "daemon", message: `unknown Jev mode ${JSON.stringify(rawMode)} ignored` });
|
|
1473
|
+
}
|
|
1474
|
+
const deployment = Number.isSafeInteger(active.deployment) ? active.deployment : null;
|
|
1475
|
+
return { jevMode, deployment, errors };
|
|
1476
|
+
}
|
|
1477
|
+
function cloudReviewerName(policyId, name) {
|
|
1478
|
+
return `cloud:${policyId}/${name}`;
|
|
1479
|
+
}
|
|
1480
|
+
function cloudAuthorityDeclaration(policy, mode) {
|
|
1481
|
+
if (policy.authority !== "reviewable")
|
|
1482
|
+
return policy.authority ? { authority: policy.authority } : {};
|
|
1483
|
+
if (policy.effect === "observe" || !cloudJevAsks(mode))
|
|
1484
|
+
return { authority: "hard" };
|
|
1485
|
+
return {
|
|
1486
|
+
authority: "reviewable",
|
|
1487
|
+
reviewedBy: (policy.reviewedBy ?? []).map((n) => CLOUD_REVIEWER_RE.test(n) ? n : cloudReviewerName(policy.id, n))
|
|
1488
|
+
};
|
|
1489
|
+
}
|
|
1490
|
+
function withCloudAuthority(policy, mode) {
|
|
1491
|
+
const { authority: _authority, reviewedBy: _reviewedBy, ...rest } = policy;
|
|
1492
|
+
return { ...rest, ...cloudAuthorityDeclaration(policy, mode) };
|
|
1493
|
+
}
|
|
1494
|
+
function cloudReviewerNames(policies, mode) {
|
|
1495
|
+
const out = [];
|
|
1496
|
+
for (const policy of policies) {
|
|
1497
|
+
const declared = cloudAuthorityDeclaration(policy, mode);
|
|
1498
|
+
if (declared.authority === "reviewable")
|
|
1499
|
+
out.push(...declared.reviewedBy ?? []);
|
|
1500
|
+
}
|
|
1501
|
+
return out;
|
|
1502
|
+
}
|
|
1503
|
+
function readCloudAuthorityInputs(agent = null) {
|
|
1504
|
+
try {
|
|
1505
|
+
const raw = readActiveJson();
|
|
1506
|
+
if (raw === undefined)
|
|
1507
|
+
return [];
|
|
1508
|
+
const manifest = parseManifest(raw);
|
|
1509
|
+
return manifest.policies.flatMap((policy) => {
|
|
1510
|
+
if (typeof policy.id !== "string")
|
|
1511
|
+
return [];
|
|
1512
|
+
const targets = parseAgentTargets(policy.agentTargets, manifest.schemaVersion);
|
|
1513
|
+
if (!agentTargetsMatch(targets, agent))
|
|
1514
|
+
return [];
|
|
1515
|
+
return [{
|
|
1516
|
+
id: policy.id,
|
|
1517
|
+
effect: policy.effect === "observe" ? "observe" : "enforce",
|
|
1518
|
+
...targets ? { agentTargets: targets } : {},
|
|
1519
|
+
...authorityFieldsOf(policy)
|
|
1520
|
+
}];
|
|
1521
|
+
});
|
|
1522
|
+
} catch {
|
|
1345
1523
|
return [];
|
|
1524
|
+
}
|
|
1525
|
+
}
|
|
1526
|
+
function readActiveCloudManagedPolicies(agent = null) {
|
|
1527
|
+
return readActiveCloudManagedPoliciesFor((targets) => agentTargetsMatch(targets, agent));
|
|
1528
|
+
}
|
|
1529
|
+
function readActiveCloudManagedPoliciesFor(applies) {
|
|
1530
|
+
const root = cloudManagedPolicyRoot();
|
|
1346
1531
|
let raw;
|
|
1347
1532
|
try {
|
|
1348
|
-
raw =
|
|
1533
|
+
raw = readActiveJson();
|
|
1349
1534
|
} catch (err) {
|
|
1350
1535
|
throw new Error(`failed to read cloud-managed active manifest: ${err instanceof Error ? err.message : String(err)}`);
|
|
1351
1536
|
}
|
|
1537
|
+
if (raw === undefined)
|
|
1538
|
+
return [];
|
|
1352
1539
|
const manifest = parseManifest(raw);
|
|
1540
|
+
const applicable = manifest.policies.filter((policy) => applies(parseAgentTargets(policy.agentTargets, manifest.schemaVersion)));
|
|
1353
1541
|
const seen = new Set;
|
|
1354
|
-
return
|
|
1542
|
+
return applicable.map((policy) => {
|
|
1355
1543
|
if (!POLICY_ID_RE.test(policy.id) || policy.id === "." || policy.id === "..") {
|
|
1356
1544
|
throw new Error(`unsafe cloud-managed policy id ${JSON.stringify(policy.id)}`);
|
|
1357
1545
|
}
|
|
@@ -1380,17 +1568,20 @@ function readActiveCloudManagedPolicies() {
|
|
|
1380
1568
|
sha256: policy.sha256,
|
|
1381
1569
|
path,
|
|
1382
1570
|
deployment: manifest.deployment,
|
|
1571
|
+
...parseAgentTargets(policy.agentTargets, manifest.schemaVersion) ? { agentTargets: parseAgentTargets(policy.agentTargets, manifest.schemaVersion) } : {},
|
|
1383
1572
|
...authorityFieldsOf(policy)
|
|
1384
1573
|
};
|
|
1385
1574
|
});
|
|
1386
1575
|
}
|
|
1387
|
-
var ACCEPTED_ACTIVE_SCHEMA_VERSIONS, SHA256_RE, POLICY_ID_RE;
|
|
1576
|
+
var ACCEPTED_ACTIVE_SCHEMA_VERSIONS, SHA256_RE, POLICY_ID_RE, CLOUD_POLICY_ERRORS_FILE = "errors.json", JEV_BUDGET_FILE = "jev-budget.json", noCloudJev = () => ({ jevMode: null, deployment: null, errors: [] }), activeJsonCache = null, CLOUD_REVIEWER_RE;
|
|
1388
1577
|
var init_cloud_managed_policies = __esm(() => {
|
|
1389
1578
|
init_fp_home();
|
|
1579
|
+
init_agent_targets();
|
|
1390
1580
|
init_policy_authority();
|
|
1391
|
-
ACCEPTED_ACTIVE_SCHEMA_VERSIONS = [1, 2];
|
|
1581
|
+
ACCEPTED_ACTIVE_SCHEMA_VERSIONS = [1, 2, 3];
|
|
1392
1582
|
SHA256_RE = /^[a-f0-9]{64}$/;
|
|
1393
1583
|
POLICY_ID_RE = /^[A-Za-z0-9._-]{1,128}$/;
|
|
1584
|
+
CLOUD_REVIEWER_RE = /^cloud:[^/]+\/./;
|
|
1394
1585
|
});
|
|
1395
1586
|
|
|
1396
1587
|
// src/hooks/semver-precedence.ts
|
|
@@ -1918,6 +2109,11 @@ function effectiveReviewerNames() {
|
|
|
1918
2109
|
names = reviewerNamesFor(packs);
|
|
1919
2110
|
cachedContested = contestedSemanticNames(packs);
|
|
1920
2111
|
} catch {}
|
|
2112
|
+
try {
|
|
2113
|
+
const cloud = cloudReviewerNames(readCloudAuthorityInputs(reviewerAgent), readCloudJevMode());
|
|
2114
|
+
if (cloud.length > 0)
|
|
2115
|
+
names = new Set([...names, ...cloud]);
|
|
2116
|
+
} catch {}
|
|
1921
2117
|
cached = names;
|
|
1922
2118
|
return names;
|
|
1923
2119
|
}
|
|
@@ -1935,14 +2131,16 @@ function reviewerNamesFor(packs) {
|
|
|
1935
2131
|
return NO_REVIEWERS;
|
|
1936
2132
|
return new Set(declared);
|
|
1937
2133
|
}
|
|
1938
|
-
function forgetEffectiveReviewerNames(cli) {
|
|
2134
|
+
function forgetEffectiveReviewerNames(cli, agent = null) {
|
|
1939
2135
|
cached = null;
|
|
1940
2136
|
reviewerCli = cli;
|
|
2137
|
+
reviewerAgent = agent;
|
|
1941
2138
|
}
|
|
1942
|
-
var cached = null, cachedContested, reviewerCli;
|
|
2139
|
+
var cached = null, cachedContested, reviewerCli, reviewerAgent = null;
|
|
1943
2140
|
var init_effective_reviewers = __esm(() => {
|
|
1944
2141
|
init_pack_manifest();
|
|
1945
2142
|
init_policy_authority();
|
|
2143
|
+
init_cloud_managed_policies();
|
|
1946
2144
|
cachedContested = new Map;
|
|
1947
2145
|
});
|
|
1948
2146
|
|
|
@@ -2009,11 +2207,11 @@ function getPoliciesForEvent(eventType, toolName) {
|
|
|
2009
2207
|
cache.set(key, result);
|
|
2010
2208
|
return result;
|
|
2011
2209
|
}
|
|
2012
|
-
function clearPolicies(cli) {
|
|
2210
|
+
function clearPolicies(cli, agent = null) {
|
|
2013
2211
|
const g = globalThis;
|
|
2014
2212
|
g[REGISTRY_KEY] = [];
|
|
2015
2213
|
setIndexCache(null);
|
|
2016
|
-
forgetEffectiveReviewerNames(cli);
|
|
2214
|
+
forgetEffectiveReviewerNames(cli, agent);
|
|
2017
2215
|
}
|
|
2018
2216
|
var REGISTRY_KEY = "__FAILPROOFAI_POLICY_REGISTRY__", INDEX_CACHE_KEY = "__FAILPROOFAI_POLICY_INDEX_CACHE__", DEFAULT_POLICY_NAMESPACE = "failproofai";
|
|
2019
2217
|
var init_policy_registry = __esm(() => {
|
|
@@ -2023,7 +2221,7 @@ var init_policy_registry = __esm(() => {
|
|
|
2023
2221
|
|
|
2024
2222
|
// src/hooks/builtin-policies.ts
|
|
2025
2223
|
import { resolve as resolve5, join as join2 } from "node:path";
|
|
2026
|
-
import { statSync as
|
|
2224
|
+
import { statSync as statSync4 } from "node:fs";
|
|
2027
2225
|
import { readFile, writeFile } from "node:fs/promises";
|
|
2028
2226
|
import { execSync, execFileSync } from "node:child_process";
|
|
2029
2227
|
import { homedir as homedir3 } from "node:os";
|
|
@@ -2568,7 +2766,7 @@ function destroysFailproofaiState(command, depth = 0) {
|
|
|
2568
2766
|
}
|
|
2569
2767
|
function statGitHeadMtimeMs(cwd) {
|
|
2570
2768
|
try {
|
|
2571
|
-
return
|
|
2769
|
+
return statSync4(join2(cwd, ".git", "HEAD")).mtimeMs;
|
|
2572
2770
|
} catch {
|
|
2573
2771
|
return null;
|
|
2574
2772
|
}
|
|
@@ -4386,7 +4584,7 @@ import {
|
|
|
4386
4584
|
mkdirSync as mkdirSync3,
|
|
4387
4585
|
renameSync as renameSync2,
|
|
4388
4586
|
rmSync as rmSync2,
|
|
4389
|
-
statSync as
|
|
4587
|
+
statSync as statSync5,
|
|
4390
4588
|
writeFileSync as writeFileSync2
|
|
4391
4589
|
} from "node:fs";
|
|
4392
4590
|
import { dirname as dirname2 } from "node:path";
|
|
@@ -4401,12 +4599,12 @@ function writeJsonAtomically(filePath, value, opts = {}) {
|
|
|
4401
4599
|
try {
|
|
4402
4600
|
writeFileSync2(tmp, JSON.stringify(value, null, 2), { mode });
|
|
4403
4601
|
try {
|
|
4404
|
-
if ((
|
|
4602
|
+
if ((statSync5(tmp).mode & 63) !== 0)
|
|
4405
4603
|
chmodSync(tmp, mode);
|
|
4406
4604
|
} catch {}
|
|
4407
4605
|
renameSync2(tmp, filePath);
|
|
4408
4606
|
try {
|
|
4409
|
-
if ((
|
|
4607
|
+
if ((statSync5(filePath).mode & 63) !== 0)
|
|
4410
4608
|
chmodSync(filePath, mode);
|
|
4411
4609
|
} catch {}
|
|
4412
4610
|
} catch (err) {
|
|
@@ -4429,7 +4627,7 @@ import {
|
|
|
4429
4627
|
openSync,
|
|
4430
4628
|
readFileSync as readFileSync4,
|
|
4431
4629
|
readSync,
|
|
4432
|
-
statSync as
|
|
4630
|
+
statSync as statSync6,
|
|
4433
4631
|
writeFileSync as writeFileSync3
|
|
4434
4632
|
} from "node:fs";
|
|
4435
4633
|
import { dirname as dirname3 } from "node:path";
|
|
@@ -4586,6 +4784,13 @@ function projectConfig(parsed) {
|
|
|
4586
4784
|
function isAgentTraced(id, config = readConfig()) {
|
|
4587
4785
|
return !config.agents || config.agents.selected.includes(id);
|
|
4588
4786
|
}
|
|
4787
|
+
function readCredentials() {
|
|
4788
|
+
try {
|
|
4789
|
+
return projectCredentials(JSON.parse(readFileSync4(credentialsFile(), "utf8")));
|
|
4790
|
+
} catch {
|
|
4791
|
+
return {};
|
|
4792
|
+
}
|
|
4793
|
+
}
|
|
4589
4794
|
function projectCredentials(parsed) {
|
|
4590
4795
|
{
|
|
4591
4796
|
const cloud = parsed.cloud;
|
|
@@ -4661,7 +4866,7 @@ function readJevCloudCredential() {
|
|
|
4661
4866
|
if (meaningful) {
|
|
4662
4867
|
let dirMode = null;
|
|
4663
4868
|
try {
|
|
4664
|
-
const m =
|
|
4869
|
+
const m = statSync6(dirname3(path)).mode & 511;
|
|
4665
4870
|
if ((m & DIR_WRITABLE_BY_OTHERS) !== 0)
|
|
4666
4871
|
dirMode = m;
|
|
4667
4872
|
} catch {}
|
|
@@ -5008,7 +5213,7 @@ async function evaluatePolicies(eventType, payload, session, config, twoTier) {
|
|
|
5008
5213
|
twoTier: {
|
|
5009
5214
|
activity: combined.activity,
|
|
5010
5215
|
decidedByJev: combined.decidedByJev,
|
|
5011
|
-
...combined.decidedByJev && review.kind === "answered" && review.origin ? { jevOrigin: review.origin } : {},
|
|
5216
|
+
...(combined.decidedByJev || combined.observeVerdict) && review.kind === "answered" && review.origin ? { jevOrigin: review.origin } : {},
|
|
5012
5217
|
...combined.observeVerdict ? { observeVerdict: combined.observeVerdict } : {}
|
|
5013
5218
|
}
|
|
5014
5219
|
};
|
|
@@ -6069,7 +6274,7 @@ async function loadSingleFile(absPath, opts) {
|
|
|
6069
6274
|
return null;
|
|
6070
6275
|
} catch (err) {
|
|
6071
6276
|
const msg = err instanceof Error ? err.message : String(err);
|
|
6072
|
-
const errorType = /Cannot find module|MODULE_NOT_FOUND|
|
|
6277
|
+
const errorType = /Cannot find module|MODULE_NOT_FOUND|Cannot find package/i.test(msg) ? "module_not_found" : /ENOENT/i.test(msg) ? "file_not_found" : /SyntaxError|Unexpected token/i.test(msg) ? "syntax_error" : /timed out loading module/i.test(msg) ? "load_timeout" : "runtime_error";
|
|
6073
6278
|
trackHookEvent(getInstanceId(), "custom_hooks_load_error", {
|
|
6074
6279
|
error_type: errorType,
|
|
6075
6280
|
is_convention: !!opts?.conventionScope,
|
|
@@ -6129,8 +6334,11 @@ async function loadAllCustomHooks(customPoliciesPaths, opts) {
|
|
|
6129
6334
|
const conventionEnabled = opts?.customPoliciesEnabled !== false;
|
|
6130
6335
|
const loadedPaths = new Set;
|
|
6131
6336
|
const cloudManagedByPath = new Map;
|
|
6337
|
+
const cloudIdsByPath = new Map;
|
|
6338
|
+
const cloudFailures = new Map;
|
|
6132
6339
|
for (const policy of opts?.cloudManagedPolicies ?? []) {
|
|
6133
6340
|
const key = resolve7(policy.path);
|
|
6341
|
+
cloudIdsByPath.set(key, [...cloudIdsByPath.get(key) ?? [], policy.id]);
|
|
6134
6342
|
const existing = cloudManagedByPath.get(key);
|
|
6135
6343
|
if (!existing) {
|
|
6136
6344
|
cloudManagedByPath.set(key, policy);
|
|
@@ -6211,6 +6419,10 @@ async function loadAllCustomHooks(customPoliciesPaths, opts) {
|
|
|
6211
6419
|
for (const id of packIdsByPath.get(absPath) ?? [pack.id])
|
|
6212
6420
|
packFailures.set(id, failure);
|
|
6213
6421
|
}
|
|
6422
|
+
if (failure && cloudManaged) {
|
|
6423
|
+
for (const id of cloudIdsByPath.get(absPath) ?? [cloudManaged.id])
|
|
6424
|
+
cloudFailures.set(id, failure);
|
|
6425
|
+
}
|
|
6214
6426
|
for (const hook of getCustomHooks().slice(hooksBefore)) {
|
|
6215
6427
|
const tagged = hook;
|
|
6216
6428
|
if (cloudManaged) {
|
|
@@ -6227,6 +6439,11 @@ async function loadAllCustomHooks(customPoliciesPaths, opts) {
|
|
|
6227
6439
|
}
|
|
6228
6440
|
} else {
|
|
6229
6441
|
hookLogWarn(`custom policy path not found: ${absPath}`);
|
|
6442
|
+
if (cloudManaged) {
|
|
6443
|
+
const missing = { type: "path_missing", reason: `path missing: ${absPath}` };
|
|
6444
|
+
for (const id of cloudIdsByPath.get(absPath) ?? [cloudManaged.id])
|
|
6445
|
+
cloudFailures.set(id, missing);
|
|
6446
|
+
}
|
|
6230
6447
|
if (pack) {
|
|
6231
6448
|
const missing = { type: "path_missing", reason: `path missing: ${absPath}` };
|
|
6232
6449
|
for (const id of packIdsByPath.get(absPath) ?? [pack.id])
|
|
@@ -6309,7 +6526,7 @@ async function loadAllCustomHooks(customPoliciesPaths, opts) {
|
|
|
6309
6526
|
if (winner && ids.length > 1)
|
|
6310
6527
|
packAliases.set(winner.id, ids);
|
|
6311
6528
|
}
|
|
6312
|
-
return { hooks: allHooks, conventionSources, packFailures, packAliases };
|
|
6529
|
+
return { hooks: allHooks, conventionSources, packFailures, packAliases, cloudFailures };
|
|
6313
6530
|
}
|
|
6314
6531
|
var LOADING_KEY = "__FAILPROOFAI_LOADING_HOOKS__", CONVENTION_FILE_RE, loadSequence = 0, policyModuleCache, POLICY_MODULE_CACHE_MAX_ENTRIES = 500, LOADABLE_EXT_RE, warnedSemanticOutsidePack;
|
|
6315
6532
|
var init_custom_hooks_loader = __esm(() => {
|
|
@@ -6337,7 +6554,7 @@ import {
|
|
|
6337
6554
|
readdirSync as readdirSync2,
|
|
6338
6555
|
mkdirSync as mkdirSync5,
|
|
6339
6556
|
existsSync as existsSync9,
|
|
6340
|
-
statSync as
|
|
6557
|
+
statSync as statSync7,
|
|
6341
6558
|
unlinkSync
|
|
6342
6559
|
} from "node:fs";
|
|
6343
6560
|
import { join as join4 } from "node:path";
|
|
@@ -6358,7 +6575,7 @@ function acquireLock() {
|
|
|
6358
6575
|
if (e.code !== "EEXIST")
|
|
6359
6576
|
return;
|
|
6360
6577
|
try {
|
|
6361
|
-
const s =
|
|
6578
|
+
const s = statSync7(lockPath);
|
|
6362
6579
|
if (Date.now() - s.mtimeMs > LOCK_STALE_MS) {
|
|
6363
6580
|
writeFileSync4(lockPath, String(process.pid), "utf-8");
|
|
6364
6581
|
return;
|
|
@@ -7156,7 +7373,7 @@ var init_cursor_projects = __esm(() => {
|
|
|
7156
7373
|
});
|
|
7157
7374
|
|
|
7158
7375
|
// lib/sqlite-reader.ts
|
|
7159
|
-
import { existsSync as existsSync10, readFileSync as readFileSync6, statSync as
|
|
7376
|
+
import { existsSync as existsSync10, readFileSync as readFileSync6, statSync as statSync8 } from "node:fs";
|
|
7160
7377
|
import initSqlJs from "sql.js/dist/sql-asm.js";
|
|
7161
7378
|
async function tryNodeSqlite(dbPath) {
|
|
7162
7379
|
try {
|
|
@@ -7180,8 +7397,8 @@ function loadSqlJs() {
|
|
|
7180
7397
|
sqlPromise = initSqlJs();
|
|
7181
7398
|
return sqlPromise;
|
|
7182
7399
|
}
|
|
7183
|
-
function
|
|
7184
|
-
const stat =
|
|
7400
|
+
function fileVersion2(path) {
|
|
7401
|
+
const stat = statSync8(path);
|
|
7185
7402
|
return { size: stat.size, mtimeMs: stat.mtimeMs, ctimeMs: stat.ctimeMs };
|
|
7186
7403
|
}
|
|
7187
7404
|
function sameVersion(a, b) {
|
|
@@ -7268,9 +7485,9 @@ function applyCommittedWal(db, wal) {
|
|
|
7268
7485
|
function readPortableSnapshot(dbPath) {
|
|
7269
7486
|
const walPath = `${dbPath}-wal`;
|
|
7270
7487
|
for (let attempt = 0;attempt < 3; attempt += 1) {
|
|
7271
|
-
const before =
|
|
7488
|
+
const before = fileVersion2(dbPath);
|
|
7272
7489
|
const main = readFileSync6(dbPath);
|
|
7273
|
-
const afterMain =
|
|
7490
|
+
const afterMain = fileVersion2(dbPath);
|
|
7274
7491
|
if (!sameVersion(before, afterMain))
|
|
7275
7492
|
continue;
|
|
7276
7493
|
let wal = null;
|
|
@@ -7280,7 +7497,7 @@ function readPortableSnapshot(dbPath) {
|
|
|
7280
7497
|
if (error.code !== "ENOENT")
|
|
7281
7498
|
throw error;
|
|
7282
7499
|
}
|
|
7283
|
-
const afterWal =
|
|
7500
|
+
const afterWal = fileVersion2(dbPath);
|
|
7284
7501
|
if (!sameVersion(before, afterWal))
|
|
7285
7502
|
continue;
|
|
7286
7503
|
return wal ? applyCommittedWal(main, wal) : main;
|
|
@@ -8218,7 +8435,7 @@ var init_openclaw_db = __esm(() => {
|
|
|
8218
8435
|
|
|
8219
8436
|
// lib/openclaw-sessions.ts
|
|
8220
8437
|
import { readFile as readFile7 } from "node:fs/promises";
|
|
8221
|
-
import { readdirSync as readdirSync4, statSync as
|
|
8438
|
+
import { readdirSync as readdirSync4, statSync as statSync9 } from "node:fs";
|
|
8222
8439
|
import { homedir as homedir11 } from "node:os";
|
|
8223
8440
|
import { join as join14 } from "node:path";
|
|
8224
8441
|
function openclawHome() {
|
|
@@ -8371,7 +8588,7 @@ function listOpenClawTranscripts() {
|
|
|
8371
8588
|
continue;
|
|
8372
8589
|
const transcriptPath = join14(sessionsDir, file);
|
|
8373
8590
|
try {
|
|
8374
|
-
const st =
|
|
8591
|
+
const st = statSync9(transcriptPath);
|
|
8375
8592
|
out.push({
|
|
8376
8593
|
agentId,
|
|
8377
8594
|
sessionId,
|
|
@@ -8614,7 +8831,7 @@ var init_openclaw_projects = __esm(() => {
|
|
|
8614
8831
|
|
|
8615
8832
|
// lib/factory-sessions.ts
|
|
8616
8833
|
import { readFile as readFile8 } from "node:fs/promises";
|
|
8617
|
-
import { readdirSync as readdirSync5, statSync as
|
|
8834
|
+
import { readdirSync as readdirSync5, statSync as statSync10 } from "node:fs";
|
|
8618
8835
|
import { homedir as homedir12 } from "node:os";
|
|
8619
8836
|
import { join as join16 } from "node:path";
|
|
8620
8837
|
function factoryHome() {
|
|
@@ -8782,7 +8999,7 @@ function listFactoryTranscripts() {
|
|
|
8782
8999
|
continue;
|
|
8783
9000
|
const transcriptPath = join16(projectPath, file);
|
|
8784
9001
|
try {
|
|
8785
|
-
const st =
|
|
9002
|
+
const st = statSync10(transcriptPath);
|
|
8786
9003
|
out.push({ projectName, cwd, sessionId, transcriptPath, mtimeMs: st.mtimeMs, sizeBytes: st.size });
|
|
8787
9004
|
} catch {}
|
|
8788
9005
|
}
|
|
@@ -9201,7 +9418,7 @@ var init_devin_projects = __esm(() => {
|
|
|
9201
9418
|
|
|
9202
9419
|
// lib/antigravity-sessions.ts
|
|
9203
9420
|
import { readFile as readFile9 } from "node:fs/promises";
|
|
9204
|
-
import { readdirSync as readdirSync6, statSync as
|
|
9421
|
+
import { readdirSync as readdirSync6, statSync as statSync11 } from "node:fs";
|
|
9205
9422
|
import { homedir as homedir14 } from "node:os";
|
|
9206
9423
|
import { join as join18 } from "node:path";
|
|
9207
9424
|
function antigravityHome() {
|
|
@@ -9336,7 +9553,7 @@ function listAntigravityTranscripts() {
|
|
|
9336
9553
|
continue;
|
|
9337
9554
|
const transcriptPath = join18(root, conversationId, rel);
|
|
9338
9555
|
try {
|
|
9339
|
-
const st =
|
|
9556
|
+
const st = statSync11(transcriptPath);
|
|
9340
9557
|
if (!st.isFile())
|
|
9341
9558
|
continue;
|
|
9342
9559
|
out.push({ conversationId, transcriptPath, mtimeMs: st.mtimeMs, sizeBytes: st.size });
|
|
@@ -9349,7 +9566,7 @@ function findAntigravityTranscript(conversationId) {
|
|
|
9349
9566
|
return null;
|
|
9350
9567
|
const transcriptPath = join18(antigravityBrainRoot(), conversationId, antigravityTranscriptRelPath());
|
|
9351
9568
|
try {
|
|
9352
|
-
if (
|
|
9569
|
+
if (statSync11(transcriptPath).isFile())
|
|
9353
9570
|
return transcriptPath;
|
|
9354
9571
|
} catch {}
|
|
9355
9572
|
return null;
|
|
@@ -10258,7 +10475,7 @@ var init_log_entries = __esm(() => {
|
|
|
10258
10475
|
});
|
|
10259
10476
|
|
|
10260
10477
|
// lib/codex-sessions.ts
|
|
10261
|
-
import { readFileSync as readFileSync8, readdirSync as readdirSync7, existsSync as existsSync13, writeFileSync as writeFileSync5, mkdirSync as mkdirSync6, statSync as
|
|
10478
|
+
import { readFileSync as readFileSync8, readdirSync as readdirSync7, existsSync as existsSync13, writeFileSync as writeFileSync5, mkdirSync as mkdirSync6, statSync as statSync12 } from "node:fs";
|
|
10262
10479
|
import { readFile as readFile11 } from "node:fs/promises";
|
|
10263
10480
|
import { dirname as dirname6, join as join24 } from "node:path";
|
|
10264
10481
|
import { homedir as homedir16 } from "node:os";
|
|
@@ -10586,7 +10803,7 @@ var init_resolve_permission_mode = __esm(() => {
|
|
|
10586
10803
|
});
|
|
10587
10804
|
|
|
10588
10805
|
// lib/copilot-sessions.ts
|
|
10589
|
-
import { readFileSync as readFileSync10, readdirSync as readdirSync8, existsSync as existsSync14, statSync as
|
|
10806
|
+
import { readFileSync as readFileSync10, readdirSync as readdirSync8, existsSync as existsSync14, statSync as statSync13 } from "node:fs";
|
|
10590
10807
|
import { readFile as readFile12 } from "node:fs/promises";
|
|
10591
10808
|
import { join as join25, resolve as resolve10, sep as sep2 } from "node:path";
|
|
10592
10809
|
import { homedir as homedir17 } from "node:os";
|
|
@@ -10803,7 +11020,7 @@ var init_copilot_sessions = __esm(() => {
|
|
|
10803
11020
|
});
|
|
10804
11021
|
|
|
10805
11022
|
// lib/cursor-sessions.ts
|
|
10806
|
-
import { readFileSync as readFileSync11, readdirSync as readdirSync9, existsSync as existsSync15, statSync as
|
|
11023
|
+
import { readFileSync as readFileSync11, readdirSync as readdirSync9, existsSync as existsSync15, statSync as statSync14 } from "node:fs";
|
|
10807
11024
|
import { readFile as readFile13 } from "node:fs/promises";
|
|
10808
11025
|
import { basename as basename3, join as join26, resolve as resolve11, sep as sep3 } from "node:path";
|
|
10809
11026
|
import { homedir as homedir18 } from "node:os";
|
|
@@ -11059,7 +11276,7 @@ var init_cursor_sessions = __esm(() => {
|
|
|
11059
11276
|
});
|
|
11060
11277
|
|
|
11061
11278
|
// lib/pi-sessions.ts
|
|
11062
|
-
import { readFileSync as readFileSync12, readdirSync as readdirSync10, existsSync as existsSync16, statSync as
|
|
11279
|
+
import { readFileSync as readFileSync12, readdirSync as readdirSync10, existsSync as existsSync16, statSync as statSync15 } from "node:fs";
|
|
11063
11280
|
import { readFile as readFile14 } from "node:fs/promises";
|
|
11064
11281
|
import { join as join27, resolve as resolve12, sep as sep4 } from "node:path";
|
|
11065
11282
|
import { homedir as homedir19 } from "node:os";
|
|
@@ -11320,6 +11537,238 @@ var init_resolve_transcript_path = __esm(() => {
|
|
|
11320
11537
|
init_factory_sessions();
|
|
11321
11538
|
init_antigravity_sessions();
|
|
11322
11539
|
});
|
|
11540
|
+
// src/hooks/cloud-policy-errors.ts
|
|
11541
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
11542
|
+
import { chmodSync as chmodSync3, existsSync as existsSync17, readFileSync as readFileSync13, renameSync as renameSync4, rmSync as rmSync3, writeFileSync as writeFileSync6 } from "node:fs";
|
|
11543
|
+
import { homedir as homedir20 } from "node:os";
|
|
11544
|
+
import { resolve as resolve13 } from "node:path";
|
|
11545
|
+
function isPackDropEntry(e) {
|
|
11546
|
+
return e.id.startsWith("pack:") && (e.message.startsWith(JEV_BUDGET) || e.message.startsWith(JEV_NAME_CLASH));
|
|
11547
|
+
}
|
|
11548
|
+
function redactLocalPaths(message, home = safeHomedir()) {
|
|
11549
|
+
let text = message;
|
|
11550
|
+
const base = home?.replace(/\/+$/, "") ?? "";
|
|
11551
|
+
if (base.length > 1) {
|
|
11552
|
+
let out = "";
|
|
11553
|
+
let rest = text;
|
|
11554
|
+
for (let at = rest.indexOf(base);at >= 0; at = rest.indexOf(base)) {
|
|
11555
|
+
const next = rest.charAt(at + base.length);
|
|
11556
|
+
const whole = next === "" || next === "/" || next === ":" || PATH_END.test(next);
|
|
11557
|
+
out += rest.slice(0, at) + (whole ? "~" : base);
|
|
11558
|
+
rest = rest.slice(at + base.length);
|
|
11559
|
+
}
|
|
11560
|
+
text = out + rest;
|
|
11561
|
+
}
|
|
11562
|
+
return text.replace(/(^|[\s"'`(\[<{=,]|:(?!\/\/(?!\/)))(\/[^\s"'`)\]>},;]*)/g, (_m, lead, path) => {
|
|
11563
|
+
const last = path.replace(/\/+$/, "").split("/").pop() ?? "";
|
|
11564
|
+
return lead + (last === "" ? "/" : last);
|
|
11565
|
+
});
|
|
11566
|
+
}
|
|
11567
|
+
function safeHomedir() {
|
|
11568
|
+
try {
|
|
11569
|
+
return homedir20();
|
|
11570
|
+
} catch {
|
|
11571
|
+
return null;
|
|
11572
|
+
}
|
|
11573
|
+
}
|
|
11574
|
+
function cloudPolicyErrorsPath() {
|
|
11575
|
+
return resolve13(cloudManagedPolicyRoot(), CLOUD_POLICY_ERRORS_FILE);
|
|
11576
|
+
}
|
|
11577
|
+
function readCloudPolicyErrors() {
|
|
11578
|
+
try {
|
|
11579
|
+
const raw = JSON.parse(readFileSync13(cloudPolicyErrorsPath(), "utf8"));
|
|
11580
|
+
if (!Array.isArray(raw.errors))
|
|
11581
|
+
return null;
|
|
11582
|
+
return raw.errors.filter((e) => !!e && typeof e === "object" && typeof e.id === "string" && typeof e.message === "string" && KINDS.has(e.kind) && (e.version === null || Number.isSafeInteger(e.version)));
|
|
11583
|
+
} catch {
|
|
11584
|
+
return null;
|
|
11585
|
+
}
|
|
11586
|
+
}
|
|
11587
|
+
function serialize(errors) {
|
|
11588
|
+
const list = errors.map((e) => ({ id: e.id, version: e.version, kind: e.kind, message: redactLocalPaths(e.message) }));
|
|
11589
|
+
return `${JSON.stringify({ errors: list }, null, 2)}
|
|
11590
|
+
`;
|
|
11591
|
+
}
|
|
11592
|
+
function writeCloudPolicyErrors(errors) {
|
|
11593
|
+
try {
|
|
11594
|
+
const root = cloudManagedPolicyRoot();
|
|
11595
|
+
if (!existsSync17(resolve13(root, "active.json")))
|
|
11596
|
+
return "skipped";
|
|
11597
|
+
const path = cloudPolicyErrorsPath();
|
|
11598
|
+
const text = serialize(errors);
|
|
11599
|
+
if (lastWritten && lastWritten.path === path && lastWritten.text === text && existsSync17(path))
|
|
11600
|
+
return "unchanged";
|
|
11601
|
+
let current = null;
|
|
11602
|
+
try {
|
|
11603
|
+
current = readFileSync13(path, "utf8");
|
|
11604
|
+
} catch {
|
|
11605
|
+
current = null;
|
|
11606
|
+
}
|
|
11607
|
+
if (current === text) {
|
|
11608
|
+
lastWritten = { path, text };
|
|
11609
|
+
return "unchanged";
|
|
11610
|
+
}
|
|
11611
|
+
if (current === null && errors.length === 0)
|
|
11612
|
+
return "skipped";
|
|
11613
|
+
writeAtomic(path, text);
|
|
11614
|
+
lastWritten = { path, text };
|
|
11615
|
+
return "written";
|
|
11616
|
+
} catch {
|
|
11617
|
+
return "failed";
|
|
11618
|
+
}
|
|
11619
|
+
}
|
|
11620
|
+
function cloudLoadCheckedPath() {
|
|
11621
|
+
return resolve13(cloudManagedPolicyRoot(), CLOUD_LOAD_CHECKED_FILE);
|
|
11622
|
+
}
|
|
11623
|
+
function readCloudLoadChecked() {
|
|
11624
|
+
try {
|
|
11625
|
+
const raw = JSON.parse(readFileSync13(cloudLoadCheckedPath(), "utf8"));
|
|
11626
|
+
if (!Number.isSafeInteger(raw.deployment) || !Array.isArray(raw.checked))
|
|
11627
|
+
return null;
|
|
11628
|
+
return { deployment: raw.deployment, checked: raw.checked.filter((c) => typeof c === "string") };
|
|
11629
|
+
} catch {
|
|
11630
|
+
return null;
|
|
11631
|
+
}
|
|
11632
|
+
}
|
|
11633
|
+
function recordCloudLoadChecked(deployment, policies) {
|
|
11634
|
+
try {
|
|
11635
|
+
if (!existsSync17(resolve13(cloudManagedPolicyRoot(), "active.json")))
|
|
11636
|
+
return;
|
|
11637
|
+
const path = cloudLoadCheckedPath();
|
|
11638
|
+
const prior = readCloudLoadChecked();
|
|
11639
|
+
const base = prior && prior.deployment === deployment ? prior.checked : [];
|
|
11640
|
+
const next = [...new Set([...base, ...policies.map((p) => `${p.id}@${p.version}`)])].sort();
|
|
11641
|
+
if (prior && prior.deployment === deployment && next.length === base.length)
|
|
11642
|
+
return;
|
|
11643
|
+
const text = `${JSON.stringify({ deployment, checked: next }, null, 2)}
|
|
11644
|
+
`;
|
|
11645
|
+
writeAtomic(path, text);
|
|
11646
|
+
} catch {}
|
|
11647
|
+
}
|
|
11648
|
+
function kindOf(policy) {
|
|
11649
|
+
return policy.authority === "reviewable" && (policy.reviewedBy?.length ?? 0) > 0 ? "both" : "regex";
|
|
11650
|
+
}
|
|
11651
|
+
function collectCloudPolicyErrors(input) {
|
|
11652
|
+
const out = [];
|
|
11653
|
+
if (input.manifestError) {
|
|
11654
|
+
out.push({ id: "active.json", version: null, kind: "daemon", message: `Cloud policies could not be loaded: ${input.manifestError}` });
|
|
11655
|
+
}
|
|
11656
|
+
if (input.agentScopeUnresolved) {
|
|
11657
|
+
out.push({
|
|
11658
|
+
id: "agentScope",
|
|
11659
|
+
version: null,
|
|
11660
|
+
kind: "daemon",
|
|
11661
|
+
message: "agent_scope_unresolved: this hook's agent profile is unknown; targeted Cloud policies did not match"
|
|
11662
|
+
});
|
|
11663
|
+
}
|
|
11664
|
+
for (const policy of input.jsPolicies) {
|
|
11665
|
+
const failure = input.jsFailures?.get(policy.id);
|
|
11666
|
+
if (failure) {
|
|
11667
|
+
out.push({ id: policy.id, version: policy.version, kind: kindOf(policy), message: `policy did not load (${failure.type}): ${failure.reason}` });
|
|
11668
|
+
}
|
|
11669
|
+
}
|
|
11670
|
+
out.push(...input.jev.errors);
|
|
11671
|
+
out.push(...input.budgetDrops ?? []);
|
|
11672
|
+
if (input.jevProblem) {
|
|
11673
|
+
out.push({ id: "jevMode", version: null, kind: "daemon", message: input.jevProblem });
|
|
11674
|
+
}
|
|
11675
|
+
out.push(...input.health ?? []);
|
|
11676
|
+
const seen = new Set;
|
|
11677
|
+
return out.map((e) => ({ ...e, message: redactLocalPaths(e.message) })).filter((e) => {
|
|
11678
|
+
const key = `${e.id}\x00${e.version}\x00${e.kind}\x00${e.message}`;
|
|
11679
|
+
if (seen.has(key))
|
|
11680
|
+
return false;
|
|
11681
|
+
seen.add(key);
|
|
11682
|
+
return true;
|
|
11683
|
+
});
|
|
11684
|
+
}
|
|
11685
|
+
function jevBudgetPath() {
|
|
11686
|
+
return resolve13(cloudManagedPolicyRoot(), JEV_BUDGET_FILE);
|
|
11687
|
+
}
|
|
11688
|
+
function readJevBudgetRecord() {
|
|
11689
|
+
try {
|
|
11690
|
+
const raw = JSON.parse(readFileSync13(jevBudgetPath(), "utf8"));
|
|
11691
|
+
if (typeof raw.machineId !== "string" || !(raw.deployment === null || Number.isSafeInteger(raw.deployment)) || raw.jevMode !== "observe" && raw.jevMode !== "enforce" || !Array.isArray(raw.dropped)) {
|
|
11692
|
+
return null;
|
|
11693
|
+
}
|
|
11694
|
+
const dropped = raw.dropped.filter((d) => !!d && typeof d.packId === "string" && typeof d.name === "string").map((d) => ({ packId: d.packId, name: d.name, ...d.clash === true ? { clash: true } : {} }));
|
|
11695
|
+
return { machineId: raw.machineId, deployment: raw.deployment, jevMode: raw.jevMode, dropped };
|
|
11696
|
+
} catch {
|
|
11697
|
+
return null;
|
|
11698
|
+
}
|
|
11699
|
+
}
|
|
11700
|
+
function budgetEntries(dropped) {
|
|
11701
|
+
return [...dropped].sort((a, b) => dropKey(a) < dropKey(b) ? -1 : dropKey(a) > dropKey(b) ? 1 : 0).map((d) => ({
|
|
11702
|
+
id: `pack:${d.packId}`,
|
|
11703
|
+
version: null,
|
|
11704
|
+
kind: "daemon",
|
|
11705
|
+
message: d.clash ? `${JEV_NAME_CLASH}: ${d.name} (the FailproofAI Cloud check is used)` : `${JEV_BUDGET}: dropped ${d.name}`
|
|
11706
|
+
}));
|
|
11707
|
+
}
|
|
11708
|
+
function installedPackIds() {
|
|
11709
|
+
try {
|
|
11710
|
+
const path = resolve13(packsRoot(), "installed.json");
|
|
11711
|
+
if (!existsSync17(path))
|
|
11712
|
+
return new Set;
|
|
11713
|
+
const raw = JSON.parse(readFileSync13(path, "utf8"));
|
|
11714
|
+
if (!Array.isArray(raw.packs))
|
|
11715
|
+
return null;
|
|
11716
|
+
return new Set(raw.packs.map((p) => p && typeof p === "object" ? p.id : null).filter((id) => typeof id === "string"));
|
|
11717
|
+
} catch {
|
|
11718
|
+
return null;
|
|
11719
|
+
}
|
|
11720
|
+
}
|
|
11721
|
+
function readJevBudgetDrops(key, installed = null) {
|
|
11722
|
+
const record = readJevBudgetRecord();
|
|
11723
|
+
if (!record || !sameKey(record, key))
|
|
11724
|
+
return [];
|
|
11725
|
+
return budgetEntries(installed ? record.dropped.filter((d) => installed.has(d.packId)) : record.dropped);
|
|
11726
|
+
}
|
|
11727
|
+
function recordJevBudgetDrops(key, drops) {
|
|
11728
|
+
try {
|
|
11729
|
+
if (drops.length === 0 || !existsSync17(resolve13(cloudManagedPolicyRoot(), "active.json")))
|
|
11730
|
+
return;
|
|
11731
|
+
const current = readJevBudgetRecord();
|
|
11732
|
+
const base = current && sameKey(current, key) ? current.dropped : [];
|
|
11733
|
+
const seen = new Set(base.map(dropKey));
|
|
11734
|
+
const added = [];
|
|
11735
|
+
for (const d of drops) {
|
|
11736
|
+
const id = dropKey(d);
|
|
11737
|
+
if (seen.has(id))
|
|
11738
|
+
continue;
|
|
11739
|
+
seen.add(id);
|
|
11740
|
+
added.push({ packId: d.packId, name: d.name, ...d.clash === true ? { clash: true } : {} });
|
|
11741
|
+
}
|
|
11742
|
+
if (current && sameKey(current, key) && added.length === 0)
|
|
11743
|
+
return;
|
|
11744
|
+
const record = { ...key, dropped: [...base, ...added] };
|
|
11745
|
+
writeAtomic(jevBudgetPath(), `${JSON.stringify(record, null, 2)}
|
|
11746
|
+
`);
|
|
11747
|
+
const report = (readCloudPolicyErrors() ?? []).filter((e) => !isPackDropEntry(e));
|
|
11748
|
+
writeCloudPolicyErrors([...report, ...budgetEntries(record.dropped)]);
|
|
11749
|
+
} catch {}
|
|
11750
|
+
}
|
|
11751
|
+
function writeAtomic(path, text) {
|
|
11752
|
+
const tmp = `${path}.tmp-${process.pid}-${randomUUID2()}`;
|
|
11753
|
+
try {
|
|
11754
|
+
writeFileSync6(tmp, text, { mode: 384, flag: "wx" });
|
|
11755
|
+
chmodSync3(tmp, 384);
|
|
11756
|
+
renameSync4(tmp, path);
|
|
11757
|
+
} catch (err) {
|
|
11758
|
+
try {
|
|
11759
|
+
rmSync3(tmp, { force: true });
|
|
11760
|
+
} catch {}
|
|
11761
|
+
throw err;
|
|
11762
|
+
}
|
|
11763
|
+
}
|
|
11764
|
+
var JEV_BUDGET = "jev_budget", JEV_NAME_CLASH = "jev_name_clash", PATH_END, KINDS, lastWritten = null, CLOUD_LOAD_CHECKED_FILE = "load-checked.json", sameKey = (a, b) => a.machineId === b.machineId && a.deployment === b.deployment && a.jevMode === b.jevMode, dropKey = (d) => `${d.packId}\x00${d.name}\x00${d.clash === true}`;
|
|
11765
|
+
var init_cloud_policy_errors = __esm(() => {
|
|
11766
|
+
init_cloud_managed_policies();
|
|
11767
|
+
init_pack_manifest();
|
|
11768
|
+
PATH_END = /[\s"'`)\]>},;]/;
|
|
11769
|
+
KINDS = new Set(["regex", "jev", "both", "daemon"]);
|
|
11770
|
+
});
|
|
11771
|
+
|
|
11323
11772
|
// src/hooks/pack-failclosed.ts
|
|
11324
11773
|
function declaredList(value) {
|
|
11325
11774
|
if (value === undefined || value === null)
|
|
@@ -11448,6 +11897,7 @@ var PERMANENT_LOAD_FAILURES;
|
|
|
11448
11897
|
var init_pack_failclosed = __esm(() => {
|
|
11449
11898
|
PERMANENT_LOAD_FAILURES = new Set([
|
|
11450
11899
|
"module_not_found",
|
|
11900
|
+
"file_not_found",
|
|
11451
11901
|
"syntax_error",
|
|
11452
11902
|
"runtime_error",
|
|
11453
11903
|
"path_missing"
|
|
@@ -11455,13 +11905,13 @@ var init_pack_failclosed = __esm(() => {
|
|
|
11455
11905
|
});
|
|
11456
11906
|
|
|
11457
11907
|
// src/hooks/session-pause.ts
|
|
11458
|
-
import { existsSync as
|
|
11908
|
+
import { existsSync as existsSync18, mkdirSync as mkdirSync7, readdirSync as readdirSync11, readFileSync as readFileSync14, rmSync as rmSync4 } from "node:fs";
|
|
11459
11909
|
import { createHash as createHash5 } from "node:crypto";
|
|
11460
|
-
import { join as join28, resolve as
|
|
11910
|
+
import { join as join28, resolve as resolve14 } from "node:path";
|
|
11461
11911
|
function pauseStateDir() {
|
|
11462
11912
|
const override = process.env.FAILPROOFAI_STATE_DIR;
|
|
11463
11913
|
if (override)
|
|
11464
|
-
return
|
|
11914
|
+
return resolve14(override, "sessions");
|
|
11465
11915
|
return sessionPauseDir();
|
|
11466
11916
|
}
|
|
11467
11917
|
function pauseFilePath(sessionId) {
|
|
@@ -11495,9 +11945,9 @@ function readActivePause(sessionId, now = Date.now()) {
|
|
|
11495
11945
|
return null;
|
|
11496
11946
|
try {
|
|
11497
11947
|
const path = pauseFilePath(sessionId);
|
|
11498
|
-
if (!
|
|
11948
|
+
if (!existsSync18(path))
|
|
11499
11949
|
return null;
|
|
11500
|
-
const stored = parseStored(JSON.parse(
|
|
11950
|
+
const stored = parseStored(JSON.parse(readFileSync14(path, "utf8")));
|
|
11501
11951
|
if (!stored)
|
|
11502
11952
|
return null;
|
|
11503
11953
|
if (stored.expiresAt <= now)
|
|
@@ -11517,6 +11967,12 @@ var init_session_pause = __esm(() => {
|
|
|
11517
11967
|
PAUSE_CEILING_MS = 8 * 60 * 60000;
|
|
11518
11968
|
});
|
|
11519
11969
|
|
|
11970
|
+
// src/hooks/health-probe.ts
|
|
11971
|
+
function isHealthProbe(eventType, parsed) {
|
|
11972
|
+
return eventType === "SessionStart" && parsed.source === HEALTH_PROBE_SOURCE && parsed.session_id === undefined;
|
|
11973
|
+
}
|
|
11974
|
+
var HEALTH_PROBE_SOURCE = "failproofai-health-probe";
|
|
11975
|
+
|
|
11520
11976
|
// src/hooks/daemon-download.ts
|
|
11521
11977
|
var init_daemon_download = __esm(() => {
|
|
11522
11978
|
init_package();
|
|
@@ -11536,15 +11992,15 @@ var init_daemon_service = __esm(() => {
|
|
|
11536
11992
|
// src/hooks/fp-reset.ts
|
|
11537
11993
|
import {
|
|
11538
11994
|
copyFileSync,
|
|
11539
|
-
existsSync as
|
|
11995
|
+
existsSync as existsSync19,
|
|
11540
11996
|
mkdirSync as mkdirSync8,
|
|
11541
|
-
readFileSync as
|
|
11997
|
+
readFileSync as readFileSync15,
|
|
11542
11998
|
readdirSync as readdirSync12,
|
|
11543
|
-
renameSync as
|
|
11544
|
-
rmSync as
|
|
11999
|
+
renameSync as renameSync5,
|
|
12000
|
+
rmSync as rmSync5,
|
|
11545
12001
|
rmdirSync,
|
|
11546
|
-
statSync as
|
|
11547
|
-
writeFileSync as
|
|
12002
|
+
statSync as statSync16,
|
|
12003
|
+
writeFileSync as writeFileSync7
|
|
11548
12004
|
} from "node:fs";
|
|
11549
12005
|
function layoutWarningForHook() {
|
|
11550
12006
|
const state = detectLayout();
|
|
@@ -11553,7 +12009,7 @@ function layoutWarningForHook() {
|
|
|
11553
12009
|
if (state.kind === "future") {
|
|
11554
12010
|
return `[failproofai] this directory was written by a newer version (layout ${state.found} vs ${LAYOUT_VERSION}) — policies are NOT being enforced. ` + `Upgrade failproofai.`;
|
|
11555
12011
|
}
|
|
11556
|
-
if (
|
|
12012
|
+
if (existsSync19(globalPolicyConfigFile()))
|
|
11557
12013
|
return null;
|
|
11558
12014
|
return `[failproofai] setup predates this version — global policies are NOT being enforced. ` + `Run \`failproofai config\` to re-create it.`;
|
|
11559
12015
|
}
|
|
@@ -11565,7 +12021,7 @@ var init_fp_reset = __esm(() => {
|
|
|
11565
12021
|
});
|
|
11566
12022
|
|
|
11567
12023
|
// src/hooks/untraced-note.ts
|
|
11568
|
-
import { existsSync as
|
|
12024
|
+
import { existsSync as existsSync20, readFileSync as readFileSync16 } from "node:fs";
|
|
11569
12025
|
import { join as join29 } from "node:path";
|
|
11570
12026
|
function untracedNotePath(home) {
|
|
11571
12027
|
return join29(stateDir(home), "untraced-notes.json");
|
|
@@ -11577,8 +12033,8 @@ function noteUntracedAgent(cli, sessionId, config) {
|
|
|
11577
12033
|
const key = `${cli}:${sessionId ?? "no-session"}`;
|
|
11578
12034
|
const path = untracedNotePath();
|
|
11579
12035
|
let seen = [];
|
|
11580
|
-
if (
|
|
11581
|
-
const parsed = JSON.parse(
|
|
12036
|
+
if (existsSync20(path)) {
|
|
12037
|
+
const parsed = JSON.parse(readFileSync16(path, "utf8"));
|
|
11582
12038
|
if (Array.isArray(parsed))
|
|
11583
12039
|
seen = parsed.filter((k) => typeof k === "string");
|
|
11584
12040
|
}
|
|
@@ -11599,12 +12055,142 @@ var init_untraced_note = __esm(() => {
|
|
|
11599
12055
|
init_hook_logger();
|
|
11600
12056
|
});
|
|
11601
12057
|
|
|
12058
|
+
// src/hooks/agent-roster.ts
|
|
12059
|
+
import { lstatSync, readFileSync as readFileSync17, statSync as statSync17 } from "node:fs";
|
|
12060
|
+
import { homedir as homedir21 } from "node:os";
|
|
12061
|
+
import { dirname as dirname7, resolve as resolve15 } from "node:path";
|
|
12062
|
+
function installedHookAt(path, cli) {
|
|
12063
|
+
try {
|
|
12064
|
+
const stat = statSync17(path);
|
|
12065
|
+
if (!stat.isFile() || stat.size > 131072)
|
|
12066
|
+
return false;
|
|
12067
|
+
const text = readFileSync17(path, "utf8");
|
|
12068
|
+
if (text.includes("failproofai"))
|
|
12069
|
+
return true;
|
|
12070
|
+
if (cli !== "pi")
|
|
12071
|
+
return false;
|
|
12072
|
+
const config = JSON.parse(text);
|
|
12073
|
+
if (!config || typeof config !== "object" || Array.isArray(config))
|
|
12074
|
+
return false;
|
|
12075
|
+
const packages = config.packages;
|
|
12076
|
+
return Array.isArray(packages) && packages.some((entry) => typeof entry === "string" && /(?:^|\/)pi-extension\/?$/.test(entry));
|
|
12077
|
+
} catch {
|
|
12078
|
+
return false;
|
|
12079
|
+
}
|
|
12080
|
+
}
|
|
12081
|
+
function runtimeAgentSettingsPath(cli, cwd, userHome = homedir21(), hookScope) {
|
|
12082
|
+
if (cli === "hermes") {
|
|
12083
|
+
if (hookScope && hookScope !== "user")
|
|
12084
|
+
return null;
|
|
12085
|
+
const home = process.env.HERMES_HOME;
|
|
12086
|
+
return resolve15(home?.trim() ? home : resolve15(userHome, ".hermes"), "config.yaml");
|
|
12087
|
+
}
|
|
12088
|
+
if (cli === "openclaw") {
|
|
12089
|
+
if (hookScope && hookScope !== "user")
|
|
12090
|
+
return null;
|
|
12091
|
+
const config = process.env.OPENCLAW_CONFIG_PATH;
|
|
12092
|
+
if (config?.trim())
|
|
12093
|
+
return resolve15(config);
|
|
12094
|
+
const state = process.env.OPENCLAW_STATE_DIR || process.env.OPENCLAW_HOME;
|
|
12095
|
+
return resolve15(state?.trim() ? state : resolve15(userHome, ".openclaw"), "openclaw.json");
|
|
12096
|
+
}
|
|
12097
|
+
const relative = USER_SETTINGS[cli];
|
|
12098
|
+
if (!relative)
|
|
12099
|
+
return null;
|
|
12100
|
+
const override = cli === "codex" ? process.env.CODEX_HOME : cli === "claude" ? process.env.CLAUDE_CONFIG_DIR : undefined;
|
|
12101
|
+
const user = resolve15(override?.trim() ? override : userHome, override?.trim() ? cli === "codex" ? "hooks.json" : "settings.json" : relative);
|
|
12102
|
+
if (hookScope === "user")
|
|
12103
|
+
return user;
|
|
12104
|
+
const scopeFiles = hookScope === "local" ? cli === "claude" ? [".claude/settings.local.json"] : [] : hookScope === "project" ? (PROJECT_SETTINGS[cli] ?? []).filter((name) => name !== ".claude/settings.local.json") : PROJECT_SETTINGS[cli] ?? [];
|
|
12105
|
+
const matches = new Set;
|
|
12106
|
+
if (hookScope === undefined && installedHookAt(user, cli))
|
|
12107
|
+
matches.add(user);
|
|
12108
|
+
let dir = resolve15(cwd ?? process.cwd());
|
|
12109
|
+
const userRoot = resolve15(userHome);
|
|
12110
|
+
for (let depth = 0;depth < 16 && dir !== userRoot; depth++) {
|
|
12111
|
+
for (const candidate of scopeFiles) {
|
|
12112
|
+
const path = resolve15(dir, candidate);
|
|
12113
|
+
if (installedHookAt(path, cli))
|
|
12114
|
+
matches.add(path);
|
|
12115
|
+
}
|
|
12116
|
+
const parent = dirname7(dir);
|
|
12117
|
+
if (parent === dir)
|
|
12118
|
+
break;
|
|
12119
|
+
dir = parent;
|
|
12120
|
+
}
|
|
12121
|
+
if (matches.size > 1)
|
|
12122
|
+
return null;
|
|
12123
|
+
if (hookScope === "project" || hookScope === "local")
|
|
12124
|
+
return matches.values().next().value ?? null;
|
|
12125
|
+
return matches.values().next().value ?? user;
|
|
12126
|
+
}
|
|
12127
|
+
function readRuntimeAgentIdentity(cli, settingsPath) {
|
|
12128
|
+
if (!settingsPath)
|
|
12129
|
+
return null;
|
|
12130
|
+
try {
|
|
12131
|
+
const path = agentRosterFile();
|
|
12132
|
+
const stat = lstatSync(path);
|
|
12133
|
+
if (!stat.isFile() || (stat.mode & 63) !== 0 || stat.size > MAX_ROSTER_BYTES)
|
|
12134
|
+
return null;
|
|
12135
|
+
const roster = JSON.parse(readFileSync17(path, "utf8"));
|
|
12136
|
+
if (!roster || typeof roster !== "object" || Array.isArray(roster))
|
|
12137
|
+
return null;
|
|
12138
|
+
const data = roster;
|
|
12139
|
+
if (data.schemaVersion !== 1 || !Array.isArray(data.agents) || data.agents.length > MAX_ROSTER_AGENTS)
|
|
12140
|
+
return null;
|
|
12141
|
+
const absolute = resolve15(settingsPath);
|
|
12142
|
+
const agent = data.agents.find((entry) => {
|
|
12143
|
+
if (!entry || typeof entry !== "object" || Array.isArray(entry))
|
|
12144
|
+
return false;
|
|
12145
|
+
const record = entry;
|
|
12146
|
+
return record.integration === cli && record.settingsPath === absolute && validAgentIdentity({ integration: record.integration, instanceId: record.instanceId });
|
|
12147
|
+
});
|
|
12148
|
+
const instanceId = agent?.instanceId;
|
|
12149
|
+
return validAgentIdentity({ integration: cli, instanceId }) ? { integration: cli, instanceId } : null;
|
|
12150
|
+
} catch {
|
|
12151
|
+
return null;
|
|
12152
|
+
}
|
|
12153
|
+
}
|
|
12154
|
+
var MAX_ROSTER_AGENTS = 256, MAX_ROSTER_BYTES = 4000000, USER_SETTINGS, PROJECT_SETTINGS;
|
|
12155
|
+
var init_agent_roster = __esm(() => {
|
|
12156
|
+
init_fp_home();
|
|
12157
|
+
init_agent_targets();
|
|
12158
|
+
USER_SETTINGS = {
|
|
12159
|
+
claude: ".claude/settings.json",
|
|
12160
|
+
codex: ".codex/hooks.json",
|
|
12161
|
+
copilot: ".copilot/hooks/failproofai.json",
|
|
12162
|
+
cursor: ".cursor/hooks.json",
|
|
12163
|
+
opencode: ".config/opencode/opencode.json",
|
|
12164
|
+
pi: ".pi/agent/settings.json",
|
|
12165
|
+
factory: ".factory/hooks.json",
|
|
12166
|
+
devin: ".config/devin/config.json",
|
|
12167
|
+
antigravity: ".gemini/config/hooks.json",
|
|
12168
|
+
goose: ".agents/plugins/failproofai/hooks/hooks.json"
|
|
12169
|
+
};
|
|
12170
|
+
PROJECT_SETTINGS = {
|
|
12171
|
+
claude: [".claude/settings.local.json", ".claude/settings.json"],
|
|
12172
|
+
codex: [".codex/hooks.json"],
|
|
12173
|
+
copilot: [".github/hooks/failproofai.json"],
|
|
12174
|
+
cursor: [".cursor/hooks.json"],
|
|
12175
|
+
opencode: [".opencode/opencode.json"],
|
|
12176
|
+
pi: [".pi/settings.json"],
|
|
12177
|
+
factory: [".factory/hooks.json"],
|
|
12178
|
+
devin: [".devin/config.json"],
|
|
12179
|
+
antigravity: [".agents/hooks.json"],
|
|
12180
|
+
goose: [".agents/plugins/failproofai/hooks/hooks.json"]
|
|
12181
|
+
};
|
|
12182
|
+
});
|
|
12183
|
+
|
|
11602
12184
|
// src/hooks/semantic/jev-config.ts
|
|
11603
|
-
import { closeSync as closeSync2, constants as fsConstants2, fstatSync as fstatSync2, openSync as openSync2, readSync as readSync2, statSync as
|
|
11604
|
-
import { dirname as
|
|
12185
|
+
import { closeSync as closeSync2, constants as fsConstants2, fstatSync as fstatSync2, openSync as openSync2, readSync as readSync2, statSync as statSync18 } from "node:fs";
|
|
12186
|
+
import { dirname as dirname8 } from "node:path";
|
|
11605
12187
|
function parseJevMode(raw) {
|
|
11606
12188
|
return raw === "off" || raw === "observe" || raw === "enforce" ? raw : null;
|
|
11607
12189
|
}
|
|
12190
|
+
function jevCloudBaseUrl(cloudBase) {
|
|
12191
|
+
const url = new URL(cloudBase);
|
|
12192
|
+
return `${url.origin}${url.pathname.replace(/\/+$/, "")}${JEV_CLOUD_BASE_PATH}`;
|
|
12193
|
+
}
|
|
11608
12194
|
function jevConfigPath() {
|
|
11609
12195
|
return jevConfigFile();
|
|
11610
12196
|
}
|
|
@@ -11746,7 +12332,12 @@ function validateJevConfig(raw, envKey, cloud) {
|
|
|
11746
12332
|
missingKey: true
|
|
11747
12333
|
};
|
|
11748
12334
|
}
|
|
11749
|
-
const cfg = {
|
|
12335
|
+
const cfg = {
|
|
12336
|
+
provider: kind,
|
|
12337
|
+
apiKey,
|
|
12338
|
+
mode: DEFAULT_JEV_MODE,
|
|
12339
|
+
timeoutMs: kind === JEV_CLOUD_PROVIDER ? CLOUD_JEV_TIMEOUT_MS : JEV_CONFIG_DEFAULT_TIMEOUT_MS
|
|
12340
|
+
};
|
|
11750
12341
|
if (o.baseUrl !== undefined) {
|
|
11751
12342
|
const r = validateBaseUrl(o.baseUrl);
|
|
11752
12343
|
if (!r.ok)
|
|
@@ -11832,7 +12423,7 @@ function looseConfigDirMode(path) {
|
|
|
11832
12423
|
if (!modesAreMeaningful())
|
|
11833
12424
|
return null;
|
|
11834
12425
|
try {
|
|
11835
|
-
const mode =
|
|
12426
|
+
const mode = statSync18(dirname8(path)).mode & 511;
|
|
11836
12427
|
return (mode & DIR_WRITABLE_BY_OTHERS2) !== 0 ? mode : null;
|
|
11837
12428
|
} catch {
|
|
11838
12429
|
return null;
|
|
@@ -11893,8 +12484,8 @@ function inspectJevConfig() {
|
|
|
11893
12484
|
path,
|
|
11894
12485
|
mode,
|
|
11895
12486
|
reason: "too-open",
|
|
11896
|
-
problem: `its directory ${
|
|
11897
|
-
fix: `chmod 700 ${
|
|
12487
|
+
problem: `its directory ${dirname8(path)} is ${dirMode.toString(8).padStart(4, "0")} — other users can write there, ` + `so they can put their own config in its place; it must be owner-only (chmod 700 ${dirname8(path)})`,
|
|
12488
|
+
fix: `chmod 700 ${dirname8(path)}`
|
|
11898
12489
|
};
|
|
11899
12490
|
}
|
|
11900
12491
|
if (st.size > MAX_CONFIG_BYTES)
|
|
@@ -11996,7 +12587,80 @@ function loadJevConfig() {
|
|
|
11996
12587
|
return null;
|
|
11997
12588
|
}
|
|
11998
12589
|
}
|
|
11999
|
-
|
|
12590
|
+
function loadJevConfigForCloudMode(mode) {
|
|
12591
|
+
if (mode === "off")
|
|
12592
|
+
return { config: null, machineId: null, problem: null };
|
|
12593
|
+
const key = `${mode}\x00${jevInputsVersion()}`;
|
|
12594
|
+
if (cloudModeMemo?.key === key)
|
|
12595
|
+
return cloudModeMemo.value;
|
|
12596
|
+
const value = computeCloudModeConfig(mode);
|
|
12597
|
+
cloudModeMemo = { key, value };
|
|
12598
|
+
return value;
|
|
12599
|
+
}
|
|
12600
|
+
function jevInputsVersion() {
|
|
12601
|
+
const credentials = credentialsFile();
|
|
12602
|
+
const config = configFile();
|
|
12603
|
+
return [
|
|
12604
|
+
process.platform,
|
|
12605
|
+
credentials,
|
|
12606
|
+
statVersion(credentials),
|
|
12607
|
+
statVersion(dirname8(credentials)),
|
|
12608
|
+
config,
|
|
12609
|
+
statVersion(config)
|
|
12610
|
+
].join("\x00");
|
|
12611
|
+
}
|
|
12612
|
+
function statVersion(path) {
|
|
12613
|
+
try {
|
|
12614
|
+
const st = statSync18(path, { bigint: true });
|
|
12615
|
+
return `${st.dev}:${st.ino}:${st.mode}:${st.size}:${st.mtimeNs}:${st.ctimeNs}`;
|
|
12616
|
+
} catch (err) {
|
|
12617
|
+
return `-${err.code ?? "error"}`;
|
|
12618
|
+
}
|
|
12619
|
+
}
|
|
12620
|
+
function computeCloudModeConfig(mode) {
|
|
12621
|
+
try {
|
|
12622
|
+
if (readConfig().collector.sessions !== true) {
|
|
12623
|
+
return { config: null, machineId: null, problem: TRANSCRIPTS_DISABLED_PROBLEM };
|
|
12624
|
+
}
|
|
12625
|
+
const credential = readJevCloudCredential();
|
|
12626
|
+
if (credential.status === "absent")
|
|
12627
|
+
return { config: null, machineId: null, problem: JEV_UNCONFIGURED_PROBLEM };
|
|
12628
|
+
if (credential.status === "refused") {
|
|
12629
|
+
return {
|
|
12630
|
+
config: null,
|
|
12631
|
+
machineId: null,
|
|
12632
|
+
problem: `${JEV_UNCONFIGURED_PROBLEM}: the FailproofAI Cloud Jev credential is refused — ${credential.problem}`
|
|
12633
|
+
};
|
|
12634
|
+
}
|
|
12635
|
+
const machineId = readCredentials().cloud?.machineId || null;
|
|
12636
|
+
if (!machineId) {
|
|
12637
|
+
return {
|
|
12638
|
+
config: null,
|
|
12639
|
+
machineId: null,
|
|
12640
|
+
problem: `${JEV_UNCONFIGURED_PROBLEM}: this machine has no FailproofAI Cloud machine id (no policy connection in credentials.json)`
|
|
12641
|
+
};
|
|
12642
|
+
}
|
|
12643
|
+
const raw = {
|
|
12644
|
+
provider: JEV_CLOUD_PROVIDER,
|
|
12645
|
+
baseUrl: jevCloudBaseUrl(cloudBaseFor(credential.credential)),
|
|
12646
|
+
mode,
|
|
12647
|
+
timeoutMs: CLOUD_JEV_TIMEOUT_MS
|
|
12648
|
+
};
|
|
12649
|
+
const r = validateJevConfig(raw, null, credential.credential);
|
|
12650
|
+
return r.ok ? { config: r.value, machineId, problem: null } : { config: null, machineId, problem: `${JEV_UNCONFIGURED_PROBLEM}: the FailproofAI Cloud Jev credential — ${r.problem}` };
|
|
12651
|
+
} catch (err) {
|
|
12652
|
+
return { config: null, machineId: null, problem: `${JEV_UNCONFIGURED_PROBLEM}: ${err instanceof Error ? err.message : String(err)}` };
|
|
12653
|
+
}
|
|
12654
|
+
}
|
|
12655
|
+
function cloudBaseFor(credential) {
|
|
12656
|
+
try {
|
|
12657
|
+
const cloud = readCredentials().cloud;
|
|
12658
|
+
if (cloud?.url && new URL(cloud.url).origin === new URL(credential.url).origin)
|
|
12659
|
+
return cloud.url;
|
|
12660
|
+
} catch {}
|
|
12661
|
+
return credential.url;
|
|
12662
|
+
}
|
|
12663
|
+
var DEFAULT_JEV_MODE = "enforce", JEV_PROVIDER_KINDS, JEV_CLOUD_PROVIDER = "failproofai", JEV_CLOUD_BASE_PATH = "/enforcement/v1/jev", JEV_API_KEY_ENV = "FAILPROOFAI_JEV_API_KEY", JEV_CONFIG_DEFAULT_TIMEOUT_MS = 3000, CLOUD_JEV_TIMEOUT_MS = 5000, MIN_JEV_TIMEOUT_MS = 100, MAX_JEV_TIMEOUT_MS = 1e4, JEV_CALIBRATED_FAMILY, MAX_CONFIG_BYTES, OPEN_FLAGS, VERSIONED_MODEL_RE, CLOUDFLARE_ACCOUNT_ID_RE, API_KEY_RE, MODEL_RE, LOOPBACK_HOSTS, CREDENTIAL_PARAM_PARTS, CREDENTIAL_PARAM_NAMES, QUOTABLE_PARAM_RE, CREDENTIAL_PREFIX_RE, KEY_STAND_IN = "supplied-by-the-environment", DIR_WRITABLE_BY_OTHERS2 = 18, KEY_LACKS_JEV_PROBLEM = "this machine is connected to FailproofAI Cloud, but no Jev key is stored for that connection (its key lacks jev:evaluate, or the connect could not confirm it)", JEV_UNCONFIGURED_PROBLEM = "jev_unconfigured", TRANSCRIPTS_DISABLED_PROBLEM = "transcripts_disabled", cloudModeMemo = null;
|
|
12000
12664
|
var init_jev_config = __esm(() => {
|
|
12001
12665
|
init_fp_config();
|
|
12002
12666
|
init_fp_home();
|
|
@@ -12015,10 +12679,127 @@ var init_jev_config = __esm(() => {
|
|
|
12015
12679
|
CREDENTIAL_PREFIX_RE = /^(?:(?:sk|rk)[-_]|gh[pousr]_|github_pat_|glpat-|xox[abprs]-|AKIA[0-9A-Z]{12}|AIza[0-9A-Za-z_-]{20}|hf_[A-Za-z0-9]{16}|vck_)/;
|
|
12016
12680
|
});
|
|
12017
12681
|
|
|
12682
|
+
// src/hooks/semantic/cloud-jev-health.ts
|
|
12683
|
+
function forScope(scope) {
|
|
12684
|
+
if (state.scope !== scope)
|
|
12685
|
+
state = fresh(scope);
|
|
12686
|
+
return state;
|
|
12687
|
+
}
|
|
12688
|
+
function cloudJevGate(scope, at = clock()) {
|
|
12689
|
+
const s = forScope(scope);
|
|
12690
|
+
if (s.openUntil === null)
|
|
12691
|
+
return { ask: true, probe: false };
|
|
12692
|
+
if (at < s.openUntil || s.probing)
|
|
12693
|
+
return { ask: false };
|
|
12694
|
+
s.probing = true;
|
|
12695
|
+
return { ask: true, probe: true };
|
|
12696
|
+
}
|
|
12697
|
+
function classifyCloudJevReview(review, opts = { reachedCloud: true }) {
|
|
12698
|
+
if (review.kind === "answered")
|
|
12699
|
+
return opts.reachedCloud ? "answered" : "neutral";
|
|
12700
|
+
if (review.kind !== "fallback")
|
|
12701
|
+
return "neutral";
|
|
12702
|
+
const code = review.reason;
|
|
12703
|
+
if (code === "http-429" || code === "rate-limited")
|
|
12704
|
+
return "rate-limited";
|
|
12705
|
+
if (FAILURES.has(code) || /^http-5\d\d$/.test(code))
|
|
12706
|
+
return "failed";
|
|
12707
|
+
return "neutral";
|
|
12708
|
+
}
|
|
12709
|
+
function recordCloudJevResult(scope, result, code, probe, at = clock()) {
|
|
12710
|
+
if (state.scope !== scope)
|
|
12711
|
+
return;
|
|
12712
|
+
const s = state;
|
|
12713
|
+
if (probe)
|
|
12714
|
+
s.probing = false;
|
|
12715
|
+
switch (result) {
|
|
12716
|
+
case "answered":
|
|
12717
|
+
s.failures = 0;
|
|
12718
|
+
s.lastFailure = null;
|
|
12719
|
+
s.openUntil = null;
|
|
12720
|
+
s.rateLimited = [];
|
|
12721
|
+
break;
|
|
12722
|
+
case "rate-limited":
|
|
12723
|
+
s.rateLimited.push(at);
|
|
12724
|
+
if (code === "http-429") {
|
|
12725
|
+
s.failures = 0;
|
|
12726
|
+
s.openUntil = null;
|
|
12727
|
+
}
|
|
12728
|
+
break;
|
|
12729
|
+
case "failed":
|
|
12730
|
+
s.failures += 1;
|
|
12731
|
+
s.lastFailure = code;
|
|
12732
|
+
if (probe || s.failures >= BREAKER_FAILURES)
|
|
12733
|
+
s.openUntil = at + BREAKER_OPEN_MS;
|
|
12734
|
+
break;
|
|
12735
|
+
case "neutral":
|
|
12736
|
+
break;
|
|
12737
|
+
}
|
|
12738
|
+
}
|
|
12739
|
+
function isCloudJevHealthMessage(message) {
|
|
12740
|
+
return message.startsWith(JEV_RATE_LIMITED) || message.startsWith(JEV_UNAVAILABLE);
|
|
12741
|
+
}
|
|
12742
|
+
function cloudJevHealthErrors(at = clock()) {
|
|
12743
|
+
const s = state;
|
|
12744
|
+
const out = [];
|
|
12745
|
+
s.rateLimited = s.rateLimited.filter((t) => at - t < RATE_LIMIT_WINDOW_MS);
|
|
12746
|
+
const n = s.rateLimited.length;
|
|
12747
|
+
if (n === 0) {
|
|
12748
|
+
s.reportedRate = null;
|
|
12749
|
+
} else {
|
|
12750
|
+
if (s.reportedRate === null || at - s.reportedRate.at >= REPORT_REFRESH_MS)
|
|
12751
|
+
s.reportedRate = { n, at };
|
|
12752
|
+
const minutes = Math.round(RATE_LIMIT_WINDOW_MS / 60000);
|
|
12753
|
+
const count = s.reportedRate.n;
|
|
12754
|
+
out.push({
|
|
12755
|
+
id: "jevMode",
|
|
12756
|
+
version: null,
|
|
12757
|
+
kind: "daemon",
|
|
12758
|
+
message: `${JEV_RATE_LIMITED}: ${count} call${count === 1 ? "" : "s"} fell back to regex in the last ${minutes} min`
|
|
12759
|
+
});
|
|
12760
|
+
}
|
|
12761
|
+
if (s.openUntil !== null) {
|
|
12762
|
+
out.push({
|
|
12763
|
+
id: "jevMode",
|
|
12764
|
+
version: null,
|
|
12765
|
+
kind: "daemon",
|
|
12766
|
+
message: `${JEV_UNAVAILABLE}: FailproofAI Cloud Jev failed ${BREAKER_FAILURES} or more calls in a row ` + `(last: ${s.lastFailure ?? "error"}), so tool calls skip it for ${BREAKER_OPEN_MS / 1000} s at a time ` + "and the regex decides alone"
|
|
12767
|
+
});
|
|
12768
|
+
}
|
|
12769
|
+
return out;
|
|
12770
|
+
}
|
|
12771
|
+
function reportCloudJevHealth(at = clock()) {
|
|
12772
|
+
try {
|
|
12773
|
+
const entries = cloudJevHealthErrors(at);
|
|
12774
|
+
const text = JSON.stringify(entries);
|
|
12775
|
+
if (text === state.lastReport)
|
|
12776
|
+
return;
|
|
12777
|
+
state.lastReport = text;
|
|
12778
|
+
const report = (readCloudPolicyErrors() ?? []).filter((e) => !(e.id === "jevMode" && isCloudJevHealthMessage(e.message)));
|
|
12779
|
+
writeCloudPolicyErrors([...report, ...entries]);
|
|
12780
|
+
} catch {}
|
|
12781
|
+
}
|
|
12782
|
+
var BREAKER_FAILURES = 3, BREAKER_OPEN_MS = 60000, RATE_LIMIT_WINDOW_MS, REPORT_REFRESH_MS = 30000, JEV_RATE_LIMITED = "jev_rate_limited", JEV_UNAVAILABLE = "jev_unavailable", BREAKER_SKIP_REASON = "unavailable", fresh = (scope) => ({
|
|
12783
|
+
scope,
|
|
12784
|
+
failures: 0,
|
|
12785
|
+
lastFailure: null,
|
|
12786
|
+
openUntil: null,
|
|
12787
|
+
probing: false,
|
|
12788
|
+
rateLimited: [],
|
|
12789
|
+
reportedRate: null,
|
|
12790
|
+
lastReport: "[]"
|
|
12791
|
+
}), state, clock = () => performance.now(), FAILURES;
|
|
12792
|
+
var init_cloud_jev_health = __esm(() => {
|
|
12793
|
+
init_cloud_policy_errors();
|
|
12794
|
+
RATE_LIMIT_WINDOW_MS = 10 * 60000;
|
|
12795
|
+
state = fresh("");
|
|
12796
|
+
FAILURES = new Set(["timeout", "network", "malformed", "model-mismatch", "upstream-error", "error"]);
|
|
12797
|
+
});
|
|
12798
|
+
|
|
12018
12799
|
// src/hooks/semantic/facts.ts
|
|
12019
|
-
import { existsSync as
|
|
12020
|
-
import { homedir as
|
|
12021
|
-
import { dirname as
|
|
12800
|
+
import { existsSync as existsSync21, readFileSync as readFileSync18, statSync as statSync19 } from "node:fs";
|
|
12801
|
+
import { homedir as homedir22 } from "node:os";
|
|
12802
|
+
import { dirname as dirname9, isAbsolute as isAbsolute3, resolve as resolve16 } from "node:path";
|
|
12022
12803
|
function classifyTool(toolName) {
|
|
12023
12804
|
if (SHELL_TOOLS.has(toolName))
|
|
12024
12805
|
return { toolClass: "shell", toolIsKnown: true };
|
|
@@ -12197,10 +12978,10 @@ function pathFact(token, base, projectRoot, home) {
|
|
|
12197
12978
|
const slash = t.lastIndexOf("/");
|
|
12198
12979
|
t = slash === -1 ? "." : slash === 0 ? "/" : t.slice(0, slash);
|
|
12199
12980
|
}
|
|
12200
|
-
const resolved = isAbsolute3(t) ?
|
|
12981
|
+
const resolved = isAbsolute3(t) ? resolve16(t) : resolve16(base, t);
|
|
12201
12982
|
return { asWritten: token, resolved, relation: relationOf(resolved, projectRoot, home) };
|
|
12202
12983
|
}
|
|
12203
|
-
function extractPaths(toolInput, cwd, projectRoot, scanned, home =
|
|
12984
|
+
function extractPaths(toolInput, cwd, projectRoot, scanned, home = homedir22()) {
|
|
12204
12985
|
const base0 = cwd ?? home;
|
|
12205
12986
|
const facts = [];
|
|
12206
12987
|
const seen = new Set;
|
|
@@ -12242,10 +13023,10 @@ function extractPaths(toolInput, cwd, projectRoot, scanned, home = homedir20())
|
|
|
12242
13023
|
function findGitDir(start) {
|
|
12243
13024
|
let dir = start;
|
|
12244
13025
|
for (let i = 0;i < 40; i++) {
|
|
12245
|
-
const candidate =
|
|
12246
|
-
if (
|
|
13026
|
+
const candidate = resolve16(dir, ".git");
|
|
13027
|
+
if (existsSync21(candidate))
|
|
12247
13028
|
return candidate;
|
|
12248
|
-
const parent =
|
|
13029
|
+
const parent = dirname9(dir);
|
|
12249
13030
|
if (parent === dir)
|
|
12250
13031
|
return null;
|
|
12251
13032
|
dir = parent;
|
|
@@ -12256,7 +13037,7 @@ function findProjectRoot(cwd) {
|
|
|
12256
13037
|
if (!cwd)
|
|
12257
13038
|
return null;
|
|
12258
13039
|
const gitDir = findGitDir(cwd);
|
|
12259
|
-
return gitDir ?
|
|
13040
|
+
return gitDir ? dirname9(gitDir) : cwd;
|
|
12260
13041
|
}
|
|
12261
13042
|
function readCurrentBranch(cwd) {
|
|
12262
13043
|
if (!cwd)
|
|
@@ -12265,15 +13046,15 @@ function readCurrentBranch(cwd) {
|
|
|
12265
13046
|
const gitPath = findGitDir(cwd);
|
|
12266
13047
|
if (!gitPath)
|
|
12267
13048
|
return null;
|
|
12268
|
-
let headFile =
|
|
12269
|
-
if (
|
|
12270
|
-
const pointer =
|
|
13049
|
+
let headFile = resolve16(gitPath, "HEAD");
|
|
13050
|
+
if (statSync19(gitPath).isFile()) {
|
|
13051
|
+
const pointer = readFileSync18(gitPath, "utf8").trim();
|
|
12271
13052
|
const m = /^gitdir:\s*(.+)$/.exec(pointer);
|
|
12272
13053
|
if (!m)
|
|
12273
13054
|
return null;
|
|
12274
|
-
headFile =
|
|
13055
|
+
headFile = resolve16(dirname9(gitPath), m[1], "HEAD");
|
|
12275
13056
|
}
|
|
12276
|
-
const head =
|
|
13057
|
+
const head = readFileSync18(headFile, "utf8").trim();
|
|
12277
13058
|
const ref = /^ref:\s*refs\/heads\/(.+)$/.exec(head);
|
|
12278
13059
|
return ref ? ref[1] : null;
|
|
12279
13060
|
} catch {
|
|
@@ -14815,31 +15596,31 @@ __export(exports_intent, {
|
|
|
14815
15596
|
readIntent: () => readIntent
|
|
14816
15597
|
});
|
|
14817
15598
|
import {
|
|
14818
|
-
chmodSync as
|
|
15599
|
+
chmodSync as chmodSync4,
|
|
14819
15600
|
closeSync as closeSync3,
|
|
14820
15601
|
mkdirSync as mkdirSync9,
|
|
14821
15602
|
openSync as openSync3,
|
|
14822
15603
|
readdirSync as readdirSync13,
|
|
14823
|
-
readFileSync as
|
|
15604
|
+
readFileSync as readFileSync19,
|
|
14824
15605
|
readSync as readSync3,
|
|
14825
|
-
renameSync as
|
|
14826
|
-
statSync as
|
|
15606
|
+
renameSync as renameSync6,
|
|
15607
|
+
statSync as statSync20,
|
|
14827
15608
|
unlinkSync as unlinkSync2,
|
|
14828
|
-
writeFileSync as
|
|
15609
|
+
writeFileSync as writeFileSync8
|
|
14829
15610
|
} from "node:fs";
|
|
14830
|
-
import { dirname as
|
|
15611
|
+
import { dirname as dirname10, resolve as resolve17 } from "node:path";
|
|
14831
15612
|
function modesAreMeaningful2() {
|
|
14832
15613
|
return process.platform !== "win32";
|
|
14833
15614
|
}
|
|
14834
15615
|
function storeDirChain() {
|
|
14835
|
-
const home =
|
|
15616
|
+
const home = resolve17(failproofaiHome());
|
|
14836
15617
|
const chain = [];
|
|
14837
15618
|
let dir = sessionsDir();
|
|
14838
15619
|
for (let i = 0;i < 8; i++) {
|
|
14839
15620
|
chain.push(dir);
|
|
14840
15621
|
if (dir === home)
|
|
14841
15622
|
break;
|
|
14842
|
-
const parent =
|
|
15623
|
+
const parent = dirname10(dir);
|
|
14843
15624
|
if (parent === dir)
|
|
14844
15625
|
break;
|
|
14845
15626
|
dir = parent;
|
|
@@ -14852,15 +15633,15 @@ function looseIntentStoreDir() {
|
|
|
14852
15633
|
for (const dir of storeDirChain()) {
|
|
14853
15634
|
let mode;
|
|
14854
15635
|
try {
|
|
14855
|
-
mode =
|
|
15636
|
+
mode = statSync20(dir).mode & 511;
|
|
14856
15637
|
} catch {
|
|
14857
15638
|
continue;
|
|
14858
15639
|
}
|
|
14859
15640
|
if ((mode & DIR_WRITABLE_BY_OTHERS3) === 0)
|
|
14860
15641
|
continue;
|
|
14861
15642
|
try {
|
|
14862
|
-
|
|
14863
|
-
if ((
|
|
15643
|
+
chmodSync4(dir, mode & ~DIR_WRITABLE_BY_OTHERS3);
|
|
15644
|
+
if ((statSync20(dir).mode & DIR_WRITABLE_BY_OTHERS3) !== 0)
|
|
14864
15645
|
return dir;
|
|
14865
15646
|
} catch {
|
|
14866
15647
|
return dir;
|
|
@@ -14870,7 +15651,7 @@ function looseIntentStoreDir() {
|
|
|
14870
15651
|
}
|
|
14871
15652
|
function readIntentFile(sessionId) {
|
|
14872
15653
|
try {
|
|
14873
|
-
const parsed = JSON.parse(
|
|
15654
|
+
const parsed = JSON.parse(readFileSync19(intentFile(sessionId), "utf8"));
|
|
14874
15655
|
return Array.isArray(parsed?.prompts) ? parsed : { prompts: [] };
|
|
14875
15656
|
} catch {
|
|
14876
15657
|
return { prompts: [] };
|
|
@@ -14887,8 +15668,8 @@ function appendPrompt(sessionId, entry) {
|
|
|
14887
15668
|
const target = intentFile(sessionId);
|
|
14888
15669
|
const isNew = !fileExists2(target);
|
|
14889
15670
|
const tmp = `${target}.${process.pid}.tmp`;
|
|
14890
|
-
|
|
14891
|
-
|
|
15671
|
+
writeFileSync8(tmp, JSON.stringify(file), { mode: 384 });
|
|
15672
|
+
renameSync6(tmp, target);
|
|
14892
15673
|
if (isNew)
|
|
14893
15674
|
pruneExpiredSessions(entry.at);
|
|
14894
15675
|
return true;
|
|
@@ -14898,7 +15679,7 @@ function appendPrompt(sessionId, entry) {
|
|
|
14898
15679
|
}
|
|
14899
15680
|
function fileExists2(path) {
|
|
14900
15681
|
try {
|
|
14901
|
-
|
|
15682
|
+
statSync20(path);
|
|
14902
15683
|
return true;
|
|
14903
15684
|
} catch {
|
|
14904
15685
|
return false;
|
|
@@ -14911,9 +15692,9 @@ function pruneExpiredSessions(now = Date.now()) {
|
|
|
14911
15692
|
for (const name of readdirSync13(dir)) {
|
|
14912
15693
|
if (!SESSION_FILE_RE3.test(name))
|
|
14913
15694
|
continue;
|
|
14914
|
-
const path =
|
|
15695
|
+
const path = resolve17(dir, name);
|
|
14915
15696
|
try {
|
|
14916
|
-
const st =
|
|
15697
|
+
const st = statSync20(path);
|
|
14917
15698
|
if (st.isFile() && now - st.mtimeMs > INTENT_MAX_AGE_MS) {
|
|
14918
15699
|
unlinkSync2(path);
|
|
14919
15700
|
removed++;
|
|
@@ -15222,7 +16003,7 @@ function visitLinesBackwards(transcriptPath, maxBytes, visit) {
|
|
|
15222
16003
|
return;
|
|
15223
16004
|
let fd;
|
|
15224
16005
|
try {
|
|
15225
|
-
const st =
|
|
16006
|
+
const st = statSync20(path);
|
|
15226
16007
|
if (!st.isFile() || st.size === 0)
|
|
15227
16008
|
return;
|
|
15228
16009
|
fd = openSync3(path, "r");
|
|
@@ -15295,7 +16076,7 @@ function readIntent(sessionId, now = Date.now()) {
|
|
|
15295
16076
|
const agent = latest && typeof latest.agent === "string" && latest.agent.length > 0 ? latest.agent : null;
|
|
15296
16077
|
return { userSaid: prompts.map((p) => p.text), agentLastMessage: agent };
|
|
15297
16078
|
}
|
|
15298
|
-
var MAX_RECORDED_PROMPTS = 5, INTENT_MAX_AGE_MS, MAX_CLOCK_SKEW_MS, SESSION_ID_RE2, sessionsDir = () =>
|
|
16079
|
+
var MAX_RECORDED_PROMPTS = 5, INTENT_MAX_AGE_MS, MAX_CLOCK_SKEW_MS, SESSION_ID_RE2, sessionsDir = () => resolve17(semanticDir(), "sessions"), intentFile = (sessionId) => resolve17(sessionsDir(), `${sessionId}.json`), DIR_WRITABLE_BY_OTHERS3 = 18, SESSION_FILE_RE3, NON_HUMAN_PREFIXES, CONTINUATION_PREFIX = "This session is being continued from a previous conversation", IDE_MACHINE_OPENERS, IDE_AMBIGUOUS_OPENERS, IDE_REQUEST_HEADINGS, obj = (v) => v && typeof v === "object" && !Array.isArray(v) ? v : undefined, CLAUDE_MACHINE_SOURCES, claudeMachineTurn = (payload) => typeof payload.source === "string" && CLAUDE_MACHINE_SOURCES.has(payload.source), piMachineTurn = (payload) => payload.input_source === "extension" || payload.source === "extension", openclawMachineRun = (payload) => {
|
|
15299
16080
|
const meta = obj(payload.openclaw);
|
|
15300
16081
|
if (!meta)
|
|
15301
16082
|
return false;
|
|
@@ -15485,6 +16266,10 @@ function normalizeNative(body, sentModel, opts) {
|
|
|
15485
16266
|
if (!body || typeof body !== "object" || Array.isArray(body))
|
|
15486
16267
|
throw new JevError("malformed", "Jev returned no object");
|
|
15487
16268
|
const b = body;
|
|
16269
|
+
const cloud = opts.cloudReply && b.cloud !== undefined ? { cloud: b.cloud } : {};
|
|
16270
|
+
if ((typeof b.answers !== "object" || b.answers === null) && "cloud" in cloud && b.error === undefined) {
|
|
16271
|
+
return { model: typeof b.model === "string" ? scrubSecret(b.model, opts.apiKey) : "", answers: {}, ...cloud };
|
|
16272
|
+
}
|
|
15488
16273
|
if (typeof b.answers !== "object" || b.answers === null) {
|
|
15489
16274
|
if (b.error !== undefined) {
|
|
15490
16275
|
const code = typeof b.error === "object" && b.error !== null ? b.error.code : undefined;
|
|
@@ -15512,7 +16297,8 @@ function normalizeNative(body, sentModel, opts) {
|
|
|
15512
16297
|
model,
|
|
15513
16298
|
answers: b.answers,
|
|
15514
16299
|
...usage ? { usage } : {},
|
|
15515
|
-
...unverified ? { modelUnverified: true } : {}
|
|
16300
|
+
...unverified ? { modelUnverified: true } : {},
|
|
16301
|
+
...cloud
|
|
15516
16302
|
};
|
|
15517
16303
|
}
|
|
15518
16304
|
function nativeTransport(opts) {
|
|
@@ -15710,7 +16496,8 @@ function transportForConfig(input) {
|
|
|
15710
16496
|
apiKey: cfg.apiKey,
|
|
15711
16497
|
model: route.model,
|
|
15712
16498
|
allowUnreported: false,
|
|
15713
|
-
derivedBase: true
|
|
16499
|
+
derivedBase: true,
|
|
16500
|
+
cloudReply: true
|
|
15714
16501
|
})),
|
|
15715
16502
|
via: "failproofai",
|
|
15716
16503
|
model: route.model
|
|
@@ -15880,8 +16667,8 @@ var init_pack_policies = __esm(() => {
|
|
|
15880
16667
|
|
|
15881
16668
|
// src/hooks/semantic/evaluator.ts
|
|
15882
16669
|
import { createHash as createHash6 } from "node:crypto";
|
|
15883
|
-
import { appendFileSync as appendFileSync3, mkdirSync as mkdirSync10, renameSync as
|
|
15884
|
-
import { resolve as
|
|
16670
|
+
import { appendFileSync as appendFileSync3, mkdirSync as mkdirSync10, renameSync as renameSync7, statSync as statSync21 } from "node:fs";
|
|
16671
|
+
import { resolve as resolve18 } from "node:path";
|
|
15885
16672
|
function storeCut(message) {
|
|
15886
16673
|
return typeof message === "string" && message.length >= MAX_USER_MESSAGE_CHARS - STORE_CUT_SLACK && OMISSION_MARK.test(message);
|
|
15887
16674
|
}
|
|
@@ -16054,14 +16841,14 @@ function appendVerdictLog(row) {
|
|
|
16054
16841
|
const file = verdictLogFile();
|
|
16055
16842
|
mkdirSync10(semanticDir(), { recursive: true, mode: 448 });
|
|
16056
16843
|
try {
|
|
16057
|
-
if (
|
|
16058
|
-
|
|
16844
|
+
if (statSync21(file).size > VERDICT_LOG_MAX_BYTES)
|
|
16845
|
+
renameSync7(file, `${file}.1`);
|
|
16059
16846
|
} catch {}
|
|
16060
16847
|
appendFileSync3(file, JSON.stringify(row) + `
|
|
16061
16848
|
`, { mode: 384 });
|
|
16062
16849
|
} catch {}
|
|
16063
16850
|
}
|
|
16064
|
-
var DEFAULT_JEV_TIMEOUT_MS = 3000, OMISSION_MARK, STORE_CUT_SLACK = 64, VERDICT_LOG_MAX_BYTES, verdictLogFile = () =>
|
|
16851
|
+
var DEFAULT_JEV_TIMEOUT_MS = 3000, OMISSION_MARK, STORE_CUT_SLACK = 64, VERDICT_LOG_MAX_BYTES, verdictLogFile = () => resolve18(semanticDir(), "verdicts.jsonl");
|
|
16065
16852
|
var init_evaluator = __esm(() => {
|
|
16066
16853
|
init_fp_home();
|
|
16067
16854
|
init_compile();
|
|
@@ -16075,6 +16862,387 @@ var init_evaluator = __esm(() => {
|
|
|
16075
16862
|
VERDICT_LOG_MAX_BYTES = 5 * 1024 * 1024;
|
|
16076
16863
|
});
|
|
16077
16864
|
|
|
16865
|
+
// src/hooks/semantic/cloud-jev.ts
|
|
16866
|
+
function noul2(probe) {
|
|
16867
|
+
return {
|
|
16868
|
+
type: "noul",
|
|
16869
|
+
instructions: probe.instructions,
|
|
16870
|
+
...probe.criteria ? { criteria: { ...probe.criteria } } : {}
|
|
16871
|
+
};
|
|
16872
|
+
}
|
|
16873
|
+
function cloudGlobalQuestions(intent, userSaidCount) {
|
|
16874
|
+
const questions = { [INJECTION_PROBE.id]: noul2(INJECTION_PROBE) };
|
|
16875
|
+
if (userSaidCount > 0) {
|
|
16876
|
+
if (intent === "v1")
|
|
16877
|
+
for (const probe of TASK_PROBES)
|
|
16878
|
+
questions[probe.id] = noul2(probe);
|
|
16879
|
+
else
|
|
16880
|
+
questions[SCOPE_PROBE.id] = noul2(SCOPE_PROBE);
|
|
16881
|
+
}
|
|
16882
|
+
return questions;
|
|
16883
|
+
}
|
|
16884
|
+
function secretWords(toolInput) {
|
|
16885
|
+
const text = (typeof toolInput.command === "string" ? toolInput.command : Object.entries(toolInput).filter(([key, v]) => typeof v === "string" && v.length <= 300 && !/content|old_string|new_string|body|text|prompt/i.test(key)).map(([, v]) => v).join(`
|
|
16886
|
+
`)).slice(0, MAX_SECRET_SCAN_CHARS);
|
|
16887
|
+
try {
|
|
16888
|
+
return redactSecretsDetailed(text, { blunt: false }).found.map((s) => s.toLowerCase()).filter((s) => s.length > 0);
|
|
16889
|
+
} catch {
|
|
16890
|
+
return [];
|
|
16891
|
+
}
|
|
16892
|
+
}
|
|
16893
|
+
function cloudTargetScan(toolInput, scan = scanTargets(toolInput)) {
|
|
16894
|
+
const secrets = scan.groups.length > 0 ? secretWords(toolInput) : [];
|
|
16895
|
+
const hidden = (word) => secrets.some((s) => s === word || word.length >= 8 && s.includes(word) || s.length >= 8 && word.includes(s));
|
|
16896
|
+
const groups = [];
|
|
16897
|
+
let chars = 2;
|
|
16898
|
+
let complete = scan.complete;
|
|
16899
|
+
for (const group of scan.groups) {
|
|
16900
|
+
const words = [...new Set([...group].map((w) => hidden(w) ? REDACTED_TARGET_WORD : w))].sort();
|
|
16901
|
+
const cost = JSON.stringify(words).length + 1;
|
|
16902
|
+
if (chars + cost > MAX_TARGET_SCAN_CHARS) {
|
|
16903
|
+
complete = false;
|
|
16904
|
+
break;
|
|
16905
|
+
}
|
|
16906
|
+
chars += cost;
|
|
16907
|
+
groups.push(words);
|
|
16908
|
+
}
|
|
16909
|
+
return { groups, complete };
|
|
16910
|
+
}
|
|
16911
|
+
function cloudFacts(facts) {
|
|
16912
|
+
const scrub = (s) => s === null ? null : redactSecrets(s, { blunt: false }).text;
|
|
16913
|
+
return {
|
|
16914
|
+
toolName: facts.toolName,
|
|
16915
|
+
toolClass: facts.toolClass,
|
|
16916
|
+
toolIsKnown: facts.toolIsKnown,
|
|
16917
|
+
cwd: scrub(facts.cwd),
|
|
16918
|
+
projectRoot: scrub(facts.projectRoot),
|
|
16919
|
+
currentGitBranch: scrub(facts.currentGitBranch),
|
|
16920
|
+
paths: facts.paths.map((p) => ({ asWritten: scrub(p.asWritten) ?? "", resolved: scrub(p.resolved) ?? "", relation: p.relation })),
|
|
16921
|
+
permissionMode: facts.permissionMode
|
|
16922
|
+
};
|
|
16923
|
+
}
|
|
16924
|
+
function buildCloudBlock(prepared, input, machineId, agent) {
|
|
16925
|
+
const scan = scanTargets(input.toolInput);
|
|
16926
|
+
const block = {
|
|
16927
|
+
v: agent === undefined ? CLOUD_BLOCK_VERSION : 2,
|
|
16928
|
+
machineId,
|
|
16929
|
+
...agent ? { agent } : {},
|
|
16930
|
+
intentMode: prepared.intent,
|
|
16931
|
+
facts: cloudFacts(prepared.facts),
|
|
16932
|
+
targetScan: cloudTargetScan(input.toolInput, scan),
|
|
16933
|
+
userSaid: prepared.userSaid.map((turn) => redactSecrets(turn, { blunt: true }).text.replace(REDACTION_MARKER, REDACTED_SAID)),
|
|
16934
|
+
agentLastMessage: prepared.agentLastMessage,
|
|
16935
|
+
userSaidCut: prepared.userSaidCut,
|
|
16936
|
+
localPolicies: prepared.selected.map((p) => p.name)
|
|
16937
|
+
};
|
|
16938
|
+
if (blockBytes(block) > MAX_CLOUD_BLOCK_BYTES) {
|
|
16939
|
+
block.userSaid = prepared.userSaid.length > 0 ? [""] : [];
|
|
16940
|
+
block.userSaidCut = false;
|
|
16941
|
+
block.targetScan = { ...block.targetScan, complete: false };
|
|
16942
|
+
}
|
|
16943
|
+
if (blockBytes(block) > MAX_CLOUD_BLOCK_BYTES) {
|
|
16944
|
+
block.targetScan = { groups: [], complete: false };
|
|
16945
|
+
}
|
|
16946
|
+
if (block.targetScan.complete && namingReadings(block.intentMode, scan.groups, prepared.userSaid, prepared.agentLastMessage) !== namingReadings(block.intentMode, block.targetScan.groups.map((g) => new Set(g)), block.userSaid, block.agentLastMessage)) {
|
|
16947
|
+
block.targetScan = { ...block.targetScan, complete: false };
|
|
16948
|
+
}
|
|
16949
|
+
return block;
|
|
16950
|
+
}
|
|
16951
|
+
function namingReadings(intent, groups, userSaid, agentLastMessage) {
|
|
16952
|
+
const scan = { targets: new Set, groups, complete: true };
|
|
16953
|
+
const said = intent === "v1" && agentLastMessage ? [...userSaid, agentLastMessage] : userSaid;
|
|
16954
|
+
return [groups.length, userSaid.length > 0, everyTargetNamed(scan, said), intent === "v1" && partlyNamed(scan, said)].join();
|
|
16955
|
+
}
|
|
16956
|
+
function buildCloudRequest(prepared, input, machineId, agent) {
|
|
16957
|
+
const own = prepared.compiled.request;
|
|
16958
|
+
return {
|
|
16959
|
+
model: own.model,
|
|
16960
|
+
state: own.state,
|
|
16961
|
+
questions: { ...own.questions, ...cloudGlobalQuestions(prepared.intent, prepared.userSaid.length) },
|
|
16962
|
+
cloud: buildCloudBlock(prepared, input, machineId, agent)
|
|
16963
|
+
};
|
|
16964
|
+
}
|
|
16965
|
+
function malformed(what) {
|
|
16966
|
+
throw new JevError("malformed", `FailproofAI Cloud's reply: ${what}`);
|
|
16967
|
+
}
|
|
16968
|
+
function nullableProbability(v, what) {
|
|
16969
|
+
if (v === null || v === undefined)
|
|
16970
|
+
return null;
|
|
16971
|
+
if (!isProbability(v))
|
|
16972
|
+
malformed(`${what} is not a probability`);
|
|
16973
|
+
return v;
|
|
16974
|
+
}
|
|
16975
|
+
function names(v, what) {
|
|
16976
|
+
if (v === undefined || v === null)
|
|
16977
|
+
return [];
|
|
16978
|
+
if (!Array.isArray(v) || v.length > MAX_LIST || !v.every(isName2))
|
|
16979
|
+
malformed(`${what} is not a list of names`);
|
|
16980
|
+
return [...v];
|
|
16981
|
+
}
|
|
16982
|
+
function parseOutcome(raw, i) {
|
|
16983
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw))
|
|
16984
|
+
malformed(`outcome ${i} is not an object`);
|
|
16985
|
+
const o = raw;
|
|
16986
|
+
if (!isName2(o.policy))
|
|
16987
|
+
malformed(`outcome ${i} has no policy name`);
|
|
16988
|
+
if (o.mode !== "deny" && o.mode !== "instruct")
|
|
16989
|
+
malformed(`outcome ${i} has no mode`);
|
|
16990
|
+
if (!isProbability(o.evidence))
|
|
16991
|
+
malformed(`outcome ${i} has no evidence`);
|
|
16992
|
+
if (typeof o.targetNamedByUser !== "boolean" || typeof o.escalatedByInjection !== "boolean") {
|
|
16993
|
+
malformed(`outcome ${i} is missing a flag`);
|
|
16994
|
+
}
|
|
16995
|
+
if (typeof o.verdict !== "string" || !VERDICTS.has(o.verdict))
|
|
16996
|
+
malformed(`outcome ${i} has no verdict`);
|
|
16997
|
+
if (o.intent !== undefined && (typeof o.intent !== "string" || !INTENTS.has(o.intent)))
|
|
16998
|
+
malformed(`outcome ${i} has an unknown intent`);
|
|
16999
|
+
if (o.targetScanIncomplete !== undefined && o.targetScanIncomplete !== true)
|
|
17000
|
+
malformed(`outcome ${i} has a bad targetScanIncomplete`);
|
|
17001
|
+
if (o.userCanOverride !== undefined && typeof o.userCanOverride !== "boolean")
|
|
17002
|
+
malformed(`outcome ${i} has a bad userCanOverride`);
|
|
17003
|
+
const origin = o.origin;
|
|
17004
|
+
if (!origin || typeof origin !== "object" || typeof origin.cloudPolicyId !== "string" || !POLICY_ID_RE2.test(origin.cloudPolicyId) || !Number.isSafeInteger(origin.cloudVersion) || origin.cloudVersion < 0) {
|
|
17005
|
+
malformed(`outcome ${i} has no Cloud origin`);
|
|
17006
|
+
}
|
|
17007
|
+
return {
|
|
17008
|
+
policy: o.policy,
|
|
17009
|
+
mode: o.mode,
|
|
17010
|
+
...typeof o.userCanOverride === "boolean" ? { userCanOverride: o.userCanOverride } : {},
|
|
17011
|
+
origin: { packId: `cloud:${origin.cloudPolicyId}`, packVersion: String(origin.cloudVersion) },
|
|
17012
|
+
evidence: o.evidence,
|
|
17013
|
+
exempt: nullableProbability(o.exempt, `outcome ${i} exempt`),
|
|
17014
|
+
userAsked: nullableProbability(o.userAsked, `outcome ${i} userAsked`),
|
|
17015
|
+
targetNamedByUser: o.targetNamedByUser,
|
|
17016
|
+
escalatedByInjection: o.escalatedByInjection,
|
|
17017
|
+
verdict: o.verdict,
|
|
17018
|
+
...o.intent !== undefined ? { intent: o.intent } : {},
|
|
17019
|
+
...o.targetScanIncomplete === true ? { targetScanIncomplete: true } : {}
|
|
17020
|
+
};
|
|
17021
|
+
}
|
|
17022
|
+
function parseCloudReply(raw) {
|
|
17023
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw))
|
|
17024
|
+
malformed("no cloud block");
|
|
17025
|
+
const block = raw;
|
|
17026
|
+
const v = block.verdict;
|
|
17027
|
+
if (!v || typeof v !== "object" || Array.isArray(v))
|
|
17028
|
+
malformed("no verdict");
|
|
17029
|
+
if (typeof v.decision !== "string" || !DECISIONS2.has(v.decision))
|
|
17030
|
+
malformed("verdict has no decision");
|
|
17031
|
+
if (v.reason !== null && v.reason !== undefined && typeof v.reason !== "string")
|
|
17032
|
+
malformed("verdict reason is not text");
|
|
17033
|
+
if (!Array.isArray(v.outcomes) || v.outcomes.length > MAX_LIST)
|
|
17034
|
+
malformed("verdict has no outcomes list");
|
|
17035
|
+
if (v.beyondTask !== undefined && typeof v.beyondTask !== "boolean")
|
|
17036
|
+
malformed("verdict beyondTask is not a flag");
|
|
17037
|
+
const outcomes = v.outcomes.map(parseOutcome);
|
|
17038
|
+
const asked = names(block.asked, "asked");
|
|
17039
|
+
const askedSet = new Set(asked);
|
|
17040
|
+
const seen = new Set;
|
|
17041
|
+
outcomes.forEach((o, i) => {
|
|
17042
|
+
if (!askedSet.has(o.policy))
|
|
17043
|
+
malformed(`outcome ${i} answers ${JSON.stringify(o.policy)}, which Cloud did not ask`);
|
|
17044
|
+
const key = `${o.origin?.packId ?? ""}\x00${o.policy}`;
|
|
17045
|
+
if (seen.has(key))
|
|
17046
|
+
malformed(`outcome ${i} answers ${JSON.stringify(o.policy)} twice`);
|
|
17047
|
+
seen.add(key);
|
|
17048
|
+
});
|
|
17049
|
+
if (outcomes.some((o) => o.verdict === "deny") && v.decision !== "deny")
|
|
17050
|
+
malformed("a check denied but the verdict does not");
|
|
17051
|
+
return {
|
|
17052
|
+
verdict: {
|
|
17053
|
+
decision: v.decision,
|
|
17054
|
+
reason: typeof v.reason === "string" ? v.reason.length > MAX_CLOUD_REASON_CHARS ? `${v.reason.slice(0, MAX_CLOUD_REASON_CHARS - 1)}…` : v.reason : null,
|
|
17055
|
+
outcomes,
|
|
17056
|
+
injectionSuspected: nullableProbability(v.injectionSuspected, "injectionSuspected"),
|
|
17057
|
+
scopeWithinRequest: nullableProbability(v.scopeWithinRequest, "scopeWithinRequest"),
|
|
17058
|
+
beyondTask: v.beyondTask === true
|
|
17059
|
+
},
|
|
17060
|
+
asked,
|
|
17061
|
+
droppedLocal: names(block.droppedLocal, "droppedLocal"),
|
|
17062
|
+
droppedCloud: names(block.droppedCloud, "droppedCloud")
|
|
17063
|
+
};
|
|
17064
|
+
}
|
|
17065
|
+
function joinLines(reasons) {
|
|
17066
|
+
const lines = [];
|
|
17067
|
+
for (const reason of reasons) {
|
|
17068
|
+
if (!reason)
|
|
17069
|
+
continue;
|
|
17070
|
+
for (const line of reason.split(`
|
|
17071
|
+
`))
|
|
17072
|
+
if (!lines.includes(line))
|
|
17073
|
+
lines.push(line);
|
|
17074
|
+
}
|
|
17075
|
+
return lines.length > 0 ? lines.join(`
|
|
17076
|
+
`) : null;
|
|
17077
|
+
}
|
|
17078
|
+
function mergeCloudVerdict(cloud, local) {
|
|
17079
|
+
const decision = RANK2[cloud.decision] >= RANK2[local.decision] ? cloud.decision : local.decision;
|
|
17080
|
+
let reason;
|
|
17081
|
+
if (decision === "deny") {
|
|
17082
|
+
reason = cloud.decision === "deny" ? cloud.reason ?? local.reason : local.reason;
|
|
17083
|
+
} else if (decision === "instruct") {
|
|
17084
|
+
reason = joinLines([cloud, local].filter((v) => v.decision === "instruct").map((v) => v.reason));
|
|
17085
|
+
} else {
|
|
17086
|
+
reason = joinLines([cloud.reason, local.reason]);
|
|
17087
|
+
}
|
|
17088
|
+
const beyond = cloud.beyondTask === undefined && local.beyondTask === undefined ? undefined : cloud.beyondTask === true || local.beyondTask === true;
|
|
17089
|
+
return {
|
|
17090
|
+
decision,
|
|
17091
|
+
reason,
|
|
17092
|
+
outcomes: [...cloud.outcomes, ...local.outcomes],
|
|
17093
|
+
injectionSuspected: local.injectionSuspected ?? cloud.injectionSuspected,
|
|
17094
|
+
scopeWithinRequest: local.scopeWithinRequest ?? cloud.scopeWithinRequest,
|
|
17095
|
+
...beyond !== undefined ? { beyondTask: beyond } : {}
|
|
17096
|
+
};
|
|
17097
|
+
}
|
|
17098
|
+
function envNumber2(name, fallback) {
|
|
17099
|
+
const n = Number(process.env[name]);
|
|
17100
|
+
return Number.isFinite(n) && n > 0 ? n : fallback;
|
|
17101
|
+
}
|
|
17102
|
+
function expectedQuestions(request, prepared, dropped) {
|
|
17103
|
+
if (dropped.size === 0)
|
|
17104
|
+
return request;
|
|
17105
|
+
const questions = Object.fromEntries(Object.entries(request.questions).filter(([id]) => {
|
|
17106
|
+
const owner = prepared.compiled.owners.get(id);
|
|
17107
|
+
return !(typeof owner === "string" && dropped.has(owner));
|
|
17108
|
+
}));
|
|
17109
|
+
return { ...request, questions };
|
|
17110
|
+
}
|
|
17111
|
+
function presentAnswers(response) {
|
|
17112
|
+
const out = {};
|
|
17113
|
+
const answers = response.answers && typeof response.answers === "object" ? response.answers : {};
|
|
17114
|
+
for (const [id, a] of Object.entries(answers)) {
|
|
17115
|
+
const p = a?.noul;
|
|
17116
|
+
if (isProbability(p))
|
|
17117
|
+
out[id] = p;
|
|
17118
|
+
}
|
|
17119
|
+
return out;
|
|
17120
|
+
}
|
|
17121
|
+
async function evaluateCloudSemantic(input, opts) {
|
|
17122
|
+
const started = performance.now();
|
|
17123
|
+
const elapsed = () => Math.round(performance.now() - started);
|
|
17124
|
+
const tool = classifyTool(input.toolName);
|
|
17125
|
+
if (tool.toolIsKnown && tool.toolClass === "other") {
|
|
17126
|
+
return {
|
|
17127
|
+
status: "ok",
|
|
17128
|
+
verdict: { ...EMPTY_ALLOW, outcomes: [] },
|
|
17129
|
+
answers: {},
|
|
17130
|
+
latencyMs: elapsed(),
|
|
17131
|
+
inputTokens: null,
|
|
17132
|
+
questionCount: 0,
|
|
17133
|
+
truncated: false,
|
|
17134
|
+
requestCut: false,
|
|
17135
|
+
redactions: 0,
|
|
17136
|
+
model: opts.model ?? DEFAULT_JEV_MODEL,
|
|
17137
|
+
modelVerified: true,
|
|
17138
|
+
via: "none",
|
|
17139
|
+
cloud: { asked: [], droppedLocal: [], droppedCloud: [] }
|
|
17140
|
+
};
|
|
17141
|
+
}
|
|
17142
|
+
let prepared;
|
|
17143
|
+
let request;
|
|
17144
|
+
try {
|
|
17145
|
+
prepared = prepareSemantic(input, opts);
|
|
17146
|
+
request = buildCloudRequest(prepared, input, opts.machineId, opts.agent);
|
|
17147
|
+
} catch (err) {
|
|
17148
|
+
return {
|
|
17149
|
+
status: "degraded",
|
|
17150
|
+
reason: `prepare: ${err instanceof Error ? err.message : String(err)}`,
|
|
17151
|
+
latencyMs: elapsed(),
|
|
17152
|
+
questionCount: 0,
|
|
17153
|
+
truncated: false,
|
|
17154
|
+
requestCut: false
|
|
17155
|
+
};
|
|
17156
|
+
}
|
|
17157
|
+
const questionCount = Object.keys(request.questions).length;
|
|
17158
|
+
const { cloud: _block, ...forwarded } = request;
|
|
17159
|
+
const oversized = prepared.oversized || JSON.stringify(forwarded).length > MAX_REQUEST_CHARS;
|
|
17160
|
+
const truncated = prepared.truncated || oversized;
|
|
17161
|
+
const requestCut = prepared.requestCut || oversized;
|
|
17162
|
+
const degraded = (reason) => ({
|
|
17163
|
+
status: "degraded",
|
|
17164
|
+
reason,
|
|
17165
|
+
latencyMs: elapsed(),
|
|
17166
|
+
questionCount,
|
|
17167
|
+
truncated,
|
|
17168
|
+
requestCut
|
|
17169
|
+
});
|
|
17170
|
+
const transport = opts.transport;
|
|
17171
|
+
if (!transport)
|
|
17172
|
+
return degraded("no-transport");
|
|
17173
|
+
const via = opts.via ?? "failproofai";
|
|
17174
|
+
if (opts.signal?.aborted)
|
|
17175
|
+
return degraded("aborted");
|
|
17176
|
+
try {
|
|
17177
|
+
const timeout = AbortSignal.timeout(opts.timeoutMs ?? envNumber2("FAILPROOFAI_JEV_TIMEOUT_MS", DEFAULT_JEV_TIMEOUT_MS));
|
|
17178
|
+
const signal = opts.signal ? AbortSignal.any([timeout, opts.signal]) : timeout;
|
|
17179
|
+
const response = await transport(request, signal);
|
|
17180
|
+
const reply = parseCloudReply(response.cloud);
|
|
17181
|
+
const own = new Map(prepared.selected.map((p) => [p.name, p]));
|
|
17182
|
+
const dropped = new Set(reply.droppedLocal.filter((name) => own.has(name)));
|
|
17183
|
+
const kept = prepared.selected.filter((p) => !dropped.has(p.name));
|
|
17184
|
+
const shortCircuit = kept.length === 0 && reply.asked.length === 0 && reply.verdict.outcomes.length === 0;
|
|
17185
|
+
const answers = shortCircuit ? presentAnswers(response) : readAnswers(expectedQuestions(request, prepared, dropped), response);
|
|
17186
|
+
const local = prepared.intent === "v1" ? decideV1(kept, answers, input.toolInput, prepared.userSaid, prepared.agentLastMessage, {
|
|
17187
|
+
...opts.v1,
|
|
17188
|
+
userSaidCut: prepared.userSaidCut
|
|
17189
|
+
}) : decide(kept, answers, input.toolInput, prepared.userSaid, opts.thresholds ?? DEFAULT_THRESHOLDS, prepared.userSaidCut);
|
|
17190
|
+
return {
|
|
17191
|
+
status: "ok",
|
|
17192
|
+
verdict: mergeCloudVerdict(reply.verdict, local),
|
|
17193
|
+
answers,
|
|
17194
|
+
latencyMs: elapsed(),
|
|
17195
|
+
inputTokens: typeof response.usage?.input_tokens === "number" ? response.usage.input_tokens : null,
|
|
17196
|
+
questionCount,
|
|
17197
|
+
truncated,
|
|
17198
|
+
requestCut,
|
|
17199
|
+
redactions: prepared.envelope.redactions,
|
|
17200
|
+
model: response.model || request.model,
|
|
17201
|
+
modelVerified: response.modelUnverified !== true,
|
|
17202
|
+
via,
|
|
17203
|
+
cloud: {
|
|
17204
|
+
asked: reply.asked,
|
|
17205
|
+
droppedLocal: [...dropped].map((name) => ({ name, packId: own.get(name)?.origin?.packId ?? null })),
|
|
17206
|
+
droppedCloud: reply.droppedCloud
|
|
17207
|
+
}
|
|
17208
|
+
};
|
|
17209
|
+
} catch (err) {
|
|
17210
|
+
if (opts.signal?.aborted)
|
|
17211
|
+
return degraded("aborted");
|
|
17212
|
+
if (err instanceof JevError)
|
|
17213
|
+
return degraded(err.code);
|
|
17214
|
+
if (err instanceof Error && (err.name === "TimeoutError" || err.name === "AbortError"))
|
|
17215
|
+
return degraded("timeout");
|
|
17216
|
+
return degraded(`error: ${err instanceof Error ? err.message : String(err)}`);
|
|
17217
|
+
}
|
|
17218
|
+
}
|
|
17219
|
+
var CLOUD_BLOCK_VERSION = 1, MAX_TARGET_SCAN_CHARS = 64000, MAX_CLOUD_BLOCK_BYTES = 240000, blockBytes = (block) => Buffer.byteLength(JSON.stringify(block), "utf8"), REDACTED_TARGET_WORD = "\x00redacted", MAX_SECRET_SCAN_CHARS, REDACTION_MARKER, REDACTED_SAID = "\x00", POLICY_ID_RE2, MAX_NAME_CHARS = 256, MAX_LIST = 4096, MAX_CLOUD_REASON_CHARS = 8192, isProbability = (v) => typeof v === "number" && Number.isFinite(v) && v >= 0 && v <= 1, isName2 = (v) => typeof v === "string" && v.length > 0 && v.length <= MAX_NAME_CHARS, DECISIONS2, VERDICTS, INTENTS, RANK2, EMPTY_ALLOW;
|
|
17220
|
+
var init_cloud_jev = __esm(() => {
|
|
17221
|
+
init_compile();
|
|
17222
|
+
init_decide();
|
|
17223
|
+
init_envelope();
|
|
17224
|
+
init_facts();
|
|
17225
|
+
init_evaluator();
|
|
17226
|
+
init_jev_client();
|
|
17227
|
+
init_policies();
|
|
17228
|
+
init_redact();
|
|
17229
|
+
MAX_SECRET_SCAN_CHARS = 4 * MAX_TARGET_SCAN_CHARS;
|
|
17230
|
+
REDACTION_MARKER = /<redacted:[^>]*>/g;
|
|
17231
|
+
POLICY_ID_RE2 = /^[A-Za-z0-9._-]{1,128}$/;
|
|
17232
|
+
DECISIONS2 = new Set(["allow", "deny", "instruct"]);
|
|
17233
|
+
VERDICTS = new Set(["deny", "instruct", "overridden", "none"]);
|
|
17234
|
+
INTENTS = new Set(["op-requested", "task-step", "downgraded-task-step"]);
|
|
17235
|
+
RANK2 = { allow: 0, instruct: 1, deny: 2 };
|
|
17236
|
+
EMPTY_ALLOW = {
|
|
17237
|
+
decision: "allow",
|
|
17238
|
+
reason: null,
|
|
17239
|
+
outcomes: [],
|
|
17240
|
+
injectionSuspected: null,
|
|
17241
|
+
scopeWithinRequest: null,
|
|
17242
|
+
beyondTask: false
|
|
17243
|
+
};
|
|
17244
|
+
});
|
|
17245
|
+
|
|
16078
17246
|
// src/hooks/semantic/jev-throttle.ts
|
|
16079
17247
|
var exports_jev_throttle = {};
|
|
16080
17248
|
__export(exports_jev_throttle, {
|
|
@@ -16285,10 +17453,10 @@ var init_jev_throttle = __esm(() => {
|
|
|
16285
17453
|
});
|
|
16286
17454
|
|
|
16287
17455
|
// src/hooks/semantic/session-root.ts
|
|
16288
|
-
import { mkdirSync as mkdirSync11, readdirSync as readdirSync14, readFileSync as
|
|
16289
|
-
import { isAbsolute as isAbsolute4, resolve as
|
|
17456
|
+
import { mkdirSync as mkdirSync11, readdirSync as readdirSync14, readFileSync as readFileSync20, statSync as statSync22, unlinkSync as unlinkSync3, writeFileSync as writeFileSync9 } from "node:fs";
|
|
17457
|
+
import { isAbsolute as isAbsolute4, resolve as resolve19 } from "node:path";
|
|
16290
17458
|
function validRoot(v) {
|
|
16291
|
-
return typeof v === "string" && isAbsolute4(v) &&
|
|
17459
|
+
return typeof v === "string" && isAbsolute4(v) && resolve19(v) === v && v !== "/";
|
|
16292
17460
|
}
|
|
16293
17461
|
function storeIsOurs() {
|
|
16294
17462
|
if (process.platform === "win32")
|
|
@@ -16296,7 +17464,7 @@ function storeIsOurs() {
|
|
|
16296
17464
|
if (looseIntentStoreDir() !== null)
|
|
16297
17465
|
return false;
|
|
16298
17466
|
try {
|
|
16299
|
-
const mode =
|
|
17467
|
+
const mode = statSync22(rootsDir()).mode & 511;
|
|
16300
17468
|
return (mode & DIR_WRITABLE_BY_OTHERS4) === 0;
|
|
16301
17469
|
} catch {
|
|
16302
17470
|
return true;
|
|
@@ -16304,7 +17472,7 @@ function storeIsOurs() {
|
|
|
16304
17472
|
}
|
|
16305
17473
|
function readPinned(sessionId) {
|
|
16306
17474
|
try {
|
|
16307
|
-
const parsed = JSON.parse(
|
|
17475
|
+
const parsed = JSON.parse(readFileSync20(rootFile(sessionId), "utf8"));
|
|
16308
17476
|
return validRoot(parsed?.root) ? parsed.root : null;
|
|
16309
17477
|
} catch {
|
|
16310
17478
|
return null;
|
|
@@ -16317,9 +17485,9 @@ function pruneSessionRoots(now = Date.now()) {
|
|
|
16317
17485
|
for (const name of readdirSync14(dir)) {
|
|
16318
17486
|
if (!ROOT_FILE_RE.test(name))
|
|
16319
17487
|
continue;
|
|
16320
|
-
const path =
|
|
17488
|
+
const path = resolve19(dir, name);
|
|
16321
17489
|
try {
|
|
16322
|
-
const st =
|
|
17490
|
+
const st = statSync22(path);
|
|
16323
17491
|
if (st.isFile() && now - st.mtimeMs > SESSION_ROOT_MAX_AGE_MS) {
|
|
16324
17492
|
unlinkSync3(path);
|
|
16325
17493
|
removed++;
|
|
@@ -16344,12 +17512,12 @@ function sessionProjectRoot(sessionId, cwd, now = Date.now()) {
|
|
|
16344
17512
|
if (!validRoot(live))
|
|
16345
17513
|
return live;
|
|
16346
17514
|
mkdirSync11(rootsDir(), { recursive: true, mode: 448 });
|
|
16347
|
-
|
|
17515
|
+
writeFileSync9(rootFile(sessionId), JSON.stringify({ root: live, at: now }), { mode: 384, flag: "wx" });
|
|
16348
17516
|
pruneSessionRoots(now);
|
|
16349
17517
|
} catch {}
|
|
16350
17518
|
return live;
|
|
16351
17519
|
}
|
|
16352
|
-
var SESSION_ID_RE3, ROOT_FILE_RE, SESSION_ROOT_MAX_AGE_MS, DIR_WRITABLE_BY_OTHERS4 = 18, rootsDir = () =>
|
|
17520
|
+
var SESSION_ID_RE3, ROOT_FILE_RE, SESSION_ROOT_MAX_AGE_MS, DIR_WRITABLE_BY_OTHERS4 = 18, rootsDir = () => resolve19(semanticDir(), "roots"), rootFile = (sessionId) => resolve19(rootsDir(), `${sessionId}.json`);
|
|
16353
17521
|
var init_session_root = __esm(() => {
|
|
16354
17522
|
init_fp_home();
|
|
16355
17523
|
init_facts();
|
|
@@ -16387,6 +17555,13 @@ function resolveTimeout(cfg) {
|
|
|
16387
17555
|
return DEFAULT_JEV_TIMEOUT_MS;
|
|
16388
17556
|
return Math.min(MAX_JEV_TIMEOUT_MS2, Math.max(MIN_JEV_TIMEOUT_MS2, t));
|
|
16389
17557
|
}
|
|
17558
|
+
function reviewerKey(o) {
|
|
17559
|
+
const packId = o.origin?.packId;
|
|
17560
|
+
return packId !== undefined && packId.startsWith("cloud:") ? cloudReviewerName(packId.slice("cloud:".length), o.policy) : o.policy;
|
|
17561
|
+
}
|
|
17562
|
+
function isCloudOutcome(o) {
|
|
17563
|
+
return o.origin?.packId?.startsWith("cloud:") === true;
|
|
17564
|
+
}
|
|
16390
17565
|
function jevDecider(outcome) {
|
|
16391
17566
|
const wanted = outcome.verdict.decision === "deny" ? "deny" : "instruct";
|
|
16392
17567
|
return outcome.verdict.outcomes.find((o) => o.verdict === wanted);
|
|
@@ -16409,6 +17584,10 @@ function toReview(outcome, cached = false) {
|
|
|
16409
17584
|
const latencyMs = sent && !cached ? outcome.latencyMs : null;
|
|
16410
17585
|
const model = sent ? outcome.model : null;
|
|
16411
17586
|
const outcomes = outcome.verdict.outcomes;
|
|
17587
|
+
const cloudAsked = "cloud" in outcome ? new Set(outcome.cloud.asked) : null;
|
|
17588
|
+
const unvouched = outcomes.some((o) => isCloudOutcome(o) && !(cloudAsked?.has(o.policy) ?? false));
|
|
17589
|
+
if (unvouched)
|
|
17590
|
+
return { kind: "fallback", reason: "malformed", latencyMs, model: null };
|
|
16412
17591
|
const injection = sent ? outcome.verdict.injectionSuspected : null;
|
|
16413
17592
|
const warned = (o) => o.verdict === "instruct" && o.intent !== "downgraded-task-step";
|
|
16414
17593
|
return {
|
|
@@ -16417,8 +17596,8 @@ function toReview(outcome, cached = false) {
|
|
|
16417
17596
|
reason: outcome.verdict.reason,
|
|
16418
17597
|
policyName: jevPolicyName(outcome),
|
|
16419
17598
|
...jevDecider(outcome)?.origin ? { origin: jevDecider(outcome)?.origin } : {},
|
|
16420
|
-
asked: sent ? outcomes.map(
|
|
16421
|
-
notDenied: sent ? outcomes.filter((o) => o.verdict !== "deny" && !warned(o)).map(
|
|
17599
|
+
asked: sent ? outcomes.map(reviewerKey) : [],
|
|
17600
|
+
notDenied: sent ? outcomes.filter((o) => o.verdict !== "deny" && !warned(o)).map(reviewerKey) : [],
|
|
16422
17601
|
injectionAsked: injection !== null,
|
|
16423
17602
|
injected: injection !== null && injection >= DEFAULT_THRESHOLDS_V1.injection,
|
|
16424
17603
|
unclearableWarned: outcomes.some((o) => o.mode === "deny" && warned(o)),
|
|
@@ -16450,11 +17629,22 @@ function startJevReview(cfg, call) {
|
|
|
16450
17629
|
let throttled;
|
|
16451
17630
|
try {
|
|
16452
17631
|
route = transportForConfig(cfg);
|
|
16453
|
-
|
|
17632
|
+
const scope = call.cloud ? `${throttleScope(cfg, route)}\x00cloud\x00${call.cloud.machineId}\x00${call.cloud.deployment ?? "-"}` : throttleScope(cfg, route);
|
|
17633
|
+
throttled = throttle.throttleTransport(route.transport, { scope });
|
|
16454
17634
|
} catch (err) {
|
|
16455
17635
|
const reason = err instanceof JevError ? err.code : "config";
|
|
16456
17636
|
return handle(Promise.resolve({ kind: "fallback", reason, latencyMs: null, model: null }));
|
|
16457
17637
|
}
|
|
17638
|
+
const cloud = call.cloud;
|
|
17639
|
+
const healthScope = cloud ? JSON.stringify([cfg.baseUrl ?? null, cloud.machineId]) : "";
|
|
17640
|
+
let probe = false;
|
|
17641
|
+
if (cloud) {
|
|
17642
|
+
const gate = cloudJevGate(healthScope);
|
|
17643
|
+
if (!gate.ask) {
|
|
17644
|
+
return handle(Promise.resolve({ kind: "fallback", reason: BREAKER_SKIP_REASON, latencyMs: null, model: null }));
|
|
17645
|
+
}
|
|
17646
|
+
probe = gate.probe;
|
|
17647
|
+
}
|
|
16458
17648
|
let intent;
|
|
16459
17649
|
try {
|
|
16460
17650
|
intent = intentReader.readIntent(call.sessionId);
|
|
@@ -16473,6 +17663,7 @@ function startJevReview(cfg, call) {
|
|
|
16473
17663
|
agentLastMessage: intent.agentLastMessage
|
|
16474
17664
|
};
|
|
16475
17665
|
let cached = false;
|
|
17666
|
+
let reachedCloud = false;
|
|
16476
17667
|
const transport = async (request, signal) => {
|
|
16477
17668
|
const response = await throttled(request, signal);
|
|
16478
17669
|
cached = servedFromCache2(response);
|
|
@@ -16480,7 +17671,7 @@ function startJevReview(cfg, call) {
|
|
|
16480
17671
|
};
|
|
16481
17672
|
const timeoutMs = resolveTimeout(cfg);
|
|
16482
17673
|
let abandoned = false;
|
|
16483
|
-
const
|
|
17674
|
+
const options = {
|
|
16484
17675
|
transport,
|
|
16485
17676
|
cli: call.cli,
|
|
16486
17677
|
via: route.via,
|
|
@@ -16489,9 +17680,25 @@ function startJevReview(cfg, call) {
|
|
|
16489
17680
|
intent: "v1",
|
|
16490
17681
|
v1: { thresholds: DEFAULT_THRESHOLDS_V1 },
|
|
16491
17682
|
signal: controller.signal
|
|
16492
|
-
}
|
|
17683
|
+
};
|
|
17684
|
+
const evaluated = cloud ? evaluateCloudSemantic(input, {
|
|
17685
|
+
...options,
|
|
17686
|
+
machineId: cloud.machineId,
|
|
17687
|
+
agent: cloud.agent,
|
|
17688
|
+
...call.localPaused ? { policies: [] } : {}
|
|
17689
|
+
}) : evaluateSemantic(input, options);
|
|
17690
|
+
const answered = evaluated.then((outcome) => {
|
|
16493
17691
|
const hit = cached && outcome.status === "ok";
|
|
17692
|
+
reachedCloud = outcome.status === "ok" && !hit && outcome.via !== "none";
|
|
16494
17693
|
const review = toReview(outcome, hit);
|
|
17694
|
+
if (cloud && !abandoned && outcome.status === "ok" && "cloud" in outcome && outcome.cloud.droppedLocal.length > 0) {
|
|
17695
|
+
const cloudNames = new Set([...outcome.cloud.asked, ...outcome.cloud.droppedCloud]);
|
|
17696
|
+
recordJevBudgetDrops({ machineId: cloud.machineId, deployment: cloud.deployment, jevMode: cloud.mode }, outcome.cloud.droppedLocal.map((d) => ({
|
|
17697
|
+
packId: d.packId ?? "unknown",
|
|
17698
|
+
name: d.name,
|
|
17699
|
+
...cloudNames.has(d.name) ? { clash: true } : {}
|
|
17700
|
+
})));
|
|
17701
|
+
}
|
|
16495
17702
|
if (!(outcome.status === "degraded" && outcome.reason === "aborted")) {
|
|
16496
17703
|
const row = verdictLogRow(input, hit ? { ...outcome, inputTokens: null } : outcome, {
|
|
16497
17704
|
sessionId: call.sessionId,
|
|
@@ -16499,7 +17706,8 @@ function startJevReview(cfg, call) {
|
|
|
16499
17706
|
eventType: call.eventType,
|
|
16500
17707
|
applied: abandoned || review.kind !== "answered" ? "legacy-fallback" : mode === "observe" ? "observe" : "two-tier"
|
|
16501
17708
|
});
|
|
16502
|
-
|
|
17709
|
+
const withCloud = outcome.status === "ok" && "cloud" in outcome ? { ...row, cloud: outcome.cloud } : row;
|
|
17710
|
+
appendVerdictLog(hit ? { ...withCloud, cached: true } : withCloud);
|
|
16503
17711
|
}
|
|
16504
17712
|
return review;
|
|
16505
17713
|
}).catch(() => ({ kind: "fallback", reason: "error", latencyMs: null, model: null }));
|
|
@@ -16511,16 +17719,27 @@ function startJevReview(cfg, call) {
|
|
|
16511
17719
|
resolve({ kind: "fallback", reason: "timeout", latencyMs: timeoutMs + JEV_DEADLINE_GRACE_MS, model: null });
|
|
16512
17720
|
}, timeoutMs + JEV_DEADLINE_GRACE_MS);
|
|
16513
17721
|
});
|
|
16514
|
-
|
|
17722
|
+
const raced = Promise.race([answered, expired]).finally(() => {
|
|
16515
17723
|
if (deadline !== undefined)
|
|
16516
17724
|
clearTimeout(deadline);
|
|
17725
|
+
});
|
|
17726
|
+
if (!cloud)
|
|
17727
|
+
return handle(raced);
|
|
17728
|
+
return handle(raced.then((review) => {
|
|
17729
|
+
recordCloudJevResult(healthScope, classifyCloudJevReview(review, { reachedCloud }), review.kind === "fallback" ? review.reason : null, probe);
|
|
17730
|
+
reportCloudJevHealth();
|
|
17731
|
+
return review;
|
|
16517
17732
|
}));
|
|
16518
17733
|
}
|
|
16519
17734
|
var throttle, intentReader, ALWAYS_ON, MIN_JEV_TIMEOUT_MS2 = 100, MAX_JEV_TIMEOUT_MS2 = 1e4, JEV_DEADLINE_GRACE_MS = 250;
|
|
16520
17735
|
var init_jev_review = __esm(() => {
|
|
16521
17736
|
init_builtin_policies();
|
|
17737
|
+
init_cloud_managed_policies();
|
|
17738
|
+
init_cloud_policy_errors();
|
|
16522
17739
|
init_policy_registry();
|
|
16523
17740
|
init_decide();
|
|
17741
|
+
init_cloud_jev();
|
|
17742
|
+
init_cloud_jev_health();
|
|
16524
17743
|
init_evaluator();
|
|
16525
17744
|
init_intent();
|
|
16526
17745
|
init_jev_client();
|
|
@@ -16669,7 +17888,7 @@ var init_enforcement_capability = __esm(() => {
|
|
|
16669
17888
|
});
|
|
16670
17889
|
|
|
16671
17890
|
// src/hooks/handler.ts
|
|
16672
|
-
import { existsSync as
|
|
17891
|
+
import { existsSync as existsSync22 } from "node:fs";
|
|
16673
17892
|
function canonicalizeEventType(raw, cli) {
|
|
16674
17893
|
if (cli === "codex") {
|
|
16675
17894
|
const mapped = CODEX_EVENT_MAP[raw];
|
|
@@ -16727,9 +17946,23 @@ function isHumanAuthoredGate(rawEventType, cli) {
|
|
|
16727
17946
|
function jevForcedOff(opts) {
|
|
16728
17947
|
return process.env.FAILPROOFAI_EVALUATOR === "legacy" || !!opts?.forceDecision;
|
|
16729
17948
|
}
|
|
16730
|
-
async function readJevConfig() {
|
|
17949
|
+
async function readJevConfig(agent) {
|
|
16731
17950
|
try {
|
|
16732
|
-
|
|
17951
|
+
const cloud = readCloudJevState();
|
|
17952
|
+
if (cloud.jevMode === "off")
|
|
17953
|
+
return null;
|
|
17954
|
+
if (cloudJevAsks(cloud.jevMode)) {
|
|
17955
|
+
await Promise.resolve().then(() => init_jev_config());
|
|
17956
|
+
const resolved = loadJevConfigForCloudMode(cloud.jevMode);
|
|
17957
|
+
if (!resolved.config || !resolved.machineId)
|
|
17958
|
+
return null;
|
|
17959
|
+
return {
|
|
17960
|
+
config: resolved.config,
|
|
17961
|
+
defaultMode: DEFAULT_JEV_MODE,
|
|
17962
|
+
cloud: { machineId: resolved.machineId, deployment: cloud.deployment, mode: cloud.jevMode, agent: agent ?? null }
|
|
17963
|
+
};
|
|
17964
|
+
}
|
|
17965
|
+
if (!existsSync22(jevConfigFile()))
|
|
16733
17966
|
return null;
|
|
16734
17967
|
await Promise.resolve().then(() => init_jev_config());
|
|
16735
17968
|
const config = loadJevConfig();
|
|
@@ -16739,20 +17972,72 @@ async function readJevConfig() {
|
|
|
16739
17972
|
return null;
|
|
16740
17973
|
}
|
|
16741
17974
|
}
|
|
16742
|
-
|
|
17975
|
+
function jevAttribution(origin) {
|
|
17976
|
+
if (!origin)
|
|
17977
|
+
return {};
|
|
17978
|
+
if (origin.packId.startsWith("cloud:")) {
|
|
17979
|
+
const version = Number(origin.packVersion);
|
|
17980
|
+
return {
|
|
17981
|
+
cloudPolicyId: origin.packId.slice("cloud:".length),
|
|
17982
|
+
...Number.isSafeInteger(version) ? { cloudVersion: version } : {}
|
|
17983
|
+
};
|
|
17984
|
+
}
|
|
17985
|
+
return origin;
|
|
17986
|
+
}
|
|
17987
|
+
async function recordCloudPolicyErrors(input) {
|
|
17988
|
+
try {
|
|
17989
|
+
const jev = readCloudJevState();
|
|
17990
|
+
const managed = input.manifestError !== null || input.jsPolicies.length > 0 || jev.jevMode !== null || jev.errors.length > 0 || input.agentScopeUnresolved === true;
|
|
17991
|
+
if (!managed && !existsSync22(cloudPolicyErrorsPath()))
|
|
17992
|
+
return;
|
|
17993
|
+
let jevProblem = null;
|
|
17994
|
+
let budgetDrops = [];
|
|
17995
|
+
let health = [];
|
|
17996
|
+
if (cloudJevAsks(jev.jevMode)) {
|
|
17997
|
+
await Promise.resolve().then(() => init_jev_config());
|
|
17998
|
+
const resolved = loadJevConfigForCloudMode(jev.jevMode);
|
|
17999
|
+
jevProblem = resolved.problem;
|
|
18000
|
+
if (resolved.machineId) {
|
|
18001
|
+
budgetDrops = existsSync22(jevBudgetPath()) ? readJevBudgetDrops({ machineId: resolved.machineId, deployment: jev.deployment, jevMode: jev.jevMode }, installedPackIds()) : [];
|
|
18002
|
+
}
|
|
18003
|
+
await Promise.resolve().then(() => init_cloud_jev_health());
|
|
18004
|
+
health = cloudJevHealthErrors();
|
|
18005
|
+
}
|
|
18006
|
+
writeCloudPolicyErrors(collectCloudPolicyErrors({
|
|
18007
|
+
manifestError: input.manifestError,
|
|
18008
|
+
jsPolicies: input.jsPolicies,
|
|
18009
|
+
jsFailures: input.jsFailures,
|
|
18010
|
+
jev,
|
|
18011
|
+
jevProblem,
|
|
18012
|
+
budgetDrops,
|
|
18013
|
+
health,
|
|
18014
|
+
agentScopeUnresolved: input.agentScopeUnresolved
|
|
18015
|
+
}));
|
|
18016
|
+
if (input.jsPolicies.length > 0)
|
|
18017
|
+
recordCloudLoadChecked(input.jsPolicies[0].deployment, input.jsPolicies);
|
|
18018
|
+
} catch (err) {
|
|
18019
|
+
hookLogInfo(`could not record Cloud policy errors: ${err instanceof Error ? err.message : String(err)}`);
|
|
18020
|
+
}
|
|
18021
|
+
}
|
|
18022
|
+
async function startTwoTier(canonicalEventType, parsed, session, cli, opts, activePause, agent) {
|
|
16743
18023
|
if (!JEV_GATE_EVENTS.has(canonicalEventType))
|
|
16744
18024
|
return null;
|
|
16745
18025
|
if (isHumanAuthoredGate(session.rawHookEventName, cli))
|
|
16746
18026
|
return null;
|
|
16747
18027
|
if (typeof parsed.tool_name !== "string" || parsed.tool_name.length === 0)
|
|
16748
18028
|
return null;
|
|
16749
|
-
if (jevForcedOff(opts)
|
|
18029
|
+
if (jevForcedOff(opts))
|
|
18030
|
+
return null;
|
|
18031
|
+
const cloudAsks = cloudJevAsks(readCloudJevMode());
|
|
18032
|
+
if (activePause && !cloudAsks)
|
|
16750
18033
|
return null;
|
|
16751
|
-
if (!jevChecksInstalled())
|
|
18034
|
+
if (!cloudAsks && !jevChecksInstalled())
|
|
16752
18035
|
return null;
|
|
16753
|
-
const loaded = await readJevConfig();
|
|
18036
|
+
const loaded = await readJevConfig(agent);
|
|
16754
18037
|
if (!loaded)
|
|
16755
18038
|
return null;
|
|
18039
|
+
if (activePause && !loaded.cloud)
|
|
18040
|
+
return null;
|
|
16756
18041
|
const cfg = loaded.config;
|
|
16757
18042
|
try {
|
|
16758
18043
|
await Promise.resolve().then(() => init_jev_review());
|
|
@@ -16763,7 +18048,9 @@ async function startTwoTier(canonicalEventType, parsed, session, cli, opts, acti
|
|
|
16763
18048
|
cwd: session.cwd,
|
|
16764
18049
|
permissionMode: session.permissionMode,
|
|
16765
18050
|
sessionId: session.sessionId,
|
|
16766
|
-
cli
|
|
18051
|
+
cli,
|
|
18052
|
+
...loaded.cloud ? { cloud: loaded.cloud } : {},
|
|
18053
|
+
...activePause ? { localPaused: true } : {}
|
|
16767
18054
|
});
|
|
16768
18055
|
} catch (err) {
|
|
16769
18056
|
hookLogInfo(`Jev review could not start (${err instanceof Error ? err.message : String(err)})`);
|
|
@@ -16792,7 +18079,7 @@ async function captureJevIntent(canonicalEventType, decision, parsed, session, c
|
|
|
16792
18079
|
if (canonicalEventType !== "UserPromptSubmit" || jevForcedOff(opts))
|
|
16793
18080
|
return;
|
|
16794
18081
|
try {
|
|
16795
|
-
if (!jevChecksInstalled())
|
|
18082
|
+
if (!cloudJevAsks(readCloudJevMode()) && !jevChecksInstalled())
|
|
16796
18083
|
return;
|
|
16797
18084
|
if (!await readJevConfig())
|
|
16798
18085
|
return;
|
|
@@ -16834,6 +18121,9 @@ async function evaluateHookEvent(eventType, cli = "claude", stdinPayload, opts)
|
|
|
16834
18121
|
});
|
|
16835
18122
|
}
|
|
16836
18123
|
}
|
|
18124
|
+
if (isHealthProbe(eventType, parsed)) {
|
|
18125
|
+
return { exitCode: 0, stdout: "", stderr: "" };
|
|
18126
|
+
}
|
|
16837
18127
|
normalizeCliPayload(cli, parsed);
|
|
16838
18128
|
const canonicalEventType = canonicalizeEventType(eventType, cli);
|
|
16839
18129
|
const rawToolName = parsed.tool_name;
|
|
@@ -16857,6 +18147,7 @@ async function evaluateHookEvent(eventType, cli = "claude", stdinPayload, opts)
|
|
|
16857
18147
|
rawHookEventName: eventType,
|
|
16858
18148
|
cli
|
|
16859
18149
|
};
|
|
18150
|
+
const runtimeAgent = readRuntimeAgentIdentity(cli, opts?.agentSettingsPath ?? runtimeAgentSettingsPath(cli, session.cwd));
|
|
16860
18151
|
let config;
|
|
16861
18152
|
let customHooksList = [];
|
|
16862
18153
|
let conventionHookNames = new Set;
|
|
@@ -16873,7 +18164,7 @@ async function evaluateHookEvent(eventType, cli = "claude", stdinPayload, opts)
|
|
|
16873
18164
|
registerPolicy("failproofai/daemon-unreachable", "Fail-closed: the failproofaid daemon could not be reached for this daemon-configured scope.", async () => ({ decision: decision.decision, reason: decision.reason }), {});
|
|
16874
18165
|
} else {
|
|
16875
18166
|
config = readMergedHooksConfig(session.cwd);
|
|
16876
|
-
clearPolicies(cli);
|
|
18167
|
+
clearPolicies(cli, runtimeAgent);
|
|
16877
18168
|
activePause = readActivePause(session.sessionId);
|
|
16878
18169
|
const packsInstalledHere = hasInstalledRegexPacks();
|
|
16879
18170
|
const legacyNames = activePause || packsInstalledHere ? [] : config.enabledPolicies;
|
|
@@ -16883,17 +18174,19 @@ async function evaluateHookEvent(eventType, cli = "claude", stdinPayload, opts)
|
|
|
16883
18174
|
}
|
|
16884
18175
|
const enabledBuiltinNames = new Set(legacyNames);
|
|
16885
18176
|
let cloudManagedPolicies = [];
|
|
18177
|
+
let cloudManifestError = null;
|
|
16886
18178
|
try {
|
|
16887
|
-
cloudManagedPolicies = readActiveCloudManagedPolicies();
|
|
18179
|
+
cloudManagedPolicies = readActiveCloudManagedPolicies(runtimeAgent);
|
|
16888
18180
|
} catch (err) {
|
|
16889
18181
|
const msg = err instanceof Error ? err.message : String(err);
|
|
18182
|
+
cloudManifestError = msg;
|
|
16890
18183
|
hookLogWarn(`[failproofai] cloud-managed policies could NOT be loaded and are not being enforced: ${msg}. Local policies are unaffected. Run \`failproofai config --status\` to check this machine's enrolment.`);
|
|
16891
18184
|
trackHookEvent(getInstanceId(), "cloud_managed_load_error", {
|
|
16892
18185
|
event_type: eventType,
|
|
16893
18186
|
cli
|
|
16894
18187
|
});
|
|
16895
18188
|
}
|
|
16896
|
-
cloudDeployment = cloudManagedPolicies[0]?.deployment;
|
|
18189
|
+
cloudDeployment = cloudManagedPolicies[0]?.deployment ?? readCloudJevState().deployment ?? undefined;
|
|
16897
18190
|
let installedPacks = [];
|
|
16898
18191
|
try {
|
|
16899
18192
|
const packResult = readInstalledPacks();
|
|
@@ -16911,10 +18204,12 @@ async function evaluateHookEvent(eventType, cli = "claude", stdinPayload, opts)
|
|
|
16911
18204
|
...cloudManagedPolicies.map((policy) => policy.path),
|
|
16912
18205
|
...installedPacks.map((pack) => pack.path)
|
|
16913
18206
|
];
|
|
18207
|
+
const cloudJevMode = readCloudJevMode();
|
|
18208
|
+
const cloudForLoading = cloudManagedPolicies.map((policy) => withCloudAuthority(policy, cloudJevMode));
|
|
16914
18209
|
const loadResult = await loadAllCustomHooks(allExplicitPaths, {
|
|
16915
18210
|
sessionCwd: session.cwd,
|
|
16916
18211
|
customPoliciesEnabled: config.customPoliciesEnabled,
|
|
16917
|
-
...
|
|
18212
|
+
...cloudForLoading.length > 0 ? { cloudManagedPolicies: cloudForLoading } : {},
|
|
16918
18213
|
...installedPacks.length > 0 ? { packs: installedPacks } : {}
|
|
16919
18214
|
});
|
|
16920
18215
|
customHooksList = loadResult.hooks;
|
|
@@ -16994,6 +18289,12 @@ async function evaluateHookEvent(eventType, cli = "claude", stdinPayload, opts)
|
|
|
16994
18289
|
warnAuthority(refusedAuthorityWarning(registeredName, refused));
|
|
16995
18290
|
registerPolicy(registeredName, hook.description ?? "", fn, hook.match ?? {}, -1, pack?.policies.find((p) => p.name === hook.name)?.params, authority);
|
|
16996
18291
|
}
|
|
18292
|
+
await recordCloudPolicyErrors({
|
|
18293
|
+
manifestError: cloudManifestError,
|
|
18294
|
+
jsPolicies: cloudManagedPolicies,
|
|
18295
|
+
jsFailures: loadResult.cloudFailures,
|
|
18296
|
+
agentScopeUnresolved: runtimeAgent === null && readCloudAgentScopeRequired()
|
|
18297
|
+
});
|
|
16997
18298
|
if (!activePause) {
|
|
16998
18299
|
const guards = missingGuards({
|
|
16999
18300
|
errors: packErrors,
|
|
@@ -17040,7 +18341,7 @@ async function evaluateHookEvent(eventType, cli = "claude", stdinPayload, opts)
|
|
|
17040
18341
|
}
|
|
17041
18342
|
hookLogInfo(`event=${canonicalEventType} cli=${cli} policies=${config.enabledPolicies.length} custom=${customHooksList.length} convention=${conventionHookNames.size}`);
|
|
17042
18343
|
}
|
|
17043
|
-
const twoTier = await startTwoTier(canonicalEventType, parsed, session, cli, opts, activePause);
|
|
18344
|
+
const twoTier = await startTwoTier(canonicalEventType, parsed, session, cli, opts, activePause, runtimeAgent);
|
|
17044
18345
|
const matchedBeforeRelease = twoTier ? getPoliciesForEvent(canonicalEventType, parsed.tool_name).map((p) => p.name) : null;
|
|
17045
18346
|
const result = twoTier ? await evaluatePolicies(canonicalEventType, parsed, session, config, {
|
|
17046
18347
|
...twoTier,
|
|
@@ -17077,7 +18378,7 @@ async function evaluateHookEvent(eventType, cli = "claude", stdinPayload, opts)
|
|
|
17077
18378
|
cwd: session.cwd,
|
|
17078
18379
|
permissionMode: session.permissionMode,
|
|
17079
18380
|
hookEventName: session.hookEventName,
|
|
17080
|
-
...result.policyName && result.twoTier?.decidedByJev ? { policySource: "jev", ...jevOrigin } : {},
|
|
18381
|
+
...result.policyName && result.twoTier?.decidedByJev ? { policySource: "jev", ...jevAttribution(jevOrigin) } : {},
|
|
17081
18382
|
...result.policyName && !result.twoTier?.decidedByJev ? (() => {
|
|
17082
18383
|
const attribution = policyAttribution.get(result.policyName);
|
|
17083
18384
|
return {
|
|
@@ -17088,6 +18389,7 @@ async function evaluateHookEvent(eventType, cli = "claude", stdinPayload, opts)
|
|
|
17088
18389
|
...attribution?.packVersion ? { packVersion: attribution.packVersion } : {}
|
|
17089
18390
|
};
|
|
17090
18391
|
})() : {},
|
|
18392
|
+
...!result.policyName && observeVerdict ? { policyName: observeVerdict.policyName, ...jevAttribution(result.twoTier?.jevOrigin) } : {},
|
|
17091
18393
|
...cloudDeployment !== undefined ? { cloudDeployment } : {},
|
|
17092
18394
|
...observedResults.length > 0 ? { observed: observedResults } : {},
|
|
17093
18395
|
...activePause ? { pausedBy: activePause.setBy, pauseExpiresAt: activePause.expiresAt } : {}
|
|
@@ -17163,23 +18465,25 @@ var init_handler = __esm(() => {
|
|
|
17163
18465
|
init_telemetry_id();
|
|
17164
18466
|
init_hook_logger();
|
|
17165
18467
|
init_cloud_managed_policies();
|
|
18468
|
+
init_cloud_policy_errors();
|
|
17166
18469
|
init_pack_manifest();
|
|
17167
18470
|
init_pack_failclosed();
|
|
17168
18471
|
init_session_pause();
|
|
17169
18472
|
init_fp_home();
|
|
17170
18473
|
init_fp_reset();
|
|
17171
18474
|
init_untraced_note();
|
|
18475
|
+
init_agent_roster();
|
|
17172
18476
|
JEV_GATE_EVENTS = new Set(["PreToolUse", "PermissionRequest"]);
|
|
17173
18477
|
});
|
|
17174
18478
|
|
|
17175
18479
|
// src/hooks/worker-server.ts
|
|
17176
18480
|
import { createConnection, createServer } from "node:net";
|
|
17177
|
-
import { existsSync as
|
|
18481
|
+
import { existsSync as existsSync23, unlinkSync as unlinkSync4 } from "node:fs";
|
|
17178
18482
|
function isWorkerHookRequest(msg) {
|
|
17179
18483
|
if (!msg || typeof msg !== "object")
|
|
17180
18484
|
return false;
|
|
17181
18485
|
const m = msg;
|
|
17182
|
-
return m.type === "hook" && typeof m.hookEvent === "string" && typeof m.cli === "string" && typeof m.stdin === "string" && (m.cwd === undefined || m.cwd === null || typeof m.cwd === "string");
|
|
18486
|
+
return m.type === "hook" && typeof m.hookEvent === "string" && typeof m.cli === "string" && typeof m.stdin === "string" && (m.cwd === undefined || m.cwd === null || typeof m.cwd === "string") && (m.agentSettingsPath === undefined || m.agentSettingsPath === null || typeof m.agentSettingsPath === "string");
|
|
17183
18487
|
}
|
|
17184
18488
|
function encodeFrame(value) {
|
|
17185
18489
|
const body = Buffer.from(JSON.stringify(value), "utf8");
|
|
@@ -17274,6 +18578,7 @@ function handleConnection(socket, shutdown) {
|
|
|
17274
18578
|
const result = await evaluateHookEvent(request.hookEvent, request.cli, request.stdin, {
|
|
17275
18579
|
awaitTelemetryFlush: false,
|
|
17276
18580
|
fallbackCwd: request.cwd ?? undefined,
|
|
18581
|
+
agentSettingsPath: request.agentSettingsPath ?? undefined,
|
|
17277
18582
|
releaseRegistry: release
|
|
17278
18583
|
});
|
|
17279
18584
|
deliver(encodeFrame({
|
|
@@ -17340,14 +18645,14 @@ function requestExistingWorkerShutdown(socketPath) {
|
|
|
17340
18645
|
function startWorkerServer(socketPath, shutdown) {
|
|
17341
18646
|
const server = createServer((socket) => handleConnection(socket, shutdown ?? (() => server.close())));
|
|
17342
18647
|
const listen = () => {
|
|
17343
|
-
if (
|
|
18648
|
+
if (existsSync23(socketPath)) {
|
|
17344
18649
|
try {
|
|
17345
18650
|
unlinkSync4(socketPath);
|
|
17346
18651
|
} catch {}
|
|
17347
18652
|
}
|
|
17348
18653
|
server.listen(socketPath);
|
|
17349
18654
|
};
|
|
17350
|
-
if (!
|
|
18655
|
+
if (!existsSync23(socketPath))
|
|
17351
18656
|
listen();
|
|
17352
18657
|
else
|
|
17353
18658
|
requestExistingWorkerShutdown(socketPath).then(listen, (err) => server.emit("error", err));
|
|
@@ -17363,13 +18668,13 @@ var init_worker_server = __esm(() => {
|
|
|
17363
18668
|
|
|
17364
18669
|
// bin/failproofai-worker.mjs
|
|
17365
18670
|
import { realpathSync as realpathSync2 } from "node:fs";
|
|
17366
|
-
import { dirname as
|
|
18671
|
+
import { dirname as dirname11, resolve as resolve20 } from "node:path";
|
|
17367
18672
|
import { fileURLToPath } from "node:url";
|
|
17368
18673
|
if (!process.env.FAILPROOFAI_PACKAGE_ROOT) {
|
|
17369
|
-
process.env.FAILPROOFAI_PACKAGE_ROOT =
|
|
18674
|
+
process.env.FAILPROOFAI_PACKAGE_ROOT = resolve20(dirname11(realpathSync2(fileURLToPath(import.meta.url))), "..");
|
|
17370
18675
|
}
|
|
17371
18676
|
if (!process.env.FAILPROOFAI_DIST_PATH) {
|
|
17372
|
-
process.env.FAILPROOFAI_DIST_PATH =
|
|
18677
|
+
process.env.FAILPROOFAI_DIST_PATH = resolve20(dirname11(realpathSync2(fileURLToPath(import.meta.url))), "..", "dist");
|
|
17373
18678
|
}
|
|
17374
18679
|
var socketPath = process.env.FAILPROOFAI_WORKER_SOCKET;
|
|
17375
18680
|
if (!socketPath) {
|