failproofai 1.0.12-beta.1 → 1.0.12

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.
Files changed (236) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/build-manifest.json +3 -3
  3. package/.next/standalone/.next/prerender-manifest.json +4 -4
  4. package/.next/standalone/.next/required-server-files.json +1 -1
  5. package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
  6. package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
  7. package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  8. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  9. package/.next/standalone/.next/server/app/_global-error.rsc +2 -2
  10. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +2 -2
  11. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +2 -2
  12. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  13. package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  14. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  15. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  16. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  17. package/.next/standalone/.next/server/app/_not-found.rsc +3 -3
  18. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  19. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
  20. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  21. package/.next/standalone/.next/server/app/api/audit/invite/route.js.nft.json +1 -1
  22. package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -1
  23. package/.next/standalone/.next/server/app/api/audit/status/route.js.nft.json +1 -1
  24. package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -1
  25. package/.next/standalone/.next/server/app/api/auth/login-verify/route.js.nft.json +1 -1
  26. package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
  27. package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -1
  28. package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
  29. package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +2 -2
  30. package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -1
  31. package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
  32. package/.next/standalone/.next/server/app/index.html +1 -1
  33. package/.next/standalone/.next/server/app/index.rsc +3 -3
  34. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  35. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +3 -3
  36. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  37. package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
  38. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  39. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  40. package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +14 -14
  41. package/.next/standalone/.next/server/app/policies/page.js +2 -2
  42. package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
  43. package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
  44. package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
  45. package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
  46. package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
  47. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
  48. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
  49. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
  50. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
  51. package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
  52. package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
  53. package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  54. package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +8 -8
  55. package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
  56. package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  57. package/.next/standalone/.next/server/chunks/_0tovk6q0miud6._.js +1 -1
  58. package/.next/standalone/.next/server/chunks/_0trp3ycqv17cl._.js +1 -1
  59. package/.next/standalone/.next/server/chunks/_1ek68lnh2daur._.js +2 -2
  60. package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4vkpxxu7._.js +1 -1
  61. package/.next/standalone/.next/server/chunks/src_hooks_0_em82s16zfym._.js +1 -1
  62. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__08ch3staq3ejw._.js +1 -1
  63. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0bigvy9xmv2ka._.js +1 -1
  64. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0h86bl2qf0k_o._.js +1 -1
  65. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0pia5h3p8re4c._.js +1 -1
  66. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1-ey9fgesfbc0._.js +1 -1
  67. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__15usvs-ms-0hf._.js +1 -1
  68. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__167mipqmjprq5._.js +3 -0
  69. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__16gb3_92zvk5x._.js +1 -1
  70. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1avi2kypusyb_._.js +1 -1
  71. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1r7drlqli-ado._.js +1 -1
  72. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0b78b0j8iyv6l._.js → [root-of-the-server]__1vofkb2oq7p7e._.js} +1 -1
  73. package/.next/standalone/.next/server/chunks/ssr/_0eoura3_9gjb-._.js +1 -1
  74. package/.next/standalone/.next/server/chunks/ssr/{_1a3tubds7s7ow._.js → _0ouu886szh6yj._.js} +4 -4
  75. package/.next/standalone/.next/server/chunks/ssr/_0pedwblqdoh58._.js +1 -1
  76. package/.next/standalone/.next/server/chunks/ssr/_1d98fyfrcaqhy._.js +3 -0
  77. package/.next/standalone/.next/server/chunks/ssr/_1djqs9i27e4kg._.js +1 -1
  78. package/.next/standalone/.next/server/chunks/ssr/_next-internal_server_app_policies_page_actions_1sp2-yo5_vm5f.js +2 -2
  79. package/.next/standalone/.next/server/chunks/ssr/app_actions_get-scheduled-audit_ts_0ei9snixb5fd-._.js +1 -1
  80. package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47q0xq5w._.js +1 -1
  81. package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x33jqb6._.js +1 -1
  82. package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpcz0uxur._.js +2 -2
  83. package/.next/standalone/.next/server/chunks/ssr/app_settings_02tf1h47jmhhd._.js +1 -1
  84. package/.next/standalone/.next/server/chunks/ssr/{node_modules_html-to-image_es_index_1i8oid1gc7s1f.js → node_modules_html-to-image_es_index_0tqc05n832v7a.js} +1 -1
  85. package/.next/standalone/.next/server/chunks/ssr/package_json_[json]_cjs_013tntikdft59._.js +1 -1
  86. package/.next/standalone/.next/server/chunks/ssr/src_hooks_0agdmptetetdt._.js +1 -1
  87. package/.next/standalone/.next/server/chunks/ssr/src_hooks_0mdwgjisv4fub._.js +1 -1
  88. package/.next/standalone/.next/server/chunks/ssr/src_hooks_fp-config_ts_04t589gp4p60j._.js +1 -1
  89. package/.next/standalone/.next/server/chunks/ssr/src_hooks_pack-cli_ts_0t7me658zqmh_._.js +1 -1
  90. package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
  91. package/.next/standalone/.next/server/pages/404.html +1 -1
  92. package/.next/standalone/.next/server/pages/500.html +1 -1
  93. package/.next/standalone/.next/server/preview-props.json +3 -3
  94. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  95. package/.next/standalone/.next/server/server-reference-manifest.json +23 -23
  96. package/.next/standalone/.next/static/chunks/{1b32-afqacaen.js → 0el9n3h9_zp5m.js} +1 -1
  97. package/.next/standalone/.next/static/chunks/0k7g_8x3o6gd-.js +1 -0
  98. package/.next/standalone/.next/static/chunks/{42e8zab314654.js → 0umzct31duk5g.js} +1 -1
  99. package/.next/standalone/.next/static/chunks/{24w3x2da9sk49.js → 0wobqgosirs8p.js} +1 -1
  100. package/.next/standalone/.next/static/chunks/12rug3jilwqzs.js +1 -0
  101. package/.next/standalone/.next/static/chunks/{2-tf6_7u623kd.js → 1kduj74-715jh.js} +1 -1
  102. package/.next/standalone/.next/static/chunks/2701amhrbsbot.js +1 -0
  103. package/.next/standalone/.next/static/chunks/{18433qz-8njv3.js → 27cavoc8paelg.js} +1 -1
  104. package/.next/standalone/.next/static/chunks/{0_zfad4co-t2z.js → 2ve23a7keupjw.js} +1 -1
  105. package/.next/standalone/.next/static/chunks/3bv6xaoitjpnh.js +6 -0
  106. package/.next/standalone/app/actions/update-jev-config.ts +5 -3
  107. package/.next/standalone/app/settings/jev-panel.tsx +1 -1
  108. package/.next/standalone/fp-cloud-cli/CHANGELOG.md +28 -18
  109. package/.next/standalone/fp-cloud-cli/README.md +127 -9
  110. package/.next/standalone/fp-cloud-cli/fp_cli/app.py +15 -1
  111. package/.next/standalone/fp-cloud-cli/fp_cli/client.py +199 -34
  112. package/.next/standalone/fp-cloud-cli/fp_cli/cloud_output.py +523 -0
  113. package/.next/standalone/fp-cloud-cli/fp_cli/commands/_cloud.py +45 -0
  114. package/.next/standalone/fp-cloud-cli/fp_cli/commands/_write.py +3 -1
  115. package/.next/standalone/fp-cloud-cli/fp_cli/commands/account_cmds.py +171 -0
  116. package/.next/standalone/fp-cloud-cli/fp_cli/commands/agent_cmds.py +80 -7
  117. package/.next/standalone/fp-cloud-cli/fp_cli/commands/alerts_cmds.py +23 -0
  118. package/.next/standalone/fp-cloud-cli/fp_cli/commands/audits_cmds.py +2 -0
  119. package/.next/standalone/fp-cloud-cli/fp_cli/commands/contracts_cmds.py +67 -0
  120. package/.next/standalone/fp-cloud-cli/fp_cli/commands/dashboards_cmds.py +159 -0
  121. package/.next/standalone/fp-cloud-cli/fp_cli/commands/evaluators_cmds.py +380 -0
  122. package/.next/standalone/fp-cloud-cli/fp_cli/commands/events_cmds.py +14 -1
  123. package/.next/standalone/fp-cloud-cli/fp_cli/commands/fleet_cmds.py +12 -216
  124. package/.next/standalone/fp-cloud-cli/fp_cli/commands/incidents_cmds.py +82 -6
  125. package/.next/standalone/fp-cloud-cli/fp_cli/commands/list_cmds.py +4 -1
  126. package/.next/standalone/fp-cloud-cli/fp_cli/commands/orgs_cmds.py +17 -0
  127. package/.next/standalone/fp-cloud-cli/fp_cli/commands/policies_cmds.py +143 -1
  128. package/.next/standalone/fp-cloud-cli/fp_cli/commands/queries_cmds.py +70 -0
  129. package/.next/standalone/fp-cloud-cli/fp_cli/commands/sentiment_cmds.py +49 -0
  130. package/.next/standalone/fp-cloud-cli/fp_cli/commands/sessions_cmds.py +95 -1
  131. package/.next/standalone/fp-cloud-cli/fp_cli/commands/settings_cmds.py +2 -0
  132. package/.next/standalone/fp-cloud-cli/fp_cli/commands/usage_cmds.py +21 -1
  133. package/.next/standalone/fp-cloud-cli/fp_cli/commands/users_cmds.py +14 -0
  134. package/.next/standalone/fp-cloud-cli/fp_cli/enforcement.py +7 -53
  135. package/.next/standalone/fp-cloud-cli/fp_cli/errors.py +3 -0
  136. package/.next/standalone/fp-cloud-cli/fp_cli/evaluator_spec.py +266 -0
  137. package/.next/standalone/fp-cloud-cli/fp_cli/output.py +189 -152
  138. package/.next/standalone/fp-cloud-cli/fp_cli/theme.py +21 -24
  139. package/.next/standalone/fp-cloud-cli/skill/SKILL.md +124 -23
  140. package/.next/standalone/fp-cloud-cli/skill/agents/openai.yaml +2 -1
  141. package/.next/standalone/fp-cloud-cli/skill/references/commands.md +173 -22
  142. package/.next/standalone/fp-cloud-cli/tests/fake_cloud_smoke.py +312 -0
  143. package/.next/standalone/fp-cloud-cli/tests/test_cloud_account.py +125 -0
  144. package/.next/standalone/fp-cloud-cli/tests/test_cloud_agent.py +253 -0
  145. package/.next/standalone/fp-cloud-cli/tests/test_cloud_human_views.py +287 -0
  146. package/.next/standalone/fp-cloud-cli/tests/test_cloud_jev.py +32 -197
  147. package/.next/standalone/fp-cloud-cli/tests/test_cloud_observability.py +116 -0
  148. package/.next/standalone/fp-cloud-cli/tests/test_cloud_transport.py +141 -0
  149. package/.next/standalone/fp-cloud-cli/tests/test_commands.py +3 -3
  150. package/.next/standalone/fp-cloud-cli/tests/test_dashboards_agent.py +3 -3
  151. package/.next/standalone/fp-cloud-cli/tests/test_evaluator_authoring.py +449 -0
  152. package/.next/standalone/fp-cloud-cli/tests/test_facets.py +1 -1
  153. package/.next/standalone/fp-cloud-cli/tests/test_help_table_coverage.py +15 -0
  154. package/.next/standalone/fp-cloud-cli/tests/test_operator.py +1 -1
  155. package/.next/standalone/fp-cloud-cli/tests/test_orgs.py +1 -1
  156. package/.next/standalone/fp-cloud-cli/tests/test_output.py +37 -37
  157. package/.next/standalone/fp-cloud-cli/tests/test_round4_behaviour.py +144 -0
  158. package/.next/standalone/fp-cloud-cli/tests/test_screen_language.py +80 -0
  159. package/.next/standalone/fp-cloud-cli/tests/test_session_reevaluate.py +33 -0
  160. package/.next/standalone/fp-cloud-cli/tests/test_staging_parity.py +198 -0
  161. package/.next/standalone/fp-cloud-cli/tests/test_whoami.py +1 -1
  162. package/.next/standalone/hermes-plugin/__init__.py +11 -0
  163. package/.next/standalone/hermes-plugin/plugin.yaml +1 -1
  164. package/.next/standalone/package.json +11 -10
  165. package/.next/standalone/sdk/python/uv.lock +31 -8
  166. package/.next/standalone/sdk/typescript/integration/fixtures/ai-4/package-lock.json +68 -176
  167. package/.next/standalone/sdk/typescript/integration/fixtures/ai-4/package.json +2 -2
  168. package/.next/standalone/sdk/typescript/integration/fixtures/ai-5/package-lock.json +4 -4
  169. package/.next/standalone/sdk/typescript/integration/fixtures/ai-5/package.json +1 -1
  170. package/.next/standalone/sdk/typescript/integration/fixtures/ai-6/package-lock.json +7 -7
  171. package/.next/standalone/sdk/typescript/integration/fixtures/ai-6/package.json +1 -1
  172. package/.next/standalone/sdk/typescript/integration/fixtures/ai-7/package-lock.json +7 -7
  173. package/.next/standalone/sdk/typescript/integration/fixtures/ai-7/package.json +1 -1
  174. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-0.3/package-lock.json +98 -115
  175. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-0.3/package.json +3 -3
  176. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-1/package-lock.json +4 -4
  177. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-1/package.json +1 -1
  178. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-dup-core/package-lock.json +4 -4
  179. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-dup-core/package.json +1 -1
  180. package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.11/package-lock.json +149 -171
  181. package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.11/package.json +2 -2
  182. package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.12/package-lock.json +4 -4
  183. package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.12/package.json +1 -1
  184. package/.next/standalone/sdk/typescript/integration/fixtures/mastra-0/package-lock.json +25 -25
  185. package/.next/standalone/sdk/typescript/integration/fixtures/mastra-0/package.json +1 -1
  186. package/.next/standalone/sdk/typescript/integration/fixtures/mastra-1/package-lock.json +7 -7
  187. package/.next/standalone/sdk/typescript/integration/fixtures/mastra-1/package.json +1 -1
  188. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/package-lock.json +10 -10
  189. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/package.json +1 -1
  190. package/.next/standalone/sdk/typescript/integration/fixtures/runtimes/package-lock.json +7 -7
  191. package/.next/standalone/sdk/typescript/integration/fixtures/runtimes/package.json +1 -1
  192. package/.next/standalone/server.js +1 -1
  193. package/dist/cli.mjs +1760 -638
  194. package/dist/worker.mjs +426 -76
  195. package/hermes-plugin/__init__.py +11 -0
  196. package/hermes-plugin/plugin.yaml +1 -1
  197. package/package.json +11 -10
  198. package/src/audit/open-browser.ts +24 -7
  199. package/src/hooks/agent-roster.ts +9 -1
  200. package/src/hooks/agent-skill.ts +206 -0
  201. package/src/hooks/cloud-connection.ts +27 -51
  202. package/src/hooks/cloud-introspect.ts +5 -2
  203. package/src/hooks/cloud-login.ts +248 -0
  204. package/src/hooks/cloud-managed-policies.ts +54 -4
  205. package/src/hooks/codex-system-hooks.ts +10 -4
  206. package/src/hooks/config-status.ts +9 -3
  207. package/src/hooks/configure-wizard.ts +356 -32
  208. package/src/hooks/delivery-health.ts +47 -2
  209. package/src/hooks/effective-reviewers.ts +14 -0
  210. package/src/hooks/fp-config.ts +19 -0
  211. package/src/hooks/fp-home.ts +1 -1
  212. package/src/hooks/handler.ts +43 -5
  213. package/src/hooks/hook-activity-store.ts +7 -1
  214. package/src/hooks/integrations.ts +18 -3
  215. package/src/hooks/jev-activity.ts +117 -1
  216. package/src/hooks/jev-cli.ts +7 -9
  217. package/src/hooks/manager.ts +80 -46
  218. package/src/hooks/policy-evaluator.ts +17 -0
  219. package/src/hooks/policy-reviewability.ts +4 -2
  220. package/src/hooks/semantic/cloud-jev.ts +219 -28
  221. package/src/hooks/semantic/combine.ts +26 -1
  222. package/src/hooks/semantic/intent.ts +127 -24
  223. package/src/hooks/semantic/jev-client.ts +1 -1
  224. package/src/hooks/semantic/jev-config.ts +6 -27
  225. package/src/hooks/semantic/jev-review.ts +111 -4
  226. package/src/hooks/tui.ts +280 -0
  227. package/src/hooks/uninstall-cli.ts +12 -1
  228. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0588st-tpiuia._.js +0 -3
  229. package/.next/standalone/.next/server/chunks/ssr/_128ebxr83nk6g._.js +0 -3
  230. package/.next/standalone/.next/static/chunks/0jutamwqz8pg5.js +0 -1
  231. package/.next/standalone/.next/static/chunks/114hbolvrv94e.js +0 -1
  232. package/.next/standalone/.next/static/chunks/1p-hsi58i-6h0.js +0 -6
  233. package/.next/standalone/.next/static/chunks/3-pku9qwv1yfu.js +0 -1
  234. /package/.next/standalone/.next/static/{xq8UgF5yFxty1VWxY2hyn → D7LY1YSrw96ZxKSpxxrFw}/_buildManifest.js +0 -0
  235. /package/.next/standalone/.next/static/{xq8UgF5yFxty1VWxY2hyn → D7LY1YSrw96ZxKSpxxrFw}/_clientMiddlewareManifest.js +0 -0
  236. /package/.next/standalone/.next/static/{xq8UgF5yFxty1VWxY2hyn → D7LY1YSrw96ZxKSpxxrFw}/_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.12-beta.1";
1169
+ var version = "1.0.12";
1170
1170
  var init_package = () => {};
1171
1171
 
1172
1172
  // src/hooks/agent-targets.ts
@@ -1474,6 +1474,40 @@ function readCloudJevState() {
1474
1474
  const deployment = Number.isSafeInteger(active.deployment) ? active.deployment : null;
1475
1475
  return { jevMode, deployment, errors };
1476
1476
  }
1477
+ function readCloudJevAssignments() {
1478
+ try {
1479
+ const active = readActiveRaw();
1480
+ if (!active || !Array.isArray(active.jevPolicies))
1481
+ return null;
1482
+ const schema = active.schemaVersion;
1483
+ const out = [];
1484
+ for (const raw of active.jevPolicies) {
1485
+ if (!raw || typeof raw !== "object" || Array.isArray(raw))
1486
+ return null;
1487
+ const entry = raw;
1488
+ if (typeof entry.id !== "string" || !POLICY_ID_RE.test(entry.id))
1489
+ return null;
1490
+ if (!Number.isSafeInteger(entry.version) || entry.version < 0)
1491
+ return null;
1492
+ if (entry.effect !== undefined && entry.effect !== "enforce" && entry.effect !== "observe")
1493
+ return null;
1494
+ const targets = parseAgentTargets(entry.agentTargets, schema);
1495
+ out.push({
1496
+ id: entry.id,
1497
+ version: entry.version,
1498
+ effect: entry.effect === "observe" ? "observe" : "enforce",
1499
+ ...targets ? { agentTargets: targets } : {}
1500
+ });
1501
+ }
1502
+ return out;
1503
+ } catch {
1504
+ return null;
1505
+ }
1506
+ }
1507
+ function cloudJevAssignmentsFor(agent) {
1508
+ const all = readCloudJevAssignments();
1509
+ return all === null ? null : all.filter((a) => agentTargetsMatch(a.agentTargets, agent));
1510
+ }
1477
1511
  function cloudReviewerName(policyId, name) {
1478
1512
  return `cloud:${policyId}/${name}`;
1479
1513
  }
@@ -2104,9 +2138,11 @@ function effectiveReviewerNames() {
2104
2138
  return cached;
2105
2139
  let names = NO_REVIEWERS;
2106
2140
  cachedContested = new Map;
2141
+ cachedPackChecks = false;
2107
2142
  try {
2108
2143
  const packs = jevPacks(readInstalledPacks().packs, reviewerCli);
2109
2144
  names = reviewerNamesFor(packs);
2145
+ cachedPackChecks = names.size > 0;
2110
2146
  cachedContested = contestedSemanticNames(packs);
2111
2147
  } catch {}
2112
2148
  try {
@@ -2124,6 +2160,10 @@ function contestedReviewerNames() {
2124
2160
  function jevChecksInstalled() {
2125
2161
  return effectiveReviewerNames().size > 0;
2126
2162
  }
2163
+ function packJevChecksInstalled() {
2164
+ effectiveReviewerNames();
2165
+ return cachedPackChecks;
2166
+ }
2127
2167
  function reviewerNamesFor(packs) {
2128
2168
  const contested = contestedSemanticNames(packs);
2129
2169
  const declared = packs.flatMap((p) => (p.semantic ?? []).filter((s) => !isReservedClaim(p, s.name)).map((s) => s.name)).filter((name) => !contested.has(name));
@@ -2136,7 +2176,7 @@ function forgetEffectiveReviewerNames(cli, agent = null) {
2136
2176
  reviewerCli = cli;
2137
2177
  reviewerAgent = agent;
2138
2178
  }
2139
- var cached = null, cachedContested, reviewerCli, reviewerAgent = null;
2179
+ var cached = null, cachedPackChecks = false, cachedContested, reviewerCli, reviewerAgent = null;
2140
2180
  var init_effective_reviewers = __esm(() => {
2141
2181
  init_pack_manifest();
2142
2182
  init_policy_authority();
@@ -4362,6 +4402,57 @@ function normalizeJevFallbackReason(raw) {
4362
4402
  const code = JEV_FREE_TEXT_PREFIXES.get(head) ?? head;
4363
4403
  return JEV_REASON_CODES.has(code) ? code : JEV_REASON_OTHER;
4364
4404
  }
4405
+ function sanitizeCheck(raw) {
4406
+ if (!raw || typeof raw !== "object" || Array.isArray(raw))
4407
+ return null;
4408
+ const r = raw;
4409
+ if (typeof r.check !== "string" || !JEV_CHECK_NAME_RE.test(r.check))
4410
+ return null;
4411
+ if (typeof r.verdict !== "string" || !CHECK_VERDICT_SET.has(r.verdict))
4412
+ return null;
4413
+ if (typeof r.why !== "string" || !CHECK_WHY_SET.has(r.why))
4414
+ return null;
4415
+ if (!isP(r.p))
4416
+ return null;
4417
+ const out = {
4418
+ check: r.check,
4419
+ verdict: r.verdict,
4420
+ why: r.why,
4421
+ p: round2(r.p)
4422
+ };
4423
+ if (typeof r.policy === "string" && isJevPolicyName(r.policy) && !/\s/.test(r.policy) && /^(?:cloud|pack)\//.test(r.policy)) {
4424
+ out.policy = r.policy;
4425
+ }
4426
+ if (isP(r.exempt))
4427
+ out.exempt = round2(r.exempt);
4428
+ if (r.watched === true)
4429
+ out.watched = true;
4430
+ if (r.probes && typeof r.probes === "object" && !Array.isArray(r.probes)) {
4431
+ const probes = {};
4432
+ for (const [id, v] of Object.entries(r.probes)) {
4433
+ if (Object.keys(probes).length >= JEV_CHECK_PROBES_MAX)
4434
+ break;
4435
+ if (JEV_PROBE_ID_RE.test(id) && isP(v))
4436
+ probes[id] = round2(v);
4437
+ }
4438
+ if (Object.keys(probes).length > 0)
4439
+ out.probes = probes;
4440
+ }
4441
+ return out;
4442
+ }
4443
+ function sanitizeJevChecks(raw) {
4444
+ if (!Array.isArray(raw))
4445
+ return;
4446
+ const out = [];
4447
+ for (const item of raw) {
4448
+ if (out.length >= JEV_CHECKS_MAX)
4449
+ break;
4450
+ const rec = sanitizeCheck(item);
4451
+ if (rec)
4452
+ out.push(rec);
4453
+ }
4454
+ return raw.length > 0 && out.length === 0 ? undefined : out;
4455
+ }
4365
4456
  function sanitizeJevActivity(entry) {
4366
4457
  if (!JEV_ACTIVITY_KEYS.some((k) => entry[k] !== undefined))
4367
4458
  return entry;
@@ -4400,6 +4491,11 @@ function sanitizeJevActivity(entry) {
4400
4491
  out.jevModel = out.jevModel.trim();
4401
4492
  else
4402
4493
  drop("jevModel");
4494
+ const checks = out.evaluator === "jev" ? sanitizeJevChecks(out.jevChecks) : undefined;
4495
+ if (checks === undefined)
4496
+ drop("jevChecks");
4497
+ else
4498
+ out.jevChecks = checks;
4403
4499
  return out;
4404
4500
  }
4405
4501
  function jevOutcome(raw) {
@@ -4410,6 +4506,8 @@ function outcomeOf(e) {
4410
4506
  return "fallback";
4411
4507
  if (e.evaluator !== "jev")
4412
4508
  return null;
4509
+ if (Array.isArray(e.jevChecks) && e.jevChecks.length === 0)
4510
+ return "no-request";
4413
4511
  if (e.jevCleared !== undefined || e.jevLatencyMs !== undefined || e.jevModel !== undefined)
4414
4512
  return "answered";
4415
4513
  if (e.jevDecision === "deny" || e.jevDecision === "instruct")
@@ -4418,7 +4516,7 @@ function outcomeOf(e) {
4418
4516
  return "no-request";
4419
4517
  return "not-consulted";
4420
4518
  }
4421
- var JEV_ACTIVITY_KEYS, EVALUATORS, DECISIONS, MODES, REASON_HEAD_RE, HTTP_CODE_RE, JEV_REASON_MAX_CHARS = 40, JEV_REASON_OTHER = "other", JEV_REASON_CODE_LIST, JEV_REASON_CODES, JEV_REASON_REQUEST_CUT = "request-cut", JEV_REASON_PROVIDER_REFUSED = "provider-refused", JEV_FREE_TEXT_PREFIXES, JEV_MODEL_RE, JEV_POLICY_NAME_MAX_CHARS = 200, NAME_FORBIDDEN_RE, REGISTERED_NAMESPACE_RE, JEV_CLEARED_MAX = 64, ANSWERED_BUT_NOT_APPLIED_REASONS;
4519
+ var JEV_ACTIVITY_KEYS, EVALUATORS, DECISIONS, MODES, REASON_HEAD_RE, HTTP_CODE_RE, JEV_REASON_MAX_CHARS = 40, JEV_REASON_OTHER = "other", JEV_REASON_CODE_LIST, JEV_REASON_CODES, JEV_REASON_REQUEST_CUT = "request-cut", JEV_REASON_PROVIDER_REFUSED = "provider-refused", JEV_FREE_TEXT_PREFIXES, JEV_MODEL_RE, JEV_POLICY_NAME_MAX_CHARS = 200, NAME_FORBIDDEN_RE, REGISTERED_NAMESPACE_RE, JEV_CLEARED_MAX = 64, JEV_CHECK_VERDICTS, JEV_CHECK_WHY, JEV_CHECKS_MAX = 32, JEV_CHECK_PROBES_MAX = 8, JEV_CHECK_NAME_RE, JEV_PROBE_ID_RE, CHECK_VERDICT_SET, CHECK_WHY_SET, isP = (v) => typeof v === "number" && Number.isFinite(v) && v >= 0 && v <= 1, round2 = (v) => Math.round(v * 100) / 100, ANSWERED_BUT_NOT_APPLIED_REASONS;
4422
4520
  var init_jev_activity = __esm(() => {
4423
4521
  JEV_ACTIVITY_KEYS = [
4424
4522
  "evaluator",
@@ -4427,7 +4525,8 @@ var init_jev_activity = __esm(() => {
4427
4525
  "jevFallbackReason",
4428
4526
  "jevLatencyMs",
4429
4527
  "jevModel",
4430
- "jevMode"
4528
+ "jevMode",
4529
+ "jevChecks"
4431
4530
  ];
4432
4531
  EVALUATORS = new Set(["jev", "jev-fallback"]);
4433
4532
  DECISIONS = new Set(["allow", "instruct", "deny"]);
@@ -4474,6 +4573,22 @@ var init_jev_activity = __esm(() => {
4474
4573
  JEV_MODEL_RE = /^[A-Za-z0-9._:/@~+-]{1,200}$/;
4475
4574
  NAME_FORBIDDEN_RE = /[\u0000-\u001f\u007f-\u009f\u2028\u2029]/;
4476
4575
  REGISTERED_NAMESPACE_RE = /^(?:custom|pack|cloud|failproofai|\.failproofai-[A-Za-z0-9_-]{1,32})\//;
4576
+ JEV_CHECK_VERDICTS = ["none", "deny", "instruct", "overridden"];
4577
+ JEV_CHECK_WHY = [
4578
+ "not-detected",
4579
+ "exempt",
4580
+ "fired",
4581
+ "injection",
4582
+ "user-asked",
4583
+ "op-requested",
4584
+ "task-step",
4585
+ "downgraded",
4586
+ "scan-incomplete"
4587
+ ];
4588
+ JEV_CHECK_NAME_RE = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
4589
+ JEV_PROBE_ID_RE = /^[a-z][a-z0-9_]{0,31}$/;
4590
+ CHECK_VERDICT_SET = new Set(JEV_CHECK_VERDICTS);
4591
+ CHECK_WHY_SET = new Set(JEV_CHECK_WHY);
4477
4592
  ANSWERED_BUT_NOT_APPLIED_REASONS = new Set([
4478
4593
  JEV_REASON_REQUEST_CUT,
4479
4594
  "truncated",
@@ -4534,7 +4649,8 @@ function combineTwoTier(verdicts, review, mode) {
4534
4649
  ...cleared.length > 0 && RANK[enforced.final.decision] < RANK[legacy.decision] ? { jevCleared: cleared } : {},
4535
4650
  ...review.latencyMs !== null ? { jevLatencyMs: review.latencyMs } : {},
4536
4651
  ...review.model ? { jevModel: review.model } : {},
4537
- jevMode: mode
4652
+ jevMode: mode,
4653
+ ...review.checks ? { jevChecks: [...review.checks] } : {}
4538
4654
  };
4539
4655
  if (mode === "observe") {
4540
4656
  const observeVerdict = review.decision === "deny" || review.decision === "instruct" ? {
@@ -5201,6 +5317,12 @@ async function evaluatePolicies(eventType, payload, session, config, twoTier) {
5201
5317
  twoTier.releaseRegistry?.();
5202
5318
  review = await twoTier.review;
5203
5319
  }
5320
+ if (review.kind === "answered" && review.asked.length === 0 && review.decision === "allow" && !review.observedAsked?.length) {
5321
+ return formatVerdict(eventType, session, toolName, regexOnly(collected.verdicts));
5322
+ }
5323
+ if (review.kind === "not-consulted" && twoTier.cloud) {
5324
+ return formatVerdict(eventType, session, toolName, regexOnly(collected.verdicts));
5325
+ }
5204
5326
  const combined = combineTwoTier(collected.verdicts, review, twoTier.mode);
5205
5327
  if (combined.cleared.length > 0) {
5206
5328
  hookLogInfo(`jev ${twoTier.mode === "observe" ? "would clear" : "cleared"}: ${combined.cleared.join(", ")}`);
@@ -5214,7 +5336,8 @@ async function evaluatePolicies(eventType, payload, session, config, twoTier) {
5214
5336
  activity: combined.activity,
5215
5337
  decidedByJev: combined.decidedByJev,
5216
5338
  ...(combined.decidedByJev || combined.observeVerdict) && review.kind === "answered" && review.origin ? { jevOrigin: review.origin } : {},
5217
- ...combined.observeVerdict ? { observeVerdict: combined.observeVerdict } : {}
5339
+ ...combined.observeVerdict ? { observeVerdict: combined.observeVerdict } : {},
5340
+ ...review.kind === "answered" && review.observedCloud?.length ? { observedCloud: review.observedCloud } : {}
5218
5341
  }
5219
5342
  };
5220
5343
  }
@@ -12092,7 +12215,13 @@ function runtimeAgentSettingsPath(cli, cwd, userHome = homedir21(), hookScope) {
12092
12215
  if (config?.trim())
12093
12216
  return resolve15(config);
12094
12217
  const state = process.env.OPENCLAW_STATE_DIR || process.env.OPENCLAW_HOME;
12095
- return resolve15(state?.trim() ? state : resolve15(userHome, ".openclaw"), "openclaw.json");
12218
+ if (state?.trim())
12219
+ return resolve15(state, "openclaw.json");
12220
+ const profile = process.env.OPENCLAW_PROFILE?.trim();
12221
+ if (profile && profile !== "default" && /^[A-Za-z0-9._-]{1,80}$/.test(profile) && !profile.startsWith(".")) {
12222
+ return resolve15(userHome, `.openclaw-${profile}`, "openclaw.json");
12223
+ }
12224
+ return resolve15(userHome, ".openclaw", "openclaw.json");
12096
12225
  }
12097
12226
  const relative = USER_SETTINGS[cli];
12098
12227
  if (!relative)
@@ -12246,13 +12375,6 @@ function validateBaseUrl(raw) {
12246
12375
  url.pathname = url.pathname.replace(/\/+$/, "") || "/";
12247
12376
  return { ok: true, value: url.toString() };
12248
12377
  }
12249
- function isPlainHttp(url) {
12250
- try {
12251
- return new URL(url).protocol === "http:";
12252
- } catch {
12253
- return false;
12254
- }
12255
- }
12256
12378
  function originOf(raw) {
12257
12379
  try {
12258
12380
  const url = new URL(raw);
@@ -12387,12 +12509,6 @@ function validateJevConfig(raw, envKey, cloud) {
12387
12509
  return { ok: false, problem: 'mode must be "off", "observe" or "enforce"' };
12388
12510
  cfg.mode = mode;
12389
12511
  }
12390
- if (cfg.baseUrl !== undefined && isPlainHttp(cfg.baseUrl) && cfg.mode === "enforce") {
12391
- return {
12392
- ok: false,
12393
- problem: "plain http (to localhost) is accepted only with mode observe: in enforce mode Jev's answers can clear a deny, " + "and while the local proxy is down any process on this machine could take its port and answer. " + (cfg.provider === JEV_CLOUD_PROVIDER ? "Reconnect to an https FailproofAI Cloud URL (failproofai config --token <key> --url https://…), or keep mode observe" : "Use https, or mode observe")
12394
- };
12395
- }
12396
12512
  return { ok: true, value: cfg };
12397
12513
  }
12398
12514
  function validateLoadedJevConfig(cfg) {
@@ -15590,6 +15706,7 @@ __export(exports_intent, {
15590
15706
  cleanHumanTurn: () => cleanHumanTurn,
15591
15707
  cleanUserSaid: () => cleanUserSaid,
15592
15708
  humanMessageText: () => humanMessageText,
15709
+ intentProfileKey: () => intentProfileKey,
15593
15710
  lastAgentMessage: () => lastAgentMessage,
15594
15711
  looseIntentStoreDir: () => looseIntentStoreDir,
15595
15712
  pruneExpiredSessions: () => pruneExpiredSessions,
@@ -15609,13 +15726,27 @@ import {
15609
15726
  writeFileSync as writeFileSync8
15610
15727
  } from "node:fs";
15611
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
+ }
15612
15743
  function modesAreMeaningful2() {
15613
15744
  return process.platform !== "win32";
15614
15745
  }
15615
- function storeDirChain() {
15746
+ function storeDirChain(innermost = sessionsDir()) {
15616
15747
  const home = resolve17(failproofaiHome());
15617
15748
  const chain = [];
15618
- let dir = sessionsDir();
15749
+ let dir = innermost;
15619
15750
  for (let i = 0;i < 8; i++) {
15620
15751
  chain.push(dir);
15621
15752
  if (dir === home)
@@ -15627,10 +15758,10 @@ function storeDirChain() {
15627
15758
  }
15628
15759
  return chain;
15629
15760
  }
15630
- function looseIntentStoreDir() {
15761
+ function looseIntentStoreDir(innermost) {
15631
15762
  if (!modesAreMeaningful2())
15632
15763
  return null;
15633
- for (const dir of storeDirChain()) {
15764
+ for (const dir of storeDirChain(innermost)) {
15634
15765
  let mode;
15635
15766
  try {
15636
15767
  mode = statSync20(dir).mode & 511;
@@ -15649,23 +15780,22 @@ function looseIntentStoreDir() {
15649
15780
  }
15650
15781
  return null;
15651
15782
  }
15652
- function readIntentFile(sessionId) {
15783
+ function readIntentFile(slot) {
15653
15784
  try {
15654
- const parsed = JSON.parse(readFileSync19(intentFile(sessionId), "utf8"));
15785
+ const parsed = JSON.parse(readFileSync19(slot.file, "utf8"));
15655
15786
  return Array.isArray(parsed?.prompts) ? parsed : { prompts: [] };
15656
15787
  } catch {
15657
15788
  return { prompts: [] };
15658
15789
  }
15659
15790
  }
15660
- function appendPrompt(sessionId, entry) {
15791
+ function appendPrompt(slot, entry) {
15661
15792
  try {
15662
- const file = readIntentFile(sessionId);
15793
+ const file = readIntentFile(slot);
15663
15794
  const last = file.prompts[file.prompts.length - 1];
15664
15795
  const kept = last && last.text === entry.text ? file.prompts.slice(0, -1) : file.prompts;
15665
15796
  file.prompts = [...kept, entry].slice(-MAX_RECORDED_PROMPTS);
15666
- const dir = sessionsDir();
15667
- mkdirSync9(dir, { recursive: true, mode: 448 });
15668
- const target = intentFile(sessionId);
15797
+ mkdirSync9(slot.dir, { recursive: true, mode: 448 });
15798
+ const target = slot.file;
15669
15799
  const isNew = !fileExists2(target);
15670
15800
  const tmp = `${target}.${process.pid}.tmp`;
15671
15801
  writeFileSync8(tmp, JSON.stringify(file), { mode: 384 });
@@ -15686,9 +15816,24 @@ function fileExists2(path) {
15686
15816
  }
15687
15817
  }
15688
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) {
15689
15835
  let removed = 0;
15690
15836
  try {
15691
- const dir = sessionsDir();
15692
15837
  for (const name of readdirSync13(dir)) {
15693
15838
  if (!SESSION_FILE_RE3.test(name))
15694
15839
  continue;
@@ -15704,23 +15849,29 @@ function pruneExpiredSessions(now = Date.now()) {
15704
15849
  } catch {}
15705
15850
  return removed;
15706
15851
  }
15707
- function recordPrompt(sessionId, prompt, agent, now) {
15852
+ function recordPrompt(sessionId, profile, prompt, agent, now) {
15708
15853
  if (!SESSION_ID_RE2.test(sessionId))
15709
15854
  return false;
15710
15855
  if (prompt.trim().length === 0)
15711
15856
  return false;
15857
+ const slot = storeSlot(sessionId, profile);
15858
+ if (!slot)
15859
+ return false;
15712
15860
  try {
15713
- return appendPrompt(sessionId, { at: now, text: storable(prompt.trim()), agent: agent === null ? null : storable(agent) });
15861
+ return appendPrompt(slot, { at: now, text: storable(prompt.trim()), agent: agent === null ? null : storable(agent) });
15714
15862
  } catch {
15715
15863
  return false;
15716
15864
  }
15717
15865
  }
15718
- function livePrompts(sessionId, now) {
15866
+ function livePrompts(sessionId, now, profile) {
15719
15867
  if (!sessionId || !SESSION_ID_RE2.test(sessionId))
15720
15868
  return [];
15721
- if (looseIntentStoreDir() !== null)
15869
+ const slot = storeSlot(sessionId, profile);
15870
+ if (!slot)
15871
+ return [];
15872
+ if (looseIntentStoreDir(slot.dir) !== null)
15722
15873
  return [];
15723
- return readIntentFile(sessionId).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);
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);
15724
15875
  }
15725
15876
  function replaceTagBlocks(text, tag, replace, attributes = false) {
15726
15877
  const open = attributes ? `<${tag}` : `<${tag}>`;
@@ -16067,16 +16218,16 @@ function captureIntent(ev, now = Date.now()) {
16067
16218
  const cleaned = cleanHumanTurn(raw);
16068
16219
  if (cleaned === null)
16069
16220
  return;
16070
- recordPrompt(sessionId, cleaned, lastAgentMessage(ev.transcriptPath), now);
16221
+ recordPrompt(sessionId, ev.profile, cleaned, lastAgentMessage(ev.transcriptPath), now);
16071
16222
  } catch {}
16072
16223
  }
16073
- function readIntent(sessionId, now = Date.now()) {
16074
- const prompts = livePrompts(sessionId, now);
16224
+ function readIntent(sessionId, now = Date.now(), profile) {
16225
+ const prompts = livePrompts(sessionId, now, profile);
16075
16226
  const latest = prompts[prompts.length - 1];
16076
16227
  const agent = latest && typeof latest.agent === "string" && latest.agent.length > 0 ? latest.agent : null;
16077
16228
  return { userSaid: prompts.map((p) => p.text), agentLastMessage: agent };
16078
16229
  }
16079
- var MAX_RECORDED_PROMPTS = 5, INTENT_MAX_AGE_MS, MAX_CLOCK_SKEW_MS, SESSION_ID_RE2, sessionsDir = () => resolve17(semanticDir(), "sessions"), intentFile = (sessionId) => resolve17(sessionsDir(), `${sessionId}.json`), DIR_WRITABLE_BY_OTHERS3 = 18, SESSION_FILE_RE3, NON_HUMAN_PREFIXES, CONTINUATION_PREFIX = "This session is being continued from a previous conversation", IDE_MACHINE_OPENERS, IDE_AMBIGUOUS_OPENERS, IDE_REQUEST_HEADINGS, obj = (v) => v && typeof v === "object" && !Array.isArray(v) ? v : undefined, CLAUDE_MACHINE_SOURCES, claudeMachineTurn = (payload) => typeof payload.source === "string" && CLAUDE_MACHINE_SOURCES.has(payload.source), piMachineTurn = (payload) => payload.input_source === "extension" || payload.source === "extension", openclawMachineRun = (payload) => {
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) => {
16080
16231
  const meta = obj(payload.openclaw);
16081
16232
  if (!meta)
16082
16233
  return false;
@@ -16092,9 +16243,11 @@ var MAX_RECORDED_PROMPTS = 5, INTENT_MAX_AGE_MS, MAX_CLOCK_SKEW_MS, SESSION_ID_R
16092
16243
  var init_intent = __esm(() => {
16093
16244
  init_fp_home();
16094
16245
  init_envelope();
16246
+ init_agent_targets();
16095
16247
  INTENT_MAX_AGE_MS = 6 * 60 * 60 * 1000;
16096
16248
  MAX_CLOCK_SKEW_MS = 5 * 60 * 1000;
16097
16249
  SESSION_ID_RE2 = /^[A-Za-z0-9._-]{1,128}$/;
16250
+ PROFILE_DIR_RE = /^[a-z]+(?:\.agt_[0-9a-f]{16,32})?$/;
16098
16251
  SESSION_FILE_RE3 = /^[A-Za-z0-9._-]{1,128}\.json(?:\.\d+\.tmp)?$/;
16099
16252
  NON_HUMAN_PREFIXES = [
16100
16253
  "<local-command-caveat>",
@@ -17004,7 +17157,11 @@ function parseOutcome(raw, i) {
17004
17157
  if (!origin || typeof origin !== "object" || typeof origin.cloudPolicyId !== "string" || !POLICY_ID_RE2.test(origin.cloudPolicyId) || !Number.isSafeInteger(origin.cloudVersion) || origin.cloudVersion < 0) {
17005
17158
  malformed(`outcome ${i} has no Cloud origin`);
17006
17159
  }
17007
- return {
17160
+ if (o.effect !== undefined && o.effect !== "enforce" && o.effect !== "observe")
17161
+ malformed(`outcome ${i} has an unknown effect`);
17162
+ if (o.reason !== undefined && o.reason !== null && typeof o.reason !== "string")
17163
+ malformed(`outcome ${i} reason is not text`);
17164
+ const outcome = {
17008
17165
  policy: o.policy,
17009
17166
  mode: o.mode,
17010
17167
  ...typeof o.userCanOverride === "boolean" ? { userCanOverride: o.userCanOverride } : {},
@@ -17018,41 +17175,103 @@ function parseOutcome(raw, i) {
17018
17175
  ...o.intent !== undefined ? { intent: o.intent } : {},
17019
17176
  ...o.targetScanIncomplete === true ? { targetScanIncomplete: true } : {}
17020
17177
  };
17178
+ return {
17179
+ outcome,
17180
+ cloudPolicyId: origin.cloudPolicyId,
17181
+ cloudVersion: origin.cloudVersion,
17182
+ observe: o.effect === "observe",
17183
+ reason: typeof o.reason === "string" ? capReason(o.reason) : null
17184
+ };
17021
17185
  }
17022
- function parseCloudReply(raw) {
17023
- if (!raw || typeof raw !== "object" || Array.isArray(raw))
17024
- malformed("no cloud block");
17025
- const block = raw;
17026
- const v = block.verdict;
17186
+ function capReason(reason) {
17187
+ return reason.length > MAX_CLOUD_REASON_CHARS ? `${reason.slice(0, MAX_CLOUD_REASON_CHARS - 1)}…` : reason;
17188
+ }
17189
+ function observedChecks(parsed, watched = null) {
17190
+ const firing = watched?.parsed.filter((p) => p.outcome.verdict === "deny" || p.outcome.verdict === "instruct") ?? [];
17191
+ const watchedReason = firing.length === 1 && typeof watched?.v.reason === "string" ? capReason(watched.v.reason) : null;
17192
+ const byPolicy = new Map;
17193
+ for (const p of parsed) {
17194
+ const verdict = p.outcome.verdict;
17195
+ if (verdict !== "deny" && verdict !== "instruct")
17196
+ continue;
17197
+ const prev = byPolicy.get(p.cloudPolicyId);
17198
+ if (prev && SEVERITY[prev.decision] >= SEVERITY[verdict])
17199
+ continue;
17200
+ byPolicy.set(p.cloudPolicyId, {
17201
+ cloudPolicyId: p.cloudPolicyId,
17202
+ cloudVersion: p.cloudVersion,
17203
+ check: p.outcome.policy,
17204
+ decision: verdict,
17205
+ reason: p.reason ?? (firing[0] === p ? watchedReason : null) ?? `Flagged by semantic review (semantic/${p.outcome.policy})`
17206
+ });
17207
+ }
17208
+ return [...byPolicy.values()];
17209
+ }
17210
+ function parseVerdictBlock(rawVerdict, rawAsked, what) {
17211
+ const v = rawVerdict;
17027
17212
  if (!v || typeof v !== "object" || Array.isArray(v))
17028
- malformed("no verdict");
17213
+ malformed(`no ${what}`);
17029
17214
  if (typeof v.decision !== "string" || !DECISIONS2.has(v.decision))
17030
- malformed("verdict has no decision");
17215
+ malformed(`${what} has no decision`);
17031
17216
  if (v.reason !== null && v.reason !== undefined && typeof v.reason !== "string")
17032
- malformed("verdict reason is not text");
17217
+ malformed(`${what} reason is not text`);
17033
17218
  if (!Array.isArray(v.outcomes) || v.outcomes.length > MAX_LIST)
17034
- malformed("verdict has no outcomes list");
17219
+ malformed(`${what} has no outcomes list`);
17035
17220
  if (v.beyondTask !== undefined && typeof v.beyondTask !== "boolean")
17036
- malformed("verdict beyondTask is not a flag");
17037
- const outcomes = v.outcomes.map(parseOutcome);
17038
- const asked = names(block.asked, "asked");
17221
+ malformed(`${what} beyondTask is not a flag`);
17222
+ const parsed = v.outcomes.map(parseOutcome);
17223
+ const asked = names(rawAsked, `${what} asked`);
17039
17224
  const askedSet = new Set(asked);
17040
17225
  const seen = new Set;
17041
- outcomes.forEach((o, i) => {
17226
+ parsed.forEach(({ outcome: o }, i) => {
17042
17227
  if (!askedSet.has(o.policy))
17043
- malformed(`outcome ${i} answers ${JSON.stringify(o.policy)}, which Cloud did not ask`);
17228
+ malformed(`${what} outcome ${i} answers ${JSON.stringify(o.policy)}, which Cloud did not ask`);
17044
17229
  const key = `${o.origin?.packId ?? ""}\x00${o.policy}`;
17045
17230
  if (seen.has(key))
17046
- malformed(`outcome ${i} answers ${JSON.stringify(o.policy)} twice`);
17231
+ malformed(`${what} outcome ${i} answers ${JSON.stringify(o.policy)} twice`);
17047
17232
  seen.add(key);
17048
17233
  });
17049
- if (outcomes.some((o) => o.verdict === "deny") && v.decision !== "deny")
17234
+ return { v, parsed, asked };
17235
+ }
17236
+ function parseCloudReply(raw, observedPolicies = []) {
17237
+ if (!raw || typeof raw !== "object" || Array.isArray(raw))
17238
+ malformed("no cloud block");
17239
+ const block = raw;
17240
+ const { v, parsed, asked } = parseVerdictBlock(block.verdict, block.asked, "verdict");
17241
+ let watched = null;
17242
+ if (block.observed !== undefined && block.observed !== null) {
17243
+ const o = block.observed;
17244
+ if (typeof o !== "object" || Array.isArray(o))
17245
+ malformed("observed is not an object");
17246
+ watched = parseVerdictBlock(o.verdict, o.asked, "observed verdict");
17247
+ if (watched.parsed.some((p) => p.outcome.verdict === "deny") && watched.v.decision !== "deny") {
17248
+ malformed("an observed check denied but its verdict does not");
17249
+ }
17250
+ }
17251
+ const observeIds = new Set(observedPolicies);
17252
+ const isObserved = (p) => p.observe || observeIds.has(p.cloudPolicyId);
17253
+ const enforced = parsed.filter((p) => !isObserved(p)).map((p) => p.outcome);
17254
+ const observedHere = parsed.filter(isObserved);
17255
+ const observed = [...observedHere, ...watched?.parsed ?? []];
17256
+ if (enforced.some((o) => o.verdict === "deny") && v.decision !== "deny")
17050
17257
  malformed("a check denied but the verdict does not");
17258
+ const cloudReason = typeof v.reason === "string" ? capReason(v.reason) : null;
17259
+ let decision = v.decision;
17260
+ let reason = cloudReason;
17261
+ if (observedHere.length > 0) {
17262
+ const own = enforced.some((o) => o.verdict === "deny") ? "deny" : enforced.some((o) => o.verdict === "instruct") || v.beyondTask === true ? "instruct" : "allow";
17263
+ const capped = RANK2[own] <= RANK2[decision] ? own : decision;
17264
+ if (capped !== decision)
17265
+ reason = null;
17266
+ decision = capped;
17267
+ }
17051
17268
  return {
17269
+ observed: observedChecks(observed, watched),
17270
+ observedAsked: [...observedHere.map((p) => p.outcome.policy), ...watched?.asked ?? []],
17052
17271
  verdict: {
17053
- decision: v.decision,
17054
- reason: typeof v.reason === "string" ? v.reason.length > MAX_CLOUD_REASON_CHARS ? `${v.reason.slice(0, MAX_CLOUD_REASON_CHARS - 1)}…` : v.reason : null,
17055
- outcomes,
17272
+ decision,
17273
+ reason,
17274
+ outcomes: enforced,
17056
17275
  injectionSuspected: nullableProbability(v.injectionSuspected, "injectionSuspected"),
17057
17276
  scopeWithinRequest: nullableProbability(v.scopeWithinRequest, "scopeWithinRequest"),
17058
17277
  beyondTask: v.beyondTask === true
@@ -17062,6 +17281,29 @@ function parseCloudReply(raw) {
17062
17281
  droppedCloud: names(block.droppedCloud, "droppedCloud")
17063
17282
  };
17064
17283
  }
17284
+ function parseObservedOutcomes(raw) {
17285
+ try {
17286
+ const block = raw?.observed;
17287
+ if (!block || typeof block !== "object" || Array.isArray(block))
17288
+ return [];
17289
+ const asked = new Set(names(block.asked, "observed.asked"));
17290
+ const outcomes = block.verdict?.outcomes ?? [];
17291
+ if (!Array.isArray(outcomes) || outcomes.length > MAX_LIST)
17292
+ return [];
17293
+ const seen = new Set;
17294
+ const out = [];
17295
+ outcomes.forEach((o, i) => {
17296
+ const parsed = parseOutcome(o, i).outcome;
17297
+ if (!asked.has(parsed.policy) || seen.has(parsed.policy))
17298
+ return;
17299
+ seen.add(parsed.policy);
17300
+ out.push(parsed);
17301
+ });
17302
+ return out;
17303
+ } catch {
17304
+ return [];
17305
+ }
17306
+ }
17065
17307
  function joinLines(reasons) {
17066
17308
  const lines = [];
17067
17309
  for (const reason of reasons) {
@@ -17108,6 +17350,22 @@ function expectedQuestions(request, prepared, dropped) {
17108
17350
  }));
17109
17351
  return { ...request, questions };
17110
17352
  }
17353
+ function cloudCheckAnswers(response, asked) {
17354
+ const out = {};
17355
+ if (asked.length === 0)
17356
+ return out;
17357
+ const names = new Set(asked);
17358
+ const answers = response.answers && typeof response.answers === "object" ? response.answers : {};
17359
+ for (const [id, a] of Object.entries(answers)) {
17360
+ const dot = id.lastIndexOf(".");
17361
+ if (dot <= 0 || !names.has(id.slice(0, dot)) || !QUESTION_PART_RE.test(id.slice(dot + 1)))
17362
+ continue;
17363
+ const p = a?.noul;
17364
+ if (isProbability(p))
17365
+ out[id] = p;
17366
+ }
17367
+ return out;
17368
+ }
17111
17369
  function presentAnswers(response) {
17112
17370
  const out = {};
17113
17371
  const answers = response.answers && typeof response.answers === "object" ? response.answers : {};
@@ -17136,7 +17394,7 @@ async function evaluateCloudSemantic(input, opts) {
17136
17394
  model: opts.model ?? DEFAULT_JEV_MODEL,
17137
17395
  modelVerified: true,
17138
17396
  via: "none",
17139
- cloud: { asked: [], droppedLocal: [], droppedCloud: [] }
17397
+ cloud: { asked: [], droppedLocal: [], droppedCloud: [], answers: {}, observed: [], observedAsked: [], observedOutcomes: [] }
17140
17398
  };
17141
17399
  }
17142
17400
  let prepared;
@@ -17177,11 +17435,13 @@ async function evaluateCloudSemantic(input, opts) {
17177
17435
  const timeout = AbortSignal.timeout(opts.timeoutMs ?? envNumber2("FAILPROOFAI_JEV_TIMEOUT_MS", DEFAULT_JEV_TIMEOUT_MS));
17178
17436
  const signal = opts.signal ? AbortSignal.any([timeout, opts.signal]) : timeout;
17179
17437
  const response = await transport(request, signal);
17180
- const reply = parseCloudReply(response.cloud);
17438
+ const reply = parseCloudReply(response.cloud, opts.observedPolicies);
17439
+ const observedAsked = new Set(reply.observedAsked);
17440
+ const observedOutcomes = parseObservedOutcomes(response.cloud).filter((o) => observedAsked.has(o.policy));
17181
17441
  const own = new Map(prepared.selected.map((p) => [p.name, p]));
17182
17442
  const dropped = new Set(reply.droppedLocal.filter((name) => own.has(name)));
17183
17443
  const kept = prepared.selected.filter((p) => !dropped.has(p.name));
17184
- const shortCircuit = kept.length === 0 && reply.asked.length === 0 && reply.verdict.outcomes.length === 0;
17444
+ const shortCircuit = kept.length === 0 && reply.asked.length === 0 && reply.verdict.outcomes.length === 0 && reply.observedAsked.length === 0;
17185
17445
  const answers = shortCircuit ? presentAnswers(response) : readAnswers(expectedQuestions(request, prepared, dropped), response);
17186
17446
  const local = prepared.intent === "v1" ? decideV1(kept, answers, input.toolInput, prepared.userSaid, prepared.agentLastMessage, {
17187
17447
  ...opts.v1,
@@ -17203,7 +17463,11 @@ async function evaluateCloudSemantic(input, opts) {
17203
17463
  cloud: {
17204
17464
  asked: reply.asked,
17205
17465
  droppedLocal: [...dropped].map((name) => ({ name, packId: own.get(name)?.origin?.packId ?? null })),
17206
- droppedCloud: reply.droppedCloud
17466
+ droppedCloud: reply.droppedCloud,
17467
+ answers: cloudCheckAnswers(response, [...reply.asked, ...reply.observedAsked]),
17468
+ observed: reply.observed,
17469
+ observedAsked: reply.observedAsked,
17470
+ observedOutcomes
17207
17471
  }
17208
17472
  };
17209
17473
  } catch (err) {
@@ -17216,7 +17480,7 @@ async function evaluateCloudSemantic(input, opts) {
17216
17480
  return degraded(`error: ${err instanceof Error ? err.message : String(err)}`);
17217
17481
  }
17218
17482
  }
17219
- var CLOUD_BLOCK_VERSION = 1, MAX_TARGET_SCAN_CHARS = 64000, MAX_CLOUD_BLOCK_BYTES = 240000, blockBytes = (block) => Buffer.byteLength(JSON.stringify(block), "utf8"), REDACTED_TARGET_WORD = "\x00redacted", MAX_SECRET_SCAN_CHARS, REDACTION_MARKER, REDACTED_SAID = "\x00", POLICY_ID_RE2, MAX_NAME_CHARS = 256, MAX_LIST = 4096, MAX_CLOUD_REASON_CHARS = 8192, isProbability = (v) => typeof v === "number" && Number.isFinite(v) && v >= 0 && v <= 1, isName2 = (v) => typeof v === "string" && v.length > 0 && v.length <= MAX_NAME_CHARS, DECISIONS2, VERDICTS, INTENTS, RANK2, EMPTY_ALLOW;
17483
+ var CLOUD_BLOCK_VERSION = 1, MAX_TARGET_SCAN_CHARS = 64000, MAX_CLOUD_BLOCK_BYTES = 240000, blockBytes = (block) => Buffer.byteLength(JSON.stringify(block), "utf8"), REDACTED_TARGET_WORD = "\x00redacted", MAX_SECRET_SCAN_CHARS, REDACTION_MARKER, REDACTED_SAID = "\x00", POLICY_ID_RE2, MAX_NAME_CHARS = 256, MAX_LIST = 4096, MAX_CLOUD_REASON_CHARS = 8192, isProbability = (v) => typeof v === "number" && Number.isFinite(v) && v >= 0 && v <= 1, isName2 = (v) => typeof v === "string" && v.length > 0 && v.length <= MAX_NAME_CHARS, DECISIONS2, VERDICTS, INTENTS, SEVERITY, RANK2, EMPTY_ALLOW, QUESTION_PART_RE;
17220
17484
  var init_cloud_jev = __esm(() => {
17221
17485
  init_compile();
17222
17486
  init_decide();
@@ -17232,6 +17496,7 @@ var init_cloud_jev = __esm(() => {
17232
17496
  DECISIONS2 = new Set(["allow", "deny", "instruct"]);
17233
17497
  VERDICTS = new Set(["deny", "instruct", "overridden", "none"]);
17234
17498
  INTENTS = new Set(["op-requested", "task-step", "downgraded-task-step"]);
17499
+ SEVERITY = { instruct: 1, deny: 2 };
17235
17500
  RANK2 = { allow: 0, instruct: 1, deny: 2 };
17236
17501
  EMPTY_ALLOW = {
17237
17502
  decision: "allow",
@@ -17241,6 +17506,7 @@ var init_cloud_jev = __esm(() => {
17241
17506
  scopeWithinRequest: null,
17242
17507
  beyondTask: false
17243
17508
  };
17509
+ QUESTION_PART_RE = /^[a-z][a-z0-9_]{0,31}$/;
17244
17510
  });
17245
17511
 
17246
17512
  // src/hooks/semantic/jev-throttle.ts
@@ -17576,6 +17842,55 @@ function fallbackCode(reason) {
17576
17842
  const code = reason.split(":")[0].trim();
17577
17843
  return /^[a-z0-9][a-z0-9-]{0,63}$/.test(code) ? code : "error";
17578
17844
  }
17845
+ function checkWhy(o) {
17846
+ switch (o.verdict) {
17847
+ case "none":
17848
+ return o.evidence < DEFAULT_THRESHOLDS_V1.fire ? "not-detected" : "exempt";
17849
+ case "overridden":
17850
+ return o.intent === "op-requested" ? "op-requested" : o.intent === "task-step" ? "task-step" : "user-asked";
17851
+ case "deny":
17852
+ return o.escalatedByInjection ? "injection" : "fired";
17853
+ default:
17854
+ if (o.intent === "downgraded-task-step")
17855
+ return "downgraded";
17856
+ return o.targetScanIncomplete ? "scan-incomplete" : "fired";
17857
+ }
17858
+ }
17859
+ function checkPolicy(o) {
17860
+ const packId = o.origin?.packId;
17861
+ if (!packId)
17862
+ return;
17863
+ const at = o.origin?.packVersion ? `@${o.origin.packVersion}` : "";
17864
+ return packId.startsWith("cloud:") ? `cloud/${packId.slice("cloud:".length)}${at}` : `pack/${packId}${at}`;
17865
+ }
17866
+ function checkRecords(outcomes, answers, watched = []) {
17867
+ const all = [...outcomes.map((o) => ({ o, watched: false })), ...watched.map((o) => ({ o, watched: true }))];
17868
+ return all.slice(0, JEV_CHECKS_MAX).map(({ o, watched: isWatched }) => {
17869
+ const probes = {};
17870
+ const prefix = `${o.policy}.`;
17871
+ for (const [id, p] of Object.entries(answers)) {
17872
+ if (Object.keys(probes).length >= JEV_CHECK_PROBES_MAX)
17873
+ break;
17874
+ if (!id.startsWith(prefix))
17875
+ continue;
17876
+ const part = id.slice(prefix.length);
17877
+ if (part === "exempt" || part === "user_asked" || !JEV_PROBE_ID_RE.test(part))
17878
+ continue;
17879
+ probes[part] = round2(p);
17880
+ }
17881
+ const policy = checkPolicy(o);
17882
+ return {
17883
+ check: o.policy,
17884
+ ...policy ? { policy } : {},
17885
+ verdict: o.verdict,
17886
+ why: checkWhy(o),
17887
+ p: round2(o.evidence),
17888
+ ...o.exempt !== null ? { exempt: round2(o.exempt) } : {},
17889
+ ...Object.keys(probes).length > 0 ? { probes } : {},
17890
+ ...isWatched ? { watched: true } : {}
17891
+ };
17892
+ });
17893
+ }
17579
17894
  function toReview(outcome, cached = false) {
17580
17895
  if (outcome.status === "degraded") {
17581
17896
  return { kind: "fallback", reason: fallbackCode(outcome.reason), latencyMs: outcome.latencyMs, model: null };
@@ -17584,15 +17899,19 @@ function toReview(outcome, cached = false) {
17584
17899
  const latencyMs = sent && !cached ? outcome.latencyMs : null;
17585
17900
  const model = sent ? outcome.model : null;
17586
17901
  const outcomes = outcome.verdict.outcomes;
17587
- const cloudAsked = "cloud" in outcome ? new Set(outcome.cloud.asked) : null;
17902
+ const cloudSummary = "cloud" in outcome ? outcome.cloud : null;
17903
+ const cloudAsked = cloudSummary ? new Set(cloudSummary.asked) : null;
17588
17904
  const unvouched = outcomes.some((o) => isCloudOutcome(o) && !(cloudAsked?.has(o.policy) ?? false));
17589
17905
  if (unvouched)
17590
17906
  return { kind: "fallback", reason: "malformed", latencyMs, model: null };
17591
17907
  const injection = sent ? outcome.verdict.injectionSuspected : null;
17592
17908
  const warned = (o) => o.verdict === "instruct" && o.intent !== "downgraded-task-step";
17909
+ const cloudAnswers = cloudSummary?.answers ?? {};
17910
+ const watched = cloudSummary?.observedOutcomes ?? [];
17593
17911
  return {
17594
17912
  kind: "answered",
17595
17913
  decision: outcome.verdict.decision,
17914
+ checks: sent ? checkRecords(outcomes, { ...outcome.answers, ...cloudAnswers }, watched) : [],
17596
17915
  reason: outcome.verdict.reason,
17597
17916
  policyName: jevPolicyName(outcome),
17598
17917
  ...jevDecider(outcome)?.origin ? { origin: jevDecider(outcome)?.origin } : {},
@@ -17604,7 +17923,16 @@ function toReview(outcome, cached = false) {
17604
17923
  truncated: outcome.truncated && sent,
17605
17924
  requestCut: outcome.requestCut && sent,
17606
17925
  latencyMs,
17607
- model
17926
+ model,
17927
+ ...sent && cloudSummary?.observedAsked?.length ? { observedAsked: cloudSummary.observedAsked } : {},
17928
+ ...cloudSummary?.observed?.length ? {
17929
+ observedCloud: cloudSummary.observed.map((o) => ({
17930
+ cloudPolicyId: o.cloudPolicyId,
17931
+ cloudVersion: o.cloudVersion,
17932
+ decision: o.decision,
17933
+ reason: o.reason
17934
+ }))
17935
+ } : {}
17608
17936
  };
17609
17937
  }
17610
17938
  function toolInputRecord(raw) {
@@ -17623,7 +17951,8 @@ function startJevReview(cfg, call) {
17623
17951
  if (!settled)
17624
17952
  controller.abort();
17625
17953
  },
17626
- authorityOf
17954
+ authorityOf,
17955
+ ...call.cloud ? { cloud: true } : {}
17627
17956
  });
17628
17957
  let route;
17629
17958
  let throttled;
@@ -17647,7 +17976,10 @@ function startJevReview(cfg, call) {
17647
17976
  }
17648
17977
  let intent;
17649
17978
  try {
17650
- 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
+ });
17651
17983
  } catch {
17652
17984
  intent = { userSaid: [], agentLastMessage: null };
17653
17985
  }
@@ -17685,6 +18017,7 @@ function startJevReview(cfg, call) {
17685
18017
  ...options,
17686
18018
  machineId: cloud.machineId,
17687
18019
  agent: cloud.agent,
18020
+ observedPolicies: cloud.observedPolicies ?? [],
17688
18021
  ...call.localPaused ? { policies: [] } : {}
17689
18022
  }) : evaluateSemantic(input, options);
17690
18023
  const answered = evaluated.then((outcome) => {
@@ -17746,6 +18079,7 @@ var init_jev_review = __esm(() => {
17746
18079
  init_jev_config();
17747
18080
  init_jev_throttle();
17748
18081
  init_session_root();
18082
+ init_jev_activity();
17749
18083
  throttle = exports_jev_throttle;
17750
18084
  intentReader = exports_intent;
17751
18085
  ALWAYS_ON = new Set(BUILTIN_POLICIES.filter((p) => p.alwaysOn).map((p) => normalizePolicyName(p.name)));
@@ -17959,7 +18293,13 @@ async function readJevConfig(agent) {
17959
18293
  return {
17960
18294
  config: resolved.config,
17961
18295
  defaultMode: DEFAULT_JEV_MODE,
17962
- cloud: { machineId: resolved.machineId, deployment: cloud.deployment, mode: cloud.jevMode, agent: agent ?? null }
18296
+ cloud: {
18297
+ machineId: resolved.machineId,
18298
+ deployment: cloud.deployment,
18299
+ mode: cloud.jevMode,
18300
+ agent: agent ?? null,
18301
+ observedPolicies: (cloudJevAssignmentsFor(agent ?? null) ?? []).filter((a) => a.effect === "observe").map((a) => a.id)
18302
+ }
17963
18303
  };
17964
18304
  }
17965
18305
  if (!existsSync22(jevConfigFile()))
@@ -18033,6 +18373,8 @@ async function startTwoTier(canonicalEventType, parsed, session, cli, opts, acti
18033
18373
  return null;
18034
18374
  if (!cloudAsks && !jevChecksInstalled())
18035
18375
  return null;
18376
+ if (cloudAsks && cloudJevAssignmentsFor(agent)?.length === 0 && (activePause || !packJevChecksInstalled()))
18377
+ return null;
18036
18378
  const loaded = await readJevConfig(agent);
18037
18379
  if (!loaded)
18038
18380
  return null;
@@ -18049,6 +18391,7 @@ async function startTwoTier(canonicalEventType, parsed, session, cli, opts, acti
18049
18391
  permissionMode: session.permissionMode,
18050
18392
  sessionId: session.sessionId,
18051
18393
  cli,
18394
+ agent,
18052
18395
  ...loaded.cloud ? { cloud: loaded.cloud } : {},
18053
18396
  ...activePause ? { localPaused: true } : {}
18054
18397
  });
@@ -18075,13 +18418,16 @@ function jevTelemetry(activity) {
18075
18418
  return {};
18076
18419
  }
18077
18420
  }
18078
- async function captureJevIntent(canonicalEventType, decision, parsed, session, cli, opts) {
18421
+ async function captureJevIntent(canonicalEventType, decision, parsed, session, cli, opts, agent) {
18079
18422
  if (canonicalEventType !== "UserPromptSubmit" || jevForcedOff(opts))
18080
18423
  return;
18081
18424
  try {
18082
- if (!cloudJevAsks(readCloudJevMode()) && !jevChecksInstalled())
18425
+ const cloudAsks = cloudJevAsks(readCloudJevMode());
18426
+ if (!cloudAsks && !jevChecksInstalled())
18427
+ return;
18428
+ if (cloudAsks && cloudJevAssignmentsFor(agent)?.length === 0 && !packJevChecksInstalled())
18083
18429
  return;
18084
- if (!await readJevConfig())
18430
+ if (!await readJevConfig(agent))
18085
18431
  return;
18086
18432
  if (decision === "deny") {
18087
18433
  await Promise.resolve().then(() => init_enforcement_capability());
@@ -18095,7 +18441,8 @@ async function captureJevIntent(canonicalEventType, decision, parsed, session, c
18095
18441
  transcriptPath: session.transcriptPath,
18096
18442
  cli,
18097
18443
  payload: parsed,
18098
- prompt: parsed.prompt
18444
+ prompt: parsed.prompt,
18445
+ profile: { cli, agent }
18099
18446
  };
18100
18447
  captureIntent(event);
18101
18448
  } catch (err) {
@@ -18356,9 +18703,12 @@ async function evaluateHookEvent(eventType, cli = "claude", stdinPayload, opts)
18356
18703
  reason: observeVerdict.reason
18357
18704
  });
18358
18705
  }
18706
+ for (const o of result.twoTier?.observedCloud ?? []) {
18707
+ observedResults.push({ policyId: o.cloudPolicyId, version: o.cloudVersion, decision: o.decision, reason: o.reason });
18708
+ }
18359
18709
  const durationMs = Math.round(performance.now() - startTime);
18360
18710
  hookLogInfo(`result=${result.decision} policy=${result.policyName ?? "none"} duration=${durationMs}ms`);
18361
- await captureJevIntent(canonicalEventType, result.decision, parsed, session, cli, opts);
18711
+ await captureJevIntent(canonicalEventType, result.decision, parsed, session, cli, opts, runtimeAgent);
18362
18712
  const matchedPolicies = matchedBeforeRelease ?? getPoliciesForEvent(canonicalEventType, parsed.tool_name).map((p) => p.name);
18363
18713
  const jevOrigin = result.policyName && result.twoTier?.decidedByJev ? result.twoTier.jevOrigin : undefined;
18364
18714
  const activityEntry = {