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/cli.mjs
CHANGED
|
@@ -29,7 +29,7 @@ var __esm = (fn, res, err) => () => {
|
|
|
29
29
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
30
30
|
|
|
31
31
|
// package.json
|
|
32
|
-
var version2 = "1.0.12-beta.
|
|
32
|
+
var version2 = "1.0.12-beta.2", package_default;
|
|
33
33
|
var init_package = __esm(() => {
|
|
34
34
|
package_default = {
|
|
35
35
|
name: "failproofai",
|
|
@@ -151,23 +151,24 @@ var init_package = __esm(() => {
|
|
|
151
151
|
postcss: "8.5.26",
|
|
152
152
|
"eslint-plugin-react-hooks": "7.0.1",
|
|
153
153
|
vite: "8.1.6",
|
|
154
|
-
undici: "7.
|
|
154
|
+
undici: "7.30.1",
|
|
155
|
+
zod: "4.6.6",
|
|
155
156
|
"brace-expansion": "5.0.12",
|
|
156
157
|
sharp: "0.35.5",
|
|
157
158
|
"source-map-js": "1.2.2",
|
|
158
159
|
browserslist: "4.28.8"
|
|
159
160
|
},
|
|
160
161
|
optionalDependencies: {
|
|
161
|
-
"@failproofai/failproofaid-linux-x64": "1.0.12-beta.
|
|
162
|
-
"@failproofai/failproofaid-linux-arm64": "1.0.12-beta.
|
|
163
|
-
"@failproofai/failproofaid-darwin-x64": "1.0.12-beta.
|
|
164
|
-
"@failproofai/failproofaid-darwin-arm64": "1.0.12-beta.
|
|
162
|
+
"@failproofai/failproofaid-linux-x64": "1.0.12-beta.2",
|
|
163
|
+
"@failproofai/failproofaid-linux-arm64": "1.0.12-beta.2",
|
|
164
|
+
"@failproofai/failproofaid-darwin-x64": "1.0.12-beta.2",
|
|
165
|
+
"@failproofai/failproofaid-darwin-arm64": "1.0.12-beta.2"
|
|
165
166
|
},
|
|
166
167
|
failproofaidBinaries: {
|
|
167
|
-
"linux-x64": "
|
|
168
|
-
"linux-arm64": "
|
|
169
|
-
"darwin-x64": "
|
|
170
|
-
"darwin-arm64": "
|
|
168
|
+
"linux-x64": "4c09117fdb80d87792d1d2b77d9359cdbd0c522b5a6222ab7b927659130ddf54",
|
|
169
|
+
"linux-arm64": "dd390d76561267fc519ceb96fb90be340044e2f564bef36a44e284f227d93f29",
|
|
170
|
+
"darwin-x64": "62381f7ffe21d02289c36c4b205166b2867dbde986444d1ea185241b94fd04ef",
|
|
171
|
+
"darwin-arm64": "9ad798817d3048a5126e80dc71883538d37c1b6b6443e9c19389dc2583c8f675"
|
|
171
172
|
}
|
|
172
173
|
};
|
|
173
174
|
});
|
|
@@ -607,6 +608,14 @@ function readCredentials() {
|
|
|
607
608
|
return {};
|
|
608
609
|
}
|
|
609
610
|
}
|
|
611
|
+
function cloudManagesJevMode() {
|
|
612
|
+
try {
|
|
613
|
+
const cloud = readCredentials().cloud;
|
|
614
|
+
return Boolean(cloud?.url && cloud.machineId);
|
|
615
|
+
} catch {
|
|
616
|
+
return false;
|
|
617
|
+
}
|
|
618
|
+
}
|
|
610
619
|
function projectCredentials(parsed) {
|
|
611
620
|
{
|
|
612
621
|
const cloud = parsed.cloud;
|
|
@@ -816,7 +825,7 @@ function writeFileAt(path, contents) {
|
|
|
816
825
|
mkdirSync2(dirname2(path), { recursive: true });
|
|
817
826
|
writeFileSync2(path, contents, "utf8");
|
|
818
827
|
}
|
|
819
|
-
var DEFAULT_AUDIT_INTERVAL_DAYS = 7, MIN_AUDIT_INTERVAL_DAYS = 1, MAX_AUDIT_INTERVAL_DAYS = 90, DEFAULT_CONFIG, OWNED_CONFIG_KEYS, isPlainObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v), OWNED_CREDENTIAL_KEYS, MAX_CREDENTIALS_BYTES, credentialsOpenFlags = () => fsConstants.O_RDONLY | (fsConstants.O_NONBLOCK ?? 0), DIR_WRITABLE_BY_OTHERS = 18;
|
|
828
|
+
var DEFAULT_AUDIT_INTERVAL_DAYS = 7, MIN_AUDIT_INTERVAL_DAYS = 1, MAX_AUDIT_INTERVAL_DAYS = 90, DEFAULT_CONFIG, OWNED_CONFIG_KEYS, isPlainObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v), OWNED_CREDENTIAL_KEYS, CLOUD_MANAGED_JEV_MODE = "Jev mode is managed by FailproofAI Cloud on this machine: enforce while a Jev policy is deployed here, off when none is.", MAX_CREDENTIALS_BYTES, credentialsOpenFlags = () => fsConstants.O_RDONLY | (fsConstants.O_NONBLOCK ?? 0), DIR_WRITABLE_BY_OTHERS = 18;
|
|
820
829
|
var init_fp_config = __esm(() => {
|
|
821
830
|
init_atomic_write();
|
|
822
831
|
init_package();
|
|
@@ -912,6 +921,57 @@ function normalizeJevFallbackReason(raw) {
|
|
|
912
921
|
const code = JEV_FREE_TEXT_PREFIXES.get(head) ?? head;
|
|
913
922
|
return JEV_REASON_CODES.has(code) ? code : JEV_REASON_OTHER;
|
|
914
923
|
}
|
|
924
|
+
function sanitizeCheck(raw) {
|
|
925
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw))
|
|
926
|
+
return null;
|
|
927
|
+
const r = raw;
|
|
928
|
+
if (typeof r.check !== "string" || !JEV_CHECK_NAME_RE.test(r.check))
|
|
929
|
+
return null;
|
|
930
|
+
if (typeof r.verdict !== "string" || !CHECK_VERDICT_SET.has(r.verdict))
|
|
931
|
+
return null;
|
|
932
|
+
if (typeof r.why !== "string" || !CHECK_WHY_SET.has(r.why))
|
|
933
|
+
return null;
|
|
934
|
+
if (!isP(r.p))
|
|
935
|
+
return null;
|
|
936
|
+
const out = {
|
|
937
|
+
check: r.check,
|
|
938
|
+
verdict: r.verdict,
|
|
939
|
+
why: r.why,
|
|
940
|
+
p: round2(r.p)
|
|
941
|
+
};
|
|
942
|
+
if (typeof r.policy === "string" && isJevPolicyName(r.policy) && !/\s/.test(r.policy) && /^(?:cloud|pack)\//.test(r.policy)) {
|
|
943
|
+
out.policy = r.policy;
|
|
944
|
+
}
|
|
945
|
+
if (isP(r.exempt))
|
|
946
|
+
out.exempt = round2(r.exempt);
|
|
947
|
+
if (r.watched === true)
|
|
948
|
+
out.watched = true;
|
|
949
|
+
if (r.probes && typeof r.probes === "object" && !Array.isArray(r.probes)) {
|
|
950
|
+
const probes = {};
|
|
951
|
+
for (const [id, v] of Object.entries(r.probes)) {
|
|
952
|
+
if (Object.keys(probes).length >= JEV_CHECK_PROBES_MAX)
|
|
953
|
+
break;
|
|
954
|
+
if (JEV_PROBE_ID_RE.test(id) && isP(v))
|
|
955
|
+
probes[id] = round2(v);
|
|
956
|
+
}
|
|
957
|
+
if (Object.keys(probes).length > 0)
|
|
958
|
+
out.probes = probes;
|
|
959
|
+
}
|
|
960
|
+
return out;
|
|
961
|
+
}
|
|
962
|
+
function sanitizeJevChecks(raw) {
|
|
963
|
+
if (!Array.isArray(raw))
|
|
964
|
+
return;
|
|
965
|
+
const out = [];
|
|
966
|
+
for (const item of raw) {
|
|
967
|
+
if (out.length >= JEV_CHECKS_MAX)
|
|
968
|
+
break;
|
|
969
|
+
const rec = sanitizeCheck(item);
|
|
970
|
+
if (rec)
|
|
971
|
+
out.push(rec);
|
|
972
|
+
}
|
|
973
|
+
return raw.length > 0 && out.length === 0 ? undefined : out;
|
|
974
|
+
}
|
|
915
975
|
function sanitizeJevActivity(entry) {
|
|
916
976
|
if (!JEV_ACTIVITY_KEYS.some((k) => entry[k] !== undefined))
|
|
917
977
|
return entry;
|
|
@@ -950,6 +1010,11 @@ function sanitizeJevActivity(entry) {
|
|
|
950
1010
|
out.jevModel = out.jevModel.trim();
|
|
951
1011
|
else
|
|
952
1012
|
drop("jevModel");
|
|
1013
|
+
const checks = out.evaluator === "jev" ? sanitizeJevChecks(out.jevChecks) : undefined;
|
|
1014
|
+
if (checks === undefined)
|
|
1015
|
+
drop("jevChecks");
|
|
1016
|
+
else
|
|
1017
|
+
out.jevChecks = checks;
|
|
953
1018
|
return out;
|
|
954
1019
|
}
|
|
955
1020
|
function jevOutcome(raw) {
|
|
@@ -960,6 +1025,8 @@ function outcomeOf(e) {
|
|
|
960
1025
|
return "fallback";
|
|
961
1026
|
if (e.evaluator !== "jev")
|
|
962
1027
|
return null;
|
|
1028
|
+
if (Array.isArray(e.jevChecks) && e.jevChecks.length === 0)
|
|
1029
|
+
return "no-request";
|
|
963
1030
|
if (e.jevCleared !== undefined || e.jevLatencyMs !== undefined || e.jevModel !== undefined)
|
|
964
1031
|
return "answered";
|
|
965
1032
|
if (e.jevDecision === "deny" || e.jevDecision === "instruct")
|
|
@@ -968,7 +1035,7 @@ function outcomeOf(e) {
|
|
|
968
1035
|
return "no-request";
|
|
969
1036
|
return "not-consulted";
|
|
970
1037
|
}
|
|
971
|
-
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;
|
|
1038
|
+
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;
|
|
972
1039
|
var init_jev_activity = __esm(() => {
|
|
973
1040
|
JEV_ACTIVITY_KEYS = [
|
|
974
1041
|
"evaluator",
|
|
@@ -977,7 +1044,8 @@ var init_jev_activity = __esm(() => {
|
|
|
977
1044
|
"jevFallbackReason",
|
|
978
1045
|
"jevLatencyMs",
|
|
979
1046
|
"jevModel",
|
|
980
|
-
"jevMode"
|
|
1047
|
+
"jevMode",
|
|
1048
|
+
"jevChecks"
|
|
981
1049
|
];
|
|
982
1050
|
EVALUATORS = new Set(["jev", "jev-fallback"]);
|
|
983
1051
|
DECISIONS = new Set(["allow", "instruct", "deny"]);
|
|
@@ -1024,6 +1092,22 @@ var init_jev_activity = __esm(() => {
|
|
|
1024
1092
|
JEV_MODEL_RE = /^[A-Za-z0-9._:/@~+-]{1,200}$/;
|
|
1025
1093
|
NAME_FORBIDDEN_RE = /[\u0000-\u001f\u007f-\u009f\u2028\u2029]/;
|
|
1026
1094
|
REGISTERED_NAMESPACE_RE = /^(?:custom|pack|cloud|failproofai|\.failproofai-[A-Za-z0-9_-]{1,32})\//;
|
|
1095
|
+
JEV_CHECK_VERDICTS = ["none", "deny", "instruct", "overridden"];
|
|
1096
|
+
JEV_CHECK_WHY = [
|
|
1097
|
+
"not-detected",
|
|
1098
|
+
"exempt",
|
|
1099
|
+
"fired",
|
|
1100
|
+
"injection",
|
|
1101
|
+
"user-asked",
|
|
1102
|
+
"op-requested",
|
|
1103
|
+
"task-step",
|
|
1104
|
+
"downgraded",
|
|
1105
|
+
"scan-incomplete"
|
|
1106
|
+
];
|
|
1107
|
+
JEV_CHECK_NAME_RE = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
|
|
1108
|
+
JEV_PROBE_ID_RE = /^[a-z][a-z0-9_]{0,31}$/;
|
|
1109
|
+
CHECK_VERDICT_SET = new Set(JEV_CHECK_VERDICTS);
|
|
1110
|
+
CHECK_WHY_SET = new Set(JEV_CHECK_WHY);
|
|
1027
1111
|
ANSWERED_BUT_NOT_APPLIED_REASONS = new Set([
|
|
1028
1112
|
JEV_REASON_REQUEST_CUT,
|
|
1029
1113
|
"truncated",
|
|
@@ -1625,7 +1709,13 @@ function runtimeAgentSettingsPath(cli, cwd, userHome = homedir2(), hookScope) {
|
|
|
1625
1709
|
if (config?.trim())
|
|
1626
1710
|
return resolve2(config);
|
|
1627
1711
|
const state = process.env.OPENCLAW_STATE_DIR || process.env.OPENCLAW_HOME;
|
|
1628
|
-
|
|
1712
|
+
if (state?.trim())
|
|
1713
|
+
return resolve2(state, "openclaw.json");
|
|
1714
|
+
const profile = process.env.OPENCLAW_PROFILE?.trim();
|
|
1715
|
+
if (profile && profile !== "default" && /^[A-Za-z0-9._-]{1,80}$/.test(profile) && !profile.startsWith(".")) {
|
|
1716
|
+
return resolve2(userHome, `.openclaw-${profile}`, "openclaw.json");
|
|
1717
|
+
}
|
|
1718
|
+
return resolve2(userHome, ".openclaw", "openclaw.json");
|
|
1629
1719
|
}
|
|
1630
1720
|
const relative = USER_SETTINGS[cli];
|
|
1631
1721
|
if (!relative)
|
|
@@ -3049,6 +3139,40 @@ function readCloudJevState() {
|
|
|
3049
3139
|
const deployment = Number.isSafeInteger(active.deployment) ? active.deployment : null;
|
|
3050
3140
|
return { jevMode, deployment, errors };
|
|
3051
3141
|
}
|
|
3142
|
+
function readCloudJevAssignments() {
|
|
3143
|
+
try {
|
|
3144
|
+
const active = readActiveRaw();
|
|
3145
|
+
if (!active || !Array.isArray(active.jevPolicies))
|
|
3146
|
+
return null;
|
|
3147
|
+
const schema = active.schemaVersion;
|
|
3148
|
+
const out = [];
|
|
3149
|
+
for (const raw of active.jevPolicies) {
|
|
3150
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw))
|
|
3151
|
+
return null;
|
|
3152
|
+
const entry = raw;
|
|
3153
|
+
if (typeof entry.id !== "string" || !POLICY_ID_RE.test(entry.id))
|
|
3154
|
+
return null;
|
|
3155
|
+
if (!Number.isSafeInteger(entry.version) || entry.version < 0)
|
|
3156
|
+
return null;
|
|
3157
|
+
if (entry.effect !== undefined && entry.effect !== "enforce" && entry.effect !== "observe")
|
|
3158
|
+
return null;
|
|
3159
|
+
const targets = parseAgentTargets(entry.agentTargets, schema);
|
|
3160
|
+
out.push({
|
|
3161
|
+
id: entry.id,
|
|
3162
|
+
version: entry.version,
|
|
3163
|
+
effect: entry.effect === "observe" ? "observe" : "enforce",
|
|
3164
|
+
...targets ? { agentTargets: targets } : {}
|
|
3165
|
+
});
|
|
3166
|
+
}
|
|
3167
|
+
return out;
|
|
3168
|
+
} catch {
|
|
3169
|
+
return null;
|
|
3170
|
+
}
|
|
3171
|
+
}
|
|
3172
|
+
function cloudJevAssignmentsFor(agent) {
|
|
3173
|
+
const all = readCloudJevAssignments();
|
|
3174
|
+
return all === null ? null : all.filter((a) => agentTargetsMatch(a.agentTargets, agent));
|
|
3175
|
+
}
|
|
3052
3176
|
function cloudReviewerName(policyId, name) {
|
|
3053
3177
|
return `cloud:${policyId}/${name}`;
|
|
3054
3178
|
}
|
|
@@ -3693,9 +3817,11 @@ function effectiveReviewerNames() {
|
|
|
3693
3817
|
return cached;
|
|
3694
3818
|
let names = NO_REVIEWERS;
|
|
3695
3819
|
cachedContested = new Map;
|
|
3820
|
+
cachedPackChecks = false;
|
|
3696
3821
|
try {
|
|
3697
3822
|
const packs = jevPacks(readInstalledPacks().packs, reviewerCli);
|
|
3698
3823
|
names = reviewerNamesFor(packs);
|
|
3824
|
+
cachedPackChecks = names.size > 0;
|
|
3699
3825
|
cachedContested = contestedSemanticNames(packs);
|
|
3700
3826
|
} catch {}
|
|
3701
3827
|
try {
|
|
@@ -3713,12 +3839,9 @@ function contestedReviewerNames() {
|
|
|
3713
3839
|
function jevChecksInstalled() {
|
|
3714
3840
|
return effectiveReviewerNames().size > 0;
|
|
3715
3841
|
}
|
|
3716
|
-
function
|
|
3717
|
-
|
|
3718
|
-
|
|
3719
|
-
} catch {
|
|
3720
|
-
return false;
|
|
3721
|
-
}
|
|
3842
|
+
function packJevChecksInstalled() {
|
|
3843
|
+
effectiveReviewerNames();
|
|
3844
|
+
return cachedPackChecks;
|
|
3722
3845
|
}
|
|
3723
3846
|
function reviewerNamesFor(packs) {
|
|
3724
3847
|
const contested = contestedSemanticNames(packs);
|
|
@@ -3732,7 +3855,7 @@ function forgetEffectiveReviewerNames(cli, agent = null) {
|
|
|
3732
3855
|
reviewerCli = cli;
|
|
3733
3856
|
reviewerAgent = agent;
|
|
3734
3857
|
}
|
|
3735
|
-
var cached = null, cachedContested, reviewerCli, reviewerAgent = null;
|
|
3858
|
+
var cached = null, cachedPackChecks = false, cachedContested, reviewerCli, reviewerAgent = null;
|
|
3736
3859
|
var init_effective_reviewers = __esm(() => {
|
|
3737
3860
|
init_pack_manifest();
|
|
3738
3861
|
init_policy_authority();
|
|
@@ -14299,11 +14422,15 @@ function removeCodexSystemHooks(deps = {}) {
|
|
|
14299
14422
|
}
|
|
14300
14423
|
return { status: "removed", path, hooks };
|
|
14301
14424
|
}
|
|
14425
|
+
function codexHome() {
|
|
14426
|
+
const dir = process.env.CODEX_HOME?.trim();
|
|
14427
|
+
return dir ? resolve9(dir) : resolve9(homedir6(), ".codex");
|
|
14428
|
+
}
|
|
14302
14429
|
function codexHookTrust(deps = {}) {
|
|
14303
14430
|
const systemPath = resolvedPath(deps);
|
|
14304
14431
|
if (systemPath && codexSystemHooksPresent({ path: systemPath }))
|
|
14305
14432
|
return { kind: "system", path: systemPath };
|
|
14306
|
-
const hooksJsonPath = deps.hooksJsonPath ?? resolve9(
|
|
14433
|
+
const hooksJsonPath = deps.hooksJsonPath ?? resolve9(codexHome(), "hooks.json");
|
|
14307
14434
|
const ours = failproofaiCodexHookIdentities(hooksJsonPath);
|
|
14308
14435
|
if (ours.length === 0)
|
|
14309
14436
|
return { kind: "none" };
|
|
@@ -14312,7 +14439,7 @@ function codexHookTrust(deps = {}) {
|
|
|
14312
14439
|
return { kind: "ungated", path: hooksJsonPath, version };
|
|
14313
14440
|
let trustedHashes = new Map;
|
|
14314
14441
|
try {
|
|
14315
|
-
trustedHashes = parseCodexTrustedHashes(readFileSync8(deps.userConfigPath ?? resolve9(
|
|
14442
|
+
trustedHashes = parseCodexTrustedHashes(readFileSync8(deps.userConfigPath ?? resolve9(codexHome(), "config.toml"), "utf8"));
|
|
14316
14443
|
} catch {}
|
|
14317
14444
|
const untrusted = ours.filter((hook) => trustedHashes.get(hook.key) !== hook.hash).length;
|
|
14318
14445
|
return untrusted === 0 ? { kind: "trusted", path: hooksJsonPath } : { kind: "untrusted", path: hooksJsonPath, untrusted, total: ours.length };
|
|
@@ -14788,6 +14915,10 @@ function settingsPathsFor(integration, scope, cwd) {
|
|
|
14788
14915
|
const paths = integration.getSettingsPaths?.(scope, cwd);
|
|
14789
14916
|
return paths && paths.length > 0 ? paths : [integration.getSettingsPath(scope, cwd)];
|
|
14790
14917
|
}
|
|
14918
|
+
function claudeConfigDir() {
|
|
14919
|
+
const dir = process.env.CLAUDE_CONFIG_DIR?.trim();
|
|
14920
|
+
return dir ? resolve12(dir) : resolve12(homedir9(), ".claude");
|
|
14921
|
+
}
|
|
14791
14922
|
function codexSystemHookEntries(binaryPath) {
|
|
14792
14923
|
return CODEX_HOOK_EVENT_TYPES.map((eventType) => {
|
|
14793
14924
|
const entry = codex.buildHookEntry(binaryPath, eventType, "user");
|
|
@@ -15490,7 +15621,7 @@ var init_integrations = __esm(() => {
|
|
|
15490
15621
|
const base = cwd ? resolve12(cwd) : process.cwd();
|
|
15491
15622
|
switch (scope) {
|
|
15492
15623
|
case "user":
|
|
15493
|
-
return resolve12(
|
|
15624
|
+
return resolve12(claudeConfigDir(), "settings.json");
|
|
15494
15625
|
case "project":
|
|
15495
15626
|
return resolve12(base, ".claude", "settings.json");
|
|
15496
15627
|
case "local":
|
|
@@ -15622,7 +15753,7 @@ var init_integrations = __esm(() => {
|
|
|
15622
15753
|
const base = cwd ? resolve12(cwd) : process.cwd();
|
|
15623
15754
|
switch (scope) {
|
|
15624
15755
|
case "user":
|
|
15625
|
-
return resolve12(
|
|
15756
|
+
return resolve12(codexHome(), "hooks.json");
|
|
15626
15757
|
case "project":
|
|
15627
15758
|
return resolve12(base, ".codex", "hooks.json");
|
|
15628
15759
|
case "local":
|
|
@@ -20503,6 +20634,204 @@ function promptCloudKey(opts) {
|
|
|
20503
20634
|
});
|
|
20504
20635
|
});
|
|
20505
20636
|
}
|
|
20637
|
+
function slowedDown(interval) {
|
|
20638
|
+
return Math.max(interval, Math.min(10, interval + 2));
|
|
20639
|
+
}
|
|
20640
|
+
function promptBrowserLogin(opts) {
|
|
20641
|
+
const stdin = opts.stdin ?? process.stdin;
|
|
20642
|
+
const stdout = opts.stdout ?? process.stdout;
|
|
20643
|
+
if (!stdin.isTTY || !stdout.isTTY)
|
|
20644
|
+
return Promise.resolve(null);
|
|
20645
|
+
const now = opts.now ?? Date.now;
|
|
20646
|
+
const c = paint(colorsEnabled(stdout));
|
|
20647
|
+
const kit = screenKit({ cols: stdout.columns || 80, color: colorsEnabled(stdout) });
|
|
20648
|
+
const spinnerFrames = "⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏";
|
|
20649
|
+
const region = { lastCount: 0 };
|
|
20650
|
+
let phase = "starting";
|
|
20651
|
+
let failLine = "";
|
|
20652
|
+
let cautionLine = "";
|
|
20653
|
+
let expiresAt = 0;
|
|
20654
|
+
let interval = 2;
|
|
20655
|
+
let frame = 0;
|
|
20656
|
+
let settled = false;
|
|
20657
|
+
let headingShown = false;
|
|
20658
|
+
const above = [];
|
|
20659
|
+
let pollTimer = null;
|
|
20660
|
+
let spinTimer = null;
|
|
20661
|
+
let attempt = 0;
|
|
20662
|
+
const countdown = () => {
|
|
20663
|
+
const left = Math.max(0, Math.ceil((expiresAt - now()) / 1000));
|
|
20664
|
+
return `${Math.floor(left / 60)}:${String(left % 60).padStart(2, "0")}`;
|
|
20665
|
+
};
|
|
20666
|
+
const build = () => {
|
|
20667
|
+
const spin = c.ink3(spinnerFrames[frame % spinnerFrames.length]);
|
|
20668
|
+
switch (phase) {
|
|
20669
|
+
case "starting":
|
|
20670
|
+
return [`${INDENT}${spin} Getting a link…`];
|
|
20671
|
+
case "waiting":
|
|
20672
|
+
return [
|
|
20673
|
+
`${INDENT}${spin} Waiting for you to authorize in the browser ${c.ink3(`· expires in ${countdown()}`)}`,
|
|
20674
|
+
...cautionLine ? [kit.caution(cautionLine)] : [],
|
|
20675
|
+
"",
|
|
20676
|
+
kit.keys(["tab more options", "ctrl-c cancel"])
|
|
20677
|
+
];
|
|
20678
|
+
case "expired":
|
|
20679
|
+
return [kit.fail("That link expired."), "", kit.keys(["enter new link", "tab more options"])];
|
|
20680
|
+
case "denied":
|
|
20681
|
+
return [kit.fail("Not authorized in the browser."), "", kit.keys(["enter try again", "tab more options"])];
|
|
20682
|
+
case "failed":
|
|
20683
|
+
return [kit.fail(failLine), "", kit.keys(["enter try again", "tab more options"])];
|
|
20684
|
+
}
|
|
20685
|
+
};
|
|
20686
|
+
const draw = () => {
|
|
20687
|
+
if (settled)
|
|
20688
|
+
return;
|
|
20689
|
+
repaint(stdout, region, headingShown ? build() : [promptHeading(c, opts.message, opts.meta), ...build()]);
|
|
20690
|
+
};
|
|
20691
|
+
const printAbove = (lines) => {
|
|
20692
|
+
const clear = region.lastCount > 0 ? `${ESC}[${region.lastCount}A${ESC}[J` : "";
|
|
20693
|
+
stdout.write(`${clear}${lines.join(`
|
|
20694
|
+
`)}
|
|
20695
|
+
`);
|
|
20696
|
+
region.lastCount = 0;
|
|
20697
|
+
above.push(...lines);
|
|
20698
|
+
};
|
|
20699
|
+
const forgetAbove = () => {
|
|
20700
|
+
const cols = stdout.columns || 80;
|
|
20701
|
+
for (const line of above)
|
|
20702
|
+
region.lastCount += Math.max(1, Math.ceil(visibleWidth(line) / cols));
|
|
20703
|
+
above.length = 0;
|
|
20704
|
+
headingShown = false;
|
|
20705
|
+
};
|
|
20706
|
+
const clearPoll = () => {
|
|
20707
|
+
if (pollTimer)
|
|
20708
|
+
clearTimeout(pollTimer);
|
|
20709
|
+
pollTimer = null;
|
|
20710
|
+
};
|
|
20711
|
+
const restoreTerminal = () => showCursor(stdout);
|
|
20712
|
+
return new Promise((resolve) => {
|
|
20713
|
+
const wasRaw = stdin.isRaw;
|
|
20714
|
+
const finish = (answer) => {
|
|
20715
|
+
if (settled)
|
|
20716
|
+
return;
|
|
20717
|
+
clearPoll();
|
|
20718
|
+
if (spinTimer)
|
|
20719
|
+
clearInterval(spinTimer);
|
|
20720
|
+
stdin.removeListener("keypress", onKey);
|
|
20721
|
+
stdin.setRawMode?.(wasRaw ?? false);
|
|
20722
|
+
stdin.pause();
|
|
20723
|
+
process.removeListener("exit", restoreTerminal);
|
|
20724
|
+
if (answer === BACK)
|
|
20725
|
+
forgetAbove();
|
|
20726
|
+
const lines = answer === null ? [c.ink3("cancelled")] : answer === BACK ? [] : opts.collapsed(answer.value);
|
|
20727
|
+
repaint(stdout, region, lines, { cut: false });
|
|
20728
|
+
settled = true;
|
|
20729
|
+
restoreTerminal();
|
|
20730
|
+
resolve(answer);
|
|
20731
|
+
};
|
|
20732
|
+
const schedulePoll = (forAttempt) => {
|
|
20733
|
+
clearPoll();
|
|
20734
|
+
pollTimer = setTimeout(() => void pollOnce(forAttempt), interval * 1000);
|
|
20735
|
+
};
|
|
20736
|
+
const pollOnce = async (forAttempt) => {
|
|
20737
|
+
let answer;
|
|
20738
|
+
try {
|
|
20739
|
+
answer = await opts.poll();
|
|
20740
|
+
} catch (err) {
|
|
20741
|
+
answer = { state: "unreachable", line: err instanceof Error ? err.message : String(err) };
|
|
20742
|
+
}
|
|
20743
|
+
if (settled || forAttempt !== attempt)
|
|
20744
|
+
return;
|
|
20745
|
+
switch (answer.state) {
|
|
20746
|
+
case "approved":
|
|
20747
|
+
return finish({ value: answer.value });
|
|
20748
|
+
case "denied":
|
|
20749
|
+
phase = "denied";
|
|
20750
|
+
return draw();
|
|
20751
|
+
case "expired":
|
|
20752
|
+
phase = "expired";
|
|
20753
|
+
return draw();
|
|
20754
|
+
case "slow_down":
|
|
20755
|
+
interval = slowedDown(interval);
|
|
20756
|
+
break;
|
|
20757
|
+
case "unreachable":
|
|
20758
|
+
cautionLine = `Can't reach the server right now (${answer.line}) — still trying.`;
|
|
20759
|
+
break;
|
|
20760
|
+
case "pending":
|
|
20761
|
+
cautionLine = "";
|
|
20762
|
+
if (answer.interval && answer.interval > 0)
|
|
20763
|
+
interval = answer.interval;
|
|
20764
|
+
break;
|
|
20765
|
+
}
|
|
20766
|
+
if (now() > expiresAt + interval * 1000) {
|
|
20767
|
+
phase = "expired";
|
|
20768
|
+
return draw();
|
|
20769
|
+
}
|
|
20770
|
+
draw();
|
|
20771
|
+
schedulePoll(forAttempt);
|
|
20772
|
+
};
|
|
20773
|
+
const begin = async () => {
|
|
20774
|
+
const mine = ++attempt;
|
|
20775
|
+
clearPoll();
|
|
20776
|
+
cautionLine = "";
|
|
20777
|
+
phase = "starting";
|
|
20778
|
+
forgetAbove();
|
|
20779
|
+
draw();
|
|
20780
|
+
let started;
|
|
20781
|
+
try {
|
|
20782
|
+
started = await opts.start();
|
|
20783
|
+
} catch (err) {
|
|
20784
|
+
started = { ok: false, line: err instanceof Error ? err.message : String(err), retryable: true };
|
|
20785
|
+
}
|
|
20786
|
+
if (settled || mine !== attempt)
|
|
20787
|
+
return;
|
|
20788
|
+
if (!started.ok) {
|
|
20789
|
+
if (!started.retryable)
|
|
20790
|
+
return finish(BACK);
|
|
20791
|
+
phase = "failed";
|
|
20792
|
+
failLine = started.line;
|
|
20793
|
+
return draw();
|
|
20794
|
+
}
|
|
20795
|
+
expiresAt = now() + started.expiresIn * 1000;
|
|
20796
|
+
interval = started.interval > 0 ? started.interval : 2;
|
|
20797
|
+
const opened = opts.open(started.url);
|
|
20798
|
+
printAbove([
|
|
20799
|
+
...headingShown ? [] : [promptHeading(c, opts.message, opts.meta)],
|
|
20800
|
+
opened ? `${INDENT}Opening your browser to connect ${opts.machineLabel}. If it doesn't open, use this link:` : `${INDENT}Open this link in any browser to connect ${opts.machineLabel}:`,
|
|
20801
|
+
`${INDENT}${c.bold(started.url)}`,
|
|
20802
|
+
""
|
|
20803
|
+
]);
|
|
20804
|
+
headingShown = true;
|
|
20805
|
+
phase = "waiting";
|
|
20806
|
+
draw();
|
|
20807
|
+
schedulePoll(mine);
|
|
20808
|
+
};
|
|
20809
|
+
function onKey(_str, key) {
|
|
20810
|
+
if (!key || settled)
|
|
20811
|
+
return;
|
|
20812
|
+
if (key.ctrl && (key.name === "c" || key.name === "d"))
|
|
20813
|
+
return finish(null);
|
|
20814
|
+
if (key.name === "escape" || key.name === "tab")
|
|
20815
|
+
return finish(BACK);
|
|
20816
|
+
if ((key.name === "return" || key.name === "enter") && phase !== "waiting" && phase !== "starting") {
|
|
20817
|
+
begin();
|
|
20818
|
+
}
|
|
20819
|
+
}
|
|
20820
|
+
process.once("exit", restoreTerminal);
|
|
20821
|
+
readline.emitKeypressEvents(stdin);
|
|
20822
|
+
stdin.setRawMode?.(true);
|
|
20823
|
+
stdin.resume();
|
|
20824
|
+
hideCursor(stdout);
|
|
20825
|
+
stdin.on("keypress", onKey);
|
|
20826
|
+
spinTimer = setInterval(() => {
|
|
20827
|
+
frame++;
|
|
20828
|
+
if (phase === "waiting" || phase === "starting")
|
|
20829
|
+
draw();
|
|
20830
|
+
}, 120);
|
|
20831
|
+
spinTimer.unref?.();
|
|
20832
|
+
begin();
|
|
20833
|
+
});
|
|
20834
|
+
}
|
|
20506
20835
|
function ctx(opts) {
|
|
20507
20836
|
return { cols: Math.max(20, opts?.cols ?? 80), c: paint(opts?.color ?? false) };
|
|
20508
20837
|
}
|
|
@@ -21746,7 +22075,8 @@ function combineTwoTier(verdicts, review, mode) {
|
|
|
21746
22075
|
...cleared.length > 0 && RANK[enforced.final.decision] < RANK[legacy.decision] ? { jevCleared: cleared } : {},
|
|
21747
22076
|
...review.latencyMs !== null ? { jevLatencyMs: review.latencyMs } : {},
|
|
21748
22077
|
...review.model ? { jevModel: review.model } : {},
|
|
21749
|
-
jevMode: mode
|
|
22078
|
+
jevMode: mode,
|
|
22079
|
+
...review.checks ? { jevChecks: [...review.checks] } : {}
|
|
21750
22080
|
};
|
|
21751
22081
|
if (mode === "observe") {
|
|
21752
22082
|
const observeVerdict = review.decision === "deny" || review.decision === "instruct" ? {
|
|
@@ -21847,6 +22177,12 @@ async function evaluatePolicies(eventType, payload, session, config, twoTier) {
|
|
|
21847
22177
|
twoTier.releaseRegistry?.();
|
|
21848
22178
|
review = await twoTier.review;
|
|
21849
22179
|
}
|
|
22180
|
+
if (review.kind === "answered" && review.asked.length === 0 && review.decision === "allow" && !review.observedAsked?.length) {
|
|
22181
|
+
return formatVerdict(eventType, session, toolName, regexOnly(collected.verdicts));
|
|
22182
|
+
}
|
|
22183
|
+
if (review.kind === "not-consulted" && twoTier.cloud) {
|
|
22184
|
+
return formatVerdict(eventType, session, toolName, regexOnly(collected.verdicts));
|
|
22185
|
+
}
|
|
21850
22186
|
const combined = combineTwoTier(collected.verdicts, review, twoTier.mode);
|
|
21851
22187
|
if (combined.cleared.length > 0) {
|
|
21852
22188
|
hookLogInfo(`jev ${twoTier.mode === "observe" ? "would clear" : "cleared"}: ${combined.cleared.join(", ")}`);
|
|
@@ -21860,7 +22196,8 @@ async function evaluatePolicies(eventType, payload, session, config, twoTier) {
|
|
|
21860
22196
|
activity: combined.activity,
|
|
21861
22197
|
decidedByJev: combined.decidedByJev,
|
|
21862
22198
|
...(combined.decidedByJev || combined.observeVerdict) && review.kind === "answered" && review.origin ? { jevOrigin: review.origin } : {},
|
|
21863
|
-
...combined.observeVerdict ? { observeVerdict: combined.observeVerdict } : {}
|
|
22199
|
+
...combined.observeVerdict ? { observeVerdict: combined.observeVerdict } : {},
|
|
22200
|
+
...review.kind === "answered" && review.observedCloud?.length ? { observedCloud: review.observedCloud } : {}
|
|
21864
22201
|
}
|
|
21865
22202
|
};
|
|
21866
22203
|
}
|
|
@@ -22862,7 +23199,7 @@ var init_hook_activity_store = __esm(() => {
|
|
|
22862
23199
|
});
|
|
22863
23200
|
|
|
22864
23201
|
// src/hooks/delivery-health.ts
|
|
22865
|
-
import { existsSync as existsSync19, readdirSync as readdirSync6, statSync as statSync12 } from "node:fs";
|
|
23202
|
+
import { existsSync as existsSync19, readFileSync as readFileSync12, readdirSync as readdirSync6, statSync as statSync12 } from "node:fs";
|
|
22866
23203
|
import { join as join8 } from "node:path";
|
|
22867
23204
|
function parseParkedName(name) {
|
|
22868
23205
|
const poison = name.endsWith(POISON_SUFFIX);
|
|
@@ -22889,7 +23226,16 @@ function parseParkedName(name) {
|
|
|
22889
23226
|
}
|
|
22890
23227
|
return { base, attempt, clientStatus, poison };
|
|
22891
23228
|
}
|
|
22892
|
-
function
|
|
23229
|
+
function readLastDeliveredAt(home) {
|
|
23230
|
+
try {
|
|
23231
|
+
const raw = JSON.parse(readFileSync12(collectorHealthFile(home), "utf8"));
|
|
23232
|
+
const ts = raw?.delivery?.last_ok_ts;
|
|
23233
|
+
return typeof ts === "number" && Number.isFinite(ts) && ts > 0 ? ts * 1000 : undefined;
|
|
23234
|
+
} catch {
|
|
23235
|
+
return;
|
|
23236
|
+
}
|
|
23237
|
+
}
|
|
23238
|
+
function deliveryHealth(home, now = Date.now(), connectedAt = home ? undefined : readCredentials().connectedAt, lastDeliveredAt = home ? undefined : readLastDeliveredAt()) {
|
|
22893
23239
|
const dir = failedDir(home);
|
|
22894
23240
|
if (!existsSync19(dir))
|
|
22895
23241
|
return EMPTY;
|
|
@@ -22903,6 +23249,7 @@ function deliveryHealth(home, now = Date.now(), connectedAt = home ? undefined :
|
|
|
22903
23249
|
let total = 0;
|
|
22904
23250
|
let rejected = 0;
|
|
22905
23251
|
let credentialRejected = 0;
|
|
23252
|
+
let resending = 0;
|
|
22906
23253
|
let oldestMtime;
|
|
22907
23254
|
for (const name of entries) {
|
|
22908
23255
|
if (!name.includes(".jsonl"))
|
|
@@ -22916,6 +23263,10 @@ function deliveryHealth(home, now = Date.now(), connectedAt = home ? undefined :
|
|
|
22916
23263
|
}
|
|
22917
23264
|
if (connectedAt !== undefined && parsed.clientStatus !== undefined && CREDENTIAL_STATUSES.has(parsed.clientStatus) && mtime < connectedAt)
|
|
22918
23265
|
continue;
|
|
23266
|
+
if (lastDeliveredAt !== undefined && parsed.clientStatus !== undefined && CREDENTIAL_STATUSES.has(parsed.clientStatus) && mtime <= lastDeliveredAt) {
|
|
23267
|
+
resending += 1;
|
|
23268
|
+
continue;
|
|
23269
|
+
}
|
|
22919
23270
|
total += 1;
|
|
22920
23271
|
if (parsed.clientStatus !== undefined) {
|
|
22921
23272
|
rejected += 1;
|
|
@@ -22931,6 +23282,7 @@ function deliveryHealth(home, now = Date.now(), connectedAt = home ? undefined :
|
|
|
22931
23282
|
rejected,
|
|
22932
23283
|
credentialRejected,
|
|
22933
23284
|
byStatus,
|
|
23285
|
+
resending,
|
|
22934
23286
|
...oldestMtime !== undefined ? { oldestAgeMs: Math.max(0, now - oldestMtime) } : {}
|
|
22935
23287
|
};
|
|
22936
23288
|
}
|
|
@@ -22966,7 +23318,8 @@ var init_delivery_health = __esm(() => {
|
|
|
22966
23318
|
total: 0,
|
|
22967
23319
|
rejected: 0,
|
|
22968
23320
|
credentialRejected: 0,
|
|
22969
|
-
byStatus: {}
|
|
23321
|
+
byStatus: {},
|
|
23322
|
+
resending: 0
|
|
22970
23323
|
};
|
|
22971
23324
|
});
|
|
22972
23325
|
|
|
@@ -23662,7 +24015,7 @@ var init_cursor_projects = __esm(() => {
|
|
|
23662
24015
|
});
|
|
23663
24016
|
|
|
23664
24017
|
// lib/sqlite-reader.ts
|
|
23665
|
-
import { existsSync as existsSync20, readFileSync as
|
|
24018
|
+
import { existsSync as existsSync20, readFileSync as readFileSync13, statSync as statSync13 } from "node:fs";
|
|
23666
24019
|
import initSqlJs from "sql.js/dist/sql-asm.js";
|
|
23667
24020
|
async function tryNodeSqlite(dbPath) {
|
|
23668
24021
|
try {
|
|
@@ -23775,13 +24128,13 @@ function readPortableSnapshot(dbPath) {
|
|
|
23775
24128
|
const walPath = `${dbPath}-wal`;
|
|
23776
24129
|
for (let attempt = 0;attempt < 3; attempt += 1) {
|
|
23777
24130
|
const before = fileVersion2(dbPath);
|
|
23778
|
-
const main =
|
|
24131
|
+
const main = readFileSync13(dbPath);
|
|
23779
24132
|
const afterMain = fileVersion2(dbPath);
|
|
23780
24133
|
if (!sameVersion(before, afterMain))
|
|
23781
24134
|
continue;
|
|
23782
24135
|
let wal = null;
|
|
23783
24136
|
try {
|
|
23784
|
-
wal =
|
|
24137
|
+
wal = readFileSync13(walPath);
|
|
23785
24138
|
} catch (error) {
|
|
23786
24139
|
if (error.code !== "ENOENT")
|
|
23787
24140
|
throw error;
|
|
@@ -24868,7 +25221,7 @@ __export(exports_openclaw_projects, {
|
|
|
24868
25221
|
getOpenClawSessions: () => getOpenClawSessions,
|
|
24869
25222
|
openClawProjectPath: () => openClawProjectPath
|
|
24870
25223
|
});
|
|
24871
|
-
import { readFileSync as
|
|
25224
|
+
import { readFileSync as readFileSync14 } from "node:fs";
|
|
24872
25225
|
import { join as join18 } from "node:path";
|
|
24873
25226
|
function str2(v) {
|
|
24874
25227
|
return typeof v === "string" && v.length > 0 ? v : undefined;
|
|
@@ -24878,7 +25231,7 @@ function readSessionsIndex(agentId) {
|
|
|
24878
25231
|
const indexPath = join18(openclawHome(), "agents", agentId, "sessions", "sessions.json");
|
|
24879
25232
|
let raw;
|
|
24880
25233
|
try {
|
|
24881
|
-
raw = JSON.parse(
|
|
25234
|
+
raw = JSON.parse(readFileSync14(indexPath, "utf-8"));
|
|
24882
25235
|
} catch {
|
|
24883
25236
|
return out;
|
|
24884
25237
|
}
|
|
@@ -26687,7 +27040,7 @@ var init_log_entries = __esm(() => {
|
|
|
26687
27040
|
});
|
|
26688
27041
|
|
|
26689
27042
|
// lib/codex-sessions.ts
|
|
26690
|
-
import { readFileSync as
|
|
27043
|
+
import { readFileSync as readFileSync15, readdirSync as readdirSync10, existsSync as existsSync22, writeFileSync as writeFileSync9, mkdirSync as mkdirSync11, statSync as statSync17 } from "node:fs";
|
|
26691
27044
|
import { readFile as readFile11 } from "node:fs/promises";
|
|
26692
27045
|
import { dirname as dirname13, join as join27 } from "node:path";
|
|
26693
27046
|
import { homedir as homedir21 } from "node:os";
|
|
@@ -26695,7 +27048,7 @@ function readCache() {
|
|
|
26695
27048
|
try {
|
|
26696
27049
|
if (!existsSync22(CACHE_PATH))
|
|
26697
27050
|
return {};
|
|
26698
|
-
return JSON.parse(
|
|
27051
|
+
return JSON.parse(readFileSync15(CACHE_PATH, "utf-8"));
|
|
26699
27052
|
} catch {
|
|
26700
27053
|
return {};
|
|
26701
27054
|
}
|
|
@@ -26975,7 +27328,7 @@ var init_codex_sessions = __esm(() => {
|
|
|
26975
27328
|
});
|
|
26976
27329
|
|
|
26977
27330
|
// src/hooks/resolve-permission-mode.ts
|
|
26978
|
-
import { readFileSync as
|
|
27331
|
+
import { readFileSync as readFileSync16 } from "node:fs";
|
|
26979
27332
|
function resolvePermissionMode(integration, parsed, sessionId) {
|
|
26980
27333
|
if (integration === "claude") {
|
|
26981
27334
|
return parsed.permission_mode ?? "default";
|
|
@@ -26990,7 +27343,7 @@ function resolveCodexMode(sessionId) {
|
|
|
26990
27343
|
const path = findCodexTranscript(sessionId);
|
|
26991
27344
|
if (!path)
|
|
26992
27345
|
return;
|
|
26993
|
-
for (const line of
|
|
27346
|
+
for (const line of readFileSync16(path, "utf-8").split(`
|
|
26994
27347
|
`)) {
|
|
26995
27348
|
if (!line.includes("turn_context"))
|
|
26996
27349
|
continue;
|
|
@@ -27015,7 +27368,7 @@ var init_resolve_permission_mode = __esm(() => {
|
|
|
27015
27368
|
});
|
|
27016
27369
|
|
|
27017
27370
|
// lib/copilot-sessions.ts
|
|
27018
|
-
import { readFileSync as
|
|
27371
|
+
import { readFileSync as readFileSync17, readdirSync as readdirSync11, existsSync as existsSync23, statSync as statSync18 } from "node:fs";
|
|
27019
27372
|
import { readFile as readFile12 } from "node:fs/promises";
|
|
27020
27373
|
import { join as join28, resolve as resolve17, sep as sep2 } from "node:path";
|
|
27021
27374
|
import { homedir as homedir22 } from "node:os";
|
|
@@ -27054,7 +27407,7 @@ function findCopilotWorkspace(sessionId) {
|
|
|
27054
27407
|
}
|
|
27055
27408
|
function readYamlScalar(path, key) {
|
|
27056
27409
|
try {
|
|
27057
|
-
const text =
|
|
27410
|
+
const text = readFileSync17(path, "utf-8");
|
|
27058
27411
|
const re = new RegExp(`^${key}\\s*:\\s*(.+?)\\s*$`, "m");
|
|
27059
27412
|
const m = text.match(re);
|
|
27060
27413
|
if (!m)
|
|
@@ -27232,7 +27585,7 @@ var init_copilot_sessions = __esm(() => {
|
|
|
27232
27585
|
});
|
|
27233
27586
|
|
|
27234
27587
|
// lib/cursor-sessions.ts
|
|
27235
|
-
import { readFileSync as
|
|
27588
|
+
import { readFileSync as readFileSync18, readdirSync as readdirSync12, existsSync as existsSync24, statSync as statSync19 } from "node:fs";
|
|
27236
27589
|
import { readFile as readFile13 } from "node:fs/promises";
|
|
27237
27590
|
import { basename as basename6, join as join29, resolve as resolve18, sep as sep3 } from "node:path";
|
|
27238
27591
|
import { homedir as homedir23 } from "node:os";
|
|
@@ -27488,7 +27841,7 @@ var init_cursor_sessions = __esm(() => {
|
|
|
27488
27841
|
});
|
|
27489
27842
|
|
|
27490
27843
|
// lib/pi-sessions.ts
|
|
27491
|
-
import { readFileSync as
|
|
27844
|
+
import { readFileSync as readFileSync19, readdirSync as readdirSync13, existsSync as existsSync25, statSync as statSync20 } from "node:fs";
|
|
27492
27845
|
import { readFile as readFile14 } from "node:fs/promises";
|
|
27493
27846
|
import { join as join30, resolve as resolve19, sep as sep4 } from "node:path";
|
|
27494
27847
|
import { homedir as homedir24 } from "node:os";
|
|
@@ -27798,7 +28151,7 @@ var STDIN_TIMEOUT_MS2 = 1e4;
|
|
|
27798
28151
|
|
|
27799
28152
|
// src/hooks/cloud-policy-errors.ts
|
|
27800
28153
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
27801
|
-
import { chmodSync as chmodSync6, existsSync as existsSync26, readFileSync as
|
|
28154
|
+
import { chmodSync as chmodSync6, existsSync as existsSync26, readFileSync as readFileSync20, renameSync as renameSync8, rmSync as rmSync9, writeFileSync as writeFileSync10 } from "node:fs";
|
|
27802
28155
|
import { homedir as homedir25 } from "node:os";
|
|
27803
28156
|
import { resolve as resolve20 } from "node:path";
|
|
27804
28157
|
function isPackDropEntry(e) {
|
|
@@ -27835,7 +28188,7 @@ function cloudPolicyErrorsPath() {
|
|
|
27835
28188
|
}
|
|
27836
28189
|
function readCloudPolicyErrors() {
|
|
27837
28190
|
try {
|
|
27838
|
-
const raw = JSON.parse(
|
|
28191
|
+
const raw = JSON.parse(readFileSync20(cloudPolicyErrorsPath(), "utf8"));
|
|
27839
28192
|
if (!Array.isArray(raw.errors))
|
|
27840
28193
|
return null;
|
|
27841
28194
|
return raw.errors.filter((e) => !!e && typeof e === "object" && typeof e.id === "string" && typeof e.message === "string" && KINDS.has(e.kind) && (e.version === null || Number.isSafeInteger(e.version)));
|
|
@@ -27859,7 +28212,7 @@ function writeCloudPolicyErrors(errors) {
|
|
|
27859
28212
|
return "unchanged";
|
|
27860
28213
|
let current = null;
|
|
27861
28214
|
try {
|
|
27862
|
-
current =
|
|
28215
|
+
current = readFileSync20(path, "utf8");
|
|
27863
28216
|
} catch {
|
|
27864
28217
|
current = null;
|
|
27865
28218
|
}
|
|
@@ -27881,7 +28234,7 @@ function cloudLoadCheckedPath() {
|
|
|
27881
28234
|
}
|
|
27882
28235
|
function readCloudLoadChecked() {
|
|
27883
28236
|
try {
|
|
27884
|
-
const raw = JSON.parse(
|
|
28237
|
+
const raw = JSON.parse(readFileSync20(cloudLoadCheckedPath(), "utf8"));
|
|
27885
28238
|
if (!Number.isSafeInteger(raw.deployment) || !Array.isArray(raw.checked))
|
|
27886
28239
|
return null;
|
|
27887
28240
|
return { deployment: raw.deployment, checked: raw.checked.filter((c) => typeof c === "string") };
|
|
@@ -27946,7 +28299,7 @@ function jevBudgetPath() {
|
|
|
27946
28299
|
}
|
|
27947
28300
|
function readJevBudgetRecord() {
|
|
27948
28301
|
try {
|
|
27949
|
-
const raw = JSON.parse(
|
|
28302
|
+
const raw = JSON.parse(readFileSync20(jevBudgetPath(), "utf8"));
|
|
27950
28303
|
if (typeof raw.machineId !== "string" || !(raw.deployment === null || Number.isSafeInteger(raw.deployment)) || raw.jevMode !== "observe" && raw.jevMode !== "enforce" || !Array.isArray(raw.dropped)) {
|
|
27951
28304
|
return null;
|
|
27952
28305
|
}
|
|
@@ -27969,7 +28322,7 @@ function installedPackIds() {
|
|
|
27969
28322
|
const path = resolve20(packsRoot(), "installed.json");
|
|
27970
28323
|
if (!existsSync26(path))
|
|
27971
28324
|
return new Set;
|
|
27972
|
-
const raw = JSON.parse(
|
|
28325
|
+
const raw = JSON.parse(readFileSync20(path, "utf8"));
|
|
27973
28326
|
if (!Array.isArray(raw.packs))
|
|
27974
28327
|
return null;
|
|
27975
28328
|
return new Set(raw.packs.map((p) => p && typeof p === "object" ? p.id : null).filter((id) => typeof id === "string"));
|
|
@@ -28164,7 +28517,7 @@ var init_pack_failclosed = __esm(() => {
|
|
|
28164
28517
|
});
|
|
28165
28518
|
|
|
28166
28519
|
// src/hooks/session-pause.ts
|
|
28167
|
-
import { existsSync as existsSync27, mkdirSync as mkdirSync12, readdirSync as readdirSync14, readFileSync as
|
|
28520
|
+
import { existsSync as existsSync27, mkdirSync as mkdirSync12, readdirSync as readdirSync14, readFileSync as readFileSync21, rmSync as rmSync10 } from "node:fs";
|
|
28168
28521
|
import { createHash as createHash8 } from "node:crypto";
|
|
28169
28522
|
import { join as join31, resolve as resolve21 } from "node:path";
|
|
28170
28523
|
function pauseStateDir() {
|
|
@@ -28233,7 +28586,7 @@ function readActivePause(sessionId, now = Date.now()) {
|
|
|
28233
28586
|
const path = pauseFilePath(sessionId);
|
|
28234
28587
|
if (!existsSync27(path))
|
|
28235
28588
|
return null;
|
|
28236
|
-
const stored = parseStored(JSON.parse(
|
|
28589
|
+
const stored = parseStored(JSON.parse(readFileSync21(path, "utf8")));
|
|
28237
28590
|
if (!stored)
|
|
28238
28591
|
return null;
|
|
28239
28592
|
if (stored.expiresAt <= now)
|
|
@@ -28286,7 +28639,7 @@ function listActivePauses(now = Date.now()) {
|
|
|
28286
28639
|
if (!name.endsWith(".json"))
|
|
28287
28640
|
continue;
|
|
28288
28641
|
try {
|
|
28289
|
-
const stored = parseStored(JSON.parse(
|
|
28642
|
+
const stored = parseStored(JSON.parse(readFileSync21(join31(dir, name), "utf8")));
|
|
28290
28643
|
if (!stored || stored.expiresAt <= now)
|
|
28291
28644
|
continue;
|
|
28292
28645
|
const { schemaVersion: _ignored, ...pause } = stored;
|
|
@@ -28328,7 +28681,7 @@ import {
|
|
|
28328
28681
|
copyFileSync as copyFileSync2,
|
|
28329
28682
|
existsSync as existsSync28,
|
|
28330
28683
|
mkdirSync as mkdirSync13,
|
|
28331
|
-
readFileSync as
|
|
28684
|
+
readFileSync as readFileSync22,
|
|
28332
28685
|
readdirSync as readdirSync15,
|
|
28333
28686
|
renameSync as renameSync9,
|
|
28334
28687
|
rmSync as rmSync11,
|
|
@@ -28455,7 +28808,7 @@ function retirePolicyConfigKeys() {
|
|
|
28455
28808
|
const at = globalPolicyConfigFile();
|
|
28456
28809
|
let parsed;
|
|
28457
28810
|
try {
|
|
28458
|
-
const raw = JSON.parse(
|
|
28811
|
+
const raw = JSON.parse(readFileSync22(at, "utf8"));
|
|
28459
28812
|
if (!raw || typeof raw !== "object" || Array.isArray(raw))
|
|
28460
28813
|
return [];
|
|
28461
28814
|
parsed = raw;
|
|
@@ -28484,7 +28837,7 @@ function readCarriedPolicyConfig() {
|
|
|
28484
28837
|
return null;
|
|
28485
28838
|
let parsed;
|
|
28486
28839
|
try {
|
|
28487
|
-
parsed = JSON.parse(
|
|
28840
|
+
parsed = JSON.parse(readFileSync22(from, "utf8"));
|
|
28488
28841
|
} catch {
|
|
28489
28842
|
return null;
|
|
28490
28843
|
}
|
|
@@ -28528,7 +28881,7 @@ function writeCarriedPolicyConfig(carried) {
|
|
|
28528
28881
|
const to = globalPolicyConfigFile();
|
|
28529
28882
|
let existing = {};
|
|
28530
28883
|
try {
|
|
28531
|
-
const parsed = JSON.parse(
|
|
28884
|
+
const parsed = JSON.parse(readFileSync22(to, "utf8"));
|
|
28532
28885
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
28533
28886
|
existing = parsed;
|
|
28534
28887
|
}
|
|
@@ -28547,7 +28900,7 @@ function readCarriedTelemetryOptOut() {
|
|
|
28547
28900
|
if (!existsSync28(from))
|
|
28548
28901
|
return false;
|
|
28549
28902
|
try {
|
|
28550
|
-
const text =
|
|
28903
|
+
const text = readFileSync22(from, "utf8");
|
|
28551
28904
|
const start = text.search(/^\s*\[telemetry\]\s*$/m);
|
|
28552
28905
|
if (start === -1)
|
|
28553
28906
|
return false;
|
|
@@ -28602,7 +28955,7 @@ function readCarriedLegacyConfig() {
|
|
|
28602
28955
|
if (!existsSync28(from))
|
|
28603
28956
|
return null;
|
|
28604
28957
|
try {
|
|
28605
|
-
return projectConfig(parseLegacyToml(
|
|
28958
|
+
return projectConfig(parseLegacyToml(readFileSync22(from, "utf8")));
|
|
28606
28959
|
} catch {
|
|
28607
28960
|
return null;
|
|
28608
28961
|
}
|
|
@@ -28611,14 +28964,14 @@ function readCarriedLegacyCredentials() {
|
|
|
28611
28964
|
const toml = legacy.credentialsToml();
|
|
28612
28965
|
if (existsSync28(toml)) {
|
|
28613
28966
|
try {
|
|
28614
|
-
const creds = projectCredentials(parseLegacyToml(
|
|
28967
|
+
const creds = projectCredentials(parseLegacyToml(readFileSync22(toml, "utf8")));
|
|
28615
28968
|
if (Object.keys(creds).length > 0)
|
|
28616
28969
|
return creds;
|
|
28617
28970
|
} catch {}
|
|
28618
28971
|
}
|
|
28619
28972
|
const readJson = (path) => {
|
|
28620
28973
|
try {
|
|
28621
|
-
const parsed = JSON.parse(
|
|
28974
|
+
const parsed = JSON.parse(readFileSync22(path, "utf8"));
|
|
28622
28975
|
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
28623
28976
|
} catch {
|
|
28624
28977
|
return null;
|
|
@@ -28691,7 +29044,7 @@ var init_fp_reset = __esm(() => {
|
|
|
28691
29044
|
});
|
|
28692
29045
|
|
|
28693
29046
|
// src/hooks/untraced-note.ts
|
|
28694
|
-
import { existsSync as existsSync29, readFileSync as
|
|
29047
|
+
import { existsSync as existsSync29, readFileSync as readFileSync23 } from "node:fs";
|
|
28695
29048
|
import { join as join32 } from "node:path";
|
|
28696
29049
|
function untracedNotePath(home) {
|
|
28697
29050
|
return join32(stateDir(home), "untraced-notes.json");
|
|
@@ -28704,7 +29057,7 @@ function noteUntracedAgent(cli, sessionId, config) {
|
|
|
28704
29057
|
const path = untracedNotePath();
|
|
28705
29058
|
let seen = [];
|
|
28706
29059
|
if (existsSync29(path)) {
|
|
28707
|
-
const parsed = JSON.parse(
|
|
29060
|
+
const parsed = JSON.parse(readFileSync23(path, "utf8"));
|
|
28708
29061
|
if (Array.isArray(parsed))
|
|
28709
29062
|
seen = parsed.filter((k) => typeof k === "string");
|
|
28710
29063
|
}
|
|
@@ -28726,7 +29079,7 @@ var init_untraced_note = __esm(() => {
|
|
|
28726
29079
|
});
|
|
28727
29080
|
|
|
28728
29081
|
// src/hooks/agent-roster.ts
|
|
28729
|
-
import { lstatSync as lstatSync4, readFileSync as
|
|
29082
|
+
import { lstatSync as lstatSync4, readFileSync as readFileSync24, statSync as statSync22 } from "node:fs";
|
|
28730
29083
|
import { homedir as homedir26 } from "node:os";
|
|
28731
29084
|
import { dirname as dirname15, resolve as resolve23 } from "node:path";
|
|
28732
29085
|
function installedHookAt2(path, cli) {
|
|
@@ -28734,7 +29087,7 @@ function installedHookAt2(path, cli) {
|
|
|
28734
29087
|
const stat = statSync22(path);
|
|
28735
29088
|
if (!stat.isFile() || stat.size > 131072)
|
|
28736
29089
|
return false;
|
|
28737
|
-
const text =
|
|
29090
|
+
const text = readFileSync24(path, "utf8");
|
|
28738
29091
|
if (text.includes("failproofai"))
|
|
28739
29092
|
return true;
|
|
28740
29093
|
if (cli !== "pi")
|
|
@@ -28762,7 +29115,13 @@ function runtimeAgentSettingsPath2(cli, cwd, userHome = homedir26(), hookScope)
|
|
|
28762
29115
|
if (config?.trim())
|
|
28763
29116
|
return resolve23(config);
|
|
28764
29117
|
const state = process.env.OPENCLAW_STATE_DIR || process.env.OPENCLAW_HOME;
|
|
28765
|
-
|
|
29118
|
+
if (state?.trim())
|
|
29119
|
+
return resolve23(state, "openclaw.json");
|
|
29120
|
+
const profile = process.env.OPENCLAW_PROFILE?.trim();
|
|
29121
|
+
if (profile && profile !== "default" && /^[A-Za-z0-9._-]{1,80}$/.test(profile) && !profile.startsWith(".")) {
|
|
29122
|
+
return resolve23(userHome, `.openclaw-${profile}`, "openclaw.json");
|
|
29123
|
+
}
|
|
29124
|
+
return resolve23(userHome, ".openclaw", "openclaw.json");
|
|
28766
29125
|
}
|
|
28767
29126
|
const relative = USER_SETTINGS2[cli];
|
|
28768
29127
|
if (!relative)
|
|
@@ -28802,7 +29161,7 @@ function readRuntimeAgentIdentity(cli, settingsPath) {
|
|
|
28802
29161
|
const stat = lstatSync4(path);
|
|
28803
29162
|
if (!stat.isFile() || (stat.mode & 63) !== 0 || stat.size > MAX_ROSTER_BYTES)
|
|
28804
29163
|
return null;
|
|
28805
|
-
const roster = JSON.parse(
|
|
29164
|
+
const roster = JSON.parse(readFileSync24(path, "utf8"));
|
|
28806
29165
|
if (!roster || typeof roster !== "object" || Array.isArray(roster))
|
|
28807
29166
|
return null;
|
|
28808
29167
|
const data = roster;
|
|
@@ -28828,7 +29187,7 @@ function readRosterLabels() {
|
|
|
28828
29187
|
const stat = lstatSync4(path);
|
|
28829
29188
|
if (!stat.isFile() || (stat.mode & 63) !== 0 || stat.size > MAX_ROSTER_BYTES)
|
|
28830
29189
|
return out;
|
|
28831
|
-
const roster = JSON.parse(
|
|
29190
|
+
const roster = JSON.parse(readFileSync24(path, "utf8"));
|
|
28832
29191
|
if (!roster || typeof roster !== "object" || Array.isArray(roster))
|
|
28833
29192
|
return out;
|
|
28834
29193
|
const data = roster;
|
|
@@ -28970,13 +29329,6 @@ function providerHostConflict(provider, url) {
|
|
|
28970
29329
|
return `${host} is ${known}'s endpoint, not ${provider}'s`;
|
|
28971
29330
|
return known === "cloudflare" ? `${host} is Cloudflare Workers AI, which provider custom cannot reach — its endpoint is per-account and its answers are wrapped, and a custom endpoint is asked in TypeSafe's own shape at <url>/systemone` : null;
|
|
28972
29331
|
}
|
|
28973
|
-
function isPlainHttp(url) {
|
|
28974
|
-
try {
|
|
28975
|
-
return new URL(url).protocol === "http:";
|
|
28976
|
-
} catch {
|
|
28977
|
-
return false;
|
|
28978
|
-
}
|
|
28979
|
-
}
|
|
28980
29332
|
function originOf(raw) {
|
|
28981
29333
|
try {
|
|
28982
29334
|
const url = new URL(raw);
|
|
@@ -29114,12 +29466,6 @@ function validateJevConfig(raw, envKey, cloud) {
|
|
|
29114
29466
|
return { ok: false, problem: 'mode must be "off", "observe" or "enforce"' };
|
|
29115
29467
|
cfg.mode = mode;
|
|
29116
29468
|
}
|
|
29117
|
-
if (cfg.baseUrl !== undefined && isPlainHttp(cfg.baseUrl) && cfg.mode === "enforce") {
|
|
29118
|
-
return {
|
|
29119
|
-
ok: false,
|
|
29120
|
-
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")
|
|
29121
|
-
};
|
|
29122
|
-
}
|
|
29123
29469
|
return { ok: true, value: cfg };
|
|
29124
29470
|
}
|
|
29125
29471
|
function validateLoadedJevConfig(cfg) {
|
|
@@ -29566,7 +29912,7 @@ var init_cloud_jev_health = __esm(() => {
|
|
|
29566
29912
|
});
|
|
29567
29913
|
|
|
29568
29914
|
// src/hooks/semantic/facts.ts
|
|
29569
|
-
import { existsSync as existsSync30, readFileSync as
|
|
29915
|
+
import { existsSync as existsSync30, readFileSync as readFileSync25, statSync as statSync24 } from "node:fs";
|
|
29570
29916
|
import { homedir as homedir27 } from "node:os";
|
|
29571
29917
|
import { dirname as dirname17, isAbsolute as isAbsolute4, resolve as resolve24 } from "node:path";
|
|
29572
29918
|
function classifyTool(toolName) {
|
|
@@ -29817,13 +30163,13 @@ function readCurrentBranch(cwd) {
|
|
|
29817
30163
|
return null;
|
|
29818
30164
|
let headFile = resolve24(gitPath, "HEAD");
|
|
29819
30165
|
if (statSync24(gitPath).isFile()) {
|
|
29820
|
-
const pointer =
|
|
30166
|
+
const pointer = readFileSync25(gitPath, "utf8").trim();
|
|
29821
30167
|
const m = /^gitdir:\s*(.+)$/.exec(pointer);
|
|
29822
30168
|
if (!m)
|
|
29823
30169
|
return null;
|
|
29824
30170
|
headFile = resolve24(dirname17(gitPath), m[1], "HEAD");
|
|
29825
30171
|
}
|
|
29826
|
-
const head =
|
|
30172
|
+
const head = readFileSync25(headFile, "utf8").trim();
|
|
29827
30173
|
const ref = /^ref:\s*refs\/heads\/(.+)$/.exec(head);
|
|
29828
30174
|
return ref ? ref[1] : null;
|
|
29829
30175
|
} catch {
|
|
@@ -30216,7 +30562,7 @@ import {
|
|
|
30216
30562
|
mkdirSync as mkdirSync14,
|
|
30217
30563
|
openSync as openSync4,
|
|
30218
30564
|
readdirSync as readdirSync16,
|
|
30219
|
-
readFileSync as
|
|
30565
|
+
readFileSync as readFileSync26,
|
|
30220
30566
|
readSync as readSync3,
|
|
30221
30567
|
renameSync as renameSync10,
|
|
30222
30568
|
statSync as statSync25,
|
|
@@ -30266,7 +30612,7 @@ function looseIntentStoreDir() {
|
|
|
30266
30612
|
}
|
|
30267
30613
|
function readIntentFile(sessionId) {
|
|
30268
30614
|
try {
|
|
30269
|
-
const parsed = JSON.parse(
|
|
30615
|
+
const parsed = JSON.parse(readFileSync26(intentFile(sessionId), "utf8"));
|
|
30270
30616
|
return Array.isArray(parsed?.prompts) ? parsed : { prompts: [] };
|
|
30271
30617
|
} catch {
|
|
30272
30618
|
return { prompts: [] };
|
|
@@ -31589,7 +31935,11 @@ function parseOutcome(raw, i) {
|
|
|
31589
31935
|
if (!origin || typeof origin !== "object" || typeof origin.cloudPolicyId !== "string" || !POLICY_ID_RE2.test(origin.cloudPolicyId) || !Number.isSafeInteger(origin.cloudVersion) || origin.cloudVersion < 0) {
|
|
31590
31936
|
malformed(`outcome ${i} has no Cloud origin`);
|
|
31591
31937
|
}
|
|
31592
|
-
|
|
31938
|
+
if (o.effect !== undefined && o.effect !== "enforce" && o.effect !== "observe")
|
|
31939
|
+
malformed(`outcome ${i} has an unknown effect`);
|
|
31940
|
+
if (o.reason !== undefined && o.reason !== null && typeof o.reason !== "string")
|
|
31941
|
+
malformed(`outcome ${i} reason is not text`);
|
|
31942
|
+
const outcome = {
|
|
31593
31943
|
policy: o.policy,
|
|
31594
31944
|
mode: o.mode,
|
|
31595
31945
|
...typeof o.userCanOverride === "boolean" ? { userCanOverride: o.userCanOverride } : {},
|
|
@@ -31603,41 +31953,103 @@ function parseOutcome(raw, i) {
|
|
|
31603
31953
|
...o.intent !== undefined ? { intent: o.intent } : {},
|
|
31604
31954
|
...o.targetScanIncomplete === true ? { targetScanIncomplete: true } : {}
|
|
31605
31955
|
};
|
|
31956
|
+
return {
|
|
31957
|
+
outcome,
|
|
31958
|
+
cloudPolicyId: origin.cloudPolicyId,
|
|
31959
|
+
cloudVersion: origin.cloudVersion,
|
|
31960
|
+
observe: o.effect === "observe",
|
|
31961
|
+
reason: typeof o.reason === "string" ? capReason(o.reason) : null
|
|
31962
|
+
};
|
|
31963
|
+
}
|
|
31964
|
+
function capReason(reason) {
|
|
31965
|
+
return reason.length > MAX_CLOUD_REASON_CHARS ? `${reason.slice(0, MAX_CLOUD_REASON_CHARS - 1)}…` : reason;
|
|
31966
|
+
}
|
|
31967
|
+
function observedChecks(parsed, watched = null) {
|
|
31968
|
+
const firing = watched?.parsed.filter((p) => p.outcome.verdict === "deny" || p.outcome.verdict === "instruct") ?? [];
|
|
31969
|
+
const watchedReason = firing.length === 1 && typeof watched?.v.reason === "string" ? capReason(watched.v.reason) : null;
|
|
31970
|
+
const byPolicy = new Map;
|
|
31971
|
+
for (const p of parsed) {
|
|
31972
|
+
const verdict = p.outcome.verdict;
|
|
31973
|
+
if (verdict !== "deny" && verdict !== "instruct")
|
|
31974
|
+
continue;
|
|
31975
|
+
const prev = byPolicy.get(p.cloudPolicyId);
|
|
31976
|
+
if (prev && SEVERITY[prev.decision] >= SEVERITY[verdict])
|
|
31977
|
+
continue;
|
|
31978
|
+
byPolicy.set(p.cloudPolicyId, {
|
|
31979
|
+
cloudPolicyId: p.cloudPolicyId,
|
|
31980
|
+
cloudVersion: p.cloudVersion,
|
|
31981
|
+
check: p.outcome.policy,
|
|
31982
|
+
decision: verdict,
|
|
31983
|
+
reason: p.reason ?? (firing[0] === p ? watchedReason : null) ?? `Flagged by semantic review (semantic/${p.outcome.policy})`
|
|
31984
|
+
});
|
|
31985
|
+
}
|
|
31986
|
+
return [...byPolicy.values()];
|
|
31606
31987
|
}
|
|
31607
|
-
function
|
|
31608
|
-
|
|
31609
|
-
malformed("no cloud block");
|
|
31610
|
-
const block = raw;
|
|
31611
|
-
const v = block.verdict;
|
|
31988
|
+
function parseVerdictBlock(rawVerdict, rawAsked, what) {
|
|
31989
|
+
const v = rawVerdict;
|
|
31612
31990
|
if (!v || typeof v !== "object" || Array.isArray(v))
|
|
31613
|
-
malformed(
|
|
31991
|
+
malformed(`no ${what}`);
|
|
31614
31992
|
if (typeof v.decision !== "string" || !DECISIONS2.has(v.decision))
|
|
31615
|
-
malformed(
|
|
31993
|
+
malformed(`${what} has no decision`);
|
|
31616
31994
|
if (v.reason !== null && v.reason !== undefined && typeof v.reason !== "string")
|
|
31617
|
-
malformed(
|
|
31995
|
+
malformed(`${what} reason is not text`);
|
|
31618
31996
|
if (!Array.isArray(v.outcomes) || v.outcomes.length > MAX_LIST)
|
|
31619
|
-
malformed(
|
|
31997
|
+
malformed(`${what} has no outcomes list`);
|
|
31620
31998
|
if (v.beyondTask !== undefined && typeof v.beyondTask !== "boolean")
|
|
31621
|
-
malformed(
|
|
31622
|
-
const
|
|
31623
|
-
const asked = names(
|
|
31999
|
+
malformed(`${what} beyondTask is not a flag`);
|
|
32000
|
+
const parsed = v.outcomes.map(parseOutcome);
|
|
32001
|
+
const asked = names(rawAsked, `${what} asked`);
|
|
31624
32002
|
const askedSet = new Set(asked);
|
|
31625
32003
|
const seen = new Set;
|
|
31626
|
-
|
|
32004
|
+
parsed.forEach(({ outcome: o }, i) => {
|
|
31627
32005
|
if (!askedSet.has(o.policy))
|
|
31628
|
-
malformed(
|
|
32006
|
+
malformed(`${what} outcome ${i} answers ${JSON.stringify(o.policy)}, which Cloud did not ask`);
|
|
31629
32007
|
const key = `${o.origin?.packId ?? ""}\x00${o.policy}`;
|
|
31630
32008
|
if (seen.has(key))
|
|
31631
|
-
malformed(
|
|
32009
|
+
malformed(`${what} outcome ${i} answers ${JSON.stringify(o.policy)} twice`);
|
|
31632
32010
|
seen.add(key);
|
|
31633
32011
|
});
|
|
31634
|
-
|
|
32012
|
+
return { v, parsed, asked };
|
|
32013
|
+
}
|
|
32014
|
+
function parseCloudReply(raw, observedPolicies = []) {
|
|
32015
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw))
|
|
32016
|
+
malformed("no cloud block");
|
|
32017
|
+
const block = raw;
|
|
32018
|
+
const { v, parsed, asked } = parseVerdictBlock(block.verdict, block.asked, "verdict");
|
|
32019
|
+
let watched = null;
|
|
32020
|
+
if (block.observed !== undefined && block.observed !== null) {
|
|
32021
|
+
const o = block.observed;
|
|
32022
|
+
if (typeof o !== "object" || Array.isArray(o))
|
|
32023
|
+
malformed("observed is not an object");
|
|
32024
|
+
watched = parseVerdictBlock(o.verdict, o.asked, "observed verdict");
|
|
32025
|
+
if (watched.parsed.some((p) => p.outcome.verdict === "deny") && watched.v.decision !== "deny") {
|
|
32026
|
+
malformed("an observed check denied but its verdict does not");
|
|
32027
|
+
}
|
|
32028
|
+
}
|
|
32029
|
+
const observeIds = new Set(observedPolicies);
|
|
32030
|
+
const isObserved = (p) => p.observe || observeIds.has(p.cloudPolicyId);
|
|
32031
|
+
const enforced = parsed.filter((p) => !isObserved(p)).map((p) => p.outcome);
|
|
32032
|
+
const observedHere = parsed.filter(isObserved);
|
|
32033
|
+
const observed = [...observedHere, ...watched?.parsed ?? []];
|
|
32034
|
+
if (enforced.some((o) => o.verdict === "deny") && v.decision !== "deny")
|
|
31635
32035
|
malformed("a check denied but the verdict does not");
|
|
32036
|
+
const cloudReason = typeof v.reason === "string" ? capReason(v.reason) : null;
|
|
32037
|
+
let decision = v.decision;
|
|
32038
|
+
let reason = cloudReason;
|
|
32039
|
+
if (observedHere.length > 0) {
|
|
32040
|
+
const own = enforced.some((o) => o.verdict === "deny") ? "deny" : enforced.some((o) => o.verdict === "instruct") || v.beyondTask === true ? "instruct" : "allow";
|
|
32041
|
+
const capped = RANK2[own] <= RANK2[decision] ? own : decision;
|
|
32042
|
+
if (capped !== decision)
|
|
32043
|
+
reason = null;
|
|
32044
|
+
decision = capped;
|
|
32045
|
+
}
|
|
31636
32046
|
return {
|
|
32047
|
+
observed: observedChecks(observed, watched),
|
|
32048
|
+
observedAsked: [...observedHere.map((p) => p.outcome.policy), ...watched?.asked ?? []],
|
|
31637
32049
|
verdict: {
|
|
31638
|
-
decision
|
|
31639
|
-
reason
|
|
31640
|
-
outcomes,
|
|
32050
|
+
decision,
|
|
32051
|
+
reason,
|
|
32052
|
+
outcomes: enforced,
|
|
31641
32053
|
injectionSuspected: nullableProbability(v.injectionSuspected, "injectionSuspected"),
|
|
31642
32054
|
scopeWithinRequest: nullableProbability(v.scopeWithinRequest, "scopeWithinRequest"),
|
|
31643
32055
|
beyondTask: v.beyondTask === true
|
|
@@ -31647,6 +32059,29 @@ function parseCloudReply(raw) {
|
|
|
31647
32059
|
droppedCloud: names(block.droppedCloud, "droppedCloud")
|
|
31648
32060
|
};
|
|
31649
32061
|
}
|
|
32062
|
+
function parseObservedOutcomes(raw) {
|
|
32063
|
+
try {
|
|
32064
|
+
const block = raw?.observed;
|
|
32065
|
+
if (!block || typeof block !== "object" || Array.isArray(block))
|
|
32066
|
+
return [];
|
|
32067
|
+
const asked = new Set(names(block.asked, "observed.asked"));
|
|
32068
|
+
const outcomes = block.verdict?.outcomes ?? [];
|
|
32069
|
+
if (!Array.isArray(outcomes) || outcomes.length > MAX_LIST)
|
|
32070
|
+
return [];
|
|
32071
|
+
const seen = new Set;
|
|
32072
|
+
const out = [];
|
|
32073
|
+
outcomes.forEach((o, i) => {
|
|
32074
|
+
const parsed = parseOutcome(o, i).outcome;
|
|
32075
|
+
if (!asked.has(parsed.policy) || seen.has(parsed.policy))
|
|
32076
|
+
return;
|
|
32077
|
+
seen.add(parsed.policy);
|
|
32078
|
+
out.push(parsed);
|
|
32079
|
+
});
|
|
32080
|
+
return out;
|
|
32081
|
+
} catch {
|
|
32082
|
+
return [];
|
|
32083
|
+
}
|
|
32084
|
+
}
|
|
31650
32085
|
function joinLines(reasons) {
|
|
31651
32086
|
const lines = [];
|
|
31652
32087
|
for (const reason of reasons) {
|
|
@@ -31693,6 +32128,22 @@ function expectedQuestions(request, prepared, dropped) {
|
|
|
31693
32128
|
}));
|
|
31694
32129
|
return { ...request, questions };
|
|
31695
32130
|
}
|
|
32131
|
+
function cloudCheckAnswers(response, asked) {
|
|
32132
|
+
const out = {};
|
|
32133
|
+
if (asked.length === 0)
|
|
32134
|
+
return out;
|
|
32135
|
+
const names = new Set(asked);
|
|
32136
|
+
const answers = response.answers && typeof response.answers === "object" ? response.answers : {};
|
|
32137
|
+
for (const [id, a] of Object.entries(answers)) {
|
|
32138
|
+
const dot = id.lastIndexOf(".");
|
|
32139
|
+
if (dot <= 0 || !names.has(id.slice(0, dot)) || !QUESTION_PART_RE.test(id.slice(dot + 1)))
|
|
32140
|
+
continue;
|
|
32141
|
+
const p = a?.noul;
|
|
32142
|
+
if (isProbability(p))
|
|
32143
|
+
out[id] = p;
|
|
32144
|
+
}
|
|
32145
|
+
return out;
|
|
32146
|
+
}
|
|
31696
32147
|
function presentAnswers(response) {
|
|
31697
32148
|
const out = {};
|
|
31698
32149
|
const answers = response.answers && typeof response.answers === "object" ? response.answers : {};
|
|
@@ -31721,7 +32172,7 @@ async function evaluateCloudSemantic(input, opts) {
|
|
|
31721
32172
|
model: opts.model ?? DEFAULT_JEV_MODEL,
|
|
31722
32173
|
modelVerified: true,
|
|
31723
32174
|
via: "none",
|
|
31724
|
-
cloud: { asked: [], droppedLocal: [], droppedCloud: [] }
|
|
32175
|
+
cloud: { asked: [], droppedLocal: [], droppedCloud: [], answers: {}, observed: [], observedAsked: [], observedOutcomes: [] }
|
|
31725
32176
|
};
|
|
31726
32177
|
}
|
|
31727
32178
|
let prepared;
|
|
@@ -31762,11 +32213,13 @@ async function evaluateCloudSemantic(input, opts) {
|
|
|
31762
32213
|
const timeout = AbortSignal.timeout(opts.timeoutMs ?? envNumber2("FAILPROOFAI_JEV_TIMEOUT_MS", DEFAULT_JEV_TIMEOUT_MS));
|
|
31763
32214
|
const signal = opts.signal ? AbortSignal.any([timeout, opts.signal]) : timeout;
|
|
31764
32215
|
const response = await transport(request, signal);
|
|
31765
|
-
const reply = parseCloudReply(response.cloud);
|
|
32216
|
+
const reply = parseCloudReply(response.cloud, opts.observedPolicies);
|
|
32217
|
+
const observedAsked = new Set(reply.observedAsked);
|
|
32218
|
+
const observedOutcomes = parseObservedOutcomes(response.cloud).filter((o) => observedAsked.has(o.policy));
|
|
31766
32219
|
const own = new Map(prepared.selected.map((p) => [p.name, p]));
|
|
31767
32220
|
const dropped = new Set(reply.droppedLocal.filter((name) => own.has(name)));
|
|
31768
32221
|
const kept = prepared.selected.filter((p) => !dropped.has(p.name));
|
|
31769
|
-
const shortCircuit = kept.length === 0 && reply.asked.length === 0 && reply.verdict.outcomes.length === 0;
|
|
32222
|
+
const shortCircuit = kept.length === 0 && reply.asked.length === 0 && reply.verdict.outcomes.length === 0 && reply.observedAsked.length === 0;
|
|
31770
32223
|
const answers = shortCircuit ? presentAnswers(response) : readAnswers(expectedQuestions(request, prepared, dropped), response);
|
|
31771
32224
|
const local = prepared.intent === "v1" ? decideV1(kept, answers, input.toolInput, prepared.userSaid, prepared.agentLastMessage, {
|
|
31772
32225
|
...opts.v1,
|
|
@@ -31788,7 +32241,11 @@ async function evaluateCloudSemantic(input, opts) {
|
|
|
31788
32241
|
cloud: {
|
|
31789
32242
|
asked: reply.asked,
|
|
31790
32243
|
droppedLocal: [...dropped].map((name) => ({ name, packId: own.get(name)?.origin?.packId ?? null })),
|
|
31791
|
-
droppedCloud: reply.droppedCloud
|
|
32244
|
+
droppedCloud: reply.droppedCloud,
|
|
32245
|
+
answers: cloudCheckAnswers(response, [...reply.asked, ...reply.observedAsked]),
|
|
32246
|
+
observed: reply.observed,
|
|
32247
|
+
observedAsked: reply.observedAsked,
|
|
32248
|
+
observedOutcomes
|
|
31792
32249
|
}
|
|
31793
32250
|
};
|
|
31794
32251
|
} catch (err) {
|
|
@@ -31801,7 +32258,7 @@ async function evaluateCloudSemantic(input, opts) {
|
|
|
31801
32258
|
return degraded(`error: ${err instanceof Error ? err.message : String(err)}`);
|
|
31802
32259
|
}
|
|
31803
32260
|
}
|
|
31804
|
-
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;
|
|
32261
|
+
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;
|
|
31805
32262
|
var init_cloud_jev = __esm(() => {
|
|
31806
32263
|
init_compile();
|
|
31807
32264
|
init_decide();
|
|
@@ -31817,6 +32274,7 @@ var init_cloud_jev = __esm(() => {
|
|
|
31817
32274
|
DECISIONS2 = new Set(["allow", "deny", "instruct"]);
|
|
31818
32275
|
VERDICTS = new Set(["deny", "instruct", "overridden", "none"]);
|
|
31819
32276
|
INTENTS = new Set(["op-requested", "task-step", "downgraded-task-step"]);
|
|
32277
|
+
SEVERITY = { instruct: 1, deny: 2 };
|
|
31820
32278
|
RANK2 = { allow: 0, instruct: 1, deny: 2 };
|
|
31821
32279
|
EMPTY_ALLOW = {
|
|
31822
32280
|
decision: "allow",
|
|
@@ -31826,6 +32284,7 @@ var init_cloud_jev = __esm(() => {
|
|
|
31826
32284
|
scopeWithinRequest: null,
|
|
31827
32285
|
beyondTask: false
|
|
31828
32286
|
};
|
|
32287
|
+
QUESTION_PART_RE = /^[a-z][a-z0-9_]{0,31}$/;
|
|
31829
32288
|
});
|
|
31830
32289
|
|
|
31831
32290
|
// src/hooks/semantic/jev-throttle.ts
|
|
@@ -32038,7 +32497,7 @@ var init_jev_throttle = __esm(() => {
|
|
|
32038
32497
|
});
|
|
32039
32498
|
|
|
32040
32499
|
// src/hooks/semantic/session-root.ts
|
|
32041
|
-
import { mkdirSync as mkdirSync16, readdirSync as readdirSync17, readFileSync as
|
|
32500
|
+
import { mkdirSync as mkdirSync16, readdirSync as readdirSync17, readFileSync as readFileSync27, statSync as statSync27, unlinkSync as unlinkSync5, writeFileSync as writeFileSync13 } from "node:fs";
|
|
32042
32501
|
import { isAbsolute as isAbsolute5, resolve as resolve27 } from "node:path";
|
|
32043
32502
|
function validRoot(v) {
|
|
32044
32503
|
return typeof v === "string" && isAbsolute5(v) && resolve27(v) === v && v !== "/";
|
|
@@ -32057,7 +32516,7 @@ function storeIsOurs() {
|
|
|
32057
32516
|
}
|
|
32058
32517
|
function readPinned(sessionId) {
|
|
32059
32518
|
try {
|
|
32060
|
-
const parsed = JSON.parse(
|
|
32519
|
+
const parsed = JSON.parse(readFileSync27(rootFile(sessionId), "utf8"));
|
|
32061
32520
|
return validRoot(parsed?.root) ? parsed.root : null;
|
|
32062
32521
|
} catch {
|
|
32063
32522
|
return null;
|
|
@@ -32161,6 +32620,55 @@ function fallbackCode(reason) {
|
|
|
32161
32620
|
const code = reason.split(":")[0].trim();
|
|
32162
32621
|
return /^[a-z0-9][a-z0-9-]{0,63}$/.test(code) ? code : "error";
|
|
32163
32622
|
}
|
|
32623
|
+
function checkWhy(o) {
|
|
32624
|
+
switch (o.verdict) {
|
|
32625
|
+
case "none":
|
|
32626
|
+
return o.evidence < DEFAULT_THRESHOLDS_V1.fire ? "not-detected" : "exempt";
|
|
32627
|
+
case "overridden":
|
|
32628
|
+
return o.intent === "op-requested" ? "op-requested" : o.intent === "task-step" ? "task-step" : "user-asked";
|
|
32629
|
+
case "deny":
|
|
32630
|
+
return o.escalatedByInjection ? "injection" : "fired";
|
|
32631
|
+
default:
|
|
32632
|
+
if (o.intent === "downgraded-task-step")
|
|
32633
|
+
return "downgraded";
|
|
32634
|
+
return o.targetScanIncomplete ? "scan-incomplete" : "fired";
|
|
32635
|
+
}
|
|
32636
|
+
}
|
|
32637
|
+
function checkPolicy(o) {
|
|
32638
|
+
const packId = o.origin?.packId;
|
|
32639
|
+
if (!packId)
|
|
32640
|
+
return;
|
|
32641
|
+
const at = o.origin?.packVersion ? `@${o.origin.packVersion}` : "";
|
|
32642
|
+
return packId.startsWith("cloud:") ? `cloud/${packId.slice("cloud:".length)}${at}` : `pack/${packId}${at}`;
|
|
32643
|
+
}
|
|
32644
|
+
function checkRecords(outcomes, answers, watched = []) {
|
|
32645
|
+
const all = [...outcomes.map((o) => ({ o, watched: false })), ...watched.map((o) => ({ o, watched: true }))];
|
|
32646
|
+
return all.slice(0, JEV_CHECKS_MAX).map(({ o, watched: isWatched }) => {
|
|
32647
|
+
const probes = {};
|
|
32648
|
+
const prefix = `${o.policy}.`;
|
|
32649
|
+
for (const [id, p] of Object.entries(answers)) {
|
|
32650
|
+
if (Object.keys(probes).length >= JEV_CHECK_PROBES_MAX)
|
|
32651
|
+
break;
|
|
32652
|
+
if (!id.startsWith(prefix))
|
|
32653
|
+
continue;
|
|
32654
|
+
const part = id.slice(prefix.length);
|
|
32655
|
+
if (part === "exempt" || part === "user_asked" || !JEV_PROBE_ID_RE.test(part))
|
|
32656
|
+
continue;
|
|
32657
|
+
probes[part] = round2(p);
|
|
32658
|
+
}
|
|
32659
|
+
const policy = checkPolicy(o);
|
|
32660
|
+
return {
|
|
32661
|
+
check: o.policy,
|
|
32662
|
+
...policy ? { policy } : {},
|
|
32663
|
+
verdict: o.verdict,
|
|
32664
|
+
why: checkWhy(o),
|
|
32665
|
+
p: round2(o.evidence),
|
|
32666
|
+
...o.exempt !== null ? { exempt: round2(o.exempt) } : {},
|
|
32667
|
+
...Object.keys(probes).length > 0 ? { probes } : {},
|
|
32668
|
+
...isWatched ? { watched: true } : {}
|
|
32669
|
+
};
|
|
32670
|
+
});
|
|
32671
|
+
}
|
|
32164
32672
|
function toReview(outcome, cached = false) {
|
|
32165
32673
|
if (outcome.status === "degraded") {
|
|
32166
32674
|
return { kind: "fallback", reason: fallbackCode(outcome.reason), latencyMs: outcome.latencyMs, model: null };
|
|
@@ -32169,15 +32677,19 @@ function toReview(outcome, cached = false) {
|
|
|
32169
32677
|
const latencyMs = sent && !cached ? outcome.latencyMs : null;
|
|
32170
32678
|
const model = sent ? outcome.model : null;
|
|
32171
32679
|
const outcomes = outcome.verdict.outcomes;
|
|
32172
|
-
const
|
|
32680
|
+
const cloudSummary = "cloud" in outcome ? outcome.cloud : null;
|
|
32681
|
+
const cloudAsked = cloudSummary ? new Set(cloudSummary.asked) : null;
|
|
32173
32682
|
const unvouched = outcomes.some((o) => isCloudOutcome(o) && !(cloudAsked?.has(o.policy) ?? false));
|
|
32174
32683
|
if (unvouched)
|
|
32175
32684
|
return { kind: "fallback", reason: "malformed", latencyMs, model: null };
|
|
32176
32685
|
const injection = sent ? outcome.verdict.injectionSuspected : null;
|
|
32177
32686
|
const warned = (o) => o.verdict === "instruct" && o.intent !== "downgraded-task-step";
|
|
32687
|
+
const cloudAnswers = cloudSummary?.answers ?? {};
|
|
32688
|
+
const watched = cloudSummary?.observedOutcomes ?? [];
|
|
32178
32689
|
return {
|
|
32179
32690
|
kind: "answered",
|
|
32180
32691
|
decision: outcome.verdict.decision,
|
|
32692
|
+
checks: sent ? checkRecords(outcomes, { ...outcome.answers, ...cloudAnswers }, watched) : [],
|
|
32181
32693
|
reason: outcome.verdict.reason,
|
|
32182
32694
|
policyName: jevPolicyName(outcome),
|
|
32183
32695
|
...jevDecider(outcome)?.origin ? { origin: jevDecider(outcome)?.origin } : {},
|
|
@@ -32189,7 +32701,16 @@ function toReview(outcome, cached = false) {
|
|
|
32189
32701
|
truncated: outcome.truncated && sent,
|
|
32190
32702
|
requestCut: outcome.requestCut && sent,
|
|
32191
32703
|
latencyMs,
|
|
32192
|
-
model
|
|
32704
|
+
model,
|
|
32705
|
+
...sent && cloudSummary?.observedAsked?.length ? { observedAsked: cloudSummary.observedAsked } : {},
|
|
32706
|
+
...cloudSummary?.observed?.length ? {
|
|
32707
|
+
observedCloud: cloudSummary.observed.map((o) => ({
|
|
32708
|
+
cloudPolicyId: o.cloudPolicyId,
|
|
32709
|
+
cloudVersion: o.cloudVersion,
|
|
32710
|
+
decision: o.decision,
|
|
32711
|
+
reason: o.reason
|
|
32712
|
+
}))
|
|
32713
|
+
} : {}
|
|
32193
32714
|
};
|
|
32194
32715
|
}
|
|
32195
32716
|
function toolInputRecord(raw) {
|
|
@@ -32208,7 +32729,8 @@ function startJevReview(cfg, call) {
|
|
|
32208
32729
|
if (!settled)
|
|
32209
32730
|
controller.abort();
|
|
32210
32731
|
},
|
|
32211
|
-
authorityOf
|
|
32732
|
+
authorityOf,
|
|
32733
|
+
...call.cloud ? { cloud: true } : {}
|
|
32212
32734
|
});
|
|
32213
32735
|
let route;
|
|
32214
32736
|
let throttled;
|
|
@@ -32270,6 +32792,7 @@ function startJevReview(cfg, call) {
|
|
|
32270
32792
|
...options,
|
|
32271
32793
|
machineId: cloud.machineId,
|
|
32272
32794
|
agent: cloud.agent,
|
|
32795
|
+
observedPolicies: cloud.observedPolicies ?? [],
|
|
32273
32796
|
...call.localPaused ? { policies: [] } : {}
|
|
32274
32797
|
}) : evaluateSemantic(input, options);
|
|
32275
32798
|
const answered = evaluated.then((outcome) => {
|
|
@@ -32331,6 +32854,7 @@ var init_jev_review = __esm(() => {
|
|
|
32331
32854
|
init_jev_config();
|
|
32332
32855
|
init_jev_throttle();
|
|
32333
32856
|
init_session_root();
|
|
32857
|
+
init_jev_activity();
|
|
32334
32858
|
throttle = exports_jev_throttle;
|
|
32335
32859
|
intentReader = exports_intent;
|
|
32336
32860
|
ALWAYS_ON = new Set(BUILTIN_POLICIES.filter((p) => p.alwaysOn).map((p) => normalizePolicyName(p.name)));
|
|
@@ -32544,7 +33068,13 @@ async function readJevConfig(agent) {
|
|
|
32544
33068
|
return {
|
|
32545
33069
|
config: resolved.config,
|
|
32546
33070
|
defaultMode: DEFAULT_JEV_MODE,
|
|
32547
|
-
cloud: {
|
|
33071
|
+
cloud: {
|
|
33072
|
+
machineId: resolved.machineId,
|
|
33073
|
+
deployment: cloud.deployment,
|
|
33074
|
+
mode: cloud.jevMode,
|
|
33075
|
+
agent: agent ?? null,
|
|
33076
|
+
observedPolicies: (cloudJevAssignmentsFor(agent ?? null) ?? []).filter((a) => a.effect === "observe").map((a) => a.id)
|
|
33077
|
+
}
|
|
32548
33078
|
};
|
|
32549
33079
|
}
|
|
32550
33080
|
if (!existsSync31(jevConfigFile()))
|
|
@@ -32618,6 +33148,8 @@ async function startTwoTier(canonicalEventType, parsed, session, cli, opts, acti
|
|
|
32618
33148
|
return null;
|
|
32619
33149
|
if (!cloudAsks && !jevChecksInstalled())
|
|
32620
33150
|
return null;
|
|
33151
|
+
if (cloudAsks && cloudJevAssignmentsFor(agent)?.length === 0 && (activePause || !packJevChecksInstalled()))
|
|
33152
|
+
return null;
|
|
32621
33153
|
const loaded = await readJevConfig(agent);
|
|
32622
33154
|
if (!loaded)
|
|
32623
33155
|
return null;
|
|
@@ -32941,6 +33473,9 @@ async function evaluateHookEvent(eventType, cli = "claude", stdinPayload, opts)
|
|
|
32941
33473
|
reason: observeVerdict.reason
|
|
32942
33474
|
});
|
|
32943
33475
|
}
|
|
33476
|
+
for (const o of result.twoTier?.observedCloud ?? []) {
|
|
33477
|
+
observedResults.push({ policyId: o.cloudPolicyId, version: o.cloudVersion, decision: o.decision, reason: o.reason });
|
|
33478
|
+
}
|
|
32944
33479
|
const durationMs = Math.round(performance.now() - startTime);
|
|
32945
33480
|
hookLogInfo(`result=${result.decision} policy=${result.policyName ?? "none"} duration=${durationMs}ms`);
|
|
32946
33481
|
await captureJevIntent(canonicalEventType, result.decision, parsed, session, cli, opts);
|
|
@@ -34070,7 +34605,7 @@ import {
|
|
|
34070
34605
|
copyFileSync as copyFileSync3,
|
|
34071
34606
|
existsSync as existsSync33,
|
|
34072
34607
|
mkdirSync as mkdirSync18,
|
|
34073
|
-
readFileSync as
|
|
34608
|
+
readFileSync as readFileSync28,
|
|
34074
34609
|
renameSync as renameSync12,
|
|
34075
34610
|
rmSync as rmSync12,
|
|
34076
34611
|
writeFileSync as writeFileSync15
|
|
@@ -34140,7 +34675,7 @@ function planMigration(from, registry = MIGRATIONS) {
|
|
|
34140
34675
|
}
|
|
34141
34676
|
function readLedger() {
|
|
34142
34677
|
try {
|
|
34143
|
-
const parsed = JSON.parse(
|
|
34678
|
+
const parsed = JSON.parse(readFileSync28(migrationLedgerFile(), "utf8"));
|
|
34144
34679
|
return Array.isArray(parsed) ? parsed : [];
|
|
34145
34680
|
} catch {
|
|
34146
34681
|
return [];
|
|
@@ -34449,7 +34984,7 @@ var init_fp_reset2 = __esm(() => {
|
|
|
34449
34984
|
// scripts/install-telemetry.mjs
|
|
34450
34985
|
import { createHmac, randomUUID as randomUUID3 } from "node:crypto";
|
|
34451
34986
|
import { execSync as execSync6 } from "node:child_process";
|
|
34452
|
-
import { readFileSync as
|
|
34987
|
+
import { readFileSync as readFileSync29, writeFileSync as writeFileSync16, mkdirSync as mkdirSync19 } from "node:fs";
|
|
34453
34988
|
import { homedir as homedir28, platform, arch, hostname, cpus } from "node:os";
|
|
34454
34989
|
import { join as join35 } from "node:path";
|
|
34455
34990
|
function hashToId3(raw) {
|
|
@@ -34459,7 +34994,7 @@ function getInstanceId3() {
|
|
|
34459
34994
|
const idDir = join35(homedir28(), ".failproofai");
|
|
34460
34995
|
const idFile = join35(idDir, "instance-id");
|
|
34461
34996
|
try {
|
|
34462
|
-
const existing =
|
|
34997
|
+
const existing = readFileSync29(idFile, "utf-8").trim();
|
|
34463
34998
|
if (existing)
|
|
34464
34999
|
return existing;
|
|
34465
35000
|
} catch {}
|
|
@@ -34468,7 +35003,7 @@ function getInstanceId3() {
|
|
|
34468
35003
|
if (p === "linux") {
|
|
34469
35004
|
for (const machineIdPath of ["/etc/machine-id", "/var/lib/dbus/machine-id"]) {
|
|
34470
35005
|
try {
|
|
34471
|
-
const id =
|
|
35006
|
+
const id = readFileSync29(machineIdPath, "utf-8").trim();
|
|
34472
35007
|
if (id)
|
|
34473
35008
|
return hashToId3(id);
|
|
34474
35009
|
} catch {}
|
|
@@ -34533,7 +35068,7 @@ var NAMESPACE3 = "failproofai-telemetry-v1", API_KEY3 = "phc_Ac1Ww1GqKc0z1SyrRWb
|
|
|
34533
35068
|
var init_install_telemetry = () => {};
|
|
34534
35069
|
|
|
34535
35070
|
// lib/install-check.ts
|
|
34536
|
-
import { existsSync as existsSync34, readFileSync as
|
|
35071
|
+
import { existsSync as existsSync34, readFileSync as readFileSync30, writeFileSync as writeFileSync17, mkdirSync as mkdirSync20 } from "node:fs";
|
|
34537
35072
|
import { dirname as dirname21, resolve as resolve29 } from "node:path";
|
|
34538
35073
|
import { platform as platform2, arch as arch2, release, homedir as homedir29, hostname as hostname2 } from "node:os";
|
|
34539
35074
|
import { createHmac as createHmac2 } from "node:crypto";
|
|
@@ -34594,7 +35129,7 @@ function checkHooks() {
|
|
|
34594
35129
|
}
|
|
34595
35130
|
let config;
|
|
34596
35131
|
try {
|
|
34597
|
-
config = JSON.parse(
|
|
35132
|
+
config = JSON.parse(readFileSync30(hooksConfigPath, "utf8"));
|
|
34598
35133
|
} catch {
|
|
34599
35134
|
return { configured: false, registered: false, policyCount: 0 };
|
|
34600
35135
|
}
|
|
@@ -34607,7 +35142,7 @@ function checkHooks() {
|
|
|
34607
35142
|
return { configured: true, registered: false, policyCount };
|
|
34608
35143
|
let settings;
|
|
34609
35144
|
try {
|
|
34610
|
-
settings = JSON.parse(
|
|
35145
|
+
settings = JSON.parse(readFileSync30(settingsPath, "utf8"));
|
|
34611
35146
|
} catch {
|
|
34612
35147
|
return { configured: true, registered: false, policyCount };
|
|
34613
35148
|
}
|
|
@@ -34632,7 +35167,7 @@ async function maybeReportInstall(version) {
|
|
|
34632
35167
|
let previousVersion = null;
|
|
34633
35168
|
try {
|
|
34634
35169
|
if (existsSync34(versionFile)) {
|
|
34635
|
-
previousVersion =
|
|
35170
|
+
previousVersion = readFileSync30(versionFile, "utf8").trim() || null;
|
|
34636
35171
|
}
|
|
34637
35172
|
} catch {}
|
|
34638
35173
|
if (previousVersion === version)
|
|
@@ -34705,6 +35240,196 @@ var init_first_run_gate = __esm(() => {
|
|
|
34705
35240
|
];
|
|
34706
35241
|
});
|
|
34707
35242
|
|
|
35243
|
+
// src/hooks/cloud-login.ts
|
|
35244
|
+
async function postJson2(origin, path, body, fetchImpl) {
|
|
35245
|
+
const controller = new AbortController;
|
|
35246
|
+
const timer = setTimeout(() => controller.abort(), TIMEOUT_MS);
|
|
35247
|
+
try {
|
|
35248
|
+
const res = await fetchImpl(`${origin.replace(/\/+$/, "")}${path}`, {
|
|
35249
|
+
method: "POST",
|
|
35250
|
+
headers: { "Content-Type": "application/json" },
|
|
35251
|
+
body: JSON.stringify(body),
|
|
35252
|
+
redirect: "manual",
|
|
35253
|
+
signal: controller.signal
|
|
35254
|
+
});
|
|
35255
|
+
let json = null;
|
|
35256
|
+
try {
|
|
35257
|
+
const parsed = await res.json();
|
|
35258
|
+
json = parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
35259
|
+
} catch {
|
|
35260
|
+
json = null;
|
|
35261
|
+
}
|
|
35262
|
+
return { status: res.status, json };
|
|
35263
|
+
} catch (err) {
|
|
35264
|
+
return { error: err instanceof Error ? err.name === "AbortError" ? "timed out" : err.message : String(err) };
|
|
35265
|
+
} finally {
|
|
35266
|
+
clearTimeout(timer);
|
|
35267
|
+
}
|
|
35268
|
+
}
|
|
35269
|
+
function displayText(v, max = 200) {
|
|
35270
|
+
if (typeof v !== "string")
|
|
35271
|
+
return;
|
|
35272
|
+
const t = v.replace(INVISIBLE, "").trim().slice(0, max);
|
|
35273
|
+
return t.length > 0 ? t : undefined;
|
|
35274
|
+
}
|
|
35275
|
+
function org(v) {
|
|
35276
|
+
const o = v && typeof v === "object" ? v : {};
|
|
35277
|
+
return { id: str3(o.id), slug: displayText(o.slug), name: displayText(o.name) };
|
|
35278
|
+
}
|
|
35279
|
+
function permissions(v) {
|
|
35280
|
+
return Array.isArray(v) ? v.map((p) => displayText(p, 64)).filter((p) => p !== undefined) : [];
|
|
35281
|
+
}
|
|
35282
|
+
function isOpenableUrl(raw) {
|
|
35283
|
+
try {
|
|
35284
|
+
const u = new URL(raw);
|
|
35285
|
+
return u.protocol === "https:" || u.protocol === "http:";
|
|
35286
|
+
} catch {
|
|
35287
|
+
return false;
|
|
35288
|
+
}
|
|
35289
|
+
}
|
|
35290
|
+
function machineOs(platform = process.platform) {
|
|
35291
|
+
return platform === "darwin" ? "macOS" : platform === "win32" ? "windows" : platform;
|
|
35292
|
+
}
|
|
35293
|
+
async function startLogin(origin, machine, fetchImpl = fetch) {
|
|
35294
|
+
const r = await postJson2(origin, LOGIN_START_PATH, { machine_label: machine.label, machine_os: machine.os, cli_version: machine.cliVersion }, fetchImpl);
|
|
35295
|
+
if ("error" in r)
|
|
35296
|
+
return { kind: "unreachable", reason: r.error };
|
|
35297
|
+
if (r.status === 404 || r.status >= 300 && r.status < 400 || r.status === 200 && !r.json) {
|
|
35298
|
+
return { kind: "unsupported" };
|
|
35299
|
+
}
|
|
35300
|
+
if (r.status === 429)
|
|
35301
|
+
return { kind: "refused", reason: "too many login attempts from here — wait a minute" };
|
|
35302
|
+
if (r.status !== 201 || !r.json) {
|
|
35303
|
+
return r.status >= 500 ? { kind: "unreachable", reason: `the server answered ${r.status}` } : { kind: "refused", reason: displayText(r.json?.error, 120) ?? `the server answered ${r.status}` };
|
|
35304
|
+
}
|
|
35305
|
+
const verificationUrl = str3(r.json.verification_url);
|
|
35306
|
+
const pollSecret = str3(r.json.poll_secret);
|
|
35307
|
+
if (!verificationUrl || !pollSecret || !isOpenableUrl(verificationUrl)) {
|
|
35308
|
+
return { kind: "unsupported" };
|
|
35309
|
+
}
|
|
35310
|
+
return {
|
|
35311
|
+
kind: "ok",
|
|
35312
|
+
verificationUrl: new URL(verificationUrl).href,
|
|
35313
|
+
pollSecret,
|
|
35314
|
+
expiresIn: within(r.json.expires_in, 30, 3600, 600),
|
|
35315
|
+
interval: within(r.json.interval, 1, 30, 2)
|
|
35316
|
+
};
|
|
35317
|
+
}
|
|
35318
|
+
async function pollLogin(origin, pollSecret, fetchImpl = fetch) {
|
|
35319
|
+
const r = await postJson2(origin, LOGIN_POLL_PATH, { poll_secret: pollSecret }, fetchImpl);
|
|
35320
|
+
if ("error" in r)
|
|
35321
|
+
return { kind: "unreachable", reason: r.error };
|
|
35322
|
+
if (r.status === 404)
|
|
35323
|
+
return { kind: "unknown" };
|
|
35324
|
+
if (r.status !== 200 || !r.json)
|
|
35325
|
+
return { kind: "unreachable", reason: `the server answered ${r.status}` };
|
|
35326
|
+
const j = r.json;
|
|
35327
|
+
switch (j.status) {
|
|
35328
|
+
case "pending":
|
|
35329
|
+
return { kind: "pending", interval: typeof j.interval === "number" ? within(j.interval, 1, 30, 2) : undefined };
|
|
35330
|
+
case "slow_down":
|
|
35331
|
+
return { kind: "slow_down" };
|
|
35332
|
+
case "approved":
|
|
35333
|
+
return {
|
|
35334
|
+
kind: "approved",
|
|
35335
|
+
org: org(j.org),
|
|
35336
|
+
approvedBy: displayText(j.approved_by),
|
|
35337
|
+
keyName: displayText(j.key_name),
|
|
35338
|
+
permissions: permissions(j.permissions)
|
|
35339
|
+
};
|
|
35340
|
+
case "denied":
|
|
35341
|
+
return { kind: "denied" };
|
|
35342
|
+
case "expired":
|
|
35343
|
+
return { kind: "expired" };
|
|
35344
|
+
case "claimed":
|
|
35345
|
+
return { kind: "claimed" };
|
|
35346
|
+
default:
|
|
35347
|
+
return { kind: "unknown" };
|
|
35348
|
+
}
|
|
35349
|
+
}
|
|
35350
|
+
async function claimLogin(origin, pollSecret, fetchImpl = fetch) {
|
|
35351
|
+
const r = await postJson2(origin, LOGIN_CLAIM_PATH, { poll_secret: pollSecret }, fetchImpl);
|
|
35352
|
+
if ("error" in r)
|
|
35353
|
+
return { kind: "unreachable", reason: r.error };
|
|
35354
|
+
const j = r.json ?? {};
|
|
35355
|
+
if (r.status === 201) {
|
|
35356
|
+
const key = str3(j.api_key);
|
|
35357
|
+
if (!key)
|
|
35358
|
+
return { kind: "refused", reason: "the server answered without a key" };
|
|
35359
|
+
return {
|
|
35360
|
+
kind: "ok",
|
|
35361
|
+
key,
|
|
35362
|
+
keyId: str3(j.key_id),
|
|
35363
|
+
keyName: displayText(j.key_name),
|
|
35364
|
+
org: org(j.org),
|
|
35365
|
+
permissions: permissions(j.permissions),
|
|
35366
|
+
approvedBy: displayText(j.approved_by)
|
|
35367
|
+
};
|
|
35368
|
+
}
|
|
35369
|
+
if (r.status === 410)
|
|
35370
|
+
return { kind: "expired" };
|
|
35371
|
+
if (r.status === 403 && j.error === "approval_revoked")
|
|
35372
|
+
return { kind: "revoked" };
|
|
35373
|
+
if (r.status >= 500)
|
|
35374
|
+
return { kind: "unreachable", reason: `the server answered ${r.status}` };
|
|
35375
|
+
return {
|
|
35376
|
+
kind: "refused",
|
|
35377
|
+
reason: displayText(j.status, 40) ? `the login request is ${displayText(j.status, 40)}` : `the server answered ${r.status}`
|
|
35378
|
+
};
|
|
35379
|
+
}
|
|
35380
|
+
var LOGIN_START_PATH = "/api/auth/cli/start", LOGIN_POLL_PATH = "/api/auth/cli/poll", LOGIN_CLAIM_PATH = "/api/auth/cli/claim", TIMEOUT_MS = 1e4, str3 = (v) => typeof v === "string" && v.length > 0 ? v : undefined, INVISIBLE, within = (v, lo, hi, fallback) => typeof v === "number" && Number.isFinite(v) && v > 0 ? Math.min(hi, Math.max(lo, v)) : fallback;
|
|
35381
|
+
var init_cloud_login = __esm(() => {
|
|
35382
|
+
INVISIBLE = /[\u0000-\u001f\u007f-\u009f\u061c\u180e\u200b-\u200f\u202a-\u202e\u2060-\u2069\ufeff]/g;
|
|
35383
|
+
});
|
|
35384
|
+
|
|
35385
|
+
// src/audit/open-browser.ts
|
|
35386
|
+
import { spawn } from "node:child_process";
|
|
35387
|
+
function canOpenBrowser(env = process.env, platform = process.platform) {
|
|
35388
|
+
if (env.SSH_CONNECTION || env.SSH_CLIENT || env.SSH_TTY)
|
|
35389
|
+
return false;
|
|
35390
|
+
if (platform === "linux" && !env.DISPLAY && !env.WAYLAND_DISPLAY)
|
|
35391
|
+
return false;
|
|
35392
|
+
return true;
|
|
35393
|
+
}
|
|
35394
|
+
function openUrl(url, platform = process.platform) {
|
|
35395
|
+
let cmd;
|
|
35396
|
+
let args;
|
|
35397
|
+
if (platform === "darwin") {
|
|
35398
|
+
cmd = "open";
|
|
35399
|
+
args = [url];
|
|
35400
|
+
} else if (platform === "win32") {
|
|
35401
|
+
cmd = "rundll32.exe";
|
|
35402
|
+
args = ["url.dll,FileProtocolHandler", url];
|
|
35403
|
+
} else {
|
|
35404
|
+
cmd = "xdg-open";
|
|
35405
|
+
args = [url];
|
|
35406
|
+
}
|
|
35407
|
+
try {
|
|
35408
|
+
const child = spawn(cmd, args, { stdio: "ignore", detached: true });
|
|
35409
|
+
child.on("error", () => {});
|
|
35410
|
+
child.unref();
|
|
35411
|
+
} catch {}
|
|
35412
|
+
}
|
|
35413
|
+
function openWhenReady(port, path) {
|
|
35414
|
+
const base = `http://localhost:${port}`;
|
|
35415
|
+
const target = `${base}${path}`;
|
|
35416
|
+
(async () => {
|
|
35417
|
+
const deadline = Date.now() + POLL_TIMEOUT_MS;
|
|
35418
|
+
while (Date.now() < deadline) {
|
|
35419
|
+
try {
|
|
35420
|
+
await fetch(base, { method: "GET", redirect: "manual" });
|
|
35421
|
+
openUrl(target);
|
|
35422
|
+
return;
|
|
35423
|
+
} catch {
|
|
35424
|
+
await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));
|
|
35425
|
+
}
|
|
35426
|
+
}
|
|
35427
|
+
openUrl(target);
|
|
35428
|
+
})();
|
|
35429
|
+
}
|
|
35430
|
+
var POLL_INTERVAL_MS = 150, POLL_TIMEOUT_MS = 30000;
|
|
35431
|
+
var init_open_browser = () => {};
|
|
35432
|
+
|
|
34708
35433
|
// src/cli-error.ts
|
|
34709
35434
|
var CliError;
|
|
34710
35435
|
var init_cli_error = __esm(() => {
|
|
@@ -34719,7 +35444,7 @@ var init_cli_error = __esm(() => {
|
|
|
34719
35444
|
});
|
|
34720
35445
|
|
|
34721
35446
|
// src/hooks/backfill-request.ts
|
|
34722
|
-
import { existsSync as existsSync35, readFileSync as
|
|
35447
|
+
import { existsSync as existsSync35, readFileSync as readFileSync31 } from "node:fs";
|
|
34723
35448
|
import { join as join36 } from "node:path";
|
|
34724
35449
|
function backfillRequestPath(home) {
|
|
34725
35450
|
return join36(failproofaiHome(home), "state", "backfill-request.json");
|
|
@@ -34771,7 +35496,7 @@ function writeBackfillRequest(next, home) {
|
|
|
34771
35496
|
let pending = null;
|
|
34772
35497
|
if (existsSync35(path)) {
|
|
34773
35498
|
try {
|
|
34774
|
-
pending = readPendingRequest(JSON.parse(
|
|
35499
|
+
pending = readPendingRequest(JSON.parse(readFileSync31(path, "utf8")), next.requestedAtMs);
|
|
34775
35500
|
} catch {
|
|
34776
35501
|
pending = null;
|
|
34777
35502
|
}
|
|
@@ -35033,6 +35758,34 @@ function integrationsInstalledAt(scope, cwd) {
|
|
|
35033
35758
|
}
|
|
35034
35759
|
});
|
|
35035
35760
|
}
|
|
35761
|
+
function cloudPolicyStatus() {
|
|
35762
|
+
let count = 0;
|
|
35763
|
+
let observing = false;
|
|
35764
|
+
const jsIds = new Set;
|
|
35765
|
+
try {
|
|
35766
|
+
for (const artifact of listActiveCloudManagedPolicies()) {
|
|
35767
|
+
jsIds.add(artifact.id);
|
|
35768
|
+
if (artifact.effect === "observe")
|
|
35769
|
+
observing = true;
|
|
35770
|
+
else
|
|
35771
|
+
count++;
|
|
35772
|
+
}
|
|
35773
|
+
} catch {}
|
|
35774
|
+
try {
|
|
35775
|
+
const { jevMode } = readCloudJevState();
|
|
35776
|
+
if (jevMode === "enforce" || jevMode === "observe") {
|
|
35777
|
+
for (const assignment of readCloudJevAssignments() ?? []) {
|
|
35778
|
+
if (jsIds.has(assignment.id))
|
|
35779
|
+
continue;
|
|
35780
|
+
if (jevMode === "observe" || assignment.effect === "observe")
|
|
35781
|
+
observing = true;
|
|
35782
|
+
else
|
|
35783
|
+
count++;
|
|
35784
|
+
}
|
|
35785
|
+
}
|
|
35786
|
+
} catch {}
|
|
35787
|
+
return { count, observing };
|
|
35788
|
+
}
|
|
35036
35789
|
function notEnforcingReason(cwd) {
|
|
35037
35790
|
const wired = deduplicateScopes(HOOK_SCOPES, cwd).some((scope) => hooksInstalledInSettings(scope, cwd));
|
|
35038
35791
|
if (!wired)
|
|
@@ -35055,14 +35808,10 @@ function notEnforcingReason(cwd) {
|
|
|
35055
35808
|
return null;
|
|
35056
35809
|
}
|
|
35057
35810
|
} catch {}
|
|
35058
|
-
|
|
35059
|
-
|
|
35060
|
-
|
|
35061
|
-
|
|
35062
|
-
else
|
|
35063
|
-
return null;
|
|
35064
|
-
}
|
|
35065
|
-
} catch {}
|
|
35811
|
+
const cloud = cloudPolicyStatus();
|
|
35812
|
+
if (cloud.count > 0)
|
|
35813
|
+
return null;
|
|
35814
|
+
observing ||= cloud.observing;
|
|
35066
35815
|
if (configuredCustomPolicyPaths(config).length > 0)
|
|
35067
35816
|
return null;
|
|
35068
35817
|
const projectDir = resolve30(findProjectConfigDir(cwd ?? process.cwd()), ".failproofai", "policies");
|
|
@@ -35085,12 +35834,7 @@ function enforcingPolicyCount(cwd) {
|
|
|
35085
35834
|
count += taken.filter((name) => !disabled.has(`pack:${pack.id}@${pack.version}:${name}`)).length;
|
|
35086
35835
|
}
|
|
35087
35836
|
} catch {}
|
|
35088
|
-
|
|
35089
|
-
for (const artifact of listActiveCloudManagedPolicies()) {
|
|
35090
|
-
if (artifact.effect !== "observe")
|
|
35091
|
-
count++;
|
|
35092
|
-
}
|
|
35093
|
-
} catch {}
|
|
35837
|
+
count += cloudPolicyStatus().count;
|
|
35094
35838
|
if (!hasInstalledRegexPacks())
|
|
35095
35839
|
count += config.enabledPolicies.length;
|
|
35096
35840
|
const projectDir = resolve30(findProjectConfigDir(cwd ?? process.cwd()), ".failproofai", "policies");
|
|
@@ -35569,6 +36313,136 @@ var init_manager = __esm(() => {
|
|
|
35569
36313
|
VALID_POLICY_NAMES = new Set(BUILTIN_POLICIES.map((p) => p.name));
|
|
35570
36314
|
});
|
|
35571
36315
|
|
|
36316
|
+
// src/hooks/agent-skill.ts
|
|
36317
|
+
import { existsSync as existsSync38, mkdirSync as mkdirSync21, rmdirSync as rmdirSync2, rmSync as rmSync13 } from "node:fs";
|
|
36318
|
+
import { homedir as homedir30 } from "node:os";
|
|
36319
|
+
import { join as join37, resolve as resolve31 } from "node:path";
|
|
36320
|
+
function envDir(name, fallback) {
|
|
36321
|
+
const value = (process.env[name] ?? "").trim();
|
|
36322
|
+
return value ? resolve31(value) : fallback;
|
|
36323
|
+
}
|
|
36324
|
+
function agentSkillRoots(id) {
|
|
36325
|
+
const home = homedir30();
|
|
36326
|
+
const config = envDir("XDG_CONFIG_HOME", join37(home, ".config"));
|
|
36327
|
+
switch (id) {
|
|
36328
|
+
case "claude":
|
|
36329
|
+
return [join37(envDir("CLAUDE_CONFIG_DIR", join37(home, ".claude")), "skills")];
|
|
36330
|
+
case "codex":
|
|
36331
|
+
return [join37(envDir("CODEX_HOME", join37(home, ".codex")), "skills")];
|
|
36332
|
+
case "copilot":
|
|
36333
|
+
return [join37(envDir("COPILOT_HOME", join37(home, ".copilot")), "skills")];
|
|
36334
|
+
case "cursor":
|
|
36335
|
+
return [join37(home, ".cursor", "skills")];
|
|
36336
|
+
case "opencode":
|
|
36337
|
+
return [join37(config, "opencode", "skills")];
|
|
36338
|
+
case "pi":
|
|
36339
|
+
return [join37(envDir("PI_CODING_AGENT_DIR", join37(home, ".pi", "agent")), "skills")];
|
|
36340
|
+
case "hermes":
|
|
36341
|
+
return listHermesProfiles().map((p) => join37(p.home, "skills"));
|
|
36342
|
+
case "openclaw":
|
|
36343
|
+
return listOpenClawProfiles().map((p) => join37(p.home, "skills"));
|
|
36344
|
+
case "factory":
|
|
36345
|
+
return [join37(envDir("FACTORY_HOME_OVERRIDE", home), ".factory", "skills")];
|
|
36346
|
+
case "devin":
|
|
36347
|
+
return [join37(config, "devin", "skills")];
|
|
36348
|
+
case "antigravity":
|
|
36349
|
+
return [join37(home, ".gemini", "config", "skills")];
|
|
36350
|
+
case "goose": {
|
|
36351
|
+
const root = (process.env.GOOSE_PATH_ROOT ?? "").trim();
|
|
36352
|
+
return [root ? join37(resolve31(root), "config", "skills") : join37(config, "goose", "skills")];
|
|
36353
|
+
}
|
|
36354
|
+
}
|
|
36355
|
+
}
|
|
36356
|
+
function listedTwice(id) {
|
|
36357
|
+
return id === "codex" && existsSync38(join37(homedir30(), ".agents", "skills", AGENT_SKILL_NAME, "SKILL.md"));
|
|
36358
|
+
}
|
|
36359
|
+
function installAgentSkill(ids) {
|
|
36360
|
+
const installed = [];
|
|
36361
|
+
for (const id of ids) {
|
|
36362
|
+
let wrote = false;
|
|
36363
|
+
const covered = listedTwice(id);
|
|
36364
|
+
for (const root of agentSkillRoots(id)) {
|
|
36365
|
+
const dir = join37(root, AGENT_SKILL_NAME);
|
|
36366
|
+
const ours = existsSync38(join37(dir, AGENT_SKILL_MARKER));
|
|
36367
|
+
if (covered) {
|
|
36368
|
+
if (ours)
|
|
36369
|
+
removeSkillDir(dir);
|
|
36370
|
+
continue;
|
|
36371
|
+
}
|
|
36372
|
+
if (existsSync38(dir) && !ours)
|
|
36373
|
+
continue;
|
|
36374
|
+
let created = false;
|
|
36375
|
+
let marked = false;
|
|
36376
|
+
try {
|
|
36377
|
+
mkdirSync21(root, { recursive: true });
|
|
36378
|
+
if (!existsSync38(dir)) {
|
|
36379
|
+
mkdirSync21(dir);
|
|
36380
|
+
created = true;
|
|
36381
|
+
}
|
|
36382
|
+
writeConfigFileAtomic(join37(dir, AGENT_SKILL_MARKER), "", { backup: false, symlinks: "replace" });
|
|
36383
|
+
marked = true;
|
|
36384
|
+
writeConfigFileAtomic(join37(dir, "SKILL.md"), AGENT_SKILL_MD, { backup: false, symlinks: "replace" });
|
|
36385
|
+
wrote = true;
|
|
36386
|
+
} catch (err) {
|
|
36387
|
+
if (created && !marked) {
|
|
36388
|
+
try {
|
|
36389
|
+
rmdirSync2(dir);
|
|
36390
|
+
} catch {}
|
|
36391
|
+
}
|
|
36392
|
+
hookLogWarn(`the failproofai skill was not written to ${dir}: ${err instanceof Error ? err.message : String(err)}`);
|
|
36393
|
+
}
|
|
36394
|
+
}
|
|
36395
|
+
if (wrote)
|
|
36396
|
+
installed.push(id);
|
|
36397
|
+
}
|
|
36398
|
+
return installed;
|
|
36399
|
+
}
|
|
36400
|
+
function installedAgentSkillDirs() {
|
|
36401
|
+
const dirs = INTEGRATION_TYPES.flatMap((id) => agentSkillRoots(id).map((root) => join37(root, AGENT_SKILL_NAME)));
|
|
36402
|
+
return [...new Set(dirs)].filter((dir) => existsSync38(join37(dir, AGENT_SKILL_MARKER)));
|
|
36403
|
+
}
|
|
36404
|
+
function removeSkillDir(dir) {
|
|
36405
|
+
try {
|
|
36406
|
+
rmSync13(dir, { recursive: true, force: true });
|
|
36407
|
+
return true;
|
|
36408
|
+
} catch (err) {
|
|
36409
|
+
hookLogWarn(`the failproofai skill was not removed from ${dir}: ${err instanceof Error ? err.message : String(err)}`);
|
|
36410
|
+
return false;
|
|
36411
|
+
}
|
|
36412
|
+
}
|
|
36413
|
+
function removeAgentSkill() {
|
|
36414
|
+
return installedAgentSkillDirs().filter(removeSkillDir);
|
|
36415
|
+
}
|
|
36416
|
+
var AGENT_SKILL_NAME = "failproofai", AGENT_SKILL_MARKER = ".failproofai-managed", SKILLS_RAW = "https://raw.githubusercontent.com/FailproofAI/skills/main/skills", AGENT_SKILL_MD;
|
|
36417
|
+
var init_agent_skill = __esm(() => {
|
|
36418
|
+
init_hermes_profiles();
|
|
36419
|
+
init_openclaw_profiles();
|
|
36420
|
+
init_hook_logger();
|
|
36421
|
+
init_safe_config_write();
|
|
36422
|
+
init_types();
|
|
36423
|
+
AGENT_SKILL_MD = `---
|
|
36424
|
+
name: ${AGENT_SKILL_NAME}
|
|
36425
|
+
description: FailproofAI hooks, policies, daemon, Cloud, the fp CLI and the SDK. Use for any question about setting up, running or fixing FailproofAI.
|
|
36426
|
+
---
|
|
36427
|
+
|
|
36428
|
+
# FailproofAI
|
|
36429
|
+
|
|
36430
|
+
This skill is a pointer. Before acting on anything FailproofAI, read the full skill, which is kept current online (use your web fetch tool, or \`curl -fsSL <url>\`):
|
|
36431
|
+
|
|
36432
|
+
${SKILLS_RAW}/${AGENT_SKILL_NAME}/SKILL.md
|
|
36433
|
+
|
|
36434
|
+
Files it names by a relative path, such as \`references/cli.md\`, are in that same folder: ${SKILLS_RAW}/${AGENT_SKILL_NAME}/<path>
|
|
36435
|
+
|
|
36436
|
+
For focused work, read the matching skill too. Each has the same layout, with its own \`references/\` beside it.
|
|
36437
|
+
|
|
36438
|
+
- Writing or testing a policy: ${SKILLS_RAW}/failproofai-policy-author/SKILL.md
|
|
36439
|
+
- Publishing a policy pack: ${SKILLS_RAW}/failproofai-policy-publish/SKILL.md
|
|
36440
|
+
- FailproofAI Cloud and the \`fp\` CLI: ${SKILLS_RAW}/fp-cloud-cli/SKILL.md
|
|
36441
|
+
- Adding the SDK to an agent, or running an evaluator: ${SKILLS_RAW}/failproofai-sdk/SKILL.md
|
|
36442
|
+
- Planning evaluations: ${SKILLS_RAW}/failproofai-eval-brainstorm/SKILL.md
|
|
36443
|
+
`;
|
|
36444
|
+
});
|
|
36445
|
+
|
|
35572
36446
|
// lib/fetch-with-timeout.ts
|
|
35573
36447
|
function fetchWithTimeout(input, init = {}, timeoutMs = DEFAULT_FETCH_TIMEOUT_MS) {
|
|
35574
36448
|
const timeoutSignal = AbortSignal.timeout(timeoutMs);
|
|
@@ -35585,7 +36459,7 @@ var DEFAULT_FETCH_TIMEOUT_MS = 15000;
|
|
|
35585
36459
|
|
|
35586
36460
|
// src/hooks/cloud-enrollment.ts
|
|
35587
36461
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
35588
|
-
import { existsSync as
|
|
36462
|
+
import { existsSync as existsSync39, readFileSync as readFileSync32, rmSync as rmSync14 } from "node:fs";
|
|
35589
36463
|
import { hostname as hostname4 } from "node:os";
|
|
35590
36464
|
function cloudCredentialPath() {
|
|
35591
36465
|
return process.env.FAILPROOFAI_CLOUD_CREDENTIALS ?? credentialsFile();
|
|
@@ -35624,10 +36498,10 @@ function readCloudCredentials() {
|
|
|
35624
36498
|
if (!usingJsonOverride())
|
|
35625
36499
|
return readCredentials().cloud ?? null;
|
|
35626
36500
|
const path = cloudCredentialPath();
|
|
35627
|
-
if (!
|
|
36501
|
+
if (!existsSync39(path))
|
|
35628
36502
|
return null;
|
|
35629
36503
|
try {
|
|
35630
|
-
const raw = JSON.parse(
|
|
36504
|
+
const raw = JSON.parse(readFileSync32(path, "utf8"));
|
|
35631
36505
|
if (raw.schemaVersion !== SCHEMA_VERSION2)
|
|
35632
36506
|
return null;
|
|
35633
36507
|
if (typeof raw.url !== "string" || typeof raw.machineId !== "string" || typeof raw.token !== "string") {
|
|
@@ -35666,10 +36540,10 @@ function resolveMachineLabel(explicit) {
|
|
|
35666
36540
|
function clearCloudCredentials() {
|
|
35667
36541
|
if (usingJsonOverride()) {
|
|
35668
36542
|
const path = cloudCredentialPath();
|
|
35669
|
-
if (!
|
|
36543
|
+
if (!existsSync39(path))
|
|
35670
36544
|
return false;
|
|
35671
36545
|
try {
|
|
35672
|
-
|
|
36546
|
+
rmSync14(path);
|
|
35673
36547
|
return true;
|
|
35674
36548
|
} catch {
|
|
35675
36549
|
return false;
|
|
@@ -35771,8 +36645,8 @@ async function introspectKey(origin, token, fetchImpl = fetch, timeoutMs = 1e4)
|
|
|
35771
36645
|
identity: {
|
|
35772
36646
|
keyId: typeof b.key_id === "string" ? b.key_id : undefined,
|
|
35773
36647
|
orgId: typeof b.org_id === "string" ? b.org_id : undefined,
|
|
35774
|
-
orgSlug:
|
|
35775
|
-
orgName:
|
|
36648
|
+
orgSlug: displayText(b.org_slug),
|
|
36649
|
+
orgName: displayText(b.org_name),
|
|
35776
36650
|
permissions: b.permissions.filter((p) => typeof p === "string"),
|
|
35777
36651
|
expiresAt: typeof b.expires_at === "string" ? b.expires_at : null,
|
|
35778
36652
|
otelIngest: typeof b.otel_ingest === "boolean" ? b.otel_ingest : undefined
|
|
@@ -35788,30 +36662,33 @@ function describeOrg(identity) {
|
|
|
35788
36662
|
return identity.orgName ?? identity.orgSlug ?? identity.orgId ?? "an unknown organisation";
|
|
35789
36663
|
}
|
|
35790
36664
|
var INTROSPECT_PATH = "/v1/auth/introspect", PERMISSION_EVENTS = "events:add", PERMISSION_POLICIES = "policies:pull", PERMISSION_JEV = "jev:evaluate";
|
|
36665
|
+
var init_cloud_introspect = __esm(() => {
|
|
36666
|
+
init_cloud_login();
|
|
36667
|
+
});
|
|
35791
36668
|
|
|
35792
36669
|
// src/hooks/credential-recovery.ts
|
|
35793
36670
|
import { createHash as createHash11 } from "node:crypto";
|
|
35794
|
-
import { existsSync as
|
|
35795
|
-
import { join as
|
|
36671
|
+
import { existsSync as existsSync40, mkdirSync as mkdirSync22, readdirSync as readdirSync19, renameSync as renameSync13 } from "node:fs";
|
|
36672
|
+
import { join as join38 } from "node:path";
|
|
35796
36673
|
function previousOrgDirectory(id) {
|
|
35797
36674
|
const safe = id && /^[A-Za-z0-9_-]{1,128}$/.test(id) ? id : id ? createHash11("sha256").update(id).digest("hex") : "unknown";
|
|
35798
|
-
return
|
|
36675
|
+
return join38(stateDir(), "previous-org", safe);
|
|
35799
36676
|
}
|
|
35800
36677
|
function recoverCredentialRefusals(sameOrg, oldOrgId) {
|
|
35801
36678
|
const dir = failedDir();
|
|
35802
|
-
if (!
|
|
36679
|
+
if (!existsSync40(dir))
|
|
35803
36680
|
return 0;
|
|
35804
36681
|
let recovered = 0;
|
|
35805
36682
|
for (const name of readdirSync19(dir)) {
|
|
35806
36683
|
if (!/\.c(401|403)\.jsonl$/.test(name) || name.startsWith("."))
|
|
35807
36684
|
continue;
|
|
35808
|
-
const targetDir = sameOrg ? dir :
|
|
35809
|
-
|
|
36685
|
+
const targetDir = sameOrg ? dir : join38(previousOrgDirectory(oldOrgId), "failed");
|
|
36686
|
+
mkdirSync22(targetDir, { recursive: true, mode: 448 });
|
|
35810
36687
|
const targetName = sameOrg ? name.replace(/\.c(401|403)(?=\.jsonl$)/, "") : name;
|
|
35811
|
-
const target =
|
|
35812
|
-
if (
|
|
36688
|
+
const target = join38(targetDir, targetName);
|
|
36689
|
+
if (existsSync40(target))
|
|
35813
36690
|
continue;
|
|
35814
|
-
renameSync13(
|
|
36691
|
+
renameSync13(join38(dir, name), target);
|
|
35815
36692
|
recovered++;
|
|
35816
36693
|
}
|
|
35817
36694
|
if (sameOrg && recovered > 0)
|
|
@@ -35829,16 +36706,16 @@ import {
|
|
|
35829
36706
|
chmodSync as chmodSync9,
|
|
35830
36707
|
closeSync as closeSync5,
|
|
35831
36708
|
constants as fsConstants5,
|
|
35832
|
-
existsSync as
|
|
36709
|
+
existsSync as existsSync41,
|
|
35833
36710
|
fstatSync as fstatSync3,
|
|
35834
36711
|
linkSync,
|
|
35835
36712
|
lstatSync as lstatSync5,
|
|
35836
|
-
mkdirSync as
|
|
36713
|
+
mkdirSync as mkdirSync23,
|
|
35837
36714
|
openSync as openSync5,
|
|
35838
|
-
readFileSync as
|
|
36715
|
+
readFileSync as readFileSync33,
|
|
35839
36716
|
readSync as readSync4,
|
|
35840
36717
|
renameSync as renameSync14,
|
|
35841
|
-
rmSync as
|
|
36718
|
+
rmSync as rmSync15,
|
|
35842
36719
|
statSync as statSync29,
|
|
35843
36720
|
unlinkSync as unlinkSync6,
|
|
35844
36721
|
writeFileSync as writeFileSync18
|
|
@@ -35876,7 +36753,7 @@ function repointCloudJevConfig(cloudBase, found) {
|
|
|
35876
36753
|
}
|
|
35877
36754
|
let raw = null;
|
|
35878
36755
|
try {
|
|
35879
|
-
const parsed = JSON.parse(
|
|
36756
|
+
const parsed = JSON.parse(readFileSync33(aside, "utf8"));
|
|
35880
36757
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed))
|
|
35881
36758
|
raw = parsed;
|
|
35882
36759
|
} catch {
|
|
@@ -35898,7 +36775,7 @@ function repointCloudJevConfig(cloudBase, found) {
|
|
|
35898
36775
|
return found;
|
|
35899
36776
|
} finally {
|
|
35900
36777
|
try {
|
|
35901
|
-
|
|
36778
|
+
rmSync15(tmp, { force: true });
|
|
35902
36779
|
} catch {}
|
|
35903
36780
|
}
|
|
35904
36781
|
try {
|
|
@@ -35920,15 +36797,15 @@ function writeCloudJevConfigIfAbsent(cloudBase) {
|
|
|
35920
36797
|
} catch {
|
|
35921
36798
|
return { status: "error", path, problem: "the FailproofAI Cloud URL is not a URL" };
|
|
35922
36799
|
}
|
|
35923
|
-
if (
|
|
36800
|
+
if (existsSync41(path))
|
|
35924
36801
|
return kept(path, cloudBase);
|
|
35925
36802
|
const body = `${JSON.stringify({ provider: JEV_CLOUD_PROVIDER, baseUrl, mode: CLOUD_JEV_INITIAL_MODE }, null, 2)}
|
|
35926
36803
|
`;
|
|
35927
36804
|
const dir = dirname22(path);
|
|
35928
36805
|
const tmp = `${path}.${process.pid}.${randomBytes3(6).toString("hex")}.tmp`;
|
|
35929
36806
|
try {
|
|
35930
|
-
if (!
|
|
35931
|
-
|
|
36807
|
+
if (!existsSync41(dir))
|
|
36808
|
+
mkdirSync23(dir, { recursive: true, mode: 448 });
|
|
35932
36809
|
writeFileSync18(tmp, body, { mode: 384, flag: "wx" });
|
|
35933
36810
|
chmodSync9(tmp, 384);
|
|
35934
36811
|
try {
|
|
@@ -35942,7 +36819,7 @@ function writeCloudJevConfigIfAbsent(cloudBase) {
|
|
|
35942
36819
|
return { status: "error", path, problem: `could not write ${path} (${err.code ?? "error"})` };
|
|
35943
36820
|
} finally {
|
|
35944
36821
|
try {
|
|
35945
|
-
|
|
36822
|
+
rmSync15(tmp, { force: true });
|
|
35946
36823
|
} catch {}
|
|
35947
36824
|
}
|
|
35948
36825
|
tightenDir(dir);
|
|
@@ -35950,7 +36827,7 @@ function writeCloudJevConfigIfAbsent(cloudBase) {
|
|
|
35950
36827
|
}
|
|
35951
36828
|
function existingJevConfig(cloudBase) {
|
|
35952
36829
|
const path = jevConfigPath();
|
|
35953
|
-
return
|
|
36830
|
+
return existsSync41(path) ? kept(path, cloudBase) : null;
|
|
35954
36831
|
}
|
|
35955
36832
|
function cloudJevRunningMode() {
|
|
35956
36833
|
try {
|
|
@@ -36049,7 +36926,7 @@ function putBack(aside, path, mode) {
|
|
|
36049
36926
|
}
|
|
36050
36927
|
let created = false;
|
|
36051
36928
|
try {
|
|
36052
|
-
const bytes =
|
|
36929
|
+
const bytes = readFileSync33(aside);
|
|
36053
36930
|
const fd = openSync5(path, "wx", mode);
|
|
36054
36931
|
created = true;
|
|
36055
36932
|
try {
|
|
@@ -36122,7 +36999,7 @@ var init_jev_cloud_connection = __esm(() => {
|
|
|
36122
36999
|
});
|
|
36123
37000
|
|
|
36124
37001
|
// src/hooks/cloud-connection.ts
|
|
36125
|
-
import { rmSync as
|
|
37002
|
+
import { rmSync as rmSync16 } from "node:fs";
|
|
36126
37003
|
function ingestUrlFor(baseUrl) {
|
|
36127
37004
|
return `${baseUrl.replace(/\/$/, "")}${INGEST_PATH}`;
|
|
36128
37005
|
}
|
|
@@ -36164,6 +37041,7 @@ async function connectToCloud(input) {
|
|
|
36164
37041
|
};
|
|
36165
37042
|
}
|
|
36166
37043
|
const known = identity.kind === "ok" ? identity.identity : null;
|
|
37044
|
+
const org = known ? { id: known.orgId, slug: known.orgSlug, name: known.orgName } : input.org;
|
|
36167
37045
|
const canIngest = known ? hasPermission(known, PERMISSION_EVENTS) : true;
|
|
36168
37046
|
const canPolicy = known ? hasPermission(known, PERMISSION_POLICIES) : true;
|
|
36169
37047
|
const missing = (permission) => `that key does not carry \`${permission}\`` + (known ? ` (it is valid for ${describeOrg(known)})` : "");
|
|
@@ -36175,7 +37053,7 @@ async function connectToCloud(input) {
|
|
|
36175
37053
|
policy: policyResult.ok ? { ok: true, policyCount: policyResult.policyCount, deployment: policyResult.deployment } : { ok: false, reason: policyResult.reason },
|
|
36176
37054
|
ingest: ingestResult.ok ? { ok: true } : { ok: false, reason: ingestResult.reason },
|
|
36177
37055
|
anyConfigured: false,
|
|
36178
|
-
org
|
|
37056
|
+
org
|
|
36179
37057
|
};
|
|
36180
37058
|
outcome.anyConfigured = policyResult.ok || ingestResult.ok;
|
|
36181
37059
|
if (!outcome.anyConfigured)
|
|
@@ -36197,13 +37075,13 @@ async function connectToCloud(input) {
|
|
|
36197
37075
|
prev.ingest ? { token: prev.ingest.key, url: prev.ingest.url } : undefined,
|
|
36198
37076
|
prev.jev ? { token: prev.jev.key, url: prev.jev.url } : undefined
|
|
36199
37077
|
].some((slot) => slot && (slot.token !== input.token || !sameOrigin(slot.url)));
|
|
36200
|
-
const sameKnownOrg = Boolean(prev.org?.id &&
|
|
36201
|
-
const orgSwitch = hadConnection && !sameKnownOrg && (prev.org?.id &&
|
|
37078
|
+
const sameKnownOrg = Boolean(prev.org?.id && org?.id && prev.org.id === org.id);
|
|
37079
|
+
const orgSwitch = hadConnection && !sameKnownOrg && (prev.org?.id && org?.id && prev.org.id !== org.id || (!prev.org?.id || !org?.id) && keyChanged || previousPolicy && !sameOrigin(previousPolicy.url) || prev.ingest && !sameOrigin(prev.ingest.url));
|
|
36202
37080
|
const boundary = orgSwitch ? next.connectedAt : prev.org?.since;
|
|
36203
37081
|
if (orgSwitch) {
|
|
36204
|
-
|
|
37082
|
+
rmSync16(backfillRequestPath(), { force: true });
|
|
36205
37083
|
const oldOrg = prev.org?.name ?? prev.org?.slug ?? prev.org?.id ?? "the previous org";
|
|
36206
|
-
const newOrg =
|
|
37084
|
+
const newOrg = org?.name ?? org?.slug ?? org?.id ?? "the new org";
|
|
36207
37085
|
changes.push(`Switched from ${oldOrg} to ${newOrg}. Nothing recorded before now will be sent to ${newOrg}; ${oldOrg}'s cloud policies stop within ~30 s.`);
|
|
36208
37086
|
clearActiveCloudManagedPolicies();
|
|
36209
37087
|
}
|
|
@@ -36231,15 +37109,15 @@ async function connectToCloud(input) {
|
|
|
36231
37109
|
changes.push(`Removed the previous Jev key ${maskToken(prev.jev.key)}: this key's ${PERMISSION_JEV} permission was not verified.`);
|
|
36232
37110
|
}
|
|
36233
37111
|
const since = boundary === undefined ? {} : { since: boundary };
|
|
36234
|
-
if (
|
|
36235
|
-
next.org = {
|
|
37112
|
+
if (org) {
|
|
37113
|
+
next.org = { ...org, ...since };
|
|
36236
37114
|
} else {
|
|
36237
37115
|
const { since: _drop, ...kept } = orgSwitch ? {} : prev.org ?? {};
|
|
36238
37116
|
next.org = { ...kept, ...since };
|
|
36239
37117
|
}
|
|
36240
37118
|
writeCredentials(next);
|
|
36241
37119
|
if (ingestResult.ok && prev.ingest && prev.ingest.key !== input.token) {
|
|
36242
|
-
recoverCredentialRefusals(Boolean(prev.org?.id && prev.org.id ===
|
|
37120
|
+
recoverCredentialRefusals(Boolean(prev.org?.id && prev.org.id === org?.id && sameOrigin(prev.ingest.url)), prev.org?.id);
|
|
36243
37121
|
}
|
|
36244
37122
|
if (process.env.FAILPROOFAI_CLOUD_CREDENTIALS) {
|
|
36245
37123
|
if (policyResult.ok)
|
|
@@ -36328,47 +37206,23 @@ function jevLines(outcome) {
|
|
|
36328
37206
|
}
|
|
36329
37207
|
const config = jev.config;
|
|
36330
37208
|
if (!config || config.status === "written" || config.status === "repointed") {
|
|
36331
|
-
const plainHttp = config !== undefined && new URL(config.baseUrl).protocol === "http:";
|
|
36332
|
-
const httpLine = " Over plain http Jev runs only in observe mode: enforce (set here or by FailproofAI Cloud) turns it off on this machine. For enforce, reconnect with `failproofai config --token <key> --url https://…`.";
|
|
36333
37209
|
const lead = config?.status === "repointed" ? [` Jev ${config.path} now points here instead of ${config.from}.`] : [];
|
|
36334
37210
|
const indent = lead.length > 0 ? " " : " Jev ";
|
|
36335
37211
|
const cloudJev = safeCloudJev();
|
|
36336
|
-
|
|
36337
|
-
|
|
36338
|
-
return [...lead, `${indent}off on this machine: FailproofAI Cloud set its Jev mode to off.`];
|
|
36339
|
-
if (plainHttp && cloudJev.jevMode === "enforce") {
|
|
36340
|
-
return [
|
|
36341
|
-
...lead,
|
|
36342
|
-
`${indent}off on this machine: FailproofAI Cloud set enforce, and over plain http Jev runs only in observe mode. For enforce, reconnect with \`failproofai config --token <key> --url https://…\`.`
|
|
36343
|
-
];
|
|
36344
|
-
}
|
|
36345
|
-
return [
|
|
36346
|
-
...lead,
|
|
36347
|
-
`${indent}on through FailproofAI Cloud, mode ${cloudJev.jevMode} (set by FailproofAI Cloud); the Jev checks it deployed here run on FailproofAI Cloud.`
|
|
36348
|
-
];
|
|
36349
|
-
}
|
|
36350
|
-
const localMode = config?.status === "repointed" ? config.mode : "observe";
|
|
36351
|
-
if (localMode === "off") {
|
|
36352
|
-
return [...lead, `${indent}switched off in ${config?.path ?? "jev.json"} (mode off). FailproofAI Cloud's Jev mode, if it sets one, arrives with its first deployment. To turn it on: \`failproofai jev setup --mode observe\`.`];
|
|
36353
|
-
}
|
|
36354
|
-
return [
|
|
36355
|
-
...lead,
|
|
36356
|
-
`${indent}configured through FailproofAI Cloud; waiting for FailproofAI Cloud's Jev mode, which arrives with this machine's first deployment (within ~30 s) and decides. Until then, and if Cloud sets none: ${localMode} (${config?.path ?? "jev.json"}). Check with \`failproofai jev status\`.`,
|
|
36357
|
-
...jevChecksDeclared() ? [] : [" No Jev checks are installed on this machine; checks FailproofAI Cloud deploys here run on Cloud. To add local ones: `failproofai policies add FailproofAI/jev-policies`."],
|
|
36358
|
-
...plainHttp ? [httpLine] : []
|
|
36359
|
-
];
|
|
37212
|
+
const state = cloudJev.jevMode === null ? "waiting for its first deployment" : cloudJev.jevMode === "off" ? "off — no Jev policy deployed" : cloudJev.jevMode;
|
|
37213
|
+
return [...lead, `${indent}managed by FailproofAI Cloud · ${state}`];
|
|
36360
37214
|
}
|
|
36361
37215
|
if (config.status === "kept") {
|
|
36362
37216
|
const lines = [` Jev key stored; ${config.path} already exists and was left as configured.`];
|
|
36363
37217
|
if (config.otherOrigin) {
|
|
36364
|
-
lines.push(config.jevOff?.why === "off" ? ` It points at ${config.otherOrigin} and has Jev switched off (mode off), so Jev is off. To point it here
|
|
37218
|
+
lines.push(config.jevOff?.why === "off" ? ` It points at ${config.otherOrigin} and has Jev switched off (mode off), so Jev is off. To point it here: \`failproofai jev setup --provider failproofai\`.` : ` It points at ${config.otherOrigin}, so Jev stays off until you run \`failproofai jev setup --provider failproofai\`.`);
|
|
36365
37219
|
} else if (config.jevOff?.why === "refused") {
|
|
36366
37220
|
lines.push(` It was refused (${config.jevOff.problem}), so Jev is off. ${config.jevOff.fix ? `Fix: \`${config.jevOff.fix}\`.` : "Write a valid one: `failproofai jev setup --provider failproofai`."}`);
|
|
36367
37221
|
} else if (config.jevOff?.why === "off") {
|
|
36368
|
-
lines.push(" It has Jev switched off (mode off)
|
|
37222
|
+
lines.push(" It has Jev switched off (mode off) until FailproofAI Cloud's Jev mode arrives with this machine's first deployment; from then on FailproofAI Cloud decides.");
|
|
36369
37223
|
}
|
|
36370
37224
|
if (jev.stillOn) {
|
|
36371
|
-
lines.push(` Jev is still on through FailproofAI Cloud (${jev.stillOn} mode): it sends each checked tool call and the recent prompt to FailproofAI Cloud.
|
|
37225
|
+
lines.push(` Jev is still on through FailproofAI Cloud (${jev.stillOn} mode): it sends each checked tool call and the recent prompt to FailproofAI Cloud. FailproofAI Cloud sets its mode: off when no Jev policy is deployed here.`);
|
|
36372
37226
|
}
|
|
36373
37227
|
return lines;
|
|
36374
37228
|
}
|
|
@@ -36427,7 +37281,7 @@ var init_cloud_connection = __esm(() => {
|
|
|
36427
37281
|
init_cloud_enrollment();
|
|
36428
37282
|
init_fp_home();
|
|
36429
37283
|
init_fp_config();
|
|
36430
|
-
|
|
37284
|
+
init_cloud_introspect();
|
|
36431
37285
|
init_collector_config();
|
|
36432
37286
|
init_credential_recovery();
|
|
36433
37287
|
init_cloud_managed_policies();
|
|
@@ -36435,14 +37289,14 @@ var init_cloud_connection = __esm(() => {
|
|
|
36435
37289
|
});
|
|
36436
37290
|
|
|
36437
37291
|
// src/hooks/setup-state.ts
|
|
36438
|
-
import { existsSync as
|
|
36439
|
-
import { dirname as dirname23, resolve as
|
|
36440
|
-
import { homedir as
|
|
36441
|
-
function globalConfigPath(home =
|
|
37292
|
+
import { existsSync as existsSync42, realpathSync as realpathSync4, statSync as statSync30 } from "node:fs";
|
|
37293
|
+
import { dirname as dirname23, resolve as resolve32 } from "node:path";
|
|
37294
|
+
import { homedir as homedir31 } from "node:os";
|
|
37295
|
+
function globalConfigPath(home = homedir31()) {
|
|
36442
37296
|
return globalPolicyConfigFile(home);
|
|
36443
37297
|
}
|
|
36444
37298
|
function projectConfigPath(projectRoot) {
|
|
36445
|
-
return
|
|
37299
|
+
return resolve32(projectRoot, ".failproofai", "policies-config.json");
|
|
36446
37300
|
}
|
|
36447
37301
|
function legacyMarkerPath(home) {
|
|
36448
37302
|
return launcherMarker(home);
|
|
@@ -36454,18 +37308,18 @@ function isDir(path) {
|
|
|
36454
37308
|
return false;
|
|
36455
37309
|
}
|
|
36456
37310
|
}
|
|
36457
|
-
function findProjectRoot2(start, home =
|
|
37311
|
+
function findProjectRoot2(start, home = homedir31()) {
|
|
36458
37312
|
const resolvedHome = realResolve(home);
|
|
36459
37313
|
let dir = realResolve(start);
|
|
36460
37314
|
while (dir !== resolvedHome) {
|
|
36461
|
-
if (isDir(
|
|
37315
|
+
if (isDir(resolve32(dir, ".failproofai")))
|
|
36462
37316
|
return dir;
|
|
36463
37317
|
const parent = dirname23(dir);
|
|
36464
37318
|
if (parent === dir)
|
|
36465
37319
|
break;
|
|
36466
37320
|
dir = parent;
|
|
36467
37321
|
}
|
|
36468
|
-
return
|
|
37322
|
+
return resolve32(start);
|
|
36469
37323
|
}
|
|
36470
37324
|
function hasGlobalHooksInstalled() {
|
|
36471
37325
|
for (const id of INTEGRATION_TYPES) {
|
|
@@ -36477,14 +37331,14 @@ function hasGlobalHooksInstalled() {
|
|
|
36477
37331
|
return false;
|
|
36478
37332
|
}
|
|
36479
37333
|
function realResolve(path) {
|
|
36480
|
-
const lexical =
|
|
37334
|
+
const lexical = resolve32(path);
|
|
36481
37335
|
try {
|
|
36482
37336
|
return realpathSync4(lexical);
|
|
36483
37337
|
} catch {
|
|
36484
37338
|
return lexical;
|
|
36485
37339
|
}
|
|
36486
37340
|
}
|
|
36487
|
-
function detectSetupState(cwd = process.cwd(), home =
|
|
37341
|
+
function detectSetupState(cwd = process.cwd(), home = homedir31()) {
|
|
36488
37342
|
const resolvedCwd = realResolve(cwd);
|
|
36489
37343
|
const resolvedHome = realResolve(home);
|
|
36490
37344
|
const projectRoot = findProjectRoot2(resolvedCwd, resolvedHome);
|
|
@@ -36492,10 +37346,10 @@ function detectSetupState(cwd = process.cwd(), home = homedir30()) {
|
|
|
36492
37346
|
cwd: resolvedCwd,
|
|
36493
37347
|
home: resolvedHome,
|
|
36494
37348
|
projectRoot,
|
|
36495
|
-
hasGlobalConfig:
|
|
36496
|
-
hasProjectConfig: projectRoot !== resolvedHome &&
|
|
37349
|
+
hasGlobalConfig: existsSync42(globalConfigPath(resolvedHome)),
|
|
37350
|
+
hasProjectConfig: projectRoot !== resolvedHome && existsSync42(projectConfigPath(projectRoot)),
|
|
36497
37351
|
hasGlobalHooks: hasGlobalHooksInstalled(),
|
|
36498
|
-
hasLegacyMarker:
|
|
37352
|
+
hasLegacyMarker: existsSync42(legacyMarkerPath(resolvedHome)),
|
|
36499
37353
|
inHomeDir: resolvedCwd === resolvedHome
|
|
36500
37354
|
};
|
|
36501
37355
|
}
|
|
@@ -36509,14 +37363,14 @@ var init_setup_state = __esm(() => {
|
|
|
36509
37363
|
});
|
|
36510
37364
|
|
|
36511
37365
|
// src/hooks/onboarding-attempt.ts
|
|
36512
|
-
import { existsSync as
|
|
37366
|
+
import { existsSync as existsSync43, mkdirSync as mkdirSync24, readFileSync as readFileSync34, rmSync as rmSync17, writeFileSync as writeFileSync19 } from "node:fs";
|
|
36513
37367
|
import { dirname as dirname24 } from "node:path";
|
|
36514
37368
|
function readOnboardingAttempt() {
|
|
36515
37369
|
const path = onboardingAttemptFile();
|
|
36516
|
-
if (!
|
|
37370
|
+
if (!existsSync43(path))
|
|
36517
37371
|
return null;
|
|
36518
37372
|
try {
|
|
36519
|
-
const raw = JSON.parse(
|
|
37373
|
+
const raw = JSON.parse(readFileSync34(path, "utf8"));
|
|
36520
37374
|
if (raw.schemaVersion !== SCHEMA_VERSION3)
|
|
36521
37375
|
return null;
|
|
36522
37376
|
if (typeof raw.reason !== "string" || typeof raw.cliVersion !== "string")
|
|
@@ -36535,7 +37389,7 @@ function readOnboardingAttempt() {
|
|
|
36535
37389
|
function recordOnboardingAttempt(reason, cliVersion, daemonStatus, now = Date.now()) {
|
|
36536
37390
|
try {
|
|
36537
37391
|
const path = onboardingAttemptFile();
|
|
36538
|
-
|
|
37392
|
+
mkdirSync24(dirname24(path), { recursive: true });
|
|
36539
37393
|
const record = {
|
|
36540
37394
|
schemaVersion: SCHEMA_VERSION3,
|
|
36541
37395
|
reason,
|
|
@@ -36548,7 +37402,7 @@ function recordOnboardingAttempt(reason, cliVersion, daemonStatus, now = Date.no
|
|
|
36548
37402
|
}
|
|
36549
37403
|
function clearOnboardingAttempt() {
|
|
36550
37404
|
try {
|
|
36551
|
-
|
|
37405
|
+
rmSync17(onboardingAttemptFile(), { force: true });
|
|
36552
37406
|
} catch {}
|
|
36553
37407
|
}
|
|
36554
37408
|
function blockerCleared(attempt, probe) {
|
|
@@ -36587,9 +37441,9 @@ var init_onboarding_attempt = __esm(() => {
|
|
|
36587
37441
|
});
|
|
36588
37442
|
|
|
36589
37443
|
// src/hooks/onboarding-lock.ts
|
|
36590
|
-
import { mkdirSync as
|
|
36591
|
-
import { homedir as
|
|
36592
|
-
function onboardingLockPath(home =
|
|
37444
|
+
import { mkdirSync as mkdirSync25, readFileSync as readFileSync35, rmSync as rmSync18, writeFileSync as writeFileSync20 } from "node:fs";
|
|
37445
|
+
import { homedir as homedir32 } from "node:os";
|
|
37446
|
+
function onboardingLockPath(home = homedir32()) {
|
|
36593
37447
|
return onboardingLockFile(home);
|
|
36594
37448
|
}
|
|
36595
37449
|
function processAlive(pid) {
|
|
@@ -36604,7 +37458,7 @@ function processAlive(pid) {
|
|
|
36604
37458
|
}
|
|
36605
37459
|
function readLock(path) {
|
|
36606
37460
|
try {
|
|
36607
|
-
const parsed = JSON.parse(
|
|
37461
|
+
const parsed = JSON.parse(readFileSync35(path, "utf8"));
|
|
36608
37462
|
if (typeof parsed.pid !== "number")
|
|
36609
37463
|
return null;
|
|
36610
37464
|
return { pid: parsed.pid, startedAt: Number(parsed.startedAt) || 0 };
|
|
@@ -36612,13 +37466,13 @@ function readLock(path) {
|
|
|
36612
37466
|
return null;
|
|
36613
37467
|
}
|
|
36614
37468
|
}
|
|
36615
|
-
function acquireOnboardingLock(home =
|
|
37469
|
+
function acquireOnboardingLock(home = homedir32()) {
|
|
36616
37470
|
const path = onboardingLockPath(home);
|
|
36617
37471
|
try {
|
|
36618
37472
|
const held = readLock(path);
|
|
36619
37473
|
if (held && held.pid !== process.pid && processAlive(held.pid))
|
|
36620
37474
|
return null;
|
|
36621
|
-
|
|
37475
|
+
mkdirSync25(stateDir(home), { recursive: true });
|
|
36622
37476
|
const body = { pid: process.pid, startedAt: Date.now() };
|
|
36623
37477
|
writeFileSync20(path, JSON.stringify(body), "utf8");
|
|
36624
37478
|
let released = false;
|
|
@@ -36630,7 +37484,7 @@ function acquireOnboardingLock(home = homedir31()) {
|
|
|
36630
37484
|
try {
|
|
36631
37485
|
const current = readLock(path);
|
|
36632
37486
|
if (!current || current.pid === process.pid)
|
|
36633
|
-
|
|
37487
|
+
rmSync18(path, { force: true });
|
|
36634
37488
|
} catch {}
|
|
36635
37489
|
}
|
|
36636
37490
|
};
|
|
@@ -36643,8 +37497,8 @@ var init_onboarding_lock = __esm(() => {
|
|
|
36643
37497
|
});
|
|
36644
37498
|
|
|
36645
37499
|
// lib/claude-sessions.ts
|
|
36646
|
-
import { readdirSync as readdirSync20, statSync as statSync31, existsSync as
|
|
36647
|
-
import { join as
|
|
37500
|
+
import { readdirSync as readdirSync20, statSync as statSync31, existsSync as existsSync44 } from "node:fs";
|
|
37501
|
+
import { join as join39, basename as basename9 } from "node:path";
|
|
36648
37502
|
function getClaudeProjectsRoot() {
|
|
36649
37503
|
return getClaudeProjectsPath();
|
|
36650
37504
|
}
|
|
@@ -36659,7 +37513,7 @@ function listClaudeProjects() {
|
|
|
36659
37513
|
return entries.filter((e) => e.isDirectory()).map((e) => ({
|
|
36660
37514
|
name: e.name,
|
|
36661
37515
|
cwd: decodeFolderName(e.name),
|
|
36662
|
-
path:
|
|
37516
|
+
path: join39(root, e.name)
|
|
36663
37517
|
}));
|
|
36664
37518
|
}
|
|
36665
37519
|
function listClaudeTranscripts(project) {
|
|
@@ -36675,7 +37529,7 @@ function listClaudeTranscripts(project) {
|
|
|
36675
37529
|
const sessionId = entry.name.slice(0, -".jsonl".length);
|
|
36676
37530
|
if (!UUID_RE2.test(sessionId))
|
|
36677
37531
|
continue;
|
|
36678
|
-
const transcriptPath =
|
|
37532
|
+
const transcriptPath = join39(project.path, entry.name);
|
|
36679
37533
|
try {
|
|
36680
37534
|
const s = statSync31(transcriptPath);
|
|
36681
37535
|
out.push({
|
|
@@ -36689,8 +37543,8 @@ function listClaudeTranscripts(project) {
|
|
|
36689
37543
|
});
|
|
36690
37544
|
} catch {}
|
|
36691
37545
|
} else if (entry.isDirectory() && UUID_RE2.test(entry.name)) {
|
|
36692
|
-
const subDir =
|
|
36693
|
-
if (!
|
|
37546
|
+
const subDir = join39(project.path, entry.name, "subagents");
|
|
37547
|
+
if (!existsSync44(subDir))
|
|
36694
37548
|
continue;
|
|
36695
37549
|
let subEntries;
|
|
36696
37550
|
try {
|
|
@@ -36702,7 +37556,7 @@ function listClaudeTranscripts(project) {
|
|
|
36702
37556
|
if (!sub.isFile() || !sub.name.endsWith(".jsonl"))
|
|
36703
37557
|
continue;
|
|
36704
37558
|
const agentId = sub.name.slice(0, -".jsonl".length);
|
|
36705
|
-
const transcriptPath =
|
|
37559
|
+
const transcriptPath = join39(subDir, sub.name);
|
|
36706
37560
|
try {
|
|
36707
37561
|
const s = statSync31(transcriptPath);
|
|
36708
37562
|
out.push({
|
|
@@ -38039,8 +38893,8 @@ var init_features = __esm(() => {
|
|
|
38039
38893
|
|
|
38040
38894
|
// src/audit/cache.ts
|
|
38041
38895
|
import { createHash as createHash12 } from "node:crypto";
|
|
38042
|
-
import { existsSync as
|
|
38043
|
-
import { join as
|
|
38896
|
+
import { existsSync as existsSync45, mkdirSync as mkdirSync26, readFileSync as readFileSync36, writeFileSync as writeFileSync21, chmodSync as chmodSync10, openSync as openSync6, readSync as readSync5, closeSync as closeSync6 } from "node:fs";
|
|
38897
|
+
import { join as join40 } from "node:path";
|
|
38044
38898
|
function getEngineVersion() {
|
|
38045
38899
|
if (cachedEngineVersion)
|
|
38046
38900
|
return cachedEngineVersion;
|
|
@@ -38060,7 +38914,7 @@ function getDetectorVersion() {
|
|
|
38060
38914
|
function getCachePathFor(transcriptPath) {
|
|
38061
38915
|
const root = auditCacheDir();
|
|
38062
38916
|
const key = createHash12("sha1").update(transcriptPath).digest("hex");
|
|
38063
|
-
return
|
|
38917
|
+
return join40(root, `${key}.json`);
|
|
38064
38918
|
}
|
|
38065
38919
|
function encodeDetectorState(state) {
|
|
38066
38920
|
return JSON.stringify(state, (_k, v) => v instanceof Map ? { __map: [...v.entries()] } : v);
|
|
@@ -38100,10 +38954,10 @@ function readCachedTranscript(transcriptPath, mtimeMs, sizeBytes) {
|
|
|
38100
38954
|
if (sizeBytes === 0)
|
|
38101
38955
|
return null;
|
|
38102
38956
|
const cachePath = getCachePathFor(transcriptPath);
|
|
38103
|
-
if (!
|
|
38957
|
+
if (!existsSync45(cachePath))
|
|
38104
38958
|
return null;
|
|
38105
38959
|
try {
|
|
38106
|
-
const raw =
|
|
38960
|
+
const raw = readFileSync36(cachePath, "utf-8");
|
|
38107
38961
|
const entry = JSON.parse(raw);
|
|
38108
38962
|
if (entry.schemaVersion !== CACHE_SCHEMA_VERSION)
|
|
38109
38963
|
return null;
|
|
@@ -38142,7 +38996,7 @@ function writeCachedTranscriptResult(transcriptPath, mtimeMs, sizeBytes, result,
|
|
|
38142
38996
|
return;
|
|
38143
38997
|
const cachePath = getCachePathFor(transcriptPath);
|
|
38144
38998
|
try {
|
|
38145
|
-
|
|
38999
|
+
mkdirSync26(auditCacheDir(), { recursive: true });
|
|
38146
39000
|
const entry = {
|
|
38147
39001
|
schemaVersion: CACHE_SCHEMA_VERSION,
|
|
38148
39002
|
cachedAt: Date.now(),
|
|
@@ -38627,9 +39481,9 @@ var init_audit = __esm(() => {
|
|
|
38627
39481
|
import {
|
|
38628
39482
|
closeSync as closeSync7,
|
|
38629
39483
|
linkSync as linkSync2,
|
|
38630
|
-
mkdirSync as
|
|
39484
|
+
mkdirSync as mkdirSync27,
|
|
38631
39485
|
openSync as openSync7,
|
|
38632
|
-
readFileSync as
|
|
39486
|
+
readFileSync as readFileSync37,
|
|
38633
39487
|
unlinkSync as unlinkSync7,
|
|
38634
39488
|
writeFileSync as writeFileSync22,
|
|
38635
39489
|
writeSync as writeSync2
|
|
@@ -38690,7 +39544,7 @@ function handleFor(path, info) {
|
|
|
38690
39544
|
}
|
|
38691
39545
|
function readLock2(path) {
|
|
38692
39546
|
try {
|
|
38693
|
-
const parsed = JSON.parse(
|
|
39547
|
+
const parsed = JSON.parse(readFileSync37(path, "utf8"));
|
|
38694
39548
|
if (typeof parsed?.pid !== "number" || typeof parsed?.startedAt !== "number")
|
|
38695
39549
|
return null;
|
|
38696
39550
|
return {
|
|
@@ -38740,8 +39594,8 @@ function createThenWrite(path, body) {
|
|
|
38740
39594
|
}
|
|
38741
39595
|
}
|
|
38742
39596
|
function ensureRunDir() {
|
|
38743
|
-
|
|
38744
|
-
|
|
39597
|
+
mkdirSync27(failproofaiHome(), { recursive: true });
|
|
39598
|
+
mkdirSync27(runDir(), { recursive: true, mode: 448 });
|
|
38745
39599
|
}
|
|
38746
39600
|
var AUDIT_LOCK_MAX_AGE_MS;
|
|
38747
39601
|
var init_audit_lock = __esm(() => {
|
|
@@ -38750,7 +39604,7 @@ var init_audit_lock = __esm(() => {
|
|
|
38750
39604
|
});
|
|
38751
39605
|
|
|
38752
39606
|
// src/audit/dashboard-cache.ts
|
|
38753
|
-
import { existsSync as
|
|
39607
|
+
import { existsSync as existsSync46, readFileSync as readFileSync38 } from "node:fs";
|
|
38754
39608
|
function getCachePath() {
|
|
38755
39609
|
return auditDashboardFile();
|
|
38756
39610
|
}
|
|
@@ -38770,10 +39624,10 @@ function writeDashboardCache(params, result) {
|
|
|
38770
39624
|
}
|
|
38771
39625
|
function readDashboardCacheMeta() {
|
|
38772
39626
|
const cachePath = getCachePath();
|
|
38773
|
-
if (!
|
|
39627
|
+
if (!existsSync46(cachePath))
|
|
38774
39628
|
return null;
|
|
38775
39629
|
try {
|
|
38776
|
-
const raw =
|
|
39630
|
+
const raw = readFileSync38(cachePath, "utf-8");
|
|
38777
39631
|
const entry = JSON.parse(raw);
|
|
38778
39632
|
if (!entry || entry.schemaVersion !== DASHBOARD_CACHE_SCHEMA_VERSION || typeof entry.cachedAt !== "string" || Number.isNaN(new Date(entry.cachedAt).getTime()))
|
|
38779
39633
|
return null;
|
|
@@ -38822,47 +39676,6 @@ function sanitizeErrorMessage(err) {
|
|
|
38822
39676
|
var MAX_ERROR_MESSAGE_LEN = 300;
|
|
38823
39677
|
var init_telemetry_sanitize = () => {};
|
|
38824
39678
|
|
|
38825
|
-
// src/audit/open-browser.ts
|
|
38826
|
-
import { spawn } from "node:child_process";
|
|
38827
|
-
function openUrl(url) {
|
|
38828
|
-
let cmd;
|
|
38829
|
-
let args;
|
|
38830
|
-
if (process.platform === "darwin") {
|
|
38831
|
-
cmd = "open";
|
|
38832
|
-
args = [url];
|
|
38833
|
-
} else if (process.platform === "win32") {
|
|
38834
|
-
cmd = "cmd";
|
|
38835
|
-
args = ["/c", "start", "", url];
|
|
38836
|
-
} else {
|
|
38837
|
-
cmd = "xdg-open";
|
|
38838
|
-
args = [url];
|
|
38839
|
-
}
|
|
38840
|
-
try {
|
|
38841
|
-
const child = spawn(cmd, args, { stdio: "ignore", detached: true });
|
|
38842
|
-
child.on("error", () => {});
|
|
38843
|
-
child.unref();
|
|
38844
|
-
} catch {}
|
|
38845
|
-
}
|
|
38846
|
-
function openWhenReady(port, path) {
|
|
38847
|
-
const base = `http://localhost:${port}`;
|
|
38848
|
-
const target = `${base}${path}`;
|
|
38849
|
-
(async () => {
|
|
38850
|
-
const deadline = Date.now() + POLL_TIMEOUT_MS;
|
|
38851
|
-
while (Date.now() < deadline) {
|
|
38852
|
-
try {
|
|
38853
|
-
await fetch(base, { method: "GET", redirect: "manual" });
|
|
38854
|
-
openUrl(target);
|
|
38855
|
-
return;
|
|
38856
|
-
} catch {
|
|
38857
|
-
await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));
|
|
38858
|
-
}
|
|
38859
|
-
}
|
|
38860
|
-
openUrl(target);
|
|
38861
|
-
})();
|
|
38862
|
-
}
|
|
38863
|
-
var POLL_INTERVAL_MS = 150, POLL_TIMEOUT_MS = 30000;
|
|
38864
|
-
var init_open_browser = () => {};
|
|
38865
|
-
|
|
38866
39679
|
// lib/telemetry.ts
|
|
38867
39680
|
function trackEvent(name, properties) {
|
|
38868
39681
|
if (!isTelemetryEnabled())
|
|
@@ -38950,7 +39763,7 @@ async function fetchWithTimeout2(url, init) {
|
|
|
38950
39763
|
throw err;
|
|
38951
39764
|
}
|
|
38952
39765
|
}
|
|
38953
|
-
async function
|
|
39766
|
+
async function postJson3(path, body, init) {
|
|
38954
39767
|
const headers = { "content-type": "application/json" };
|
|
38955
39768
|
if (init?.accessToken)
|
|
38956
39769
|
headers["authorization"] = `Bearer ${init.accessToken}`;
|
|
@@ -38966,18 +39779,18 @@ async function postJson2(path, body, init) {
|
|
|
38966
39779
|
return await res.json();
|
|
38967
39780
|
}
|
|
38968
39781
|
async function requestLoginCode(email) {
|
|
38969
|
-
return
|
|
39782
|
+
return postJson3("/v0/auth/login/request", { email });
|
|
38970
39783
|
}
|
|
38971
39784
|
async function verifyLoginCode(email, code) {
|
|
38972
|
-
return
|
|
39785
|
+
return postJson3("/v0/auth/login/verify", { email, code });
|
|
38973
39786
|
}
|
|
38974
39787
|
async function refreshAccessToken(refreshToken) {
|
|
38975
|
-
return
|
|
39788
|
+
return postJson3("/v0/auth/token/refresh", {
|
|
38976
39789
|
refresh_token: refreshToken
|
|
38977
39790
|
});
|
|
38978
39791
|
}
|
|
38979
39792
|
async function submitAuditReport(accessToken, body) {
|
|
38980
|
-
return
|
|
39793
|
+
return postJson3("/v0/audit-reports", body, { accessToken });
|
|
38981
39794
|
}
|
|
38982
39795
|
var DEFAULT_API_BASE = "https://api.befailproof.ai", AuthApiError, REQUEST_TIMEOUT_MS = 1e4;
|
|
38983
39796
|
var init_api_server_client = __esm(() => {
|
|
@@ -38997,18 +39810,18 @@ var init_api_server_client = __esm(() => {
|
|
|
38997
39810
|
});
|
|
38998
39811
|
|
|
38999
39812
|
// lib/auth/auth-store.ts
|
|
39000
|
-
import { existsSync as
|
|
39001
|
-
import { join as
|
|
39813
|
+
import { existsSync as existsSync47, readFileSync as readFileSync39, readdirSync as readdirSync21, rmSync as rmSync19 } from "node:fs";
|
|
39814
|
+
import { join as join41, resolve as resolve33 } from "node:path";
|
|
39002
39815
|
function getAuthFilePath() {
|
|
39003
39816
|
const override = process.env.FAILPROOFAI_AUTH_DIR;
|
|
39004
|
-
return override ?
|
|
39817
|
+
return override ? join41(override, "session.json") : auditSessionFile();
|
|
39005
39818
|
}
|
|
39006
39819
|
function readAuth() {
|
|
39007
39820
|
const p = getAuthFilePath();
|
|
39008
|
-
if (!
|
|
39821
|
+
if (!existsSync47(p))
|
|
39009
39822
|
return null;
|
|
39010
39823
|
try {
|
|
39011
|
-
const raw =
|
|
39824
|
+
const raw = readFileSync39(p, "utf-8");
|
|
39012
39825
|
const parsed = JSON.parse(raw);
|
|
39013
39826
|
if (typeof parsed.access_token !== "string" || typeof parsed.refresh_token !== "string" || typeof parsed.access_expires_at !== "number" || typeof parsed.user !== "object" || !parsed.user || typeof parsed.user.id !== "string" || typeof parsed.user.email !== "string") {
|
|
39014
39827
|
return null;
|
|
@@ -39032,18 +39845,18 @@ function writeAuth(auth) {
|
|
|
39032
39845
|
}
|
|
39033
39846
|
function deleteAuth() {
|
|
39034
39847
|
const p = getAuthFilePath();
|
|
39035
|
-
if (
|
|
39036
|
-
|
|
39848
|
+
if (existsSync47(p))
|
|
39849
|
+
rmSync19(p, { force: true });
|
|
39037
39850
|
try {
|
|
39038
39851
|
const root = migrationsDir();
|
|
39039
|
-
if (!
|
|
39852
|
+
if (!existsSync47(root))
|
|
39040
39853
|
return;
|
|
39041
39854
|
for (const entry of readdirSync21(root)) {
|
|
39042
39855
|
if (!entry.startsWith("backup-layout"))
|
|
39043
39856
|
continue;
|
|
39044
|
-
const copy =
|
|
39045
|
-
if (
|
|
39046
|
-
|
|
39857
|
+
const copy = resolve33(root, entry, "auth.json");
|
|
39858
|
+
if (existsSync47(copy))
|
|
39859
|
+
rmSync19(copy, { force: true });
|
|
39047
39860
|
}
|
|
39048
39861
|
} catch {}
|
|
39049
39862
|
}
|
|
@@ -39104,7 +39917,7 @@ var init_auth_store = __esm(() => {
|
|
|
39104
39917
|
});
|
|
39105
39918
|
|
|
39106
39919
|
// src/audit/redact-example.ts
|
|
39107
|
-
import { homedir as
|
|
39920
|
+
import { homedir as homedir33 } from "node:os";
|
|
39108
39921
|
function maskTruncatedSecret(input) {
|
|
39109
39922
|
for (const [pattern, label] of SECRET_PREFIXES) {
|
|
39110
39923
|
if (pattern.test(input)) {
|
|
@@ -39139,7 +39952,7 @@ function maskSecrets(input) {
|
|
|
39139
39952
|
}
|
|
39140
39953
|
return out;
|
|
39141
39954
|
}
|
|
39142
|
-
function shortenPaths(input, home =
|
|
39955
|
+
function shortenPaths(input, home = homedir33()) {
|
|
39143
39956
|
const homeRoot = home.replace(/\/+$/, "");
|
|
39144
39957
|
return input.replace(ABSOLUTE_PATH_RE, (match, offset, whole) => {
|
|
39145
39958
|
if (PUBLIC_PATH_ROOTS.some((root) => match.startsWith(root)))
|
|
@@ -39170,7 +39983,7 @@ function shortenPaths(input, home = homedir32()) {
|
|
|
39170
39983
|
return `${root}${middle}/${tail}${trailingSlash ? "/" : ""}`;
|
|
39171
39984
|
});
|
|
39172
39985
|
}
|
|
39173
|
-
function redactExample(input, home =
|
|
39986
|
+
function redactExample(input, home = homedir33()) {
|
|
39174
39987
|
const masked = maskAssignedSecrets(maskTruncatedSecret(maskSecrets(input)));
|
|
39175
39988
|
const shortened = shortenPaths(masked, home);
|
|
39176
39989
|
const collapsed = shortened.replace(/\s+/g, " ").trim();
|
|
@@ -39293,15 +40106,15 @@ var init_harm_report = __esm(() => {
|
|
|
39293
40106
|
});
|
|
39294
40107
|
|
|
39295
40108
|
// src/audit/machine-store.ts
|
|
39296
|
-
import { existsSync as
|
|
40109
|
+
import { existsSync as existsSync48, readFileSync as readFileSync40, rmSync as rmSync20 } from "node:fs";
|
|
39297
40110
|
import { hostname as hostname5 } from "node:os";
|
|
39298
40111
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
39299
40112
|
function readMachineIdentity(home) {
|
|
39300
40113
|
const path = auditMachineFile(home);
|
|
39301
|
-
if (!
|
|
40114
|
+
if (!existsSync48(path))
|
|
39302
40115
|
return null;
|
|
39303
40116
|
try {
|
|
39304
|
-
const parsed = JSON.parse(
|
|
40117
|
+
const parsed = JSON.parse(readFileSync40(path, "utf8"));
|
|
39305
40118
|
if (typeof parsed.machine_id !== "string" || !parsed.machine_id)
|
|
39306
40119
|
return null;
|
|
39307
40120
|
return {
|
|
@@ -39631,16 +40444,16 @@ var init_cli = __esm(() => {
|
|
|
39631
40444
|
});
|
|
39632
40445
|
|
|
39633
40446
|
// src/hooks/configure-wizard.ts
|
|
39634
|
-
import { existsSync as
|
|
39635
|
-
import { homedir as
|
|
39636
|
-
import { dirname as dirname25, resolve as
|
|
40447
|
+
import { existsSync as existsSync49, mkdirSync as mkdirSync28, writeFileSync as writeFileSync23, readFileSync as readFileSync41 } from "node:fs";
|
|
40448
|
+
import { homedir as homedir34 } from "node:os";
|
|
40449
|
+
import { dirname as dirname25, resolve as resolve34, sep as sep5 } from "node:path";
|
|
39637
40450
|
async function emit(event, props) {
|
|
39638
40451
|
try {
|
|
39639
40452
|
await trackHookEvent2(getInstanceId2(), event, props);
|
|
39640
40453
|
} catch {}
|
|
39641
40454
|
}
|
|
39642
40455
|
function homeify(p) {
|
|
39643
|
-
const home =
|
|
40456
|
+
const home = homedir34();
|
|
39644
40457
|
if (p === home)
|
|
39645
40458
|
return "~";
|
|
39646
40459
|
if (p.startsWith(home + sep5))
|
|
@@ -39763,7 +40576,7 @@ function removeUserScopeHooks(clis, cwd) {
|
|
|
39763
40576
|
}
|
|
39764
40577
|
}
|
|
39765
40578
|
for (const settingsPath of settingsPathsFor(integration, "user", cwd)) {
|
|
39766
|
-
if (id !== "hermes" && !
|
|
40579
|
+
if (id !== "hermes" && !existsSync49(settingsPath))
|
|
39767
40580
|
continue;
|
|
39768
40581
|
try {
|
|
39769
40582
|
removed += integration.removeHooksFromFile(settingsPath);
|
|
@@ -39801,7 +40614,7 @@ function describeCustomPolicies(cwd) {
|
|
|
39801
40614
|
const scopes = [];
|
|
39802
40615
|
let fileCount = 0;
|
|
39803
40616
|
const dirs = [
|
|
39804
|
-
{ dir:
|
|
40617
|
+
{ dir: resolve34(cwd, ".failproofai", "policies"), label: "project" },
|
|
39805
40618
|
{ dir: customPoliciesDir(), label: "global" }
|
|
39806
40619
|
];
|
|
39807
40620
|
for (const { dir, label } of dirs) {
|
|
@@ -39812,7 +40625,7 @@ function describeCustomPolicies(cwd) {
|
|
|
39812
40625
|
fileCount += found.length;
|
|
39813
40626
|
}
|
|
39814
40627
|
for (const name of findSkippedPolicyFiles(dir)) {
|
|
39815
|
-
warnings.push(`! ${homeify(
|
|
40628
|
+
warnings.push(`! ${homeify(resolve34(dir, name))} is NOT loaded — rename to ` + `${name.replace(/\.(js|mjs|ts)$/, "-policies.$1")}`);
|
|
39816
40629
|
}
|
|
39817
40630
|
}
|
|
39818
40631
|
return { active, warnings, fileCount, scopes };
|
|
@@ -39822,7 +40635,7 @@ function firstRunMarkerPath() {
|
|
|
39822
40635
|
}
|
|
39823
40636
|
function markLauncherSeen() {
|
|
39824
40637
|
try {
|
|
39825
|
-
|
|
40638
|
+
mkdirSync28(dirname25(firstRunMarkerPath()), { recursive: true });
|
|
39826
40639
|
writeFileSync23(firstRunMarkerPath(), "1", "utf8");
|
|
39827
40640
|
} catch {}
|
|
39828
40641
|
}
|
|
@@ -40057,6 +40870,158 @@ ${process.platform} service target.
|
|
|
40057
40870
|
stdin,
|
|
40058
40871
|
stdout
|
|
40059
40872
|
});
|
|
40873
|
+
const askKey = () => promptCloudKey({
|
|
40874
|
+
message: "Connect to cloud",
|
|
40875
|
+
meta: source ? `${host} · from ${source}` : host,
|
|
40876
|
+
tabHint: "go back",
|
|
40877
|
+
emptyError: "Paste a key, or press tab to go back.",
|
|
40878
|
+
check: async (key) => {
|
|
40879
|
+
if (!url)
|
|
40880
|
+
return { ok: false, line: badUrl ?? "No usable endpoint." };
|
|
40881
|
+
const r = await checkCloudKey(url, key);
|
|
40882
|
+
if (r.ok) {
|
|
40883
|
+
typedOrg = r.org;
|
|
40884
|
+
return { ok: true, line: r.note };
|
|
40885
|
+
}
|
|
40886
|
+
return { ok: false, line: r.refused ? `That key was refused: ${r.reason}.` : `Couldn't check the key: ${r.reason}.` };
|
|
40887
|
+
},
|
|
40888
|
+
collapsed: (answer) => answer === OPEN_SOURCE ? [] : [...cloudLines(planFor(answer)), ""],
|
|
40889
|
+
stdin,
|
|
40890
|
+
stdout
|
|
40891
|
+
});
|
|
40892
|
+
let loginUnsupported = false;
|
|
40893
|
+
const askLogin = (endpoint) => {
|
|
40894
|
+
let pollSecret = "";
|
|
40895
|
+
return promptBrowserLogin({
|
|
40896
|
+
message: "Connect to cloud",
|
|
40897
|
+
meta: source ? `${host} · from ${source}` : host,
|
|
40898
|
+
machineLabel,
|
|
40899
|
+
start: async () => {
|
|
40900
|
+
const r = await startLogin(endpoint, { label: machineLabel, os: machineOs(), cliVersion: version2 });
|
|
40901
|
+
if (r.kind === "ok") {
|
|
40902
|
+
pollSecret = r.pollSecret;
|
|
40903
|
+
emit("configure_cloud_login", { step: "started" });
|
|
40904
|
+
return { ok: true, url: r.verificationUrl, expiresIn: r.expiresIn, interval: r.interval };
|
|
40905
|
+
}
|
|
40906
|
+
if (r.kind === "unsupported") {
|
|
40907
|
+
emit("configure_cloud_login", { step: "unsupported" });
|
|
40908
|
+
loginUnsupported = true;
|
|
40909
|
+
return { ok: false, retryable: false, line: `${host} doesn't support logging in from here yet.` };
|
|
40910
|
+
}
|
|
40911
|
+
return {
|
|
40912
|
+
ok: false,
|
|
40913
|
+
retryable: true,
|
|
40914
|
+
line: r.kind === "refused" ? `Couldn't start the login: ${r.reason}.` : `Couldn't reach ${host}: ${r.reason}.`
|
|
40915
|
+
};
|
|
40916
|
+
},
|
|
40917
|
+
poll: async () => {
|
|
40918
|
+
const p = await pollLogin(endpoint, pollSecret);
|
|
40919
|
+
switch (p.kind) {
|
|
40920
|
+
case "approved":
|
|
40921
|
+
emit("configure_cloud_login", { step: "approved" });
|
|
40922
|
+
return {
|
|
40923
|
+
state: "approved",
|
|
40924
|
+
value: {
|
|
40925
|
+
kind: "login",
|
|
40926
|
+
pollSecret,
|
|
40927
|
+
org: p.org,
|
|
40928
|
+
approvedBy: p.approvedBy,
|
|
40929
|
+
keyName: p.keyName,
|
|
40930
|
+
permissions: p.permissions
|
|
40931
|
+
}
|
|
40932
|
+
};
|
|
40933
|
+
case "pending":
|
|
40934
|
+
return { state: "pending", interval: p.interval };
|
|
40935
|
+
case "slow_down":
|
|
40936
|
+
return { state: "slow_down" };
|
|
40937
|
+
case "denied":
|
|
40938
|
+
emit("configure_cloud_login", { step: "denied" });
|
|
40939
|
+
return { state: "denied" };
|
|
40940
|
+
case "unreachable":
|
|
40941
|
+
return { state: "unreachable", line: p.reason };
|
|
40942
|
+
default:
|
|
40943
|
+
return { state: "expired" };
|
|
40944
|
+
}
|
|
40945
|
+
},
|
|
40946
|
+
open: (link) => {
|
|
40947
|
+
if (!canOpenBrowser())
|
|
40948
|
+
return false;
|
|
40949
|
+
openUrl(link);
|
|
40950
|
+
return true;
|
|
40951
|
+
},
|
|
40952
|
+
collapsed: (plan) => [...cloudLines(plan), ""],
|
|
40953
|
+
stdin,
|
|
40954
|
+
stdout
|
|
40955
|
+
});
|
|
40956
|
+
};
|
|
40957
|
+
let savedRefused = false;
|
|
40958
|
+
const chooseConnection = async () => {
|
|
40959
|
+
const verdict = saved && !saved.splitKeys ? await transient("Checking your saved key…", () => checkCloudKey(saved.url, saved.token)) : null;
|
|
40960
|
+
const savedBroken = verdict !== null && !verdict.ok && verdict.refused;
|
|
40961
|
+
savedRefused = savedBroken;
|
|
40962
|
+
const keptPlan = verdict && verdict.ok ? { kind: "kept", how: "saved", verified: true } : verdict && !verdict.refused ? { kind: "kept", how: "saved", verified: false } : { kind: "kept", how: "skip", verified: false };
|
|
40963
|
+
const keepHint = !saved ? "" : saved.splitKeys ? "leave both keys as they are" : verdict?.ok ? `${verdict.org ?? saved.org ?? hostOf(saved.url)} · key ${maskToken(saved.token)}` : savedBroken ? "its key no longer works" : "its key couldn't be checked just now";
|
|
40964
|
+
const login = {
|
|
40965
|
+
label: saved ? "Log in again" : "Log in to FailproofAI Cloud",
|
|
40966
|
+
value: "login",
|
|
40967
|
+
hint: savedBroken ? "recommended · your saved key no longer works" : saved ? "opens your browser and makes a new key" : "recommended · opens your browser"
|
|
40968
|
+
};
|
|
40969
|
+
const key = { label: "Paste an API key", value: "key", hint: "one you already have" };
|
|
40970
|
+
const oss = { label: "Use open source", value: "oss", hint: "skip the cloud" };
|
|
40971
|
+
const keep = { label: "Keep current connection", value: "keep", hint: keepHint };
|
|
40972
|
+
const choices = !saved ? [login, key, oss] : savedBroken ? [login, key, keep] : [keep, login, key];
|
|
40973
|
+
const leftLogin = (result) => {
|
|
40974
|
+
if (result === null || result === BACK) {
|
|
40975
|
+
if (result === BACK && loginUnsupported) {
|
|
40976
|
+
write([kit.caution(`${host} doesn't support logging in from here yet. Paste an API key instead.`), ""]);
|
|
40977
|
+
}
|
|
40978
|
+
return result;
|
|
40979
|
+
}
|
|
40980
|
+
return result.value;
|
|
40981
|
+
};
|
|
40982
|
+
if (url && (!saved || savedBroken)) {
|
|
40983
|
+
if (savedBroken && verdict && !verdict.ok) {
|
|
40984
|
+
write([kit.caution(`Your saved key no longer works: ${verdict.reason}. Logging in again.`)]);
|
|
40985
|
+
}
|
|
40986
|
+
emit("configure_cloud_choice", { choice: "login", connected: Boolean(saved), auto: true });
|
|
40987
|
+
const first = leftLogin(await askLogin(url));
|
|
40988
|
+
if (first !== BACK)
|
|
40989
|
+
return first;
|
|
40990
|
+
}
|
|
40991
|
+
for (;; ) {
|
|
40992
|
+
const pick = await selectOne({
|
|
40993
|
+
message: "Connect to cloud",
|
|
40994
|
+
meta: source ? `${host} · from ${source}` : host,
|
|
40995
|
+
choices: loginUnsupported ? choices.filter((c) => c.value !== "login") : choices,
|
|
40996
|
+
collapsed: (p) => p === "keep" ? [...cloudLines(keptPlan), ""] : p === "oss" ? [...cloudLines({ kind: "oss" }), ""] : [],
|
|
40997
|
+
stdin,
|
|
40998
|
+
stdout
|
|
40999
|
+
});
|
|
41000
|
+
if (pick === null)
|
|
41001
|
+
return null;
|
|
41002
|
+
emit("configure_cloud_choice", { choice: pick, connected: Boolean(saved) });
|
|
41003
|
+
if (pick === "keep")
|
|
41004
|
+
return keptPlan;
|
|
41005
|
+
if (pick === "oss")
|
|
41006
|
+
return { kind: "oss" };
|
|
41007
|
+
if (pick === "key") {
|
|
41008
|
+
const answer = await askKey();
|
|
41009
|
+
if (answer === null)
|
|
41010
|
+
return null;
|
|
41011
|
+
if (answer === OPEN_SOURCE)
|
|
41012
|
+
continue;
|
|
41013
|
+
return planFor(answer);
|
|
41014
|
+
}
|
|
41015
|
+
if (!url) {
|
|
41016
|
+
write([kit.fail(badUrl ?? "No usable endpoint."), ""]);
|
|
41017
|
+
continue;
|
|
41018
|
+
}
|
|
41019
|
+
const result = leftLogin(await askLogin(url));
|
|
41020
|
+
if (result === BACK)
|
|
41021
|
+
continue;
|
|
41022
|
+
return result;
|
|
41023
|
+
}
|
|
41024
|
+
};
|
|
40060
41025
|
let cloud;
|
|
40061
41026
|
if (answers.oss) {
|
|
40062
41027
|
cloud = saved ? { kind: "kept", how: "skip", verified: false } : { kind: "oss" };
|
|
@@ -40088,16 +41053,17 @@ ${process.platform} service target.
|
|
|
40088
41053
|
} else {
|
|
40089
41054
|
if (badUrl)
|
|
40090
41055
|
write([kit.fail(badUrl)]);
|
|
40091
|
-
const
|
|
40092
|
-
if (
|
|
41056
|
+
const chosen = await chooseConnection();
|
|
41057
|
+
if (chosen === null)
|
|
40093
41058
|
return cancel();
|
|
40094
|
-
cloud =
|
|
41059
|
+
cloud = chosen;
|
|
40095
41060
|
}
|
|
40096
41061
|
const fp = readConfig();
|
|
40097
41062
|
const hookedNow = INTEGRATION_TYPES.filter((id) => hookedAtUserScope(id, cwd));
|
|
40098
41063
|
const plan = planAgents({ detected: detectInstalledClis(), saved: fp.agents, hooked: hookedNow });
|
|
40099
|
-
const
|
|
40100
|
-
const
|
|
41064
|
+
const connecting = cloud.kind === "connect" || cloud.kind === "login";
|
|
41065
|
+
const collectingAfter = connecting || readIngestCredential() !== null;
|
|
41066
|
+
const sessionsOn = connecting ? answers.noTranscripts !== true : fp.collector.sessions === true;
|
|
40101
41067
|
let selected;
|
|
40102
41068
|
if (answers.agents && answers.agents.length > 0) {
|
|
40103
41069
|
const named = new Set(answers.agents);
|
|
@@ -40129,6 +41095,27 @@ ${process.platform} service target.
|
|
|
40129
41095
|
const { added, removed } = agentChanges(plan, selected);
|
|
40130
41096
|
const done = [];
|
|
40131
41097
|
let daemonInstalled = daemonAlreadyRunning;
|
|
41098
|
+
if ((daemonWanted || daemonUnitStale) && !unattended) {
|
|
41099
|
+
let stillRoot = false;
|
|
41100
|
+
try {
|
|
41101
|
+
stillRoot = canElevate();
|
|
41102
|
+
} catch {
|
|
41103
|
+
stillRoot = false;
|
|
41104
|
+
}
|
|
41105
|
+
if (!stillRoot && daemonWanted) {
|
|
41106
|
+
if (!elevate("Your sudo session expired while you were away. Installing failproofaid needs root again.")) {
|
|
41107
|
+
write([
|
|
41108
|
+
kit.fail("Couldn't get root, so setup stopped before changing anything."),
|
|
41109
|
+
` Re-run once you can use sudo: ${kit.cmd("failproofai config")}`
|
|
41110
|
+
]);
|
|
41111
|
+
emit("configure_aborted", { reason: "needs_root" });
|
|
41112
|
+
return { applied: false, abort: "needs_root" };
|
|
41113
|
+
}
|
|
41114
|
+
} else if (!stillRoot && !elevate("Your sudo session expired while you were away. Refreshing failproofaid's service definition needs root again.")) {
|
|
41115
|
+
done.push(kit.caution("No root, so its service definition stays as it is. Scheduled audits stay off until it is refreshed."));
|
|
41116
|
+
daemonUnitStale = false;
|
|
41117
|
+
}
|
|
41118
|
+
}
|
|
40132
41119
|
if (daemonWanted) {
|
|
40133
41120
|
if (daemonBroken) {
|
|
40134
41121
|
await transient("Removing the failproofaid service that can't start…", async () => {
|
|
@@ -40195,39 +41182,47 @@ ${process.platform} service target.
|
|
|
40195
41182
|
setDaemonConfigured(true, version2);
|
|
40196
41183
|
pruneOldDaemonBinaries();
|
|
40197
41184
|
}
|
|
40198
|
-
const connectedAfterPlan = cloud.kind === "connect" || cloud.kind === "kept";
|
|
40199
|
-
const applied = emit("configure_applied", {
|
|
40200
|
-
target: "user",
|
|
40201
|
-
scopes: ["user"],
|
|
40202
|
-
cli: selected,
|
|
40203
|
-
cli_count: selected.length,
|
|
40204
|
-
policy_count: (readScopedHooksConfig("user", cwd).enabledPolicies ?? []).length,
|
|
40205
|
-
connected: cloud.kind === "connect",
|
|
40206
|
-
mode: connectedAfterPlan ? "cloud" : "oss",
|
|
40207
|
-
agents_selected: selected.length,
|
|
40208
|
-
agents_detected: plan.detected.size,
|
|
40209
|
-
agents_changed: added.length + removed.length > 0
|
|
40210
|
-
});
|
|
40211
41185
|
const policies = readScopedHooksConfig("user", cwd).enabledPolicies ?? [];
|
|
40212
41186
|
if (selected.length > 0)
|
|
40213
41187
|
await transient("Installing hooks…", () => installHooks(policies, "user", cwd, false, "configure-wizard", undefined, false, selected, { replace: true, quiet: true }));
|
|
40214
41188
|
removeUserScopeHooks(INTEGRATION_TYPES.filter((id) => !selected.includes(id) && (plan.baseline.has(id) || hookedNow.includes(id))), cwd);
|
|
41189
|
+
installAgentSkill(INTEGRATION_TYPES.filter((id) => plan.detected.has(id) || selected.includes(id)));
|
|
40215
41190
|
requestFreshStart(plan.mode === "rerun" ? added : [], collectingAfter && sessionsOn);
|
|
40216
41191
|
updateConfig({ agents: { selected, seen: plan.seen } });
|
|
40217
41192
|
let connected = false;
|
|
40218
|
-
|
|
40219
|
-
|
|
41193
|
+
let token = cloud.kind === "connect" ? cloud.token : null;
|
|
41194
|
+
let orgLabel = cloud.kind === "connect" ? cloud.org : undefined;
|
|
41195
|
+
let mintedName;
|
|
41196
|
+
let claimedOrg;
|
|
41197
|
+
if (cloud.kind === "login" && url) {
|
|
41198
|
+
const claimed = await transient("Creating this machine's key…", () => claimLogin(url, cloud.pollSecret));
|
|
41199
|
+
emit("configure_cloud_login", { step: "claimed", ok: claimed.kind === "ok", reason: claimed.kind });
|
|
41200
|
+
if (claimed.kind === "ok") {
|
|
41201
|
+
token = claimed.key;
|
|
41202
|
+
orgLabel = loginOrgLabel(claimed.org);
|
|
41203
|
+
mintedName = claimed.keyName;
|
|
41204
|
+
claimedOrg = claimed.org;
|
|
41205
|
+
} else {
|
|
41206
|
+
hookLogWarn(`cloud login could not be completed: ${claimed.kind}`);
|
|
41207
|
+
done.push(kit.caution(claimed.kind === "expired" ? "The login took too long to finish, so no key was created. Everything else was applied." : claimed.kind === "revoked" ? "Whoever approved the login can no longer create keys in that org, so no key was created." : claimed.kind === "unreachable" ? `Couldn't reach ${host} to create the key (${claimed.reason}); everything else was applied.` : `The key couldn't be created: ${claimed.reason}. Everything else was applied.`, "failproofai config"));
|
|
41208
|
+
}
|
|
41209
|
+
}
|
|
41210
|
+
if (token && url) {
|
|
40220
41211
|
try {
|
|
40221
41212
|
const outcome = await transient("Connecting…", () => connectToCloud({
|
|
40222
41213
|
url,
|
|
40223
41214
|
token,
|
|
40224
41215
|
machineId,
|
|
40225
41216
|
machineLabel,
|
|
40226
|
-
sessions: answers.noTranscripts !== true
|
|
41217
|
+
sessions: answers.noTranscripts !== true,
|
|
41218
|
+
org: claimedOrg
|
|
40227
41219
|
}));
|
|
40228
41220
|
connected = outcome.anyConfigured;
|
|
40229
41221
|
done.push(...outcome.changes ?? []);
|
|
40230
|
-
done.push(...connectDoneLines(kit, outcome, host,
|
|
41222
|
+
done.push(...connectDoneLines(kit, outcome, host, orgLabel));
|
|
41223
|
+
if (cloud.kind === "login" && saved && connected) {
|
|
41224
|
+
done.push(` Your previous key for this machine still works until you revoke it on ${host}'s keys page.`);
|
|
41225
|
+
}
|
|
40231
41226
|
if (outcome.ingest.ok && answers.noTranscripts === true) {
|
|
40232
41227
|
done.push(" Decisions only: session transcripts are not sent (--no-transcripts).");
|
|
40233
41228
|
}
|
|
@@ -40236,10 +41231,29 @@ ${process.platform} service target.
|
|
|
40236
41231
|
hookLogWarn(`cloud connection was not written: ${err instanceof Error ? err.message : String(err)}`);
|
|
40237
41232
|
done.push(kit.caution("Couldn't connect; everything else was applied.", "failproofai config"));
|
|
40238
41233
|
}
|
|
41234
|
+
if (cloud.kind === "login" && !connected) {
|
|
41235
|
+
done.push(` The key ${mintedName ? `"${mintedName}" ` : ""}was created but isn't in use here; revoke it on ${host}'s keys page.`);
|
|
41236
|
+
}
|
|
40239
41237
|
} else if (cloud.kind === "kept" && cloud.how === "saved" && fp.mode !== "cloud") {
|
|
40240
41238
|
updateConfig({ mode: "cloud" });
|
|
40241
41239
|
}
|
|
40242
|
-
|
|
41240
|
+
const keptOld = cloud.kind === "login" && !connected && Boolean(saved);
|
|
41241
|
+
if (keptOld) {
|
|
41242
|
+
done.push(savedRefused ? " This machine keeps its previous connection, but its key no longer works. Run failproofai config again to log in." : " This machine keeps its previous connection.");
|
|
41243
|
+
}
|
|
41244
|
+
const cloudAfter = connected || cloud.kind === "kept" || keptOld;
|
|
41245
|
+
await emit("configure_applied", {
|
|
41246
|
+
target: "user",
|
|
41247
|
+
scopes: ["user"],
|
|
41248
|
+
cli: selected,
|
|
41249
|
+
cli_count: selected.length,
|
|
41250
|
+
policy_count: policies.length,
|
|
41251
|
+
connected,
|
|
41252
|
+
mode: cloudAfter ? "cloud" : "oss",
|
|
41253
|
+
agents_selected: selected.length,
|
|
41254
|
+
agents_detected: plan.detected.size,
|
|
41255
|
+
agents_changed: added.length + removed.length > 0
|
|
41256
|
+
});
|
|
40243
41257
|
markLauncherSeen();
|
|
40244
41258
|
clearOnboardingAttempt();
|
|
40245
41259
|
const codexTrust = selected.includes("codex") ? codexHookTrust() : undefined;
|
|
@@ -40248,7 +41262,7 @@ ${process.platform} service target.
|
|
|
40248
41262
|
done,
|
|
40249
41263
|
cwd,
|
|
40250
41264
|
agents: selected.length,
|
|
40251
|
-
connected:
|
|
41265
|
+
connected: cloudAfter,
|
|
40252
41266
|
codexTrust
|
|
40253
41267
|
}));
|
|
40254
41268
|
return {
|
|
@@ -40259,10 +41273,15 @@ ${process.platform} service target.
|
|
|
40259
41273
|
policies,
|
|
40260
41274
|
daemonInstalled,
|
|
40261
41275
|
connected,
|
|
40262
|
-
mode:
|
|
41276
|
+
mode: cloudAfter ? "cloud" : "oss",
|
|
40263
41277
|
agents: { selected, added, removed }
|
|
40264
41278
|
};
|
|
40265
41279
|
}
|
|
41280
|
+
function loginOrgLabel(org) {
|
|
41281
|
+
if (org.name && org.slug)
|
|
41282
|
+
return `${org.name} (${org.slug})`;
|
|
41283
|
+
return org.name ?? org.slug ?? "your org";
|
|
41284
|
+
}
|
|
40266
41285
|
function savedConnection() {
|
|
40267
41286
|
const cloud = readCloudCredentials();
|
|
40268
41287
|
const ingest = readIngestCredential();
|
|
@@ -40289,8 +41308,12 @@ function resolveCloudUrl(flag, existing) {
|
|
|
40289
41308
|
const env = process.env.FAILPROOFAI_CLOUD_URL?.trim();
|
|
40290
41309
|
const fromFlag = flag?.trim();
|
|
40291
41310
|
const override = fromFlag || env;
|
|
40292
|
-
if (!override)
|
|
40293
|
-
|
|
41311
|
+
if (!override) {
|
|
41312
|
+
if (!existing)
|
|
41313
|
+
return { ok: true, url: cloudBaseFor2(DEFAULT_INGEST_URL) };
|
|
41314
|
+
const saved = validateCloudUrl(existing);
|
|
41315
|
+
return saved.ok ? { ok: true, url: existing } : { ok: false, message: `the saved cloud address "${existing}" cannot be used: ${saved.reason}` };
|
|
41316
|
+
}
|
|
40294
41317
|
const source = fromFlag && fromFlag !== env ? "--url" : "FAILPROOFAI_CLOUD_URL";
|
|
40295
41318
|
const validated = validateCloudUrl(cloudBaseFor2(override));
|
|
40296
41319
|
if (!validated.ok) {
|
|
@@ -40309,6 +41332,9 @@ function hostOf(url) {
|
|
|
40309
41332
|
}
|
|
40310
41333
|
}
|
|
40311
41334
|
async function checkCloudKey(url, key) {
|
|
41335
|
+
const target = validateCloudUrl(url);
|
|
41336
|
+
if (!target.ok)
|
|
41337
|
+
return { ok: false, refused: false, reason: `the address ${url} can't be used: ${target.reason}` };
|
|
40312
41338
|
const identity = await introspectKey(url, key);
|
|
40313
41339
|
if (identity.kind === "rejected")
|
|
40314
41340
|
return { ok: false, refused: true, reason: "the server did not accept it" };
|
|
@@ -40345,6 +41371,11 @@ function cloudCollapsedLines(kit, plan, at) {
|
|
|
40345
41371
|
kit.ok(plan.org ? `Key accepted for ${plan.org} on ${at.host}` : `Key accepted by ${at.host}`),
|
|
40346
41372
|
...plan.note ? [kit.caution(plan.note)] : []
|
|
40347
41373
|
];
|
|
41374
|
+
case "login":
|
|
41375
|
+
return [
|
|
41376
|
+
head,
|
|
41377
|
+
kit.ok(`Logged in${plan.approvedBy ? ` as ${plan.approvedBy}` : ""} · ${loginOrgLabel(plan.org)} on ${at.host}`)
|
|
41378
|
+
];
|
|
40348
41379
|
}
|
|
40349
41380
|
}
|
|
40350
41381
|
function connectDoneLines(kit, outcome, host, org) {
|
|
@@ -40401,10 +41432,13 @@ function doneLines(kit, state) {
|
|
|
40401
41432
|
var init_configure_wizard = __esm(() => {
|
|
40402
41433
|
init_pack_store();
|
|
40403
41434
|
init_tui();
|
|
41435
|
+
init_cloud_login();
|
|
41436
|
+
init_open_browser();
|
|
40404
41437
|
init_collector_config();
|
|
40405
41438
|
init_integrations();
|
|
40406
41439
|
init_types();
|
|
40407
41440
|
init_manager();
|
|
41441
|
+
init_agent_skill();
|
|
40408
41442
|
init_codex_system_hooks();
|
|
40409
41443
|
init_pack_manifest();
|
|
40410
41444
|
init_hooks_config();
|
|
@@ -40415,6 +41449,7 @@ var init_configure_wizard = __esm(() => {
|
|
|
40415
41449
|
init_hook_logger();
|
|
40416
41450
|
init_cloud_enrollment();
|
|
40417
41451
|
init_cloud_connection();
|
|
41452
|
+
init_cloud_introspect();
|
|
40418
41453
|
init_fp_config();
|
|
40419
41454
|
init_backfill_request();
|
|
40420
41455
|
init_agent_selection();
|
|
@@ -40427,18 +41462,18 @@ var init_configure_wizard = __esm(() => {
|
|
|
40427
41462
|
});
|
|
40428
41463
|
|
|
40429
41464
|
// src/hooks/flush-cli.ts
|
|
40430
|
-
import { existsSync as
|
|
40431
|
-
import { dirname as dirname26, join as
|
|
41465
|
+
import { existsSync as existsSync50, mkdirSync as mkdirSync29, writeFileSync as writeFileSync24, readdirSync as readdirSync22, statSync as statSync36 } from "node:fs";
|
|
41466
|
+
import { dirname as dirname26, join as join42 } from "node:path";
|
|
40432
41467
|
function flushRequestPath2(home) {
|
|
40433
|
-
return
|
|
41468
|
+
return join42(failproofaiHome(home), "state", "flush-request.json");
|
|
40434
41469
|
}
|
|
40435
41470
|
function spoolDirs2(home) {
|
|
40436
41471
|
const root = spoolDir(home);
|
|
40437
41472
|
const dirs = [root, customAgentsEventsDir(home)];
|
|
40438
|
-
if (!
|
|
41473
|
+
if (!existsSync50(root))
|
|
40439
41474
|
return dirs;
|
|
40440
41475
|
try {
|
|
40441
|
-
return dirs.concat(readdirSync22(root, { withFileTypes: true }).filter((e) => e.isDirectory() && e.name !== "failed").map((e) =>
|
|
41476
|
+
return dirs.concat(readdirSync22(root, { withFileTypes: true }).filter((e) => e.isDirectory() && e.name !== "failed").map((e) => join42(root, e.name)));
|
|
40442
41477
|
} catch {
|
|
40443
41478
|
return dirs;
|
|
40444
41479
|
}
|
|
@@ -40469,7 +41504,7 @@ function spoolBacklog2(home, now = Date.now()) {
|
|
|
40469
41504
|
count += names.length;
|
|
40470
41505
|
for (const name of names) {
|
|
40471
41506
|
try {
|
|
40472
|
-
const mtime = statSync36(
|
|
41507
|
+
const mtime = statSync36(join42(dir, name)).mtimeMs;
|
|
40473
41508
|
if (oldest === undefined || mtime < oldest)
|
|
40474
41509
|
oldest = mtime;
|
|
40475
41510
|
} catch {}
|
|
@@ -40531,7 +41566,7 @@ async function runFlushCommand2(opts = {}) {
|
|
|
40531
41566
|
return { exitCode: 0, pending: 0, lines: nothing };
|
|
40532
41567
|
}
|
|
40533
41568
|
const path = flushRequestPath2(home);
|
|
40534
|
-
|
|
41569
|
+
mkdirSync29(dirname26(path), { recursive: true });
|
|
40535
41570
|
writeFileSync24(path, `${JSON.stringify({ requestedAtMs: Date.now() }, null, 2)}
|
|
40536
41571
|
`, {
|
|
40537
41572
|
mode: 384
|
|
@@ -40565,7 +41600,7 @@ var init_flush_cli2 = __esm(() => {
|
|
|
40565
41600
|
});
|
|
40566
41601
|
|
|
40567
41602
|
// src/hooks/backfill-cli.ts
|
|
40568
|
-
import { existsSync as
|
|
41603
|
+
import { existsSync as existsSync51 } from "node:fs";
|
|
40569
41604
|
async function adapterSessionCount(cli, sinceMs) {
|
|
40570
41605
|
try {
|
|
40571
41606
|
return (await getAdapter(cli).listTranscripts({ sinceMs })).length;
|
|
@@ -40583,7 +41618,7 @@ async function runBackfillCommand(opts = {}) {
|
|
|
40583
41618
|
const sinceLabel = new Date(sinceMs).toISOString().slice(0, 10);
|
|
40584
41619
|
const home = failproofaiHome();
|
|
40585
41620
|
const fail = (text, ...fix) => ({ exitCode: 1, lines: [kit.fail(text), ...fix] });
|
|
40586
|
-
if (!
|
|
41621
|
+
if (!existsSync51(home)) {
|
|
40587
41622
|
return fail(`There is no failproofai home at ${home}.`, ` Set this machine up first: ${kit.cmd("failproofai config")}`);
|
|
40588
41623
|
}
|
|
40589
41624
|
if (!readIngestCredential()) {
|
|
@@ -43058,20 +44093,20 @@ var init_main = __esm(() => {
|
|
|
43058
44093
|
});
|
|
43059
44094
|
|
|
43060
44095
|
// src/hooks/otel-writers.ts
|
|
43061
|
-
import { homedir as
|
|
43062
|
-
import { resolve as
|
|
44096
|
+
import { homedir as homedir35 } from "node:os";
|
|
44097
|
+
import { resolve as resolve35 } from "node:path";
|
|
43063
44098
|
import { accessSync as accessSync2, constants, readdirSync as readdirSync23, statSync as statSync37 } from "node:fs";
|
|
43064
|
-
function vscodeSettingsPath(home =
|
|
44099
|
+
function vscodeSettingsPath(home = homedir35(), platform = process.platform) {
|
|
43065
44100
|
if (platform === "darwin")
|
|
43066
|
-
return
|
|
44101
|
+
return resolve35(home, "Library/Application Support/Code/User/settings.json");
|
|
43067
44102
|
if (platform === "win32")
|
|
43068
|
-
return
|
|
43069
|
-
return
|
|
44103
|
+
return resolve35(process.env.APPDATA ?? resolve35(home, "AppData/Roaming"), "Code/User/settings.json");
|
|
44104
|
+
return resolve35(process.env.XDG_CONFIG_HOME ?? resolve35(home, ".config"), "Code/User/settings.json");
|
|
43070
44105
|
}
|
|
43071
|
-
function agentConfigPath(agent, home =
|
|
43072
|
-
return agent === "copilot" ? vscodeSettingsPath(home) :
|
|
44106
|
+
function agentConfigPath(agent, home = homedir35()) {
|
|
44107
|
+
return agent === "copilot" ? vscodeSettingsPath(home) : resolve35(home, `.${agent}`, agent === "codex" ? "config.toml" : "settings.json");
|
|
43073
44108
|
}
|
|
43074
|
-
function vscodeInstalled(home =
|
|
44109
|
+
function vscodeInstalled(home = homedir35(), platform = process.platform) {
|
|
43075
44110
|
const executable = (path) => {
|
|
43076
44111
|
try {
|
|
43077
44112
|
accessSync2(path, platform === "win32" ? constants.F_OK : constants.X_OK);
|
|
@@ -43081,13 +44116,13 @@ function vscodeInstalled(home = homedir34(), platform = process.platform) {
|
|
|
43081
44116
|
}
|
|
43082
44117
|
};
|
|
43083
44118
|
const names = platform === "win32" ? ["code.cmd", "code-insiders.cmd", "Code.exe", "Code - Insiders.exe"] : ["code", "code-insiders"];
|
|
43084
|
-
if ((process.env.PATH ?? "").split(platform === "win32" ? ";" : ":").some((dir) => names.some((name) => executable(
|
|
44119
|
+
if ((process.env.PATH ?? "").split(platform === "win32" ? ";" : ":").some((dir) => names.some((name) => executable(resolve35(dir, name)))))
|
|
43085
44120
|
return true;
|
|
43086
44121
|
if (vscodeProbe.appPaths(home, platform).some(executable))
|
|
43087
44122
|
return true;
|
|
43088
44123
|
return [".vscode", ".vscode-insiders"].some((folder) => {
|
|
43089
44124
|
try {
|
|
43090
|
-
return readdirSync23(
|
|
44125
|
+
return readdirSync23(resolve35(home, folder, "extensions"), { withFileTypes: true }).some((entry) => entry.isDirectory() && /^github\.copilot(?:-chat)?-\d/i.test(entry.name));
|
|
43091
44126
|
} catch {
|
|
43092
44127
|
return false;
|
|
43093
44128
|
}
|
|
@@ -43295,10 +44330,10 @@ var init_otel_writers = __esm(() => {
|
|
|
43295
44330
|
return platform === "darwin" ? [
|
|
43296
44331
|
"/Applications/Visual Studio Code.app/Contents/MacOS/Electron",
|
|
43297
44332
|
"/Applications/Visual Studio Code - Insiders.app/Contents/MacOS/Electron",
|
|
43298
|
-
|
|
44333
|
+
resolve35(home, "Applications/Visual Studio Code.app/Contents/MacOS/Electron")
|
|
43299
44334
|
] : platform === "win32" ? [
|
|
43300
|
-
|
|
43301
|
-
|
|
44335
|
+
resolve35(process.env.LOCALAPPDATA ?? resolve35(home, "AppData/Local"), "Programs/Microsoft VS Code/Code.exe"),
|
|
44336
|
+
resolve35(process.env.ProgramFiles ?? "C:/Program Files", "Microsoft VS Code/Code.exe")
|
|
43302
44337
|
] : ["/usr/share/code/code", "/opt/visual-studio-code/code"];
|
|
43303
44338
|
}
|
|
43304
44339
|
};
|
|
@@ -43307,16 +44342,16 @@ var init_otel_writers = __esm(() => {
|
|
|
43307
44342
|
// src/hooks/otel-cli.ts
|
|
43308
44343
|
import {
|
|
43309
44344
|
chmodSync as chmodSync11,
|
|
43310
|
-
existsSync as
|
|
43311
|
-
mkdirSync as
|
|
43312
|
-
readFileSync as
|
|
44345
|
+
existsSync as existsSync52,
|
|
44346
|
+
mkdirSync as mkdirSync30,
|
|
44347
|
+
readFileSync as readFileSync42,
|
|
43313
44348
|
statSync as statSync38,
|
|
43314
44349
|
unlinkSync as unlinkSync8,
|
|
43315
44350
|
writeFileSync as writeFileSync25
|
|
43316
44351
|
} from "node:fs";
|
|
43317
44352
|
import { dirname as dirname27 } from "node:path";
|
|
43318
44353
|
import { createHash as createHash13, randomUUID as randomUUID6 } from "node:crypto";
|
|
43319
|
-
import { homedir as
|
|
44354
|
+
import { homedir as homedir36 } from "node:os";
|
|
43320
44355
|
import { connect } from "node:net";
|
|
43321
44356
|
function rawConfig() {
|
|
43322
44357
|
return readJsonFile(configFile());
|
|
@@ -43346,7 +44381,7 @@ async function waitForCollectorConfig(generation, timeoutMs) {
|
|
|
43346
44381
|
const deadline = Date.now() + timeoutMs;
|
|
43347
44382
|
do {
|
|
43348
44383
|
try {
|
|
43349
|
-
const health = JSON.parse(
|
|
44384
|
+
const health = JSON.parse(readFileSync42(collectorHealthFile(), "utf8"));
|
|
43350
44385
|
if (health.config_generation === generation && typeof health.ts === "number" && Date.now() - health.ts * 1000 < 35000)
|
|
43351
44386
|
return true;
|
|
43352
44387
|
} catch {}
|
|
@@ -43355,7 +44390,7 @@ async function waitForCollectorConfig(generation, timeoutMs) {
|
|
|
43355
44390
|
return false;
|
|
43356
44391
|
}
|
|
43357
44392
|
function privateState(agent) {
|
|
43358
|
-
return JSON.parse(
|
|
44393
|
+
return JSON.parse(readFileSync42(otelAgentStateFile(agent), "utf8"));
|
|
43359
44394
|
}
|
|
43360
44395
|
function credential() {
|
|
43361
44396
|
const ingest = readCredentials().ingest;
|
|
@@ -43372,15 +44407,15 @@ function credential() {
|
|
|
43372
44407
|
return { key, origin: url.origin };
|
|
43373
44408
|
}
|
|
43374
44409
|
function backupOnce(path, original) {
|
|
43375
|
-
if (
|
|
44410
|
+
if (existsSync52(`${path}.failproofai-bak`))
|
|
43376
44411
|
return;
|
|
43377
|
-
|
|
44412
|
+
mkdirSync30(dirname27(path), { recursive: true });
|
|
43378
44413
|
writeFileSync25(`${path}.failproofai-bak`, original ?? "", { flag: "wx", mode: 384 });
|
|
43379
44414
|
chmodSync11(`${path}.failproofai-bak`, 384);
|
|
43380
44415
|
}
|
|
43381
44416
|
function savePrivate(agent, state) {
|
|
43382
44417
|
const path = otelAgentStateFile(agent);
|
|
43383
|
-
|
|
44418
|
+
mkdirSync30(dirname27(path), { recursive: true, mode: 448 });
|
|
43384
44419
|
writeConfigFileAtomic(path, JSON.stringify(state), { backup: false, mode: 384 });
|
|
43385
44420
|
chmodSync11(path, 384);
|
|
43386
44421
|
}
|
|
@@ -43419,8 +44454,8 @@ function restoreAgent(agent, raw) {
|
|
|
43419
44454
|
if (!record)
|
|
43420
44455
|
return;
|
|
43421
44456
|
const state = privateState(agent);
|
|
43422
|
-
if (
|
|
43423
|
-
const current =
|
|
44457
|
+
if (existsSync52(record.file)) {
|
|
44458
|
+
const current = readFileSync42(record.file, "utf8");
|
|
43424
44459
|
if (digest(current) === state.writtenHash) {
|
|
43425
44460
|
if (state.original === null)
|
|
43426
44461
|
unlinkSync8(record.file);
|
|
@@ -43459,8 +44494,8 @@ async function enableAgent(agent, yes, localFlag, content, options) {
|
|
|
43459
44494
|
const { key, origin } = credential();
|
|
43460
44495
|
const raw = rawConfig();
|
|
43461
44496
|
const previousConfig = structuredClone(raw);
|
|
43462
|
-
const file = agentConfigPath(agent, options.home ??
|
|
43463
|
-
if (agent === "copilot" && !vscodeInstalled(options.home ??
|
|
44497
|
+
const file = agentConfigPath(agent, options.home ?? homedir36());
|
|
44498
|
+
if (agent === "copilot" && !vscodeInstalled(options.home ?? homedir36())) {
|
|
43464
44499
|
return { lines: ["VS Code not found — skipping copilot"], exitCode: 0 };
|
|
43465
44500
|
}
|
|
43466
44501
|
const existing = records(raw)[agent];
|
|
@@ -43475,7 +44510,7 @@ async function enableAgent(agent, yes, localFlag, content, options) {
|
|
|
43475
44510
|
if (!Number.isInteger(port) || port < 1 || port > 65535)
|
|
43476
44511
|
throw new Error("collector.otlp.port must be between 1 and 65535.");
|
|
43477
44512
|
const destination = otlpDestination(origin, local, port);
|
|
43478
|
-
const original =
|
|
44513
|
+
const original = existsSync52(file) ? readFileSync42(file, "utf8") : null;
|
|
43479
44514
|
const parsed = parseAgentConfig(original ?? "", agent);
|
|
43480
44515
|
const oldState = existing ? privateState(agent) : null;
|
|
43481
44516
|
const privacyConfig = oldState && original !== null && digest(original) === oldState.writtenHash ? parseAgentConfig(oldState.original ?? "", agent) : parsed;
|
|
@@ -43537,7 +44572,7 @@ async function enableAgent(agent, yes, localFlag, content, options) {
|
|
|
43537
44572
|
} catch (err) {
|
|
43538
44573
|
if (original !== null)
|
|
43539
44574
|
writeConfigFileAtomic(file, original, { backup: false, mode: state.originalMode });
|
|
43540
|
-
else if (
|
|
44575
|
+
else if (existsSync52(file))
|
|
43541
44576
|
unlinkSync8(file);
|
|
43542
44577
|
saveConfig(previousConfig);
|
|
43543
44578
|
throw err;
|
|
@@ -43580,9 +44615,9 @@ async function status(options) {
|
|
|
43580
44615
|
let parsed = {};
|
|
43581
44616
|
let unreadable = false;
|
|
43582
44617
|
try {
|
|
43583
|
-
const file = record?.file ?? agentConfigPath(agent, options.home ??
|
|
43584
|
-
if (
|
|
43585
|
-
parsed = parseAgentConfig(
|
|
44618
|
+
const file = record?.file ?? agentConfigPath(agent, options.home ?? homedir36());
|
|
44619
|
+
if (existsSync52(file))
|
|
44620
|
+
parsed = parseAgentConfig(readFileSync42(file, "utf8"), agent);
|
|
43586
44621
|
} catch {
|
|
43587
44622
|
unreadable = true;
|
|
43588
44623
|
}
|
|
@@ -43604,7 +44639,7 @@ async function status(options) {
|
|
|
43604
44639
|
}
|
|
43605
44640
|
let health = {};
|
|
43606
44641
|
try {
|
|
43607
|
-
health = JSON.parse(
|
|
44642
|
+
health = JSON.parse(readFileSync42(otlpHealthFile(), "utf8"));
|
|
43608
44643
|
} catch {}
|
|
43609
44644
|
const requested = readConfig().collector.otlp?.enabled === true;
|
|
43610
44645
|
const live = requested && health.relay === "listening" && await relayListening(readConfig().collector.otlp?.port ?? 4318);
|
|
@@ -43691,6 +44726,7 @@ var init_otel_cli = __esm(() => {
|
|
|
43691
44726
|
init_fp_home();
|
|
43692
44727
|
init_safe_config_write();
|
|
43693
44728
|
init_collector_config();
|
|
44729
|
+
init_cloud_introspect();
|
|
43694
44730
|
init_cloud_enrollment();
|
|
43695
44731
|
init_integrations();
|
|
43696
44732
|
init_tui();
|
|
@@ -43704,6 +44740,7 @@ var init_otel_cli2 = __esm(() => {
|
|
|
43704
44740
|
init_fp_home();
|
|
43705
44741
|
init_safe_config_write();
|
|
43706
44742
|
init_collector_config();
|
|
44743
|
+
init_cloud_introspect();
|
|
43707
44744
|
init_cloud_enrollment();
|
|
43708
44745
|
init_integrations();
|
|
43709
44746
|
init_tui();
|
|
@@ -43741,8 +44778,8 @@ var init_otel_output = __esm(() => {
|
|
|
43741
44778
|
});
|
|
43742
44779
|
|
|
43743
44780
|
// src/hooks/harness-cli.ts
|
|
43744
|
-
import { homedir as
|
|
43745
|
-
import { resolve as
|
|
44781
|
+
import { homedir as homedir37 } from "node:os";
|
|
44782
|
+
import { resolve as resolve36 } from "node:path";
|
|
43746
44783
|
function unknownHarness(name) {
|
|
43747
44784
|
const kit = kitFor();
|
|
43748
44785
|
return fail([kit.fail(`Unknown harness: ${name}.`), ` Known: ${HARNESS_KEYS.join(", ")}`]);
|
|
@@ -43789,8 +44826,8 @@ function comparableLabel(raw) {
|
|
|
43789
44826
|
return raw.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
43790
44827
|
}
|
|
43791
44828
|
function comparablePath(raw) {
|
|
43792
|
-
const home =
|
|
43793
|
-
const expanded = raw === "~" ? home : raw.startsWith("~/") ?
|
|
44829
|
+
const home = homedir37();
|
|
44830
|
+
const expanded = raw === "~" ? home : raw.startsWith("~/") ? resolve36(home, raw.slice(2)) : raw;
|
|
43794
44831
|
return expanded.replace(/\/+$/, "");
|
|
43795
44832
|
}
|
|
43796
44833
|
function effectiveLabel(entry) {
|
|
@@ -43948,7 +44985,7 @@ var init_harness_cli = __esm(() => {
|
|
|
43948
44985
|
});
|
|
43949
44986
|
|
|
43950
44987
|
// src/hooks/policy-reviewability.ts
|
|
43951
|
-
import { resolve as
|
|
44988
|
+
import { resolve as resolve37 } from "node:path";
|
|
43952
44989
|
function countReviewable(policies, knownReviewers) {
|
|
43953
44990
|
let enabled = 0;
|
|
43954
44991
|
let reviewable = 0;
|
|
@@ -43986,7 +45023,7 @@ function surveyReviewableCoverage(cwd) {
|
|
|
43986
45023
|
}
|
|
43987
45024
|
try {
|
|
43988
45025
|
const mode = readCloudJevMode();
|
|
43989
|
-
const assignments =
|
|
45026
|
+
const assignments = listActiveCloudManagedPolicies();
|
|
43990
45027
|
const cloudReviewers = cloudReviewerNames(assignments, mode);
|
|
43991
45028
|
if (cloudReviewers.length > 0)
|
|
43992
45029
|
reviewers = new Set([...reviewers ?? [], ...cloudReviewers]);
|
|
@@ -43996,9 +45033,9 @@ function surveyReviewableCoverage(cwd) {
|
|
|
43996
45033
|
let customFiles = 0;
|
|
43997
45034
|
try {
|
|
43998
45035
|
const projectRoot = findProjectConfigDir(cwd ?? process.cwd());
|
|
43999
|
-
const files = new Set(configuredCustomPolicyPaths(config).map((p) =>
|
|
45036
|
+
const files = new Set(configuredCustomPolicyPaths(config).map((p) => resolve37(projectRoot, p)));
|
|
44000
45037
|
if (config.customPoliciesEnabled !== false) {
|
|
44001
|
-
const projectDir =
|
|
45038
|
+
const projectDir = resolve37(projectRoot, ".failproofai", "policies");
|
|
44002
45039
|
for (const dir of [projectDir, customPoliciesDir()])
|
|
44003
45040
|
for (const f of discoverPolicyFiles(dir))
|
|
44004
45041
|
files.add(f);
|
|
@@ -44161,7 +45198,7 @@ var init_jev_stats = __esm(() => {
|
|
|
44161
45198
|
});
|
|
44162
45199
|
|
|
44163
45200
|
// src/hooks/jev-cli.ts
|
|
44164
|
-
import { chmodSync as chmodSync12, existsSync as
|
|
45201
|
+
import { chmodSync as chmodSync12, existsSync as existsSync53, statSync as statSync39, unlinkSync as unlinkSync9 } from "node:fs";
|
|
44165
45202
|
import { dirname as dirname28 } from "node:path";
|
|
44166
45203
|
function jevHeader(name, meta, opts) {
|
|
44167
45204
|
return [screenKit(opts).header(meta ? `${name} · ${meta}` : name)];
|
|
@@ -44264,7 +45301,7 @@ function cloudKeyRow() {
|
|
|
44264
45301
|
function octal(mode) {
|
|
44265
45302
|
return mode === null ? null : mode.toString(8).padStart(4, "0");
|
|
44266
45303
|
}
|
|
44267
|
-
function
|
|
45304
|
+
function permissions2(mode) {
|
|
44268
45305
|
if (mode === null)
|
|
44269
45306
|
return "unknown";
|
|
44270
45307
|
return (mode & 63) === 0 ? `${octal(mode)} (owner-only)` : `${octal(mode)} (too open)`;
|
|
@@ -44476,6 +45513,8 @@ async function setupRun(argv, deps, opts) {
|
|
|
44476
45513
|
if (parsed.positionals.length > 0)
|
|
44477
45514
|
return fail2([STRAY_ARGUMENT, "", ...JEV_USAGE]);
|
|
44478
45515
|
const { values, bools } = parsed;
|
|
45516
|
+
if (values.has("--mode") && cloudManagesJevMode())
|
|
45517
|
+
return fail2(CLOUD_MANAGED_MODE_LINES);
|
|
44479
45518
|
if (bools.has("--key-stdin") && bools.has("--key-from-env"))
|
|
44480
45519
|
return fail2(["Use one of --key-stdin and --key-from-env, not both."]);
|
|
44481
45520
|
if (values.has("--token") && (bools.has("--key-stdin") || bools.has("--key-from-env"))) {
|
|
@@ -44765,7 +45804,7 @@ async function setupRun(argv, deps, opts) {
|
|
|
44765
45804
|
["timeout", `${cfg.timeoutMs} ms`],
|
|
44766
45805
|
["key", keyNote],
|
|
44767
45806
|
["config", path],
|
|
44768
|
-
["permissions",
|
|
45807
|
+
["permissions", permissions2(fileMode)]
|
|
44769
45808
|
], opts), offBase ? jevWarn([
|
|
44770
45809
|
`Saved as given, but ${provider}'s API is at ${offBase.api}, and this URL sends requests to ${offBase.endpoint} instead.`,
|
|
44771
45810
|
`Unless something of yours answers Jev requests at that path, every evaluation will fail there and hooks will fall back to regex — \`failproofai jev test\` says which it is in one request. To send requests back to ${provider}'s own API: failproofai jev setup --base-url default`
|
|
@@ -44890,7 +45929,7 @@ async function cloudSetup(values, bools, opts) {
|
|
|
44890
45929
|
["timeout", `${cfg.timeoutMs} ms`],
|
|
44891
45930
|
["key", keySource ? CLOUD_KEY_SOURCE : cloudKeyRow()],
|
|
44892
45931
|
["config", path],
|
|
44893
|
-
["permissions",
|
|
45932
|
+
["permissions", permissions2(fileMode)]
|
|
44894
45933
|
], opts), jevNote("Hooks read this file on every tool call — no restart. Calls are charged to your FailproofAI Cloud org's plan.", opts), shownMode === "off" ? null : keySource ? jevNext("failproofai jev test", "Check it with one live request:", opts) : jevNext("failproofai config --token <key>", `Jev stays off until this machine is connected with a key that carries jev:evaluate (the "machine" preset on the dashboard's Keys page):`, opts)));
|
|
44895
45934
|
}
|
|
44896
45935
|
function routeForRouting(routing) {
|
|
@@ -44954,12 +45993,6 @@ function cloudProblemAdvice(problem) {
|
|
|
44954
45993
|
"To use FailproofAI Cloud's Jev checks, reconnect without --no-transcripts (failproofai config --token <key>)."
|
|
44955
45994
|
];
|
|
44956
45995
|
}
|
|
44957
|
-
if (/plain http/.test(problem)) {
|
|
44958
|
-
return [
|
|
44959
|
-
"Jev does not run here: FailproofAI Cloud set enforce, and this machine is connected over plain http, where Jev runs only in observe mode.",
|
|
44960
|
-
"Reconnect to an https FailproofAI Cloud URL (failproofai config --token <key> --url https://…), or set the machine's Jev mode to observe from FailproofAI Cloud."
|
|
44961
|
-
];
|
|
44962
|
-
}
|
|
44963
45996
|
return [
|
|
44964
45997
|
`Jev cannot run here: ${problem}.`,
|
|
44965
45998
|
"Connect with a key that carries jev:evaluate (failproofai config --token <key>). A local jev.json is not used while FailproofAI Cloud sets the mode."
|
|
@@ -45158,7 +46191,7 @@ The daemon does not see this shell's environment.`) : [];
|
|
|
45158
46191
|
...route ? [["endpoint", displayEndpoint(route.endpoint)]] : [],
|
|
45159
46192
|
["mode", modeLine(inspection.routing.mode ?? DEFAULT_JEV_MODE)],
|
|
45160
46193
|
["key", `from ${JEV_API_KEY_ENV}, not set in this shell; the daemon never sees a shell's environment`],
|
|
45161
|
-
["config", `${inspection.path}${kit.sep}${
|
|
46194
|
+
["config", `${inspection.path}${kit.sep}${permissions2(inspection.mode)}`]
|
|
45162
46195
|
], [legacyNote], [step(`Set ${JEV_API_KEY_ENV} for this shell, or store the key in the file:`, "failproofai jev setup --key-stdin < key-file")]));
|
|
45163
46196
|
}
|
|
45164
46197
|
if (inspection.status === "off") {
|
|
@@ -45225,7 +46258,7 @@ The daemon does not see this shell's environment.`) : [];
|
|
|
45225
46258
|
"key",
|
|
45226
46259
|
inspection.keySource === "cloud" ? CLOUD_KEY_SOURCE : inspection.keySource === "file" ? "set in the config file" : `from ${JEV_API_KEY_ENV} (this shell only; the daemon does not see it)`
|
|
45227
46260
|
],
|
|
45228
|
-
["config", `${inspection.path}${kit.sep}${
|
|
46261
|
+
["config", `${inspection.path}${kit.sep}${permissions2(inspection.mode)}`],
|
|
45229
46262
|
...coverage ? [["reviewable", reviewableSummary(coverage)]] : []
|
|
45230
46263
|
], [coverageProblem ? kit.notice("caution", coverageProblem) : [], legacyNote], []));
|
|
45231
46264
|
}
|
|
@@ -45434,7 +46467,7 @@ function remove(argv, opts) {
|
|
|
45434
46467
|
if (parsed.positionals.length > 0)
|
|
45435
46468
|
return fail2([STRAY_ARGUMENT, "", ...JEV_USAGE]);
|
|
45436
46469
|
const path = jevConfigPath();
|
|
45437
|
-
if (!
|
|
46470
|
+
if (!existsSync53(path)) {
|
|
45438
46471
|
return ok2(stack(jevHeader("Jev remove", "nothing to do", opts), jevNote(`There is no ${path}; Jev is already off.`, opts)));
|
|
45439
46472
|
}
|
|
45440
46473
|
try {
|
|
@@ -45470,7 +46503,7 @@ async function runJevCommand(argv, deps = {}) {
|
|
|
45470
46503
|
}
|
|
45471
46504
|
}
|
|
45472
46505
|
}
|
|
45473
|
-
var liveModelListReader = (url, apiKey) => readJevModelList(url, apiKey, AbortSignal.timeout(JEV_MODEL_LIST_TIMEOUT_MS)), ok2 = (lines, json) => ({ lines, exitCode: 0, ...json !== undefined ? { json } : {} }), fail2 = (lines, json) => ({ lines, exitCode: 1, ...json !== undefined ? { json } : {} }), JEV_USAGE, JEV_TEST_QUESTION_ID = "jev_test", DEFAULT_TEST_TIMEOUT_MS = 15000, ENV_KEY_STAND_IN = "env-key-stand-in", STRAY_ARGUMENT = "Unexpected argument (not repeated here, in case it is a key). The key goes on stdin: --key-stdin.", SUBCOMMAND_SHAPE, VALUE_FLAGS2, BOOL_FLAGS, OPTION_SHAPE, CLOUD_KEY_SOURCE = "FailproofAI Cloud connection", KEY_LACKS_JEV_TITLE = "off — no Jev key is stored for this machine's FailproofAI Cloud connection", MAX_SHOWN_MODELS = 20, TOKEN_HISTORY_WARNING, CLOUD_CREDENTIAL_REFUSED = "the FailproofAI Cloud credential was refused", MODE_SET_BY_CLOUD = "mode set by FailproofAI Cloud";
|
|
46506
|
+
var liveModelListReader = (url, apiKey) => readJevModelList(url, apiKey, AbortSignal.timeout(JEV_MODEL_LIST_TIMEOUT_MS)), ok2 = (lines, json) => ({ lines, exitCode: 0, ...json !== undefined ? { json } : {} }), fail2 = (lines, json) => ({ lines, exitCode: 1, ...json !== undefined ? { json } : {} }), JEV_USAGE, JEV_TEST_QUESTION_ID = "jev_test", DEFAULT_TEST_TIMEOUT_MS = 15000, ENV_KEY_STAND_IN = "env-key-stand-in", STRAY_ARGUMENT = "Unexpected argument (not repeated here, in case it is a key). The key goes on stdin: --key-stdin.", SUBCOMMAND_SHAPE, VALUE_FLAGS2, BOOL_FLAGS, OPTION_SHAPE, CLOUD_KEY_SOURCE = "FailproofAI Cloud connection", CLOUD_MANAGED_MODE_LINES, KEY_LACKS_JEV_TITLE = "off — no Jev key is stored for this machine's FailproofAI Cloud connection", MAX_SHOWN_MODELS = 20, TOKEN_HISTORY_WARNING, CLOUD_CREDENTIAL_REFUSED = "the FailproofAI Cloud credential was refused", MODE_SET_BY_CLOUD = "mode set by FailproofAI Cloud";
|
|
45474
46507
|
var init_jev_cli = __esm(() => {
|
|
45475
46508
|
init_atomic_write();
|
|
45476
46509
|
init_jev_config();
|
|
@@ -45494,6 +46527,7 @@ var init_jev_cli = __esm(() => {
|
|
|
45494
46527
|
VALUE_FLAGS2 = new Set(["--provider", "--url", "--token", "--base-url", "--account-id", "--model", "--timeout-ms", "--mode"]);
|
|
45495
46528
|
BOOL_FLAGS = new Set(["--key-stdin", "--key-from-env", "--json"]);
|
|
45496
46529
|
OPTION_SHAPE = /^--?[a-z][a-z0-9-]{0,30}$/;
|
|
46530
|
+
CLOUD_MANAGED_MODE_LINES = [CLOUD_MANAGED_JEV_MODE, "Deploy or remove Jev policies in FailproofAI Cloud to change it. Nothing was written."];
|
|
45497
46531
|
TOKEN_HISTORY_WARNING = [
|
|
45498
46532
|
TOKEN_ON_ARGV,
|
|
45499
46533
|
"Prefer piping the key in — `failproofai jev --url <url> --key-stdin < key-file` — and rotate this one if it matters."
|
|
@@ -45505,11 +46539,11 @@ import {
|
|
|
45505
46539
|
chmodSync as chmodSync13,
|
|
45506
46540
|
closeSync as closeSync8,
|
|
45507
46541
|
constants as fsConstants6,
|
|
45508
|
-
existsSync as
|
|
46542
|
+
existsSync as existsSync54,
|
|
45509
46543
|
fstatSync as fstatSync4,
|
|
45510
|
-
mkdirSync as
|
|
46544
|
+
mkdirSync as mkdirSync31,
|
|
45511
46545
|
openSync as openSync8,
|
|
45512
|
-
readFileSync as
|
|
46546
|
+
readFileSync as readFileSync43,
|
|
45513
46547
|
readSync as readSync6,
|
|
45514
46548
|
statSync as statSync40,
|
|
45515
46549
|
writeFileSync as writeFileSync26
|
|
@@ -45521,17 +46555,17 @@ function detectLayout2() {
|
|
|
45521
46555
|
return { kind: "current", version: raw };
|
|
45522
46556
|
return raw.layout > LAYOUT_VERSION ? { kind: "future", found: raw.layout } : { kind: "stale", found: raw.layout };
|
|
45523
46557
|
}
|
|
45524
|
-
if (
|
|
46558
|
+
if (existsSync54(configFile())) {
|
|
45525
46559
|
const layoutThreePositions = [
|
|
45526
46560
|
legacy.authJson(),
|
|
45527
46561
|
legacy.nextAudit(),
|
|
45528
46562
|
legacy.auditSchedule()
|
|
45529
46563
|
];
|
|
45530
|
-
if (layoutThreePositions.some((p) =>
|
|
46564
|
+
if (layoutThreePositions.some((p) => existsSync54(p)))
|
|
45531
46565
|
return { kind: "stale", found: 3 };
|
|
45532
46566
|
return { kind: "current", version: { layout: LAYOUT_VERSION, cli: "" }, inferred: true };
|
|
45533
46567
|
}
|
|
45534
|
-
if (
|
|
46568
|
+
if (existsSync54(legacy.configToml()))
|
|
45535
46569
|
return { kind: "stale", found: 2 };
|
|
45536
46570
|
const layoutOneMarkers = [
|
|
45537
46571
|
legacy.policyConfig(),
|
|
@@ -45542,7 +46576,7 @@ function detectLayout2() {
|
|
|
45542
46576
|
legacy.ingestCredentials(),
|
|
45543
46577
|
legacy.auditDashboard()
|
|
45544
46578
|
];
|
|
45545
|
-
return layoutOneMarkers.some((p) =>
|
|
46579
|
+
return layoutOneMarkers.some((p) => existsSync54(p)) ? { kind: "stale", found: 1 } : { kind: "absent" };
|
|
45546
46580
|
}
|
|
45547
46581
|
function readLegacyTomlVersion2(text) {
|
|
45548
46582
|
const layout = Number(/^\s*layout\s*=\s*(\d+)\s*$/m.exec(text)?.[1]);
|
|
@@ -45554,7 +46588,7 @@ function readLegacyTomlVersion2(text) {
|
|
|
45554
46588
|
function readVersionFile2() {
|
|
45555
46589
|
let text;
|
|
45556
46590
|
try {
|
|
45557
|
-
text =
|
|
46591
|
+
text = readFileSync43(versionFile(), "utf8");
|
|
45558
46592
|
} catch {
|
|
45559
46593
|
return null;
|
|
45560
46594
|
}
|
|
@@ -45588,14 +46622,14 @@ var init_fp_home2 = () => {};
|
|
|
45588
46622
|
import {
|
|
45589
46623
|
chmodSync as chmodSync14,
|
|
45590
46624
|
copyFileSync as copyFileSync4,
|
|
45591
|
-
existsSync as
|
|
45592
|
-
mkdirSync as
|
|
45593
|
-
readFileSync as
|
|
46625
|
+
existsSync as existsSync55,
|
|
46626
|
+
mkdirSync as mkdirSync32,
|
|
46627
|
+
readFileSync as readFileSync44,
|
|
45594
46628
|
renameSync as renameSync15,
|
|
45595
|
-
rmSync as
|
|
46629
|
+
rmSync as rmSync21,
|
|
45596
46630
|
writeFileSync as writeFileSync27
|
|
45597
46631
|
} from "node:fs";
|
|
45598
|
-
import { basename as basename10, dirname as dirname29, join as
|
|
46632
|
+
import { basename as basename10, dirname as dirname29, join as join43, resolve as resolve38 } from "node:path";
|
|
45599
46633
|
function migrateToLayout42() {
|
|
45600
46634
|
const moves = [
|
|
45601
46635
|
{ from: legacy.authJson(), to: auditSessionFile() },
|
|
@@ -45604,20 +46638,20 @@ function migrateToLayout42() {
|
|
|
45604
46638
|
];
|
|
45605
46639
|
const authDirOverride = process.env.FAILPROOFAI_AUTH_DIR;
|
|
45606
46640
|
if (authDirOverride) {
|
|
45607
|
-
moves.push({ from:
|
|
45608
|
-
from:
|
|
45609
|
-
to:
|
|
46641
|
+
moves.push({ from: join43(authDirOverride, "auth.json"), to: join43(authDirOverride, "session.json") }, {
|
|
46642
|
+
from: join43(authDirOverride, "next-audit.json"),
|
|
46643
|
+
to: join43(authDirOverride, "reminder.json")
|
|
45610
46644
|
});
|
|
45611
46645
|
}
|
|
45612
46646
|
const migrated = [];
|
|
45613
46647
|
for (const { from, to } of moves) {
|
|
45614
|
-
if (!
|
|
46648
|
+
if (!existsSync55(from))
|
|
45615
46649
|
continue;
|
|
45616
|
-
if (
|
|
45617
|
-
|
|
46650
|
+
if (existsSync55(to)) {
|
|
46651
|
+
rmSync21(from, { force: true });
|
|
45618
46652
|
continue;
|
|
45619
46653
|
}
|
|
45620
|
-
|
|
46654
|
+
mkdirSync32(dirname29(to), { recursive: true });
|
|
45621
46655
|
try {
|
|
45622
46656
|
renameSync15(from, to);
|
|
45623
46657
|
} catch {
|
|
@@ -45625,16 +46659,16 @@ function migrateToLayout42() {
|
|
|
45625
46659
|
copyFileSync4(from, to);
|
|
45626
46660
|
} catch (err) {
|
|
45627
46661
|
try {
|
|
45628
|
-
|
|
46662
|
+
rmSync21(to, { force: true });
|
|
45629
46663
|
} catch {}
|
|
45630
46664
|
throw err;
|
|
45631
46665
|
}
|
|
45632
|
-
|
|
46666
|
+
rmSync21(from, { force: true });
|
|
45633
46667
|
}
|
|
45634
46668
|
migrated.push(`${basename10(from)} → audit/${basename10(to)}`);
|
|
45635
46669
|
}
|
|
45636
46670
|
for (const secret of [auditSessionFile()]) {
|
|
45637
|
-
if (!
|
|
46671
|
+
if (!existsSync55(secret))
|
|
45638
46672
|
continue;
|
|
45639
46673
|
try {
|
|
45640
46674
|
chmodSync14(secret, 384);
|
|
@@ -45660,7 +46694,7 @@ function planMigration2(from, registry = MIGRATIONS2) {
|
|
|
45660
46694
|
}
|
|
45661
46695
|
function readLedger2() {
|
|
45662
46696
|
try {
|
|
45663
|
-
const parsed = JSON.parse(
|
|
46697
|
+
const parsed = JSON.parse(readFileSync44(migrationLedgerFile(), "utf8"));
|
|
45664
46698
|
return Array.isArray(parsed) ? parsed : [];
|
|
45665
46699
|
} catch {
|
|
45666
46700
|
return [];
|
|
@@ -45668,7 +46702,7 @@ function readLedger2() {
|
|
|
45668
46702
|
}
|
|
45669
46703
|
function appendLedger2(entry) {
|
|
45670
46704
|
try {
|
|
45671
|
-
|
|
46705
|
+
mkdirSync32(migrationsDir(), { recursive: true });
|
|
45672
46706
|
const all = [...readLedger2(), entry];
|
|
45673
46707
|
writeFileSync27(migrationLedgerFile(), `${JSON.stringify(all, null, 2)}
|
|
45674
46708
|
`, "utf8");
|
|
@@ -45682,12 +46716,12 @@ function pruneMigratedCredentials2(from) {
|
|
|
45682
46716
|
for (let layout = from;layout < LAYOUT_VERSION; layout++) {
|
|
45683
46717
|
for (const { as, landsAt } of PRUNED_AFTER_SUCCESS2) {
|
|
45684
46718
|
try {
|
|
45685
|
-
if (!
|
|
46719
|
+
if (!existsSync55(landsAt()))
|
|
45686
46720
|
continue;
|
|
45687
|
-
const copy =
|
|
45688
|
-
if (!
|
|
46721
|
+
const copy = resolve38(migrationBackupDir(layout), as);
|
|
46722
|
+
if (!existsSync55(copy))
|
|
45689
46723
|
continue;
|
|
45690
|
-
|
|
46724
|
+
rmSync21(copy, { force: true });
|
|
45691
46725
|
pruned.push(as);
|
|
45692
46726
|
} catch {}
|
|
45693
46727
|
}
|
|
@@ -45698,7 +46732,7 @@ function filesToBackUp2() {
|
|
|
45698
46732
|
const seen = new Map;
|
|
45699
46733
|
for (const f of [...BACKED_UP2, ...BACKED_UP_LEGACY2]) {
|
|
45700
46734
|
const path = f.at();
|
|
45701
|
-
if (
|
|
46735
|
+
if (existsSync55(path))
|
|
45702
46736
|
seen.set(path, backupNameOf2(f));
|
|
45703
46737
|
}
|
|
45704
46738
|
return [...seen].map(([path, as]) => ({ path, as }));
|
|
@@ -45707,14 +46741,14 @@ function backupBeforeMigrating2(from) {
|
|
|
45707
46741
|
const dir = migrationBackupDir(from);
|
|
45708
46742
|
const saved = [];
|
|
45709
46743
|
try {
|
|
45710
|
-
|
|
45711
|
-
|
|
46744
|
+
rmSync21(dir, { recursive: true, force: true });
|
|
46745
|
+
mkdirSync32(dir, { recursive: true });
|
|
45712
46746
|
} catch {
|
|
45713
46747
|
return [];
|
|
45714
46748
|
}
|
|
45715
46749
|
for (const { path: source, as } of filesToBackUp2()) {
|
|
45716
46750
|
try {
|
|
45717
|
-
copyFileSync4(source,
|
|
46751
|
+
copyFileSync4(source, resolve38(dir, as));
|
|
45718
46752
|
saved.push(as);
|
|
45719
46753
|
} catch {}
|
|
45720
46754
|
}
|
|
@@ -45852,16 +46886,16 @@ var init_migrations2 = __esm(() => {
|
|
|
45852
46886
|
|
|
45853
46887
|
// src/hooks/daemon-service.ts
|
|
45854
46888
|
import {
|
|
45855
|
-
existsSync as
|
|
45856
|
-
mkdirSync as
|
|
46889
|
+
existsSync as existsSync56,
|
|
46890
|
+
mkdirSync as mkdirSync33,
|
|
45857
46891
|
mkdtempSync as mkdtempSync2,
|
|
45858
|
-
readFileSync as
|
|
46892
|
+
readFileSync as readFileSync45,
|
|
45859
46893
|
writeFileSync as writeFileSync28,
|
|
45860
46894
|
unlinkSync as unlinkSync10,
|
|
45861
|
-
rmSync as
|
|
46895
|
+
rmSync as rmSync22
|
|
45862
46896
|
} from "node:fs";
|
|
45863
|
-
import { homedir as
|
|
45864
|
-
import { resolve as
|
|
46897
|
+
import { homedir as homedir38, tmpdir as tmpdir3, userInfo as userInfo2 } from "node:os";
|
|
46898
|
+
import { resolve as resolve39 } from "node:path";
|
|
45865
46899
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
45866
46900
|
function isDaemonSupportedPlatform2() {
|
|
45867
46901
|
return process.platform === "linux" || process.platform === "darwin";
|
|
@@ -45877,13 +46911,13 @@ function resolveFailproofaidBinaryPath2() {
|
|
|
45877
46911
|
if (process.env.FAILPROOFAI_DAEMON_BINARY)
|
|
45878
46912
|
return process.env.FAILPROOFAI_DAEMON_BINARY;
|
|
45879
46913
|
const downloaded = installedBinaryPath();
|
|
45880
|
-
if (
|
|
46914
|
+
if (existsSync56(downloaded))
|
|
45881
46915
|
return downloaded;
|
|
45882
46916
|
const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT;
|
|
45883
46917
|
if (packageRoot) {
|
|
45884
46918
|
for (const profile of ["release", "debug"]) {
|
|
45885
|
-
const candidate =
|
|
45886
|
-
if (
|
|
46919
|
+
const candidate = resolve39(packageRoot, "target", profile, "failproofaid");
|
|
46920
|
+
if (existsSync56(candidate))
|
|
45887
46921
|
return candidate;
|
|
45888
46922
|
}
|
|
45889
46923
|
}
|
|
@@ -45913,8 +46947,8 @@ function resolveWorkerCommand2() {
|
|
|
45913
46947
|
const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT;
|
|
45914
46948
|
if (!packageRoot)
|
|
45915
46949
|
return null;
|
|
45916
|
-
const workerScript =
|
|
45917
|
-
if (!
|
|
46950
|
+
const workerScript = resolve39(packageRoot, "dist", "worker.mjs");
|
|
46951
|
+
if (!existsSync56(workerScript))
|
|
45918
46952
|
return null;
|
|
45919
46953
|
return `${shellQuote2(process.execPath)} ${shellQuote2(workerScript)}`;
|
|
45920
46954
|
}
|
|
@@ -45924,8 +46958,8 @@ function resolveCliCommand2() {
|
|
|
45924
46958
|
const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT;
|
|
45925
46959
|
if (!packageRoot)
|
|
45926
46960
|
return null;
|
|
45927
|
-
const cliScript =
|
|
45928
|
-
if (!
|
|
46961
|
+
const cliScript = resolve39(packageRoot, "dist", "cli.mjs");
|
|
46962
|
+
if (!existsSync56(cliScript))
|
|
45929
46963
|
return null;
|
|
45930
46964
|
return `${shellQuote2(process.execPath)} ${shellQuote2(cliScript)}`;
|
|
45931
46965
|
}
|
|
@@ -45938,8 +46972,8 @@ function workerScriptPath2() {
|
|
|
45938
46972
|
const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT;
|
|
45939
46973
|
if (!packageRoot)
|
|
45940
46974
|
return null;
|
|
45941
|
-
const workerScript =
|
|
45942
|
-
return
|
|
46975
|
+
const workerScript = resolve39(packageRoot, "dist", "worker.mjs");
|
|
46976
|
+
return existsSync56(workerScript) ? workerScript : null;
|
|
45943
46977
|
}
|
|
45944
46978
|
function assertUnitSafe2(value, field) {
|
|
45945
46979
|
if (UNIT_UNSAFE_RE2.test(value)) {
|
|
@@ -45965,10 +46999,10 @@ function systemdUnitDir2() {
|
|
|
45965
46999
|
return process.env.FAILPROOFAI_SYSTEMD_DIR || "/etc/systemd/system";
|
|
45966
47000
|
}
|
|
45967
47001
|
function systemdUnitPath2(user = serviceUser2()) {
|
|
45968
|
-
return
|
|
47002
|
+
return resolve39(systemdUnitDir2(), systemdUnitName2(user));
|
|
45969
47003
|
}
|
|
45970
47004
|
function legacySystemdUserUnitPath2() {
|
|
45971
|
-
return
|
|
47005
|
+
return resolve39(homedir38(), ".config", "systemd", "user", "failproofaid.service");
|
|
45972
47006
|
}
|
|
45973
47007
|
function launchdLabel2(user = serviceUser2()) {
|
|
45974
47008
|
return `ai.failproof.failproofaid.${user}`;
|
|
@@ -45977,7 +47011,7 @@ function launchdPlistPath2(user = serviceUser2()) {
|
|
|
45977
47011
|
return `/Library/LaunchDaemons/${launchdLabel2(user)}.plist`;
|
|
45978
47012
|
}
|
|
45979
47013
|
function legacyLaunchAgentPlistPath2() {
|
|
45980
|
-
return
|
|
47014
|
+
return resolve39(homedir38(), "Library", "LaunchAgents", "ai.failproof.failproofaid.plist");
|
|
45981
47015
|
}
|
|
45982
47016
|
function legacySharedLaunchDaemonPath2() {
|
|
45983
47017
|
return "/Library/LaunchDaemons/ai.failproof.failproofaid.plist";
|
|
@@ -46015,20 +47049,20 @@ function runPrivileged2(command, args) {
|
|
|
46015
47049
|
execFileSync3(cmd, argv, { stdio: "ignore", timeout: SERVICE_CMD_TIMEOUT_MS2 });
|
|
46016
47050
|
}
|
|
46017
47051
|
function writePrivilegedFile2(destination, contents, mode = "0644") {
|
|
46018
|
-
const stagingDir = mkdtempSync2(
|
|
46019
|
-
const staging =
|
|
47052
|
+
const stagingDir = mkdtempSync2(resolve39(tmpdir3(), "failproofaid-stage-"));
|
|
47053
|
+
const staging = resolve39(stagingDir, "service-definition");
|
|
46020
47054
|
try {
|
|
46021
47055
|
writeFileSync28(staging, contents, "utf8");
|
|
46022
47056
|
runPrivileged2("install", ["-m", mode, staging, destination]);
|
|
46023
47057
|
} finally {
|
|
46024
|
-
|
|
47058
|
+
rmSync22(stagingDir, { recursive: true, force: true });
|
|
46025
47059
|
}
|
|
46026
47060
|
}
|
|
46027
47061
|
function removeLegacyUserService2() {
|
|
46028
47062
|
try {
|
|
46029
47063
|
if (process.platform === "linux") {
|
|
46030
47064
|
const legacy = legacySystemdUserUnitPath2();
|
|
46031
|
-
if (!
|
|
47065
|
+
if (!existsSync56(legacy))
|
|
46032
47066
|
return;
|
|
46033
47067
|
try {
|
|
46034
47068
|
execFileSync3("systemctl", ["--user", "disable", "--now", "failproofaid.service"], {
|
|
@@ -46045,7 +47079,7 @@ function removeLegacyUserService2() {
|
|
|
46045
47079
|
} catch {}
|
|
46046
47080
|
} else {
|
|
46047
47081
|
const legacyAgent = legacyLaunchAgentPlistPath2();
|
|
46048
|
-
if (
|
|
47082
|
+
if (existsSync56(legacyAgent)) {
|
|
46049
47083
|
try {
|
|
46050
47084
|
execFileSync3("launchctl", ["unload", "-w", legacyAgent], {
|
|
46051
47085
|
stdio: "ignore",
|
|
@@ -46055,7 +47089,7 @@ function removeLegacyUserService2() {
|
|
|
46055
47089
|
unlinkSync10(legacyAgent);
|
|
46056
47090
|
}
|
|
46057
47091
|
const legacyDaemon = legacySharedLaunchDaemonPath2();
|
|
46058
|
-
if (
|
|
47092
|
+
if (existsSync56(legacyDaemon)) {
|
|
46059
47093
|
try {
|
|
46060
47094
|
runPrivileged2("launchctl", ["unload", "-w", legacyDaemon]);
|
|
46061
47095
|
} catch {}
|
|
@@ -46071,8 +47105,8 @@ function systemdUnitContents2(binaryPath, workerCmd, cliCmd = null) {
|
|
|
46071
47105
|
`).join("");
|
|
46072
47106
|
const user = assertUnitSafe2(serviceUser2(), "User");
|
|
46073
47107
|
assertUnitSafe2(binaryPath, "ExecStart");
|
|
46074
|
-
assertUnitSafe2(
|
|
46075
|
-
const conditionPaths = [binaryPath, workerScriptPath2()].filter((p) => typeof p === "string" &&
|
|
47108
|
+
assertUnitSafe2(homedir38(), "HOME");
|
|
47109
|
+
const conditionPaths = [binaryPath, workerScriptPath2()].filter((p) => typeof p === "string" && existsSync56(p));
|
|
46076
47110
|
const conditionLines = conditionPaths.map((p) => `ConditionPathExists=${assertUnitSafe2(p, "ConditionPathExists")}
|
|
46077
47111
|
`).join("");
|
|
46078
47112
|
return `[Unit]
|
|
@@ -46085,7 +47119,7 @@ User=${user}
|
|
|
46085
47119
|
# Set explicitly rather than relying on systemd deriving it from User=:
|
|
46086
47120
|
# failproofaid stores per-user state and refuses to start without HOME, so this
|
|
46087
47121
|
# required variable is not left to a version-dependent default.
|
|
46088
|
-
Environment="HOME=${
|
|
47122
|
+
Environment="HOME=${homedir38()}"
|
|
46089
47123
|
${envLines}ExecStart=${binaryPath}
|
|
46090
47124
|
Restart=on-failure
|
|
46091
47125
|
RestartSec=2
|
|
@@ -46130,9 +47164,9 @@ ${env.map(([key, value]) => ` <key>${key}</key>
|
|
|
46130
47164
|
<key>UserName</key>
|
|
46131
47165
|
<string>${escapeXml2(serviceUser2())}</string>
|
|
46132
47166
|
${envBlock} <key>StandardOutPath</key>
|
|
46133
|
-
<string>${escapeXml2(
|
|
47167
|
+
<string>${escapeXml2(resolve39(logDir, "failproofaid.log"))}</string>
|
|
46134
47168
|
<key>StandardErrorPath</key>
|
|
46135
|
-
<string>${escapeXml2(
|
|
47169
|
+
<string>${escapeXml2(resolve39(logDir, "failproofaid.err.log"))}</string>
|
|
46136
47170
|
</dict>
|
|
46137
47171
|
</plist>
|
|
46138
47172
|
`;
|
|
@@ -46178,7 +47212,7 @@ async function installDaemonService2() {
|
|
|
46178
47212
|
} else {
|
|
46179
47213
|
const plistPath = launchdPlistPath2();
|
|
46180
47214
|
const logDir = logsDir();
|
|
46181
|
-
|
|
47215
|
+
mkdirSync33(logDir, { recursive: true });
|
|
46182
47216
|
try {
|
|
46183
47217
|
runPrivileged2("launchctl", ["unload", plistPath]);
|
|
46184
47218
|
} catch {}
|
|
@@ -46294,7 +47328,7 @@ async function refreshDaemonToCliVersion(deps = {}) {
|
|
|
46294
47328
|
return { ok: true, lines: ["No failproofaid service on this machine; nothing to update."] };
|
|
46295
47329
|
}
|
|
46296
47330
|
const recorded = readVersionFile()?.daemon;
|
|
46297
|
-
if (current === "running" && recorded === version2 &&
|
|
47331
|
+
if (current === "running" && recorded === version2 && existsSync56(installedBinaryPath(version2))) {
|
|
46298
47332
|
return { ok: true, lines: [`failproofaid ${version2} is already installed and running; nothing to update.`] };
|
|
46299
47333
|
}
|
|
46300
47334
|
if (interactive())
|
|
@@ -46333,7 +47367,7 @@ function daemonServiceStatus2() {
|
|
|
46333
47367
|
if (!isDaemonSupportedPlatform2())
|
|
46334
47368
|
return "unsupported-platform";
|
|
46335
47369
|
if (process.platform === "linux") {
|
|
46336
|
-
if (!
|
|
47370
|
+
if (!existsSync56(systemdUnitPath2()))
|
|
46337
47371
|
return "not-installed";
|
|
46338
47372
|
try {
|
|
46339
47373
|
const out = execFileSync3("systemctl", ["is-active", systemdUnitName2()], {
|
|
@@ -46346,7 +47380,7 @@ function daemonServiceStatus2() {
|
|
|
46346
47380
|
}
|
|
46347
47381
|
}
|
|
46348
47382
|
const plistPath = launchdPlistPath2();
|
|
46349
|
-
if (!
|
|
47383
|
+
if (!existsSync56(plistPath))
|
|
46350
47384
|
return "not-installed";
|
|
46351
47385
|
try {
|
|
46352
47386
|
const root = typeof process.getuid === "function" && process.getuid() === 0;
|
|
@@ -46414,7 +47448,7 @@ var init_hermes_update = __esm(() => {
|
|
|
46414
47448
|
});
|
|
46415
47449
|
|
|
46416
47450
|
// src/hooks/uninstall-cli.ts
|
|
46417
|
-
import { existsSync as
|
|
47451
|
+
import { existsSync as existsSync57, rmSync as rmSync23 } from "node:fs";
|
|
46418
47452
|
function survey(cwd) {
|
|
46419
47453
|
const clis = [];
|
|
46420
47454
|
for (const id of listInstallableIds()) {
|
|
@@ -46434,11 +47468,12 @@ function survey(cwd) {
|
|
|
46434
47468
|
const servicePath = isDaemonSupportedPlatform() ? daemonServiceFilePath() : null;
|
|
46435
47469
|
return {
|
|
46436
47470
|
clis,
|
|
47471
|
+
skillDirs: installedAgentSkillDirs(),
|
|
46437
47472
|
codexSystemPath: codexSystemHooksPresent() ? codexSystemConfigPath() : null,
|
|
46438
47473
|
servicePath,
|
|
46439
|
-
serviceInstalled: !!servicePath &&
|
|
47474
|
+
serviceInstalled: !!servicePath && existsSync57(servicePath),
|
|
46440
47475
|
daemonConfigured,
|
|
46441
|
-
homeExists:
|
|
47476
|
+
homeExists: existsSync57(failproofaiHome())
|
|
46442
47477
|
};
|
|
46443
47478
|
}
|
|
46444
47479
|
async function runUninstallCommand(opts = {}) {
|
|
@@ -46448,7 +47483,7 @@ async function runUninstallCommand(opts = {}) {
|
|
|
46448
47483
|
const many = (n, one) => `${n} ${one}${n === 1 ? "" : "s"}`;
|
|
46449
47484
|
const errText = (err) => err instanceof Error ? err.message : String(err);
|
|
46450
47485
|
const lines = [];
|
|
46451
|
-
const nothingToDo = found.clis.length === 0 && !found.serviceInstalled && !found.daemonConfigured && !(opts.purge && found.homeExists);
|
|
47486
|
+
const nothingToDo = found.clis.length === 0 && found.skillDirs.length === 0 && !found.serviceInstalled && !found.daemonConfigured && !(opts.purge && found.homeExists);
|
|
46452
47487
|
if (nothingToDo) {
|
|
46453
47488
|
return {
|
|
46454
47489
|
exitCode: 0,
|
|
@@ -46462,6 +47497,8 @@ ${home} still holds settings and history. Delete it with \`failproofai uninstal
|
|
|
46462
47497
|
const removals = [];
|
|
46463
47498
|
if (found.clis.length > 0)
|
|
46464
47499
|
removals.push(`failproofai's hooks from ${many(found.clis.length, "agent")}`);
|
|
47500
|
+
if (found.skillDirs.length > 0)
|
|
47501
|
+
removals.push(`the failproofai skill from ${many(found.skillDirs.length, "agent folder")}`);
|
|
46465
47502
|
if (found.serviceInstalled)
|
|
46466
47503
|
removals.push("the failproofaid service (needs sudo)");
|
|
46467
47504
|
if (purging)
|
|
@@ -46548,6 +47585,15 @@ ${home} still holds settings and history. Delete it with \`failproofai uninstal
|
|
|
46548
47585
|
` + "Finish with `failproofai policies --uninstall --scope all`");
|
|
46549
47586
|
}
|
|
46550
47587
|
}
|
|
47588
|
+
if (found.skillDirs.length > 0) {
|
|
47589
|
+
const left = found.skillDirs.length - removeAgentSkill().length;
|
|
47590
|
+
if (left === 0)
|
|
47591
|
+
lines.push(kit.ok(`Removed the failproofai skill from ${many(found.skillDirs.length, "agent folder")}.`));
|
|
47592
|
+
else
|
|
47593
|
+
failures.push(`Could not remove the failproofai skill from ${many(left, "agent folder")}:
|
|
47594
|
+
${installedAgentSkillDirs().join(`
|
|
47595
|
+
`)}`);
|
|
47596
|
+
}
|
|
46551
47597
|
if (found.serviceInstalled) {
|
|
46552
47598
|
elevateOnce();
|
|
46553
47599
|
const byHand = (servicePath) => `
|
|
@@ -46557,18 +47603,18 @@ Remove it as root:
|
|
|
46557
47603
|
Check it with \`${daemonStatusCommand()}\`` : "");
|
|
46558
47604
|
try {
|
|
46559
47605
|
await uninstallDaemonService();
|
|
46560
|
-
if (found.servicePath &&
|
|
47606
|
+
if (found.servicePath && existsSync57(found.servicePath)) {
|
|
46561
47607
|
failures.push("The failproofaid service is still there, most often because sudo was not available." + byHand(found.servicePath));
|
|
46562
47608
|
} else {
|
|
46563
47609
|
lines.push(kit.ok("Stopped and removed the failproofaid service."));
|
|
46564
47610
|
}
|
|
46565
47611
|
} catch (err) {
|
|
46566
|
-
failures.push(`Could not remove the failproofaid service: ${errText(err)}` + (found.servicePath &&
|
|
47612
|
+
failures.push(`Could not remove the failproofaid service: ${errText(err)}` + (found.servicePath && existsSync57(found.servicePath) ? byHand(found.servicePath) : ""));
|
|
46567
47613
|
}
|
|
46568
47614
|
}
|
|
46569
47615
|
if (purging) {
|
|
46570
47616
|
try {
|
|
46571
|
-
|
|
47617
|
+
rmSync23(home, { recursive: true, force: true });
|
|
46572
47618
|
purged = true;
|
|
46573
47619
|
lines.push(kit.ok(`Deleted ${home}.`));
|
|
46574
47620
|
} catch (err) {
|
|
@@ -46603,16 +47649,17 @@ var init_uninstall_cli = __esm(() => {
|
|
|
46603
47649
|
init_daemon_service();
|
|
46604
47650
|
init_integrations();
|
|
46605
47651
|
init_manager();
|
|
47652
|
+
init_agent_skill();
|
|
46606
47653
|
init_codex_system_hooks();
|
|
46607
47654
|
init_tui();
|
|
46608
47655
|
});
|
|
46609
47656
|
|
|
46610
47657
|
// src/hooks/pack-cli.ts
|
|
46611
47658
|
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
46612
|
-
import { homedir as
|
|
47659
|
+
import { homedir as homedir39, tmpdir as tmpdir4 } from "node:os";
|
|
46613
47660
|
import { createHash as createHash14 } from "node:crypto";
|
|
46614
|
-
import { copyFileSync as copyFileSync5, existsSync as
|
|
46615
|
-
import { basename as basename11, dirname as dirname30, isAbsolute as isAbsolute6, join as
|
|
47661
|
+
import { copyFileSync as copyFileSync5, existsSync as existsSync58, mkdirSync as mkdirSync34, mkdtempSync as mkdtempSync3, readFileSync as readFileSync46, readdirSync as readdirSync24, realpathSync as realpathSync5, rmSync as rmSync24, statSync as statSync41, writeFileSync as writeFileSync29 } from "node:fs";
|
|
47662
|
+
import { basename as basename11, dirname as dirname30, isAbsolute as isAbsolute6, join as join44, relative as relative5, resolve as resolve40, sep as sep6 } from "node:path";
|
|
46616
47663
|
function parseList(rest, ...flags) {
|
|
46617
47664
|
let found = false;
|
|
46618
47665
|
const out = [];
|
|
@@ -46727,7 +47774,7 @@ async function build(rest) {
|
|
|
46727
47774
|
const commit = flag("commit");
|
|
46728
47775
|
const effect = flag("effect") ?? "enforce";
|
|
46729
47776
|
const minCliVersion = flag("min-cli-version");
|
|
46730
|
-
const outDir =
|
|
47777
|
+
const outDir = resolve40(flag("out") ?? "dist-pack");
|
|
46731
47778
|
const repo = flag("repo");
|
|
46732
47779
|
if (!entry || !id || !version) {
|
|
46733
47780
|
return fail3([
|
|
@@ -46747,10 +47794,10 @@ async function build(rest) {
|
|
|
46747
47794
|
} catch (err) {
|
|
46748
47795
|
return fail3([err instanceof Error ? err.message : String(err)]);
|
|
46749
47796
|
}
|
|
46750
|
-
const entryPath =
|
|
46751
|
-
if (!
|
|
47797
|
+
const entryPath = resolve40(entry);
|
|
47798
|
+
if (!existsSync58(entryPath))
|
|
46752
47799
|
return fail3([`No such file: ${entryPath}`]);
|
|
46753
|
-
const source =
|
|
47800
|
+
const source = readFileSync46(entryPath, "utf8");
|
|
46754
47801
|
const localImport = firstRelativeSpecifier(source);
|
|
46755
47802
|
if (localImport) {
|
|
46756
47803
|
return fail3([
|
|
@@ -46869,14 +47916,14 @@ async function build(rest) {
|
|
|
46869
47916
|
...semantic.length > 0 ? { semantic } : {}
|
|
46870
47917
|
}, null, 2) + `
|
|
46871
47918
|
`;
|
|
46872
|
-
|
|
46873
|
-
const manifestPath =
|
|
46874
|
-
const entryOut =
|
|
47919
|
+
mkdirSync34(outDir, { recursive: true });
|
|
47920
|
+
const manifestPath = resolve40(outDir, PACK_MANIFEST_ASSET);
|
|
47921
|
+
const entryOut = resolve40(outDir, PACK_ENTRY_ASSET);
|
|
46875
47922
|
writeFileSync29(manifestPath, manifest, "utf8");
|
|
46876
47923
|
copyFileSync5(entryPath, entryOut);
|
|
46877
47924
|
const sha = (bytes) => createHash14("sha256").update(bytes).digest("hex");
|
|
46878
|
-
writeFileSync29(
|
|
46879
|
-
${sha(
|
|
47925
|
+
writeFileSync29(resolve40(outDir, PACK_CHECKSUMS_ASSET), `${sha(manifest)} ${PACK_MANIFEST_ASSET}
|
|
47926
|
+
${sha(readFileSync46(entryOut))} ${PACK_ENTRY_ASSET}
|
|
46880
47927
|
`, "utf8");
|
|
46881
47928
|
const on = policies.filter((p) => p.defaultEnabled).length;
|
|
46882
47929
|
const semanticOnly = policies.length === 0 && semantic.length > 0;
|
|
@@ -47017,11 +48064,11 @@ async function scaffold(target) {
|
|
|
47017
48064
|
return ok3(["Nothing written."]);
|
|
47018
48065
|
chosen = answer.trim();
|
|
47019
48066
|
}
|
|
47020
|
-
const path =
|
|
47021
|
-
if (
|
|
48067
|
+
const path = resolve40(withPolicyExtension(chosen ?? "my-policies"));
|
|
48068
|
+
if (existsSync58(path)) {
|
|
47022
48069
|
return fail3([`${path} already exists — name a different file, or edit that one.`]);
|
|
47023
48070
|
}
|
|
47024
|
-
|
|
48071
|
+
mkdirSync34(resolve40(path, ".."), { recursive: true });
|
|
47025
48072
|
writeFileSync29(path, `import { customPolicies, allow, deny } from "failproofai";
|
|
47026
48073
|
|
|
47027
48074
|
// One file, no relative imports: only this entry is digest-pinned, so a pack
|
|
@@ -47059,7 +48106,7 @@ customPolicies.add({
|
|
|
47059
48106
|
function inferRepo(entryPath) {
|
|
47060
48107
|
try {
|
|
47061
48108
|
const url = execFileSync4("git", ["remote", "get-url", "origin"], {
|
|
47062
|
-
cwd:
|
|
48109
|
+
cwd: resolve40(entryPath, ".."),
|
|
47063
48110
|
encoding: "utf8",
|
|
47064
48111
|
stdio: ["ignore", "pipe", "ignore"],
|
|
47065
48112
|
timeout: 5000
|
|
@@ -47071,7 +48118,7 @@ function inferRepo(entryPath) {
|
|
|
47071
48118
|
}
|
|
47072
48119
|
}
|
|
47073
48120
|
function inferCommit(entryPath, outDir, sources) {
|
|
47074
|
-
const cwd =
|
|
48121
|
+
const cwd = resolve40(entryPath, "..");
|
|
47075
48122
|
const raw = (args) => {
|
|
47076
48123
|
try {
|
|
47077
48124
|
return execFileSync4("git", args, {
|
|
@@ -47126,9 +48173,9 @@ function realOrSelf(path) {
|
|
|
47126
48173
|
}
|
|
47127
48174
|
}
|
|
47128
48175
|
function sourcesInHead(git, raw, sources) {
|
|
47129
|
-
const paths = sources.map((f) => realOrSelf(
|
|
48176
|
+
const paths = sources.map((f) => realOrSelf(resolve40(f)));
|
|
47130
48177
|
const shown = git(["rev-parse", "--show-toplevel"]);
|
|
47131
|
-
const top = shown === null ? null : realOrSelf(
|
|
48178
|
+
const top = shown === null ? null : realOrSelf(resolve40(shown));
|
|
47132
48179
|
const missing = [];
|
|
47133
48180
|
for (const path of paths) {
|
|
47134
48181
|
const rel = top ? relative5(top, path) : null;
|
|
@@ -47152,7 +48199,7 @@ function sourcesInHead(git, raw, sources) {
|
|
|
47152
48199
|
]);
|
|
47153
48200
|
if (status === null)
|
|
47154
48201
|
return { ok: false, offending: paths, why: "modified" };
|
|
47155
|
-
const dirty = porcelainEntries(status).flatMap((entry) => [entry.path, entry.from].filter(Boolean).map((path) =>
|
|
48202
|
+
const dirty = porcelainEntries(status).flatMap((entry) => [entry.path, entry.from].filter(Boolean).map((path) => resolve40(top ?? ".", path)));
|
|
47156
48203
|
if (dirty.length > 0)
|
|
47157
48204
|
return { ok: false, offending: dirty, why: "modified" };
|
|
47158
48205
|
return { ok: true };
|
|
@@ -47160,19 +48207,19 @@ function sourcesInHead(git, raw, sources) {
|
|
|
47160
48207
|
function skipOutDir(git, entryPath, outDir) {
|
|
47161
48208
|
if (!outDir)
|
|
47162
48209
|
return [];
|
|
47163
|
-
const out =
|
|
47164
|
-
if (
|
|
48210
|
+
const out = resolve40(outDir);
|
|
48211
|
+
if (resolve40(entryPath).startsWith(out + sep6))
|
|
47165
48212
|
return [];
|
|
47166
48213
|
const top = git(["rev-parse", "--show-toplevel"]);
|
|
47167
48214
|
if (!top)
|
|
47168
48215
|
return [];
|
|
47169
|
-
const rel = relative5(
|
|
48216
|
+
const rel = relative5(resolve40(top), out);
|
|
47170
48217
|
if (!rel || rel.startsWith("..") || isAbsolute6(rel))
|
|
47171
48218
|
return [];
|
|
47172
48219
|
return ["--", ":(top)", `:(exclude,literal,top)${rel.split(sep6).join("/")}`];
|
|
47173
48220
|
}
|
|
47174
48221
|
function inferTaggedVersion(entryPath, sources) {
|
|
47175
|
-
const cwd =
|
|
48222
|
+
const cwd = resolve40(entryPath, "..");
|
|
47176
48223
|
const raw = (args) => {
|
|
47177
48224
|
try {
|
|
47178
48225
|
return execFileSync4("git", args, {
|
|
@@ -47210,11 +48257,11 @@ function findEntry(dir) {
|
|
|
47210
48257
|
for (const name of names) {
|
|
47211
48258
|
if (!/\.(mjs|js|ts)$/.test(name))
|
|
47212
48259
|
continue;
|
|
47213
|
-
const full =
|
|
48260
|
+
const full = resolve40(dir, name);
|
|
47214
48261
|
try {
|
|
47215
48262
|
if (statSync41(full).size > 512 * 1024)
|
|
47216
48263
|
continue;
|
|
47217
|
-
const text =
|
|
48264
|
+
const text = readFileSync46(full, "utf8");
|
|
47218
48265
|
if (/from\s+["']failproofai["']/.test(text) && /(?:customPolicies|semanticPolicies)\s*\.\s*add\s*\(/.test(text)) {
|
|
47219
48266
|
found.push(full);
|
|
47220
48267
|
}
|
|
@@ -47225,7 +48272,7 @@ function findEntry(dir) {
|
|
|
47225
48272
|
return found.sort();
|
|
47226
48273
|
}
|
|
47227
48274
|
function withLocalImports(sources) {
|
|
47228
|
-
const seen = new Set(sources.map((f) =>
|
|
48275
|
+
const seen = new Set(sources.map((f) => resolve40(f)));
|
|
47229
48276
|
const queue = [...seen];
|
|
47230
48277
|
while (queue.length > 0 && seen.size < 500) {
|
|
47231
48278
|
const file = queue.shift();
|
|
@@ -47233,13 +48280,13 @@ function withLocalImports(sources) {
|
|
|
47233
48280
|
try {
|
|
47234
48281
|
if (statSync41(file).size > 512 * 1024)
|
|
47235
48282
|
continue;
|
|
47236
|
-
text =
|
|
48283
|
+
text = readFileSync46(file, "utf8");
|
|
47237
48284
|
} catch {
|
|
47238
48285
|
continue;
|
|
47239
48286
|
}
|
|
47240
48287
|
for (const re of LOCAL_IMPORT_RES) {
|
|
47241
48288
|
for (const match of text.matchAll(re)) {
|
|
47242
|
-
const base =
|
|
48289
|
+
const base = resolve40(dirname30(file), match[1]);
|
|
47243
48290
|
for (const ext of LOCAL_IMPORT_EXTENSIONS) {
|
|
47244
48291
|
const candidate = base + ext;
|
|
47245
48292
|
if (seen.has(candidate))
|
|
@@ -47260,7 +48307,7 @@ function withLocalImports(sources) {
|
|
|
47260
48307
|
return [...seen];
|
|
47261
48308
|
}
|
|
47262
48309
|
function settleGitState(entryPath, provenance, packFiles, id, outDir) {
|
|
47263
|
-
const cwd =
|
|
48310
|
+
const cwd = resolve40(entryPath, "..");
|
|
47264
48311
|
const raw = (args) => {
|
|
47265
48312
|
try {
|
|
47266
48313
|
return execFileSync4("git", args, {
|
|
@@ -47335,11 +48382,11 @@ function settleGitState(entryPath, provenance, packFiles, id, outDir) {
|
|
|
47335
48382
|
if (root === null || status === null)
|
|
47336
48383
|
return null;
|
|
47337
48384
|
const entries = porcelainEntries(status);
|
|
47338
|
-
const dirty = entries.map((entry) =>
|
|
47339
|
-
const renamedFrom = entries.filter((entry) => entry.from).map((entry) =>
|
|
48385
|
+
const dirty = entries.map((entry) => resolve40(root, entry.path));
|
|
48386
|
+
const renamedFrom = entries.filter((entry) => entry.from).map((entry) => resolve40(root, entry.from));
|
|
47340
48387
|
if (dirty.length === 0)
|
|
47341
48388
|
return null;
|
|
47342
|
-
const mine = new Set(packFiles.map((f) =>
|
|
48389
|
+
const mine = new Set(packFiles.map((f) => resolve40(f)));
|
|
47343
48390
|
const foreign = dirty.filter((path) => !mine.has(path));
|
|
47344
48391
|
const toStage = [...dirty, ...renamedFrom];
|
|
47345
48392
|
if (foreign.length > 0) {
|
|
@@ -47470,7 +48517,7 @@ function pushExistingHistory(dir, owner, name, token) {
|
|
|
47470
48517
|
const branch = git(["rev-parse", "--abbrev-ref", "HEAD"]);
|
|
47471
48518
|
if (!branch || branch === "HEAD" || !git(["rev-parse", "--verify", "HEAD"]))
|
|
47472
48519
|
return false;
|
|
47473
|
-
const askpass =
|
|
48520
|
+
const askpass = join44(mkdtempSync3(join44(tmpdir4(), "fpai-askpass-")), "askpass.sh");
|
|
47474
48521
|
try {
|
|
47475
48522
|
writeFileSync29(askpass, `#!/bin/sh
|
|
47476
48523
|
case "$1" in
|
|
@@ -47492,7 +48539,7 @@ esac
|
|
|
47492
48539
|
return true;
|
|
47493
48540
|
} finally {
|
|
47494
48541
|
try {
|
|
47495
|
-
|
|
48542
|
+
rmSync24(dirname30(askpass), { recursive: true, force: true });
|
|
47496
48543
|
} catch {}
|
|
47497
48544
|
}
|
|
47498
48545
|
}
|
|
@@ -47516,8 +48563,8 @@ failproofai policies add ${owner}/${name}
|
|
|
47516
48563
|
function findBun() {
|
|
47517
48564
|
const candidates = [
|
|
47518
48565
|
"bun",
|
|
47519
|
-
process.env.BUN_INSTALL ?
|
|
47520
|
-
|
|
48566
|
+
process.env.BUN_INSTALL ? resolve40(process.env.BUN_INSTALL, "bin", "bun") : null,
|
|
48567
|
+
resolve40(homedir39(), ".bun", "bin", "bun"),
|
|
47521
48568
|
"/opt/homebrew/bin/bun",
|
|
47522
48569
|
"/usr/local/bin/bun"
|
|
47523
48570
|
].filter((c) => c !== null);
|
|
@@ -47543,12 +48590,12 @@ function bundleEntry(sources, outDir) {
|
|
|
47543
48590
|
]
|
|
47544
48591
|
};
|
|
47545
48592
|
}
|
|
47546
|
-
|
|
47547
|
-
const entry =
|
|
47548
|
-
writeFileSync29(entry, sources.map((f) => `import ${JSON.stringify(f.startsWith("/") ? f :
|
|
48593
|
+
mkdirSync34(outDir, { recursive: true });
|
|
48594
|
+
const entry = resolve40(outDir, ".entry.generated.mjs");
|
|
48595
|
+
writeFileSync29(entry, sources.map((f) => `import ${JSON.stringify(f.startsWith("/") ? f : resolve40(f))};`).join(`
|
|
47549
48596
|
`) + `
|
|
47550
48597
|
`, "utf8");
|
|
47551
|
-
const bundled =
|
|
48598
|
+
const bundled = resolve40(outDir, ".bundled.mjs");
|
|
47552
48599
|
try {
|
|
47553
48600
|
execFileSync4(bun, [
|
|
47554
48601
|
"build",
|
|
@@ -47680,7 +48727,7 @@ async function publish(rest) {
|
|
|
47680
48727
|
`);
|
|
47681
48728
|
const token = githubToken();
|
|
47682
48729
|
const login = token ? await credentialLogin(token) : null;
|
|
47683
|
-
const folder = basename11(
|
|
48730
|
+
const folder = basename11(resolve40(entry, ".."));
|
|
47684
48731
|
const answered = await askWhereToPublish(`${login ?? "your-account"}/${folder}`, { stdin: process.stdin, stdout: process.stdout });
|
|
47685
48732
|
if (answered === null)
|
|
47686
48733
|
return ok3(["Nothing was published."]);
|
|
@@ -47690,7 +48737,7 @@ async function publish(rest) {
|
|
|
47690
48737
|
let version = flag("version") ?? (entry ? inferTaggedVersion(entry, bundledSources) : null) ?? undefined;
|
|
47691
48738
|
const dryRun = rest.includes("--dry-run") || !repo;
|
|
47692
48739
|
const allowPrivate = rest.includes("--allow-private");
|
|
47693
|
-
const id = flag("id") ?? repo ?? (dryRun && entry ? `local/${basename11(
|
|
48740
|
+
const id = flag("id") ?? repo ?? (dryRun && entry ? `local/${basename11(resolve40(entry, ".."))}` : undefined);
|
|
47694
48741
|
const [owner, name] = (repo ?? "/").split("/");
|
|
47695
48742
|
if (repo && (!owner || !name || repo.split("/").length !== 2)) {
|
|
47696
48743
|
return fail3([`--repo must be <owner>/<repo>, got ${JSON.stringify(repo)}`]);
|
|
@@ -47709,7 +48756,7 @@ async function publish(rest) {
|
|
|
47709
48756
|
"With no --repo it writes the three release assets and stops."
|
|
47710
48757
|
]);
|
|
47711
48758
|
}
|
|
47712
|
-
const outDirEarly =
|
|
48759
|
+
const outDirEarly = resolve40(flag("out") ?? "dist-pack");
|
|
47713
48760
|
let provenance = entry ? inferCommit(entry, outDirEarly, bundledSources) : null;
|
|
47714
48761
|
const gitLines = [];
|
|
47715
48762
|
if (!version && entry && interactive) {
|
|
@@ -47748,7 +48795,7 @@ async function publish(rest) {
|
|
|
47748
48795
|
"It needs write access to releases on that repository, and nothing else."
|
|
47749
48796
|
]);
|
|
47750
48797
|
}
|
|
47751
|
-
const ensured = await ensureRepo(owner, name, id, token,
|
|
48798
|
+
const ensured = await ensureRepo(owner, name, id, token, resolve40(entry, ".."));
|
|
47752
48799
|
if ("error" in ensured)
|
|
47753
48800
|
return fail3(ensured.error);
|
|
47754
48801
|
created = ensured.created;
|
|
@@ -47761,7 +48808,7 @@ async function publish(rest) {
|
|
|
47761
48808
|
}
|
|
47762
48809
|
const tag = flag("tag") ?? version;
|
|
47763
48810
|
let entryToBuild = entry;
|
|
47764
|
-
const needsBundle = discovered.length > 1 || firstRelativeSpecifier(
|
|
48811
|
+
const needsBundle = discovered.length > 1 || firstRelativeSpecifier(readFileSync46(entry, "utf8")) !== null;
|
|
47765
48812
|
if (needsBundle) {
|
|
47766
48813
|
const sources = discovered.length > 1 ? discovered : [entry];
|
|
47767
48814
|
const bundled = bundleEntry(sources, outDirEarly);
|
|
@@ -47842,7 +48889,7 @@ async function publish(rest) {
|
|
|
47842
48889
|
if (prior) {
|
|
47843
48890
|
await gh(`${GITHUB_API2}/repos/${owner}/${name}/releases/assets/${prior.id}`, auth, { method: "DELETE" });
|
|
47844
48891
|
}
|
|
47845
|
-
const bytes =
|
|
48892
|
+
const bytes = readFileSync46(resolve40(outDir, asset));
|
|
47846
48893
|
const upload = await gh(`${GITHUB_UPLOADS2}/repos/${owner}/${name}/releases/${releaseId}/assets?name=${encodeURIComponent(asset)}`, auth, {
|
|
47847
48894
|
method: "POST",
|
|
47848
48895
|
contentType: asset.endsWith(".json") ? "application/json" : "application/octet-stream",
|
|
@@ -48569,8 +49616,8 @@ var init_install_prompt = __esm(() => {
|
|
|
48569
49616
|
|
|
48570
49617
|
// src/hooks/manager.ts
|
|
48571
49618
|
import { execSync as execSync8 } from "node:child_process";
|
|
48572
|
-
import { existsSync as
|
|
48573
|
-
import { resolve as
|
|
49619
|
+
import { existsSync as existsSync59 } from "node:fs";
|
|
49620
|
+
import { resolve as resolve41, basename as basename12 } from "node:path";
|
|
48574
49621
|
import { platform as platform4, arch as arch4, release as release3, hostname as hostname6 } from "node:os";
|
|
48575
49622
|
function getSettingsPath2(scope, cwd) {
|
|
48576
49623
|
return claudeCode.getSettingsPath(scope, cwd);
|
|
@@ -48713,6 +49760,34 @@ function integrationsInstalledAt2(scope, cwd) {
|
|
|
48713
49760
|
}
|
|
48714
49761
|
});
|
|
48715
49762
|
}
|
|
49763
|
+
function cloudPolicyStatus2() {
|
|
49764
|
+
let count = 0;
|
|
49765
|
+
let observing = false;
|
|
49766
|
+
const jsIds = new Set;
|
|
49767
|
+
try {
|
|
49768
|
+
for (const artifact of listActiveCloudManagedPolicies()) {
|
|
49769
|
+
jsIds.add(artifact.id);
|
|
49770
|
+
if (artifact.effect === "observe")
|
|
49771
|
+
observing = true;
|
|
49772
|
+
else
|
|
49773
|
+
count++;
|
|
49774
|
+
}
|
|
49775
|
+
} catch {}
|
|
49776
|
+
try {
|
|
49777
|
+
const { jevMode } = readCloudJevState();
|
|
49778
|
+
if (jevMode === "enforce" || jevMode === "observe") {
|
|
49779
|
+
for (const assignment of readCloudJevAssignments() ?? []) {
|
|
49780
|
+
if (jsIds.has(assignment.id))
|
|
49781
|
+
continue;
|
|
49782
|
+
if (jevMode === "observe" || assignment.effect === "observe")
|
|
49783
|
+
observing = true;
|
|
49784
|
+
else
|
|
49785
|
+
count++;
|
|
49786
|
+
}
|
|
49787
|
+
}
|
|
49788
|
+
} catch {}
|
|
49789
|
+
return { count, observing };
|
|
49790
|
+
}
|
|
48716
49791
|
function notEnforcingReason2(cwd) {
|
|
48717
49792
|
const wired = deduplicateScopes2(HOOK_SCOPES, cwd).some((scope) => hooksInstalledInSettings2(scope, cwd));
|
|
48718
49793
|
if (!wired)
|
|
@@ -48735,17 +49810,13 @@ function notEnforcingReason2(cwd) {
|
|
|
48735
49810
|
return null;
|
|
48736
49811
|
}
|
|
48737
49812
|
} catch {}
|
|
48738
|
-
|
|
48739
|
-
|
|
48740
|
-
|
|
48741
|
-
|
|
48742
|
-
else
|
|
48743
|
-
return null;
|
|
48744
|
-
}
|
|
48745
|
-
} catch {}
|
|
49813
|
+
const cloud = cloudPolicyStatus2();
|
|
49814
|
+
if (cloud.count > 0)
|
|
49815
|
+
return null;
|
|
49816
|
+
observing ||= cloud.observing;
|
|
48746
49817
|
if (configuredCustomPolicyPaths(config).length > 0)
|
|
48747
49818
|
return null;
|
|
48748
|
-
const projectDir =
|
|
49819
|
+
const projectDir = resolve41(findProjectConfigDir(cwd ?? process.cwd()), ".failproofai", "policies");
|
|
48749
49820
|
if (discoverPolicyFiles(projectDir).length > 0 || discoverPolicyFiles(customPoliciesDir()).length > 0) {
|
|
48750
49821
|
return null;
|
|
48751
49822
|
}
|
|
@@ -48841,9 +49912,9 @@ async function installHooksImpl2(policyNames, scope = "user", cwd, includeBeta =
|
|
|
48841
49912
|
delete configToWrite.customPoliciesPath;
|
|
48842
49913
|
delete configToWrite.customPoliciesPaths;
|
|
48843
49914
|
} else if (customPoliciesPath && (typeof customPoliciesPath === "string" || customPoliciesPath.length > 0)) {
|
|
48844
|
-
const incoming = (typeof customPoliciesPath === "string" ? [customPoliciesPath] : customPoliciesPath).map((path) =>
|
|
48845
|
-
const carried = (previousConfig.customPoliciesPaths ?? (previousConfig.customPoliciesPath ? [previousConfig.customPoliciesPath] : [])).map((path) =>
|
|
48846
|
-
if (
|
|
49915
|
+
const incoming = (typeof customPoliciesPath === "string" ? [customPoliciesPath] : customPoliciesPath).map((path) => resolve41(path));
|
|
49916
|
+
const carried = (previousConfig.customPoliciesPaths ?? (previousConfig.customPoliciesPath ? [previousConfig.customPoliciesPath] : [])).map((path) => resolve41(path)).filter((path) => {
|
|
49917
|
+
if (existsSync59(path))
|
|
48847
49918
|
return true;
|
|
48848
49919
|
console.log(`Dropping custom policies path (file no longer exists): ${path}`);
|
|
48849
49920
|
return false;
|
|
@@ -48928,7 +49999,7 @@ Validated ${validatedHooks.length} custom hook(s) from ${path}: ${validatedHooks
|
|
|
48928
49999
|
const placed = installCodexSystemHooks(codexSystemHookEntries(binaryPath));
|
|
48929
50000
|
if (placed.ok) {
|
|
48930
50001
|
const userPath = integration.getSettingsPath("user", cwd);
|
|
48931
|
-
if (
|
|
50002
|
+
if (existsSync59(userPath))
|
|
48932
50003
|
integration.removeHooksFromFile(userPath);
|
|
48933
50004
|
writtenSettingsPaths.push({ cli: cliId, path: placed.path });
|
|
48934
50005
|
continue;
|
|
@@ -49125,7 +50196,7 @@ async function removeHooks2(policyNames, scope = "user", cwd, opts) {
|
|
|
49125
50196
|
}
|
|
49126
50197
|
}
|
|
49127
50198
|
const settingsPaths = settingsPathsFor(integration, s, cwd);
|
|
49128
|
-
const existing = cliId === "hermes" ? settingsPaths : settingsPaths.filter((p) =>
|
|
50199
|
+
const existing = cliId === "hermes" ? settingsPaths : settingsPaths.filter((p) => existsSync59(p));
|
|
49129
50200
|
if (existing.length === 0) {
|
|
49130
50201
|
totalRemoved += removedFromSystem;
|
|
49131
50202
|
if (removedFromSystem > 0)
|
|
@@ -49282,7 +50353,9 @@ function renderPoliciesScreen(screen, opts = {}) {
|
|
|
49282
50353
|
out.push(`${INDENT}Jev mode: off, set by FailproofAI Cloud (overrides jev.json).`);
|
|
49283
50354
|
} else if (jevMode) {
|
|
49284
50355
|
out.push(`${INDENT}Jev mode: ${jevMode}, set by FailproofAI Cloud. Jev checks run on FailproofAI Cloud; nothing of them is installed here.`);
|
|
49285
|
-
|
|
50356
|
+
if (!screen.cloud.jevListed) {
|
|
50357
|
+
out.push(`${INDENT}Jev-only Cloud policies are not listed here; see them with ${kit.cmd("fp fleet show")} or on the dashboard.`);
|
|
50358
|
+
}
|
|
49286
50359
|
}
|
|
49287
50360
|
for (const problem of problems ?? [])
|
|
49288
50361
|
out.push(kit.caution(problem));
|
|
@@ -49332,8 +50405,8 @@ async function listHooks(cwd, { all = false } = {}) {
|
|
|
49332
50405
|
const custom = [];
|
|
49333
50406
|
let customProblem = null;
|
|
49334
50407
|
for (const path of configuredCustomPolicyPaths(config)) {
|
|
49335
|
-
const absPath =
|
|
49336
|
-
if (!
|
|
50408
|
+
const absPath = resolve41(findProjectConfigDir(cwd ?? process.cwd()), path);
|
|
50409
|
+
if (!existsSync59(absPath)) {
|
|
49337
50410
|
custom.push({ state: "failed", name: absPath, description: "not found" });
|
|
49338
50411
|
customProblem ??= "A custom policy file was not found, so its policies are not running.";
|
|
49339
50412
|
continue;
|
|
@@ -49353,7 +50426,7 @@ async function listHooks(cwd, { all = false } = {}) {
|
|
|
49353
50426
|
}
|
|
49354
50427
|
}
|
|
49355
50428
|
const base = findProjectConfigDir(cwd ?? process.cwd());
|
|
49356
|
-
const projectDir =
|
|
50429
|
+
const projectDir = resolve41(base, ".failproofai", "policies");
|
|
49357
50430
|
const userDir = customPoliciesDir();
|
|
49358
50431
|
const sameDir = userDir === projectDir;
|
|
49359
50432
|
const conventionDirs = [
|
|
@@ -49441,19 +50514,27 @@ async function listHooks(cwd, { all = false } = {}) {
|
|
|
49441
50514
|
loadErrors.set(e.id, e.message);
|
|
49442
50515
|
}
|
|
49443
50516
|
} catch {}
|
|
49444
|
-
let
|
|
50517
|
+
let jevAssignments = null;
|
|
49445
50518
|
try {
|
|
49446
|
-
|
|
49447
|
-
|
|
49448
|
-
|
|
49449
|
-
|
|
49450
|
-
|
|
49451
|
-
const labels = active.some((a) => a.agentTargets?.some((tg) => tg.instanceId)) ? readRosterLabels() : new Map;
|
|
50519
|
+
jevAssignments = readCloudJevAssignments();
|
|
50520
|
+
} catch {}
|
|
50521
|
+
const jsIds = new Set(active.map((a) => a.id));
|
|
50522
|
+
const jevOnly = (jevAssignments ?? []).filter((a) => !jsIds.has(a.id));
|
|
50523
|
+
const labels = [...active, ...jevOnly].some((a) => a.agentTargets?.some((tg) => tg.instanceId)) ? readRosterLabels() : new Map;
|
|
49452
50524
|
const targetText = (targets) => `for ${targets.map((tg) => tg.instanceId ? `${tg.integration} / ${labels.get(tg.instanceId) ?? tg.instanceId}` : tg.integration).join(", ")}`;
|
|
49453
|
-
if (active.length > 0 || jev.jevMode !== null) {
|
|
50525
|
+
if (active.length > 0 || jevOnly.length > 0 || jev.jevMode !== null) {
|
|
50526
|
+
const jevRows = jevOnly.map((a) => {
|
|
50527
|
+
const tags = [
|
|
50528
|
+
...a.effect === "observe" ? ["observe"] : [],
|
|
50529
|
+
"jev",
|
|
50530
|
+
...a.agentTargets?.length ? [targetText(a.agentTargets)] : []
|
|
50531
|
+
];
|
|
50532
|
+
return { state: "on", name: a.id, description: `v${a.version}`, tag: tags.join(" · ") };
|
|
50533
|
+
});
|
|
49454
50534
|
cloud = {
|
|
49455
50535
|
deployment: active[0]?.deployment ?? jev.deployment ?? null,
|
|
49456
|
-
|
|
50536
|
+
jevListed: jevAssignments !== null,
|
|
50537
|
+
rows: [...active.map((artifact) => {
|
|
49457
50538
|
const both = artifact.authority === "reviewable" && (artifact.reviewedBy?.length ?? 0) > 0;
|
|
49458
50539
|
const checks = both ? (artifact.reviewedBy ?? []).join(", ") : "";
|
|
49459
50540
|
const tags = [
|
|
@@ -49471,21 +50552,13 @@ async function listHooks(cwd, { all = false } = {}) {
|
|
|
49471
50552
|
tag: [...tags, `not loaded: ${failed}`].join(" · ")
|
|
49472
50553
|
};
|
|
49473
50554
|
}
|
|
49474
|
-
if (!loadChecked?.has(`${artifact.id}@${artifact.version}`)) {
|
|
49475
|
-
return {
|
|
49476
|
-
state: "off",
|
|
49477
|
-
name: artifact.id,
|
|
49478
|
-
description: `v${artifact.version}`,
|
|
49479
|
-
tag: [...tags, "not loaded yet: it loads at the next agent tool call"].join(" · ")
|
|
49480
|
-
};
|
|
49481
|
-
}
|
|
49482
50555
|
return {
|
|
49483
50556
|
state: "on",
|
|
49484
50557
|
name: artifact.id,
|
|
49485
50558
|
description: `v${artifact.version}`,
|
|
49486
50559
|
...tags.length > 0 ? { tag: tags.join(" · ") } : {}
|
|
49487
50560
|
};
|
|
49488
|
-
}),
|
|
50561
|
+
}), ...jevRows],
|
|
49489
50562
|
jevMode: jev.jevMode,
|
|
49490
50563
|
problems: [
|
|
49491
50564
|
...jsProblem !== null ? [`The Cloud JavaScript policies could not be read, so none of them is enforcing: ${jsProblem}`] : [],
|
|
@@ -49558,11 +50631,11 @@ var init_manager2 = __esm(() => {
|
|
|
49558
50631
|
});
|
|
49559
50632
|
|
|
49560
50633
|
// src/audit/audit-schedule.ts
|
|
49561
|
-
import { readFileSync as
|
|
50634
|
+
import { readFileSync as readFileSync47 } from "node:fs";
|
|
49562
50635
|
function readAuditSchedule(home) {
|
|
49563
50636
|
let raw;
|
|
49564
50637
|
try {
|
|
49565
|
-
raw =
|
|
50638
|
+
raw = readFileSync47(auditScheduleFile(home), "utf8");
|
|
49566
50639
|
} catch {
|
|
49567
50640
|
return null;
|
|
49568
50641
|
}
|
|
@@ -49914,14 +50987,14 @@ var init_schedule_cli = __esm(() => {
|
|
|
49914
50987
|
});
|
|
49915
50988
|
|
|
49916
50989
|
// scripts/parse-script-args.ts
|
|
49917
|
-
import { resolve as
|
|
50990
|
+
import { resolve as resolve42 } from "path";
|
|
49918
50991
|
function parseStringFlag(flagName, errorLabel, inlineValue, args, index, options) {
|
|
49919
50992
|
const raw = inlineValue ?? args[index + 1];
|
|
49920
50993
|
if (raw === undefined || inlineValue === null && raw.startsWith("-")) {
|
|
49921
50994
|
console.error(`Error: ${flagName} requires ${errorLabel}`);
|
|
49922
50995
|
process.exit(1);
|
|
49923
50996
|
}
|
|
49924
|
-
const value = options?.resolve ?
|
|
50997
|
+
const value = options?.resolve ? resolve42(raw) : raw;
|
|
49925
50998
|
return { value, spliceCount: inlineValue !== null ? 1 : 2 };
|
|
49926
50999
|
}
|
|
49927
51000
|
function parseScriptArgs(argv) {
|
|
@@ -49977,21 +51050,21 @@ function parseScriptArgs(argv) {
|
|
|
49977
51050
|
var init_parse_script_args = () => {};
|
|
49978
51051
|
|
|
49979
51052
|
// scripts/install-diagnosis.mjs
|
|
49980
|
-
import { existsSync as
|
|
49981
|
-
import { dirname as dirname31, resolve as
|
|
49982
|
-
import { homedir as
|
|
51053
|
+
import { existsSync as existsSync60, readFileSync as readFileSync48, realpathSync as realpathSync6 } from "node:fs";
|
|
51054
|
+
import { dirname as dirname31, resolve as resolve43 } from "node:path";
|
|
51055
|
+
import { homedir as homedir40, platform as platform5 } from "node:os";
|
|
49983
51056
|
import { spawnSync } from "node:child_process";
|
|
49984
51057
|
function findPackageRoot(start) {
|
|
49985
51058
|
try {
|
|
49986
51059
|
let dir = realpathSync6(start);
|
|
49987
|
-
if (
|
|
51060
|
+
if (existsSync60(dir) && !existsSync60(resolve43(dir, "package.json"))) {
|
|
49988
51061
|
dir = dirname31(dir);
|
|
49989
51062
|
}
|
|
49990
51063
|
while (true) {
|
|
49991
|
-
const pkgPath =
|
|
49992
|
-
if (
|
|
51064
|
+
const pkgPath = resolve43(dir, "package.json");
|
|
51065
|
+
if (existsSync60(pkgPath)) {
|
|
49993
51066
|
try {
|
|
49994
|
-
const pkg = JSON.parse(
|
|
51067
|
+
const pkg = JSON.parse(readFileSync48(pkgPath, "utf8"));
|
|
49995
51068
|
if (pkg.name === PKG_NAME)
|
|
49996
51069
|
return dir;
|
|
49997
51070
|
} catch {}
|
|
@@ -50009,7 +51082,7 @@ function readPackageVersion(packageRoot) {
|
|
|
50009
51082
|
if (!packageRoot)
|
|
50010
51083
|
return null;
|
|
50011
51084
|
try {
|
|
50012
|
-
const pkg = JSON.parse(
|
|
51085
|
+
const pkg = JSON.parse(readFileSync48(resolve43(packageRoot, "package.json"), "utf8"));
|
|
50013
51086
|
return typeof pkg.version === "string" ? pkg.version : null;
|
|
50014
51087
|
} catch {
|
|
50015
51088
|
return null;
|
|
@@ -50035,16 +51108,16 @@ function locateNpmGlobal() {
|
|
|
50035
51108
|
const root = (res.stdout || "").trim();
|
|
50036
51109
|
if (!root)
|
|
50037
51110
|
return null;
|
|
50038
|
-
const candidate =
|
|
50039
|
-
return
|
|
51111
|
+
const candidate = resolve43(root, PKG_NAME);
|
|
51112
|
+
return existsSync60(resolve43(candidate, "package.json")) ? candidate : null;
|
|
50040
51113
|
} catch {
|
|
50041
51114
|
return null;
|
|
50042
51115
|
}
|
|
50043
51116
|
}
|
|
50044
51117
|
function locateBunGlobal() {
|
|
50045
51118
|
try {
|
|
50046
|
-
const candidate =
|
|
50047
|
-
return
|
|
51119
|
+
const candidate = resolve43(homedir40(), ".bun", "install", "global", "node_modules", PKG_NAME);
|
|
51120
|
+
return existsSync60(resolve43(candidate, "package.json")) ? candidate : null;
|
|
50048
51121
|
} catch {
|
|
50049
51122
|
return null;
|
|
50050
51123
|
}
|
|
@@ -50052,8 +51125,8 @@ function locateBunGlobal() {
|
|
|
50052
51125
|
function buildRecommendation(pathFirstBin) {
|
|
50053
51126
|
if (!pathFirstBin)
|
|
50054
51127
|
return null;
|
|
50055
|
-
const bunBinPrefix =
|
|
50056
|
-
const bunGlobalPrefix =
|
|
51128
|
+
const bunBinPrefix = resolve43(homedir40(), ".bun", "bin") + "/";
|
|
51129
|
+
const bunGlobalPrefix = resolve43(homedir40(), ".bun", "install", "global") + "/";
|
|
50057
51130
|
const isBun = pathFirstBin.startsWith(bunBinPrefix) || pathFirstBin.startsWith(bunGlobalPrefix);
|
|
50058
51131
|
if (isBun) {
|
|
50059
51132
|
return `rm -f ~/.bun/bin/${PKG_NAME} && rm -rf ~/.bun/install/global/node_modules/${PKG_NAME}`;
|
|
@@ -50526,8 +51599,8 @@ var init_launch_ready = () => {};
|
|
|
50526
51599
|
|
|
50527
51600
|
// scripts/launch.ts
|
|
50528
51601
|
import { spawn as spawn2 } from "child_process";
|
|
50529
|
-
import { realpathSync as realpathSync7, existsSync as
|
|
50530
|
-
import { resolve as
|
|
51602
|
+
import { realpathSync as realpathSync7, existsSync as existsSync61 } from "node:fs";
|
|
51603
|
+
import { resolve as resolve44, dirname as dirname32 } from "node:path";
|
|
50531
51604
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
50532
51605
|
function launch(mode, options = {}) {
|
|
50533
51606
|
const { loggingLevel, disableTelemetry, allowedDevOrigins, host, remainingArgs } = parseScriptArgs(process.argv.slice(2));
|
|
@@ -50563,9 +51636,9 @@ ${k.caution(exposedBindWarning(exposed.host))}
|
|
|
50563
51636
|
process.env.PORT = port;
|
|
50564
51637
|
process.env.HOSTNAME = bindHost;
|
|
50565
51638
|
cmd = "node";
|
|
50566
|
-
const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT ??
|
|
50567
|
-
const serverJsPath =
|
|
50568
|
-
if (!
|
|
51639
|
+
const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT ?? resolve44(dirname32(realpathSync7(fileURLToPath2(import.meta.url))), "..");
|
|
51640
|
+
const serverJsPath = resolve44(packageRoot, ".next/standalone/server.js");
|
|
51641
|
+
if (!existsSync61(serverJsPath)) {
|
|
50569
51642
|
let shadowMessage = null;
|
|
50570
51643
|
try {
|
|
50571
51644
|
const diag = diagnoseShadow({ selfPackageRoot: packageRoot, selfVersion: version2 });
|
|
@@ -51272,12 +52345,12 @@ var init_session_pause_cli = __esm(() => {
|
|
|
51272
52345
|
});
|
|
51273
52346
|
|
|
51274
52347
|
// src/hooks/config-status.ts
|
|
51275
|
-
import { readFileSync as
|
|
51276
|
-
import { resolve as
|
|
52348
|
+
import { readFileSync as readFileSync49 } from "node:fs";
|
|
52349
|
+
import { resolve as resolve45 } from "node:path";
|
|
51277
52350
|
function readCollectorHealth(file = collectorHealthFile()) {
|
|
51278
52351
|
let parsed;
|
|
51279
52352
|
try {
|
|
51280
|
-
parsed = JSON.parse(
|
|
52353
|
+
parsed = JSON.parse(readFileSync49(file, "utf8"));
|
|
51281
52354
|
} catch {
|
|
51282
52355
|
return null;
|
|
51283
52356
|
}
|
|
@@ -51347,14 +52420,14 @@ function summarizePolicySources(cwd) {
|
|
|
51347
52420
|
summary.morePacks = Math.max(0, enforcing - 1);
|
|
51348
52421
|
} catch {}
|
|
51349
52422
|
try {
|
|
51350
|
-
for (const artifact of
|
|
52423
|
+
for (const artifact of listActiveCloudManagedPolicies()) {
|
|
51351
52424
|
if (artifact.effect === "observe")
|
|
51352
52425
|
summary.observing++;
|
|
51353
52426
|
else
|
|
51354
52427
|
summary.cloudOn++;
|
|
51355
52428
|
}
|
|
51356
52429
|
} catch {}
|
|
51357
|
-
const projectDir =
|
|
52430
|
+
const projectDir = resolve45(findProjectConfigDir(cwd ?? process.cwd()), ".failproofai", "policies");
|
|
51358
52431
|
const conventionFiles = new Set([...discoverPolicyFiles(projectDir), ...discoverPolicyFiles(customPoliciesDir())]);
|
|
51359
52432
|
summary.customFiles = configuredCustomPolicyPaths(config).length + conventionFiles.size;
|
|
51360
52433
|
if (config.enabledPolicies.length > 0 && !hasInstalledRegexPacks())
|
|
@@ -51555,7 +52628,8 @@ function renderStatusScreen(facts, opts = {}) {
|
|
|
51555
52628
|
}
|
|
51556
52629
|
if (!health.delivering)
|
|
51557
52630
|
return `${kit.off} Not delivering, failproofaid has no key`;
|
|
51558
|
-
const
|
|
52631
|
+
const pending = queued + (refused.resending ?? 0);
|
|
52632
|
+
const backlog = pending === 0 ? "nothing queued" : `${many(pending, "batch", "batches")} queued`;
|
|
51559
52633
|
const stuck = queued > 0 && (oldestQueuedMs ?? 0) > STATUS_QUEUE_STUCK_MS && (health.lastOkAt === undefined || now - health.lastOkAt > STATUS_QUEUE_STUCK_MS);
|
|
51560
52634
|
if (stuck) {
|
|
51561
52635
|
const last = health.lastOkAt !== undefined ? `last delivered ${ago(health.lastOkAt)}` : "nothing delivered since failproofaid started";
|
|
@@ -51790,8 +52864,8 @@ var init_session_pause_cli2 = __esm(() => {
|
|
|
51790
52864
|
|
|
51791
52865
|
// scripts/launch.ts
|
|
51792
52866
|
import { spawn as spawn3 } from "child_process";
|
|
51793
|
-
import { realpathSync as realpathSync8, existsSync as
|
|
51794
|
-
import { resolve as
|
|
52867
|
+
import { realpathSync as realpathSync8, existsSync as existsSync62 } from "node:fs";
|
|
52868
|
+
import { resolve as resolve46, dirname as dirname33 } from "node:path";
|
|
51795
52869
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
51796
52870
|
function launch2(mode, options = {}) {
|
|
51797
52871
|
const { loggingLevel, disableTelemetry, allowedDevOrigins, host, remainingArgs } = parseScriptArgs(process.argv.slice(2));
|
|
@@ -51827,9 +52901,9 @@ ${k.caution(exposedBindWarning(exposed.host))}
|
|
|
51827
52901
|
process.env.PORT = port;
|
|
51828
52902
|
process.env.HOSTNAME = bindHost;
|
|
51829
52903
|
cmd = "node";
|
|
51830
|
-
const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT ??
|
|
51831
|
-
const serverJsPath =
|
|
51832
|
-
if (!
|
|
52904
|
+
const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT ?? resolve46(dirname33(realpathSync8(fileURLToPath3(import.meta.url))), "..");
|
|
52905
|
+
const serverJsPath = resolve46(packageRoot, ".next/standalone/server.js");
|
|
52906
|
+
if (!existsSync62(serverJsPath)) {
|
|
51833
52907
|
let shadowMessage = null;
|
|
51834
52908
|
try {
|
|
51835
52909
|
const diag = diagnoseShadow({ selfPackageRoot: packageRoot, selfVersion: version2 });
|
|
@@ -51949,17 +53023,17 @@ var init_cli_error2 = __esm(() => {
|
|
|
51949
53023
|
|
|
51950
53024
|
// bin/failproofai.mjs
|
|
51951
53025
|
import { realpathSync as realpathSync9 } from "fs";
|
|
51952
|
-
import { dirname as dirname34, resolve as
|
|
53026
|
+
import { dirname as dirname34, resolve as resolve47 } from "path";
|
|
51953
53027
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
51954
53028
|
// package.json
|
|
51955
|
-
var version = "1.0.12-beta.
|
|
53029
|
+
var version = "1.0.12-beta.2";
|
|
51956
53030
|
|
|
51957
53031
|
// bin/failproofai.mjs
|
|
51958
53032
|
if (!process.env.FAILPROOFAI_PACKAGE_ROOT) {
|
|
51959
|
-
process.env.FAILPROOFAI_PACKAGE_ROOT =
|
|
53033
|
+
process.env.FAILPROOFAI_PACKAGE_ROOT = resolve47(dirname34(realpathSync9(fileURLToPath4(import.meta.url))), "..");
|
|
51960
53034
|
}
|
|
51961
53035
|
if (!process.env.FAILPROOFAI_DIST_PATH) {
|
|
51962
|
-
process.env.FAILPROOFAI_DIST_PATH =
|
|
53036
|
+
process.env.FAILPROOFAI_DIST_PATH = resolve47(dirname34(realpathSync9(fileURLToPath4(import.meta.url))), "..", "dist");
|
|
51963
53037
|
}
|
|
51964
53038
|
var args = process.argv.slice(2);
|
|
51965
53039
|
if (args[0] === "p" || args[0] === "policy")
|