failproofai 1.0.0-beta.6 → 1.0.0-beta.8
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 +7 -7
- 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 +7 -7
- package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +3 -3
- 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 +14 -14
- package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +14 -14
- package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +9 -9
- 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/_not-found.segment.rsc +3 -3
- 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/reminder/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 +14 -14
- package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +14 -14
- package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +9 -9
- 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 +10 -10
- 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 +4 -4
- 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/[root-of-the-server]__06hexd0._.js +1 -1
- package/.next/standalone/.next/server/chunks/_0lxbzdq._.js +1 -1
- package/.next/standalone/.next/server/chunks/_1zuiiy3._.js +1 -1
- package/.next/standalone/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_17k9e3w.js +3 -3
- package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1e7-pa7._.js → [root-of-the-server]__0ommekk._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0spkm68._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1rv-sc9._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1_a_gwn._.js → [root-of-the-server]__1tkyag1._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1tyf0tc._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1u-wx42._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1v185mo._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_04mekdy._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{_0igtyj5._.js → _0i4l3_6._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_0r-dsre._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_0rjgfln._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_0se484m._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_0uz7o9y._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_1fahg9e._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_1w8sola._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_1w_6p9g._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_builtin-policies_ts_09j2ndl._.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/server-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.json +15 -15
- package/.next/standalone/.next/static/chunks/02vvywmww22zz.js +1 -0
- package/.next/standalone/.next/static/chunks/{34fa65k0cldkj.js → 0_-focvo4cuiv.js} +1 -1
- package/.next/standalone/.next/static/chunks/{3f_939wi3kfnx.js → 1fwh-2un_l-eo.js} +1 -1
- package/.next/standalone/.next/static/chunks/{3p1vpm2_-tfwm.js → 1zrdsxe91qq6i.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0_2n13i94rnw5.js → 2047vah_v4emu.js} +1 -1
- package/.next/standalone/.next/static/chunks/{35v07j9gc1pvr.js → 23hl78dzffun4.js} +1 -1
- package/.next/standalone/.next/static/chunks/2bw0stk-s-1dd.js +1 -0
- package/.next/standalone/.next/static/chunks/{3rbpw_waieafm.js → 2r_j5wrkbu5wm.js} +1 -1
- package/.next/standalone/.next/static/chunks/{23557z4e6dtsr.js → 3m8onpqrjxzu5.js} +1 -1
- package/.next/standalone/.next/static/chunks/{28zkwzu50puki.js → 3yn1y6ckypqwp.js} +1 -1
- package/.next/standalone/package.json +5 -5
- package/.next/standalone/server.js +1 -1
- package/bin/failproofai.mjs +143 -27
- package/dist/cli.mjs +1288 -118
- package/dist/worker.mjs +77 -6
- package/package.json +5 -5
- package/scripts/repro-npm-install.sh +155 -0
- package/src/hooks/builtin-policies.ts +154 -2
- package/src/hooks/configure-wizard.ts +70 -6
- package/src/hooks/daemon-client.ts +35 -0
- package/src/hooks/daemon-service.ts +237 -24
- package/src/hooks/first-run-gate.ts +9 -1
- package/src/hooks/fp-home.ts +13 -0
- package/src/hooks/fp-reset.ts +25 -0
- package/src/hooks/onboarding-attempt.ts +179 -0
- package/src/hooks/uninstall-cli.ts +345 -0
- package/src/hooks/worker-server.ts +12 -2
- package/.next/standalone/.next/static/chunks/3081gykdubv8b.js +0 -1
- package/.next/standalone/.next/static/chunks/40ffnfpkeyvb0.js +0 -1
- /package/.next/standalone/.next/static/{Ptn8aBQl_cnNgOd0ebyv0 → gOR8i03AeQm1VnIayDHVV}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{Ptn8aBQl_cnNgOd0ebyv0 → gOR8i03AeQm1VnIayDHVV}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{Ptn8aBQl_cnNgOd0ebyv0 → gOR8i03AeQm1VnIayDHVV}/_ssgManifest.js +0 -0
package/dist/cli.mjs
CHANGED
|
@@ -19,7 +19,7 @@ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
|
19
19
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
20
20
|
|
|
21
21
|
// package.json
|
|
22
|
-
var version2 = "1.0.0-beta.
|
|
22
|
+
var version2 = "1.0.0-beta.8";
|
|
23
23
|
var init_package = () => {};
|
|
24
24
|
|
|
25
25
|
// src/posthog-key.ts
|
|
@@ -1025,7 +1025,7 @@ function resettablePaths() {
|
|
|
1025
1025
|
logsDir()
|
|
1026
1026
|
];
|
|
1027
1027
|
}
|
|
1028
|
-
var LAYOUT_VERSION = 2, at = (...parts) => resolve(failproofaiHome(), ...parts), atHome = (home, ...parts) => home ? resolve(failproofaiHome(home), ...parts) : at(...parts), versionFile = (home) => atHome(home, "VERSION"), configFile = (home) => atHome(home, "config.toml"), credentialsFile = (home) => atHome(home, "credentials.toml"), binDir = (home) => atHome(home, "bin"), policiesDir = (home) => atHome(home, "policies"), localPoliciesDir = (home) => atHome(home, "policies", "local-policies"), globalPolicyConfigFile = (home) => resolve(localPoliciesDir(home), "policies-config.json"), cloudPoliciesDir = (home) => resolve(policiesDir(home), "cloud-policies"), customPoliciesDir = (home) => resolve(policiesDir(home), "custom-policies"), customAgentsDir = (home) => atHome(home, "custom-agents"), auditDir = (home) => atHome(home, "audit"), auditDashboardFile = (home) => resolve(auditDir(home), "dashboard.json"), auditCacheDir = (home) => resolve(auditDir(home), "cache"), hookActivityDir = (home) => atHome(home, "hook-activity"), runDir = (home) => atHome(home, "run"), daemonSocket = () => process.env.FAILPROOFAI_DAEMON_SOCKET || resolve(runDir(), "failproofaid.sock"), auditLockFile = (home) => resolve(runDir(home), "audit.lock"), stateDir = (home) => atHome(home, "state"), shimsDir = (home) => resolve(stateDir(home), "shims"), sessionPauseDir = () => resolve(stateDir(), "sessions"), telemetryIdFile = (home) => resolve(stateDir(home), "telemetry-id"), launcherMarker = (home) => resolve(stateDir(home), "launcher-configured"), lastVersionFile = (home) => resolve(stateDir(home), "last-version"), onboardingLockFile = (home) => resolve(stateDir(home), "onboarding.lock"), codexSessionPathsFile = (home) => resolve(stateDir(home), "codex-session-paths.json"), logsDir = (home) => atHome(home, "logs"), legacy;
|
|
1028
|
+
var LAYOUT_VERSION = 2, at = (...parts) => resolve(failproofaiHome(), ...parts), atHome = (home, ...parts) => home ? resolve(failproofaiHome(home), ...parts) : at(...parts), versionFile = (home) => atHome(home, "VERSION"), configFile = (home) => atHome(home, "config.toml"), credentialsFile = (home) => atHome(home, "credentials.toml"), binDir = (home) => atHome(home, "bin"), policiesDir = (home) => atHome(home, "policies"), localPoliciesDir = (home) => atHome(home, "policies", "local-policies"), globalPolicyConfigFile = (home) => resolve(localPoliciesDir(home), "policies-config.json"), cloudPoliciesDir = (home) => resolve(policiesDir(home), "cloud-policies"), customPoliciesDir = (home) => resolve(policiesDir(home), "custom-policies"), customAgentsDir = (home) => atHome(home, "custom-agents"), auditDir = (home) => atHome(home, "audit"), auditDashboardFile = (home) => resolve(auditDir(home), "dashboard.json"), auditCacheDir = (home) => resolve(auditDir(home), "cache"), hookActivityDir = (home) => atHome(home, "hook-activity"), runDir = (home) => atHome(home, "run"), daemonSocket = () => process.env.FAILPROOFAI_DAEMON_SOCKET || resolve(runDir(), "failproofaid.sock"), auditLockFile = (home) => resolve(runDir(home), "audit.lock"), stateDir = (home) => atHome(home, "state"), shimsDir = (home) => resolve(stateDir(home), "shims"), sessionPauseDir = () => resolve(stateDir(), "sessions"), telemetryIdFile = (home) => resolve(stateDir(home), "telemetry-id"), launcherMarker = (home) => resolve(stateDir(home), "launcher-configured"), onboardingAttemptFile = (home) => resolve(stateDir(home), "onboarding-attempt.json"), lastVersionFile = (home) => resolve(stateDir(home), "last-version"), onboardingLockFile = (home) => resolve(stateDir(home), "onboarding.lock"), codexSessionPathsFile = (home) => resolve(stateDir(home), "codex-session-paths.json"), logsDir = (home) => atHome(home, "logs"), legacy;
|
|
1029
1029
|
var init_fp_home = __esm(() => {
|
|
1030
1030
|
legacy = {
|
|
1031
1031
|
policyConfig: () => at("policies-config.json"),
|
|
@@ -1454,6 +1454,7 @@ __export(exports_daemon_client, {
|
|
|
1454
1454
|
tryDaemonHook: () => tryDaemonHook,
|
|
1455
1455
|
isDaemonConfigured: () => isDaemonConfigured,
|
|
1456
1456
|
daemonSocketPresent: () => daemonSocketPresent,
|
|
1457
|
+
daemonAcceptsConnections: () => daemonAcceptsConnections,
|
|
1457
1458
|
attemptDaemonHook: () => attemptDaemonHook
|
|
1458
1459
|
});
|
|
1459
1460
|
import { createConnection } from "node:net";
|
|
@@ -1465,6 +1466,27 @@ function daemonSocketPresent() {
|
|
|
1465
1466
|
return false;
|
|
1466
1467
|
}
|
|
1467
1468
|
}
|
|
1469
|
+
async function daemonAcceptsConnections(timeoutMs = DAEMON_CONNECT_TIMEOUT_MS) {
|
|
1470
|
+
if (process.platform === "win32")
|
|
1471
|
+
return false;
|
|
1472
|
+
return new Promise((resolve2) => {
|
|
1473
|
+
let settled = false;
|
|
1474
|
+
const done = (v) => {
|
|
1475
|
+
if (settled)
|
|
1476
|
+
return;
|
|
1477
|
+
settled = true;
|
|
1478
|
+
clearTimeout(timer);
|
|
1479
|
+
socket.removeAllListeners();
|
|
1480
|
+
socket.destroy();
|
|
1481
|
+
resolve2(v);
|
|
1482
|
+
};
|
|
1483
|
+
const socket = createConnection({ path: socketPath() });
|
|
1484
|
+
const timer = setTimeout(() => done(false), timeoutMs);
|
|
1485
|
+
timer.unref?.();
|
|
1486
|
+
socket.on("connect", () => done(true));
|
|
1487
|
+
socket.on("error", () => done(false));
|
|
1488
|
+
});
|
|
1489
|
+
}
|
|
1468
1490
|
function socketPath() {
|
|
1469
1491
|
if (process.env.FAILPROOFAI_DAEMON_SOCKET)
|
|
1470
1492
|
return process.env.FAILPROOFAI_DAEMON_SOCKET;
|
|
@@ -2751,11 +2773,82 @@ function blockEnvFiles(ctx) {
|
|
|
2751
2773
|
}
|
|
2752
2774
|
return allow();
|
|
2753
2775
|
}
|
|
2776
|
+
function quoteAwareSegments(command) {
|
|
2777
|
+
const segments = [];
|
|
2778
|
+
let tokens = [];
|
|
2779
|
+
let token = "";
|
|
2780
|
+
let quote = null;
|
|
2781
|
+
const endToken = () => {
|
|
2782
|
+
if (token)
|
|
2783
|
+
tokens.push(token);
|
|
2784
|
+
token = "";
|
|
2785
|
+
};
|
|
2786
|
+
const endSegment = () => {
|
|
2787
|
+
endToken();
|
|
2788
|
+
if (tokens.length)
|
|
2789
|
+
segments.push(tokens);
|
|
2790
|
+
tokens = [];
|
|
2791
|
+
};
|
|
2792
|
+
for (let i = 0;i < command.length; i++) {
|
|
2793
|
+
const c = command[i];
|
|
2794
|
+
if (quote) {
|
|
2795
|
+
if (c === "\\" && quote === '"' && i + 1 < command.length) {
|
|
2796
|
+
token += command[++i];
|
|
2797
|
+
continue;
|
|
2798
|
+
}
|
|
2799
|
+
if (c === quote) {
|
|
2800
|
+
quote = null;
|
|
2801
|
+
continue;
|
|
2802
|
+
}
|
|
2803
|
+
token += c;
|
|
2804
|
+
continue;
|
|
2805
|
+
}
|
|
2806
|
+
if (c === "\\" && i + 1 < command.length) {
|
|
2807
|
+
token += command[++i];
|
|
2808
|
+
continue;
|
|
2809
|
+
}
|
|
2810
|
+
if (c === '"' || c === "'") {
|
|
2811
|
+
quote = c;
|
|
2812
|
+
continue;
|
|
2813
|
+
}
|
|
2814
|
+
if (/\s/.test(c)) {
|
|
2815
|
+
endToken();
|
|
2816
|
+
continue;
|
|
2817
|
+
}
|
|
2818
|
+
if (/[;&|\n\r(){}`]/.test(c)) {
|
|
2819
|
+
endSegment();
|
|
2820
|
+
continue;
|
|
2821
|
+
}
|
|
2822
|
+
token += c;
|
|
2823
|
+
}
|
|
2824
|
+
endSegment();
|
|
2825
|
+
return segments;
|
|
2826
|
+
}
|
|
2827
|
+
function namesElevation(command, depth = 0) {
|
|
2828
|
+
for (const tokens of quoteAwareSegments(command)) {
|
|
2829
|
+
let i = 0;
|
|
2830
|
+
while (i < tokens.length) {
|
|
2831
|
+
const token = tokens[i];
|
|
2832
|
+
const base = token.slice(token.lastIndexOf("/") + 1);
|
|
2833
|
+
if (base === "sudo" || base === "doas")
|
|
2834
|
+
return true;
|
|
2835
|
+
const isSkippable = ENV_ASSIGNMENT_RE.test(token) || token.startsWith("-") || token.startsWith(">") || token.startsWith("<") || RUNNER_OPERAND_RE.test(token) || COMMAND_PREFIX_TOKENS.has(base);
|
|
2836
|
+
if (!isSkippable)
|
|
2837
|
+
break;
|
|
2838
|
+
if (EVAL_FLAG_RE.test(token) && depth < 3 && i + 1 < tokens.length) {
|
|
2839
|
+
if (namesElevation(tokens[i + 1], depth + 1))
|
|
2840
|
+
return true;
|
|
2841
|
+
}
|
|
2842
|
+
i++;
|
|
2843
|
+
}
|
|
2844
|
+
}
|
|
2845
|
+
return false;
|
|
2846
|
+
}
|
|
2754
2847
|
function blockSudo(ctx) {
|
|
2755
2848
|
if (ctx.toolName !== "Bash")
|
|
2756
2849
|
return allow();
|
|
2757
2850
|
const cmd = getCommand(ctx).trimStart();
|
|
2758
|
-
if (
|
|
2851
|
+
if (namesElevation(cmd)) {
|
|
2759
2852
|
const allowPatterns = ctx.params?.allowPatterns ?? [];
|
|
2760
2853
|
if (allowPatterns.some((p) => matchesAllowedPattern(cmd, p)))
|
|
2761
2854
|
return allow();
|
|
@@ -3515,7 +3608,7 @@ function registerBuiltinPolicies(enabledNames) {
|
|
|
3515
3608
|
}
|
|
3516
3609
|
}
|
|
3517
3610
|
}
|
|
3518
|
-
var isClaudeInternalPath, isClaudeSettingsFile, SHELL_OPERATORS, SHELL_METACHAR_RE, JWT_RE, API_KEY_PATTERNS, CONNECTION_STRING_RE, PRIVATE_KEY_RE, BEARER_TOKEN_RE, SQL_TOOL_RE, DESTRUCTIVE_SQL_RE, DELETE_NO_WHERE_RE, SQL_WHERE_RE, SCHEMA_ALTER_RE, PUBLISH_CMD_RE, ENV_PRINTENV_RE, ECHO_ENV_RE, EXPORT_RE, PS_ENV_VAR_RE, PS_CHILDITEM_ENV_RE, DOTNET_GETENV_RE, CMD_ECHO_ENV_RE, ENV_FILE_PATH_RE, ENV_CMD_RE,
|
|
3611
|
+
var isClaudeInternalPath, isClaudeSettingsFile, SHELL_OPERATORS, SHELL_METACHAR_RE, JWT_RE, API_KEY_PATTERNS, CONNECTION_STRING_RE, PRIVATE_KEY_RE, BEARER_TOKEN_RE, SQL_TOOL_RE, DESTRUCTIVE_SQL_RE, DELETE_NO_WHERE_RE, SQL_WHERE_RE, SCHEMA_ALTER_RE, PUBLISH_CMD_RE, ENV_PRINTENV_RE, ECHO_ENV_RE, EXPORT_RE, PS_ENV_VAR_RE, PS_CHILDITEM_ENV_RE, DOTNET_GETENV_RE, CMD_ECHO_ENV_RE, ENV_FILE_PATH_RE, ENV_CMD_RE, PS_ELEVATION_RE, RUNAS_RE, CURL_PIPE_SH_RE, SEGMENT_SEPARATORS, COMMAND_PREFIX_TOKENS, SELF_BINARY_TOKEN_RE, CONFIG_SUBCOMMAND_RE, PAUSE_FLAG_RE, ENV_ASSIGNMENT_RE, RUNNER_OPERAND_RE, PS_WEB_PIPE_RE, SHORT_FLAG_BUNDLE_RE, SAFE_FORCE_PREFIXES, SECRET_FILE_RE, SECRET_FILE_ID_RSA_RE, SECRET_FILE_CREDENTIALS_RE, GIT_COMMIT_MERGE_RE, FAILPROOFAI_CLI_RE, FAILPROOFAI_UNINSTALL_RE, GIT_AMEND_RE, GIT_STASH_DROP_RE, GIT_ADD_ALL_RE, NPM_GLOBAL_RE, YARN_GLOBAL_RE, PNPM_GLOBAL_RE, BUN_GLOBAL_RE, CARGO_INSTALL_RE, PIP_SYSTEM_RE, PKG_MANAGER_DETECTORS, NOHUP_RE, SCREEN_DETACH_RE, TMUX_DETACH_RE, DISOWN_RE, BACKGROUND_AMPERSAND_RE, KUBECTL_RE, TERRAFORM_RE, AWS_CLI_RE, GCLOUD_RE, AZ_CLI_RE, HELM_RE, GH_PIPELINE_RE, gitBranchCache, GIT_BRANCH_CACHE_MAX_ENTRIES = 500, EVAL_FLAG_RE, HOME_PREFIX_RE, RM_CMD_RE, FIND_CMD_RE, FIND_EXEC_RE, FIND_GLOBAL_OPT_RE, FIND_EXPR_START_RE, SCRATCH_ROOTS, CATASTROPHIC_DEPTH = 2, READ_LIKE_CMDS, TOOL_CALL_TRACKER_MAX_BYTES = 65536, SEGMENT_SPLIT_RE, BUILTIN_POLICIES;
|
|
3519
3612
|
var init_builtin_policies = __esm(() => {
|
|
3520
3613
|
init_hook_logger();
|
|
3521
3614
|
isClaudeInternalPath = isAgentInternalPath;
|
|
@@ -3552,7 +3645,6 @@ var init_builtin_policies = __esm(() => {
|
|
|
3552
3645
|
CMD_ECHO_ENV_RE = /echo\s+%[A-Za-z_]/i;
|
|
3553
3646
|
ENV_FILE_PATH_RE = /(?:^|[\\/])\.env(?:\.|$)/;
|
|
3554
3647
|
ENV_CMD_RE = /\.env(?:\b|\s|$|\.)/;
|
|
3555
|
-
SUDO_RE = /(?:^|;|&&|\|\|)\s*sudo\s/;
|
|
3556
3648
|
PS_ELEVATION_RE = /Start-Process\s+.*-Verb\s+RunAs/i;
|
|
3557
3649
|
RUNAS_RE = /(?:^|;|&&|\|\|)\s*runas\s/i;
|
|
3558
3650
|
CURL_PIPE_SH_RE = /(?:curl|wget)\s.*\|\s*(?:sh|bash|zsh|dash|ksh|csh|tcsh|fish|ash)\b/;
|
|
@@ -3638,6 +3730,7 @@ var init_builtin_policies = __esm(() => {
|
|
|
3638
3730
|
HELM_RE = /(?:^|[;\n]|&&|\|\|?|&)\s*helm(?:\s|$)/;
|
|
3639
3731
|
GH_PIPELINE_RE = /(?:^|[;\n]|&&|\|\|?|&)\s*gh\s+(?:workflow\s+(?:run|enable|disable)|run\s+(?:rerun|cancel)|pr\s+merge|release\s+(?:create|delete)|cache\s+delete|secret\s+(?:set|delete))\b/;
|
|
3640
3732
|
gitBranchCache = new Map;
|
|
3733
|
+
EVAL_FLAG_RE = /^-{1,2}c$/;
|
|
3641
3734
|
HOME_PREFIX_RE = /^(?:~[A-Za-z0-9_.-]*|\$HOME|\$\{HOME\})(?=$|\/)/;
|
|
3642
3735
|
RM_CMD_RE = /^(?:\/\S*\/)?rm$/;
|
|
3643
3736
|
FIND_CMD_RE = /^(?:\/\S*\/)?find$/;
|
|
@@ -10739,6 +10832,7 @@ __export(exports_daemon_client2, {
|
|
|
10739
10832
|
tryDaemonHook: () => tryDaemonHook2,
|
|
10740
10833
|
isDaemonConfigured: () => isDaemonConfigured2,
|
|
10741
10834
|
daemonSocketPresent: () => daemonSocketPresent2,
|
|
10835
|
+
daemonAcceptsConnections: () => daemonAcceptsConnections2,
|
|
10742
10836
|
attemptDaemonHook: () => attemptDaemonHook2
|
|
10743
10837
|
});
|
|
10744
10838
|
import { createConnection as createConnection2 } from "node:net";
|
|
@@ -10750,6 +10844,27 @@ function daemonSocketPresent2() {
|
|
|
10750
10844
|
return false;
|
|
10751
10845
|
}
|
|
10752
10846
|
}
|
|
10847
|
+
async function daemonAcceptsConnections2(timeoutMs = DAEMON_CONNECT_TIMEOUT_MS2) {
|
|
10848
|
+
if (process.platform === "win32")
|
|
10849
|
+
return false;
|
|
10850
|
+
return new Promise((resolve14) => {
|
|
10851
|
+
let settled = false;
|
|
10852
|
+
const done = (v) => {
|
|
10853
|
+
if (settled)
|
|
10854
|
+
return;
|
|
10855
|
+
settled = true;
|
|
10856
|
+
clearTimeout(timer);
|
|
10857
|
+
socket.removeAllListeners();
|
|
10858
|
+
socket.destroy();
|
|
10859
|
+
resolve14(v);
|
|
10860
|
+
};
|
|
10861
|
+
const socket = createConnection2({ path: socketPath2() });
|
|
10862
|
+
const timer = setTimeout(() => done(false), timeoutMs);
|
|
10863
|
+
timer.unref?.();
|
|
10864
|
+
socket.on("connect", () => done(true));
|
|
10865
|
+
socket.on("error", () => done(false));
|
|
10866
|
+
});
|
|
10867
|
+
}
|
|
10753
10868
|
function socketPath2() {
|
|
10754
10869
|
if (process.env.FAILPROOFAI_DAEMON_SOCKET)
|
|
10755
10870
|
return process.env.FAILPROOFAI_DAEMON_SOCKET;
|
|
@@ -10947,6 +11062,15 @@ function resolveCliCommand() {
|
|
|
10947
11062
|
function shellQuote(value) {
|
|
10948
11063
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
10949
11064
|
}
|
|
11065
|
+
function workerScriptPath() {
|
|
11066
|
+
if (process.env.FAILPROOFAI_WORKER_CMD)
|
|
11067
|
+
return null;
|
|
11068
|
+
const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT;
|
|
11069
|
+
if (!packageRoot)
|
|
11070
|
+
return null;
|
|
11071
|
+
const workerScript = resolve14(packageRoot, "dist", "worker.mjs");
|
|
11072
|
+
return existsSync17(workerScript) ? workerScript : null;
|
|
11073
|
+
}
|
|
10950
11074
|
function assertUnitSafe(value, field) {
|
|
10951
11075
|
if (UNIT_UNSAFE_RE.test(value)) {
|
|
10952
11076
|
throw new Error(`refusing to write a service definition: ${field} contains a quote, backslash or newline ` + `(${JSON.stringify(value)}), which would inject directives into a root-owned unit file`);
|
|
@@ -11085,10 +11209,13 @@ function systemdUnitContents(binaryPath, workerCmd, cliCmd = null) {
|
|
|
11085
11209
|
const user = assertUnitSafe(serviceUser(), "User");
|
|
11086
11210
|
assertUnitSafe(binaryPath, "ExecStart");
|
|
11087
11211
|
assertUnitSafe(homedir19(), "HOME");
|
|
11212
|
+
const conditionPaths = [binaryPath, workerScriptPath()].filter((p) => typeof p === "string" && existsSync17(p));
|
|
11213
|
+
const conditionLines = conditionPaths.map((p) => `ConditionPathExists=${assertUnitSafe(p, "ConditionPathExists")}
|
|
11214
|
+
`).join("");
|
|
11088
11215
|
return `[Unit]
|
|
11089
11216
|
Description=failproofai background daemon (failproofaid) for ${user}
|
|
11090
11217
|
After=network.target
|
|
11091
|
-
|
|
11218
|
+
${conditionLines}
|
|
11092
11219
|
[Service]
|
|
11093
11220
|
Type=simple
|
|
11094
11221
|
User=${user}
|
|
@@ -11209,19 +11336,37 @@ async function installDaemonService() {
|
|
|
11209
11336
|
}
|
|
11210
11337
|
return { installed: true };
|
|
11211
11338
|
}
|
|
11212
|
-
async function
|
|
11339
|
+
async function probeDaemon() {
|
|
11213
11340
|
try {
|
|
11214
|
-
const { attemptDaemonHook: attemptDaemonHook3 } = await Promise.resolve().then(() => (init_daemon_client2(), exports_daemon_client2));
|
|
11215
|
-
const
|
|
11216
|
-
|
|
11217
|
-
|
|
11218
|
-
|
|
11219
|
-
|
|
11220
|
-
|
|
11341
|
+
const { attemptDaemonHook: attemptDaemonHook3, daemonAcceptsConnections: daemonAcceptsConnections3 } = await Promise.resolve().then(() => (init_daemon_client2(), exports_daemon_client2));
|
|
11342
|
+
const deadline = Date.now() + DAEMON_PROBE_READY_TIMEOUT_MS;
|
|
11343
|
+
let everConnected = false;
|
|
11344
|
+
for (;; ) {
|
|
11345
|
+
if (await daemonAcceptsConnections3()) {
|
|
11346
|
+
everConnected = true;
|
|
11347
|
+
const attempt = await attemptDaemonHook3({
|
|
11348
|
+
hookEvent: "SessionStart",
|
|
11349
|
+
cli: "claude",
|
|
11350
|
+
stdin: JSON.stringify({
|
|
11351
|
+
hook_event_name: "SessionStart",
|
|
11352
|
+
source: "failproofai-health-probe"
|
|
11353
|
+
})
|
|
11354
|
+
}, { responseTimeoutMs: DAEMON_PROBE_TIMEOUT_MS });
|
|
11355
|
+
if (attempt.ok || attempt.failure === "protocol-mismatch")
|
|
11356
|
+
return { ok: true };
|
|
11357
|
+
}
|
|
11358
|
+
if (Date.now() >= deadline)
|
|
11359
|
+
break;
|
|
11360
|
+
await new Promise((r) => setTimeout(r, DAEMON_PROBE_RETRY_MS));
|
|
11361
|
+
}
|
|
11362
|
+
return { ok: false, reason: everConnected ? "worker" : "unreachable" };
|
|
11221
11363
|
} catch {
|
|
11222
|
-
return false;
|
|
11364
|
+
return { ok: false, reason: "unreachable" };
|
|
11223
11365
|
}
|
|
11224
11366
|
}
|
|
11367
|
+
async function probeDaemonEndToEnd() {
|
|
11368
|
+
return (await probeDaemon()).ok;
|
|
11369
|
+
}
|
|
11225
11370
|
async function waitForDaemonRunning() {
|
|
11226
11371
|
const deadline = Date.now() + SERVICE_START_TIMEOUT_MS;
|
|
11227
11372
|
for (;; ) {
|
|
@@ -11406,6 +11551,16 @@ function daemonVersionSkew() {
|
|
|
11406
11551
|
return null;
|
|
11407
11552
|
return recorded === version2 ? null : { installed: recorded, expected: version2 };
|
|
11408
11553
|
}
|
|
11554
|
+
function inactiveLinuxStatus() {
|
|
11555
|
+
try {
|
|
11556
|
+
return interpretConditionResult(execFileSync3("systemctl", ["show", systemdUnitName(), "--property=ConditionResult", "--value"], { stdio: ["ignore", "pipe", "ignore"], timeout: SERVICE_CMD_TIMEOUT_MS }).toString());
|
|
11557
|
+
} catch {
|
|
11558
|
+
return "stopped";
|
|
11559
|
+
}
|
|
11560
|
+
}
|
|
11561
|
+
function interpretConditionResult(raw) {
|
|
11562
|
+
return raw.trim() === "no" ? "condition-failed" : "stopped";
|
|
11563
|
+
}
|
|
11409
11564
|
function daemonServiceStatus() {
|
|
11410
11565
|
if (!isDaemonSupportedPlatform())
|
|
11411
11566
|
return "unsupported-platform";
|
|
@@ -11417,9 +11572,9 @@ function daemonServiceStatus() {
|
|
|
11417
11572
|
stdio: ["ignore", "pipe", "ignore"],
|
|
11418
11573
|
timeout: SERVICE_CMD_TIMEOUT_MS
|
|
11419
11574
|
}).toString().trim();
|
|
11420
|
-
return out === "active" ? "running" :
|
|
11575
|
+
return out === "active" ? "running" : inactiveLinuxStatus();
|
|
11421
11576
|
} catch {
|
|
11422
|
-
return
|
|
11577
|
+
return inactiveLinuxStatus();
|
|
11423
11578
|
}
|
|
11424
11579
|
}
|
|
11425
11580
|
const plistPath = launchdPlistPath();
|
|
@@ -11440,7 +11595,7 @@ function daemonServiceStatus() {
|
|
|
11440
11595
|
return "stopped";
|
|
11441
11596
|
}
|
|
11442
11597
|
}
|
|
11443
|
-
var SERVICE_CMD_TIMEOUT_MS = 1e4, SERVICE_START_TIMEOUT_MS = 5000, SERVICE_START_POLL_MS = 100, SERVICE_SETTLE_MS = 750, SUDO_PROMPT_TIMEOUT_MS = 120000, UNIT_UNSAFE_RE, DAEMON_PROBE_TIMEOUT_MS = 5000;
|
|
11598
|
+
var SERVICE_CMD_TIMEOUT_MS = 1e4, SERVICE_START_TIMEOUT_MS = 5000, SERVICE_START_POLL_MS = 100, SERVICE_SETTLE_MS = 750, SUDO_PROMPT_TIMEOUT_MS = 120000, UNIT_UNSAFE_RE, DAEMON_PROBE_TIMEOUT_MS = 5000, DAEMON_PROBE_READY_TIMEOUT_MS = 1e4, DAEMON_PROBE_RETRY_MS = 150;
|
|
11444
11599
|
var init_daemon_service = __esm(() => {
|
|
11445
11600
|
init_hook_logger();
|
|
11446
11601
|
init_daemon_download();
|
|
@@ -11906,6 +12061,20 @@ async function healDaemonFlag() {
|
|
|
11906
12061
|
``
|
|
11907
12062
|
];
|
|
11908
12063
|
}
|
|
12064
|
+
if (status === "condition-failed") {
|
|
12065
|
+
updateConfig({ daemon: { configured: false } });
|
|
12066
|
+
return [
|
|
12067
|
+
`failproofaid is installed but cannot start — a file its service requires is`,
|
|
12068
|
+
`gone (most often because failproofai was removed with \`npm rm -g\`, which`,
|
|
12069
|
+
`deletes the worker but leaves the service behind). This machine was`,
|
|
12070
|
+
`configured to require the daemon, which denies every tool call, so that flag`,
|
|
12071
|
+
`is cleared; policies now evaluate in-process.`,
|
|
12072
|
+
``,
|
|
12073
|
+
`Run \`failproofai uninstall\` to remove the leftover service, or`,
|
|
12074
|
+
`\`failproofai config\` to rebuild it. \`${daemonStatusCommand()}\` names the missing path.`,
|
|
12075
|
+
``
|
|
12076
|
+
];
|
|
12077
|
+
}
|
|
11909
12078
|
if (status === "running" && !await probeDaemonEndToEnd()) {
|
|
11910
12079
|
updateConfig({ daemon: { configured: false } });
|
|
11911
12080
|
return [
|
|
@@ -12215,7 +12384,8 @@ var init_first_run_gate = __esm(() => {
|
|
|
12215
12384
|
FIRST_RUN_EXEMPT_SUBCOMMANDS = [
|
|
12216
12385
|
"config",
|
|
12217
12386
|
"policies",
|
|
12218
|
-
"policy"
|
|
12387
|
+
"policy",
|
|
12388
|
+
"uninstall"
|
|
12219
12389
|
];
|
|
12220
12390
|
});
|
|
12221
12391
|
|
|
@@ -21925,6 +22095,129 @@ This file can be committed to git — no machine-specific paths.`);
|
|
|
21925
22095
|
} catch {}
|
|
21926
22096
|
}
|
|
21927
22097
|
}
|
|
22098
|
+
async function removeHooks(policyNames, scope = "user", cwd, opts) {
|
|
22099
|
+
const configScope = scope === "all" ? "user" : scope;
|
|
22100
|
+
const selectedClis = opts?.cli && opts.cli.length > 0 ? [...new Set(opts.cli)] : ["claude"];
|
|
22101
|
+
if (opts?.removeCustomHooks) {
|
|
22102
|
+
const config = readScopedHooksConfig(configScope, cwd);
|
|
22103
|
+
delete config.customPoliciesPath;
|
|
22104
|
+
delete config.customPoliciesPaths;
|
|
22105
|
+
writeScopedHooksConfig(config, configScope, cwd);
|
|
22106
|
+
console.log("Custom hooks path cleared.");
|
|
22107
|
+
}
|
|
22108
|
+
if (policyNames && policyNames.length > 0 && !(policyNames.length === 1 && policyNames[0] === "all")) {
|
|
22109
|
+
validatePolicyNames(policyNames);
|
|
22110
|
+
const config = readScopedHooksConfig(configScope, cwd);
|
|
22111
|
+
const removeSet = new Set(policyNames);
|
|
22112
|
+
const remaining = config.enabledPolicies.filter((p) => !removeSet.has(p));
|
|
22113
|
+
const notEnabled = policyNames.filter((p) => !config.enabledPolicies.includes(p));
|
|
22114
|
+
if (notEnabled.length > 0) {
|
|
22115
|
+
console.log(`Warning: policy(ies) not currently enabled: ${notEnabled.join(", ")}`);
|
|
22116
|
+
}
|
|
22117
|
+
const { policyParams: existingParams, ...baseConfig } = config;
|
|
22118
|
+
const filteredParams = existingParams ? Object.fromEntries(Object.entries(existingParams).filter(([k]) => !removeSet.has(k))) : null;
|
|
22119
|
+
const updatedConfig = {
|
|
22120
|
+
...baseConfig,
|
|
22121
|
+
enabledPolicies: remaining,
|
|
22122
|
+
...filteredParams && Object.keys(filteredParams).length > 0 ? { policyParams: filteredParams } : {}
|
|
22123
|
+
};
|
|
22124
|
+
writeScopedHooksConfig(updatedConfig, configScope, cwd);
|
|
22125
|
+
try {
|
|
22126
|
+
const distinctId = getInstanceId2();
|
|
22127
|
+
const actuallyRemoved = policyNames.filter((p) => config.enabledPolicies.includes(p));
|
|
22128
|
+
await trackHookEvent2(distinctId, "hooks_removed", {
|
|
22129
|
+
scope,
|
|
22130
|
+
cli: selectedClis,
|
|
22131
|
+
removal_mode: opts?.betaOnly ? "beta_policies" : "policies",
|
|
22132
|
+
beta_only: opts?.betaOnly ?? false,
|
|
22133
|
+
policies_removed: actuallyRemoved,
|
|
22134
|
+
removed_count: actuallyRemoved.length,
|
|
22135
|
+
...opts?.source ? { source: opts.source } : {},
|
|
22136
|
+
platform: platform3(),
|
|
22137
|
+
arch: arch3(),
|
|
22138
|
+
os_release: release2(),
|
|
22139
|
+
hostname_hash: hashToId2(hostname3())
|
|
22140
|
+
});
|
|
22141
|
+
} catch {}
|
|
22142
|
+
console.log(`Disabled ${policyNames.length - notEnabled.length} policy(ies).`);
|
|
22143
|
+
console.log(`Remaining: ${remaining.length > 0 ? remaining.join(", ") : "(none)"}`);
|
|
22144
|
+
return;
|
|
22145
|
+
}
|
|
22146
|
+
const configBeforeRemoval = readScopedHooksConfig(configScope, cwd);
|
|
22147
|
+
let totalRemoved = 0;
|
|
22148
|
+
let nothingToReport = false;
|
|
22149
|
+
for (const cliId of selectedClis) {
|
|
22150
|
+
const integration = getIntegration(cliId);
|
|
22151
|
+
const scopesToRemove = scope === "all" ? [...integration.scopes] : integration.scopes.includes(scope) ? [scope] : [];
|
|
22152
|
+
for (const s of scopesToRemove) {
|
|
22153
|
+
const settingsPaths = settingsPathsFor(integration, s, cwd);
|
|
22154
|
+
const existing = settingsPaths.filter((p) => existsSync21(p));
|
|
22155
|
+
if (existing.length === 0) {
|
|
22156
|
+
if (scope !== "all" && selectedClis.length === 1) {
|
|
22157
|
+
console.log("No settings file found. Nothing to remove.");
|
|
22158
|
+
nothingToReport = true;
|
|
22159
|
+
}
|
|
22160
|
+
continue;
|
|
22161
|
+
}
|
|
22162
|
+
let removedHere = 0;
|
|
22163
|
+
for (const settingsPath of existing) {
|
|
22164
|
+
const removed = integration.removeHooksFromFile(settingsPath);
|
|
22165
|
+
removedHere += removed;
|
|
22166
|
+
if (removed > 0 && scope !== "all") {
|
|
22167
|
+
console.log(`Removed ${removed} failproofai hook(s) from ${integration.displayName} settings.`);
|
|
22168
|
+
console.log(`Settings: ${settingsPath}`);
|
|
22169
|
+
}
|
|
22170
|
+
}
|
|
22171
|
+
if (removedHere === 0 && scope !== "all" && selectedClis.length === 1) {
|
|
22172
|
+
console.log("No hooks found in settings. Nothing to remove.");
|
|
22173
|
+
nothingToReport = true;
|
|
22174
|
+
continue;
|
|
22175
|
+
}
|
|
22176
|
+
totalRemoved += removedHere;
|
|
22177
|
+
}
|
|
22178
|
+
}
|
|
22179
|
+
if (nothingToReport && totalRemoved === 0)
|
|
22180
|
+
return;
|
|
22181
|
+
if (scope === "all") {
|
|
22182
|
+
console.log(`Removed ${totalRemoved} failproofai hook(s) from all scopes.`);
|
|
22183
|
+
for (const cliId of selectedClis) {
|
|
22184
|
+
const integration = getIntegration(cliId);
|
|
22185
|
+
for (const s of integration.scopes) {
|
|
22186
|
+
for (const p of settingsPathsFor(integration, s, cwd)) {
|
|
22187
|
+
console.log(` ${integration.displayName} / ${s}: ${p}`);
|
|
22188
|
+
}
|
|
22189
|
+
}
|
|
22190
|
+
}
|
|
22191
|
+
}
|
|
22192
|
+
try {
|
|
22193
|
+
const distinctId = getInstanceId2();
|
|
22194
|
+
await trackHookEvent2(distinctId, "hooks_removed", {
|
|
22195
|
+
scope,
|
|
22196
|
+
cli: selectedClis,
|
|
22197
|
+
removal_mode: "hooks",
|
|
22198
|
+
policies_removed: configBeforeRemoval.enabledPolicies,
|
|
22199
|
+
removed_count: totalRemoved,
|
|
22200
|
+
...opts?.source ? { source: opts.source } : {},
|
|
22201
|
+
platform: platform3(),
|
|
22202
|
+
arch: arch3(),
|
|
22203
|
+
os_release: release2(),
|
|
22204
|
+
hostname_hash: hashToId2(hostname3())
|
|
22205
|
+
});
|
|
22206
|
+
} catch {}
|
|
22207
|
+
if (scope === "all") {
|
|
22208
|
+
for (const s of HOOK_SCOPES) {
|
|
22209
|
+
const existing = readScopedHooksConfig(s, cwd);
|
|
22210
|
+
if (existing.enabledPolicies.length > 0 || existing.customPoliciesPaths?.length || existing.customPoliciesPath || existing.policyParams) {
|
|
22211
|
+
const { customPoliciesPath: _drop, customPoliciesPaths: _dropMany, policyParams: _dropParams, ...rest } = existing;
|
|
22212
|
+
writeScopedHooksConfig({ ...rest, enabledPolicies: [] }, s, cwd);
|
|
22213
|
+
}
|
|
22214
|
+
}
|
|
22215
|
+
} else if (!HOOK_SCOPES.some((s) => hooksInstalledInSettings(s, cwd))) {
|
|
22216
|
+
const existing = readScopedHooksConfig(configScope, cwd);
|
|
22217
|
+
const { customPoliciesPath: _drop, customPoliciesPaths: _dropMany, policyParams: _dropParams, ...rest } = existing;
|
|
22218
|
+
writeScopedHooksConfig({ ...rest, enabledPolicies: [] }, configScope, cwd);
|
|
22219
|
+
}
|
|
22220
|
+
}
|
|
21928
22221
|
var VALID_POLICY_NAMES;
|
|
21929
22222
|
var init_manager = __esm(() => {
|
|
21930
22223
|
init_types();
|
|
@@ -22438,8 +22731,87 @@ var init_setup_state = __esm(() => {
|
|
|
22438
22731
|
init_fp_home();
|
|
22439
22732
|
});
|
|
22440
22733
|
|
|
22734
|
+
// src/hooks/onboarding-attempt.ts
|
|
22735
|
+
import { existsSync as existsSync24, mkdirSync as mkdirSync14, readFileSync as readFileSync19, rmSync as rmSync8, writeFileSync as writeFileSync11 } from "node:fs";
|
|
22736
|
+
import { dirname as dirname12 } from "node:path";
|
|
22737
|
+
function readOnboardingAttempt() {
|
|
22738
|
+
const path3 = onboardingAttemptFile();
|
|
22739
|
+
if (!existsSync24(path3))
|
|
22740
|
+
return null;
|
|
22741
|
+
try {
|
|
22742
|
+
const raw = JSON.parse(readFileSync19(path3, "utf8"));
|
|
22743
|
+
if (raw.schemaVersion !== SCHEMA_VERSION3)
|
|
22744
|
+
return null;
|
|
22745
|
+
if (typeof raw.reason !== "string" || typeof raw.cliVersion !== "string")
|
|
22746
|
+
return null;
|
|
22747
|
+
return {
|
|
22748
|
+
schemaVersion: SCHEMA_VERSION3,
|
|
22749
|
+
reason: raw.reason,
|
|
22750
|
+
cliVersion: raw.cliVersion,
|
|
22751
|
+
daemonStatus: typeof raw.daemonStatus === "string" ? raw.daemonStatus : "",
|
|
22752
|
+
at: typeof raw.at === "number" ? raw.at : 0
|
|
22753
|
+
};
|
|
22754
|
+
} catch {
|
|
22755
|
+
return null;
|
|
22756
|
+
}
|
|
22757
|
+
}
|
|
22758
|
+
function recordOnboardingAttempt(reason, cliVersion, daemonStatus, now = Date.now()) {
|
|
22759
|
+
try {
|
|
22760
|
+
const path3 = onboardingAttemptFile();
|
|
22761
|
+
mkdirSync14(dirname12(path3), { recursive: true });
|
|
22762
|
+
const record = {
|
|
22763
|
+
schemaVersion: SCHEMA_VERSION3,
|
|
22764
|
+
reason,
|
|
22765
|
+
cliVersion,
|
|
22766
|
+
daemonStatus,
|
|
22767
|
+
at: now
|
|
22768
|
+
};
|
|
22769
|
+
writeFileSync11(path3, JSON.stringify(record, null, 2), "utf8");
|
|
22770
|
+
} catch {}
|
|
22771
|
+
}
|
|
22772
|
+
function clearOnboardingAttempt() {
|
|
22773
|
+
try {
|
|
22774
|
+
rmSync8(onboardingAttemptFile(), { force: true });
|
|
22775
|
+
} catch {}
|
|
22776
|
+
}
|
|
22777
|
+
function blockerCleared(attempt, probe) {
|
|
22778
|
+
switch (attempt.reason) {
|
|
22779
|
+
case "needs_root":
|
|
22780
|
+
return probe.canElevate();
|
|
22781
|
+
case "daemon_failed":
|
|
22782
|
+
return probe.daemonStatus() !== attempt.daemonStatus || probe.canElevate();
|
|
22783
|
+
case "cancelled":
|
|
22784
|
+
return probe.cliVersion !== attempt.cliVersion;
|
|
22785
|
+
case "not_a_tty":
|
|
22786
|
+
case "running_as_sudo":
|
|
22787
|
+
return true;
|
|
22788
|
+
default:
|
|
22789
|
+
return true;
|
|
22790
|
+
}
|
|
22791
|
+
}
|
|
22792
|
+
function attemptHintLines(attempt) {
|
|
22793
|
+
const why = {
|
|
22794
|
+
needs_root: "it needs root to install the failproofaid service",
|
|
22795
|
+
daemon_failed: "the failproofaid service could not be started",
|
|
22796
|
+
cancelled: "it was cancelled",
|
|
22797
|
+
not_a_tty: "there was no terminal to ask in",
|
|
22798
|
+
running_as_sudo: "it was run under sudo"
|
|
22799
|
+
};
|
|
22800
|
+
const detail = why[attempt.reason] ?? "it did not finish";
|
|
22801
|
+
return [
|
|
22802
|
+
``,
|
|
22803
|
+
`[failproofai] Setup is not finished — ${detail}.`,
|
|
22804
|
+
` Run \`failproofai config\` when you are ready.`,
|
|
22805
|
+
``
|
|
22806
|
+
];
|
|
22807
|
+
}
|
|
22808
|
+
var SCHEMA_VERSION3 = 1;
|
|
22809
|
+
var init_onboarding_attempt = __esm(() => {
|
|
22810
|
+
init_fp_home();
|
|
22811
|
+
});
|
|
22812
|
+
|
|
22441
22813
|
// src/hooks/onboarding-lock.ts
|
|
22442
|
-
import { mkdirSync as
|
|
22814
|
+
import { mkdirSync as mkdirSync15, readFileSync as readFileSync20, rmSync as rmSync9, writeFileSync as writeFileSync12 } from "node:fs";
|
|
22443
22815
|
import { homedir as homedir26 } from "node:os";
|
|
22444
22816
|
function onboardingLockPath(home = homedir26()) {
|
|
22445
22817
|
return onboardingLockFile(home);
|
|
@@ -22456,7 +22828,7 @@ function processAlive(pid) {
|
|
|
22456
22828
|
}
|
|
22457
22829
|
function readLock(path3) {
|
|
22458
22830
|
try {
|
|
22459
|
-
const parsed = JSON.parse(
|
|
22831
|
+
const parsed = JSON.parse(readFileSync20(path3, "utf8"));
|
|
22460
22832
|
if (typeof parsed.pid !== "number")
|
|
22461
22833
|
return null;
|
|
22462
22834
|
return { pid: parsed.pid, startedAt: Number(parsed.startedAt) || 0 };
|
|
@@ -22470,9 +22842,9 @@ function acquireOnboardingLock(home = homedir26()) {
|
|
|
22470
22842
|
const held = readLock(path3);
|
|
22471
22843
|
if (held && held.pid !== process.pid && processAlive(held.pid))
|
|
22472
22844
|
return null;
|
|
22473
|
-
|
|
22845
|
+
mkdirSync15(stateDir(home), { recursive: true });
|
|
22474
22846
|
const body = { pid: process.pid, startedAt: Date.now() };
|
|
22475
|
-
|
|
22847
|
+
writeFileSync12(path3, JSON.stringify(body), "utf8");
|
|
22476
22848
|
let released = false;
|
|
22477
22849
|
return {
|
|
22478
22850
|
release() {
|
|
@@ -22482,7 +22854,7 @@ function acquireOnboardingLock(home = homedir26()) {
|
|
|
22482
22854
|
try {
|
|
22483
22855
|
const current = readLock(path3);
|
|
22484
22856
|
if (!current || current.pid === process.pid)
|
|
22485
|
-
|
|
22857
|
+
rmSync9(path3, { force: true });
|
|
22486
22858
|
} catch {}
|
|
22487
22859
|
}
|
|
22488
22860
|
};
|
|
@@ -22495,7 +22867,7 @@ var init_onboarding_lock = __esm(() => {
|
|
|
22495
22867
|
});
|
|
22496
22868
|
|
|
22497
22869
|
// lib/claude-sessions.ts
|
|
22498
|
-
import { readdirSync as readdirSync14, statSync as statSync16, existsSync as
|
|
22870
|
+
import { readdirSync as readdirSync14, statSync as statSync16, existsSync as existsSync26 } from "node:fs";
|
|
22499
22871
|
import { join as join28, basename as basename5 } from "node:path";
|
|
22500
22872
|
function getClaudeProjectsRoot() {
|
|
22501
22873
|
return getClaudeProjectsPath();
|
|
@@ -22542,7 +22914,7 @@ function listClaudeTranscripts(project) {
|
|
|
22542
22914
|
} catch {}
|
|
22543
22915
|
} else if (entry.isDirectory() && UUID_RE2.test(entry.name)) {
|
|
22544
22916
|
const subDir = join28(project.path, entry.name, "subagents");
|
|
22545
|
-
if (!
|
|
22917
|
+
if (!existsSync26(subDir))
|
|
22546
22918
|
continue;
|
|
22547
22919
|
let subEntries;
|
|
22548
22920
|
try {
|
|
@@ -23817,7 +24189,7 @@ var init_features = __esm(() => {
|
|
|
23817
24189
|
|
|
23818
24190
|
// src/audit/cache.ts
|
|
23819
24191
|
import { createHash as createHash6 } from "node:crypto";
|
|
23820
|
-
import { existsSync as
|
|
24192
|
+
import { existsSync as existsSync27, mkdirSync as mkdirSync16, readFileSync as readFileSync21, writeFileSync as writeFileSync13, chmodSync as chmodSync4 } from "node:fs";
|
|
23821
24193
|
import { join as join29 } from "node:path";
|
|
23822
24194
|
function getEngineVersion() {
|
|
23823
24195
|
if (cachedEngineVersion)
|
|
@@ -23844,10 +24216,10 @@ function readCachedTranscriptResult(transcriptPath, mtimeMs, sizeBytes) {
|
|
|
23844
24216
|
if (sizeBytes === 0)
|
|
23845
24217
|
return null;
|
|
23846
24218
|
const cachePath = getCachePathFor(transcriptPath);
|
|
23847
|
-
if (!
|
|
24219
|
+
if (!existsSync27(cachePath))
|
|
23848
24220
|
return null;
|
|
23849
24221
|
try {
|
|
23850
|
-
const raw =
|
|
24222
|
+
const raw = readFileSync21(cachePath, "utf-8");
|
|
23851
24223
|
const entry = JSON.parse(raw);
|
|
23852
24224
|
if (entry.schemaVersion !== CACHE_SCHEMA_VERSION)
|
|
23853
24225
|
return null;
|
|
@@ -23871,7 +24243,7 @@ function writeCachedTranscriptResult(transcriptPath, mtimeMs, sizeBytes, result)
|
|
|
23871
24243
|
return;
|
|
23872
24244
|
const cachePath = getCachePathFor(transcriptPath);
|
|
23873
24245
|
try {
|
|
23874
|
-
|
|
24246
|
+
mkdirSync16(auditCacheDir(), { recursive: true });
|
|
23875
24247
|
const entry = {
|
|
23876
24248
|
schemaVersion: CACHE_SCHEMA_VERSION,
|
|
23877
24249
|
cachedAt: Date.now(),
|
|
@@ -23881,7 +24253,7 @@ function writeCachedTranscriptResult(transcriptPath, mtimeMs, sizeBytes, result)
|
|
|
23881
24253
|
detectorVersion: getDetectorVersion(),
|
|
23882
24254
|
result
|
|
23883
24255
|
};
|
|
23884
|
-
|
|
24256
|
+
writeFileSync13(cachePath, JSON.stringify(entry), { encoding: "utf-8", mode: 384 });
|
|
23885
24257
|
try {
|
|
23886
24258
|
chmodSync4(cachePath, 384);
|
|
23887
24259
|
} catch {}
|
|
@@ -24247,11 +24619,11 @@ var init_audit = __esm(() => {
|
|
|
24247
24619
|
import {
|
|
24248
24620
|
closeSync,
|
|
24249
24621
|
linkSync,
|
|
24250
|
-
mkdirSync as
|
|
24622
|
+
mkdirSync as mkdirSync17,
|
|
24251
24623
|
openSync,
|
|
24252
|
-
readFileSync as
|
|
24624
|
+
readFileSync as readFileSync22,
|
|
24253
24625
|
unlinkSync as unlinkSync4,
|
|
24254
|
-
writeFileSync as
|
|
24626
|
+
writeFileSync as writeFileSync14,
|
|
24255
24627
|
writeSync
|
|
24256
24628
|
} from "node:fs";
|
|
24257
24629
|
function acquireAuditLock(source, now = Date.now()) {
|
|
@@ -24310,7 +24682,7 @@ function handleFor(path3, info) {
|
|
|
24310
24682
|
}
|
|
24311
24683
|
function readLock2(path3) {
|
|
24312
24684
|
try {
|
|
24313
|
-
const parsed = JSON.parse(
|
|
24685
|
+
const parsed = JSON.parse(readFileSync22(path3, "utf8"));
|
|
24314
24686
|
if (typeof parsed?.pid !== "number" || typeof parsed?.startedAt !== "number")
|
|
24315
24687
|
return null;
|
|
24316
24688
|
return {
|
|
@@ -24326,7 +24698,7 @@ function writeLockExclusive(path3, info) {
|
|
|
24326
24698
|
const body = JSON.stringify(info);
|
|
24327
24699
|
const staging = `${path3}.${process.pid}.tmp`;
|
|
24328
24700
|
try {
|
|
24329
|
-
|
|
24701
|
+
writeFileSync14(staging, body, { mode: 384 });
|
|
24330
24702
|
} catch {
|
|
24331
24703
|
return false;
|
|
24332
24704
|
}
|
|
@@ -24360,8 +24732,8 @@ function createThenWrite(path3, body) {
|
|
|
24360
24732
|
}
|
|
24361
24733
|
}
|
|
24362
24734
|
function ensureRunDir() {
|
|
24363
|
-
|
|
24364
|
-
|
|
24735
|
+
mkdirSync17(failproofaiHome(), { recursive: true });
|
|
24736
|
+
mkdirSync17(runDir(), { recursive: true, mode: 448 });
|
|
24365
24737
|
}
|
|
24366
24738
|
var AUDIT_LOCK_MAX_AGE_MS;
|
|
24367
24739
|
var init_audit_lock = __esm(() => {
|
|
@@ -24525,26 +24897,26 @@ function parseScriptArgs(argv) {
|
|
|
24525
24897
|
var init_parse_script_args = () => {};
|
|
24526
24898
|
|
|
24527
24899
|
// scripts/install-diagnosis.mjs
|
|
24528
|
-
import { existsSync as
|
|
24529
|
-
import { dirname as
|
|
24900
|
+
import { existsSync as existsSync28, readFileSync as readFileSync23, realpathSync as realpathSync3 } from "node:fs";
|
|
24901
|
+
import { dirname as dirname13, resolve as resolve21 } from "node:path";
|
|
24530
24902
|
import { homedir as homedir27, platform as platform4 } from "node:os";
|
|
24531
24903
|
import { spawnSync } from "node:child_process";
|
|
24532
24904
|
function findPackageRoot(start) {
|
|
24533
24905
|
try {
|
|
24534
24906
|
let dir = realpathSync3(start);
|
|
24535
|
-
if (
|
|
24536
|
-
dir =
|
|
24907
|
+
if (existsSync28(dir) && !existsSync28(resolve21(dir, "package.json"))) {
|
|
24908
|
+
dir = dirname13(dir);
|
|
24537
24909
|
}
|
|
24538
24910
|
while (true) {
|
|
24539
24911
|
const pkgPath = resolve21(dir, "package.json");
|
|
24540
|
-
if (
|
|
24912
|
+
if (existsSync28(pkgPath)) {
|
|
24541
24913
|
try {
|
|
24542
|
-
const pkg = JSON.parse(
|
|
24914
|
+
const pkg = JSON.parse(readFileSync23(pkgPath, "utf8"));
|
|
24543
24915
|
if (pkg.name === PKG_NAME)
|
|
24544
24916
|
return dir;
|
|
24545
24917
|
} catch {}
|
|
24546
24918
|
}
|
|
24547
|
-
const parent =
|
|
24919
|
+
const parent = dirname13(dir);
|
|
24548
24920
|
if (parent === dir)
|
|
24549
24921
|
return null;
|
|
24550
24922
|
dir = parent;
|
|
@@ -24557,7 +24929,7 @@ function readPackageVersion(packageRoot) {
|
|
|
24557
24929
|
if (!packageRoot)
|
|
24558
24930
|
return null;
|
|
24559
24931
|
try {
|
|
24560
|
-
const pkg = JSON.parse(
|
|
24932
|
+
const pkg = JSON.parse(readFileSync23(resolve21(packageRoot, "package.json"), "utf8"));
|
|
24561
24933
|
return typeof pkg.version === "string" ? pkg.version : null;
|
|
24562
24934
|
} catch {
|
|
24563
24935
|
return null;
|
|
@@ -24584,7 +24956,7 @@ function locateNpmGlobal() {
|
|
|
24584
24956
|
if (!root)
|
|
24585
24957
|
return null;
|
|
24586
24958
|
const candidate = resolve21(root, PKG_NAME);
|
|
24587
|
-
return
|
|
24959
|
+
return existsSync28(resolve21(candidate, "package.json")) ? candidate : null;
|
|
24588
24960
|
} catch {
|
|
24589
24961
|
return null;
|
|
24590
24962
|
}
|
|
@@ -24592,7 +24964,7 @@ function locateNpmGlobal() {
|
|
|
24592
24964
|
function locateBunGlobal() {
|
|
24593
24965
|
try {
|
|
24594
24966
|
const candidate = resolve21(homedir27(), ".bun", "install", "global", "node_modules", PKG_NAME);
|
|
24595
|
-
return
|
|
24967
|
+
return existsSync28(resolve21(candidate, "package.json")) ? candidate : null;
|
|
24596
24968
|
} catch {
|
|
24597
24969
|
return null;
|
|
24598
24970
|
}
|
|
@@ -24699,8 +25071,8 @@ __export(exports_launch, {
|
|
|
24699
25071
|
launch: () => launch
|
|
24700
25072
|
});
|
|
24701
25073
|
import { spawn as spawn2 } from "child_process";
|
|
24702
|
-
import { realpathSync as realpathSync4, existsSync as
|
|
24703
|
-
import { resolve as resolve22, dirname as
|
|
25074
|
+
import { realpathSync as realpathSync4, existsSync as existsSync29 } from "node:fs";
|
|
25075
|
+
import { resolve as resolve22, dirname as dirname14 } from "node:path";
|
|
24704
25076
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
24705
25077
|
import { createInterface } from "node:readline";
|
|
24706
25078
|
function launch(mode) {
|
|
@@ -24724,9 +25096,9 @@ function launch(mode) {
|
|
|
24724
25096
|
process.env.PORT = port;
|
|
24725
25097
|
process.env.HOSTNAME = bindHost;
|
|
24726
25098
|
cmd = "node";
|
|
24727
|
-
const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT ?? resolve22(
|
|
25099
|
+
const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT ?? resolve22(dirname14(realpathSync4(fileURLToPath2(import.meta.url))), "..");
|
|
24728
25100
|
const serverJsPath = resolve22(packageRoot, ".next/standalone/server.js");
|
|
24729
|
-
if (!
|
|
25101
|
+
if (!existsSync29(serverJsPath)) {
|
|
24730
25102
|
let shadowMessage = null;
|
|
24731
25103
|
try {
|
|
24732
25104
|
const diag = diagnoseShadow({ selfPackageRoot: packageRoot, selfVersion: version2 });
|
|
@@ -25171,9 +25543,9 @@ __export(exports_configure_wizard, {
|
|
|
25171
25543
|
buildPresetChoices: () => buildPresetChoices,
|
|
25172
25544
|
buildAgentChoices: () => buildAgentChoices
|
|
25173
25545
|
});
|
|
25174
|
-
import { existsSync as
|
|
25546
|
+
import { existsSync as existsSync30, mkdirSync as mkdirSync18, writeFileSync as writeFileSync15, readFileSync as readFileSync24 } from "node:fs";
|
|
25175
25547
|
import { homedir as homedir28 } from "node:os";
|
|
25176
|
-
import { dirname as
|
|
25548
|
+
import { dirname as dirname15, resolve as resolve23, sep as sep5 } from "node:path";
|
|
25177
25549
|
async function emit(event, props) {
|
|
25178
25550
|
try {
|
|
25179
25551
|
await trackHookEvent2(getInstanceId2(), event, props);
|
|
@@ -25280,8 +25652,8 @@ function setCustomPoliciesEnabled(scope, cwd, enabled) {
|
|
|
25280
25652
|
const path3 = getConfigPathForScope(scope, cwd);
|
|
25281
25653
|
let config = {};
|
|
25282
25654
|
try {
|
|
25283
|
-
if (
|
|
25284
|
-
config = JSON.parse(
|
|
25655
|
+
if (existsSync30(path3))
|
|
25656
|
+
config = JSON.parse(readFileSync24(path3, "utf8"));
|
|
25285
25657
|
} catch {
|
|
25286
25658
|
return;
|
|
25287
25659
|
}
|
|
@@ -25290,7 +25662,7 @@ function setCustomPoliciesEnabled(scope, cwd, enabled) {
|
|
|
25290
25662
|
else
|
|
25291
25663
|
config.customPoliciesEnabled = false;
|
|
25292
25664
|
try {
|
|
25293
|
-
|
|
25665
|
+
writeFileSync15(path3, JSON.stringify(config, null, 2) + `
|
|
25294
25666
|
`, "utf8");
|
|
25295
25667
|
} catch {}
|
|
25296
25668
|
}
|
|
@@ -25390,14 +25762,33 @@ function firstRunMarkerPath() {
|
|
|
25390
25762
|
return launcherMarker();
|
|
25391
25763
|
}
|
|
25392
25764
|
function hasSeenLauncher() {
|
|
25393
|
-
return
|
|
25765
|
+
return existsSync30(firstRunMarkerPath());
|
|
25394
25766
|
}
|
|
25395
25767
|
function markLauncherSeen() {
|
|
25396
25768
|
try {
|
|
25397
|
-
|
|
25398
|
-
|
|
25769
|
+
mkdirSync18(dirname15(firstRunMarkerPath()), { recursive: true });
|
|
25770
|
+
writeFileSync15(firstRunMarkerPath(), "1", "utf8");
|
|
25399
25771
|
} catch {}
|
|
25400
25772
|
}
|
|
25773
|
+
function retryProbe() {
|
|
25774
|
+
return {
|
|
25775
|
+
canElevate: () => {
|
|
25776
|
+
try {
|
|
25777
|
+
return canElevate();
|
|
25778
|
+
} catch {
|
|
25779
|
+
return false;
|
|
25780
|
+
}
|
|
25781
|
+
},
|
|
25782
|
+
daemonStatus: () => {
|
|
25783
|
+
try {
|
|
25784
|
+
return daemonServiceStatus();
|
|
25785
|
+
} catch {
|
|
25786
|
+
return "";
|
|
25787
|
+
}
|
|
25788
|
+
},
|
|
25789
|
+
cliVersion: version2
|
|
25790
|
+
};
|
|
25791
|
+
}
|
|
25401
25792
|
async function maybeFirstRunConfigure(io = {}, opts = {}) {
|
|
25402
25793
|
if (process.env.FAILPROOFAI_NO_FIRST_RUN === "1")
|
|
25403
25794
|
return false;
|
|
@@ -25409,6 +25800,13 @@ async function maybeFirstRunConfigure(io = {}, opts = {}) {
|
|
|
25409
25800
|
markLauncherSeen();
|
|
25410
25801
|
return false;
|
|
25411
25802
|
}
|
|
25803
|
+
const attempt = opts.force ? null : readOnboardingAttempt();
|
|
25804
|
+
if (attempt && !blockerCleared(attempt, retryProbe())) {
|
|
25805
|
+
for (const line of attemptHintLines(attempt))
|
|
25806
|
+
stdout.write(`${line}
|
|
25807
|
+
`);
|
|
25808
|
+
return false;
|
|
25809
|
+
}
|
|
25412
25810
|
if (!stdin.isTTY || !stdout.isTTY) {
|
|
25413
25811
|
stdout.write(`
|
|
25414
25812
|
[failproofai] Not set up yet — run \`failproofai config\` to get started.
|
|
@@ -25427,6 +25825,9 @@ async function maybeFirstRunConfigure(io = {}, opts = {}) {
|
|
|
25427
25825
|
try {
|
|
25428
25826
|
emit("first_run_configure_shown", {});
|
|
25429
25827
|
const result = await runConfigureWizard(io);
|
|
25828
|
+
if (!result.applied && result.abort) {
|
|
25829
|
+
recordOnboardingAttempt(result.abort, version2, daemonServiceStatus());
|
|
25830
|
+
}
|
|
25430
25831
|
if (result.applied && opts.postSetupAudit !== false) {
|
|
25431
25832
|
try {
|
|
25432
25833
|
const { runPostSetupAudit: runPostSetupAudit2 } = await Promise.resolve().then(() => (init_cli(), exports_cli));
|
|
@@ -25754,18 +26155,22 @@ Setup stopped before changing anything. Once that is fixed, re-run:
|
|
|
25754
26155
|
outro("Nothing was changed.", { ok: false }, stdout);
|
|
25755
26156
|
return { applied: false, abort: "daemon_failed" };
|
|
25756
26157
|
}
|
|
25757
|
-
|
|
25758
|
-
|
|
25759
|
-
|
|
25760
|
-
|
|
25761
|
-
|
|
25762
|
-
|
|
26158
|
+
const probe = await probeDaemon();
|
|
26159
|
+
if (!probe.ok) {
|
|
26160
|
+
hookLogWarn(`failproofaid was installed and running but did not answer a policy evaluation (${probe.reason})`);
|
|
26161
|
+
stdout.write((probe.reason === "worker" ? `
|
|
26162
|
+
failproofaid started but cannot evaluate policies — it is listening, and
|
|
26163
|
+
` + `its worker process could not be run.
|
|
26164
|
+
` : `
|
|
26165
|
+
failproofaid started but could not be reached on its socket.
|
|
26166
|
+
`) + `Setup stopped before changing anything, because a machine configured to
|
|
26167
|
+
require a daemon that cannot answer denies every tool call.
|
|
25763
26168
|
|
|
25764
26169
|
Check it with: ${daemonStatusCommand() ?? "systemctl status failproofaid"}
|
|
25765
26170
|
Then re-run: failproofai config
|
|
25766
26171
|
|
|
25767
26172
|
`);
|
|
25768
|
-
emit("configure_aborted", { reason:
|
|
26173
|
+
emit("configure_aborted", { reason: `daemon_not_answering_${probe.reason}` });
|
|
25769
26174
|
outro("Nothing was changed.", { ok: false }, stdout);
|
|
25770
26175
|
return { applied: false, abort: "daemon_failed" };
|
|
25771
26176
|
}
|
|
@@ -25850,6 +26255,7 @@ Hooks keep enforcing; scheduled audits stay off until it is.
|
|
|
25850
26255
|
}
|
|
25851
26256
|
await applied;
|
|
25852
26257
|
markLauncherSeen();
|
|
26258
|
+
clearOnboardingAttempt();
|
|
25853
26259
|
const customNote = customEnabled === true ? " + your custom policies" : customEnabled === false ? " · custom policies DISABLED" : "";
|
|
25854
26260
|
const daemonNote = daemonInstalled ? " · daemon on" : "";
|
|
25855
26261
|
const cloudNote = connected ? " · reporting on" : "";
|
|
@@ -25885,20 +26291,701 @@ var init_configure_wizard = __esm(() => {
|
|
|
25885
26291
|
init_fp_home();
|
|
25886
26292
|
init_daemon_download();
|
|
25887
26293
|
init_package();
|
|
26294
|
+
init_onboarding_attempt();
|
|
25888
26295
|
init_onboarding_lock();
|
|
25889
26296
|
});
|
|
25890
26297
|
|
|
25891
|
-
// src/hooks/
|
|
25892
|
-
var
|
|
25893
|
-
__export(
|
|
25894
|
-
|
|
25895
|
-
|
|
25896
|
-
|
|
25897
|
-
|
|
26298
|
+
// src/hooks/uninstall-cli.ts
|
|
26299
|
+
var exports_uninstall_cli = {};
|
|
26300
|
+
__export(exports_uninstall_cli, {
|
|
26301
|
+
serviceStateLabel: () => serviceStateLabel,
|
|
26302
|
+
runUninstallCommand: () => runUninstallCommand
|
|
26303
|
+
});
|
|
26304
|
+
import { existsSync as existsSync31, rmSync as rmSync10 } from "node:fs";
|
|
26305
|
+
function survey(cwd) {
|
|
26306
|
+
const clis = [];
|
|
26307
|
+
for (const id of listInstallableIds()) {
|
|
26308
|
+
for (const scope of ["user", "project", "local"]) {
|
|
26309
|
+
try {
|
|
26310
|
+
if (getIntegration(id).hooksInstalledInSettings(scope, cwd)) {
|
|
26311
|
+
clis.push(id);
|
|
26312
|
+
break;
|
|
26313
|
+
}
|
|
26314
|
+
} catch {}
|
|
26315
|
+
}
|
|
26316
|
+
}
|
|
26317
|
+
let daemonConfigured = false;
|
|
26318
|
+
try {
|
|
26319
|
+
daemonConfigured = readConfig().daemon.configured;
|
|
26320
|
+
} catch {}
|
|
26321
|
+
const servicePath = isDaemonSupportedPlatform() ? daemonServiceFilePath() : null;
|
|
26322
|
+
return {
|
|
26323
|
+
clis,
|
|
26324
|
+
servicePath,
|
|
26325
|
+
serviceInstalled: !!servicePath && existsSync31(servicePath),
|
|
26326
|
+
daemonConfigured,
|
|
26327
|
+
homeExists: existsSync31(failproofaiHome())
|
|
26328
|
+
};
|
|
26329
|
+
}
|
|
26330
|
+
async function runUninstallCommand(opts = {}) {
|
|
26331
|
+
const found = survey(opts.cwd);
|
|
26332
|
+
const lines = [];
|
|
26333
|
+
const nothingToDo = found.clis.length === 0 && !found.serviceInstalled && !found.daemonConfigured && !(opts.purge && found.homeExists);
|
|
26334
|
+
if (nothingToDo) {
|
|
26335
|
+
return {
|
|
26336
|
+
exitCode: 0,
|
|
26337
|
+
planLines: 0,
|
|
26338
|
+
purged: false,
|
|
26339
|
+
lines: [
|
|
26340
|
+
"Nothing to uninstall — no hook entries, no daemon service, and nothing configured.",
|
|
26341
|
+
...found.homeExists && !opts.purge ? [
|
|
26342
|
+
``,
|
|
26343
|
+
`${failproofaiHome()} still holds settings and audit history.`,
|
|
26344
|
+
`Remove it with \`failproofai uninstall --purge\`.`
|
|
26345
|
+
] : []
|
|
26346
|
+
]
|
|
26347
|
+
};
|
|
26348
|
+
}
|
|
26349
|
+
const plan = [];
|
|
26350
|
+
if (found.clis.length > 0) {
|
|
26351
|
+
plan.push(` • remove failproofai hook entries from ${found.clis.length} agent CLI${found.clis.length === 1 ? "" : "s"}: ` + found.clis.map((id) => getIntegration(id).displayName ?? id).join(", "));
|
|
26352
|
+
}
|
|
26353
|
+
if (found.daemonConfigured) {
|
|
26354
|
+
plan.push(` • stop requiring the daemon (policies go back to evaluating in-process)`);
|
|
26355
|
+
}
|
|
26356
|
+
if (found.serviceInstalled) {
|
|
26357
|
+
plan.push(` • stop, disable and delete the service at ${found.servicePath} — needs sudo`);
|
|
26358
|
+
}
|
|
26359
|
+
let purged = false;
|
|
26360
|
+
if (opts.purge && found.homeExists) {
|
|
26361
|
+
plan.push(` • delete ${failproofaiHome()} — settings, credentials, audit history and the daemon binary`);
|
|
26362
|
+
}
|
|
26363
|
+
lines.push("failproofai uninstall will:", ...plan);
|
|
26364
|
+
if (!opts.purge && found.homeExists) {
|
|
26365
|
+
lines.push(``, `${failproofaiHome()} is KEPT (settings and audit history survive a reinstall).`, `Add --purge to delete it too.`);
|
|
26366
|
+
}
|
|
26367
|
+
const planLines = lines.length;
|
|
26368
|
+
if (opts.dryRun) {
|
|
26369
|
+
lines.push(``, `--dry-run: nothing was changed.`);
|
|
26370
|
+
return { exitCode: 0, lines, planLines, purged: false };
|
|
26371
|
+
}
|
|
26372
|
+
if (!opts.yes) {
|
|
26373
|
+
if (!opts.confirm) {
|
|
26374
|
+
lines.push(``, `Refusing to uninstall without confirmation. Re-run with --yes.`);
|
|
26375
|
+
return { exitCode: 1, lines, planLines, purged: false };
|
|
26376
|
+
}
|
|
26377
|
+
if (!await opts.confirm(lines)) {
|
|
26378
|
+
return { exitCode: 1, planLines, purged: false, lines: [...lines, ``, `Cancelled — nothing was changed.`] };
|
|
26379
|
+
}
|
|
26380
|
+
}
|
|
26381
|
+
lines.push(``);
|
|
26382
|
+
const failures = [];
|
|
26383
|
+
if (found.daemonConfigured) {
|
|
26384
|
+
try {
|
|
26385
|
+
setDaemonConfigured(false);
|
|
26386
|
+
lines.push(`✓ policies now evaluate in-process (this machine no longer requires the daemon)`);
|
|
26387
|
+
} catch (err) {
|
|
26388
|
+
return {
|
|
26389
|
+
exitCode: 2,
|
|
26390
|
+
planLines,
|
|
26391
|
+
purged: false,
|
|
26392
|
+
lines: [
|
|
26393
|
+
...lines,
|
|
26394
|
+
`✗ could not update ${failproofaiHome()}/config.toml: ${err instanceof Error ? err.message : String(err)}`,
|
|
26395
|
+
``,
|
|
26396
|
+
`Stopped before touching the service. Removing it while this machine still`,
|
|
26397
|
+
`requires it would deny every tool call. Fix the file's permissions and re-run.`
|
|
26398
|
+
]
|
|
26399
|
+
};
|
|
26400
|
+
}
|
|
26401
|
+
}
|
|
26402
|
+
if (found.clis.length > 0) {
|
|
26403
|
+
try {
|
|
26404
|
+
await removeHooks(undefined, "all", opts.cwd, {
|
|
26405
|
+
cli: found.clis,
|
|
26406
|
+
removeCustomHooks: true,
|
|
26407
|
+
source: "uninstall_command"
|
|
26408
|
+
});
|
|
26409
|
+
lines.push(`✓ removed hook entries from ${found.clis.length} agent CLI${found.clis.length === 1 ? "" : "s"}`);
|
|
26410
|
+
} catch (err) {
|
|
26411
|
+
failures.push(`hook entries: ${err instanceof Error ? err.message : String(err)} ` + `(finish with \`failproofai policies --uninstall --scope all\`)`);
|
|
26412
|
+
}
|
|
26413
|
+
}
|
|
26414
|
+
if (found.serviceInstalled) {
|
|
26415
|
+
try {
|
|
26416
|
+
await uninstallDaemonService();
|
|
26417
|
+
if (found.servicePath && existsSync31(found.servicePath)) {
|
|
26418
|
+
failures.push(`the service at ${found.servicePath} is still there (most often: no sudo). ` + `Remove it with the commands below.`);
|
|
26419
|
+
} else {
|
|
26420
|
+
lines.push(`✓ stopped and removed the daemon service`);
|
|
26421
|
+
}
|
|
26422
|
+
} catch (err) {
|
|
26423
|
+
failures.push(`daemon service: ${err instanceof Error ? err.message : String(err)}`);
|
|
26424
|
+
}
|
|
26425
|
+
}
|
|
26426
|
+
if (opts.purge && found.homeExists) {
|
|
26427
|
+
try {
|
|
26428
|
+
rmSync10(failproofaiHome(), { recursive: true, force: true });
|
|
26429
|
+
purged = true;
|
|
26430
|
+
lines.push(`✓ deleted ${failproofaiHome()}`);
|
|
26431
|
+
} catch (err) {
|
|
26432
|
+
failures.push(`${failproofaiHome()}: ${err instanceof Error ? err.message : String(err)}`);
|
|
26433
|
+
}
|
|
26434
|
+
}
|
|
26435
|
+
if (failures.length > 0) {
|
|
26436
|
+
lines.push(``, `Not everything could be removed:`);
|
|
26437
|
+
for (const f of failures)
|
|
26438
|
+
lines.push(` ✗ ${f}`);
|
|
26439
|
+
if (found.servicePath && existsSync31(found.servicePath)) {
|
|
26440
|
+
lines.push(``, `To remove the service by hand:`, ...manualServiceRemoval(found.servicePath), ``, `(\`${daemonStatusCommand()}\` shows its current state.)`);
|
|
26441
|
+
}
|
|
26442
|
+
return { exitCode: 1, lines, planLines, purged };
|
|
26443
|
+
}
|
|
26444
|
+
lines.push(``, `Done. failproofai no longer enforces anything on this machine.`, ``, `The npm package itself is still installed — npm runs no uninstall script, which`, `is why this command exists. Remove it with:`, ` npm rm -g failproofai`);
|
|
26445
|
+
if (!opts.purge && found.homeExists) {
|
|
26446
|
+
lines.push(``, `${failproofaiHome()} was kept. Delete it with \`failproofai uninstall --purge\`.`);
|
|
26447
|
+
}
|
|
26448
|
+
return { exitCode: 0, lines, planLines, purged };
|
|
26449
|
+
}
|
|
26450
|
+
function manualServiceRemoval(servicePath) {
|
|
26451
|
+
if (process.platform === "darwin") {
|
|
26452
|
+
return [` sudo launchctl unload -w ${servicePath}`, ` sudo rm -f ${servicePath}`];
|
|
26453
|
+
}
|
|
26454
|
+
const unit = servicePath.split("/").pop() ?? servicePath;
|
|
26455
|
+
return [
|
|
26456
|
+
` sudo systemctl disable --now ${unit}`,
|
|
26457
|
+
` sudo rm -f ${servicePath}`,
|
|
26458
|
+
` sudo systemctl daemon-reload`
|
|
26459
|
+
];
|
|
26460
|
+
}
|
|
26461
|
+
function serviceStateLabel() {
|
|
26462
|
+
const status = daemonServiceStatus();
|
|
26463
|
+
return status === "condition-failed" ? "installed but skipped by systemd (a file it needs is missing)" : status;
|
|
26464
|
+
}
|
|
26465
|
+
var init_uninstall_cli = __esm(() => {
|
|
26466
|
+
init_fp_home();
|
|
26467
|
+
init_fp_config();
|
|
26468
|
+
init_daemon_service();
|
|
26469
|
+
init_integrations();
|
|
26470
|
+
init_manager();
|
|
26471
|
+
});
|
|
26472
|
+
|
|
26473
|
+
// src/hooks/tui.ts
|
|
26474
|
+
var exports_tui = {};
|
|
26475
|
+
__export(exports_tui, {
|
|
26476
|
+
truncate: () => truncate2,
|
|
26477
|
+
summarize: () => summarize2,
|
|
26478
|
+
selectOne: () => selectOne2,
|
|
26479
|
+
renderLaunchBanner: () => renderLaunchBanner2,
|
|
26480
|
+
renderBrandLogo: () => renderBrandLogo2,
|
|
26481
|
+
promptText: () => promptText2,
|
|
26482
|
+
paint: () => paint2,
|
|
26483
|
+
outro: () => outro2,
|
|
26484
|
+
multiSelect: () => multiSelect2,
|
|
26485
|
+
intro: () => intro2,
|
|
26486
|
+
ellipsize: () => ellipsize2,
|
|
26487
|
+
colorsEnabled: () => colorsEnabled2,
|
|
26488
|
+
brandAnsi: () => brandAnsi2,
|
|
26489
|
+
STEP_DONE: () => STEP_DONE2,
|
|
26490
|
+
STEP_ACTIVE: () => STEP_ACTIVE2,
|
|
26491
|
+
CHECK_ON: () => CHECK_ON2,
|
|
26492
|
+
CHECK_OFF: () => CHECK_OFF2,
|
|
26493
|
+
CARET: () => CARET2,
|
|
26494
|
+
BAR: () => BAR2,
|
|
26495
|
+
ANSI_RESET: () => ANSI_RESET2,
|
|
26496
|
+
ANSI_DIM: () => ANSI_DIM2,
|
|
26497
|
+
ANSI_BOLD: () => ANSI_BOLD2
|
|
26498
|
+
});
|
|
26499
|
+
import * as readline3 from "node:readline";
|
|
26500
|
+
function colorsEnabled2(out) {
|
|
26501
|
+
return !!out.isTTY && !process.env.NO_COLOR;
|
|
26502
|
+
}
|
|
26503
|
+
function brandAnsi2(role) {
|
|
26504
|
+
const h = HUES2[role];
|
|
26505
|
+
const code = truecolorEnabled2() ? `38;2;${h.rgb.join(";")}` : h.basic;
|
|
26506
|
+
return `${ESC2}[${code}m`;
|
|
26507
|
+
}
|
|
26508
|
+
function truecolorEnabled2() {
|
|
26509
|
+
return /truecolor|24bit/i.test(process.env.COLORTERM || "");
|
|
26510
|
+
}
|
|
26511
|
+
function paint2(on) {
|
|
26512
|
+
const tc = on && truecolorEnabled2();
|
|
26513
|
+
const mk = (h, bold = false) => (s) => {
|
|
26514
|
+
if (!on)
|
|
26515
|
+
return s;
|
|
26516
|
+
const code = tc ? `38;2;${h.rgb[0]};${h.rgb[1]};${h.rgb[2]}` : h.basic;
|
|
26517
|
+
return `${ESC2}[${bold ? "1;" : ""}${code}m${s}${ESC2}[0m`;
|
|
26518
|
+
};
|
|
26519
|
+
return {
|
|
26520
|
+
bold: (s) => on ? `${ESC2}[1m${s}${ESC2}[0m` : s,
|
|
26521
|
+
dim: mk(HUES2.dim),
|
|
26522
|
+
guide: mk(HUES2.guide),
|
|
26523
|
+
pink: mk(HUES2.pink),
|
|
26524
|
+
pinkBold: mk(HUES2.pink, true),
|
|
26525
|
+
softPink: mk(HUES2.logoPink),
|
|
26526
|
+
warn: mk(HUES2.warn)
|
|
26527
|
+
};
|
|
26528
|
+
}
|
|
26529
|
+
function renderLogo2(colorize) {
|
|
26530
|
+
const pad = ".".repeat(LOGO_GRID2[0]?.length ?? 0);
|
|
26531
|
+
const rgb = (ch) => ch === "t" ? LOGO_TEAL2 : ch === "p" ? LOGO_PINK2 : null;
|
|
26532
|
+
const lines = [];
|
|
26533
|
+
for (let r = 0;r < LOGO_GRID2.length; r += 2) {
|
|
26534
|
+
const top = LOGO_GRID2[r];
|
|
26535
|
+
const bot = LOGO_GRID2[r + 1] ?? pad;
|
|
26536
|
+
let line = "";
|
|
26537
|
+
for (let x = 0;x < top.length; x++) {
|
|
26538
|
+
const t = rgb(top[x]);
|
|
26539
|
+
const b = rgb(bot[x]);
|
|
26540
|
+
if (!t && !b) {
|
|
26541
|
+
line += " ";
|
|
26542
|
+
} else if (!colorize) {
|
|
26543
|
+
line += t && b ? "█" : t ? "▀" : "▄";
|
|
26544
|
+
} else if (t && b) {
|
|
26545
|
+
line += t === b ? `${ESC2}[38;2;${t.join(";")}m█${ESC2}[0m` : `${ESC2}[38;2;${t.join(";")};48;2;${b.join(";")}m▀${ESC2}[0m`;
|
|
26546
|
+
} else if (t) {
|
|
26547
|
+
line += `${ESC2}[38;2;${t.join(";")}m▀${ESC2}[0m`;
|
|
26548
|
+
} else {
|
|
26549
|
+
line += `${ESC2}[38;2;${b.join(";")}m▄${ESC2}[0m`;
|
|
26550
|
+
}
|
|
26551
|
+
}
|
|
26552
|
+
lines.push(line);
|
|
26553
|
+
}
|
|
26554
|
+
return lines;
|
|
26555
|
+
}
|
|
26556
|
+
function truncate2(line, width) {
|
|
26557
|
+
let visual = 0;
|
|
26558
|
+
let out = "";
|
|
26559
|
+
let i = 0;
|
|
26560
|
+
while (i < line.length) {
|
|
26561
|
+
if (line[i] === ESC2 && line[i + 1] === "[") {
|
|
26562
|
+
let j = i + 2;
|
|
26563
|
+
while (j < line.length && !/[A-Za-z]/.test(line[j]))
|
|
26564
|
+
j++;
|
|
26565
|
+
j++;
|
|
26566
|
+
out += line.slice(i, j);
|
|
26567
|
+
i = j;
|
|
26568
|
+
} else {
|
|
26569
|
+
if (visual >= width)
|
|
26570
|
+
break;
|
|
26571
|
+
out += line[i];
|
|
26572
|
+
visual++;
|
|
26573
|
+
i++;
|
|
26574
|
+
}
|
|
26575
|
+
}
|
|
26576
|
+
return out;
|
|
26577
|
+
}
|
|
26578
|
+
function ellipsize2(text, width) {
|
|
26579
|
+
if (width <= 0)
|
|
26580
|
+
return "";
|
|
26581
|
+
if (text.length <= width)
|
|
26582
|
+
return text;
|
|
26583
|
+
return text.slice(0, width - 1).trimEnd() + "…";
|
|
26584
|
+
}
|
|
26585
|
+
function summarize2(labels, noun = "selected") {
|
|
26586
|
+
if (labels.length === 0)
|
|
26587
|
+
return "none";
|
|
26588
|
+
if (labels.length <= 3)
|
|
26589
|
+
return labels.join(", ");
|
|
26590
|
+
const head = labels.slice(0, 3).join(", ");
|
|
26591
|
+
return `${labels.length} ${noun} · ${head} +${labels.length - 3}`;
|
|
26592
|
+
}
|
|
26593
|
+
function writeLines2(out, lines) {
|
|
26594
|
+
const cols = out.columns || 80;
|
|
26595
|
+
out.write(lines.map((l) => l === "" ? l : truncate2(l, cols)).join(`
|
|
26596
|
+
`) + `
|
|
26597
|
+
`);
|
|
26598
|
+
}
|
|
26599
|
+
function renderBrandLogo2(stdout = process.stdout) {
|
|
26600
|
+
const c2 = paint2(colorsEnabled2(stdout));
|
|
26601
|
+
const cols = stdout.columns || 80;
|
|
26602
|
+
if (cols < LOGO_MIN_COLS2) {
|
|
26603
|
+
return [`${c2.guide(FLOWER2)} fa${c2.pink("il")}proof ai ${c2.dim("· " + TAGLINE2)}`];
|
|
26604
|
+
}
|
|
26605
|
+
const tc = colorsEnabled2(stdout) && truecolorEnabled2();
|
|
26606
|
+
const lines = renderLogo2(tc).map((l) => ` ${l}`);
|
|
26607
|
+
lines.push("");
|
|
26608
|
+
lines.push(` fa${c2.pink("il")}proof ai`);
|
|
26609
|
+
lines.push(` ${c2.dim(TAGLINE2)}`);
|
|
26610
|
+
return lines;
|
|
26611
|
+
}
|
|
26612
|
+
function intro2(message, stdout = process.stdout) {
|
|
26613
|
+
if (!stdout.isTTY)
|
|
26614
|
+
return;
|
|
26615
|
+
const c2 = paint2(colorsEnabled2(stdout));
|
|
26616
|
+
const lines = ["", ...renderBrandLogo2(stdout)];
|
|
26617
|
+
lines.push(c2.dim(BAR2));
|
|
26618
|
+
lines.push(`${c2.guide(STEP_ACTIVE2)} ${c2.bold(message)}`);
|
|
26619
|
+
writeLines2(stdout, lines);
|
|
26620
|
+
}
|
|
26621
|
+
function renderLaunchBanner2(version3, stdout = process.stdout) {
|
|
26622
|
+
const c2 = paint2(colorsEnabled2(stdout));
|
|
26623
|
+
const row = (label, value) => ` ${c2.guide(label.padEnd(9))}${value}`;
|
|
26624
|
+
const header = stdout.isTTY ? renderBrandLogo2(stdout) : [" failproof ai", ` ${TAGLINE2}`];
|
|
26625
|
+
return [
|
|
26626
|
+
"",
|
|
26627
|
+
...header,
|
|
26628
|
+
"",
|
|
26629
|
+
row("version", c2.pink(version3)),
|
|
26630
|
+
row("star", c2.dim("https://github.com/failproofai/failproofai")),
|
|
26631
|
+
row("docs", c2.dim("https://docs.befailproof.ai/introduction")),
|
|
26632
|
+
row("discord", c2.dim("https://discord.befailproof.ai/")),
|
|
26633
|
+
""
|
|
26634
|
+
];
|
|
26635
|
+
}
|
|
26636
|
+
function outro2(message, opts = {}, stdout = process.stdout) {
|
|
26637
|
+
const c2 = paint2(colorsEnabled2(stdout));
|
|
26638
|
+
const ok = opts.ok !== false;
|
|
26639
|
+
if (!stdout.isTTY) {
|
|
26640
|
+
stdout.write(message + `
|
|
26641
|
+
`);
|
|
26642
|
+
return;
|
|
26643
|
+
}
|
|
26644
|
+
const end = ok ? c2.pink(BAR_END2) : c2.dim(BAR_END2);
|
|
26645
|
+
const text = ok ? c2.pink(message) : c2.dim(message);
|
|
26646
|
+
writeLines2(stdout, [c2.dim(BAR2), `${end} ${text}`]);
|
|
26647
|
+
}
|
|
26648
|
+
function repaint2(out, region, lines) {
|
|
26649
|
+
if (region.lastCount > 0)
|
|
26650
|
+
out.write(`${ESC2}[${region.lastCount}A${ESC2}[J`);
|
|
26651
|
+
writeLines2(out, lines);
|
|
26652
|
+
region.lastCount = lines.length;
|
|
26653
|
+
}
|
|
26654
|
+
function hideCursor2(out) {
|
|
26655
|
+
out.write(`${ESC2}[?25l`);
|
|
26656
|
+
}
|
|
26657
|
+
function showCursor2(out) {
|
|
26658
|
+
out.write(`${ESC2}[?25h`);
|
|
26659
|
+
}
|
|
26660
|
+
function nameWidth2(labels) {
|
|
26661
|
+
return Math.min(24, Math.max(6, ...labels.map((l) => l.length)));
|
|
26662
|
+
}
|
|
26663
|
+
function displayRows2(choices) {
|
|
26664
|
+
const rows = [];
|
|
26665
|
+
let lastSection;
|
|
26666
|
+
choices.forEach((choice, index) => {
|
|
26667
|
+
if (choice.section && choice.section !== lastSection) {
|
|
26668
|
+
lastSection = choice.section;
|
|
26669
|
+
rows.push({ kind: "header", text: choice.section });
|
|
26670
|
+
}
|
|
26671
|
+
rows.push({ kind: "item", index });
|
|
26672
|
+
});
|
|
26673
|
+
return rows;
|
|
26674
|
+
}
|
|
26675
|
+
function viewport2(rows, cursorRow, window) {
|
|
26676
|
+
if (rows.length <= window)
|
|
26677
|
+
return { start: 0, end: rows.length };
|
|
26678
|
+
let start = cursorRow - Math.floor(window / 2);
|
|
26679
|
+
start = Math.max(0, Math.min(start, rows.length - window));
|
|
26680
|
+
return { start, end: start + window };
|
|
26681
|
+
}
|
|
26682
|
+
function runPrompt2(p) {
|
|
26683
|
+
const { stdin, stdout, c: c2, choices } = p;
|
|
26684
|
+
const region = { lastCount: 0 };
|
|
26685
|
+
const nameCol = nameWidth2(choices.map((ch) => ch.label));
|
|
26686
|
+
let cursor2 = 0;
|
|
26687
|
+
const build = () => {
|
|
26688
|
+
const cols = stdout.columns || 80;
|
|
26689
|
+
const lines = [c2.dim(BAR2), `${c2.guide(STEP_ACTIVE2)} ${c2.bold(p.message)}`];
|
|
26690
|
+
for (const b of p.body ?? [])
|
|
26691
|
+
lines.push(`${c2.dim(BAR2)} ${c2.dim(b)}`);
|
|
26692
|
+
const rows = displayRows2(choices);
|
|
26693
|
+
let cursorRow = 0;
|
|
26694
|
+
rows.forEach((r, ri) => {
|
|
26695
|
+
if (r.kind === "item" && r.index === cursor2)
|
|
26696
|
+
cursorRow = ri;
|
|
26697
|
+
});
|
|
26698
|
+
const { start, end } = viewport2(rows, cursorRow, WINDOW3);
|
|
26699
|
+
const above = rows.slice(0, start).filter((r) => r.kind === "item").length;
|
|
26700
|
+
const below = rows.slice(end).filter((r) => r.kind === "item").length;
|
|
26701
|
+
if (above > 0)
|
|
26702
|
+
lines.push(`${c2.dim(BAR2)} ${c2.dim(`↑ ${above} more`)}`);
|
|
26703
|
+
const budget = Math.max(6, cols - nameCol - 10);
|
|
26704
|
+
for (let ri = start;ri < end; ri++) {
|
|
26705
|
+
const row = rows[ri];
|
|
26706
|
+
if (row.kind === "header") {
|
|
26707
|
+
lines.push(`${c2.dim(BAR2)} ${c2.dim(row.text)}`);
|
|
26708
|
+
} else {
|
|
26709
|
+
lines.push(`${c2.dim(BAR2)} ${p.renderRow(row.index, row.index === cursor2, budget)}`);
|
|
26710
|
+
}
|
|
26711
|
+
}
|
|
26712
|
+
if (below > 0)
|
|
26713
|
+
lines.push(`${c2.dim(BAR2)} ${c2.dim(`↓ ${below} more`)}`);
|
|
26714
|
+
const warn = p.warnLine?.();
|
|
26715
|
+
if (warn)
|
|
26716
|
+
lines.push(`${c2.dim(BAR2)} ${warn}`);
|
|
26717
|
+
lines.push(`${c2.dim(BAR2)} ${c2.dim(p.footer)}`);
|
|
26718
|
+
return lines;
|
|
26719
|
+
};
|
|
26720
|
+
const collapse = (result) => {
|
|
26721
|
+
repaint2(stdout, region, [
|
|
26722
|
+
c2.dim(BAR2),
|
|
26723
|
+
`${c2.dim(STEP_DONE2)} ${p.message}`,
|
|
26724
|
+
`${c2.dim(BAR2)} ${c2.dim(p.summaryFor(result))}`
|
|
26725
|
+
]);
|
|
26726
|
+
};
|
|
26727
|
+
return new Promise((resolve24) => {
|
|
26728
|
+
hideCursor2(stdout);
|
|
26729
|
+
repaint2(stdout, region, build());
|
|
26730
|
+
readline3.emitKeypressEvents(stdin);
|
|
26731
|
+
const wasRaw = stdin.isRaw;
|
|
26732
|
+
stdin.setRawMode?.(true);
|
|
26733
|
+
stdin.resume();
|
|
26734
|
+
const cleanup = () => {
|
|
26735
|
+
stdin.removeListener("keypress", onKey);
|
|
26736
|
+
stdin.setRawMode?.(wasRaw ?? false);
|
|
26737
|
+
stdin.pause();
|
|
26738
|
+
showCursor2(stdout);
|
|
26739
|
+
};
|
|
26740
|
+
const finish = (result) => {
|
|
26741
|
+
cleanup();
|
|
26742
|
+
collapse(result);
|
|
26743
|
+
resolve24(result);
|
|
26744
|
+
};
|
|
26745
|
+
function onKey(_s, key) {
|
|
26746
|
+
if (!key)
|
|
26747
|
+
return;
|
|
26748
|
+
if (key.ctrl && (key.name === "c" || key.name === "d") || key.name === "escape") {
|
|
26749
|
+
finish(null);
|
|
26750
|
+
} else if (key.name === "up") {
|
|
26751
|
+
cursor2 = cursor2 > 0 ? cursor2 - 1 : choices.length - 1;
|
|
26752
|
+
repaint2(stdout, region, build());
|
|
26753
|
+
} else if (key.name === "down") {
|
|
26754
|
+
cursor2 = cursor2 < choices.length - 1 ? cursor2 + 1 : 0;
|
|
26755
|
+
repaint2(stdout, region, build());
|
|
26756
|
+
} else {
|
|
26757
|
+
const outcome = p.onKey(key, cursor2);
|
|
26758
|
+
if (outcome === "redraw")
|
|
26759
|
+
repaint2(stdout, region, build());
|
|
26760
|
+
else if (outcome)
|
|
26761
|
+
finish(outcome.done);
|
|
26762
|
+
}
|
|
26763
|
+
}
|
|
26764
|
+
stdin.on("keypress", onKey);
|
|
26765
|
+
});
|
|
26766
|
+
}
|
|
26767
|
+
function selectOne2(opts) {
|
|
26768
|
+
const stdin = opts.stdin ?? process.stdin;
|
|
26769
|
+
const stdout = opts.stdout ?? process.stdout;
|
|
26770
|
+
const choices = opts.choices;
|
|
26771
|
+
if (!choices.length)
|
|
26772
|
+
return Promise.resolve(null);
|
|
26773
|
+
if (!stdin.isTTY || !stdout.isTTY) {
|
|
26774
|
+
return Promise.resolve(choices[0].value);
|
|
26775
|
+
}
|
|
26776
|
+
const c2 = paint2(colorsEnabled2(stdout));
|
|
26777
|
+
const nameCol = nameWidth2(choices.map((ch) => ch.label));
|
|
26778
|
+
return runPrompt2({
|
|
26779
|
+
stdin,
|
|
26780
|
+
stdout,
|
|
26781
|
+
message: opts.message,
|
|
26782
|
+
c: c2,
|
|
26783
|
+
body: opts.body,
|
|
26784
|
+
choices,
|
|
26785
|
+
renderRow: (index, active, budget) => {
|
|
26786
|
+
const choice = choices[index];
|
|
26787
|
+
const dot = active ? c2.pink(RADIO_ON2) : c2.dim(RADIO_OFF2);
|
|
26788
|
+
const rawLabel = choice.label.padEnd(nameCol);
|
|
26789
|
+
const label = active ? c2.pinkBold(rawLabel) : rawLabel;
|
|
26790
|
+
const hint = choice.hint ? ` ${c2.dim(ellipsize2(choice.hint, budget))}` : "";
|
|
26791
|
+
return `${dot} ${label}${hint}`;
|
|
26792
|
+
},
|
|
26793
|
+
footer: "↑/↓ navigate · enter to select · esc to cancel",
|
|
26794
|
+
onKey: (key, cursor2) => key.name === "return" ? { done: choices[cursor2].value } : undefined,
|
|
26795
|
+
summaryFor: (value) => value === null ? "cancelled" : choices.find((ch) => ch.value === value)?.label ?? String(value)
|
|
26796
|
+
});
|
|
26797
|
+
}
|
|
26798
|
+
function multiSelect2(opts) {
|
|
26799
|
+
const stdin = opts.stdin ?? process.stdin;
|
|
26800
|
+
const stdout = opts.stdout ?? process.stdout;
|
|
26801
|
+
const choices = opts.choices;
|
|
26802
|
+
const minSelected = opts.minSelected ?? 0;
|
|
26803
|
+
const noun = opts.summaryNoun ?? "selected";
|
|
26804
|
+
const checked = choices.map((ch) => ch.locked ? ch.checked ?? true : !!ch.checked);
|
|
26805
|
+
if (!stdin.isTTY || !stdout.isTTY) {
|
|
26806
|
+
return Promise.resolve(choices.filter((_, i) => checked[i]).map((ch) => ch.value));
|
|
26807
|
+
}
|
|
26808
|
+
const c2 = paint2(colorsEnabled2(stdout));
|
|
26809
|
+
const nameCol = nameWidth2(choices.map((ch) => ch.label));
|
|
26810
|
+
let warn = false;
|
|
26811
|
+
return runPrompt2({
|
|
26812
|
+
stdin,
|
|
26813
|
+
stdout,
|
|
26814
|
+
message: opts.message,
|
|
26815
|
+
c: c2,
|
|
26816
|
+
choices,
|
|
26817
|
+
renderRow: (index, active, budget) => {
|
|
26818
|
+
const choice = choices[index];
|
|
26819
|
+
const caret = active ? c2.pink(CARET2) : " ";
|
|
26820
|
+
const box = choice.locked ? checked[index] ? c2.guide(CHECK_ON2) : c2.dim(CHECK_OFF2) : checked[index] ? c2.pink(CHECK_ON2) : c2.dim(CHECK_OFF2);
|
|
26821
|
+
const rawLabel = choice.label.padEnd(nameCol);
|
|
26822
|
+
const label = active ? c2.pinkBold(rawLabel) : checked[index] ? rawLabel : c2.dim(rawLabel);
|
|
26823
|
+
const hint = choice.hint ? ` ${c2.dim(ellipsize2(choice.hint, budget))}` : "";
|
|
26824
|
+
return `${caret} ${box} ${label}${hint}`;
|
|
26825
|
+
},
|
|
26826
|
+
warnLine: () => warn ? c2.warn(`Select at least ${minSelected}.`) : null,
|
|
26827
|
+
footer: opts.hint ?? "↑/↓ move · space select · ctrl+a all · enter confirm",
|
|
26828
|
+
onKey: (key, cursor2) => {
|
|
26829
|
+
if (key.name === "space") {
|
|
26830
|
+
if (choices[cursor2]?.locked)
|
|
26831
|
+
return "redraw";
|
|
26832
|
+
checked[cursor2] = !checked[cursor2];
|
|
26833
|
+
warn = false;
|
|
26834
|
+
return "redraw";
|
|
26835
|
+
}
|
|
26836
|
+
if (key.ctrl && key.name === "a") {
|
|
26837
|
+
const allOn = choices.every((ch, i) => checked[i] || ch.locked);
|
|
26838
|
+
for (let i = 0;i < checked.length; i++) {
|
|
26839
|
+
checked[i] = choices[i]?.locked ? true : !allOn;
|
|
26840
|
+
}
|
|
26841
|
+
return "redraw";
|
|
26842
|
+
}
|
|
26843
|
+
if (key.name === "return") {
|
|
26844
|
+
const selected = choices.filter((_, i) => checked[i]).map((ch) => ch.value);
|
|
26845
|
+
const chosen = choices.filter((ch, i) => checked[i] && !ch.locked).length;
|
|
26846
|
+
if (chosen < minSelected) {
|
|
26847
|
+
warn = true;
|
|
26848
|
+
return "redraw";
|
|
26849
|
+
}
|
|
26850
|
+
return { done: selected };
|
|
26851
|
+
}
|
|
26852
|
+
return;
|
|
26853
|
+
},
|
|
26854
|
+
summaryFor: (values) => values === null ? "cancelled" : summarize2(choices.filter((ch) => values.includes(ch.value) && !ch.summaryExclude).map((ch) => ch.label), noun)
|
|
26855
|
+
});
|
|
26856
|
+
}
|
|
26857
|
+
function promptText2(opts) {
|
|
26858
|
+
const stdin = opts.stdin ?? process.stdin;
|
|
26859
|
+
const stdout = opts.stdout ?? process.stdout;
|
|
26860
|
+
const c2 = paint2(colorsEnabled2(stdout));
|
|
26861
|
+
const accept = (raw) => {
|
|
26862
|
+
const value = raw.trim() || opts.defaultValue || "";
|
|
26863
|
+
const error = opts.validate?.(value) ?? null;
|
|
26864
|
+
return error ? { ok: false, error } : { ok: true, value };
|
|
26865
|
+
};
|
|
26866
|
+
if (!stdin.isTTY) {
|
|
26867
|
+
return new Promise((resolve24) => {
|
|
26868
|
+
let buf = "";
|
|
26869
|
+
const onData = (chunk) => {
|
|
26870
|
+
buf += String(chunk);
|
|
26871
|
+
if (buf.includes(`
|
|
26872
|
+
`))
|
|
26873
|
+
done();
|
|
26874
|
+
};
|
|
26875
|
+
const done = () => {
|
|
26876
|
+
stdin.removeListener("data", onData);
|
|
26877
|
+
stdin.removeListener("end", done);
|
|
26878
|
+
const r = accept(buf.split(`
|
|
26879
|
+
`)[0] ?? "");
|
|
26880
|
+
resolve24(r.ok ? r.value : null);
|
|
26881
|
+
};
|
|
26882
|
+
stdin.on("data", onData);
|
|
26883
|
+
stdin.on("end", done);
|
|
26884
|
+
});
|
|
26885
|
+
}
|
|
26886
|
+
return new Promise((resolve24) => {
|
|
26887
|
+
let value = "";
|
|
26888
|
+
const draw = (error) => {
|
|
26889
|
+
const shown = opts.mask ? "•".repeat(value.length) : value;
|
|
26890
|
+
const hint = opts.hint ? ` ${c2.dim(opts.hint)}` : "";
|
|
26891
|
+
const err = error ? `
|
|
26892
|
+
${c2.warn(error)}` : "";
|
|
26893
|
+
stdout.write(`\r\x1B[2K${c2.bold(opts.message)} ${shown}${hint}${err}`);
|
|
26894
|
+
if (err)
|
|
26895
|
+
stdout.write("\x1B[1A");
|
|
26896
|
+
};
|
|
26897
|
+
draw();
|
|
26898
|
+
readline3.emitKeypressEvents(stdin);
|
|
26899
|
+
const wasRaw = stdin.isRaw;
|
|
26900
|
+
stdin.setRawMode?.(true);
|
|
26901
|
+
stdin.resume();
|
|
26902
|
+
const cleanup = () => {
|
|
26903
|
+
stdin.removeListener("keypress", onKey);
|
|
26904
|
+
stdin.setRawMode?.(wasRaw ?? false);
|
|
26905
|
+
stdin.pause();
|
|
26906
|
+
stdout.write(`
|
|
26907
|
+
`);
|
|
26908
|
+
};
|
|
26909
|
+
function onKey(str2, key) {
|
|
26910
|
+
if (!key)
|
|
26911
|
+
return;
|
|
26912
|
+
if (key.ctrl && (key.name === "c" || key.name === "d") || key.name === "escape") {
|
|
26913
|
+
cleanup();
|
|
26914
|
+
resolve24(null);
|
|
26915
|
+
return;
|
|
26916
|
+
}
|
|
26917
|
+
if (key.name === "return" || key.name === "enter") {
|
|
26918
|
+
const r = accept(value);
|
|
26919
|
+
if (r.ok) {
|
|
26920
|
+
cleanup();
|
|
26921
|
+
resolve24(r.value);
|
|
26922
|
+
} else {
|
|
26923
|
+
draw(r.error);
|
|
26924
|
+
}
|
|
26925
|
+
return;
|
|
26926
|
+
}
|
|
26927
|
+
if (key.name === "backspace") {
|
|
26928
|
+
value = value.slice(0, -1);
|
|
26929
|
+
draw();
|
|
26930
|
+
return;
|
|
26931
|
+
}
|
|
26932
|
+
if (str2 && !key.ctrl && !key.meta) {
|
|
26933
|
+
value += str2;
|
|
26934
|
+
draw();
|
|
26935
|
+
}
|
|
26936
|
+
}
|
|
26937
|
+
stdin.on("keypress", onKey);
|
|
26938
|
+
});
|
|
26939
|
+
}
|
|
26940
|
+
var ESC2 = "\x1B", BAR2 = "│", BAR_END2 = "└", STEP_ACTIVE2 = "◆", STEP_DONE2 = "◇", RADIO_ON2 = "●", RADIO_OFF2 = "○", CHECK_ON2 = "◼", CHECK_OFF2 = "◻", CARET2 = "❯", FLOWER2 = "❋", HUES2, ANSI_RESET2, ANSI_BOLD2, ANSI_DIM2, LOGO_MIN_COLS2 = 22, TAGLINE2 = "end-to-end failure layer for ai agents", LOGO_GRID2, LOGO_TEAL2, LOGO_PINK2, WINDOW3 = 8;
|
|
26941
|
+
var init_tui2 = __esm(() => {
|
|
26942
|
+
HUES2 = {
|
|
26943
|
+
guide: { rgb: [102, 209, 181], basic: "36" },
|
|
26944
|
+
pink: { rgb: [255, 46, 136], basic: "95" },
|
|
26945
|
+
logoPink: { rgb: [228, 88, 124], basic: "95" },
|
|
26946
|
+
warn: { rgb: [227, 179, 65], basic: "33" },
|
|
26947
|
+
dim: { rgb: [107, 118, 132], basic: "2" }
|
|
26948
|
+
};
|
|
26949
|
+
ANSI_RESET2 = `${ESC2}[0m`;
|
|
26950
|
+
ANSI_BOLD2 = `${ESC2}[1m`;
|
|
26951
|
+
ANSI_DIM2 = `${ESC2}[2m`;
|
|
26952
|
+
LOGO_GRID2 = [
|
|
26953
|
+
"...tt........",
|
|
26954
|
+
"..tttt.......",
|
|
26955
|
+
".tttttt..pppp",
|
|
26956
|
+
".tttttt..pppp",
|
|
26957
|
+
"..tttt...pppp",
|
|
26958
|
+
"...tt....pppp",
|
|
26959
|
+
".........pppp",
|
|
26960
|
+
".........pppp",
|
|
26961
|
+
"..pppp...pppp",
|
|
26962
|
+
"..pppp...pppp",
|
|
26963
|
+
"..pppp...pppp",
|
|
26964
|
+
".pppppp..pppp",
|
|
26965
|
+
".pppppp..pppp",
|
|
26966
|
+
".pppppp..pppp",
|
|
26967
|
+
".pppppp..pppp",
|
|
26968
|
+
"..pppp...pppp",
|
|
26969
|
+
"..ppppppppppp",
|
|
26970
|
+
"..ppppppppppp",
|
|
26971
|
+
"..ppppppppppp",
|
|
26972
|
+
"..ppppppppppp"
|
|
26973
|
+
];
|
|
26974
|
+
LOGO_TEAL2 = HUES2.guide.rgb;
|
|
26975
|
+
LOGO_PINK2 = HUES2.logoPink.rgb;
|
|
26976
|
+
});
|
|
26977
|
+
|
|
26978
|
+
// src/hooks/manager.ts
|
|
26979
|
+
var exports_manager = {};
|
|
26980
|
+
__export(exports_manager, {
|
|
26981
|
+
removeHooks: () => removeHooks2,
|
|
26982
|
+
listHooks: () => listHooks,
|
|
26983
|
+
installHooks: () => installHooks2,
|
|
26984
|
+
hooksInstalledInSettings: () => hooksInstalledInSettings2,
|
|
25898
26985
|
getSettingsPath: () => getSettingsPath2
|
|
25899
26986
|
});
|
|
25900
26987
|
import { execSync as execSync7 } from "node:child_process";
|
|
25901
|
-
import { existsSync as
|
|
26988
|
+
import { existsSync as existsSync32 } from "node:fs";
|
|
25902
26989
|
import { resolve as resolve24, basename as basename6 } from "node:path";
|
|
25903
26990
|
import { platform as platform5, arch as arch4, release as release3, hostname as hostname5 } from "node:os";
|
|
25904
26991
|
function getSettingsPath2(scope, cwd) {
|
|
@@ -26009,7 +27096,7 @@ async function installHooksImpl2(policyNames, scope = "user", cwd, includeBeta =
|
|
|
26009
27096
|
} else if (customPoliciesPath && (typeof customPoliciesPath === "string" || customPoliciesPath.length > 0)) {
|
|
26010
27097
|
const incoming = (typeof customPoliciesPath === "string" ? [customPoliciesPath] : customPoliciesPath).map((path3) => resolve24(path3));
|
|
26011
27098
|
const carried = (previousConfig.customPoliciesPaths ?? (previousConfig.customPoliciesPath ? [previousConfig.customPoliciesPath] : [])).map((path3) => resolve24(path3)).filter((path3) => {
|
|
26012
|
-
if (
|
|
27099
|
+
if (existsSync32(path3))
|
|
26013
27100
|
return true;
|
|
26014
27101
|
console.log(`Dropping custom policies path (file no longer exists): ${path3}`);
|
|
26015
27102
|
return false;
|
|
@@ -26145,7 +27232,7 @@ This file can be committed to git — no machine-specific paths.`);
|
|
|
26145
27232
|
} catch {}
|
|
26146
27233
|
}
|
|
26147
27234
|
}
|
|
26148
|
-
async function
|
|
27235
|
+
async function removeHooks2(policyNames, scope = "user", cwd, opts) {
|
|
26149
27236
|
const configScope = scope === "all" ? "user" : scope;
|
|
26150
27237
|
const selectedClis = opts?.cli && opts.cli.length > 0 ? [...new Set(opts.cli)] : ["claude"];
|
|
26151
27238
|
if (opts?.removeCustomHooks) {
|
|
@@ -26201,7 +27288,7 @@ async function removeHooks(policyNames, scope = "user", cwd, opts) {
|
|
|
26201
27288
|
const scopesToRemove = scope === "all" ? [...integration.scopes] : integration.scopes.includes(scope) ? [scope] : [];
|
|
26202
27289
|
for (const s of scopesToRemove) {
|
|
26203
27290
|
const settingsPaths = settingsPathsFor(integration, s, cwd);
|
|
26204
|
-
const existing = settingsPaths.filter((p) =>
|
|
27291
|
+
const existing = settingsPaths.filter((p) => existsSync32(p));
|
|
26205
27292
|
if (existing.length === 0) {
|
|
26206
27293
|
if (scope !== "all" && selectedClis.length === 1) {
|
|
26207
27294
|
console.log("No settings file found. Nothing to remove.");
|
|
@@ -26402,7 +27489,7 @@ Failproof AI Hook Policies
|
|
|
26402
27489
|
for (const path3 of explicitPaths) {
|
|
26403
27490
|
const absPath = resolve24(findProjectConfigDir(cwd ?? process.cwd()), path3);
|
|
26404
27491
|
console.log(` ${absPath}`);
|
|
26405
|
-
if (!
|
|
27492
|
+
if (!existsSync32(absPath)) {
|
|
26406
27493
|
console.log(` \x1B[31m✗ File not found: ${absPath}\x1B[0m`);
|
|
26407
27494
|
continue;
|
|
26408
27495
|
}
|
|
@@ -26499,7 +27586,7 @@ __export(exports_install_prompt, {
|
|
|
26499
27586
|
promptPolicySelection: () => promptPolicySelection2,
|
|
26500
27587
|
buildCliMenuOptions: () => buildCliMenuOptions
|
|
26501
27588
|
});
|
|
26502
|
-
import * as
|
|
27589
|
+
import * as readline4 from "node:readline";
|
|
26503
27590
|
async function resolveTargetClis(explicit, action = "install") {
|
|
26504
27591
|
const detected = explicit && explicit.length > 0 ? [] : detectInstalledClis();
|
|
26505
27592
|
const stdinIsTty = !!process.stdin.isTTY;
|
|
@@ -26606,13 +27693,13 @@ async function promptCliTargetSelection(detected, action = "install") {
|
|
|
26606
27693
|
let cursor2 = 0;
|
|
26607
27694
|
let lastLineCount = 0;
|
|
26608
27695
|
let cursorHidden = false;
|
|
26609
|
-
function
|
|
27696
|
+
function hideCursor3() {
|
|
26610
27697
|
if (!cursorHidden) {
|
|
26611
27698
|
process.stdout.write("\x1B[?25l");
|
|
26612
27699
|
cursorHidden = true;
|
|
26613
27700
|
}
|
|
26614
27701
|
}
|
|
26615
|
-
function
|
|
27702
|
+
function showCursor3() {
|
|
26616
27703
|
if (cursorHidden) {
|
|
26617
27704
|
process.stdout.write("\x1B[?25h");
|
|
26618
27705
|
cursorHidden = false;
|
|
@@ -26622,7 +27709,7 @@ async function promptCliTargetSelection(detected, action = "install") {
|
|
|
26622
27709
|
const heading = action === "uninstall" ? "Remove failproofai hooks" : "Install failproofai hooks";
|
|
26623
27710
|
function render() {
|
|
26624
27711
|
const cols = process.stdout.columns || 100;
|
|
26625
|
-
|
|
27712
|
+
hideCursor3();
|
|
26626
27713
|
const g = dim(BAR);
|
|
26627
27714
|
const lines = [g, `${teal(STEP_ACTIVE)} ${bold(heading)}`];
|
|
26628
27715
|
for (const row of buildDisplayRows()) {
|
|
@@ -26655,13 +27742,13 @@ async function promptCliTargetSelection(detected, action = "install") {
|
|
|
26655
27742
|
const itemCount = options.length;
|
|
26656
27743
|
return new Promise((resolve25) => {
|
|
26657
27744
|
render();
|
|
26658
|
-
|
|
27745
|
+
readline4.emitKeypressEvents(process.stdin);
|
|
26659
27746
|
const wasRaw = process.stdin.isRaw;
|
|
26660
27747
|
if (process.stdin.setRawMode)
|
|
26661
27748
|
process.stdin.setRawMode(true);
|
|
26662
27749
|
process.stdin.resume();
|
|
26663
27750
|
function cleanup() {
|
|
26664
|
-
|
|
27751
|
+
showCursor3();
|
|
26665
27752
|
process.stdin.removeListener("keypress", onKey);
|
|
26666
27753
|
if (process.stdin.setRawMode)
|
|
26667
27754
|
process.stdin.setRawMode(wasRaw ?? false);
|
|
@@ -26722,13 +27809,13 @@ async function promptPolicySelection2(preSelected, options = {}) {
|
|
|
26722
27809
|
let search = "";
|
|
26723
27810
|
let lastLineCount = 0;
|
|
26724
27811
|
let cursorHidden = false;
|
|
26725
|
-
function
|
|
27812
|
+
function hideCursor3() {
|
|
26726
27813
|
if (!cursorHidden) {
|
|
26727
27814
|
process.stdout.write("\x1B[?25l");
|
|
26728
27815
|
cursorHidden = true;
|
|
26729
27816
|
}
|
|
26730
27817
|
}
|
|
26731
|
-
function
|
|
27818
|
+
function showCursor3() {
|
|
26732
27819
|
if (cursorHidden) {
|
|
26733
27820
|
process.stdout.write("\x1B[?25h");
|
|
26734
27821
|
cursorHidden = false;
|
|
@@ -26775,7 +27862,7 @@ async function promptPolicySelection2(preSelected, options = {}) {
|
|
|
26775
27862
|
}
|
|
26776
27863
|
function render() {
|
|
26777
27864
|
const cols = process.stdout.columns || 100;
|
|
26778
|
-
|
|
27865
|
+
hideCursor3();
|
|
26779
27866
|
const filtered = getFiltered();
|
|
26780
27867
|
const shown = filtered.length;
|
|
26781
27868
|
if (shown > 0 && cursor2 >= shown)
|
|
@@ -26794,10 +27881,10 @@ async function promptPolicySelection2(preSelected, options = {}) {
|
|
|
26794
27881
|
for (let i = 0;i < WINDOW_SIZE + 1; i++)
|
|
26795
27882
|
lines.push(g);
|
|
26796
27883
|
} else {
|
|
26797
|
-
const
|
|
27884
|
+
const displayRows3 = buildDisplayRows(filtered);
|
|
26798
27885
|
let cursorDisplayRow = 0;
|
|
26799
|
-
for (let i = 0;i <
|
|
26800
|
-
const row =
|
|
27886
|
+
for (let i = 0;i < displayRows3.length; i++) {
|
|
27887
|
+
const row = displayRows3[i];
|
|
26801
27888
|
if (row.kind === "item" && row.filteredIndex === cursor2) {
|
|
26802
27889
|
cursorDisplayRow = i;
|
|
26803
27890
|
break;
|
|
@@ -26805,12 +27892,12 @@ async function promptPolicySelection2(preSelected, options = {}) {
|
|
|
26805
27892
|
}
|
|
26806
27893
|
let windowStart = cursorDisplayRow - Math.floor(WINDOW_SIZE / 2);
|
|
26807
27894
|
windowStart = Math.max(0, windowStart);
|
|
26808
|
-
windowStart = Math.min(windowStart, Math.max(0,
|
|
26809
|
-
const windowEnd = Math.min(
|
|
26810
|
-
const aboveItems =
|
|
27895
|
+
windowStart = Math.min(windowStart, Math.max(0, displayRows3.length - WINDOW_SIZE));
|
|
27896
|
+
const windowEnd = Math.min(displayRows3.length, windowStart + WINDOW_SIZE);
|
|
27897
|
+
const aboveItems = displayRows3.slice(0, windowStart).filter((r) => r.kind === "item").length;
|
|
26811
27898
|
lines.push(aboveItems > 0 ? `${g} ${dim(`↑ ${aboveItems} more`)}` : g);
|
|
26812
27899
|
for (let i = windowStart;i < windowEnd; i++) {
|
|
26813
|
-
const row =
|
|
27900
|
+
const row = displayRows3[i];
|
|
26814
27901
|
if (row.kind === "header") {
|
|
26815
27902
|
lines.push(`${g} ${dim(row.category.toUpperCase())} ${dim(`${row.enabledCount}/${row.totalCount}`)}`);
|
|
26816
27903
|
} else {
|
|
@@ -26827,7 +27914,7 @@ async function promptPolicySelection2(preSelected, options = {}) {
|
|
|
26827
27914
|
}
|
|
26828
27915
|
for (let i = windowEnd - windowStart;i < WINDOW_SIZE; i++)
|
|
26829
27916
|
lines.push(g);
|
|
26830
|
-
const belowItems =
|
|
27917
|
+
const belowItems = displayRows3.slice(windowEnd).filter((r) => r.kind === "item").length;
|
|
26831
27918
|
lines.push(belowItems > 0 ? `${g} ${dim(`↓ ${belowItems} more`)}` : g);
|
|
26832
27919
|
}
|
|
26833
27920
|
lines.push(g);
|
|
@@ -26843,7 +27930,7 @@ async function promptPolicySelection2(preSelected, options = {}) {
|
|
|
26843
27930
|
render();
|
|
26844
27931
|
process.stdin.setRawMode(true);
|
|
26845
27932
|
process.stdin.resume();
|
|
26846
|
-
|
|
27933
|
+
readline4.emitKeypressEvents(process.stdin);
|
|
26847
27934
|
function keypressHandler(_str, key) {
|
|
26848
27935
|
if (!key)
|
|
26849
27936
|
return;
|
|
@@ -26899,7 +27986,7 @@ ${dim(BAR)} ${dim(`${selected.length} selected`)}
|
|
|
26899
27986
|
}
|
|
26900
27987
|
}
|
|
26901
27988
|
function cleanup() {
|
|
26902
|
-
|
|
27989
|
+
showCursor3();
|
|
26903
27990
|
process.stdin.removeListener("keypress", keypressHandler);
|
|
26904
27991
|
process.stdin.setRawMode(false);
|
|
26905
27992
|
process.stdin.pause();
|
|
@@ -27537,8 +28624,8 @@ __export(exports_launch2, {
|
|
|
27537
28624
|
launch: () => launch2
|
|
27538
28625
|
});
|
|
27539
28626
|
import { spawn as spawn3 } from "child_process";
|
|
27540
|
-
import { realpathSync as realpathSync5, existsSync as
|
|
27541
|
-
import { resolve as resolve25, dirname as
|
|
28627
|
+
import { realpathSync as realpathSync5, existsSync as existsSync33 } from "node:fs";
|
|
28628
|
+
import { resolve as resolve25, dirname as dirname16 } from "node:path";
|
|
27542
28629
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
27543
28630
|
import { createInterface as createInterface2 } from "node:readline";
|
|
27544
28631
|
function launch2(mode) {
|
|
@@ -27562,9 +28649,9 @@ function launch2(mode) {
|
|
|
27562
28649
|
process.env.PORT = port;
|
|
27563
28650
|
process.env.HOSTNAME = bindHost;
|
|
27564
28651
|
cmd = "node";
|
|
27565
|
-
const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT ?? resolve25(
|
|
28652
|
+
const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT ?? resolve25(dirname16(realpathSync5(fileURLToPath3(import.meta.url))), "..");
|
|
27566
28653
|
const serverJsPath = resolve25(packageRoot, ".next/standalone/server.js");
|
|
27567
|
-
if (!
|
|
28654
|
+
if (!existsSync33(serverJsPath)) {
|
|
27568
28655
|
let shadowMessage = null;
|
|
27569
28656
|
try {
|
|
27570
28657
|
const diag = diagnoseShadow({ selfPackageRoot: packageRoot, selfVersion: version2 });
|
|
@@ -27661,17 +28748,17 @@ var init_cli_error2 = __esm(() => {
|
|
|
27661
28748
|
|
|
27662
28749
|
// bin/failproofai.mjs
|
|
27663
28750
|
import { realpathSync as realpathSync6 } from "fs";
|
|
27664
|
-
import { dirname as
|
|
28751
|
+
import { dirname as dirname17, resolve as resolve26 } from "path";
|
|
27665
28752
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
27666
28753
|
// package.json
|
|
27667
|
-
var version = "1.0.0-beta.
|
|
28754
|
+
var version = "1.0.0-beta.8";
|
|
27668
28755
|
|
|
27669
28756
|
// bin/failproofai.mjs
|
|
27670
28757
|
if (!process.env.FAILPROOFAI_PACKAGE_ROOT) {
|
|
27671
|
-
process.env.FAILPROOFAI_PACKAGE_ROOT = resolve26(
|
|
28758
|
+
process.env.FAILPROOFAI_PACKAGE_ROOT = resolve26(dirname17(realpathSync6(fileURLToPath4(import.meta.url))), "..");
|
|
27672
28759
|
}
|
|
27673
28760
|
if (!process.env.FAILPROOFAI_DIST_PATH) {
|
|
27674
|
-
process.env.FAILPROOFAI_DIST_PATH = resolve26(
|
|
28761
|
+
process.env.FAILPROOFAI_DIST_PATH = resolve26(dirname17(realpathSync6(fileURLToPath4(import.meta.url))), "..", "dist");
|
|
27675
28762
|
}
|
|
27676
28763
|
var args = process.argv.slice(2);
|
|
27677
28764
|
if (args[0] === "p")
|
|
@@ -27731,15 +28818,10 @@ if (hookIdx >= 0) {
|
|
|
27731
28818
|
let result;
|
|
27732
28819
|
if (attempt.ok) {
|
|
27733
28820
|
result = attempt.response;
|
|
27734
|
-
} else if (attempt.failure === "protocol-mismatch") {
|
|
27735
|
-
console.error("[failproofai] failproofaid speaks a different protocol version than this CLI \u2014 " + "evaluating in-process instead (slower, identical policies). Run `failproofai config` to update the daemon.");
|
|
27736
|
-
result = await evaluateHookEvent2(eventType, cli, stdinRead.payload);
|
|
27737
28821
|
} else {
|
|
28822
|
+
const reason = attempt.failure === "protocol-mismatch" ? "failproofaid is running a different protocol version than this CLI, so it cannot evaluate this call. Run `failproofai config` to update the daemon." : "failproofaid could not be reached. This machine is configured to run hooks through it " + "\u2014 check the daemon (see `failproofai config`) rather than retrying blindly.";
|
|
27738
28823
|
result = await evaluateHookEvent2(eventType, cli, stdinRead.payload, {
|
|
27739
|
-
forceDecision: {
|
|
27740
|
-
decision: "deny",
|
|
27741
|
-
reason: "failproofaid could not be reached. This machine is configured to run hooks through it " + "\u2014 check the daemon (see `failproofai config`) rather than retrying blindly."
|
|
27742
|
-
}
|
|
28824
|
+
forceDecision: { decision: "deny", reason }
|
|
27743
28825
|
});
|
|
27744
28826
|
}
|
|
27745
28827
|
if (result.stdout)
|
|
@@ -27767,7 +28849,7 @@ if (hookIdx >= 0) {
|
|
|
27767
28849
|
}
|
|
27768
28850
|
}
|
|
27769
28851
|
async function runCli() {
|
|
27770
|
-
const SUBCOMMANDS = ["policies", "policy", "audit", "config"];
|
|
28852
|
+
const SUBCOMMANDS = ["policies", "policy", "audit", "config", "uninstall"];
|
|
27771
28853
|
if ((args.includes("--help") || args.includes("-h")) && !SUBCOMMANDS.includes(args[0])) {
|
|
27772
28854
|
const extraArgs = args.filter((a) => a !== "--help" && a !== "-h");
|
|
27773
28855
|
if (extraArgs.length > 0) {
|
|
@@ -27813,6 +28895,16 @@ COMMANDS
|
|
|
27813
28895
|
dashboard at http://localhost:8020/audit
|
|
27814
28896
|
audit --help, -h Show this help for the audit command
|
|
27815
28897
|
|
|
28898
|
+
uninstall Remove failproofai from this machine: hook
|
|
28899
|
+
entries from every agent CLI, and the daemon
|
|
28900
|
+
service. Run this BEFORE \`npm rm -g failproofai\`
|
|
28901
|
+
\u2014 npm runs no uninstall script, so removing the
|
|
28902
|
+
package alone leaves both behind.
|
|
28903
|
+
--purge Also delete ~/.failproofai (settings,
|
|
28904
|
+
credentials, audit history, daemon binary)
|
|
28905
|
+
--dry-run Show what would be removed, change nothing
|
|
28906
|
+
--yes, -y Skip the confirmation prompt
|
|
28907
|
+
|
|
27816
28908
|
--version, -v Print version and exit
|
|
27817
28909
|
--help, -h Show this help message
|
|
27818
28910
|
|
|
@@ -27890,6 +28982,84 @@ Run \`failproofai --help\` for usage.`);
|
|
|
27890
28982
|
await maybeFirstRunConfigure2({}, { postSetupAudit: args[0] !== "audit", force: layoutWasReset });
|
|
27891
28983
|
} catch {}
|
|
27892
28984
|
}
|
|
28985
|
+
if (args[0] === "uninstall") {
|
|
28986
|
+
const subArgs = args.slice(1);
|
|
28987
|
+
if (subArgs.includes("--help") || subArgs.includes("-h")) {
|
|
28988
|
+
console.log(`
|
|
28989
|
+
failproofai uninstall \u2014 remove failproofai from this machine
|
|
28990
|
+
|
|
28991
|
+
USAGE
|
|
28992
|
+
failproofai uninstall [--purge] [--dry-run] [--yes]
|
|
28993
|
+
|
|
28994
|
+
WHAT IT REMOVES
|
|
28995
|
+
\u2022 failproofai hook entries from every agent CLI that has them
|
|
28996
|
+
\u2022 the failproofaid daemon service (needs sudo)
|
|
28997
|
+
\u2022 the "require the daemon" flag \u2014 cleared FIRST, so a partial uninstall can
|
|
28998
|
+
never leave this machine denying every tool call
|
|
28999
|
+
|
|
29000
|
+
OPTIONS
|
|
29001
|
+
--purge Also delete ~/.failproofai \u2014 settings, credentials, audit
|
|
29002
|
+
history and the downloaded daemon binary. Off by default so a
|
|
29003
|
+
reinstall keeps your history.
|
|
29004
|
+
--dry-run Print what would be removed and change nothing.
|
|
29005
|
+
--yes, -y Skip the confirmation prompt. Required when there is no TTY.
|
|
29006
|
+
|
|
29007
|
+
WHY THIS EXISTS
|
|
29008
|
+
npm runs no uninstall script, so \`npm rm -g failproofai\` removes the package
|
|
29009
|
+
and leaves the hook entries and the service behind. Run this first, then:
|
|
29010
|
+
npm rm -g failproofai
|
|
29011
|
+
`);
|
|
29012
|
+
process.exit(0);
|
|
29013
|
+
}
|
|
29014
|
+
const KNOWN = new Set(["--purge", "--dry-run", "--yes", "-y"]);
|
|
29015
|
+
const unknown = subArgs.find((a) => !KNOWN.has(a));
|
|
29016
|
+
if (unknown) {
|
|
29017
|
+
throw new CliError3(`Unexpected argument: ${unknown}
|
|
29018
|
+
Run \`failproofai uninstall --help\` for usage.`);
|
|
29019
|
+
}
|
|
29020
|
+
lastSubcommand = "uninstall_command";
|
|
29021
|
+
const { runUninstallCommand: runUninstallCommand2 } = await Promise.resolve().then(() => (init_uninstall_cli(), exports_uninstall_cli));
|
|
29022
|
+
const purge = subArgs.includes("--purge");
|
|
29023
|
+
const dryRun = subArgs.includes("--dry-run");
|
|
29024
|
+
const yes = subArgs.includes("--yes") || subArgs.includes("-y");
|
|
29025
|
+
let planWasShown = false;
|
|
29026
|
+
const result = await runUninstallCommand2({
|
|
29027
|
+
purge,
|
|
29028
|
+
dryRun,
|
|
29029
|
+
yes,
|
|
29030
|
+
cwd: process.cwd(),
|
|
29031
|
+
confirm: process.stdin.isTTY ? async (planLines) => {
|
|
29032
|
+
planWasShown = true;
|
|
29033
|
+
const { selectOne: selectOne3 } = await Promise.resolve().then(() => (init_tui2(), exports_tui));
|
|
29034
|
+
const answer = await selectOne3({
|
|
29035
|
+
message: purge ? "Remove failproofai and DELETE ~/.failproofai?" : "Remove failproofai from this machine?",
|
|
29036
|
+
body: planLines,
|
|
29037
|
+
choices: [
|
|
29038
|
+
{ label: "No, cancel", value: false },
|
|
29039
|
+
{ label: purge ? "Yes, remove and purge" : "Yes, remove it", value: true }
|
|
29040
|
+
]
|
|
29041
|
+
});
|
|
29042
|
+
return answer === true;
|
|
29043
|
+
} : undefined
|
|
29044
|
+
});
|
|
29045
|
+
const skip = planWasShown ? result.planLines : 0;
|
|
29046
|
+
for (const line of result.lines.slice(skip)) {
|
|
29047
|
+
if (result.exitCode === 0)
|
|
29048
|
+
console.log(line);
|
|
29049
|
+
else
|
|
29050
|
+
console.error(line);
|
|
29051
|
+
}
|
|
29052
|
+
if (!result.purged) {
|
|
29053
|
+
await track("cli_uninstall_command", {
|
|
29054
|
+
ok: result.exitCode === 0,
|
|
29055
|
+
purge,
|
|
29056
|
+
dry_run: dryRun
|
|
29057
|
+
});
|
|
29058
|
+
}
|
|
29059
|
+
lastSubcommand = null;
|
|
29060
|
+
await exitAfterFlush(result.exitCode);
|
|
29061
|
+
return;
|
|
29062
|
+
}
|
|
27893
29063
|
if (args[0] === "policies") {
|
|
27894
29064
|
const subArgs = args.slice(1);
|
|
27895
29065
|
const isInstall = subArgs.includes("--install") || subArgs.includes("-i");
|
|
@@ -28019,7 +29189,7 @@ Run \`failproofai policies --help\` for usage.`);
|
|
|
28019
29189
|
}
|
|
28020
29190
|
if (isUninstall) {
|
|
28021
29191
|
lastSubcommand = "uninstall";
|
|
28022
|
-
const { removeHooks:
|
|
29192
|
+
const { removeHooks: removeHooks3 } = await Promise.resolve().then(() => (init_manager2(), exports_manager));
|
|
28023
29193
|
const { resolveTargetClis: resolveTargetClis2 } = await Promise.resolve().then(() => (init_install_prompt2(), exports_install_prompt));
|
|
28024
29194
|
const scopeIdx = subArgs.indexOf("--scope");
|
|
28025
29195
|
const scope = scopeIdx >= 0 ? subArgs[scopeIdx + 1] : "user";
|
|
@@ -28064,7 +29234,7 @@ Run \`failproofai policies --help\` for usage.`);
|
|
|
28064
29234
|
}
|
|
28065
29235
|
const policyNames = subArgs.filter((a, idx) => !a.startsWith("-") && !consumedIdxs.has(idx));
|
|
28066
29236
|
const cli = await resolveTargetClis2(cliFlagValues.length > 0 ? cliFlagValues : undefined, "uninstall");
|
|
28067
|
-
await
|
|
29237
|
+
await removeHooks3(policyNames.length > 0 ? policyNames : undefined, scope, undefined, { betaOnly, removeCustomHooks, cli });
|
|
28068
29238
|
await track("cli_uninstall_success", {
|
|
28069
29239
|
scope,
|
|
28070
29240
|
cli,
|
|
@@ -28196,8 +29366,8 @@ For multiple policies use \`failproofai policies --${action === "add" ? "install
|
|
|
28196
29366
|
include_beta: includeBeta
|
|
28197
29367
|
});
|
|
28198
29368
|
} else {
|
|
28199
|
-
const { removeHooks:
|
|
28200
|
-
await
|
|
29369
|
+
const { removeHooks: removeHooks3 } = await Promise.resolve().then(() => (init_manager2(), exports_manager));
|
|
29370
|
+
await removeHooks3([policyName], scope, undefined, { betaOnly: false, removeCustomHooks: false, cli });
|
|
28201
29371
|
await track("cli_policy_remove_success", {
|
|
28202
29372
|
scope,
|
|
28203
29373
|
cli,
|