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.
- package/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/build-manifest.json +3 -3
- package/.next/standalone/.next/prerender-manifest.json +3 -3
- package/.next/standalone/.next/required-server-files.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_global-error.html +1 -1
- package/.next/standalone/.next/server/app/_global-error.rsc +2 -2
- package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_not-found.html +1 -1
- package/.next/standalone/.next/server/app/_not-found.rsc +3 -3
- package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/api/audit/invite/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/audit/status/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/login-verify/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +2 -2
- package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/index.html +1 -1
- package/.next/standalone/.next/server/app/index.rsc +3 -3
- package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +14 -14
- package/.next/standalone/.next/server/app/policies/page.js +2 -2
- package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +8 -8
- package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/chunks/_0tovk6q0miud6._.js +1 -1
- package/.next/standalone/.next/server/chunks/_0trp3ycqv17cl._.js +1 -1
- package/.next/standalone/.next/server/chunks/_1ek68lnh2daur._.js +2 -2
- package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4vkpxxu7._.js +1 -1
- package/.next/standalone/.next/server/chunks/src_hooks_0_em82s16zfym._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__00l2u6j86cb8y._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__08ch3staq3ejw._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0bigvy9xmv2ka._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0h86bl2qf0k_o._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0pia5h3p8re4c._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0pwj2h2efe5f-._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1-ey9fgesfbc0._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__15usvs-ms-0hf._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__16gb3_92zvk5x._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1avi2kypusyb_._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1r7drlqli-ado._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0b78b0j8iyv6l._.js → [root-of-the-server]__1vofkb2oq7p7e._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_0bseae9u7g98r._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_0eoura3_9gjb-._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_0mouhaflye1ro._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{_1a3tubds7s7ow._.js → _0ouu886szh6yj._.js} +4 -4
- package/.next/standalone/.next/server/chunks/ssr/_0pedwblqdoh58._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_1djqs9i27e4kg._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_1fw0_nzkae5ao._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_20hn4gn87nsjc._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_next-internal_server_app_policies_page_actions_1sp2-yo5_vm5f.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/app_actions_get-scheduled-audit_ts_0ei9snixb5fd-._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47q0xq5w._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_components_project-list_tsx_1ke6anr0vt64h._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x33jqb6._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpcz0uxur._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/app_settings_02tf1h47jmhhd._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{node_modules_html-to-image_es_index_1i8oid1gc7s1f.js → node_modules_html-to-image_es_index_1fv03uigni8s5.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_0janj0i6dqko7._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/package_json_[json]_cjs_013tntikdft59._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_0agdmptetetdt._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_0mdwgjisv4fub._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_fp-config_ts_04t589gp4p60j._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_pack-cli_ts_0t7me658zqmh_._.js +1 -1
- package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
- package/.next/standalone/.next/server/pages/404.html +1 -1
- package/.next/standalone/.next/server/pages/500.html +1 -1
- package/.next/standalone/.next/server/preview-props.json +3 -3
- package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.json +23 -23
- package/.next/standalone/.next/static/chunks/{2-tf6_7u623kd.js → 0ay__-d2h1xb5.js} +1 -1
- package/.next/standalone/.next/static/chunks/{18433qz-8njv3.js → 0tbm3vjm62h-2.js} +1 -1
- package/.next/standalone/.next/static/chunks/{1b32-afqacaen.js → 1c_jf6g5wnslk.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0_zfad4co-t2z.js → 1my3-5p47t7r-.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0jutamwqz8pg5.js → 20py8k1gd_i1m.js} +1 -1
- package/.next/standalone/.next/static/chunks/21hckpmsc4g70.js +6 -0
- package/.next/standalone/.next/static/chunks/2hmex93ppj1ke.js +1 -0
- package/.next/standalone/.next/static/chunks/{42e8zab314654.js → 2o6d37j425uci.js} +1 -1
- package/.next/standalone/.next/static/chunks/40oworn_-x12p.js +1 -0
- package/.next/standalone/.next/static/chunks/{24w3x2da9sk49.js → 42xptz88mtq3x.js} +1 -1
- package/.next/standalone/app/actions/update-jev-config.ts +5 -3
- package/.next/standalone/app/settings/jev-panel.tsx +1 -1
- package/.next/standalone/fp-cloud-cli/CHANGELOG.md +9 -18
- package/.next/standalone/fp-cloud-cli/README.md +7 -9
- package/.next/standalone/fp-cloud-cli/fp_cli/client.py +1 -27
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/fleet_cmds.py +12 -216
- package/.next/standalone/fp-cloud-cli/fp_cli/enforcement.py +7 -53
- package/.next/standalone/fp-cloud-cli/fp_cli/output.py +2 -71
- package/.next/standalone/fp-cloud-cli/skill/SKILL.md +1 -1
- package/.next/standalone/fp-cloud-cli/skill/references/commands.md +6 -7
- package/.next/standalone/fp-cloud-cli/tests/test_cloud_jev.py +32 -197
- package/.next/standalone/hermes-plugin/__init__.py +11 -0
- package/.next/standalone/hermes-plugin/plugin.yaml +1 -1
- package/.next/standalone/package.json +11 -10
- package/.next/standalone/sdk/python/uv.lock +31 -8
- package/.next/standalone/server.js +1 -1
- package/dist/cli.mjs +1686 -612
- package/dist/worker.mjs +354 -49
- package/hermes-plugin/__init__.py +11 -0
- package/hermes-plugin/plugin.yaml +1 -1
- package/package.json +11 -10
- package/src/audit/open-browser.ts +24 -7
- package/src/hooks/agent-roster.ts +9 -1
- package/src/hooks/agent-skill.ts +203 -0
- package/src/hooks/cloud-connection.ts +27 -51
- package/src/hooks/cloud-introspect.ts +5 -2
- package/src/hooks/cloud-login.ts +248 -0
- package/src/hooks/cloud-managed-policies.ts +54 -4
- package/src/hooks/codex-system-hooks.ts +10 -4
- package/src/hooks/config-status.ts +9 -3
- package/src/hooks/configure-wizard.ts +356 -32
- package/src/hooks/delivery-health.ts +47 -2
- package/src/hooks/effective-reviewers.ts +14 -0
- package/src/hooks/fp-config.ts +19 -0
- package/src/hooks/handler.ts +21 -2
- package/src/hooks/hook-activity-store.ts +7 -1
- package/src/hooks/integrations.ts +18 -3
- package/src/hooks/jev-activity.ts +117 -1
- package/src/hooks/jev-cli.ts +7 -9
- package/src/hooks/manager.ts +80 -46
- package/src/hooks/policy-evaluator.ts +17 -0
- package/src/hooks/policy-reviewability.ts +4 -2
- package/src/hooks/semantic/cloud-jev.ts +219 -28
- package/src/hooks/semantic/combine.ts +26 -1
- package/src/hooks/semantic/jev-client.ts +1 -1
- package/src/hooks/semantic/jev-config.ts +6 -27
- package/src/hooks/semantic/jev-review.ts +90 -2
- package/src/hooks/tui.ts +280 -0
- package/src/hooks/uninstall-cli.ts +12 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0588st-tpiuia._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_128ebxr83nk6g._.js +0 -3
- package/.next/standalone/.next/static/chunks/114hbolvrv94e.js +0 -1
- package/.next/standalone/.next/static/chunks/1p-hsi58i-6h0.js +0 -6
- package/.next/standalone/.next/static/chunks/3-pku9qwv1yfu.js +0 -1
- /package/.next/standalone/.next/static/{xq8UgF5yFxty1VWxY2hyn → LHCtFxVG0mdvd4lsXAOFC}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{xq8UgF5yFxty1VWxY2hyn → LHCtFxVG0mdvd4lsXAOFC}/_clientMiddlewareManifest.js +0 -0
- /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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
17023
|
-
|
|
17024
|
-
|
|
17025
|
-
|
|
17026
|
-
const
|
|
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(
|
|
17176
|
+
malformed(`no ${what}`);
|
|
17029
17177
|
if (typeof v.decision !== "string" || !DECISIONS2.has(v.decision))
|
|
17030
|
-
malformed(
|
|
17178
|
+
malformed(`${what} has no decision`);
|
|
17031
17179
|
if (v.reason !== null && v.reason !== undefined && typeof v.reason !== "string")
|
|
17032
|
-
malformed(
|
|
17180
|
+
malformed(`${what} reason is not text`);
|
|
17033
17181
|
if (!Array.isArray(v.outcomes) || v.outcomes.length > MAX_LIST)
|
|
17034
|
-
malformed(
|
|
17182
|
+
malformed(`${what} has no outcomes list`);
|
|
17035
17183
|
if (v.beyondTask !== undefined && typeof v.beyondTask !== "boolean")
|
|
17036
|
-
malformed(
|
|
17037
|
-
const
|
|
17038
|
-
const asked = names(
|
|
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
|
-
|
|
17189
|
+
parsed.forEach(({ outcome: o }, i) => {
|
|
17042
17190
|
if (!askedSet.has(o.policy))
|
|
17043
|
-
malformed(
|
|
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(
|
|
17194
|
+
malformed(`${what} outcome ${i} answers ${JSON.stringify(o.policy)} twice`);
|
|
17047
17195
|
seen.add(key);
|
|
17048
17196
|
});
|
|
17049
|
-
|
|
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
|
|
17054
|
-
reason
|
|
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
|
|
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: {
|
|
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);
|