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/hermes-plugin/README.md
CHANGED
|
@@ -165,23 +165,25 @@ decision, because otherwise corrupted retry state could block a turn forever.
|
|
|
165
165
|
## Local protocol
|
|
166
166
|
|
|
167
167
|
Requests and responses use the existing length-prefixed failproofaid Unix
|
|
168
|
-
socket protocol, version
|
|
168
|
+
socket protocol, version 2. A v1 daemon must be upgraded before it can safely
|
|
169
|
+
evaluate agent/profile-scoped policies.
|
|
169
170
|
|
|
170
171
|
```json
|
|
171
172
|
{
|
|
172
173
|
"type": "policyEvaluation",
|
|
173
|
-
"protocolVersion":
|
|
174
|
+
"protocolVersion": 2,
|
|
174
175
|
"integration": "hermes",
|
|
175
176
|
"event": "pre_tool_call",
|
|
176
177
|
"payload": {},
|
|
177
|
-
"cwd": "/workspace/project"
|
|
178
|
+
"cwd": "/workspace/project",
|
|
179
|
+
"agentSettingsPath": "/path/to/the/hermes/profile"
|
|
178
180
|
}
|
|
179
181
|
```
|
|
180
182
|
|
|
181
183
|
```json
|
|
182
184
|
{
|
|
183
185
|
"type": "policyResult",
|
|
184
|
-
"protocolVersion":
|
|
186
|
+
"protocolVersion": 2,
|
|
185
187
|
"decision": "instruct",
|
|
186
188
|
"policyNames": ["custom/approved-write-route"],
|
|
187
189
|
"reason": "Use the approved write route.",
|
|
@@ -102,6 +102,21 @@ def _profile_name() -> str:
|
|
|
102
102
|
return "default"
|
|
103
103
|
|
|
104
104
|
|
|
105
|
+
def _profile_settings_path(profile: str) -> str | None:
|
|
106
|
+
"""Evidence of the profile running this plugin, not a transcript guess."""
|
|
107
|
+
configured = os.environ.get("HERMES_HOME", "").strip()
|
|
108
|
+
if configured:
|
|
109
|
+
selected = Path(configured).expanduser() / "config.yaml"
|
|
110
|
+
elif profile == "default":
|
|
111
|
+
selected = Path.home() / ".hermes" / "config.yaml"
|
|
112
|
+
elif re.fullmatch(r"[A-Za-z0-9._-]{1,80}", profile):
|
|
113
|
+
selected = Path.home() / ".hermes" / "profiles" / profile / "config.yaml"
|
|
114
|
+
else:
|
|
115
|
+
return None
|
|
116
|
+
# An unresolvable profile does not acquire some other profile's ID.
|
|
117
|
+
return str(selected.absolute()) if selected.is_file() else None
|
|
118
|
+
|
|
119
|
+
|
|
105
120
|
def _string(value: object) -> str:
|
|
106
121
|
return value if isinstance(value, str) else ""
|
|
107
122
|
|
|
@@ -660,6 +675,7 @@ class FailproofAIPlugin:
|
|
|
660
675
|
event=event,
|
|
661
676
|
payload=payload,
|
|
662
677
|
cwd=cwd,
|
|
678
|
+
agent_settings_path=_profile_settings_path(self.profile),
|
|
663
679
|
connect_timeout_ms=self.connect_timeout_ms,
|
|
664
680
|
evaluation_timeout_ms=timeout_ms or self.evaluation_timeout_ms,
|
|
665
681
|
)
|
package/hermes-plugin/client.py
CHANGED
|
@@ -11,7 +11,7 @@ from dataclasses import dataclass
|
|
|
11
11
|
from pathlib import Path
|
|
12
12
|
from typing import Any, Mapping, Sequence
|
|
13
13
|
|
|
14
|
-
PROTOCOL_VERSION =
|
|
14
|
+
PROTOCOL_VERSION = 2
|
|
15
15
|
MAX_FRAME_BYTES = 16 * 1024 * 1024
|
|
16
16
|
MAX_REQUEST_BYTES = 1024 * 1024
|
|
17
17
|
|
|
@@ -75,6 +75,7 @@ def evaluate_policy(
|
|
|
75
75
|
event: str,
|
|
76
76
|
payload: Mapping[str, Any],
|
|
77
77
|
cwd: str | None,
|
|
78
|
+
agent_settings_path: str | None = None,
|
|
78
79
|
connect_timeout_ms: int = 250,
|
|
79
80
|
evaluation_timeout_ms: int = 12_000,
|
|
80
81
|
) -> PolicyVerdict:
|
|
@@ -85,6 +86,9 @@ def evaluate_policy(
|
|
|
85
86
|
"event": event,
|
|
86
87
|
"payload": dict(payload),
|
|
87
88
|
"cwd": cwd,
|
|
89
|
+
# An unknown profile is explicit. Omitting this field would let a new
|
|
90
|
+
# daemon's warm worker attribute the call to its own Hermes home.
|
|
91
|
+
"agentSettingsPath": agent_settings_path or "",
|
|
88
92
|
}
|
|
89
93
|
try:
|
|
90
94
|
body = json.dumps(
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "failproofai",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.12-beta.1",
|
|
4
4
|
"description": "Observability and enforcement for AI agent harnesses. 40 built-in policies hooked into 12 of them — Claude Code, Codex, Cursor, Hermes, OpenClaw and more — blocking the tool call before it runs. Local dashboard included, no account needed.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"failproofai": "./dist/cli.mjs",
|
|
@@ -81,7 +81,7 @@
|
|
|
81
81
|
"access": "public"
|
|
82
82
|
},
|
|
83
83
|
"devDependencies": {
|
|
84
|
-
"@anthropic-ai/sdk": "^0.
|
|
84
|
+
"@anthropic-ai/sdk": "^0.135.0",
|
|
85
85
|
"@mdx-js/mdx": "^3.1.1",
|
|
86
86
|
"@tailwindcss/postcss": "^4.3.1",
|
|
87
87
|
"@tanstack/react-virtual": "^3.14.10",
|
|
@@ -117,7 +117,7 @@
|
|
|
117
117
|
"nanoid": "3.3.18",
|
|
118
118
|
"postcss": "8.5.26",
|
|
119
119
|
"eslint-plugin-react-hooks": "7.0.1",
|
|
120
|
-
"vite": "8.
|
|
120
|
+
"vite": "8.1.6",
|
|
121
121
|
"undici": "7.29.1",
|
|
122
122
|
"brace-expansion": "5.0.12",
|
|
123
123
|
"sharp": "0.35.5",
|
|
@@ -125,15 +125,15 @@
|
|
|
125
125
|
"browserslist": "4.28.8"
|
|
126
126
|
},
|
|
127
127
|
"optionalDependencies": {
|
|
128
|
-
"@failproofai/failproofaid-linux-x64": "1.0.
|
|
129
|
-
"@failproofai/failproofaid-linux-arm64": "1.0.
|
|
130
|
-
"@failproofai/failproofaid-darwin-x64": "1.0.
|
|
131
|
-
"@failproofai/failproofaid-darwin-arm64": "1.0.
|
|
128
|
+
"@failproofai/failproofaid-linux-x64": "1.0.12-beta.1",
|
|
129
|
+
"@failproofai/failproofaid-linux-arm64": "1.0.12-beta.1",
|
|
130
|
+
"@failproofai/failproofaid-darwin-x64": "1.0.12-beta.1",
|
|
131
|
+
"@failproofai/failproofaid-darwin-arm64": "1.0.12-beta.1"
|
|
132
132
|
},
|
|
133
133
|
"failproofaidBinaries": {
|
|
134
|
-
"linux-x64": "
|
|
135
|
-
"linux-arm64": "
|
|
136
|
-
"darwin-x64": "
|
|
137
|
-
"darwin-arm64": "
|
|
134
|
+
"linux-x64": "df15e65b60066248038c8ac6d423bffcb0e38637e8a42fa22250afa111fd46ac",
|
|
135
|
+
"linux-arm64": "59d7ae758c8981c5e0a89eb64be18ebd278213525dd4447891a51be6bb018ed9",
|
|
136
|
+
"darwin-x64": "b0d3d39abaa02ed0a14dddc68277975a7a23e200830b7edbffdedde3af81ce73",
|
|
137
|
+
"darwin-arm64": "a6d343b5926e84c0eb437af307f85b69b3128f94c6e34acbf9d0b13a7c7e9d63"
|
|
138
138
|
}
|
|
139
139
|
}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read the daemon-owned profile roster. The telemetry agent_id and transcript
|
|
3
|
+
* path are not profile evidence. A scoped Cloud assignment is withheld unless
|
|
4
|
+
* this invocation resolves to one of the daemon's recorded config paths.
|
|
5
|
+
*/
|
|
6
|
+
import { lstatSync, readFileSync, statSync } from "node:fs";
|
|
7
|
+
import { homedir } from "node:os";
|
|
8
|
+
import { dirname, resolve } from "node:path";
|
|
9
|
+
import { agentRosterFile } from "./fp-home";
|
|
10
|
+
import { validAgentIdentity, type AgentIdentity } from "./agent-targets";
|
|
11
|
+
import type { HookScope, IntegrationType } from "./types";
|
|
12
|
+
|
|
13
|
+
/** `MAX_AGENTS` / `MAX_ROSTER_BYTES` in the daemon's `agent_roster.rs`. */
|
|
14
|
+
export const MAX_ROSTER_AGENTS = 256;
|
|
15
|
+
export const MAX_ROSTER_BYTES = 4_000_000;
|
|
16
|
+
|
|
17
|
+
const USER_SETTINGS: Partial<Record<IntegrationType, string>> = {
|
|
18
|
+
claude: ".claude/settings.json",
|
|
19
|
+
codex: ".codex/hooks.json",
|
|
20
|
+
copilot: ".copilot/hooks/failproofai.json",
|
|
21
|
+
cursor: ".cursor/hooks.json",
|
|
22
|
+
opencode: ".config/opencode/opencode.json",
|
|
23
|
+
pi: ".pi/agent/settings.json",
|
|
24
|
+
factory: ".factory/hooks.json",
|
|
25
|
+
devin: ".config/devin/config.json",
|
|
26
|
+
antigravity: ".gemini/config/hooks.json",
|
|
27
|
+
goose: ".agents/plugins/failproofai/hooks/hooks.json",
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const PROJECT_SETTINGS: Partial<Record<IntegrationType, string[]>> = {
|
|
31
|
+
claude: [".claude/settings.local.json", ".claude/settings.json"],
|
|
32
|
+
codex: [".codex/hooks.json"],
|
|
33
|
+
copilot: [".github/hooks/failproofai.json"],
|
|
34
|
+
cursor: [".cursor/hooks.json"],
|
|
35
|
+
opencode: [".opencode/opencode.json"],
|
|
36
|
+
pi: [".pi/settings.json"],
|
|
37
|
+
factory: [".factory/hooks.json"],
|
|
38
|
+
devin: [".devin/config.json"],
|
|
39
|
+
antigravity: [".agents/hooks.json"],
|
|
40
|
+
goose: [".agents/plugins/failproofai/hooks/hooks.json"],
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
function installedHookAt(path: string, cli: IntegrationType): boolean {
|
|
44
|
+
try {
|
|
45
|
+
const stat = statSync(path);
|
|
46
|
+
if (!stat.isFile() || stat.size > 131_072) return false;
|
|
47
|
+
const text = readFileSync(path, "utf8");
|
|
48
|
+
if (text.includes("failproofai")) return true;
|
|
49
|
+
// Pi's project entry is portable and relative to `.pi/settings.json`:
|
|
50
|
+
// `../pi-extension` contains no product name. Missing it here let a
|
|
51
|
+
// simultaneously installed user hook masquerade as this project's Pi.
|
|
52
|
+
if (cli !== "pi") return false;
|
|
53
|
+
const config: unknown = JSON.parse(text);
|
|
54
|
+
if (!config || typeof config !== "object" || Array.isArray(config)) return false;
|
|
55
|
+
const packages = (config as { packages?: unknown }).packages;
|
|
56
|
+
return Array.isArray(packages) && packages.some(
|
|
57
|
+
(entry) => typeof entry === "string" && /(?:^|\/)pi-extension\/?$/.test(entry),
|
|
58
|
+
);
|
|
59
|
+
} catch {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** Called in the originating hook process; the worker's env may be different. */
|
|
65
|
+
export function runtimeAgentSettingsPath(
|
|
66
|
+
cli: IntegrationType,
|
|
67
|
+
cwd?: string,
|
|
68
|
+
userHome = homedir(),
|
|
69
|
+
hookScope?: HookScope,
|
|
70
|
+
): string | null {
|
|
71
|
+
if (cli === "hermes") {
|
|
72
|
+
if (hookScope && hookScope !== "user") return null;
|
|
73
|
+
const home = process.env.HERMES_HOME;
|
|
74
|
+
return resolve(home?.trim() ? home : resolve(userHome, ".hermes"), "config.yaml");
|
|
75
|
+
}
|
|
76
|
+
if (cli === "openclaw") {
|
|
77
|
+
if (hookScope && hookScope !== "user") return null;
|
|
78
|
+
const config = process.env.OPENCLAW_CONFIG_PATH;
|
|
79
|
+
if (config?.trim()) return resolve(config);
|
|
80
|
+
const state = process.env.OPENCLAW_STATE_DIR || process.env.OPENCLAW_HOME;
|
|
81
|
+
return resolve(state?.trim() ? state : resolve(userHome, ".openclaw"), "openclaw.json");
|
|
82
|
+
}
|
|
83
|
+
const relative = USER_SETTINGS[cli];
|
|
84
|
+
if (!relative) return null;
|
|
85
|
+
const override = cli === "codex" ? process.env.CODEX_HOME
|
|
86
|
+
: cli === "claude" ? process.env.CLAUDE_CONFIG_DIR : undefined;
|
|
87
|
+
const user = resolve(override?.trim() ? override : userHome, override?.trim()
|
|
88
|
+
? cli === "codex" ? "hooks.json" : "settings.json"
|
|
89
|
+
: relative);
|
|
90
|
+
if (hookScope === "user") return user;
|
|
91
|
+
|
|
92
|
+
const scopeFiles = hookScope === "local"
|
|
93
|
+
? cli === "claude" ? [".claude/settings.local.json"] : []
|
|
94
|
+
: hookScope === "project"
|
|
95
|
+
? (PROJECT_SETTINGS[cli] ?? []).filter((name) => name !== ".claude/settings.local.json")
|
|
96
|
+
: PROJECT_SETTINGS[cli] ?? [];
|
|
97
|
+
const matches = new Set<string>();
|
|
98
|
+
if (hookScope === undefined && installedHookAt(user, cli)) matches.add(user);
|
|
99
|
+
let dir = resolve(cwd ?? process.cwd());
|
|
100
|
+
const userRoot = resolve(userHome);
|
|
101
|
+
for (let depth = 0; depth < 16 && dir !== userRoot; depth++) {
|
|
102
|
+
for (const candidate of scopeFiles) {
|
|
103
|
+
const path = resolve(dir, candidate);
|
|
104
|
+
if (installedHookAt(path, cli)) matches.add(path);
|
|
105
|
+
}
|
|
106
|
+
const parent = dirname(dir);
|
|
107
|
+
if (parent === dir) break;
|
|
108
|
+
dir = parent;
|
|
109
|
+
}
|
|
110
|
+
// No source hint can tell WHICH installed hook fired if both user and
|
|
111
|
+
// project/local scopes contain us. A guessed profile would let an exact
|
|
112
|
+
// assignment match another installation: withhold it instead.
|
|
113
|
+
if (matches.size > 1) return null;
|
|
114
|
+
if (hookScope === "project" || hookScope === "local") return matches.values().next().value ?? null;
|
|
115
|
+
return matches.values().next().value ?? user;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export function readRuntimeAgentIdentity(cli: IntegrationType, settingsPath: string | null): AgentIdentity | null {
|
|
119
|
+
if (!settingsPath) return null;
|
|
120
|
+
try {
|
|
121
|
+
const path = agentRosterFile();
|
|
122
|
+
const stat = lstatSync(path);
|
|
123
|
+
if (!stat.isFile() || (stat.mode & 0o077) !== 0 || stat.size > MAX_ROSTER_BYTES) return null;
|
|
124
|
+
const roster: unknown = JSON.parse(readFileSync(path, "utf8"));
|
|
125
|
+
if (!roster || typeof roster !== "object" || Array.isArray(roster)) return null;
|
|
126
|
+
const data = roster as Record<string, unknown>;
|
|
127
|
+
if (data.schemaVersion !== 1 || !Array.isArray(data.agents) || data.agents.length > MAX_ROSTER_AGENTS) return null;
|
|
128
|
+
const absolute = resolve(settingsPath);
|
|
129
|
+
const agent = data.agents.find((entry: unknown) => {
|
|
130
|
+
if (!entry || typeof entry !== "object" || Array.isArray(entry)) return false;
|
|
131
|
+
const record = entry as Record<string, unknown>;
|
|
132
|
+
return record.integration === cli && record.settingsPath === absolute &&
|
|
133
|
+
validAgentIdentity({ integration: record.integration, instanceId: record.instanceId });
|
|
134
|
+
});
|
|
135
|
+
const instanceId = (agent as Record<string, unknown> | undefined)?.instanceId;
|
|
136
|
+
return validAgentIdentity({ integration: cli, instanceId })
|
|
137
|
+
? { integration: cli, instanceId: instanceId as string }
|
|
138
|
+
: null;
|
|
139
|
+
} catch {
|
|
140
|
+
// Unavailable, malformed or old roster: never infer a profile from cwd,
|
|
141
|
+
// transcript, or the display name and widen a scoped deployment.
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Display labels from the daemon's roster, by `agt_` id (`claude / .claude-work`
|
|
148
|
+
* style: integration, then the profile label). For listings only; never an
|
|
149
|
+
* identity — `readRuntimeAgentIdentity` is the only thing that decides which
|
|
150
|
+
* profile a hook is. Empty when the roster cannot be read.
|
|
151
|
+
*/
|
|
152
|
+
export function readRosterLabels(): Map<string, string> {
|
|
153
|
+
const out = new Map<string, string>();
|
|
154
|
+
try {
|
|
155
|
+
const path = agentRosterFile();
|
|
156
|
+
const stat = lstatSync(path);
|
|
157
|
+
if (!stat.isFile() || (stat.mode & 0o077) !== 0 || stat.size > MAX_ROSTER_BYTES) return out;
|
|
158
|
+
const roster: unknown = JSON.parse(readFileSync(path, "utf8"));
|
|
159
|
+
if (!roster || typeof roster !== "object" || Array.isArray(roster)) return out;
|
|
160
|
+
const data = roster as Record<string, unknown>;
|
|
161
|
+
if (data.schemaVersion !== 1 || !Array.isArray(data.agents) || data.agents.length > MAX_ROSTER_AGENTS) return out;
|
|
162
|
+
for (const entry of data.agents) {
|
|
163
|
+
if (!entry || typeof entry !== "object" || Array.isArray(entry)) continue;
|
|
164
|
+
const record = entry as Record<string, unknown>;
|
|
165
|
+
if (typeof record.instanceId !== "string" || typeof record.profileLabel !== "string" || record.profileLabel === "") continue;
|
|
166
|
+
out.set(record.instanceId, record.profileLabel.slice(0, 80));
|
|
167
|
+
}
|
|
168
|
+
} catch {
|
|
169
|
+
// No roster: the bare ids are shown.
|
|
170
|
+
}
|
|
171
|
+
return out;
|
|
172
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/** Agent identity for enforcement, separate from the project-derived telemetry agent_id. */
|
|
2
|
+
import { INTEGRATION_TYPES, type IntegrationType } from "./types";
|
|
3
|
+
|
|
4
|
+
export interface AgentIdentity {
|
|
5
|
+
integration: IntegrationType;
|
|
6
|
+
instanceId: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface AgentTarget {
|
|
10
|
+
integration: IntegrationType;
|
|
11
|
+
instanceId?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const INSTANCE_ID_RE = /^agt_[0-9a-f]{16,32}$/;
|
|
15
|
+
const integrations = new Set<string>(INTEGRATION_TYPES);
|
|
16
|
+
|
|
17
|
+
export function validAgentIdentity(value: unknown): value is AgentIdentity {
|
|
18
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
19
|
+
const agent = value as Record<string, unknown>;
|
|
20
|
+
return Object.keys(agent).every((key) => key === "integration" || key === "instanceId") &&
|
|
21
|
+
typeof agent.integration === "string" && integrations.has(agent.integration) &&
|
|
22
|
+
typeof agent.instanceId === "string" && INSTANCE_ID_RE.test(agent.instanceId);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** Null/absent means all; a malformed selector is never silently treated as all. */
|
|
26
|
+
export function parseAgentTargets(value: unknown, schemaVersion: number): AgentTarget[] | undefined {
|
|
27
|
+
if (value === undefined || value === null) return undefined;
|
|
28
|
+
if (schemaVersion < 3 || !Array.isArray(value) || value.length < 1 || value.length > 32) {
|
|
29
|
+
throw new Error("invalid agentTargets in cloud-managed active manifest");
|
|
30
|
+
}
|
|
31
|
+
const seen = new Set<string>();
|
|
32
|
+
return value.map((raw) => {
|
|
33
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
34
|
+
throw new Error("invalid agentTargets in cloud-managed active manifest");
|
|
35
|
+
}
|
|
36
|
+
const entry = raw as Record<string, unknown>;
|
|
37
|
+
if (Object.keys(entry).some((key) => key !== "integration" && key !== "instanceId") ||
|
|
38
|
+
typeof entry.integration !== "string" || !integrations.has(entry.integration) ||
|
|
39
|
+
(entry.instanceId !== undefined &&
|
|
40
|
+
(typeof entry.instanceId !== "string" || !INSTANCE_ID_RE.test(entry.instanceId)))) {
|
|
41
|
+
throw new Error("invalid agentTargets in cloud-managed active manifest");
|
|
42
|
+
}
|
|
43
|
+
const key = `${entry.integration}\0${entry.instanceId ?? ""}`;
|
|
44
|
+
if (seen.has(key)) throw new Error("duplicate agentTargets in cloud-managed active manifest");
|
|
45
|
+
seen.add(key);
|
|
46
|
+
return {
|
|
47
|
+
integration: entry.integration as IntegrationType,
|
|
48
|
+
...(entry.instanceId !== undefined ? { instanceId: entry.instanceId as string } : {}),
|
|
49
|
+
};
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** An unknown runtime identity cannot widen any scoped assignment. */
|
|
54
|
+
export function agentTargetsMatch(targets: readonly AgentTarget[] | undefined, agent: AgentIdentity | null): boolean {
|
|
55
|
+
if (targets === undefined) return true;
|
|
56
|
+
if (!validAgentIdentity(agent)) return false;
|
|
57
|
+
return targets.some((target) =>
|
|
58
|
+
target.integration === agent.integration &&
|
|
59
|
+
(target.instanceId === undefined || target.instanceId === agent.instanceId));
|
|
60
|
+
}
|
|
@@ -63,7 +63,7 @@ import {
|
|
|
63
63
|
type CollectorSettings,
|
|
64
64
|
} from "./collector-config";
|
|
65
65
|
import { recoverCredentialRefusals } from "./credential-recovery";
|
|
66
|
-
import { clearActiveCloudManagedPolicies } from "./cloud-managed-policies";
|
|
66
|
+
import { clearActiveCloudManagedPolicies, readCloudJevState } from "./cloud-managed-policies";
|
|
67
67
|
import { rmSync } from "node:fs";
|
|
68
68
|
import { backfillRequestPath } from "./backfill-request";
|
|
69
69
|
|
|
@@ -180,11 +180,18 @@ export interface JevConnectOutcome {
|
|
|
180
180
|
* is stored; `jev setup --provider failproofai` switches Jev on.
|
|
181
181
|
*/
|
|
182
182
|
optIn?: true;
|
|
183
|
+
/**
|
|
184
|
+
* A `--no-transcripts` connection removed this `jev.json`: it named the
|
|
185
|
+
* FailproofAI Cloud provider and was not switched off (the rule `config
|
|
186
|
+
* --disconnect` uses), so Jev through FailproofAI Cloud stays off here.
|
|
187
|
+
* Set with `optIn`.
|
|
188
|
+
*/
|
|
189
|
+
removedCloudConfig?: string;
|
|
183
190
|
/**
|
|
184
191
|
* A `--no-transcripts` connection found a `jev.json` already in place that
|
|
185
|
-
* keeps Jev running through FailproofAI Cloud, in this mode
|
|
186
|
-
*
|
|
187
|
-
*
|
|
192
|
+
* keeps Jev running through FailproofAI Cloud, in this mode, and could not
|
|
193
|
+
* remove it (see `removedCloudConfig`). A connection that asked for
|
|
194
|
+
* decisions only is told that Jev still sends more than that.
|
|
188
195
|
*/
|
|
189
196
|
stillOn?: "observe" | "enforce";
|
|
190
197
|
/**
|
|
@@ -316,7 +323,12 @@ export async function connectToCloud(input: ConnectInput): Promise<ConnectOutcom
|
|
|
316
323
|
prev.ingest ? { token: prev.ingest.key, url: prev.ingest.url } : undefined,
|
|
317
324
|
prev.jev ? { token: prev.jev.key, url: prev.jev.url } : undefined,
|
|
318
325
|
].some((slot) => slot && (slot.token !== input.token || !sameOrigin(slot.url)));
|
|
319
|
-
|
|
326
|
+
// Both sides name their organisation: that alone decides. The same org on
|
|
327
|
+
// a new URL (http → https, a new host for the same Cloud) is a reconnect,
|
|
328
|
+
// not a switch — clearing its deployment would drop enforcement until the
|
|
329
|
+
// next poll, and "Switched from X to X" says nothing true.
|
|
330
|
+
const sameKnownOrg = Boolean(prev.org?.id && known?.orgId && prev.org.id === known.orgId);
|
|
331
|
+
const orgSwitch = hadConnection && !sameKnownOrg && (
|
|
320
332
|
(prev.org?.id && known?.orgId && prev.org.id !== known.orgId) ||
|
|
321
333
|
((!prev.org?.id || !known?.orgId) && keyChanged) ||
|
|
322
334
|
(previousPolicy && !sameOrigin(previousPolicy.url)) ||
|
|
@@ -425,23 +437,37 @@ export async function connectToCloud(input: ConnectInput): Promise<ConnectOutcom
|
|
|
425
437
|
writeJevCloudCredential({ url: new URL(input.url).origin, key: input.token });
|
|
426
438
|
// Loaded here and nowhere earlier: a connect whose key does not carry Jev
|
|
427
439
|
// pulls in none of the Jev modules.
|
|
428
|
-
const { cloudJevRunningMode, existingJevConfig,
|
|
440
|
+
const { cloudJevRunningMode, existingJevConfig, removeCloudJevConfig, writeCloudJevConfig } = await import(
|
|
441
|
+
"./jev-cloud-connection"
|
|
442
|
+
);
|
|
429
443
|
if (input.sessions === true) {
|
|
430
|
-
outcome.jev = { ok: true, config:
|
|
444
|
+
outcome.jev = { ok: true, config: writeCloudJevConfig(input.url) };
|
|
431
445
|
} else {
|
|
432
446
|
// `--no-transcripts` never switches Jev on (the user's decision). Jev
|
|
433
447
|
// sends each checked tool call and the recent prompt to FailproofAI
|
|
434
448
|
// Cloud, and someone who just asked for decisions only has not asked
|
|
435
449
|
// for that. The key is stored all the same, so opting in later is one
|
|
436
|
-
// command with no key to paste; jev.json is not written.
|
|
437
|
-
//
|
|
438
|
-
//
|
|
439
|
-
//
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
450
|
+
// command with no key to paste; jev.json is not written.
|
|
451
|
+
//
|
|
452
|
+
// And a jev.json naming the FailproofAI Cloud provider — left by an
|
|
453
|
+
// earlier connect with transcripts on — is removed, by exactly the rule
|
|
454
|
+
// `config --disconnect` uses (`removeCloudJevConfig`: the Cloud's file,
|
|
455
|
+
// not switched off). Kept, it went on sending this machine's tool calls
|
|
456
|
+
// to FailproofAI Cloud with no Cloud mode set (e2e-c10 O2, user
|
|
457
|
+
// decision). A BYOK file is its owner's and stays, reported as ever; so
|
|
458
|
+
// does a Cloud file switched off, the owner's opt-out.
|
|
459
|
+
const removal = removeCloudJevConfig();
|
|
460
|
+
if (removal.status === "removed") {
|
|
461
|
+
outcome.jev = { ok: true, optIn: true, removedCloudConfig: removal.path };
|
|
462
|
+
} else {
|
|
463
|
+
const existing = existingJevConfig(input.url);
|
|
464
|
+
// Still sending (the removal failed): said, or "Decisions only."
|
|
465
|
+
// would be the last word while Jev keeps sending.
|
|
466
|
+
const stillOn = existing ? cloudJevRunningMode() : null;
|
|
467
|
+
outcome.jev = existing
|
|
468
|
+
? { ok: true, config: existing, ...(stillOn ? { stillOn } : {}) }
|
|
469
|
+
: { ok: true, optIn: true };
|
|
470
|
+
}
|
|
445
471
|
}
|
|
446
472
|
} else if (known) {
|
|
447
473
|
// Introspect ANSWERED, and the key does not carry Jev. This connection
|
|
@@ -491,6 +517,14 @@ export async function connectToCloud(input: ConnectInput): Promise<ConnectOutcom
|
|
|
491
517
|
* this machine now, and — the one case worth a second line — why an existing
|
|
492
518
|
* `jev.json` was not touched.
|
|
493
519
|
*/
|
|
520
|
+
function safeCloudJev(): ReturnType<typeof readCloudJevState> {
|
|
521
|
+
try {
|
|
522
|
+
return readCloudJevState();
|
|
523
|
+
} catch {
|
|
524
|
+
return { jevMode: null, deployment: null, errors: [] };
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
|
|
494
528
|
export function jevLines(outcome: ConnectOutcome): string[] {
|
|
495
529
|
const jev = outcome.jev;
|
|
496
530
|
if (!jev) return [];
|
|
@@ -503,6 +537,11 @@ export function jevLines(outcome: ConnectOutcome): string[] {
|
|
|
503
537
|
if (!jev.ok) {
|
|
504
538
|
return [` Jev not through FailproofAI Cloud: ${jev.reason ?? `that key does not carry \`${PERMISSION_JEV}\``}.`];
|
|
505
539
|
}
|
|
540
|
+
if (jev.optIn && jev.removedCloudConfig) {
|
|
541
|
+
return [
|
|
542
|
+
` Jev removed ${jev.removedCloudConfig}, which sent each checked tool call and the recent prompt to FailproofAI Cloud: Jev via FailproofAI Cloud stays off on this machine (--no-transcripts). To switch it on: \`failproofai jev setup --provider failproofai\`.`,
|
|
543
|
+
];
|
|
544
|
+
}
|
|
506
545
|
if (jev.optIn) {
|
|
507
546
|
// One line, and nothing that reads as "on": this connection asked for
|
|
508
547
|
// decisions only, and Jev would send more than that.
|
|
@@ -511,20 +550,51 @@ export function jevLines(outcome: ConnectOutcome): string[] {
|
|
|
511
550
|
];
|
|
512
551
|
}
|
|
513
552
|
const config = jev.config;
|
|
514
|
-
if (!config || config.status === "written") {
|
|
515
|
-
// Plain http (loopback only) is accepted in observe mode and nowhere else
|
|
516
|
-
//
|
|
517
|
-
|
|
553
|
+
if (!config || config.status === "written" || config.status === "repointed") {
|
|
554
|
+
// Plain http (loopback only) is accepted in observe mode and nowhere else:
|
|
555
|
+
// in enforce mode — set here, or by FailproofAI Cloud — Jev is OFF on this
|
|
556
|
+
// machine rather than enforcing, by the CLI and the dashboard alike.
|
|
557
|
+
const plainHttp = config !== undefined && new URL(config.baseUrl).protocol === "http:";
|
|
558
|
+
const httpLine = " Over plain http Jev runs only in observe mode: enforce (set here or by FailproofAI Cloud) turns it off on this machine. For enforce, reconnect with `failproofai config --token <key> --url https://…`.";
|
|
559
|
+
// What happened to jev.json, said first on a re-point; the mode lines
|
|
560
|
+
// below are the same for both (N1).
|
|
561
|
+
const lead =
|
|
562
|
+
config?.status === "repointed" ? [` Jev ${config.path} now points here instead of ${config.from}.`] : [];
|
|
563
|
+
const indent = lead.length > 0 ? " " : " Jev ";
|
|
564
|
+
// FailproofAI Cloud already set this machine's Jev mode (a reconnect, or a
|
|
565
|
+
// deployment that arrived first): that mode and Cloud's own checks decide,
|
|
566
|
+
// not the local jev.json or the packs installed here.
|
|
567
|
+
const cloudJev = safeCloudJev();
|
|
568
|
+
if (cloudJev.jevMode !== null) {
|
|
569
|
+
if (cloudJev.jevMode === "off") return [...lead, `${indent}off on this machine: FailproofAI Cloud set its Jev mode to off.`];
|
|
570
|
+
if (plainHttp && cloudJev.jevMode === "enforce") {
|
|
571
|
+
return [
|
|
572
|
+
...lead,
|
|
573
|
+
`${indent}off on this machine: FailproofAI Cloud set enforce, and over plain http Jev runs only in observe mode. For enforce, reconnect with \`failproofai config --token <key> --url https://…\`.`,
|
|
574
|
+
];
|
|
575
|
+
}
|
|
576
|
+
return [
|
|
577
|
+
...lead,
|
|
578
|
+
`${indent}on through FailproofAI Cloud, mode ${cloudJev.jevMode} (set by FailproofAI Cloud); the Jev checks it deployed here run on FailproofAI Cloud.`,
|
|
579
|
+
];
|
|
580
|
+
}
|
|
581
|
+
// No Cloud deployment has been read on this machine yet (a first connect,
|
|
582
|
+
// or the first after a disconnect): FailproofAI Cloud's Jev mode, when it
|
|
583
|
+
// sets one, arrives with that deployment and overrides jev.json — so the
|
|
584
|
+
// local mode is said as the fallback it is, not as a promise (N3).
|
|
585
|
+
const localMode = config?.status === "repointed" ? config.mode : "observe";
|
|
586
|
+
if (localMode === "off") {
|
|
587
|
+
return [...lead, `${indent}switched off in ${config?.path ?? "jev.json"} (mode off). FailproofAI Cloud's Jev mode, if it sets one, arrives with its first deployment. To turn it on: \`failproofai jev setup --mode observe\`.`];
|
|
588
|
+
}
|
|
518
589
|
return [
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
//
|
|
590
|
+
...lead,
|
|
591
|
+
`${indent}configured through FailproofAI Cloud; waiting for FailproofAI Cloud's Jev mode, which arrives with this machine's first deployment (within ~30 s) and decides. Until then, and if Cloud sets none: ${localMode} (${config?.path ?? "jev.json"}). Check with \`failproofai jev status\`.`,
|
|
592
|
+
// The package ships no Jev checks, so local "on" asks nothing until a
|
|
593
|
+
// pack gives it some. Checks FailproofAI Cloud deploys run on Cloud.
|
|
522
594
|
...(jevChecksDeclared()
|
|
523
595
|
? []
|
|
524
|
-
: ["
|
|
525
|
-
plainHttp
|
|
526
|
-
? " Enforce needs an https FailproofAI Cloud URL: reconnect with `failproofai config --token <key> --url https://…`. Over plain http Jev stays in observe mode."
|
|
527
|
-
: " Enforce it with `failproofai jev setup --mode enforce`, or from the dashboard.",
|
|
596
|
+
: [" No Jev checks are installed on this machine; checks FailproofAI Cloud deploys here run on Cloud. To add local ones: `failproofai policies add FailproofAI/jev-policies`."]),
|
|
597
|
+
...(plainHttp ? [httpLine] : []),
|
|
528
598
|
];
|
|
529
599
|
}
|
|
530
600
|
if (config.status === "kept") {
|
|
@@ -409,12 +409,13 @@ export function runDisconnectCommand(): CommandResult {
|
|
|
409
409
|
// machine that had deliberately left its organisation went on being governed
|
|
410
410
|
// by whatever deployment was current when it left, indefinitely, while
|
|
411
411
|
// `--status` reported it as unconnected.
|
|
412
|
-
const stoppedManaged = clearActiveCloudManagedPolicies();
|
|
413
412
|
// Back to OSS. Leaving mode = "cloud" with no credentials would describe a
|
|
414
413
|
// machine that does not exist, and every cloud code path keys off this flag
|
|
415
414
|
// rather than off "is a token lying around" precisely so that a disconnected
|
|
416
415
|
// machine is provably silent instead of silent-by-happenstance.
|
|
417
416
|
updateConfig({ mode: "oss" });
|
|
417
|
+
const sharedPolicyRoot = process.env.FAILPROOFAI_CLOUD_POLICY_DIR !== undefined;
|
|
418
|
+
const stoppedManaged = clearActiveCloudManagedPolicies();
|
|
418
419
|
|
|
419
420
|
const jevLines =
|
|
420
421
|
jevConfig.status === "removed"
|
|
@@ -450,10 +451,12 @@ export function runDisconnectCommand(): CommandResult {
|
|
|
450
451
|
const lines = [
|
|
451
452
|
"Disconnected from FailproofAI Cloud.",
|
|
452
453
|
"",
|
|
453
|
-
stoppedManaged
|
|
454
|
-
? " Cloud-managed policies stop being enforced and stop being refreshed
|
|
454
|
+
stoppedManaged || (sharedPolicyRoot && !!existing)
|
|
455
|
+
? " Cloud-managed policies stop being enforced and stop being refreshed, and any Jev mode\n" +
|
|
456
|
+
" FailproofAI Cloud set goes with them (its Jev checks never ran on this machine).\n" +
|
|
455
457
|
" Local builtin, custom and convention policies are unaffected."
|
|
456
458
|
: " Local builtin, custom and convention policies are unaffected.",
|
|
459
|
+
...(sharedPolicyRoot ? [" An overridden Cloud policy directory was left untouched; OSS mode ignores its old deployment."] : []),
|
|
457
460
|
...jevLines,
|
|
458
461
|
];
|
|
459
462
|
if (removedIngest) {
|
|
@@ -589,4 +592,4 @@ export function connectionStatusLines(daemonStatus = daemonServiceStatus): strin
|
|
|
589
592
|
kitRows(report.rows, opts),
|
|
590
593
|
report.warnings.length > 0 ? warning(report.warnings, opts) : null,
|
|
591
594
|
);
|
|
592
|
-
}
|
|
595
|
+
}
|