failproofai 1.0.12-beta.1 → 1.0.12-beta.2

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 (168) 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 +3 -3
  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]__00l2u6j86cb8y._.js +3 -0
  63. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__08ch3staq3ejw._.js +1 -1
  64. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0bigvy9xmv2ka._.js +1 -1
  65. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0h86bl2qf0k_o._.js +1 -1
  66. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0pia5h3p8re4c._.js +1 -1
  67. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0pwj2h2efe5f-._.js +1 -1
  68. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1-ey9fgesfbc0._.js +1 -1
  69. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__15usvs-ms-0hf._.js +1 -1
  70. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__16gb3_92zvk5x._.js +1 -1
  71. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1avi2kypusyb_._.js +1 -1
  72. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1r7drlqli-ado._.js +1 -1
  73. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0b78b0j8iyv6l._.js → [root-of-the-server]__1vofkb2oq7p7e._.js} +1 -1
  74. package/.next/standalone/.next/server/chunks/ssr/_0bseae9u7g98r._.js +1 -1
  75. package/.next/standalone/.next/server/chunks/ssr/_0eoura3_9gjb-._.js +1 -1
  76. package/.next/standalone/.next/server/chunks/ssr/_0mouhaflye1ro._.js +1 -1
  77. package/.next/standalone/.next/server/chunks/ssr/{_1a3tubds7s7ow._.js → _0ouu886szh6yj._.js} +4 -4
  78. package/.next/standalone/.next/server/chunks/ssr/_0pedwblqdoh58._.js +1 -1
  79. package/.next/standalone/.next/server/chunks/ssr/_1djqs9i27e4kg._.js +1 -1
  80. package/.next/standalone/.next/server/chunks/ssr/_1fw0_nzkae5ao._.js +3 -0
  81. package/.next/standalone/.next/server/chunks/ssr/_20hn4gn87nsjc._.js +1 -1
  82. package/.next/standalone/.next/server/chunks/ssr/_next-internal_server_app_policies_page_actions_1sp2-yo5_vm5f.js +2 -2
  83. package/.next/standalone/.next/server/chunks/ssr/app_actions_get-scheduled-audit_ts_0ei9snixb5fd-._.js +1 -1
  84. package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47q0xq5w._.js +1 -1
  85. package/.next/standalone/.next/server/chunks/ssr/app_components_project-list_tsx_1ke6anr0vt64h._.js +1 -1
  86. package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x33jqb6._.js +1 -1
  87. package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpcz0uxur._.js +2 -2
  88. package/.next/standalone/.next/server/chunks/ssr/app_settings_02tf1h47jmhhd._.js +1 -1
  89. package/.next/standalone/.next/server/chunks/ssr/{node_modules_html-to-image_es_index_1i8oid1gc7s1f.js → node_modules_html-to-image_es_index_1fv03uigni8s5.js} +1 -1
  90. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_0janj0i6dqko7._.js +1 -1
  91. package/.next/standalone/.next/server/chunks/ssr/package_json_[json]_cjs_013tntikdft59._.js +1 -1
  92. package/.next/standalone/.next/server/chunks/ssr/src_hooks_0agdmptetetdt._.js +1 -1
  93. package/.next/standalone/.next/server/chunks/ssr/src_hooks_0mdwgjisv4fub._.js +1 -1
  94. package/.next/standalone/.next/server/chunks/ssr/src_hooks_fp-config_ts_04t589gp4p60j._.js +1 -1
  95. package/.next/standalone/.next/server/chunks/ssr/src_hooks_pack-cli_ts_0t7me658zqmh_._.js +1 -1
  96. package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
  97. package/.next/standalone/.next/server/pages/404.html +1 -1
  98. package/.next/standalone/.next/server/pages/500.html +1 -1
  99. package/.next/standalone/.next/server/preview-props.json +3 -3
  100. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  101. package/.next/standalone/.next/server/server-reference-manifest.json +23 -23
  102. package/.next/standalone/.next/static/chunks/{2-tf6_7u623kd.js → 0ay__-d2h1xb5.js} +1 -1
  103. package/.next/standalone/.next/static/chunks/{18433qz-8njv3.js → 0tbm3vjm62h-2.js} +1 -1
  104. package/.next/standalone/.next/static/chunks/{1b32-afqacaen.js → 1c_jf6g5wnslk.js} +1 -1
  105. package/.next/standalone/.next/static/chunks/{0_zfad4co-t2z.js → 1my3-5p47t7r-.js} +1 -1
  106. package/.next/standalone/.next/static/chunks/{0jutamwqz8pg5.js → 20py8k1gd_i1m.js} +1 -1
  107. package/.next/standalone/.next/static/chunks/21hckpmsc4g70.js +6 -0
  108. package/.next/standalone/.next/static/chunks/2hmex93ppj1ke.js +1 -0
  109. package/.next/standalone/.next/static/chunks/{42e8zab314654.js → 2o6d37j425uci.js} +1 -1
  110. package/.next/standalone/.next/static/chunks/40oworn_-x12p.js +1 -0
  111. package/.next/standalone/.next/static/chunks/{24w3x2da9sk49.js → 42xptz88mtq3x.js} +1 -1
  112. package/.next/standalone/app/actions/update-jev-config.ts +5 -3
  113. package/.next/standalone/app/settings/jev-panel.tsx +1 -1
  114. package/.next/standalone/fp-cloud-cli/CHANGELOG.md +9 -18
  115. package/.next/standalone/fp-cloud-cli/README.md +7 -9
  116. package/.next/standalone/fp-cloud-cli/fp_cli/client.py +1 -27
  117. package/.next/standalone/fp-cloud-cli/fp_cli/commands/fleet_cmds.py +12 -216
  118. package/.next/standalone/fp-cloud-cli/fp_cli/enforcement.py +7 -53
  119. package/.next/standalone/fp-cloud-cli/fp_cli/output.py +2 -71
  120. package/.next/standalone/fp-cloud-cli/skill/SKILL.md +1 -1
  121. package/.next/standalone/fp-cloud-cli/skill/references/commands.md +6 -7
  122. package/.next/standalone/fp-cloud-cli/tests/test_cloud_jev.py +32 -197
  123. package/.next/standalone/hermes-plugin/__init__.py +11 -0
  124. package/.next/standalone/hermes-plugin/plugin.yaml +1 -1
  125. package/.next/standalone/package.json +11 -10
  126. package/.next/standalone/sdk/python/uv.lock +31 -8
  127. package/.next/standalone/server.js +1 -1
  128. package/dist/cli.mjs +1686 -612
  129. package/dist/worker.mjs +354 -49
  130. package/hermes-plugin/__init__.py +11 -0
  131. package/hermes-plugin/plugin.yaml +1 -1
  132. package/package.json +11 -10
  133. package/src/audit/open-browser.ts +24 -7
  134. package/src/hooks/agent-roster.ts +9 -1
  135. package/src/hooks/agent-skill.ts +203 -0
  136. package/src/hooks/cloud-connection.ts +27 -51
  137. package/src/hooks/cloud-introspect.ts +5 -2
  138. package/src/hooks/cloud-login.ts +248 -0
  139. package/src/hooks/cloud-managed-policies.ts +54 -4
  140. package/src/hooks/codex-system-hooks.ts +10 -4
  141. package/src/hooks/config-status.ts +9 -3
  142. package/src/hooks/configure-wizard.ts +356 -32
  143. package/src/hooks/delivery-health.ts +47 -2
  144. package/src/hooks/effective-reviewers.ts +14 -0
  145. package/src/hooks/fp-config.ts +19 -0
  146. package/src/hooks/handler.ts +21 -2
  147. package/src/hooks/hook-activity-store.ts +7 -1
  148. package/src/hooks/integrations.ts +18 -3
  149. package/src/hooks/jev-activity.ts +117 -1
  150. package/src/hooks/jev-cli.ts +7 -9
  151. package/src/hooks/manager.ts +80 -46
  152. package/src/hooks/policy-evaluator.ts +17 -0
  153. package/src/hooks/policy-reviewability.ts +4 -2
  154. package/src/hooks/semantic/cloud-jev.ts +219 -28
  155. package/src/hooks/semantic/combine.ts +26 -1
  156. package/src/hooks/semantic/jev-client.ts +1 -1
  157. package/src/hooks/semantic/jev-config.ts +6 -27
  158. package/src/hooks/semantic/jev-review.ts +90 -2
  159. package/src/hooks/tui.ts +280 -0
  160. package/src/hooks/uninstall-cli.ts +12 -1
  161. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0588st-tpiuia._.js +0 -3
  162. package/.next/standalone/.next/server/chunks/ssr/_128ebxr83nk6g._.js +0 -3
  163. package/.next/standalone/.next/static/chunks/114hbolvrv94e.js +0 -1
  164. package/.next/standalone/.next/static/chunks/1p-hsi58i-6h0.js +0 -6
  165. package/.next/standalone/.next/static/chunks/3-pku9qwv1yfu.js +0 -1
  166. /package/.next/standalone/.next/static/{xq8UgF5yFxty1VWxY2hyn → LHCtFxVG0mdvd4lsXAOFC}/_buildManifest.js +0 -0
  167. /package/.next/standalone/.next/static/{xq8UgF5yFxty1VWxY2hyn → LHCtFxVG0mdvd4lsXAOFC}/_clientMiddlewareManifest.js +0 -0
  168. /package/.next/standalone/.next/static/{xq8UgF5yFxty1VWxY2hyn → LHCtFxVG0mdvd4lsXAOFC}/_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-beta.2";
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) {
@@ -17004,7 +17120,11 @@ function parseOutcome(raw, i) {
17004
17120
  if (!origin || typeof origin !== "object" || typeof origin.cloudPolicyId !== "string" || !POLICY_ID_RE2.test(origin.cloudPolicyId) || !Number.isSafeInteger(origin.cloudVersion) || origin.cloudVersion < 0) {
17005
17121
  malformed(`outcome ${i} has no Cloud origin`);
17006
17122
  }
17007
- return {
17123
+ if (o.effect !== undefined && o.effect !== "enforce" && o.effect !== "observe")
17124
+ malformed(`outcome ${i} has an unknown effect`);
17125
+ if (o.reason !== undefined && o.reason !== null && typeof o.reason !== "string")
17126
+ malformed(`outcome ${i} reason is not text`);
17127
+ const outcome = {
17008
17128
  policy: o.policy,
17009
17129
  mode: o.mode,
17010
17130
  ...typeof o.userCanOverride === "boolean" ? { userCanOverride: o.userCanOverride } : {},
@@ -17018,41 +17138,103 @@ function parseOutcome(raw, i) {
17018
17138
  ...o.intent !== undefined ? { intent: o.intent } : {},
17019
17139
  ...o.targetScanIncomplete === true ? { targetScanIncomplete: true } : {}
17020
17140
  };
17141
+ return {
17142
+ outcome,
17143
+ cloudPolicyId: origin.cloudPolicyId,
17144
+ cloudVersion: origin.cloudVersion,
17145
+ observe: o.effect === "observe",
17146
+ reason: typeof o.reason === "string" ? capReason(o.reason) : null
17147
+ };
17021
17148
  }
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;
17149
+ function capReason(reason) {
17150
+ return reason.length > MAX_CLOUD_REASON_CHARS ? `${reason.slice(0, MAX_CLOUD_REASON_CHARS - 1)}…` : reason;
17151
+ }
17152
+ function observedChecks(parsed, watched = null) {
17153
+ const firing = watched?.parsed.filter((p) => p.outcome.verdict === "deny" || p.outcome.verdict === "instruct") ?? [];
17154
+ const watchedReason = firing.length === 1 && typeof watched?.v.reason === "string" ? capReason(watched.v.reason) : null;
17155
+ const byPolicy = new Map;
17156
+ for (const p of parsed) {
17157
+ const verdict = p.outcome.verdict;
17158
+ if (verdict !== "deny" && verdict !== "instruct")
17159
+ continue;
17160
+ const prev = byPolicy.get(p.cloudPolicyId);
17161
+ if (prev && SEVERITY[prev.decision] >= SEVERITY[verdict])
17162
+ continue;
17163
+ byPolicy.set(p.cloudPolicyId, {
17164
+ cloudPolicyId: p.cloudPolicyId,
17165
+ cloudVersion: p.cloudVersion,
17166
+ check: p.outcome.policy,
17167
+ decision: verdict,
17168
+ reason: p.reason ?? (firing[0] === p ? watchedReason : null) ?? `Flagged by semantic review (semantic/${p.outcome.policy})`
17169
+ });
17170
+ }
17171
+ return [...byPolicy.values()];
17172
+ }
17173
+ function parseVerdictBlock(rawVerdict, rawAsked, what) {
17174
+ const v = rawVerdict;
17027
17175
  if (!v || typeof v !== "object" || Array.isArray(v))
17028
- malformed("no verdict");
17176
+ malformed(`no ${what}`);
17029
17177
  if (typeof v.decision !== "string" || !DECISIONS2.has(v.decision))
17030
- malformed("verdict has no decision");
17178
+ malformed(`${what} has no decision`);
17031
17179
  if (v.reason !== null && v.reason !== undefined && typeof v.reason !== "string")
17032
- malformed("verdict reason is not text");
17180
+ malformed(`${what} reason is not text`);
17033
17181
  if (!Array.isArray(v.outcomes) || v.outcomes.length > MAX_LIST)
17034
- malformed("verdict has no outcomes list");
17182
+ malformed(`${what} has no outcomes list`);
17035
17183
  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");
17184
+ malformed(`${what} beyondTask is not a flag`);
17185
+ const parsed = v.outcomes.map(parseOutcome);
17186
+ const asked = names(rawAsked, `${what} asked`);
17039
17187
  const askedSet = new Set(asked);
17040
17188
  const seen = new Set;
17041
- outcomes.forEach((o, i) => {
17189
+ parsed.forEach(({ outcome: o }, i) => {
17042
17190
  if (!askedSet.has(o.policy))
17043
- malformed(`outcome ${i} answers ${JSON.stringify(o.policy)}, which Cloud did not ask`);
17191
+ malformed(`${what} outcome ${i} answers ${JSON.stringify(o.policy)}, which Cloud did not ask`);
17044
17192
  const key = `${o.origin?.packId ?? ""}\x00${o.policy}`;
17045
17193
  if (seen.has(key))
17046
- malformed(`outcome ${i} answers ${JSON.stringify(o.policy)} twice`);
17194
+ malformed(`${what} outcome ${i} answers ${JSON.stringify(o.policy)} twice`);
17047
17195
  seen.add(key);
17048
17196
  });
17049
- if (outcomes.some((o) => o.verdict === "deny") && v.decision !== "deny")
17197
+ return { v, parsed, asked };
17198
+ }
17199
+ function parseCloudReply(raw, observedPolicies = []) {
17200
+ if (!raw || typeof raw !== "object" || Array.isArray(raw))
17201
+ malformed("no cloud block");
17202
+ const block = raw;
17203
+ const { v, parsed, asked } = parseVerdictBlock(block.verdict, block.asked, "verdict");
17204
+ let watched = null;
17205
+ if (block.observed !== undefined && block.observed !== null) {
17206
+ const o = block.observed;
17207
+ if (typeof o !== "object" || Array.isArray(o))
17208
+ malformed("observed is not an object");
17209
+ watched = parseVerdictBlock(o.verdict, o.asked, "observed verdict");
17210
+ if (watched.parsed.some((p) => p.outcome.verdict === "deny") && watched.v.decision !== "deny") {
17211
+ malformed("an observed check denied but its verdict does not");
17212
+ }
17213
+ }
17214
+ const observeIds = new Set(observedPolicies);
17215
+ const isObserved = (p) => p.observe || observeIds.has(p.cloudPolicyId);
17216
+ const enforced = parsed.filter((p) => !isObserved(p)).map((p) => p.outcome);
17217
+ const observedHere = parsed.filter(isObserved);
17218
+ const observed = [...observedHere, ...watched?.parsed ?? []];
17219
+ if (enforced.some((o) => o.verdict === "deny") && v.decision !== "deny")
17050
17220
  malformed("a check denied but the verdict does not");
17221
+ const cloudReason = typeof v.reason === "string" ? capReason(v.reason) : null;
17222
+ let decision = v.decision;
17223
+ let reason = cloudReason;
17224
+ if (observedHere.length > 0) {
17225
+ const own = enforced.some((o) => o.verdict === "deny") ? "deny" : enforced.some((o) => o.verdict === "instruct") || v.beyondTask === true ? "instruct" : "allow";
17226
+ const capped = RANK2[own] <= RANK2[decision] ? own : decision;
17227
+ if (capped !== decision)
17228
+ reason = null;
17229
+ decision = capped;
17230
+ }
17051
17231
  return {
17232
+ observed: observedChecks(observed, watched),
17233
+ observedAsked: [...observedHere.map((p) => p.outcome.policy), ...watched?.asked ?? []],
17052
17234
  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,
17235
+ decision,
17236
+ reason,
17237
+ outcomes: enforced,
17056
17238
  injectionSuspected: nullableProbability(v.injectionSuspected, "injectionSuspected"),
17057
17239
  scopeWithinRequest: nullableProbability(v.scopeWithinRequest, "scopeWithinRequest"),
17058
17240
  beyondTask: v.beyondTask === true
@@ -17062,6 +17244,29 @@ function parseCloudReply(raw) {
17062
17244
  droppedCloud: names(block.droppedCloud, "droppedCloud")
17063
17245
  };
17064
17246
  }
17247
+ function parseObservedOutcomes(raw) {
17248
+ try {
17249
+ const block = raw?.observed;
17250
+ if (!block || typeof block !== "object" || Array.isArray(block))
17251
+ return [];
17252
+ const asked = new Set(names(block.asked, "observed.asked"));
17253
+ const outcomes = block.verdict?.outcomes ?? [];
17254
+ if (!Array.isArray(outcomes) || outcomes.length > MAX_LIST)
17255
+ return [];
17256
+ const seen = new Set;
17257
+ const out = [];
17258
+ outcomes.forEach((o, i) => {
17259
+ const parsed = parseOutcome(o, i).outcome;
17260
+ if (!asked.has(parsed.policy) || seen.has(parsed.policy))
17261
+ return;
17262
+ seen.add(parsed.policy);
17263
+ out.push(parsed);
17264
+ });
17265
+ return out;
17266
+ } catch {
17267
+ return [];
17268
+ }
17269
+ }
17065
17270
  function joinLines(reasons) {
17066
17271
  const lines = [];
17067
17272
  for (const reason of reasons) {
@@ -17108,6 +17313,22 @@ function expectedQuestions(request, prepared, dropped) {
17108
17313
  }));
17109
17314
  return { ...request, questions };
17110
17315
  }
17316
+ function cloudCheckAnswers(response, asked) {
17317
+ const out = {};
17318
+ if (asked.length === 0)
17319
+ return out;
17320
+ const names = new Set(asked);
17321
+ const answers = response.answers && typeof response.answers === "object" ? response.answers : {};
17322
+ for (const [id, a] of Object.entries(answers)) {
17323
+ const dot = id.lastIndexOf(".");
17324
+ if (dot <= 0 || !names.has(id.slice(0, dot)) || !QUESTION_PART_RE.test(id.slice(dot + 1)))
17325
+ continue;
17326
+ const p = a?.noul;
17327
+ if (isProbability(p))
17328
+ out[id] = p;
17329
+ }
17330
+ return out;
17331
+ }
17111
17332
  function presentAnswers(response) {
17112
17333
  const out = {};
17113
17334
  const answers = response.answers && typeof response.answers === "object" ? response.answers : {};
@@ -17136,7 +17357,7 @@ async function evaluateCloudSemantic(input, opts) {
17136
17357
  model: opts.model ?? DEFAULT_JEV_MODEL,
17137
17358
  modelVerified: true,
17138
17359
  via: "none",
17139
- cloud: { asked: [], droppedLocal: [], droppedCloud: [] }
17360
+ cloud: { asked: [], droppedLocal: [], droppedCloud: [], answers: {}, observed: [], observedAsked: [], observedOutcomes: [] }
17140
17361
  };
17141
17362
  }
17142
17363
  let prepared;
@@ -17177,11 +17398,13 @@ async function evaluateCloudSemantic(input, opts) {
17177
17398
  const timeout = AbortSignal.timeout(opts.timeoutMs ?? envNumber2("FAILPROOFAI_JEV_TIMEOUT_MS", DEFAULT_JEV_TIMEOUT_MS));
17178
17399
  const signal = opts.signal ? AbortSignal.any([timeout, opts.signal]) : timeout;
17179
17400
  const response = await transport(request, signal);
17180
- const reply = parseCloudReply(response.cloud);
17401
+ const reply = parseCloudReply(response.cloud, opts.observedPolicies);
17402
+ const observedAsked = new Set(reply.observedAsked);
17403
+ const observedOutcomes = parseObservedOutcomes(response.cloud).filter((o) => observedAsked.has(o.policy));
17181
17404
  const own = new Map(prepared.selected.map((p) => [p.name, p]));
17182
17405
  const dropped = new Set(reply.droppedLocal.filter((name) => own.has(name)));
17183
17406
  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;
17407
+ const shortCircuit = kept.length === 0 && reply.asked.length === 0 && reply.verdict.outcomes.length === 0 && reply.observedAsked.length === 0;
17185
17408
  const answers = shortCircuit ? presentAnswers(response) : readAnswers(expectedQuestions(request, prepared, dropped), response);
17186
17409
  const local = prepared.intent === "v1" ? decideV1(kept, answers, input.toolInput, prepared.userSaid, prepared.agentLastMessage, {
17187
17410
  ...opts.v1,
@@ -17203,7 +17426,11 @@ async function evaluateCloudSemantic(input, opts) {
17203
17426
  cloud: {
17204
17427
  asked: reply.asked,
17205
17428
  droppedLocal: [...dropped].map((name) => ({ name, packId: own.get(name)?.origin?.packId ?? null })),
17206
- droppedCloud: reply.droppedCloud
17429
+ droppedCloud: reply.droppedCloud,
17430
+ answers: cloudCheckAnswers(response, [...reply.asked, ...reply.observedAsked]),
17431
+ observed: reply.observed,
17432
+ observedAsked: reply.observedAsked,
17433
+ observedOutcomes
17207
17434
  }
17208
17435
  };
17209
17436
  } catch (err) {
@@ -17216,7 +17443,7 @@ async function evaluateCloudSemantic(input, opts) {
17216
17443
  return degraded(`error: ${err instanceof Error ? err.message : String(err)}`);
17217
17444
  }
17218
17445
  }
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;
17446
+ 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
17447
  var init_cloud_jev = __esm(() => {
17221
17448
  init_compile();
17222
17449
  init_decide();
@@ -17232,6 +17459,7 @@ var init_cloud_jev = __esm(() => {
17232
17459
  DECISIONS2 = new Set(["allow", "deny", "instruct"]);
17233
17460
  VERDICTS = new Set(["deny", "instruct", "overridden", "none"]);
17234
17461
  INTENTS = new Set(["op-requested", "task-step", "downgraded-task-step"]);
17462
+ SEVERITY = { instruct: 1, deny: 2 };
17235
17463
  RANK2 = { allow: 0, instruct: 1, deny: 2 };
17236
17464
  EMPTY_ALLOW = {
17237
17465
  decision: "allow",
@@ -17241,6 +17469,7 @@ var init_cloud_jev = __esm(() => {
17241
17469
  scopeWithinRequest: null,
17242
17470
  beyondTask: false
17243
17471
  };
17472
+ QUESTION_PART_RE = /^[a-z][a-z0-9_]{0,31}$/;
17244
17473
  });
17245
17474
 
17246
17475
  // src/hooks/semantic/jev-throttle.ts
@@ -17576,6 +17805,55 @@ function fallbackCode(reason) {
17576
17805
  const code = reason.split(":")[0].trim();
17577
17806
  return /^[a-z0-9][a-z0-9-]{0,63}$/.test(code) ? code : "error";
17578
17807
  }
17808
+ function checkWhy(o) {
17809
+ switch (o.verdict) {
17810
+ case "none":
17811
+ return o.evidence < DEFAULT_THRESHOLDS_V1.fire ? "not-detected" : "exempt";
17812
+ case "overridden":
17813
+ return o.intent === "op-requested" ? "op-requested" : o.intent === "task-step" ? "task-step" : "user-asked";
17814
+ case "deny":
17815
+ return o.escalatedByInjection ? "injection" : "fired";
17816
+ default:
17817
+ if (o.intent === "downgraded-task-step")
17818
+ return "downgraded";
17819
+ return o.targetScanIncomplete ? "scan-incomplete" : "fired";
17820
+ }
17821
+ }
17822
+ function checkPolicy(o) {
17823
+ const packId = o.origin?.packId;
17824
+ if (!packId)
17825
+ return;
17826
+ const at = o.origin?.packVersion ? `@${o.origin.packVersion}` : "";
17827
+ return packId.startsWith("cloud:") ? `cloud/${packId.slice("cloud:".length)}${at}` : `pack/${packId}${at}`;
17828
+ }
17829
+ function checkRecords(outcomes, answers, watched = []) {
17830
+ const all = [...outcomes.map((o) => ({ o, watched: false })), ...watched.map((o) => ({ o, watched: true }))];
17831
+ return all.slice(0, JEV_CHECKS_MAX).map(({ o, watched: isWatched }) => {
17832
+ const probes = {};
17833
+ const prefix = `${o.policy}.`;
17834
+ for (const [id, p] of Object.entries(answers)) {
17835
+ if (Object.keys(probes).length >= JEV_CHECK_PROBES_MAX)
17836
+ break;
17837
+ if (!id.startsWith(prefix))
17838
+ continue;
17839
+ const part = id.slice(prefix.length);
17840
+ if (part === "exempt" || part === "user_asked" || !JEV_PROBE_ID_RE.test(part))
17841
+ continue;
17842
+ probes[part] = round2(p);
17843
+ }
17844
+ const policy = checkPolicy(o);
17845
+ return {
17846
+ check: o.policy,
17847
+ ...policy ? { policy } : {},
17848
+ verdict: o.verdict,
17849
+ why: checkWhy(o),
17850
+ p: round2(o.evidence),
17851
+ ...o.exempt !== null ? { exempt: round2(o.exempt) } : {},
17852
+ ...Object.keys(probes).length > 0 ? { probes } : {},
17853
+ ...isWatched ? { watched: true } : {}
17854
+ };
17855
+ });
17856
+ }
17579
17857
  function toReview(outcome, cached = false) {
17580
17858
  if (outcome.status === "degraded") {
17581
17859
  return { kind: "fallback", reason: fallbackCode(outcome.reason), latencyMs: outcome.latencyMs, model: null };
@@ -17584,15 +17862,19 @@ function toReview(outcome, cached = false) {
17584
17862
  const latencyMs = sent && !cached ? outcome.latencyMs : null;
17585
17863
  const model = sent ? outcome.model : null;
17586
17864
  const outcomes = outcome.verdict.outcomes;
17587
- const cloudAsked = "cloud" in outcome ? new Set(outcome.cloud.asked) : null;
17865
+ const cloudSummary = "cloud" in outcome ? outcome.cloud : null;
17866
+ const cloudAsked = cloudSummary ? new Set(cloudSummary.asked) : null;
17588
17867
  const unvouched = outcomes.some((o) => isCloudOutcome(o) && !(cloudAsked?.has(o.policy) ?? false));
17589
17868
  if (unvouched)
17590
17869
  return { kind: "fallback", reason: "malformed", latencyMs, model: null };
17591
17870
  const injection = sent ? outcome.verdict.injectionSuspected : null;
17592
17871
  const warned = (o) => o.verdict === "instruct" && o.intent !== "downgraded-task-step";
17872
+ const cloudAnswers = cloudSummary?.answers ?? {};
17873
+ const watched = cloudSummary?.observedOutcomes ?? [];
17593
17874
  return {
17594
17875
  kind: "answered",
17595
17876
  decision: outcome.verdict.decision,
17877
+ checks: sent ? checkRecords(outcomes, { ...outcome.answers, ...cloudAnswers }, watched) : [],
17596
17878
  reason: outcome.verdict.reason,
17597
17879
  policyName: jevPolicyName(outcome),
17598
17880
  ...jevDecider(outcome)?.origin ? { origin: jevDecider(outcome)?.origin } : {},
@@ -17604,7 +17886,16 @@ function toReview(outcome, cached = false) {
17604
17886
  truncated: outcome.truncated && sent,
17605
17887
  requestCut: outcome.requestCut && sent,
17606
17888
  latencyMs,
17607
- model
17889
+ model,
17890
+ ...sent && cloudSummary?.observedAsked?.length ? { observedAsked: cloudSummary.observedAsked } : {},
17891
+ ...cloudSummary?.observed?.length ? {
17892
+ observedCloud: cloudSummary.observed.map((o) => ({
17893
+ cloudPolicyId: o.cloudPolicyId,
17894
+ cloudVersion: o.cloudVersion,
17895
+ decision: o.decision,
17896
+ reason: o.reason
17897
+ }))
17898
+ } : {}
17608
17899
  };
17609
17900
  }
17610
17901
  function toolInputRecord(raw) {
@@ -17623,7 +17914,8 @@ function startJevReview(cfg, call) {
17623
17914
  if (!settled)
17624
17915
  controller.abort();
17625
17916
  },
17626
- authorityOf
17917
+ authorityOf,
17918
+ ...call.cloud ? { cloud: true } : {}
17627
17919
  });
17628
17920
  let route;
17629
17921
  let throttled;
@@ -17685,6 +17977,7 @@ function startJevReview(cfg, call) {
17685
17977
  ...options,
17686
17978
  machineId: cloud.machineId,
17687
17979
  agent: cloud.agent,
17980
+ observedPolicies: cloud.observedPolicies ?? [],
17688
17981
  ...call.localPaused ? { policies: [] } : {}
17689
17982
  }) : evaluateSemantic(input, options);
17690
17983
  const answered = evaluated.then((outcome) => {
@@ -17746,6 +18039,7 @@ var init_jev_review = __esm(() => {
17746
18039
  init_jev_config();
17747
18040
  init_jev_throttle();
17748
18041
  init_session_root();
18042
+ init_jev_activity();
17749
18043
  throttle = exports_jev_throttle;
17750
18044
  intentReader = exports_intent;
17751
18045
  ALWAYS_ON = new Set(BUILTIN_POLICIES.filter((p) => p.alwaysOn).map((p) => normalizePolicyName(p.name)));
@@ -17959,7 +18253,13 @@ async function readJevConfig(agent) {
17959
18253
  return {
17960
18254
  config: resolved.config,
17961
18255
  defaultMode: DEFAULT_JEV_MODE,
17962
- cloud: { machineId: resolved.machineId, deployment: cloud.deployment, mode: cloud.jevMode, agent: agent ?? null }
18256
+ cloud: {
18257
+ machineId: resolved.machineId,
18258
+ deployment: cloud.deployment,
18259
+ mode: cloud.jevMode,
18260
+ agent: agent ?? null,
18261
+ observedPolicies: (cloudJevAssignmentsFor(agent ?? null) ?? []).filter((a) => a.effect === "observe").map((a) => a.id)
18262
+ }
17963
18263
  };
17964
18264
  }
17965
18265
  if (!existsSync22(jevConfigFile()))
@@ -18033,6 +18333,8 @@ async function startTwoTier(canonicalEventType, parsed, session, cli, opts, acti
18033
18333
  return null;
18034
18334
  if (!cloudAsks && !jevChecksInstalled())
18035
18335
  return null;
18336
+ if (cloudAsks && cloudJevAssignmentsFor(agent)?.length === 0 && (activePause || !packJevChecksInstalled()))
18337
+ return null;
18036
18338
  const loaded = await readJevConfig(agent);
18037
18339
  if (!loaded)
18038
18340
  return null;
@@ -18356,6 +18658,9 @@ async function evaluateHookEvent(eventType, cli = "claude", stdinPayload, opts)
18356
18658
  reason: observeVerdict.reason
18357
18659
  });
18358
18660
  }
18661
+ for (const o of result.twoTier?.observedCloud ?? []) {
18662
+ observedResults.push({ policyId: o.cloudPolicyId, version: o.cloudVersion, decision: o.decision, reason: o.reason });
18663
+ }
18359
18664
  const durationMs = Math.round(performance.now() - startTime);
18360
18665
  hookLogInfo(`result=${result.decision} policy=${result.policyName ?? "none"} duration=${durationMs}ms`);
18361
18666
  await captureJevIntent(canonicalEventType, result.decision, parsed, session, cli, opts);