failproofai 1.0.12-beta.0 → 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 +22 -22
- 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 +1 -1
- 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 +4 -4
- package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page/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 +7 -7
- package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/chunks/{[externals]__0-ha5ydqq0mws._.js → [externals]__0vt9i6fqinjne._.js} +1 -1
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__20xe05hm5u8_1._.js → [root-of-the-server]__0f_4g-vazrvxv._.js} +1 -1
- package/.next/standalone/.next/server/chunks/_0hf5q4xzyg40j._.js +1 -1
- package/.next/standalone/.next/server/chunks/_0tovk6q0miud6._.js +1 -1
- package/.next/standalone/.next/server/chunks/_0trp3ycqv17cl._.js +1 -1
- package/.next/standalone/.next/server/chunks/_19011-u44143j._.js +1 -1
- package/.next/standalone/.next/server/chunks/_1ek68lnh2daur._.js +2 -2
- package/.next/standalone/.next/server/chunks/{_0kc-piux3hady._.js → _1y590mjzpkbos._.js} +2 -2
- package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4vkpxxu7._.js +1 -1
- package/.next/standalone/.next/server/chunks/src_hooks_0_em82s16zfym._.js +5 -0
- package/.next/standalone/.next/server/chunks/src_hooks_builtin-policies_ts_1yq5ybgx1v98e._.js +3 -0
- package/.next/standalone/.next/server/chunks/src_hooks_custom-hooks-loader_ts_0lnb3n3h94wnn._.js +1 -1
- package/.next/standalone/.next/server/chunks/src_hooks_daemon-client_ts_0il_yu1zc0291._.js +1 -1
- package/.next/standalone/.next/server/chunks/src_hooks_fp-home_ts_09kv0bn_4twyh._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0ts0fg5yih1c1._.js → [root-of-the-server]__00l2u6j86cb8y._.js} +2 -2
- 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]__1_xbg2kx30wp-._.js → [root-of-the-server]__0naevg4bcoh54._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0pia5h3p8re4c._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__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]__0vcyntk4snf0f._.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/{_1gb0ifpkowwub._.js → _0ouu886szh6yj._.js} +10 -9
- 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/{_1ve8y151ua7qx._.js → _1fw0_nzkae5ao._.js} +2 -2
- 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_00jxj8foxqz5t.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_06kzv9ddabn3_._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_0agdmptetetdt._.js +5 -0
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_0mdwgjisv4fub._.js +5 -0
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_1cv9_c4l1tzrm._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_daemon-client_ts_0k41_i7jg6ndv._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_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/{0pjxnp927y7_j.js → 0ay__-d2h1xb5.js} +1 -1
- package/.next/standalone/.next/static/chunks/{2znt1784j9gd9.js → 0tbm3vjm62h-2.js} +1 -1
- package/.next/standalone/.next/static/chunks/1c_jf6g5wnslk.js +1 -0
- package/.next/standalone/.next/static/chunks/{3tn1bzk094e8e.js → 1my3-5p47t7r-.js} +1 -1
- package/.next/standalone/.next/static/chunks/20py8k1gd_i1m.js +1 -0
- 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/2o6d37j425uci.js +1 -0
- package/.next/standalone/.next/static/chunks/40oworn_-x12p.js +1 -0
- package/.next/standalone/.next/static/chunks/{2qz5piiir-qqm.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 +32 -0
- package/.next/standalone/fp-cloud-cli/README.md +40 -1
- package/.next/standalone/fp-cloud-cli/fp_cli/client.py +91 -12
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/fleet_cmds.py +78 -16
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/policies_cmds.py +84 -18
- package/.next/standalone/fp-cloud-cli/fp_cli/enforcement.py +124 -6
- package/.next/standalone/fp-cloud-cli/fp_cli/models.py +89 -6
- package/.next/standalone/fp-cloud-cli/fp_cli/output.py +189 -20
- package/.next/standalone/fp-cloud-cli/fp_cli/policy_check.py +8 -5
- package/.next/standalone/fp-cloud-cli/skill/SKILL.md +2 -2
- package/.next/standalone/fp-cloud-cli/skill/references/commands.md +14 -7
- package/.next/standalone/fp-cloud-cli/tests/test_cloud_jev.py +527 -0
- package/.next/standalone/fp-cloud-cli/tests/test_enforcement_logic.py +46 -0
- package/.next/standalone/fp-cloud-cli/tests/test_output.py +23 -0
- package/.next/standalone/hermes-plugin/README.md +6 -4
- package/.next/standalone/hermes-plugin/__init__.py +27 -0
- package/.next/standalone/hermes-plugin/client.py +5 -1
- 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/bin/failproofai.mjs +17 -1
- package/dist/cli.mjs +3507 -1250
- package/dist/worker.mjs +1779 -169
- package/hermes-plugin/README.md +6 -4
- package/hermes-plugin/__init__.py +27 -0
- package/hermes-plugin/client.py +5 -1
- package/hermes-plugin/plugin.yaml +1 -1
- package/package.json +11 -10
- package/src/audit/open-browser.ts +6 -7
- package/src/hooks/agent-roster.ts +180 -0
- package/src/hooks/agent-skill.ts +203 -0
- package/src/hooks/agent-targets.ts +60 -0
- package/src/hooks/cloud-connection.ts +91 -45
- package/src/hooks/cloud-enrollment-cli.ts +7 -4
- package/src/hooks/cloud-login.ts +6 -3
- package/src/hooks/cloud-managed-policies.ts +430 -20
- package/src/hooks/cloud-policy-errors.ts +481 -0
- package/src/hooks/codex-system-hooks.ts +10 -4
- package/src/hooks/config-status.ts +10 -4
- package/src/hooks/configure-wizard.ts +54 -26
- package/src/hooks/custom-hooks-loader.ts +26 -3
- package/src/hooks/daemon-client.ts +9 -4
- package/src/hooks/daemon-service.ts +2 -1
- package/src/hooks/delivery-health.ts +47 -2
- package/src/hooks/effective-reviewers.ts +36 -1
- package/src/hooks/fp-config.ts +19 -0
- package/src/hooks/fp-home.ts +6 -0
- package/src/hooks/handler.ts +255 -19
- package/src/hooks/health-probe.ts +15 -0
- package/src/hooks/hook-activity-store.ts +7 -1
- package/src/hooks/integrations.ts +36 -14
- package/src/hooks/jev-activity.ts +117 -1
- package/src/hooks/jev-cli.ts +196 -1
- package/src/hooks/jev-cloud-connection.ts +92 -0
- package/src/hooks/manager.ts +174 -34
- package/src/hooks/pack-failclosed.ts +2 -0
- package/src/hooks/pack-manifest.ts +8 -1
- package/src/hooks/policy-evaluator.ts +22 -1
- package/src/hooks/policy-registry.ts +3 -2
- package/src/hooks/policy-reviewability.ts +23 -5
- package/src/hooks/semantic/cloud-jev-health.ts +227 -0
- package/src/hooks/semantic/cloud-jev.ts +868 -0
- package/src/hooks/semantic/combine.ts +26 -1
- package/src/hooks/semantic/jev-client.ts +19 -2
- package/src/hooks/semantic/jev-config.ts +179 -30
- package/src/hooks/semantic/jev-review.ts +217 -10
- package/src/hooks/semantic/pack-policies.ts +2 -1
- package/src/hooks/semantic/types.ts +8 -0
- package/src/hooks/session-pause-cli.ts +1 -1
- package/src/hooks/tui.ts +13 -4
- package/src/hooks/uninstall-cli.ts +12 -1
- package/src/hooks/worker-server.ts +5 -1
- package/.next/standalone/.next/server/chunks/src_hooks_1aveq0uhs2t1b._.js +0 -5
- package/.next/standalone/.next/server/chunks/src_hooks_1eem5a7cyqlb2._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_effective-reviewers_ts_1h4wtvo55j16x._.js +0 -5
- package/.next/standalone/.next/static/chunks/0a-ccsp3xmypz.js +0 -1
- package/.next/standalone/.next/static/chunks/13jv-xvabeb62.js +0 -6
- package/.next/standalone/.next/static/chunks/2ank2u3apy8m6.js +0 -1
- package/.next/standalone/.next/static/chunks/2meqb9kygrncb.js +0 -1
- package/.next/standalone/.next/static/chunks/2ohktp_-lkv3x.js +0 -1
- package/.next/standalone/.next/static/chunks/2py0eldhwz8ay.js +0 -1
- /package/.next/standalone/.next/static/{SNr7o_-G4kNBQTR-iLZMM → LHCtFxVG0mdvd4lsXAOFC}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{SNr7o_-G4kNBQTR-iLZMM → LHCtFxVG0mdvd4lsXAOFC}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{SNr7o_-G4kNBQTR-iLZMM → LHCtFxVG0mdvd4lsXAOFC}/_ssgManifest.js +0 -0
|
@@ -7,6 +7,13 @@
|
|
|
7
7
|
* `jev.json` never loads the semantic evaluator at all, and its hook path is
|
|
8
8
|
* exactly what it was before two tiers existed.
|
|
9
9
|
*
|
|
10
|
+
* Or once FailproofAI Cloud sets this machine's Jev mode to `observe` or
|
|
11
|
+
* `enforce` (CONTRACT C10): then the call goes to FailproofAI Cloud on the
|
|
12
|
+
* Cloud Jev credential (`JevCallContext.cloud`), Cloud decides the checks it
|
|
13
|
+
* deployed here, and `evaluateCloudSemantic` merges that verdict with the
|
|
14
|
+
* machine's own. Cloud's outcomes are filed as their policy's OWN reviewers
|
|
15
|
+
* (`reviewerKey`), so a `both` policy is cleared by its Cloud checks alone.
|
|
16
|
+
*
|
|
10
17
|
* Everything the request needs comes through the §7 contracts:
|
|
11
18
|
* `transportForConfig` (T1) for the provider, `throttleTransport` (T5) for the
|
|
12
19
|
* cache and rate limit (scoped to the config's provider, endpoint and model;
|
|
@@ -44,17 +51,29 @@
|
|
|
44
51
|
* it distinguishes, which is what `toReview` below does.
|
|
45
52
|
*/
|
|
46
53
|
import { BUILTIN_POLICIES } from "../builtin-policies";
|
|
54
|
+
import { cloudReviewerName } from "../cloud-managed-policies";
|
|
55
|
+
import type { AgentIdentity } from "../agent-targets";
|
|
56
|
+
import { recordJevBudgetDrops } from "../cloud-policy-errors";
|
|
47
57
|
import { normalizePolicyName } from "../policy-registry";
|
|
48
58
|
import { effectiveAuthority, type PolicyAuthority, type RegisteredPolicy } from "../policy-types";
|
|
49
59
|
import type { JevMode, JevReview, TwoTierReview } from "./combine";
|
|
50
60
|
import { DEFAULT_THRESHOLDS_V1 } from "./decide";
|
|
61
|
+
import { evaluateCloudSemantic, type CloudSemanticOutcome } from "./cloud-jev";
|
|
62
|
+
import {
|
|
63
|
+
BREAKER_SKIP_REASON,
|
|
64
|
+
classifyCloudJevReview,
|
|
65
|
+
cloudJevGate,
|
|
66
|
+
recordCloudJevResult,
|
|
67
|
+
reportCloudJevHealth,
|
|
68
|
+
} from "./cloud-jev-health";
|
|
51
69
|
import { DEFAULT_JEV_TIMEOUT_MS, appendVerdictLog, evaluateSemantic, verdictLogRow, type SemanticOutcome } from "./evaluator";
|
|
52
70
|
import * as intentStore from "./intent";
|
|
53
71
|
import { JevError, transportForConfig, type JevTransport } from "./jev-client";
|
|
54
72
|
import { DEFAULT_JEV_MODE, type JevConfig } from "./jev-config";
|
|
55
73
|
import * as jevThrottle from "./jev-throttle";
|
|
56
74
|
import { sessionProjectRoot } from "./session-root";
|
|
57
|
-
import type { SemanticInput } from "./types";
|
|
75
|
+
import type { PolicyOutcome, SemanticInput } from "./types";
|
|
76
|
+
import { JEV_CHECKS_MAX, JEV_CHECK_PROBES_MAX, JEV_PROBE_ID_RE, round2, type JevCheckRecord } from "../jev-activity";
|
|
58
77
|
|
|
59
78
|
/**
|
|
60
79
|
* T5's throttle as this file calls it. §7 declares only
|
|
@@ -149,6 +168,25 @@ export interface JevCallContext {
|
|
|
149
168
|
permissionMode?: string;
|
|
150
169
|
sessionId?: string;
|
|
151
170
|
cli: string;
|
|
171
|
+
/**
|
|
172
|
+
* Set when FailproofAI Cloud's Jev mode asks (CONTRACT C10.2): the call goes
|
|
173
|
+
* to Cloud with this machine's id, and the deployment it was made under
|
|
174
|
+
* scopes the answer cache (a new deployment can change Cloud's checks).
|
|
175
|
+
*/
|
|
176
|
+
cloud?: {
|
|
177
|
+
machineId: string;
|
|
178
|
+
deployment: number | null;
|
|
179
|
+
mode: "observe" | "enforce";
|
|
180
|
+
agent?: AgentIdentity | null;
|
|
181
|
+
/** Cloud policies whose Jev assignment here is `observe`: recorded, never applied. */
|
|
182
|
+
observedPolicies?: ReadonlyArray<string>;
|
|
183
|
+
};
|
|
184
|
+
/**
|
|
185
|
+
* A session pause is active. It suspends local policy, so no installed
|
|
186
|
+
* pack's check is asked; FailproofAI Cloud's checks are exempt from a pause
|
|
187
|
+
* (as Cloud JS assignments are) and still are. Only meaningful with `cloud`.
|
|
188
|
+
*/
|
|
189
|
+
localPaused?: boolean;
|
|
152
190
|
}
|
|
153
191
|
|
|
154
192
|
export function resolveMode(cfg: JevConfig): JevMode {
|
|
@@ -177,6 +215,24 @@ export function resolveTimeout(cfg: JevConfig): number {
|
|
|
177
215
|
return Math.min(MAX_JEV_TIMEOUT_MS, Math.max(MIN_JEV_TIMEOUT_MS, t));
|
|
178
216
|
}
|
|
179
217
|
|
|
218
|
+
/**
|
|
219
|
+
* The reviewer an outcome answers for: a FailproofAI Cloud check's is
|
|
220
|
+
* `cloud:<policyId>/<name>` (its outcome's own `origin.cloudPolicyId`, carried
|
|
221
|
+
* pack-shaped as `cloud:<id>`), which is what a Cloud `both` policy registers
|
|
222
|
+
* its `reviewedBy` as — so only that policy's own Cloud outcomes can clear it,
|
|
223
|
+
* and a Cloud outcome never clears an installed pack's policy (CONTRACT C10.5).
|
|
224
|
+
* An installed pack's check is its plain name, as it always was.
|
|
225
|
+
*/
|
|
226
|
+
export function reviewerKey(o: Pick<PolicyOutcome, "policy" | "origin">): string {
|
|
227
|
+
const packId = o.origin?.packId;
|
|
228
|
+
return packId !== undefined && packId.startsWith("cloud:") ? cloudReviewerName(packId.slice("cloud:".length), o.policy) : o.policy;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/** Whether an outcome came from FailproofAI Cloud (its `cloud:<id>` origin; see `parseCloudReply`). */
|
|
232
|
+
function isCloudOutcome(o: Pick<PolicyOutcome, "origin">): boolean {
|
|
233
|
+
return o.origin?.packId?.startsWith("cloud:") === true;
|
|
234
|
+
}
|
|
235
|
+
|
|
180
236
|
/** The semantic policy an attributable Jev verdict is filed under. */
|
|
181
237
|
function jevDecider(outcome: Extract<SemanticOutcome, { status: "ok" }>) {
|
|
182
238
|
const wanted = outcome.verdict.decision === "deny" ? "deny" : "instruct";
|
|
@@ -200,6 +256,66 @@ export function fallbackCode(reason: string): string {
|
|
|
200
256
|
return /^[a-z0-9][a-z0-9-]{0,63}$/.test(code) ? code : "error";
|
|
201
257
|
}
|
|
202
258
|
|
|
259
|
+
/** Why an outcome ended where it did (`JevCheckRecord.why`), from its own fields. */
|
|
260
|
+
function checkWhy(o: PolicyOutcome): JevCheckRecord["why"] {
|
|
261
|
+
switch (o.verdict) {
|
|
262
|
+
case "none":
|
|
263
|
+
// Both deciders: under `fire` nothing fired; at or over it only the exemption stops it.
|
|
264
|
+
return o.evidence < DEFAULT_THRESHOLDS_V1.fire ? "not-detected" : "exempt";
|
|
265
|
+
case "overridden":
|
|
266
|
+
return o.intent === "op-requested" ? "op-requested" : o.intent === "task-step" ? "task-step" : "user-asked";
|
|
267
|
+
case "deny":
|
|
268
|
+
return o.escalatedByInjection ? "injection" : "fired";
|
|
269
|
+
default:
|
|
270
|
+
if (o.intent === "downgraded-task-step") return "downgraded";
|
|
271
|
+
return o.targetScanIncomplete ? "scan-incomplete" : "fired";
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/** Who declared a check, as a registered-name prefix: `cloud/<id>@<v>` or `pack/<id>@<v>`. */
|
|
276
|
+
function checkPolicy(o: PolicyOutcome): string | undefined {
|
|
277
|
+
const packId = o.origin?.packId;
|
|
278
|
+
if (!packId) return undefined;
|
|
279
|
+
const at = o.origin?.packVersion ? `@${o.origin.packVersion}` : "";
|
|
280
|
+
return packId.startsWith("cloud:") ? `cloud/${packId.slice("cloud:".length)}${at}` : `pack/${packId}${at}`;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Every asked check's answer, for the activity row (`jevChecks`): verdict,
|
|
285
|
+
* why, evidence, exempt and each probe's probability. `answers` holds the
|
|
286
|
+
* machine's own answers and Cloud's for its checks (`<check>.<probe>`).
|
|
287
|
+
*/
|
|
288
|
+
export function checkRecords(
|
|
289
|
+
outcomes: ReadonlyArray<PolicyOutcome>,
|
|
290
|
+
answers: Readonly<Record<string, number>>,
|
|
291
|
+
watched: ReadonlyArray<PolicyOutcome> = [],
|
|
292
|
+
): JevCheckRecord[] {
|
|
293
|
+
const all = [...outcomes.map((o) => ({ o, watched: false })), ...watched.map((o) => ({ o, watched: true }))];
|
|
294
|
+
return all.slice(0, JEV_CHECKS_MAX).map(({ o, watched: isWatched }) => {
|
|
295
|
+
const probes: Record<string, number> = {};
|
|
296
|
+
const prefix = `${o.policy}.`;
|
|
297
|
+
for (const [id, p] of Object.entries(answers)) {
|
|
298
|
+
if (Object.keys(probes).length >= JEV_CHECK_PROBES_MAX) break;
|
|
299
|
+
if (!id.startsWith(prefix)) continue;
|
|
300
|
+
const part = id.slice(prefix.length);
|
|
301
|
+
// `exempt` has its own field; `user_asked` (v0) is a consent question, not a probe.
|
|
302
|
+
if (part === "exempt" || part === "user_asked" || !JEV_PROBE_ID_RE.test(part)) continue;
|
|
303
|
+
probes[part] = round2(p);
|
|
304
|
+
}
|
|
305
|
+
const policy = checkPolicy(o);
|
|
306
|
+
return {
|
|
307
|
+
check: o.policy,
|
|
308
|
+
...(policy ? { policy } : {}),
|
|
309
|
+
verdict: o.verdict,
|
|
310
|
+
why: checkWhy(o),
|
|
311
|
+
p: round2(o.evidence),
|
|
312
|
+
...(o.exempt !== null ? { exempt: round2(o.exempt) } : {}),
|
|
313
|
+
...(Object.keys(probes).length > 0 ? { probes } : {}),
|
|
314
|
+
...(isWatched ? { watched: true as const } : {}),
|
|
315
|
+
};
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
|
|
203
319
|
/**
|
|
204
320
|
* @param cached - the answer came from T5's cache, not the provider: it is
|
|
205
321
|
* applied like any other, but its ~0 ms is not a latency (`latencyMs`
|
|
@@ -215,6 +331,16 @@ export function toReview(outcome: SemanticOutcome, cached = false): JevReview {
|
|
|
215
331
|
const latencyMs = sent && !cached ? outcome.latencyMs : null;
|
|
216
332
|
const model = sent ? outcome.model : null;
|
|
217
333
|
const outcomes = outcome.verdict.outcomes;
|
|
334
|
+
// A FailproofAI Cloud outcome is trusted only for a check the reply's own
|
|
335
|
+
// `asked` names. `parseCloudReply` already refuses a reply that contradicts
|
|
336
|
+
// itself; this keeps the review from relying on that alone, because a Cloud
|
|
337
|
+
// outcome is what clears a `both` policy's regex half. One it cannot vouch
|
|
338
|
+
// for — or a Cloud-origin outcome with no Cloud reply at all — means the
|
|
339
|
+
// picture is not one to clear anything on: the regex decides alone.
|
|
340
|
+
const cloudSummary = "cloud" in outcome ? (outcome as CloudSemanticOutcome & { status: "ok" }).cloud : null;
|
|
341
|
+
const cloudAsked = cloudSummary ? new Set(cloudSummary.asked) : null;
|
|
342
|
+
const unvouched = outcomes.some((o) => isCloudOutcome(o) && !(cloudAsked?.has(o.policy) ?? false));
|
|
343
|
+
if (unvouched) return { kind: "fallback", reason: "malformed", latencyMs, model: null };
|
|
218
344
|
// `null` when the injection probe was not in the request, which now means
|
|
219
345
|
// only that no request was made: v1 asks it on every call it sends, with or
|
|
220
346
|
// without a recorded human message (see `compile.ts`).
|
|
@@ -223,20 +349,25 @@ export function toReview(outcome: SemanticOutcome, cached = false): JevReview {
|
|
|
223
349
|
// not downgrade from a deny (see "A check that fired without consent keeps
|
|
224
350
|
// the floor" in `combine.ts`).
|
|
225
351
|
const warned = (o: (typeof outcomes)[number]) => o.verdict === "instruct" && o.intent !== "downgraded-task-step";
|
|
352
|
+
const cloudAnswers = cloudSummary?.answers ?? {};
|
|
353
|
+
const watched = cloudSummary?.observedOutcomes ?? [];
|
|
226
354
|
return {
|
|
227
355
|
kind: "answered",
|
|
228
356
|
decision: outcome.verdict.decision,
|
|
357
|
+
// What each asked check concluded, for the activity row. `[]` when the
|
|
358
|
+
// request carried no check (globals only, or Cloud's short-circuit).
|
|
359
|
+
checks: sent ? checkRecords(outcomes, { ...outcome.answers, ...cloudAnswers }, watched) : [],
|
|
229
360
|
reason: outcome.verdict.reason,
|
|
230
361
|
policyName: jevPolicyName(outcome),
|
|
231
362
|
...(jevDecider(outcome)?.origin ? { origin: jevDecider(outcome)?.origin } : {}),
|
|
232
363
|
// Every selected policy's questions were in the request, and `readAnswers`
|
|
233
364
|
// refuses a response missing any of them — so selected == asked, and only
|
|
234
365
|
// when a request was actually made.
|
|
235
|
-
asked: sent ? outcomes.map(
|
|
366
|
+
asked: sent ? outcomes.map(reviewerKey) : [],
|
|
236
367
|
// `none` found nothing, `overridden` is what the human asked for, and a
|
|
237
368
|
// deny the human's task softened to a warning is that task's consent — all
|
|
238
369
|
// three clear. A `deny`, or a warning nobody consented to, keeps the block.
|
|
239
|
-
notDenied: sent ? outcomes.filter((o) => o.verdict !== "deny" && !warned(o)).map(
|
|
370
|
+
notDenied: sent ? outcomes.filter((o) => o.verdict !== "deny" && !warned(o)).map(reviewerKey) : [],
|
|
240
371
|
injectionAsked: injection !== null,
|
|
241
372
|
injected: injection !== null && injection >= DEFAULT_THRESHOLDS_V1.injection,
|
|
242
373
|
// A check that CAN deny warned without consent: nothing may be cleared on
|
|
@@ -267,6 +398,18 @@ export function toReview(outcome: SemanticOutcome, cached = false): JevReview {
|
|
|
267
398
|
requestCut: outcome.requestCut && sent,
|
|
268
399
|
latencyMs,
|
|
269
400
|
model,
|
|
401
|
+
// An `observe` Cloud assignment's checks: asked, recorded, never applied.
|
|
402
|
+
...(sent && cloudSummary?.observedAsked?.length ? { observedAsked: cloudSummary.observedAsked } : {}),
|
|
403
|
+
...(cloudSummary?.observed?.length
|
|
404
|
+
? {
|
|
405
|
+
observedCloud: cloudSummary.observed.map((o) => ({
|
|
406
|
+
cloudPolicyId: o.cloudPolicyId,
|
|
407
|
+
cloudVersion: o.cloudVersion,
|
|
408
|
+
decision: o.decision,
|
|
409
|
+
reason: o.reason,
|
|
410
|
+
})),
|
|
411
|
+
}
|
|
412
|
+
: {}),
|
|
270
413
|
};
|
|
271
414
|
}
|
|
272
415
|
|
|
@@ -291,18 +434,37 @@ export function startJevReview(cfg: JevConfig, call: JevCallContext): TwoTierRev
|
|
|
291
434
|
if (!settled) controller.abort();
|
|
292
435
|
},
|
|
293
436
|
authorityOf,
|
|
437
|
+
...(call.cloud ? { cloud: true } : {}),
|
|
294
438
|
});
|
|
295
439
|
|
|
296
440
|
let route: ReturnType<typeof transportForConfig>;
|
|
297
441
|
let throttled: JevTransport;
|
|
298
442
|
try {
|
|
299
443
|
route = transportForConfig(cfg);
|
|
300
|
-
|
|
444
|
+
// A Cloud answer also depends on what Cloud deployed to this machine, which
|
|
445
|
+
// the request does not show: a new deployment is a new cache scope.
|
|
446
|
+
const scope = call.cloud
|
|
447
|
+
? `${throttleScope(cfg, route)}\u0000cloud\u0000${call.cloud.machineId}\u0000${call.cloud.deployment ?? "-"}`
|
|
448
|
+
: throttleScope(cfg, route);
|
|
449
|
+
throttled = throttle.throttleTransport(route.transport, { scope });
|
|
301
450
|
} catch (err) {
|
|
302
451
|
const reason = err instanceof JevError ? err.code : "config";
|
|
303
452
|
return handle(Promise.resolve({ kind: "fallback", reason, latencyMs: null, model: null }));
|
|
304
453
|
}
|
|
305
454
|
|
|
455
|
+
// FailproofAI Cloud Jev that keeps failing is skipped for a while, so every
|
|
456
|
+
// tool call does not wait out its timeout (`cloud-jev-health.ts`).
|
|
457
|
+
const cloud = call.cloud;
|
|
458
|
+
const healthScope = cloud ? JSON.stringify([cfg.baseUrl ?? null, cloud.machineId]) : "";
|
|
459
|
+
let probe = false;
|
|
460
|
+
if (cloud) {
|
|
461
|
+
const gate = cloudJevGate(healthScope);
|
|
462
|
+
if (!gate.ask) {
|
|
463
|
+
return handle(Promise.resolve({ kind: "fallback", reason: BREAKER_SKIP_REASON, latencyMs: null, model: null }));
|
|
464
|
+
}
|
|
465
|
+
probe = gate.probe;
|
|
466
|
+
}
|
|
467
|
+
|
|
306
468
|
let intent: ReturnType<IntentStore["readIntent"]>;
|
|
307
469
|
try {
|
|
308
470
|
intent = intentReader.readIntent(call.sessionId);
|
|
@@ -326,6 +488,8 @@ export function startJevReview(cfg: JevConfig, call: JevCallContext): TwoTierRev
|
|
|
326
488
|
|
|
327
489
|
/** Set when the answer came from T5's cache (a hit carries the original `usage` and no real latency). */
|
|
328
490
|
let cached = false;
|
|
491
|
+
/** A local inert allow or a cached reply cannot prove Cloud is healthy now. */
|
|
492
|
+
let reachedCloud = false;
|
|
329
493
|
const transport: JevTransport = async (request, signal) => {
|
|
330
494
|
const response = await throttled(request, signal);
|
|
331
495
|
cached = servedFromCache(response);
|
|
@@ -335,21 +499,52 @@ export function startJevReview(cfg: JevConfig, call: JevCallContext): TwoTierRev
|
|
|
335
499
|
const timeoutMs = resolveTimeout(cfg);
|
|
336
500
|
/** Set once the backstop below gave up on the answer: a late one is logged, never applied. */
|
|
337
501
|
let abandoned = false;
|
|
338
|
-
const
|
|
502
|
+
const options = {
|
|
339
503
|
transport,
|
|
340
504
|
cli: call.cli,
|
|
341
505
|
via: route.via,
|
|
342
506
|
model: route.model,
|
|
343
507
|
timeoutMs,
|
|
344
|
-
intent: "v1",
|
|
508
|
+
intent: "v1" as const,
|
|
345
509
|
v1: { thresholds: DEFAULT_THRESHOLDS_V1 },
|
|
346
510
|
signal: controller.signal,
|
|
347
511
|
// No `contextTruncated`: nothing reports a store cut out of band, so the
|
|
348
512
|
// evaluator's own (narrower) guess stands. See `IntentStore` above.
|
|
349
|
-
}
|
|
513
|
+
};
|
|
514
|
+
const evaluated: Promise<SemanticOutcome | CloudSemanticOutcome> = cloud
|
|
515
|
+
? evaluateCloudSemantic(input, {
|
|
516
|
+
...options,
|
|
517
|
+
machineId: cloud.machineId,
|
|
518
|
+
agent: cloud.agent,
|
|
519
|
+
observedPolicies: cloud.observedPolicies ?? [],
|
|
520
|
+
// Paused: no installed pack's check is sent, only the globals, and
|
|
521
|
+
// Cloud's own checks are selected and decided on Cloud as ever.
|
|
522
|
+
...(call.localPaused ? { policies: [] } : {}),
|
|
523
|
+
})
|
|
524
|
+
: evaluateSemantic(input, options);
|
|
525
|
+
const answered = evaluated
|
|
350
526
|
.then((outcome): JevReview => {
|
|
351
527
|
const hit = cached && outcome.status === "ok";
|
|
528
|
+
reachedCloud = outcome.status === "ok" && !hit && outcome.via !== "none";
|
|
352
529
|
const review = toReview(outcome, hit);
|
|
530
|
+
// The machine's own pack checks Cloud dropped from this request
|
|
531
|
+
// (CONTRACT C10.5), reported for the deployment it happened under. Only
|
|
532
|
+
// from an answer that arrived in time: one the backstop abandoned is not
|
|
533
|
+
// applied, and neither is anything it said. A group dropped because a
|
|
534
|
+
// Cloud check of the same name was selected (Cloud wins the name, D-S-2)
|
|
535
|
+
// is told apart from a budget drop: that Cloud check is in `asked`, or in
|
|
536
|
+
// `droppedCloud` when the budget then dropped it too.
|
|
537
|
+
if (cloud && !abandoned && outcome.status === "ok" && "cloud" in outcome && outcome.cloud.droppedLocal.length > 0) {
|
|
538
|
+
const cloudNames = new Set([...outcome.cloud.asked, ...outcome.cloud.droppedCloud]);
|
|
539
|
+
recordJevBudgetDrops(
|
|
540
|
+
{ machineId: cloud.machineId, deployment: cloud.deployment, jevMode: cloud.mode },
|
|
541
|
+
outcome.cloud.droppedLocal.map((d) => ({
|
|
542
|
+
packId: d.packId ?? "unknown",
|
|
543
|
+
name: d.name,
|
|
544
|
+
...(cloudNames.has(d.name) ? { clash: true } : {}),
|
|
545
|
+
})),
|
|
546
|
+
);
|
|
547
|
+
}
|
|
353
548
|
// An aborted request has nothing worth replaying; everything else goes
|
|
354
549
|
// to the local verdict log (never shipped), so any verdict can be
|
|
355
550
|
// re-derived offline from its recorded probabilities. A cache hit is
|
|
@@ -361,7 +556,8 @@ export function startJevReview(cfg: JevConfig, call: JevCallContext): TwoTierRev
|
|
|
361
556
|
eventType: call.eventType,
|
|
362
557
|
applied: abandoned || review.kind !== "answered" ? "legacy-fallback" : mode === "observe" ? "observe" : "two-tier",
|
|
363
558
|
});
|
|
364
|
-
|
|
559
|
+
const withCloud = outcome.status === "ok" && "cloud" in outcome ? { ...row, cloud: outcome.cloud } : row;
|
|
560
|
+
appendVerdictLog(hit ? { ...withCloud, cached: true } : withCloud);
|
|
365
561
|
}
|
|
366
562
|
return review;
|
|
367
563
|
})
|
|
@@ -381,9 +577,20 @@ export function startJevReview(cfg: JevConfig, call: JevCallContext): TwoTierRev
|
|
|
381
577
|
resolve({ kind: "fallback", reason: "timeout", latencyMs: timeoutMs + JEV_DEADLINE_GRACE_MS, model: null });
|
|
382
578
|
}, timeoutMs + JEV_DEADLINE_GRACE_MS);
|
|
383
579
|
});
|
|
580
|
+
const raced = Promise.race([answered, expired]).finally(() => {
|
|
581
|
+
if (deadline !== undefined) clearTimeout(deadline);
|
|
582
|
+
});
|
|
583
|
+
if (!cloud) return handle(raced);
|
|
384
584
|
return handle(
|
|
385
|
-
|
|
386
|
-
|
|
585
|
+
raced.then((review) => {
|
|
586
|
+
recordCloudJevResult(
|
|
587
|
+
healthScope,
|
|
588
|
+
classifyCloudJevReview(review, { reachedCloud }),
|
|
589
|
+
review.kind === "fallback" ? review.reason : null,
|
|
590
|
+
probe,
|
|
591
|
+
);
|
|
592
|
+
reportCloudJevHealth();
|
|
593
|
+
return review;
|
|
387
594
|
}),
|
|
388
595
|
);
|
|
389
596
|
}
|
|
@@ -142,7 +142,8 @@ export interface ResolvedSemanticPolicies {
|
|
|
142
142
|
}
|
|
143
143
|
|
|
144
144
|
/** Turn one validated manifest entry into a policy the compiler can use. */
|
|
145
|
-
|
|
145
|
+
/** Exported for the FailproofAI Cloud Jev parity replay (`__tests__/hooks/cloud-jev-parity.test.ts`). */
|
|
146
|
+
export function toSemanticPolicy(entry: SemanticManifestEntry, pack: { id: string; version?: string }): SemanticPolicy {
|
|
146
147
|
// An unknown precondition name DROPS the policy (the caller catches this),
|
|
147
148
|
// rather than compiling it with no gate at all. Ungating would be the wider
|
|
148
149
|
// direction, not the weaker one, but it is not what the author asked for: a
|
|
@@ -21,6 +21,12 @@ export interface JevRequest {
|
|
|
21
21
|
model: string;
|
|
22
22
|
state: Record<string, unknown>;
|
|
23
23
|
questions: Record<string, NoulQuestion>;
|
|
24
|
+
/**
|
|
25
|
+
* FailproofAI Cloud only: the tool-call metadata Cloud decides this
|
|
26
|
+
* machine's deployed Jev checks on (CONTRACT C10.3, `cloud-jev.ts`). Cloud
|
|
27
|
+
* strips it before anything reaches TypeSafe.
|
|
28
|
+
*/
|
|
29
|
+
cloud?: Record<string, unknown>;
|
|
24
30
|
}
|
|
25
31
|
|
|
26
32
|
export interface JevNoulAnswer {
|
|
@@ -34,6 +40,8 @@ export interface JevResponse {
|
|
|
34
40
|
usage?: { input_tokens?: number; output_tokens?: number };
|
|
35
41
|
/** Set when the provider did not report which Jev version answered (Cloudflare's unversioned alias). */
|
|
36
42
|
modelUnverified?: boolean;
|
|
43
|
+
/** FailproofAI Cloud only: its verdict for this machine's Cloud checks, unvalidated (`parseCloudReply`). */
|
|
44
|
+
cloud?: unknown;
|
|
37
45
|
}
|
|
38
46
|
|
|
39
47
|
/** A yes/no probe. A policy fires only when every one of its probes holds. */
|
|
@@ -195,7 +195,7 @@ export function runPauseCommand(opts: PauseCommandOptions): PauseCommandResult {
|
|
|
195
195
|
...(capped
|
|
196
196
|
? [`${INDENT}Capped at ${pauseDurationWords(PAUSE_CEILING_MS)} from when this pause began.`]
|
|
197
197
|
: []),
|
|
198
|
-
`${INDENT}Cloud-managed policies keep enforcing.`,
|
|
198
|
+
`${INDENT}Cloud-managed policies, and FailproofAI Cloud's Jev checks, keep enforcing.`,
|
|
199
199
|
`${INDENT}Resume early: ${kit.cmd(resume)}`,
|
|
200
200
|
],
|
|
201
201
|
affected: 1,
|
package/src/hooks/tui.ts
CHANGED
|
@@ -1481,6 +1481,15 @@ export function promptBrowserLogin<T>(opts: BrowserLoginOptions<T>): Promise<{ v
|
|
|
1481
1481
|
above.push(...lines);
|
|
1482
1482
|
};
|
|
1483
1483
|
|
|
1484
|
+
/** Fold what was printed above into the region, so the next repaint erases
|
|
1485
|
+
* it too — the heading goes with it and returns to the region. */
|
|
1486
|
+
const forgetAbove = (): void => {
|
|
1487
|
+
const cols = stdout.columns || 80;
|
|
1488
|
+
for (const line of above) region.lastCount += Math.max(1, Math.ceil(visibleWidth(line) / cols));
|
|
1489
|
+
above.length = 0;
|
|
1490
|
+
headingShown = false;
|
|
1491
|
+
};
|
|
1492
|
+
|
|
1484
1493
|
const clearPoll = (): void => {
|
|
1485
1494
|
if (pollTimer) clearTimeout(pollTimer);
|
|
1486
1495
|
pollTimer = null;
|
|
@@ -1500,10 +1509,7 @@ export function promptBrowserLogin<T>(opts: BrowserLoginOptions<T>): Promise<{ v
|
|
|
1500
1509
|
stdin.pause();
|
|
1501
1510
|
process.removeListener("exit", restoreTerminal);
|
|
1502
1511
|
// Leaving for the menu takes the printed link with it.
|
|
1503
|
-
if (answer === BACK)
|
|
1504
|
-
const cols = stdout.columns || 80;
|
|
1505
|
-
for (const line of above) region.lastCount += Math.max(1, Math.ceil(visibleWidth(line) / cols));
|
|
1506
|
-
}
|
|
1512
|
+
if (answer === BACK) forgetAbove();
|
|
1507
1513
|
const lines =
|
|
1508
1514
|
answer === null
|
|
1509
1515
|
? [c.ink3("cancelled")]
|
|
@@ -1564,6 +1570,9 @@ export function promptBrowserLogin<T>(opts: BrowserLoginOptions<T>): Promise<{ v
|
|
|
1564
1570
|
clearPoll();
|
|
1565
1571
|
cautionLine = "";
|
|
1566
1572
|
phase = "starting";
|
|
1573
|
+
// A retry: the expired or refused link is dead, so it leaves the screen
|
|
1574
|
+
// rather than sit above the new one, where it could still be opened.
|
|
1575
|
+
forgetAbove();
|
|
1567
1576
|
draw();
|
|
1568
1577
|
let started: BrowserLoginStart;
|
|
1569
1578
|
try {
|
|
@@ -47,6 +47,7 @@ import {
|
|
|
47
47
|
import { listInstallableIds, getIntegration } from "./integrations";
|
|
48
48
|
import type { IntegrationType } from "./types";
|
|
49
49
|
import { removeHooks } from "./manager";
|
|
50
|
+
import { installedAgentSkillDirs, removeAgentSkill } from "./agent-skill";
|
|
50
51
|
import { CODEX_MANAGED_BEGIN, CODEX_MANAGED_END, codexSystemConfigPath, codexSystemHooksPresent } from "./codex-system-hooks";
|
|
51
52
|
import { optsFor, screenKit, type RenderOpts } from "./tui";
|
|
52
53
|
|
|
@@ -110,6 +111,8 @@ export interface UninstallResult {
|
|
|
110
111
|
/** Everything this machine has that uninstalling would remove. */
|
|
111
112
|
interface Leftovers {
|
|
112
113
|
clis: IntegrationType[];
|
|
114
|
+
/** The failproofai skill folders `config` wrote into agents. */
|
|
115
|
+
skillDirs: string[];
|
|
113
116
|
/** failproofai's block in Codex's system config, which only root can remove. */
|
|
114
117
|
codexSystemPath: string | null;
|
|
115
118
|
servicePath: string | null;
|
|
@@ -149,6 +152,7 @@ function survey(cwd?: string): Leftovers {
|
|
|
149
152
|
const servicePath = isDaemonSupportedPlatform() ? daemonServiceFilePath() : null;
|
|
150
153
|
return {
|
|
151
154
|
clis,
|
|
155
|
+
skillDirs: installedAgentSkillDirs(),
|
|
152
156
|
codexSystemPath: codexSystemHooksPresent() ? codexSystemConfigPath() : null,
|
|
153
157
|
servicePath,
|
|
154
158
|
serviceInstalled: !!servicePath && existsSync(servicePath),
|
|
@@ -166,7 +170,7 @@ export async function runUninstallCommand(opts: UninstallOptions = {}): Promise<
|
|
|
166
170
|
const lines: string[] = [];
|
|
167
171
|
|
|
168
172
|
const nothingToDo =
|
|
169
|
-
found.clis.length === 0 && !found.serviceInstalled && !found.daemonConfigured &&
|
|
173
|
+
found.clis.length === 0 && found.skillDirs.length === 0 && !found.serviceInstalled && !found.daemonConfigured &&
|
|
170
174
|
!(opts.purge && found.homeExists);
|
|
171
175
|
if (nothingToDo) {
|
|
172
176
|
return {
|
|
@@ -191,6 +195,7 @@ export async function runUninstallCommand(opts: UninstallOptions = {}): Promise<
|
|
|
191
195
|
const purging = Boolean(opts.purge && found.homeExists);
|
|
192
196
|
const removals: string[] = [];
|
|
193
197
|
if (found.clis.length > 0) removals.push(`failproofai's hooks from ${many(found.clis.length, "agent")}`);
|
|
198
|
+
if (found.skillDirs.length > 0) removals.push(`the failproofai skill from ${many(found.skillDirs.length, "agent folder")}`);
|
|
194
199
|
if (found.serviceInstalled) removals.push("the failproofaid service (needs sudo)");
|
|
195
200
|
if (purging) removals.push(home);
|
|
196
201
|
const releasesDaemon = found.daemonConfigured && !found.serviceInstalled;
|
|
@@ -321,6 +326,12 @@ export async function runUninstallCommand(opts: UninstallOptions = {}): Promise<
|
|
|
321
326
|
}
|
|
322
327
|
}
|
|
323
328
|
|
|
329
|
+
if (found.skillDirs.length > 0) {
|
|
330
|
+
const left = found.skillDirs.length - removeAgentSkill().length;
|
|
331
|
+
if (left === 0) lines.push(kit.ok(`Removed the failproofai skill from ${many(found.skillDirs.length, "agent folder")}.`));
|
|
332
|
+
else failures.push(`Could not remove the failproofai skill from ${many(left, "agent folder")}:\n${installedAgentSkillDirs().join("\n")}`);
|
|
333
|
+
}
|
|
334
|
+
|
|
324
335
|
if (found.serviceInstalled) {
|
|
325
336
|
// Every run that gets here agreed to the whole plan, and the plan names the
|
|
326
337
|
// service: `--yes` is yes to the plan, an interactive yes is the same answer
|
|
@@ -36,6 +36,7 @@ interface WorkerHookRequest {
|
|
|
36
36
|
cli: IntegrationType;
|
|
37
37
|
stdin: string;
|
|
38
38
|
cwd?: string;
|
|
39
|
+
agentSettingsPath?: string;
|
|
39
40
|
}
|
|
40
41
|
|
|
41
42
|
function isWorkerHookRequest(msg: unknown): msg is WorkerHookRequest {
|
|
@@ -54,7 +55,9 @@ function isWorkerHookRequest(msg: unknown): msg is WorkerHookRequest {
|
|
|
54
55
|
// `failproofai config` aborted with "its worker process could not be run"
|
|
55
56
|
// against a daemon and worker that were both perfectly healthy. On a
|
|
56
57
|
// daemonConfigured machine the same mismatch denies the tool call.
|
|
57
|
-
(m.cwd === undefined || m.cwd === null || typeof m.cwd === "string")
|
|
58
|
+
(m.cwd === undefined || m.cwd === null || typeof m.cwd === "string") &&
|
|
59
|
+
(m.agentSettingsPath === undefined || m.agentSettingsPath === null ||
|
|
60
|
+
typeof m.agentSettingsPath === "string")
|
|
58
61
|
);
|
|
59
62
|
}
|
|
60
63
|
|
|
@@ -278,6 +281,7 @@ function handleConnection(socket: Socket, shutdown: () => void): void {
|
|
|
278
281
|
// Normalised here so no consumer has to know the wire spells
|
|
279
282
|
// "absent" as null.
|
|
280
283
|
fallbackCwd: request.cwd ?? undefined,
|
|
284
|
+
agentSettingsPath: request.agentSettingsPath ?? undefined,
|
|
281
285
|
releaseRegistry: release,
|
|
282
286
|
});
|
|
283
287
|
deliver(
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
(()=>{"use strict";module.exports=[16774,99891,98901,52306,e=>{let r;var t=e.i(66680),i=e.i(2157),o=e.i(50227),n=e.i(24214),a=e.i(79857);e.i(97348);let s=new Set(["destructive-deletion","production-infra-change","git-history-rewrite","push-to-protected-branch","commit-on-protected-branch","secret-exposure","credential-exfiltration","remote-code-execution","privilege-escalation","database-destruction","read-outside-workspace","agent-config-tampering","system-modification","env-secrets-dump","external-destructive-action","external-data-egress"]),c=new Set,l=e=>"string"==typeof e&&e.length>0;function f(e){let r={};("hard"===e.authority||"reviewable"===e.authority)&&(r.authority=e.authority);let t=e.reviewedBy;return Array.isArray(t)&&t.length>0&&t.every(l)&&(r.reviewedBy=[...t]),r}e.s(["_",0,c,"g",0,s,"i",0,f,"d",0,function(e,r=c,t){let i=e?.authority==="reviewable";if(!e||"hard"==(!0!==e.alwaysOn&&"reviewable"===e.authority&&Array.isArray(e.reviewedBy)&&e.reviewedBy.filter(e=>"string"==typeof e&&e.length>0).length>0?"reviewable":"hard")){var o;return i?{authority:"hard",downgraded:!0===(o=e).alwaysOn?"it is alwaysOn, and the self-protection guard is never reviewable":Array.isArray(o.reviewedBy)&&0!==o.reviewedBy.length?"reviewedBy is not a list of semantic policy names":"reviewedBy does not name any semantic policy"}:{authority:"hard"}}let n=e.reviewedBy;if(!n.every(l))return{authority:"hard",downgraded:"reviewedBy is not a list of semantic policy names"};let a=n.filter(e=>!r.has(e));return 0!==r.size||a.some(e=>t?.has(e))?a.length>0?{authority:"hard",downgraded:`reviewedBy names ${a.map(e=>(function(e,r,t){let i=JSON.stringify(e),o=t?.get(e);if(o)return`${i}, which packs ${o.join(" and ")} declare differently, so it is asked for neither`;if(r===s)return`${i}, which is not a semantic policy in this build`;let n=[...r].sort(),a=n.length>6?`${n.slice(0,6).join(", ")} and ${n.length-6} more`:n.join(", ");return`${i}, which is not among the Jev checks it is judged against (${a})`})(e,r,t)).join("; ")}`}:{authority:"reviewable",reviewedBy:[...new Set(n)]}:{authority:"hard"}}],99891);let d=/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*)(?:\.(?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*))*))?(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?$/,p=/^(?:0|[1-9]\d*)$/;function h(e){if("string"!=typeof e)return null;let r=d.exec(e);return r?{major:Number(r[1]),minor:Number(r[2]),patch:Number(r[3]),prerelease:void 0===r[4]?[]:r[4].split(".").map(e=>p.test(e)?Number(e):e)}:null}let u=(e,r)=>e<r?-1:+(e>r),y=["always","protected_branch","in_git_repo","has_paths","paths_outside_project","system_or_root_paths"];function m(e){return"string"==typeof e&&y.includes(e)}e.s(["B",0,y,"M",0,m],98901);let g=[1],w=/^[a-f0-9]{64}$/,$=/^[A-Za-z0-9._-]{1,64}\/[A-Za-z0-9._-]{1,64}$/,v=/^[A-Za-z0-9][A-Za-z0-9._+-]{0,63}$/,b=/^[0-9a-f]{7,40}$/,A=/^[A-Za-z0-9._-]{1,128}$/,O=/^[a-z][a-z0-9_]{0,31}$/,S=new Set(["exempt","user_asked"]),k=new Set(["shell","write","read","network","other"]),E=new Set(["string","number","boolean","string[]","pattern[]"]);function j(e,r,t,i){if("string"!=typeof t||0===t.length)throw Error(`${e} is missing ${r}`);if(t.length>i)throw Error(`${e} has a ${r} of ${t.length} characters, over the ${i}-character cap`);return t}function P(e,r,t){let i;if(!r||"object"!=typeof r||Array.isArray(r))throw Error(`${e} is not an object`);if(null!==t)i=t;else{if("string"!=typeof r.id||!O.test(r.id))throw Error(`${e} has an unsafe id ${JSON.stringify(r.id)}`);if(S.has(r.id))throw Error(`${e} uses the reserved probe id ${JSON.stringify(r.id)}`);i=r.id}let o=j(e,"instructions",r.instructions,600);if(void 0===r.criteria)return{id:i,instructions:o};if(!r.criteria||"object"!=typeof r.criteria||Array.isArray(r.criteria))throw Error(`${e} has criteria that is not an object`);let n=r.criteria;return{id:i,instructions:o,criteria:{true:j(e,"criteria.true",n.true,300),false:j(e,"criteria.false",n.false,300)}}}function _(){let e,r=process.env.FAILPROOFAI_PACK_DIR?(0,o.resolve)(process.env.FAILPROOFAI_PACK_DIR,"installed.json"):(0,a.v)();if(!(0,i.existsSync)(r))return{packs:[],errors:[]};try{e=JSON.parse((0,i.readFileSync)(r,"utf8"))}catch(e){return{packs:[],errors:[{id:null,reason:`unreadable pack manifest: ${N(e)}`}]}}if(!e||"object"!=typeof e)return{packs:[],errors:[{id:null,reason:"pack manifest is not an object"}]};let s=e;if(!g.includes(s.schemaVersion))return{packs:[],errors:[{id:null,reason:`unsupported pack manifest schema ${String(s.schemaVersion)} (supported: ${g.join(", ")})`}]};if(!Array.isArray(s.packs))return{packs:[],errors:[{id:null,reason:"pack manifest packs is not an array"}]};let c=process.env.FAILPROOFAI_PACK_DIR??(0,a.n)(),l=[],d=[],p=[],O=new Set;for(let e of s.packs){let r=e&&"object"==typeof e&&"string"==typeof e.id?e.id:null,a=[];try{let r=function(e,r,a){if(!r||"object"!=typeof r)throw Error("pack entry is not an object");let s=function(e){if("string"!=typeof e.id||!$.test(e.id))throw Error(`unsafe pack id ${JSON.stringify(e.id)}`);if("string"!=typeof e.version||!v.test(e.version))throw Error(`invalid version for pack ${e.id}`);if(void 0!==e.effect&&"enforce"!==e.effect&&"observe"!==e.effect)throw Error(`unknown effect ${JSON.stringify(e.effect)} for pack ${e.id}`);let r="string"==typeof e.commit&&b.test(e.commit.trim().toLowerCase())?e.commit.trim().toLowerCase():void 0;return{id:e.id,version:e.version,effect:e.effect??"enforce",...r?{commit:r}:{}}}(r);if("string"!=typeof r.source||0===r.source.length)throw Error(`pack ${r.id} has no source`);if("string"!=typeof r.sha256||!w.test(r.sha256))throw Error(`invalid SHA-256 for pack ${r.id}`);let c=s.effect,l=function(e,r,t=n.version){if(void 0===r)return{kind:"satisfied"};let i=function(e,r){let t=h(e),i=h(r);return t&&i?u(t.major,i.major)||u(t.minor,i.minor)||u(t.patch,i.patch)||function(e,r){if(0===e.length&&0===r.length)return 0;if(0===e.length)return 1;if(0===r.length)return -1;for(let t=0;t<Math.min(e.length,r.length);t++){let i=e[t],o=r[t];if(i===o)continue;let n="number"==typeof i,a="number"==typeof o;if(n!==a)return n?-1:1;if(n&&a)return u(i,o);return i<o?-1:1}return u(e.length,r.length)}(t.prerelease,i.prerelease):null}(t,r);return null===i?{kind:"unreadable",reason:`pack ${e} declares minCliVersion ${JSON.stringify(r)}, which is not a version this CLI can compare against its own (${t}) — the requirement was ignored`}:i<0?{kind:"too-old",reason:`pack ${e} needs failproofai ${String(r)} or newer and this is ${t} — run \`npm i -g "failproofai@>=${String(r)}" && failproofai update\``}:{kind:"satisfied",declared:r}}(s.id,r.minCliVersion);if("too-old"===l.kind)throw Error(l.reason);"unreadable"===l.kind&&a.push(l.reason);let d=function(e,r){if(!r||(0,o.isAbsolute)(r))throw Error(`unsafe managed policy path ${JSON.stringify(r)}`);let t=(0,o.resolve)(e,r),n=(0,o.relative)(e,t);if(n.startsWith("..")||(0,o.isAbsolute)(n))throw Error(`managed policy path escapes its root: ${JSON.stringify(r)}`);let a=(0,i.realpathSync)(e),s=(0,i.realpathSync)(t),c=(0,o.relative)(a,s);if(c.startsWith("..")||(0,o.isAbsolute)(c))throw Error(`managed policy symlink escapes its root: ${JSON.stringify(r)}`);return s}(e,r.entry),p=(0,t.createHash)("sha256").update((0,i.readFileSync)(d)).digest("hex");if(p!==r.sha256)throw Error(`pack ${r.id} failed integrity verification: expected ${r.sha256}, got ${p}`);if(!Array.isArray(r.policies))throw Error(`pack ${r.id} policies is not an array`);let g=r.policies.map((e,t)=>(function(e,r,t,i){let o=`${e} policy #${t}`;if(!r||"object"!=typeof r)throw Error(`${o} is not an object`);let n=r.name;if("string"!=typeof n||!A.test(n))throw Error(`${o} has an unsafe name ${JSON.stringify(n)}`);if("alwaysOn"in r)throw Error(`${o} declares alwaysOn, which packs may not set`);if("string"!=typeof r.description||0===r.description.length)throw Error(`${o} is missing a description`);if("string"!=typeof r.category||0===r.category.length)throw Error(`${o} is missing a category`);if("boolean"!=typeof r.defaultEnabled)throw Error(`${o} is missing defaultEnabled`);if(!r.match||"object"!=typeof r.match)throw Error(`${o} is missing a match`);let a=r.match;for(let e of["events","toolNames"]){let r=a[e];if(void 0!==r&&(!Array.isArray(r)||r.some(e=>"string"!=typeof e||0===e.length)))throw Error(`${o} has a match.${e} that is not a list of names`)}let s=f(r),c=["authority","reviewedBy"].filter(e=>e in r&&!(e in s));if("params"in r){let e=function(e){if(!e||"object"!=typeof e||Array.isArray(e))return"params is not an object";for(let[r,t]of Object.entries(e)){if(0===r.length)return"params has an empty parameter name";if(!t||"object"!=typeof t||Array.isArray(t))return`params.${r} is not an object`;if("string"!=typeof t.type||!E.has(t.type))return`params.${r} has type ${JSON.stringify(t.type)}, which is not one of ${[...E].join(", ")}`;if("string"!=typeof t.description||0===t.description.length)return`params.${r} is missing a description`;if(!("default"in t))return`params.${r} is missing a default`}}(r.params);e&&(i?.push(`${o} declares a params schema that was dropped: ${e}`),c.push("params"))}return c.length>0?Object.fromEntries(Object.entries(r).filter(([e])=>!c.includes(e))):r})(r.id,e,t,a)),O=new Set;for(let e of g){if(O.has(e.name))throw Error(`pack ${r.id} declares ${e.name} twice`);O.add(e.name)}let S=null;if(void 0!==r.enabled){if(!Array.isArray(r.enabled)||r.enabled.some(e=>"string"!=typeof e))throw Error(`pack ${r.id} enabled is not an array of names`);S=r.enabled.filter(e=>O.has(e))}let _=null;if(void 0!==r.clis){if(!Array.isArray(r.clis)||r.clis.some(e=>"string"!=typeof e))throw Error(`pack ${r.id} clis is not an array of agent names`);_=r.clis}return{clis:_,id:s.id,version:s.version,source:r.source,path:d,sha256:r.sha256,effect:c,policies:g,semantic:function(e,r,t){if(void 0===r)return[];if(!Array.isArray(r))return t.push(`pack ${e} semantic is not an array, so none of it was loaded`),[];let i=[],o=new Set;for(let[n,a]of r.entries()){if(i.length>=24){t.push(`pack ${e} declares more than 24 semantic policies; the ${r.length-24} past that cap were dropped`);break}try{let r=function(e,r,t){let i=`${e} semantic policy #${t}`;if(!r||"object"!=typeof r||Array.isArray(r))throw Error(`${i} is not an object`);let o=r.name;if("string"!=typeof o||!A.test(o))throw Error(`${i} has an unsafe name ${JSON.stringify(o)}`);if("alwaysOn"in r)throw Error(`${i} declares alwaysOn, which packs may not set`);let n=j(`${e} semantic policy ${o}`,"title",r.title,120),a=`${e} semantic policy ${o}`;if(!Array.isArray(r.appliesTo)||0===r.appliesTo.length)throw Error(`${a} has no appliesTo tool classes`);let s=r.appliesTo.find(e=>"string"!=typeof e||!k.has(e));if(void 0!==s)throw Error(`${a} applies to ${JSON.stringify(s)}, which is not a tool class (${[...k].join(", ")})`);if("deny"!==r.mode&&"instruct"!==r.mode)throw Error(`${a} has mode ${JSON.stringify(r.mode)}, which must be "deny" or "instruct"`);if("boolean"!=typeof r.userCanOverride)throw Error(`${a} is missing userCanOverride, which has no default`);if(!Array.isArray(r.probes)||0===r.probes.length)throw Error(`${a} declares no probes`);if(r.probes.length>6)throw Error(`${a} declares ${r.probes.length} probes, over the cap of 6`);let c=r.probes.map((e,r)=>P(`${a} probe #${r}`,e,null)),l=new Set;for(let e of c){if(l.has(e.id))throw Error(`${a} declares probe ${e.id} twice`);l.add(e.id)}let f=void 0===r.exempt?void 0:P(`${a} exempt`,r.exempt,"exempt");if(void 0!==r.precondition&&!m(r.precondition))throw Error(`${a} names precondition ${JSON.stringify(r.precondition)}, which this build does not have (${y.join(", ")})`);let d=j(a,"guidance",r.guidance,600);return{name:o,title:n,appliesTo:r.appliesTo,mode:r.mode,userCanOverride:r.userCanOverride,probes:c,...f?{exempt:f}:{},...void 0!==r.precondition?{precondition:r.precondition}:{},guidance:d}}(e,a,n);if(o.has(r.name))throw Error(`pack ${e} declares semantic policy ${r.name} twice`);o.add(r.name),i.push(r)}catch(e){t.push(N(e))}}return i}(s.id,r.semantic,a),..."satisfied"===l.kind&&l.declared?{minCliVersion:l.declared}:{},enabled:S}}(c,e,a);if(O.has(r.id))throw Error(`duplicate pack id ${r.id}`);O.add(r.id),l.push(r),p.push(...a)}catch(i){let t=e&&("observe"===e.effect||"enforce"===e.effect)?e.effect:"enforce";d.push({id:r,reason:N(i),effect:t,...Array.isArray(e?.policies)?{declared:function(e){let r=[];for(let t of e)t&&"object"==typeof t&&"string"==typeof t.name&&t.match&&"object"==typeof t.match&&r.push(t);return r}(e.policies)}:{},...Array.isArray(e?.policies)&&0===e.policies.length?{semanticOnly:!0}:{},...Array.isArray(e?.clis)&&e.clis.every(e=>"string"==typeof e)?{clis:e.clis}:{}})}}return{packs:l,errors:d,...p.length>0?{warnings:p}:{}}}function N(e){return e instanceof Error?e.message:String(e)}e.s(["f",0,_],52306);let F=null;function I(e){let r=new Map,t=new Map;for(let i of e)for(let e of i.semantic??[]){if(J(i,e.name))continue;let o=function e(r){if(Array.isArray(r))return`[${r.map(e).join(",")}]`;if(null!==r&&"object"==typeof r){let t=Object.entries(r).filter(([,e])=>void 0!==e).sort(([e],[r])=>e<r?-1:+(e>r));return`{${t.map(([r,t])=>`${JSON.stringify(r)}:${e(t)}`).join(",")}}`}return JSON.stringify(r)??"null"}(e),n=r.get(e.name);if(void 0===n){r.set(e.name,{form:o,ids:[i.id]});continue}n.ids.push(i.id),n.form!==o&&t.set(e.name,n.ids)}return t}function J(e,r){return s.has(r)&&!/^github:FailproofAI\//i.test(e.source??"")}e.s(["j",0,function(){if(F)return F;let e=c;try{var t,i,o;let n,a,s=(t=_().packs,i=r,t.filter(e=>"observe"!==e.effect&&!(i&&Array.isArray(e.clis)&&e.clis.length>0&&!e.clis.includes(i))));o=s,n=I(o),a=o.flatMap(e=>(e.semantic??[]).filter(r=>!J(e,r.name)).map(e=>e.name)).filter(e=>!n.has(e)),e=0===a.length?c:new Set(a),I(s)}catch{}return F=e,e},"Z",0,function(e){F=null,r=e}],16774)},97348,e=>{var r=e.i(2157),t=e.i(50227),i=e.i(79857);let o={info:0,warn:1,error:2},n=(0,i.A)(),a=!1,s="warn",c=!1,l=n;function f(e){return!function(){if(a)return;a=!0;let e=(process.env.FAILPROOFAI_LOG_LEVEL??"").toLowerCase();("info"===e||"warn"===e||"error"===e)&&(s=e);let r=(process.env.FAILPROOFAI_HOOK_LOG_FILE??"").trim();r&&(c=!0,"1"!==r&&"true"!==r&&(l=r))}(),o[e]>=o[s]}function d(e,r){process.stderr.write(`[failproofai:hook] ${e} ${r}
|
|
2
|
-
`)}function p(e,i){if(c)try{(0,r.existsSync)(l)||(0,r.mkdirSync)(l,{recursive:!0});let o=(0,t.join)(l,"hooks.log");try{if((0,r.statSync)(o).size>=524288){let e=`hooks-${Date.now()}.log`;(0,r.renameSync)(o,(0,t.join)(l,e))}}catch{}let n=new Date().toISOString(),a=`[${n}] ${e} ${i}
|
|
3
|
-
`;(0,r.appendFileSync)(o,a,"utf-8")}catch{}}e.s(["F",0,function(e){f("error")&&(d("ERROR",e),p("ERROR",e))},"Q",0,function(e){f("info")&&(d("INFO",e),p("INFO",e))},"g",0,function(e){f("warn")&&(d("WARN",e),p("WARN",e))}])},73136,49335,e=>{var r=e.i(2157),t=e.i(50227),i=e.i(60526),o=e.i(97348),n=e.i(79857);function a(e){if(!(0,r.existsSync)(e))return{};try{let t=(0,r.readFileSync)(e,"utf8");return JSON.parse(t)}catch(r){return(0,o.g)(`failed to parse config at ${e}: ${r instanceof Error?r.message:String(r)}`),{}}}e.s(["f",0,function(e){let o=function(e){let o=(0,i.homedir)(),n=(0,t.resolve)(e);for(;n!==o;){let e=(0,t.resolve)(n,".failproofai");try{if((0,r.statSync)(e).isDirectory())return n}catch{}let i=(0,t.dirname)(n);if(i===n)break;n=i}return(0,t.resolve)(e)}(e??process.cwd()),s=(0,t.resolve)(o,".failproofai","policies-config.json"),c=(0,t.resolve)(o,".failproofai","policies-config.local.json"),l=(0,n.O)(),f=a(s),d=a(c),p=a(l),h=new Set([...f.enabledPolicies??[],...d.enabledPolicies??[],...p.enabledPolicies??[]]),u={};for(let e of[f,d,p])if(e.policyParams)for(let[r,t]of Object.entries(e.policyParams))r in u||(u[r]=t);let y=[f,d,p].map(e=>void 0!==e.customPoliciesPaths?e.customPoliciesPaths:void 0!==e.customPoliciesPath?[e.customPoliciesPath]:void 0).find(e=>void 0!==e),m=new Set([...f.disabledCustomPolicies??[],...d.disabledCustomPolicies??[],...p.disabledCustomPolicies??[]]),g=f.customPoliciesEnabled??d.customPoliciesEnabled??p.customPoliciesEnabled,w=f.llm??d.llm??p.llm;return{enabledPolicies:[...h],...Object.keys(u).length>0?{policyParams:u}:{},...void 0!==y?{customPoliciesPaths:y}:{},...m.size?{disabledCustomPolicies:[...m]}:{},...void 0!==g?{customPoliciesEnabled:g}:{},...void 0!==w?{llm:w}:{}}}],73136);var s=e.i(24214),c=e.i(28067),l=e.i(17694);let f=c._,d=new Set;async function p(e,r,t){let i=JSON.stringify({api_key:process.env.FAILPROOFAI_POSTHOG_KEY??f,event:r,distinct_id:e,properties:{...t,$lib:"failproofai-hooks",failproofai_version:s.version,product:c.W}});try{await fetch(process.env.FAILPROOFAI_POSTHOG_HOST?`${process.env.FAILPROOFAI_POSTHOG_HOST}/capture/`:"https://us.i.posthog.com/capture/",{method:"POST",headers:{"Content-Type":"application/json"},body:i,signal:AbortSignal.timeout(5e3)})}catch{}}async function h(e,r,t){if(!(0,l.f)())return;let i=p(e,r,t);d.add(i),i.finally(()=>d.delete(i)),await i}e.s(["f",0,h],49335)}]})();
|
|
4
|
-
|
|
5
|
-
//# sourceMappingURL=src_hooks_1aveq0uhs2t1b._.js.map
|