failproofai 1.0.12-beta.2 → 1.0.13-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 +13 -13
- package/.next/standalone/.next/prerender-manifest.json +3 -3
- package/.next/standalone/.next/required-server-files.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page/build-manifest.json +2 -2
- package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page.js +2 -1
- package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_global-error.html +1 -1
- package/.next/standalone/.next/server/app/_global-error.rsc +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 +2 -2
- package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/_not-found/page.js +4 -3
- package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_not-found.html +1 -1
- package/.next/standalone/.next/server/app/_not-found.rsc +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 +6 -5
- 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 +27 -26
- 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 +4 -3
- 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 +6 -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 -5
- 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 -5
- 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 +6 -5
- 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 +4 -3
- 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 +2 -2
- package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +2 -2
- package/.next/standalone/.next/server/app/audit/page.js +7 -6
- 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 +2 -2
- package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/page.js +6 -5
- package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/policies/page/build-manifest.json +2 -2
- package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +14 -14
- package/.next/standalone/.next/server/app/policies/page.js +5 -4
- package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page/build-manifest.json +2 -2
- package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page.js +21 -20
- package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/build-manifest.json +2 -2
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js +10 -9
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/projects/page/build-manifest.json +2 -2
- package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/projects/page.js +7 -6
- package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/settings/page/build-manifest.json +2 -2
- package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +8 -8
- package/.next/standalone/.next/server/app/settings/page.js +6 -5
- 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]__0vt9i6fqinjne._.js → [externals]__1h83uo-b1b6-2._.js} +1 -1
- package/.next/standalone/.next/server/chunks/[externals]__214wn4wh2x79y._.js +3 -0
- package/.next/standalone/.next/server/chunks/{[externals]__1rlxpymm37wel._.js → [root-of-the-server]__031qp1lkow_kc._.js} +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__038kwryp970nh._.js +3 -0
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0_hsnj_a2mvl_._.js → [root-of-the-server]__03s1za0hn71yp._.js} +2 -2
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0wg9dk8x8bnau._.js → [root-of-the-server]__07a0sa6fuw5_b._.js} +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__08atcie7jzswm._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__08dchfudh2_4f._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0car70pylmvor._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0spt0kv8azrpl._.js +1 -1
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__12kq3x-h7t7i1._.js → [root-of-the-server]__0yvyp5b7jmlc4._.js} +2 -2
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__02vous7mpi2xm._.js → [root-of-the-server]__145vo_drnuvas._.js} +2 -2
- package/.next/standalone/.next/server/chunks/{[externals]__0h0p9dmv_e7r7._.js → [root-of-the-server]__1a2d0ewycsp6k._.js} +2 -2
- package/.next/standalone/.next/server/chunks/{[externals]__1_407huhlmj1m._.js → [root-of-the-server]__1am_1tz0o0aqz._.js} +2 -2
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__03i5o4a840guz._.js → [root-of-the-server]__1gxfzuvpyw30j._.js} +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1j6kfp0vzu5rw._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1l0ayum_hqqsw._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1lh8c0mmhdrbj._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1o9rznwc0w7og._.js +3 -0
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0f_4g-vazrvxv._.js → [root-of-the-server]__1o_622x0fglpr._.js} +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1oclamblhzhrf._.js +68 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1v1-l-83czzsr._.js +63 -0
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__1a5zkndjwlc13._.js → [root-of-the-server]__1wwi53kkqhnfi._.js} +1 -1
- package/.next/standalone/.next/server/chunks/{_1y590mjzpkbos._.js → _02sa8fcu9_9xo._.js} +2 -2
- 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/_1-2owkp-1_987._.js +1 -1
- package/.next/standalone/.next/server/chunks/_13ltj8a9z92o8._.js +1 -1
- package/.next/standalone/.next/server/chunks/_15k37au70vjvg._.js +1 -1
- package/.next/standalone/.next/server/chunks/_18rfu4__wjhwb._.js +1 -1
- package/.next/standalone/.next/server/chunks/_1ek68lnh2daur._.js +2 -2
- package/.next/standalone/.next/server/chunks/_1fz8m31sndkcu._.js +1 -1
- package/.next/standalone/.next/server/chunks/_1ogwigfb0163w._.js +1 -1
- package/.next/standalone/.next/server/chunks/_1vslkoe35wok6._.js +1 -1
- package/.next/standalone/.next/server/chunks/node_modules_@opentelemetry_api_build_esm_index_0oo58a7rymoxh.js +3 -0
- package/.next/standalone/.next/server/chunks/node_modules_@opentelemetry_api_build_esm_index_1jp9ij0_ddtgk.js +3 -0
- package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_01r25oigsgz07._.js +2 -2
- package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_09z9-p77cu37y._.js +2 -2
- package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4vkpxxu7._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0ffu2-38y03ic._.js → [root-of-the-server]__021vebe-4il8s._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__075uro8t92s0_._.js +14 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__08ch3staq3ejw._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{[externals]__12qr51qgrrt6o._.js → [root-of-the-server]__097i34ct1o88x._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0alpzjn3450sr._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0aup10z2o8zc1._.js +3 -0
- 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]__0bioghlkjf7s7._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__01j58mdcdw0vn._.js → [root-of-the-server]__0ed1zh4scn7-k._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0naevg4bcoh54._.js → [root-of-the-server]__0evgy902m9h5e._.js} +2 -2
- 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]__00l2u6j86cb8y._.js → [root-of-the-server]__0mhtkwwx1pxcq._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0nhm28v58ty9z._.js +3 -0
- 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]__0vse4qi496ol-._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__17r4zrwanhp6r._.js → [root-of-the-server]__0yb3u36xjy3b9._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0g8b0kyorya-t._.js → [root-of-the-server]__0ywj2u6ovfm_5._.js} +1 -1
- 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]__0zn1d4blhd3bu._.js → [root-of-the-server]__10v5cyxvj64j4._.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]__190xwrr5zrfi3._.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]__1vx7o8ukefudh._.js → [root-of-the-server]__1guwlpkyurdn9._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1k96jctukf65_._.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]__1sj-wn2jp6va5._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1vofkb2oq7p7e._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1s2-ck3k3rsoo._.js → [root-of-the-server]__20dt376-socef._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1lnfv02ucky7m._.js → [root-of-the-server]__2158020r_amn9._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{_1fw0_nzkae5ao._.js → _0bc4f4quq6w47._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/_0bseae9u7g98r._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_0eoura3_9gjb-._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_0mouhaflye1ro._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_0ouu886szh6yj._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_0pedwblqdoh58._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_1_ozgifqv1ssi._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_1djqs9i27e4kg._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_20hn4gn87nsjc._.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_components_project-list_tsx_1ke6anr0vt64h._.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_09s4n108bqreq._.js → node_modules_0ptcnmeaxvd_a._.js} +22 -2
- package/.next/standalone/.next/server/chunks/ssr/node_modules_@opentelemetry_api_build_esm_index_0ntwr8lzj6p2i.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/{node_modules_html-to-image_es_index_1fv03uigni8s5.js → node_modules_html-to-image_es_index_1jwgv0pf-gy96.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_0bz67659f5z-3._.js +32 -0
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_0janj0i6dqko7._.js +3 -3
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_0ocrceo0c9psx._.js +32 -0
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_1alv566ojmz5j._.js +32 -0
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_1khq67j4vo9y4._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_shared_lib_0ftnv26hg1lry._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/node_modules_posthog-node_dist_entrypoints_index_node_mjs_0dagmbznysrc2._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/node_modules_posthog-node_dist_entrypoints_index_node_mjs_11bnuznb72p7z._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/package_json_[json]_cjs_013tntikdft59._.js +1 -1
- package/.next/standalone/.next/server/middleware-build-manifest.js +13 -13
- 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/0cbom4-ijx_a_.js +1 -0
- package/.next/standalone/.next/static/chunks/0u5weo5jdn2s8.js +1 -0
- package/.next/standalone/.next/static/chunks/{1c_jf6g5wnslk.js → 18-icoqze51kl.js} +1 -1
- package/.next/standalone/.next/static/chunks/2d-u90dt4-8rd.js +6 -0
- package/.next/standalone/.next/static/chunks/2n-bzb7pxe7hu.js +1 -0
- package/.next/standalone/.next/static/chunks/{2o6d37j425uci.js → 2zc7lg-jq353g.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0tbm3vjm62h-2.js → 33djjf12bhcsv.js} +1 -1
- package/.next/standalone/.next/static/chunks/{42xptz88mtq3x.js → 38u_i3j5funpi.js} +1 -1
- package/.next/standalone/.next/static/chunks/{20py8k1gd_i1m.js → 3symuj7t4js-c.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0ay__-d2h1xb5.js → 3vzut6zpdrvtx.js} +1 -1
- package/.next/standalone/.next/static/chunks/{063al_q720fkj.js → 3xgxl1s_in776.js} +2 -2
- package/.next/standalone/SECURITY.md +20 -4
- package/.next/standalone/fp-cloud-cli/CHANGELOG.md +34 -1
- package/.next/standalone/fp-cloud-cli/README.md +120 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/_version.py +1 -1
- package/.next/standalone/fp-cloud-cli/fp_cli/app.py +15 -1
- package/.next/standalone/fp-cloud-cli/fp_cli/client.py +198 -7
- package/.next/standalone/fp-cloud-cli/fp_cli/cloud_output.py +523 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/_cloud.py +45 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/_write.py +3 -1
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/account_cmds.py +171 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/agent_cmds.py +80 -7
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/alerts_cmds.py +23 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/audits_cmds.py +2 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/contracts_cmds.py +67 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/dashboards_cmds.py +159 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/evaluators_cmds.py +380 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/events_cmds.py +14 -1
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/incidents_cmds.py +82 -6
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/list_cmds.py +4 -1
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/orgs_cmds.py +17 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/policies_cmds.py +143 -1
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/queries_cmds.py +70 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/sentiment_cmds.py +49 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/sessions_cmds.py +95 -1
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/settings_cmds.py +2 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/usage_cmds.py +21 -1
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/users_cmds.py +14 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/errors.py +3 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/evaluator_spec.py +266 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/output.py +187 -81
- package/.next/standalone/fp-cloud-cli/fp_cli/theme.py +21 -24
- package/.next/standalone/fp-cloud-cli/skill/SKILL.md +124 -23
- package/.next/standalone/fp-cloud-cli/skill/agents/openai.yaml +2 -1
- package/.next/standalone/fp-cloud-cli/skill/references/commands.md +168 -16
- package/.next/standalone/fp-cloud-cli/tests/fake_cloud_smoke.py +312 -0
- package/.next/standalone/fp-cloud-cli/tests/test_cloud_account.py +125 -0
- package/.next/standalone/fp-cloud-cli/tests/test_cloud_agent.py +253 -0
- package/.next/standalone/fp-cloud-cli/tests/test_cloud_human_views.py +287 -0
- package/.next/standalone/fp-cloud-cli/tests/test_cloud_observability.py +116 -0
- package/.next/standalone/fp-cloud-cli/tests/test_cloud_transport.py +141 -0
- package/.next/standalone/fp-cloud-cli/tests/test_commands.py +3 -3
- package/.next/standalone/fp-cloud-cli/tests/test_dashboards_agent.py +3 -3
- package/.next/standalone/fp-cloud-cli/tests/test_evaluator_authoring.py +449 -0
- package/.next/standalone/fp-cloud-cli/tests/test_facets.py +1 -1
- package/.next/standalone/fp-cloud-cli/tests/test_help_table_coverage.py +15 -0
- package/.next/standalone/fp-cloud-cli/tests/test_operator.py +1 -1
- package/.next/standalone/fp-cloud-cli/tests/test_orgs.py +1 -1
- package/.next/standalone/fp-cloud-cli/tests/test_output.py +37 -37
- package/.next/standalone/fp-cloud-cli/tests/test_round4_behaviour.py +144 -0
- package/.next/standalone/fp-cloud-cli/tests/test_screen_language.py +80 -0
- package/.next/standalone/fp-cloud-cli/tests/test_session_reevaluate.py +33 -0
- package/.next/standalone/fp-cloud-cli/tests/test_staging_parity.py +198 -0
- package/.next/standalone/fp-cloud-cli/tests/test_whoami.py +1 -1
- package/.next/standalone/fp-cloud-cli/uv.lock +4 -4
- 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/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 +24 -24
- package/.next/standalone/node_modules/next/dist/compiled/next-server/app-page-turbo.runtime.prod.js +26 -26
- package/.next/standalone/node_modules/next/dist/compiled/next-server/app-route-turbo.runtime.prod.js +3 -3
- package/.next/standalone/node_modules/next/dist/compiled/next-server/pages-turbo.runtime.prod.js +13 -13
- package/.next/standalone/node_modules/next/dist/lib/patch-incorrect-lockfile.js +3 -3
- package/.next/standalone/node_modules/next/dist/server/app-render/app-render.js +41 -40
- package/.next/standalone/node_modules/next/dist/server/app-render/async-local-storage.js +1 -1
- package/.next/standalone/node_modules/next/dist/server/app-render/dynamic-rendering-validation.js +814 -0
- package/.next/standalone/node_modules/next/dist/server/app-render/dynamic-rendering.js +1 -799
- package/.next/standalone/node_modules/next/dist/server/base-server.js +39 -5
- 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/dedupe-fetch.js +4 -43
- package/.next/standalone/node_modules/next/dist/server/lib/patch-fetch-symbol.js +13 -0
- package/.next/standalone/node_modules/next/dist/server/lib/patch-fetch.js +3 -7
- package/.next/standalone/node_modules/next/dist/server/lib/router-server.js +3 -3
- package/.next/standalone/node_modules/next/dist/server/lib/router-utils/instrumentation-globals.external.js +77 -12
- package/.next/standalone/node_modules/next/dist/server/lib/start-server.js +1 -1
- package/.next/standalone/node_modules/next/dist/server/lib/trace/constants.js +12 -0
- package/.next/standalone/node_modules/next/dist/server/lib/trace/tracer.js +30 -14
- package/.next/standalone/node_modules/next/dist/server/next-server.js +10 -11
- package/.next/standalone/node_modules/next/dist/server/route-modules/pages/pages-handler.js +29 -23
- package/.next/standalone/node_modules/next/dist/server/route-modules/route-module.js +85 -8
- package/.next/standalone/node_modules/next/dist/server/use-cache/use-cache-wrapper.js +1 -1
- package/.next/standalone/node_modules/next/dist/server/web/adapter.js +124 -65
- package/.next/standalone/node_modules/next/dist/server/web/forward-trace-context.js +102 -0
- 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 +10 -10
- package/.next/standalone/node_modules/react/cjs/react.production.js +1 -1
- package/.next/standalone/node_modules/react/package.json +1 -1
- package/.next/standalone/node_modules/react-dom/cjs/react-dom-server-legacy.browser.production.js +1 -1
- package/.next/standalone/node_modules/react-dom/cjs/react-dom-server-legacy.node.production.js +1 -1
- package/.next/standalone/node_modules/react-dom/cjs/react-dom-server.browser.production.js +31 -27
- package/.next/standalone/node_modules/react-dom/cjs/react-dom-server.edge.production.js +33 -27
- package/.next/standalone/node_modules/react-dom/cjs/react-dom-server.node.production.js +38 -30
- package/.next/standalone/node_modules/react-dom/cjs/react-dom.production.js +1 -1
- package/.next/standalone/node_modules/react-dom/package.json +2 -2
- package/.next/standalone/package.json +10 -10
- package/.next/standalone/sdk/python/CHANGELOG.md +8 -4
- package/.next/standalone/sdk/python/failproofai_sdk/evaluator/source.py +2 -2
- package/.next/standalone/sdk/python/pyproject.toml +2 -7
- package/.next/standalone/sdk/python/skill/references/frameworks.md +0 -15
- package/.next/standalone/sdk/python/tests/test_docs.py +1 -4
- package/.next/standalone/sdk/python/tests/test_evaluator_source.py +1 -1
- package/.next/standalone/sdk/python/tests/test_packaging.py +4 -7
- package/.next/standalone/sdk/python/tests/test_zero_dependencies.py +2 -13
- package/.next/standalone/sdk/python/uv.lock +43 -905
- package/.next/standalone/sdk/typescript/CHANGELOG.md +52 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/ai-5/package-lock.json +7 -7
- package/.next/standalone/sdk/typescript/integration/fixtures/ai-5/package.json +2 -2
- package/.next/standalone/sdk/typescript/integration/fixtures/ai-6/package-lock.json +7 -7
- package/.next/standalone/sdk/typescript/integration/fixtures/ai-6/package.json +1 -1
- package/.next/standalone/sdk/typescript/integration/fixtures/ai-7/package-lock.json +7 -7
- package/.next/standalone/sdk/typescript/integration/fixtures/ai-7/package.json +1 -1
- package/.next/standalone/sdk/typescript/integration/fixtures/langchain-1/package-lock.json +4 -4
- package/.next/standalone/sdk/typescript/integration/fixtures/langchain-1/package.json +1 -1
- package/.next/standalone/sdk/typescript/integration/fixtures/langchain-dup-core/package-lock.json +4 -4
- package/.next/standalone/sdk/typescript/integration/fixtures/langchain-dup-core/package.json +1 -1
- package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.11/package-lock.json +3 -3
- package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.11/package.json +3 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.12/package-lock.json +4 -4
- package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.12/package.json +1 -1
- package/.next/standalone/sdk/typescript/integration/fixtures/mastra-0/package-lock.json +25 -25
- package/.next/standalone/sdk/typescript/integration/fixtures/mastra-0/package.json +1 -1
- package/.next/standalone/sdk/typescript/integration/fixtures/mastra-1/package-lock.json +34 -22
- package/.next/standalone/sdk/typescript/integration/fixtures/mastra-1/package.json +3 -2
- package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/package-lock.json +10 -10
- package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/package.json +1 -1
- package/.next/standalone/sdk/typescript/integration/fixtures/runtimes/deno-npm.ts +1 -1
- package/.next/standalone/sdk/typescript/integration/fixtures/runtimes/package-lock.json +7 -7
- package/.next/standalone/sdk/typescript/integration/fixtures/runtimes/package.json +1 -1
- package/.next/standalone/server.js +1 -1
- package/README.md +0 -6
- package/dist/cli.mjs +87 -38
- package/dist/worker.mjs +73 -28
- package/hermes-plugin/plugin.yaml +1 -1
- package/openclaw-plugin/daemon-client.js +254 -0
- package/openclaw-plugin/hooks.js +187 -0
- package/openclaw-plugin/index.js +17 -211
- package/package.json +10 -10
- package/scripts/sync-agent-cli-harnesses-prompt.md +26 -31
- package/src/hooks/agent-skill.ts +3 -0
- package/src/hooks/enforcement-capability.ts +1 -1
- package/src/hooks/fp-home.ts +1 -1
- package/src/hooks/handler.ts +22 -3
- package/src/hooks/integrations.ts +5 -2
- package/src/hooks/semantic/intent.ts +127 -24
- package/src/hooks/semantic/jev-review.ts +21 -2
- package/.next/standalone/.codex/hooks.json +0 -76
- package/.next/standalone/.cursor/hooks.json +0 -47
- package/.next/standalone/.factory/hooks.json +0 -112
- package/.next/standalone/.next/server/chunks/[externals]__1x24dzcbbq6-g._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0__a_je8fsn65._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0l-oi4gdtmlo5._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0t9ufnv5hi2hq._.js +0 -327
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1aaw59g-5uty7._.js +0 -322
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1hqpg6vgmfexv._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[externals]__0ilfh9mfnzsth._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[externals]__0ohnuzsaozaca._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0pwj2h2efe5f-._.js +0 -14
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_0zuikgt2xho-v._.js +0 -271
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_158jo-9mwvgad._.js +0 -291
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_19r82zsxo2jj1._.js +0 -291
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_1dupwucoqt5qm._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_shared_lib_03w27x2kh17_8._.js +0 -23
- package/.next/standalone/.next/static/chunks/1my3-5p47t7r-.js +0 -1
- package/.next/standalone/.next/static/chunks/21hckpmsc4g70.js +0 -6
- package/.next/standalone/.next/static/chunks/2hmex93ppj1ke.js +0 -1
- package/.next/standalone/.next/static/chunks/40oworn_-x12p.js +0 -1
- package/.next/standalone/.opencode/opencode.json +0 -4
- package/.next/standalone/.opencode/plugins/failproofai.mjs +0 -210
- package/.next/standalone/.pi/settings.json +0 -5
- package/.next/standalone/node_modules/react/cjs/react.development.js +0 -1330
- package/scripts/dev-hook.mjs +0 -333
- /package/.next/standalone/.next/static/{LHCtFxVG0mdvd4lsXAOFC → 1n2dyfTQb0MDajeqlipJy}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{LHCtFxVG0mdvd4lsXAOFC → 1n2dyfTQb0MDajeqlipJy}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{LHCtFxVG0mdvd4lsXAOFC → 1n2dyfTQb0MDajeqlipJy}/_ssgManifest.js +0 -0
package/dist/worker.mjs
CHANGED
|
@@ -1166,7 +1166,7 @@ function instruct(reason) {
|
|
|
1166
1166
|
}
|
|
1167
1167
|
|
|
1168
1168
|
// package.json
|
|
1169
|
-
var version = "1.0.
|
|
1169
|
+
var version = "1.0.13-beta.1";
|
|
1170
1170
|
var init_package = () => {};
|
|
1171
1171
|
|
|
1172
1172
|
// src/hooks/agent-targets.ts
|
|
@@ -15706,6 +15706,7 @@ __export(exports_intent, {
|
|
|
15706
15706
|
cleanHumanTurn: () => cleanHumanTurn,
|
|
15707
15707
|
cleanUserSaid: () => cleanUserSaid,
|
|
15708
15708
|
humanMessageText: () => humanMessageText,
|
|
15709
|
+
intentProfileKey: () => intentProfileKey,
|
|
15709
15710
|
lastAgentMessage: () => lastAgentMessage,
|
|
15710
15711
|
looseIntentStoreDir: () => looseIntentStoreDir,
|
|
15711
15712
|
pruneExpiredSessions: () => pruneExpiredSessions,
|
|
@@ -15725,13 +15726,27 @@ import {
|
|
|
15725
15726
|
writeFileSync as writeFileSync8
|
|
15726
15727
|
} from "node:fs";
|
|
15727
15728
|
import { dirname as dirname10, resolve as resolve17 } from "node:path";
|
|
15729
|
+
function intentProfileKey(profile) {
|
|
15730
|
+
if (validAgentIdentity(profile.agent))
|
|
15731
|
+
return `${profile.agent.integration}.${profile.agent.instanceId}`;
|
|
15732
|
+
return isKnownCli(profile.cli) ? profile.cli : null;
|
|
15733
|
+
}
|
|
15734
|
+
function storeSlot(sessionId, profile) {
|
|
15735
|
+
if (profile === undefined)
|
|
15736
|
+
return { dir: sessionsDir(), file: resolve17(sessionsDir(), `${sessionId}.json`) };
|
|
15737
|
+
const key = intentProfileKey(profile);
|
|
15738
|
+
if (key === null || !PROFILE_DIR_RE.test(key))
|
|
15739
|
+
return null;
|
|
15740
|
+
const dir = resolve17(sessionsDir(), key);
|
|
15741
|
+
return { dir, file: resolve17(dir, `${sessionId}.json`) };
|
|
15742
|
+
}
|
|
15728
15743
|
function modesAreMeaningful2() {
|
|
15729
15744
|
return process.platform !== "win32";
|
|
15730
15745
|
}
|
|
15731
|
-
function storeDirChain() {
|
|
15746
|
+
function storeDirChain(innermost = sessionsDir()) {
|
|
15732
15747
|
const home = resolve17(failproofaiHome());
|
|
15733
15748
|
const chain = [];
|
|
15734
|
-
let dir =
|
|
15749
|
+
let dir = innermost;
|
|
15735
15750
|
for (let i = 0;i < 8; i++) {
|
|
15736
15751
|
chain.push(dir);
|
|
15737
15752
|
if (dir === home)
|
|
@@ -15743,10 +15758,10 @@ function storeDirChain() {
|
|
|
15743
15758
|
}
|
|
15744
15759
|
return chain;
|
|
15745
15760
|
}
|
|
15746
|
-
function looseIntentStoreDir() {
|
|
15761
|
+
function looseIntentStoreDir(innermost) {
|
|
15747
15762
|
if (!modesAreMeaningful2())
|
|
15748
15763
|
return null;
|
|
15749
|
-
for (const dir of storeDirChain()) {
|
|
15764
|
+
for (const dir of storeDirChain(innermost)) {
|
|
15750
15765
|
let mode;
|
|
15751
15766
|
try {
|
|
15752
15767
|
mode = statSync20(dir).mode & 511;
|
|
@@ -15765,23 +15780,22 @@ function looseIntentStoreDir() {
|
|
|
15765
15780
|
}
|
|
15766
15781
|
return null;
|
|
15767
15782
|
}
|
|
15768
|
-
function readIntentFile(
|
|
15783
|
+
function readIntentFile(slot) {
|
|
15769
15784
|
try {
|
|
15770
|
-
const parsed = JSON.parse(readFileSync19(
|
|
15785
|
+
const parsed = JSON.parse(readFileSync19(slot.file, "utf8"));
|
|
15771
15786
|
return Array.isArray(parsed?.prompts) ? parsed : { prompts: [] };
|
|
15772
15787
|
} catch {
|
|
15773
15788
|
return { prompts: [] };
|
|
15774
15789
|
}
|
|
15775
15790
|
}
|
|
15776
|
-
function appendPrompt(
|
|
15791
|
+
function appendPrompt(slot, entry) {
|
|
15777
15792
|
try {
|
|
15778
|
-
const file = readIntentFile(
|
|
15793
|
+
const file = readIntentFile(slot);
|
|
15779
15794
|
const last = file.prompts[file.prompts.length - 1];
|
|
15780
15795
|
const kept = last && last.text === entry.text ? file.prompts.slice(0, -1) : file.prompts;
|
|
15781
15796
|
file.prompts = [...kept, entry].slice(-MAX_RECORDED_PROMPTS);
|
|
15782
|
-
|
|
15783
|
-
|
|
15784
|
-
const target = intentFile(sessionId);
|
|
15797
|
+
mkdirSync9(slot.dir, { recursive: true, mode: 448 });
|
|
15798
|
+
const target = slot.file;
|
|
15785
15799
|
const isNew = !fileExists2(target);
|
|
15786
15800
|
const tmp = `${target}.${process.pid}.tmp`;
|
|
15787
15801
|
writeFileSync8(tmp, JSON.stringify(file), { mode: 384 });
|
|
@@ -15802,9 +15816,24 @@ function fileExists2(path) {
|
|
|
15802
15816
|
}
|
|
15803
15817
|
}
|
|
15804
15818
|
function pruneExpiredSessions(now = Date.now()) {
|
|
15819
|
+
const root = sessionsDir();
|
|
15820
|
+
let removed = pruneDir(root, now);
|
|
15821
|
+
try {
|
|
15822
|
+
for (const name of readdirSync13(root)) {
|
|
15823
|
+
if (!PROFILE_DIR_RE.test(name))
|
|
15824
|
+
continue;
|
|
15825
|
+
const dir = resolve17(root, name);
|
|
15826
|
+
try {
|
|
15827
|
+
if (statSync20(dir).isDirectory())
|
|
15828
|
+
removed += pruneDir(dir, now);
|
|
15829
|
+
} catch {}
|
|
15830
|
+
}
|
|
15831
|
+
} catch {}
|
|
15832
|
+
return removed;
|
|
15833
|
+
}
|
|
15834
|
+
function pruneDir(dir, now) {
|
|
15805
15835
|
let removed = 0;
|
|
15806
15836
|
try {
|
|
15807
|
-
const dir = sessionsDir();
|
|
15808
15837
|
for (const name of readdirSync13(dir)) {
|
|
15809
15838
|
if (!SESSION_FILE_RE3.test(name))
|
|
15810
15839
|
continue;
|
|
@@ -15820,23 +15849,29 @@ function pruneExpiredSessions(now = Date.now()) {
|
|
|
15820
15849
|
} catch {}
|
|
15821
15850
|
return removed;
|
|
15822
15851
|
}
|
|
15823
|
-
function recordPrompt(sessionId, prompt, agent, now) {
|
|
15852
|
+
function recordPrompt(sessionId, profile, prompt, agent, now) {
|
|
15824
15853
|
if (!SESSION_ID_RE2.test(sessionId))
|
|
15825
15854
|
return false;
|
|
15826
15855
|
if (prompt.trim().length === 0)
|
|
15827
15856
|
return false;
|
|
15857
|
+
const slot = storeSlot(sessionId, profile);
|
|
15858
|
+
if (!slot)
|
|
15859
|
+
return false;
|
|
15828
15860
|
try {
|
|
15829
|
-
return appendPrompt(
|
|
15861
|
+
return appendPrompt(slot, { at: now, text: storable(prompt.trim()), agent: agent === null ? null : storable(agent) });
|
|
15830
15862
|
} catch {
|
|
15831
15863
|
return false;
|
|
15832
15864
|
}
|
|
15833
15865
|
}
|
|
15834
|
-
function livePrompts(sessionId, now) {
|
|
15866
|
+
function livePrompts(sessionId, now, profile) {
|
|
15835
15867
|
if (!sessionId || !SESSION_ID_RE2.test(sessionId))
|
|
15836
15868
|
return [];
|
|
15837
|
-
|
|
15869
|
+
const slot = storeSlot(sessionId, profile);
|
|
15870
|
+
if (!slot)
|
|
15838
15871
|
return [];
|
|
15839
|
-
|
|
15872
|
+
if (looseIntentStoreDir(slot.dir) !== null)
|
|
15873
|
+
return [];
|
|
15874
|
+
return readIntentFile(slot).prompts.filter((p) => typeof p?.text === "string" && typeof p.at === "number" && now - p.at <= INTENT_MAX_AGE_MS && p.at - now <= MAX_CLOCK_SKEW_MS);
|
|
15840
15875
|
}
|
|
15841
15876
|
function replaceTagBlocks(text, tag, replace, attributes = false) {
|
|
15842
15877
|
const open = attributes ? `<${tag}` : `<${tag}>`;
|
|
@@ -16183,16 +16218,16 @@ function captureIntent(ev, now = Date.now()) {
|
|
|
16183
16218
|
const cleaned = cleanHumanTurn(raw);
|
|
16184
16219
|
if (cleaned === null)
|
|
16185
16220
|
return;
|
|
16186
|
-
recordPrompt(sessionId, cleaned, lastAgentMessage(ev.transcriptPath), now);
|
|
16221
|
+
recordPrompt(sessionId, ev.profile, cleaned, lastAgentMessage(ev.transcriptPath), now);
|
|
16187
16222
|
} catch {}
|
|
16188
16223
|
}
|
|
16189
|
-
function readIntent(sessionId, now = Date.now()) {
|
|
16190
|
-
const prompts = livePrompts(sessionId, now);
|
|
16224
|
+
function readIntent(sessionId, now = Date.now(), profile) {
|
|
16225
|
+
const prompts = livePrompts(sessionId, now, profile);
|
|
16191
16226
|
const latest = prompts[prompts.length - 1];
|
|
16192
16227
|
const agent = latest && typeof latest.agent === "string" && latest.agent.length > 0 ? latest.agent : null;
|
|
16193
16228
|
return { userSaid: prompts.map((p) => p.text), agentLastMessage: agent };
|
|
16194
16229
|
}
|
|
16195
|
-
var MAX_RECORDED_PROMPTS = 5, INTENT_MAX_AGE_MS, MAX_CLOCK_SKEW_MS, SESSION_ID_RE2, sessionsDir = () => resolve17(semanticDir(), "sessions"),
|
|
16230
|
+
var MAX_RECORDED_PROMPTS = 5, INTENT_MAX_AGE_MS, MAX_CLOCK_SKEW_MS, SESSION_ID_RE2, sessionsDir = () => resolve17(semanticDir(), "sessions"), PROFILE_DIR_RE, 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) => {
|
|
16196
16231
|
const meta = obj(payload.openclaw);
|
|
16197
16232
|
if (!meta)
|
|
16198
16233
|
return false;
|
|
@@ -16208,9 +16243,11 @@ var MAX_RECORDED_PROMPTS = 5, INTENT_MAX_AGE_MS, MAX_CLOCK_SKEW_MS, SESSION_ID_R
|
|
|
16208
16243
|
var init_intent = __esm(() => {
|
|
16209
16244
|
init_fp_home();
|
|
16210
16245
|
init_envelope();
|
|
16246
|
+
init_agent_targets();
|
|
16211
16247
|
INTENT_MAX_AGE_MS = 6 * 60 * 60 * 1000;
|
|
16212
16248
|
MAX_CLOCK_SKEW_MS = 5 * 60 * 1000;
|
|
16213
16249
|
SESSION_ID_RE2 = /^[A-Za-z0-9._-]{1,128}$/;
|
|
16250
|
+
PROFILE_DIR_RE = /^[a-z]+(?:\.agt_[0-9a-f]{16,32})?$/;
|
|
16214
16251
|
SESSION_FILE_RE3 = /^[A-Za-z0-9._-]{1,128}\.json(?:\.\d+\.tmp)?$/;
|
|
16215
16252
|
NON_HUMAN_PREFIXES = [
|
|
16216
16253
|
"<local-command-caveat>",
|
|
@@ -17939,7 +17976,10 @@ function startJevReview(cfg, call) {
|
|
|
17939
17976
|
}
|
|
17940
17977
|
let intent;
|
|
17941
17978
|
try {
|
|
17942
|
-
intent = intentReader.readIntent(call.sessionId
|
|
17979
|
+
intent = intentReader.readIntent(call.sessionId, undefined, {
|
|
17980
|
+
cli: call.cli,
|
|
17981
|
+
agent: call.agent !== undefined ? call.agent : call.cloud?.agent ?? null
|
|
17982
|
+
});
|
|
17943
17983
|
} catch {
|
|
17944
17984
|
intent = { userSaid: [], agentLastMessage: null };
|
|
17945
17985
|
}
|
|
@@ -18351,6 +18391,7 @@ async function startTwoTier(canonicalEventType, parsed, session, cli, opts, acti
|
|
|
18351
18391
|
permissionMode: session.permissionMode,
|
|
18352
18392
|
sessionId: session.sessionId,
|
|
18353
18393
|
cli,
|
|
18394
|
+
agent,
|
|
18354
18395
|
...loaded.cloud ? { cloud: loaded.cloud } : {},
|
|
18355
18396
|
...activePause ? { localPaused: true } : {}
|
|
18356
18397
|
});
|
|
@@ -18377,13 +18418,16 @@ function jevTelemetry(activity) {
|
|
|
18377
18418
|
return {};
|
|
18378
18419
|
}
|
|
18379
18420
|
}
|
|
18380
|
-
async function captureJevIntent(canonicalEventType, decision, parsed, session, cli, opts) {
|
|
18421
|
+
async function captureJevIntent(canonicalEventType, decision, parsed, session, cli, opts, agent) {
|
|
18381
18422
|
if (canonicalEventType !== "UserPromptSubmit" || jevForcedOff(opts))
|
|
18382
18423
|
return;
|
|
18383
18424
|
try {
|
|
18384
|
-
|
|
18425
|
+
const cloudAsks = cloudJevAsks(readCloudJevMode());
|
|
18426
|
+
if (!cloudAsks && !jevChecksInstalled())
|
|
18427
|
+
return;
|
|
18428
|
+
if (cloudAsks && cloudJevAssignmentsFor(agent)?.length === 0 && !packJevChecksInstalled())
|
|
18385
18429
|
return;
|
|
18386
|
-
if (!await readJevConfig())
|
|
18430
|
+
if (!await readJevConfig(agent))
|
|
18387
18431
|
return;
|
|
18388
18432
|
if (decision === "deny") {
|
|
18389
18433
|
await Promise.resolve().then(() => init_enforcement_capability());
|
|
@@ -18397,7 +18441,8 @@ async function captureJevIntent(canonicalEventType, decision, parsed, session, c
|
|
|
18397
18441
|
transcriptPath: session.transcriptPath,
|
|
18398
18442
|
cli,
|
|
18399
18443
|
payload: parsed,
|
|
18400
|
-
prompt: parsed.prompt
|
|
18444
|
+
prompt: parsed.prompt,
|
|
18445
|
+
profile: { cli, agent }
|
|
18401
18446
|
};
|
|
18402
18447
|
captureIntent(event);
|
|
18403
18448
|
} catch (err) {
|
|
@@ -18663,7 +18708,7 @@ async function evaluateHookEvent(eventType, cli = "claude", stdinPayload, opts)
|
|
|
18663
18708
|
}
|
|
18664
18709
|
const durationMs = Math.round(performance.now() - startTime);
|
|
18665
18710
|
hookLogInfo(`result=${result.decision} policy=${result.policyName ?? "none"} duration=${durationMs}ms`);
|
|
18666
|
-
await captureJevIntent(canonicalEventType, result.decision, parsed, session, cli, opts);
|
|
18711
|
+
await captureJevIntent(canonicalEventType, result.decision, parsed, session, cli, opts, runtimeAgent);
|
|
18667
18712
|
const matchedPolicies = matchedBeforeRelease ?? getPoliciesForEvent(canonicalEventType, parsed.tool_name).map((p) => p.name);
|
|
18668
18713
|
const jevOrigin = result.policyName && result.twoTier?.decidedByJev ? result.twoTier.jevOrigin : undefined;
|
|
18669
18714
|
const activityEntry = {
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Asks failproofaid for a verdict over its owner-only Unix socket — the same
|
|
3
|
+
* `hook` request `failproofai --hook <event> --cli openclaw` sends to the
|
|
4
|
+
* daemon (crates/PROTOCOL.md), made from inside the gateway instead of from a
|
|
5
|
+
* process spawned per hook. The Hermes plugin (hermes-plugin/client.py) reaches
|
|
6
|
+
* the daemon the same way.
|
|
7
|
+
*
|
|
8
|
+
* Why not spawn the CLI: OpenClaw ≥ 2026.9.6 imports this plugin from a copy
|
|
9
|
+
* under ~/.openclaw/tmp/plugin-captures/…, and the copy holds only this
|
|
10
|
+
* directory's files. A CLI path derived from import.meta.url (`../dist/cli.mjs`)
|
|
11
|
+
* then points at nothing; the old shim read the spawn failure as "allow", so
|
|
12
|
+
* every tool call ran unchecked and no hook activity was recorded. The socket
|
|
13
|
+
* path depends only on the environment, never on where this file sits.
|
|
14
|
+
*
|
|
15
|
+
* Self-contained on purpose — node built-ins only, nothing imported from
|
|
16
|
+
* outside this directory — because the capture copies nothing else.
|
|
17
|
+
*/
|
|
18
|
+
import { createConnection } from "node:net";
|
|
19
|
+
import { homedir } from "node:os";
|
|
20
|
+
import { resolve } from "node:path";
|
|
21
|
+
|
|
22
|
+
export const PROTOCOL_VERSION = 2;
|
|
23
|
+
// The daemon's frame limit (crates/fpai-ipc/src/framing.rs), both ways.
|
|
24
|
+
const MAX_FRAME_BYTES = 16 * 1024 * 1024;
|
|
25
|
+
// The payload limit the CLI applies to its stdin (handler.ts, read-stdin.ts).
|
|
26
|
+
// It bounds the RAW payload: the envelope carries it as an escaped JSON
|
|
27
|
+
// string plus routing fields, so it is larger, and only the frame limit
|
|
28
|
+
// applies to the envelope.
|
|
29
|
+
export const MAX_PAYLOAD_BYTES = 1_048_576;
|
|
30
|
+
|
|
31
|
+
// The CLI's daemon client budgets these separately for the reason it gives:
|
|
32
|
+
// connecting is the "is anything listening" probe, the response covers the
|
|
33
|
+
// whole evaluation. 250 ms matches the Hermes plugin; 30 s matches the
|
|
34
|
+
// daemon's own read timeout on its worker (worker.rs).
|
|
35
|
+
export const CONNECT_TIMEOUT_MS = 250;
|
|
36
|
+
export const RESPONSE_TIMEOUT_MS = 30_000;
|
|
37
|
+
|
|
38
|
+
const PROTOCOL_MISMATCH_MESSAGE =
|
|
39
|
+
"failproofaid is running a different protocol version than this plugin, so it cannot " +
|
|
40
|
+
"evaluate this call. Run `failproofai update` to update the daemon.";
|
|
41
|
+
const UNREACHABLE_MESSAGE =
|
|
42
|
+
"failproofaid could not be reached. This machine is configured to run hooks through it " +
|
|
43
|
+
"— check the daemon (see `failproofai config`) rather than retrying blindly.";
|
|
44
|
+
|
|
45
|
+
/** Mirrors `daemonSocket()` in src/hooks/fp-home.ts. */
|
|
46
|
+
export function daemonSocketPath(env = process.env, home = homedir()) {
|
|
47
|
+
return (
|
|
48
|
+
env.FAILPROOFAI_DAEMON_SOCKET ||
|
|
49
|
+
resolve(env.FAILPROOFAI_HOME || resolve(home, ".failproofai"), "run", "failproofaid.sock")
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* The gateway profile's openclaw.json — what the spawned CLI computed from the
|
|
55
|
+
* gateway's environment (`runtimeAgentSettingsPath("openclaw", …)` in
|
|
56
|
+
* src/hooks/agent-roster.ts). Sent explicitly: left out, the daemon's worker
|
|
57
|
+
* would resolve it from the DAEMON's environment and attribute a
|
|
58
|
+
* `--profile <name>` gateway to the default profile.
|
|
59
|
+
*/
|
|
60
|
+
export function openclawAgentSettingsPath(env = process.env, home = homedir()) {
|
|
61
|
+
const config = env.OPENCLAW_CONFIG_PATH;
|
|
62
|
+
if (config?.trim()) return resolve(config);
|
|
63
|
+
const state = env.OPENCLAW_STATE_DIR || env.OPENCLAW_HOME;
|
|
64
|
+
if (state?.trim()) return resolve(state, "openclaw.json");
|
|
65
|
+
const profile = env.OPENCLAW_PROFILE?.trim();
|
|
66
|
+
if (profile && profile !== "default" && /^[A-Za-z0-9._-]{1,80}$/.test(profile) && !profile.startsWith(".")) {
|
|
67
|
+
return resolve(home, `.openclaw-${profile}`, "openclaw.json");
|
|
68
|
+
}
|
|
69
|
+
return resolve(home, ".openclaw", "openclaw.json");
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function failed(failure, message) {
|
|
73
|
+
return { ok: false, failure, message };
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Turn the daemon's reply into a flat `{permission, reason}` verdict. For
|
|
78
|
+
* OpenClaw the evaluator always exits 0 and prints either nothing (allow) or
|
|
79
|
+
* one JSON object, so anything else is an evaluation failure — never an allow.
|
|
80
|
+
*/
|
|
81
|
+
function readHookResult(message) {
|
|
82
|
+
if (message === null || typeof message !== "object" || Array.isArray(message)) {
|
|
83
|
+
return failed("invalid", "failproofaid returned a non-object response");
|
|
84
|
+
}
|
|
85
|
+
if (message.protocolVersion !== PROTOCOL_VERSION) {
|
|
86
|
+
return failed("protocol-mismatch", PROTOCOL_MISMATCH_MESSAGE);
|
|
87
|
+
}
|
|
88
|
+
if (message.type === "error") {
|
|
89
|
+
const detail = typeof message.message === "string" && message.message ? message.message : "no detail";
|
|
90
|
+
return failed("evaluation", `failproofaid could not evaluate this call: ${detail}`);
|
|
91
|
+
}
|
|
92
|
+
if (message.type !== "hookResult") {
|
|
93
|
+
return failed("invalid", `failproofaid returned an unexpected ${JSON.stringify(message.type)} response`);
|
|
94
|
+
}
|
|
95
|
+
// The daemon always serializes all three (crates/fpai-ipc/src/envelope.rs);
|
|
96
|
+
// a frame missing one is not a hookResult, and must not read as an empty
|
|
97
|
+
// stdout — that is the allow.
|
|
98
|
+
if (
|
|
99
|
+
!Number.isInteger(message.exitCode) ||
|
|
100
|
+
typeof message.stdout !== "string" ||
|
|
101
|
+
typeof message.stderr !== "string"
|
|
102
|
+
) {
|
|
103
|
+
return failed("invalid", "failproofaid returned an incomplete hookResult");
|
|
104
|
+
}
|
|
105
|
+
if (message.exitCode !== 0) {
|
|
106
|
+
return failed("evaluation", `failproofai exited ${String(message.exitCode)} without a verdict`);
|
|
107
|
+
}
|
|
108
|
+
const stdout = message.stdout.trim();
|
|
109
|
+
if (!stdout) return { ok: true, verdict: { permission: "allow" } };
|
|
110
|
+
let verdict;
|
|
111
|
+
try {
|
|
112
|
+
verdict = JSON.parse(stdout);
|
|
113
|
+
} catch {
|
|
114
|
+
return failed("invalid", "failproofai returned a verdict that is not JSON");
|
|
115
|
+
}
|
|
116
|
+
return isVerdict(verdict)
|
|
117
|
+
? { ok: true, verdict }
|
|
118
|
+
: failed("invalid", "failproofai returned a malformed verdict");
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const PERMISSIONS = new Set(["allow", "deny", "instruct"]);
|
|
122
|
+
|
|
123
|
+
/** The flat shape policy-evaluator.ts prints for `--cli openclaw`; unknown keys are ignored. */
|
|
124
|
+
function isVerdict(verdict) {
|
|
125
|
+
if (verdict === null || typeof verdict !== "object" || Array.isArray(verdict)) return false;
|
|
126
|
+
if (!PERMISSIONS.has(verdict.permission)) return false;
|
|
127
|
+
if (verdict.reason !== undefined && typeof verdict.reason !== "string") return false;
|
|
128
|
+
if (verdict.policyName !== undefined && typeof verdict.policyName !== "string") return false;
|
|
129
|
+
if (
|
|
130
|
+
verdict.policyNames !== undefined &&
|
|
131
|
+
!(Array.isArray(verdict.policyNames) && verdict.policyNames.every((name) => typeof name === "string"))
|
|
132
|
+
) {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* One request, one connection, one frame each way. Never rejects: resolves to
|
|
140
|
+
* `{ok: true, verdict}` (plus `oversized: true`, see below) or
|
|
141
|
+
* `{ok: false, failure, message}`.
|
|
142
|
+
*
|
|
143
|
+
* A payload over MAX_PAYLOAD_BYTES is sent as an empty stdin, exactly as the
|
|
144
|
+
* CLI discards an oversized stdin and evaluates an empty payload;
|
|
145
|
+
* `oversized: true` lets the caller say so instead of discarding it silently.
|
|
146
|
+
*/
|
|
147
|
+
export function requestHookVerdict({
|
|
148
|
+
event,
|
|
149
|
+
payload,
|
|
150
|
+
cwd = "",
|
|
151
|
+
agentSettingsPath = "",
|
|
152
|
+
socketPath = daemonSocketPath(),
|
|
153
|
+
connectTimeoutMs = CONNECT_TIMEOUT_MS,
|
|
154
|
+
responseTimeoutMs = RESPONSE_TIMEOUT_MS,
|
|
155
|
+
}) {
|
|
156
|
+
return new Promise((done) => {
|
|
157
|
+
let body;
|
|
158
|
+
let oversized = false;
|
|
159
|
+
try {
|
|
160
|
+
let stdin = JSON.stringify(payload ?? {});
|
|
161
|
+
if (Buffer.byteLength(stdin, "utf8") > MAX_PAYLOAD_BYTES) {
|
|
162
|
+
stdin = "";
|
|
163
|
+
oversized = true;
|
|
164
|
+
}
|
|
165
|
+
body = Buffer.from(
|
|
166
|
+
JSON.stringify({
|
|
167
|
+
type: "hook",
|
|
168
|
+
protocolVersion: PROTOCOL_VERSION,
|
|
169
|
+
hookEvent: event,
|
|
170
|
+
cli: "openclaw",
|
|
171
|
+
stdin,
|
|
172
|
+
...(typeof cwd === "string" && cwd ? { cwd } : {}),
|
|
173
|
+
agentSettingsPath: agentSettingsPath || "",
|
|
174
|
+
}),
|
|
175
|
+
"utf8",
|
|
176
|
+
);
|
|
177
|
+
} catch (err) {
|
|
178
|
+
done(failed("invalid", `could not encode the hook request: ${err?.message ?? String(err)}`));
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
// Unreachable for a payload within MAX_PAYLOAD_BYTES (escaping at most
|
|
182
|
+
// sextuples it); kept so nothing over the daemon's limit is ever sent.
|
|
183
|
+
if (body.length > MAX_FRAME_BYTES) {
|
|
184
|
+
done(failed("invalid", "hook request exceeds the daemon's 16 MiB frame limit"));
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
let settled = false;
|
|
189
|
+
let connected = false;
|
|
190
|
+
let received = Buffer.alloc(0);
|
|
191
|
+
let timer;
|
|
192
|
+
let socket;
|
|
193
|
+
const finish = (result) => {
|
|
194
|
+
if (settled) return;
|
|
195
|
+
settled = true;
|
|
196
|
+
clearTimeout(timer);
|
|
197
|
+
try { socket?.destroy(); } catch { /* already closed */ }
|
|
198
|
+
done(result);
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
try {
|
|
202
|
+
socket = createConnection(socketPath);
|
|
203
|
+
} catch {
|
|
204
|
+
finish(failed("unreachable", UNREACHABLE_MESSAGE));
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
timer = setTimeout(() => finish(failed("unreachable", UNREACHABLE_MESSAGE)), connectTimeoutMs);
|
|
208
|
+
|
|
209
|
+
socket.on("connect", () => {
|
|
210
|
+
connected = true;
|
|
211
|
+
clearTimeout(timer);
|
|
212
|
+
timer = setTimeout(
|
|
213
|
+
() => finish(failed("timeout", `failproofaid did not answer within ${responseTimeoutMs} ms`)),
|
|
214
|
+
responseTimeoutMs,
|
|
215
|
+
);
|
|
216
|
+
const header = Buffer.alloc(4);
|
|
217
|
+
header.writeUInt32BE(body.length, 0);
|
|
218
|
+
socket.write(Buffer.concat([header, body]));
|
|
219
|
+
});
|
|
220
|
+
socket.on("data", (chunk) => {
|
|
221
|
+
received = Buffer.concat([received, chunk]);
|
|
222
|
+
if (received.length < 4) return;
|
|
223
|
+
const length = received.readUInt32BE(0);
|
|
224
|
+
if (length > MAX_FRAME_BYTES) {
|
|
225
|
+
finish(failed("invalid", "failproofaid response exceeds the 16 MiB limit"));
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
if (received.length < 4 + length) return;
|
|
229
|
+
let message;
|
|
230
|
+
try {
|
|
231
|
+
message = JSON.parse(received.subarray(4, 4 + length).toString("utf8"));
|
|
232
|
+
} catch {
|
|
233
|
+
finish(failed("invalid", "failproofaid returned a response that is not JSON"));
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
const result = readHookResult(message);
|
|
237
|
+
finish(result.ok && oversized ? { ...result, oversized: true } : result);
|
|
238
|
+
});
|
|
239
|
+
socket.on("error", (err) => {
|
|
240
|
+
finish(
|
|
241
|
+
connected
|
|
242
|
+
? failed("evaluation", `failproofaid connection failed: ${err?.message ?? String(err)}`)
|
|
243
|
+
: failed("unreachable", UNREACHABLE_MESSAGE),
|
|
244
|
+
);
|
|
245
|
+
});
|
|
246
|
+
socket.on("close", () => {
|
|
247
|
+
finish(
|
|
248
|
+
connected
|
|
249
|
+
? failed("evaluation", "failproofaid closed the connection before returning a verdict")
|
|
250
|
+
: failed("unreachable", UNREACHABLE_MESSAGE),
|
|
251
|
+
);
|
|
252
|
+
});
|
|
253
|
+
});
|
|
254
|
+
}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenClaw typed plugin hooks → failproofai verdicts.
|
|
3
|
+
*
|
|
4
|
+
* Kept apart from index.js (whose only job is `definePluginEntry`) so the
|
|
5
|
+
* hook wiring is importable without the `openclaw/plugin-sdk` package, which
|
|
6
|
+
* only resolves inside the gateway.
|
|
7
|
+
*
|
|
8
|
+
* Each hook sends a Claude-shaped payload (params→tool_input, toolName→
|
|
9
|
+
* tool_name, transcriptPath→transcript_path, stopHookActive→stop_hook_active,
|
|
10
|
+
* sessionKey→session_id) with the RAW event and tool names; the daemon's
|
|
11
|
+
* worker canonicalizes them via the OPENCLAW_* maps in src/hooks/types.ts
|
|
12
|
+
* (single source of truth — no inline maps here, unlike the OpenCode/Pi shims).
|
|
13
|
+
*
|
|
14
|
+
* When failproofaid cannot return a verdict the gates fail closed, as every
|
|
15
|
+
* other CLI does on a daemon-configured machine (bin/failproofai.mjs): a tool
|
|
16
|
+
* call or prompt is blocked with the reason, and the reason is logged. The
|
|
17
|
+
* turn-end gate is the exception — a revise cannot bring the daemon back, so
|
|
18
|
+
* forcing one would loop the turn instead of protecting anything.
|
|
19
|
+
*/
|
|
20
|
+
import { createInstructRetryGate, mapBeforeToolVerdict } from "./instruct-retry-gate.js";
|
|
21
|
+
import { createWorkspaceContext } from "./workspace-context.js";
|
|
22
|
+
import { openclawAgentSettingsPath, requestHookVerdict } from "./daemon-client.js";
|
|
23
|
+
|
|
24
|
+
const sharedRetryGate = createInstructRetryGate();
|
|
25
|
+
const sharedWorkspace = createWorkspaceContext();
|
|
26
|
+
|
|
27
|
+
const OBSERVATION_EVENTS = [
|
|
28
|
+
"after_tool_call",
|
|
29
|
+
"session_start",
|
|
30
|
+
"session_end",
|
|
31
|
+
"subagent_ended",
|
|
32
|
+
"before_compaction",
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
const HOOK_OPTIONS = { priority: 100, timeoutMs: 60_000 };
|
|
36
|
+
|
|
37
|
+
/** Claude-shaped stdin base. Extra keys are ignored by the evaluator's payload
|
|
38
|
+
* parser; they're forwarded for activity attribution. */
|
|
39
|
+
function baseMeta(payload, ctx, config, workspace) {
|
|
40
|
+
const p = payload || {};
|
|
41
|
+
const c = ctx || {};
|
|
42
|
+
return {
|
|
43
|
+
session_id: c.sessionId ?? p.sessionId ?? c.sessionKey ?? p.sessionKey,
|
|
44
|
+
cwd: workspace.resolveWorkspace(p, c, config) ?? process.cwd(),
|
|
45
|
+
transcript_path: p.transcriptPath,
|
|
46
|
+
stop_hook_active: p.stopHookActive === true,
|
|
47
|
+
openclaw: {
|
|
48
|
+
agentId: c.agentId,
|
|
49
|
+
sessionKey: c.sessionKey ?? p.sessionKey,
|
|
50
|
+
runId: c.runId ?? p.runId,
|
|
51
|
+
provider: p.provider,
|
|
52
|
+
model: p.model,
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function defaultEvaluate(event, payload) {
|
|
58
|
+
return requestHookVerdict({
|
|
59
|
+
event,
|
|
60
|
+
payload,
|
|
61
|
+
cwd: payload.cwd,
|
|
62
|
+
agentSettingsPath: openclawAgentSettingsPath(),
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function logFailure(api, event, message) {
|
|
67
|
+
const line = `[failproofai] ${event}: ${message}`;
|
|
68
|
+
try {
|
|
69
|
+
if (typeof api?.logger?.error === "function") {
|
|
70
|
+
api.logger.error(line);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
} catch { /* fall through to stderr */ }
|
|
74
|
+
process.stderr.write(`${line}\n`);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const blockedReason = (message) => `FailproofAI could not check this call, so it was blocked: ${message}`;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Register every hook on `api`. `evaluate(event, payload)` resolves to
|
|
81
|
+
* `{ok: true, verdict}` or `{ok: false, message}`; tests inject their own.
|
|
82
|
+
*/
|
|
83
|
+
export function registerFailproofaiHooks(api, {
|
|
84
|
+
evaluate = defaultEvaluate,
|
|
85
|
+
retryGate = sharedRetryGate,
|
|
86
|
+
workspace = sharedWorkspace,
|
|
87
|
+
} = {}) {
|
|
88
|
+
const ask = async (event, payload) => {
|
|
89
|
+
let result;
|
|
90
|
+
try {
|
|
91
|
+
result = await evaluate(event, payload);
|
|
92
|
+
} catch (err) {
|
|
93
|
+
result = { ok: false, message: `the failproofai plugin failed: ${err?.message ?? String(err)}` };
|
|
94
|
+
}
|
|
95
|
+
if (!result?.ok) logFailure(api, event, result?.message ?? "no verdict");
|
|
96
|
+
// Same outcome as the CLI's oversized stdin (warn, evaluate an empty
|
|
97
|
+
// payload), and said out loud for the same reason it is there.
|
|
98
|
+
else if (result.oversized) {
|
|
99
|
+
logFailure(api, event, "payload exceeds 1 MiB, so it was evaluated as an empty payload");
|
|
100
|
+
}
|
|
101
|
+
return result ?? { ok: false, message: "no verdict" };
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
// before_tool_call → PreToolUse. Deny always blocks. Instruct blocks the
|
|
105
|
+
// first matching attempt only, using blockReason to give the model the
|
|
106
|
+
// instruction, then permits retries from that session/policy for 5 minutes.
|
|
107
|
+
api.on(
|
|
108
|
+
"before_tool_call",
|
|
109
|
+
async (payload, ctx) => {
|
|
110
|
+
const p = payload || {};
|
|
111
|
+
const result = await ask("before_tool_call", {
|
|
112
|
+
...baseMeta(payload, ctx, api.config, workspace),
|
|
113
|
+
tool_name: p.toolName,
|
|
114
|
+
tool_input: p.params,
|
|
115
|
+
hook_event_name: "before_tool_call",
|
|
116
|
+
});
|
|
117
|
+
if (!result.ok) return { block: true, blockReason: blockedReason(result.message) };
|
|
118
|
+
return mapBeforeToolVerdict(result.verdict, payload, ctx, retryGate);
|
|
119
|
+
},
|
|
120
|
+
HOOK_OPTIONS,
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
// before_agent_run → UserPromptSubmit. Deny: return {outcome:"block", reason}.
|
|
124
|
+
api.on(
|
|
125
|
+
"before_agent_run",
|
|
126
|
+
async (payload, ctx) => {
|
|
127
|
+
const p = payload || {};
|
|
128
|
+
workspace.remember(payload, ctx);
|
|
129
|
+
const result = await ask("before_agent_run", {
|
|
130
|
+
...baseMeta(payload, ctx, api.config, workspace),
|
|
131
|
+
prompt: p.prompt,
|
|
132
|
+
hook_event_name: "before_agent_run",
|
|
133
|
+
});
|
|
134
|
+
if (!result.ok) return { outcome: "block", reason: blockedReason(result.message) };
|
|
135
|
+
if (result.verdict.permission === "deny") {
|
|
136
|
+
return { outcome: "block", reason: result.verdict.reason || "Blocked by failproofai" };
|
|
137
|
+
}
|
|
138
|
+
return undefined;
|
|
139
|
+
},
|
|
140
|
+
HOOK_OPTIONS,
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
// before_agent_finalize → Stop. The real turn-end gate: a deny becomes a
|
|
144
|
+
// revise so the agent runs another pass. The evaluator supplies the
|
|
145
|
+
// MANDATORY ACTION wording; the payload's stop_hook_active guards the
|
|
146
|
+
// require-*-before-stop builtins against infinite loops.
|
|
147
|
+
api.on(
|
|
148
|
+
"before_agent_finalize",
|
|
149
|
+
async (payload, ctx) => {
|
|
150
|
+
const result = await ask("before_agent_finalize", {
|
|
151
|
+
...baseMeta(payload, ctx, api.config, workspace),
|
|
152
|
+
hook_event_name: "before_agent_finalize",
|
|
153
|
+
});
|
|
154
|
+
if (result.ok && result.verdict.permission === "deny") {
|
|
155
|
+
return { action: "revise", reason: result.verdict.reason || "Action required by failproofai" };
|
|
156
|
+
}
|
|
157
|
+
return undefined;
|
|
158
|
+
},
|
|
159
|
+
HOOK_OPTIONS,
|
|
160
|
+
);
|
|
161
|
+
|
|
162
|
+
// Observation hooks — await so activity ordering is stable, ignore verdict.
|
|
163
|
+
// after_tool_call → PostToolUse; session_start/end → SessionStart/End;
|
|
164
|
+
// subagent_ended → SubagentStop (obs only); before_compaction → PreCompact.
|
|
165
|
+
for (const event of OBSERVATION_EVENTS) {
|
|
166
|
+
api.on(
|
|
167
|
+
event,
|
|
168
|
+
async (payload, ctx) => {
|
|
169
|
+
const p = payload || {};
|
|
170
|
+
await ask(event, {
|
|
171
|
+
...baseMeta(payload, ctx, api.config, workspace),
|
|
172
|
+
tool_name: p.toolName,
|
|
173
|
+
tool_input: p.params,
|
|
174
|
+
tool_response: p.result,
|
|
175
|
+
reason: p.reason,
|
|
176
|
+
hook_event_name: event,
|
|
177
|
+
});
|
|
178
|
+
if (event === "session_end") {
|
|
179
|
+
retryGate.clear(payload, ctx);
|
|
180
|
+
workspace.clear(payload, ctx);
|
|
181
|
+
}
|
|
182
|
+
return undefined;
|
|
183
|
+
},
|
|
184
|
+
HOOK_OPTIONS,
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
}
|