failproofai 0.0.2-beta.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/build-manifest.json +3 -3
- package/.next/standalone/.next/prerender-manifest.json +3 -3
- package/.next/standalone/.next/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 +2 -2
- package/.next/standalone/.next/server/app/_not-found.rsc +15 -15
- package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +15 -15
- 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 +10 -10
- 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/index.html +1 -1
- package/.next/standalone/.next/server/app/index.rsc +15 -15
- package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +15 -15
- package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +10 -10
- 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 +8 -8
- package/.next/standalone/.next/server/app/policies/page.js +1 -1
- 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/chunks/[root-of-the-server]__02nt~6d._.js +1 -1
- package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_0z7w.hh._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__092s1ta._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__09icjsf._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0g.lg8b._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0h..k-e._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0osi8nq._.js → [root-of-the-server]__0okos0k._.js} +3 -3
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0a3kr67._.js → [root-of-the-server]__0qo8503._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0w6l33k._.js +4 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__11pa2ra._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0rbuarm._.js → [root-of-the-server]__12kr5~_._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__12t-wym._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/_10lm7or._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_0xerkr6._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_0q-m0y-._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_0rd0oc-._.js +1 -1
- package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
- package/.next/standalone/.next/server/pages/404.html +2 -2
- 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 +9 -9
- package/.next/standalone/.next/static/chunks/{0qvj8bhl661lq.js → 06og.7e9nkpjh.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0gcz-jqgqz~9m.js → 0_4y_t03jn2nq.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0kob_5.phc~sk.js → 0c_ljlxa._4lc.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0jhw8ofx.5g_e.js → 0cvffh-pbsv5u.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0mjc3aq2wxvlt.js → 0ov60i6md~37t.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0q7z97izctgrw.js → 0x-625~1vx1lu.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0a08gn8709y98.js → 0y~0creqvl5wx.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0mr-jhx402yci.js → 15wf7x-e.8ia3.js} +1 -1
- package/.next/standalone/README.md +9 -9
- package/.next/standalone/bin/failproofai.mjs +221 -128
- package/.next/standalone/dist/cli.mjs +202 -88
- package/.next/standalone/package.json +1 -1
- package/.next/standalone/scripts/publish-aliases.mjs +4 -2
- package/.next/standalone/src/cli-error.ts +18 -0
- package/.next/standalone/src/hooks/manager.ts +17 -3
- package/README.md +9 -9
- package/bin/failproofai.mjs +221 -128
- package/dist/cli.mjs +202 -88
- package/package.json +1 -1
- package/scripts/publish-aliases.mjs +4 -2
- package/src/cli-error.ts +18 -0
- package/src/hooks/manager.ts +17 -3
- /package/.next/standalone/.next/static/{Dnk96sbMPjYOx1pdLdOH0 → WS-OQSqL1Lp1w_obXfjvl}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{Dnk96sbMPjYOx1pdLdOH0 → WS-OQSqL1Lp1w_obXfjvl}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{Dnk96sbMPjYOx1pdLdOH0 → WS-OQSqL1Lp1w_obXfjvl}/_ssgManifest.js +0 -0
package/dist/cli.mjs
CHANGED
|
@@ -1536,7 +1536,7 @@ var init_hook_activity_store = __esm(() => {
|
|
|
1536
1536
|
});
|
|
1537
1537
|
|
|
1538
1538
|
// package.json
|
|
1539
|
-
var version2 = "0.0.2
|
|
1539
|
+
var version2 = "0.0.2";
|
|
1540
1540
|
var init_package = () => {};
|
|
1541
1541
|
|
|
1542
1542
|
// src/posthog-key.ts
|
|
@@ -2077,6 +2077,19 @@ var init_install_prompt = __esm(() => {
|
|
|
2077
2077
|
init_builtin_policies();
|
|
2078
2078
|
});
|
|
2079
2079
|
|
|
2080
|
+
// src/cli-error.ts
|
|
2081
|
+
var CliError;
|
|
2082
|
+
var init_cli_error = __esm(() => {
|
|
2083
|
+
CliError = class CliError extends Error {
|
|
2084
|
+
exitCode;
|
|
2085
|
+
constructor(message, exitCode = 1) {
|
|
2086
|
+
super(message);
|
|
2087
|
+
this.name = "CliError";
|
|
2088
|
+
this.exitCode = exitCode;
|
|
2089
|
+
}
|
|
2090
|
+
};
|
|
2091
|
+
});
|
|
2092
|
+
|
|
2080
2093
|
// src/hooks/manager.ts
|
|
2081
2094
|
var exports_manager = {};
|
|
2082
2095
|
__export(exports_manager, {
|
|
@@ -2130,7 +2143,7 @@ function resolveFailproofaiBinary() {
|
|
|
2130
2143
|
return result.split(`
|
|
2131
2144
|
`)[0].trim();
|
|
2132
2145
|
} catch {
|
|
2133
|
-
throw new
|
|
2146
|
+
throw new CliError(`failproofai binary not found in PATH.
|
|
2134
2147
|
` + "Install it globally first: npm install -g failproofai");
|
|
2135
2148
|
}
|
|
2136
2149
|
}
|
|
@@ -2144,7 +2157,7 @@ function validatePolicyNames(names) {
|
|
|
2144
2157
|
const invalid = names.filter((n) => !VALID_POLICY_NAMES.has(n));
|
|
2145
2158
|
if (invalid.length > 0) {
|
|
2146
2159
|
const validList = [...VALID_POLICY_NAMES].join(", ");
|
|
2147
|
-
throw new
|
|
2160
|
+
throw new CliError(`Unknown policy name(s): ${invalid.join(", ")}
|
|
2148
2161
|
` + `Valid policies: ${validList}`);
|
|
2149
2162
|
}
|
|
2150
2163
|
}
|
|
@@ -2211,6 +2224,15 @@ function removeHooksFromSettingsFile(settingsPath) {
|
|
|
2211
2224
|
return removed;
|
|
2212
2225
|
}
|
|
2213
2226
|
async function installHooks(policyNames, scope = "user", cwd, includeBeta = false, source, customPoliciesPath, removeCustomHooks = false) {
|
|
2227
|
+
if (policyNames !== undefined && policyNames.length > 0) {
|
|
2228
|
+
const nonAllNames = policyNames.filter((n) => n !== "all");
|
|
2229
|
+
if (nonAllNames.length > 0)
|
|
2230
|
+
validatePolicyNames(nonAllNames);
|
|
2231
|
+
if (policyNames.includes("all") && nonAllNames.length > 0) {
|
|
2232
|
+
throw new CliError(`"all" cannot be combined with specific policy names.
|
|
2233
|
+
` + `Use either: --install all or --install block-sudo sanitize-jwt ...`);
|
|
2234
|
+
}
|
|
2235
|
+
}
|
|
2214
2236
|
const binaryPath = resolveFailproofaiBinary();
|
|
2215
2237
|
const previousConfig = readHooksConfig();
|
|
2216
2238
|
const previousEnabled = new Set(previousConfig.enabledPolicies);
|
|
@@ -2220,8 +2242,6 @@ async function installHooks(policyNames, scope = "user", cwd, includeBeta = fals
|
|
|
2220
2242
|
if (policyNames.length === 1 && policyNames[0] === "all") {
|
|
2221
2243
|
incoming = BUILTIN_POLICIES.filter((p) => includeBeta || !p.beta).map((p) => p.name);
|
|
2222
2244
|
} else {
|
|
2223
|
-
if (policyNames.length > 0)
|
|
2224
|
-
validatePolicyNames(policyNames);
|
|
2225
2245
|
incoming = policyNames;
|
|
2226
2246
|
}
|
|
2227
2247
|
selectedPolicies = [...new Set([...previousConfig.enabledPolicies, ...incoming])];
|
|
@@ -2565,6 +2585,7 @@ var init_manager = __esm(() => {
|
|
|
2565
2585
|
init_custom_hooks_loader();
|
|
2566
2586
|
init_hook_telemetry();
|
|
2567
2587
|
init_telemetry_id();
|
|
2588
|
+
init_cli_error();
|
|
2568
2589
|
VALID_POLICY_NAMES = new Set(BUILTIN_POLICIES.map((p) => p.name));
|
|
2569
2590
|
});
|
|
2570
2591
|
|
|
@@ -2719,12 +2740,29 @@ var init_launch = __esm(() => {
|
|
|
2719
2740
|
init_package();
|
|
2720
2741
|
});
|
|
2721
2742
|
|
|
2743
|
+
// src/cli-error.ts
|
|
2744
|
+
var exports_cli_error = {};
|
|
2745
|
+
__export(exports_cli_error, {
|
|
2746
|
+
CliError: () => CliError2
|
|
2747
|
+
});
|
|
2748
|
+
var CliError2;
|
|
2749
|
+
var init_cli_error2 = __esm(() => {
|
|
2750
|
+
CliError2 = class CliError2 extends Error {
|
|
2751
|
+
exitCode;
|
|
2752
|
+
constructor(message, exitCode = 1) {
|
|
2753
|
+
super(message);
|
|
2754
|
+
this.name = "CliError";
|
|
2755
|
+
this.exitCode = exitCode;
|
|
2756
|
+
}
|
|
2757
|
+
};
|
|
2758
|
+
});
|
|
2759
|
+
|
|
2722
2760
|
// bin/failproofai.mjs
|
|
2723
2761
|
import { realpathSync as realpathSync2 } from "fs";
|
|
2724
2762
|
import { dirname as dirname5, resolve as resolve8 } from "path";
|
|
2725
2763
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
2726
2764
|
// package.json
|
|
2727
|
-
var version = "0.0.2
|
|
2765
|
+
var version = "0.0.2";
|
|
2728
2766
|
|
|
2729
2767
|
// bin/failproofai.mjs
|
|
2730
2768
|
if (!process.env.FAILPROOFAI_PACKAGE_ROOT) {
|
|
@@ -2736,9 +2774,32 @@ if (!process.env.FAILPROOFAI_DIST_PATH) {
|
|
|
2736
2774
|
var args = process.argv.slice(2);
|
|
2737
2775
|
if (args[0] === "p")
|
|
2738
2776
|
args[0] = "policies";
|
|
2739
|
-
var
|
|
2740
|
-
if (
|
|
2741
|
-
|
|
2777
|
+
var hookIdx = args.indexOf("--hook");
|
|
2778
|
+
if (hookIdx >= 0) {
|
|
2779
|
+
if (!args[hookIdx + 1]) {
|
|
2780
|
+
console.error("Error: Missing event type after --hook");
|
|
2781
|
+
console.error("Usage: failproofai --hook <event> (e.g. PreToolUse, PostToolUse)");
|
|
2782
|
+
process.exit(1);
|
|
2783
|
+
}
|
|
2784
|
+
try {
|
|
2785
|
+
const { handleHookEvent: handleHookEvent2 } = await Promise.resolve().then(() => (init_handler(), exports_handler));
|
|
2786
|
+
const exitCode = await handleHookEvent2(args[hookIdx + 1]);
|
|
2787
|
+
process.exit(exitCode);
|
|
2788
|
+
} catch (err) {
|
|
2789
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2790
|
+
console.error(`Unexpected error: ${msg}`);
|
|
2791
|
+
process.exit(2);
|
|
2792
|
+
}
|
|
2793
|
+
}
|
|
2794
|
+
async function runCli() {
|
|
2795
|
+
const SUBCOMMANDS = ["policies"];
|
|
2796
|
+
if ((args.includes("--help") || args.includes("-h")) && !SUBCOMMANDS.includes(args[0])) {
|
|
2797
|
+
const extraArgs = args.filter((a) => a !== "--help" && a !== "-h");
|
|
2798
|
+
if (extraArgs.length > 0) {
|
|
2799
|
+
throw new CliError3(`Unexpected argument: ${extraArgs[0]}
|
|
2800
|
+
Run \`failproofai --help\` for usage.`);
|
|
2801
|
+
}
|
|
2802
|
+
console.log(`
|
|
2742
2803
|
failproofai v${version}
|
|
2743
2804
|
|
|
2744
2805
|
USAGE
|
|
@@ -2778,25 +2839,24 @@ LINKS
|
|
|
2778
2839
|
\u2B50 Star us: https://github.com/exospherehost/failproofai
|
|
2779
2840
|
\uD83D\uDCD6 Docs: https://befailproof.ai
|
|
2780
2841
|
`.trimStart());
|
|
2781
|
-
|
|
2782
|
-
}
|
|
2783
|
-
if (args.includes("--version") || args.includes("-v")) {
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
}
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
console.log(`
|
|
2842
|
+
process.exit(0);
|
|
2843
|
+
}
|
|
2844
|
+
if ((args.includes("--version") || args.includes("-v")) && !SUBCOMMANDS.includes(args[0])) {
|
|
2845
|
+
const extraArgs = args.filter((a) => a !== "--version" && a !== "-v");
|
|
2846
|
+
if (extraArgs.length > 0) {
|
|
2847
|
+
throw new CliError3(`Unexpected argument: ${extraArgs[0]}
|
|
2848
|
+
Run \`failproofai --help\` for usage.`);
|
|
2849
|
+
}
|
|
2850
|
+
console.log(version);
|
|
2851
|
+
process.exit(0);
|
|
2852
|
+
}
|
|
2853
|
+
if (args[0] === "policies") {
|
|
2854
|
+
const subArgs = args.slice(1);
|
|
2855
|
+
const isInstall = subArgs.includes("--install") || subArgs.includes("-i");
|
|
2856
|
+
const isUninstall = subArgs.includes("--uninstall") || subArgs.includes("-u");
|
|
2857
|
+
const isHelp = subArgs.includes("--help") || subArgs.includes("-h");
|
|
2858
|
+
if (isHelp) {
|
|
2859
|
+
console.log(`
|
|
2800
2860
|
failproofai policies \u2014 manage Failproof AI policies
|
|
2801
2861
|
|
|
2802
2862
|
USAGE
|
|
@@ -2827,65 +2887,119 @@ EXAMPLES
|
|
|
2827
2887
|
failproofai policies -u
|
|
2828
2888
|
failproofai policies --uninstall --custom
|
|
2829
2889
|
`.trimStart());
|
|
2890
|
+
process.exit(0);
|
|
2891
|
+
}
|
|
2892
|
+
if (isInstall) {
|
|
2893
|
+
const { installHooks: installHooks2 } = await Promise.resolve().then(() => (init_manager(), exports_manager));
|
|
2894
|
+
const scopeIdx = subArgs.indexOf("--scope");
|
|
2895
|
+
const scope = scopeIdx >= 0 ? subArgs[scopeIdx + 1] : "user";
|
|
2896
|
+
if (scopeIdx >= 0 && (!scope || scope.startsWith("-"))) {
|
|
2897
|
+
throw new CliError3("Missing value for --scope. Valid values: user, project, local");
|
|
2898
|
+
}
|
|
2899
|
+
if (scopeIdx >= 0 && !["user", "project", "local"].includes(scope)) {
|
|
2900
|
+
throw new CliError3(`Invalid scope: ${scope}. Valid values: user, project, local`);
|
|
2901
|
+
}
|
|
2902
|
+
const customIdx = subArgs.includes("--custom") ? subArgs.indexOf("--custom") : subArgs.includes("-c") ? subArgs.indexOf("-c") : -1;
|
|
2903
|
+
const customPoliciesPath = customIdx >= 0 ? subArgs[customIdx + 1] : undefined;
|
|
2904
|
+
if (customIdx >= 0 && (!customPoliciesPath || customPoliciesPath.startsWith("-"))) {
|
|
2905
|
+
throw new CliError3(`Missing path after --custom/-c
|
|
2906
|
+
Usage: --custom <path> (e.g. --custom ./my-policies.js)`);
|
|
2907
|
+
}
|
|
2908
|
+
const includeBeta = subArgs.includes("--beta");
|
|
2909
|
+
const consumedIdxs = new Set;
|
|
2910
|
+
if (scopeIdx >= 0)
|
|
2911
|
+
consumedIdxs.add(scopeIdx + 1);
|
|
2912
|
+
if (customIdx >= 0)
|
|
2913
|
+
consumedIdxs.add(customIdx + 1);
|
|
2914
|
+
const flags = new Set(["--install", "-i", "--scope", "--beta", "--custom", "-c"]);
|
|
2915
|
+
const unknownInstallFlag = subArgs.find((a) => a.startsWith("-") && !flags.has(a));
|
|
2916
|
+
if (unknownInstallFlag) {
|
|
2917
|
+
throw new CliError3(`Unknown flag: ${unknownInstallFlag}
|
|
2918
|
+
Run \`failproofai policies --help\` for usage.`);
|
|
2919
|
+
}
|
|
2920
|
+
const explicitPolicyNames = subArgs.filter((a, idx) => !a.startsWith("-") && !consumedIdxs.has(idx));
|
|
2921
|
+
const policyNames = explicitPolicyNames.length > 0 ? explicitPolicyNames : customPoliciesPath !== undefined ? [] : undefined;
|
|
2922
|
+
await installHooks2(policyNames, scope, undefined, includeBeta, undefined, customPoliciesPath);
|
|
2923
|
+
process.exit(0);
|
|
2924
|
+
}
|
|
2925
|
+
if (isUninstall) {
|
|
2926
|
+
const { removeHooks: removeHooks2 } = await Promise.resolve().then(() => (init_manager(), exports_manager));
|
|
2927
|
+
const scopeIdx = subArgs.indexOf("--scope");
|
|
2928
|
+
const scope = scopeIdx >= 0 ? subArgs[scopeIdx + 1] : "user";
|
|
2929
|
+
if (scopeIdx >= 0 && (!scope || scope.startsWith("-"))) {
|
|
2930
|
+
throw new CliError3("Missing value for --scope. Valid values: user, project, local, all");
|
|
2931
|
+
}
|
|
2932
|
+
if (scopeIdx >= 0 && !["user", "project", "local", "all"].includes(scope)) {
|
|
2933
|
+
throw new CliError3(`Invalid scope: ${scope}. Valid values: user, project, local, all`);
|
|
2934
|
+
}
|
|
2935
|
+
const betaOnly = subArgs.includes("--beta");
|
|
2936
|
+
const removeCustomHooks = subArgs.includes("--custom") || subArgs.includes("-c");
|
|
2937
|
+
const consumedIdxs = new Set;
|
|
2938
|
+
if (scopeIdx >= 0)
|
|
2939
|
+
consumedIdxs.add(scopeIdx + 1);
|
|
2940
|
+
const flags = new Set(["--uninstall", "-u", "--scope", "--beta", "--custom", "-c"]);
|
|
2941
|
+
const unknownUninstallFlag = subArgs.find((a) => a.startsWith("-") && !flags.has(a));
|
|
2942
|
+
if (unknownUninstallFlag) {
|
|
2943
|
+
throw new CliError3(`Unknown flag: ${unknownUninstallFlag}
|
|
2944
|
+
Run \`failproofai policies --help\` for usage.`);
|
|
2945
|
+
}
|
|
2946
|
+
const policyNames = subArgs.filter((a, idx) => !a.startsWith("-") && !consumedIdxs.has(idx));
|
|
2947
|
+
await removeHooks2(policyNames.length > 0 ? policyNames : undefined, scope, undefined, { betaOnly, removeCustomHooks });
|
|
2948
|
+
process.exit(0);
|
|
2949
|
+
}
|
|
2950
|
+
const knownListFlags = new Set(["--install", "-i", "--uninstall", "-u", "--help", "-h", "--list"]);
|
|
2951
|
+
const unknownListArg = subArgs.find((a) => a.startsWith("-") && !knownListFlags.has(a));
|
|
2952
|
+
if (unknownListArg) {
|
|
2953
|
+
throw new CliError3(`Unknown flag: ${unknownListArg}
|
|
2954
|
+
Run \`failproofai policies --help\` for usage.`);
|
|
2955
|
+
}
|
|
2956
|
+
const positionalArgs = subArgs.filter((a) => !a.startsWith("-"));
|
|
2957
|
+
if (positionalArgs.length > 0) {
|
|
2958
|
+
throw new CliError3(`Unexpected argument: ${positionalArgs[0]}
|
|
2959
|
+
Run \`failproofai policies --help\` for usage.`);
|
|
2960
|
+
}
|
|
2961
|
+
const { listHooks: listHooks2 } = await Promise.resolve().then(() => (init_manager(), exports_manager));
|
|
2962
|
+
await listHooks2();
|
|
2830
2963
|
process.exit(0);
|
|
2831
2964
|
}
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
}
|
|
2858
|
-
const {
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
}
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
const primary = ["--version", "--help", "--hook", "policies"];
|
|
2874
|
-
const closest = primary.reduce((best, flag) => {
|
|
2875
|
-
const dist = levenshtein(unknownFlag, flag);
|
|
2876
|
-
return dist < best.dist ? { flag, dist } : best;
|
|
2877
|
-
}, { flag: primary[0], dist: Infinity });
|
|
2878
|
-
console.error(`Unknown flag: ${unknownFlag}`);
|
|
2879
|
-
console.error(`Did you mean: ${closest.flag}?`);
|
|
2880
|
-
console.error(`Run \`failproofai --help\` for usage details.`);
|
|
2881
|
-
process.exit(1);
|
|
2882
|
-
}
|
|
2883
|
-
var unknownSubcommand = args.find((a) => !a.startsWith("-") && a !== "policies");
|
|
2884
|
-
if (unknownSubcommand) {
|
|
2885
|
-
console.error(`Unknown command: ${unknownSubcommand}`);
|
|
2886
|
-
console.error(`Did you mean: failproofai policies?`);
|
|
2887
|
-
console.error(`Run \`failproofai --help\` for usage details.`);
|
|
2888
|
-
process.exit(1);
|
|
2889
|
-
}
|
|
2890
|
-
var { launch: launch2 } = await Promise.resolve().then(() => (init_launch(), exports_launch));
|
|
2891
|
-
launch2("start");
|
|
2965
|
+
const knownFlags = ["--version", "-v", "--help", "-h", "--hook"];
|
|
2966
|
+
const unknownFlag = args.find((a) => a.startsWith("-") && !knownFlags.includes(a));
|
|
2967
|
+
if (unknownFlag) {
|
|
2968
|
+
let levenshtein = function(a, b) {
|
|
2969
|
+
const m = a.length, n = b.length;
|
|
2970
|
+
const dp = Array.from({ length: m + 1 }, (_, i) => Array.from({ length: n + 1 }, (_2, j) => i === 0 ? j : j === 0 ? i : 0));
|
|
2971
|
+
for (let i = 1;i <= m; i++)
|
|
2972
|
+
for (let j = 1;j <= n; j++)
|
|
2973
|
+
dp[i][j] = a[i - 1] === b[j - 1] ? dp[i - 1][j - 1] : 1 + Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]);
|
|
2974
|
+
return dp[m][n];
|
|
2975
|
+
};
|
|
2976
|
+
const primary = ["--version", "--help", "--hook", "policies"];
|
|
2977
|
+
const closest = primary.reduce((best, flag) => {
|
|
2978
|
+
const dist = levenshtein(unknownFlag, flag);
|
|
2979
|
+
return dist < best.dist ? { flag, dist } : best;
|
|
2980
|
+
}, { flag: primary[0], dist: Infinity });
|
|
2981
|
+
throw new CliError3(`Unknown flag: ${unknownFlag}
|
|
2982
|
+
Did you mean: ${closest.flag}?
|
|
2983
|
+
Run \`failproofai --help\` for usage details.`);
|
|
2984
|
+
}
|
|
2985
|
+
const unknownSubcommand = args.find((a) => !a.startsWith("-") && a !== "policies");
|
|
2986
|
+
if (unknownSubcommand) {
|
|
2987
|
+
throw new CliError3(`Unknown command: ${unknownSubcommand}
|
|
2988
|
+
Did you mean: failproofai policies?
|
|
2989
|
+
Run \`failproofai --help\` for usage details.`);
|
|
2990
|
+
}
|
|
2991
|
+
const { launch: launch2 } = await Promise.resolve().then(() => (init_launch(), exports_launch));
|
|
2992
|
+
launch2("start");
|
|
2993
|
+
}
|
|
2994
|
+
var { CliError: CliError3 } = await Promise.resolve().then(() => (init_cli_error2(), exports_cli_error));
|
|
2995
|
+
try {
|
|
2996
|
+
await runCli();
|
|
2997
|
+
} catch (err) {
|
|
2998
|
+
if (err instanceof CliError3) {
|
|
2999
|
+
console.error(`Error: ${err.message}`);
|
|
3000
|
+
process.exit(err.exitCode);
|
|
3001
|
+
}
|
|
3002
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
3003
|
+
console.error(`Unexpected error: ${msg}`);
|
|
3004
|
+
process.exit(2);
|
|
3005
|
+
}
|
package/package.json
CHANGED
|
@@ -8,6 +8,8 @@ const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
|
8
8
|
const rootPkg = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf8'));
|
|
9
9
|
const VERSION = rootPkg.version;
|
|
10
10
|
const DRY_RUN = process.argv.includes('--dry-run');
|
|
11
|
+
const distTagIdx = process.argv.indexOf('--dist-tag');
|
|
12
|
+
const DIST_TAG = distTagIdx !== -1 ? process.argv[distTagIdx + 1] : (VERSION.includes('-') ? 'beta' : 'latest');
|
|
11
13
|
|
|
12
14
|
const ALIASES = [
|
|
13
15
|
// Formatting variants — no "ai", or hyphen/underscore separators
|
|
@@ -54,7 +56,7 @@ for (const name of ALIASES) {
|
|
|
54
56
|
cpSync(join(__dirname, 'alias-proxy.js'), join(binDir, 'proxy.js'));
|
|
55
57
|
|
|
56
58
|
if (DRY_RUN) {
|
|
57
|
-
console.log(`[dry-run] Would publish ${name}@${VERSION}`);
|
|
59
|
+
console.log(`[dry-run] Would publish ${name}@${VERSION} (tag: ${DIST_TAG})`);
|
|
58
60
|
console.log(JSON.stringify(pkg, null, 2));
|
|
59
61
|
console.log('---');
|
|
60
62
|
rmSync(tmpDir, { recursive: true, force: true });
|
|
@@ -63,7 +65,7 @@ for (const name of ALIASES) {
|
|
|
63
65
|
|
|
64
66
|
console.log(`Publishing ${name}@${VERSION}...`);
|
|
65
67
|
try {
|
|
66
|
-
execSync(
|
|
68
|
+
execSync(`npm publish --tag ${DIST_TAG}`, { cwd: tmpDir, stdio: 'pipe' });
|
|
67
69
|
console.log(`Done: ${name}`);
|
|
68
70
|
} catch (err) {
|
|
69
71
|
const output = (err.stdout?.toString() ?? '') + (err.stderr?.toString() ?? '');
|
package/src/cli-error.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CliError — structured error for the failproofai CLI.
|
|
3
|
+
*
|
|
4
|
+
* Throw this for any error that should be reported to the user as a clean
|
|
5
|
+
* message (no stack trace). The exit code communicates the failure class:
|
|
6
|
+
*
|
|
7
|
+
* 1 — user error (bad args, unknown policy name, invalid flag)
|
|
8
|
+
* 2 — internal (file I/O failure, unexpected state)
|
|
9
|
+
*/
|
|
10
|
+
export class CliError extends Error {
|
|
11
|
+
readonly exitCode: 1 | 2;
|
|
12
|
+
|
|
13
|
+
constructor(message: string, exitCode: 1 | 2 = 1) {
|
|
14
|
+
super(message);
|
|
15
|
+
this.name = "CliError";
|
|
16
|
+
this.exitCode = exitCode;
|
|
17
|
+
}
|
|
18
|
+
}
|
package/src/hooks/manager.ts
CHANGED
|
@@ -21,6 +21,7 @@ import { BUILTIN_POLICIES } from "./builtin-policies";
|
|
|
21
21
|
import { loadCustomHooks } from "./custom-hooks-loader";
|
|
22
22
|
import { trackHookEvent } from "./hook-telemetry";
|
|
23
23
|
import { getInstanceId, hashToId } from "../../lib/telemetry-id";
|
|
24
|
+
import { CliError } from "../cli-error";
|
|
24
25
|
|
|
25
26
|
const VALID_POLICY_NAMES = new Set(BUILTIN_POLICIES.map((p) => p.name));
|
|
26
27
|
|
|
@@ -67,7 +68,7 @@ function resolveFailproofaiBinary(): string {
|
|
|
67
68
|
// `where` on Windows may return multiple lines; take the first
|
|
68
69
|
return result.split("\n")[0].trim();
|
|
69
70
|
} catch {
|
|
70
|
-
throw new
|
|
71
|
+
throw new CliError(
|
|
71
72
|
"failproofai binary not found in PATH.\n" +
|
|
72
73
|
"Install it globally first: npm install -g failproofai"
|
|
73
74
|
);
|
|
@@ -85,7 +86,7 @@ function validatePolicyNames(names: string[]): void {
|
|
|
85
86
|
const invalid = names.filter((n) => !VALID_POLICY_NAMES.has(n));
|
|
86
87
|
if (invalid.length > 0) {
|
|
87
88
|
const validList = [...VALID_POLICY_NAMES].join(", ");
|
|
88
|
-
throw new
|
|
89
|
+
throw new CliError(
|
|
89
90
|
`Unknown policy name(s): ${invalid.join(", ")}\n` +
|
|
90
91
|
`Valid policies: ${validList}`
|
|
91
92
|
);
|
|
@@ -185,6 +186,20 @@ export async function installHooks(
|
|
|
185
186
|
customPoliciesPath?: string,
|
|
186
187
|
removeCustomHooks = false,
|
|
187
188
|
): Promise<void> {
|
|
189
|
+
// Validate user input first before any system checks
|
|
190
|
+
if (policyNames !== undefined && policyNames.length > 0) {
|
|
191
|
+
const nonAllNames = policyNames.filter((n) => n !== "all");
|
|
192
|
+
// Check unknown names first (most actionable error for the user)
|
|
193
|
+
if (nonAllNames.length > 0) validatePolicyNames(nonAllNames);
|
|
194
|
+
// Then check if "all" is mixed with valid specific names
|
|
195
|
+
if (policyNames.includes("all") && nonAllNames.length > 0) {
|
|
196
|
+
throw new CliError(
|
|
197
|
+
`"all" cannot be combined with specific policy names.\n` +
|
|
198
|
+
`Use either: --install all or --install block-sudo sanitize-jwt ...`
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
188
203
|
const binaryPath = resolveFailproofaiBinary();
|
|
189
204
|
|
|
190
205
|
// Capture existing config before overwriting (used for telemetry diff)
|
|
@@ -201,7 +216,6 @@ export async function installHooks(
|
|
|
201
216
|
.filter((p) => includeBeta || !p.beta)
|
|
202
217
|
.map((p) => p.name);
|
|
203
218
|
} else {
|
|
204
|
-
if (policyNames.length > 0) validatePolicyNames(policyNames);
|
|
205
219
|
incoming = policyNames;
|
|
206
220
|
}
|
|
207
221
|
// Additive: union with whatever was already enabled, deduplicated.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|