failproofai 0.0.1 → 0.0.2-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/build-manifest.json +3 -3
- package/.next/standalone/.next/prerender-manifest.json +3 -3
- package/.next/standalone/.next/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]__0jvf9jj._.js → [root-of-the-server]__0103jwf._.js} +2 -2
- 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]__09z7o2x._.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]__0~7bzp~._.js → [root-of-the-server]__0ovwjau._.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]__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/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/{0eh2hq9~6bf53.js → 001k0zayn2o.s.js} +1 -1
- package/.next/standalone/.next/static/chunks/{056c865hodfe7.js → 0jrzwsyo7wo26.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0wmsi.tszy~9y.js → 0pdd7~yp8ytu6.js} +1 -1
- package/.next/standalone/.next/static/chunks/{15lp0u9f5fwae.js → 0sm1iqi3m~xiz.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0o04-obbhh9.s.js → 0tbr0o7vwc~-s.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0nwr.y4dwla00.js → 0tl2f-3yc.rqc.js} +1 -1
- package/.next/standalone/.next/static/chunks/{066e8ajzl234v.js → 0uftmw5od9kdz.js} +1 -1
- package/.next/standalone/.next/static/chunks/{17q_c2.bbcoh1.js → 0wtcha31~i7rm.js} +1 -1
- package/.next/standalone/README.md +18 -10
- package/.next/standalone/bin/failproofai.mjs +221 -128
- package/.next/standalone/dist/cli.mjs +3005 -0
- package/.next/standalone/docs/architecture.md +5 -1
- package/.next/standalone/docs/built-in-policies.md +5 -1
- package/.next/standalone/docs/cli-reference.md +5 -1
- package/.next/standalone/docs/configuration.md +5 -1
- package/.next/standalone/docs/custom-hooks.md +5 -1
- package/.next/standalone/docs/dashboard.md +5 -1
- package/.next/standalone/docs/docs.json +83 -0
- package/.next/standalone/docs/favicon.ico +0 -0
- package/.next/standalone/docs/getting-started.md +8 -2
- package/.next/standalone/docs/introduction.md +47 -0
- package/.next/standalone/docs/logo/exosphere-dark.png +0 -0
- package/.next/standalone/docs/logo/exosphere-light.png +0 -0
- package/.next/standalone/docs/package-aliases.md +7 -1
- package/.next/standalone/docs/testing.md +5 -1
- package/.next/standalone/package.json +6 -5
- package/.next/standalone/scripts/launch.ts +1 -1
- package/.next/standalone/scripts/postinstall.mjs +11 -0
- package/.next/standalone/src/cli-error.ts +18 -0
- package/.next/standalone/src/hooks/manager.ts +17 -3
- package/README.md +18 -10
- package/bin/failproofai.mjs +221 -128
- package/dist/cli.mjs +3005 -0
- package/package.json +6 -5
- package/scripts/launch.ts +1 -1
- package/scripts/postinstall.mjs +11 -0
- package/src/cli-error.ts +18 -0
- package/src/hooks/manager.ts +17 -3
- package/.next/standalone/docs/index.md +0 -48
- /package/.next/standalone/.next/static/{odPaRK23IkTvoPxqrn_8P → JksWDLwDoPy6bcczVWlff}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{odPaRK23IkTvoPxqrn_8P → JksWDLwDoPy6bcczVWlff}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{odPaRK23IkTvoPxqrn_8P → JksWDLwDoPy6bcczVWlff}/_ssgManifest.js +0 -0
package/bin/failproofai.mjs
CHANGED
|
@@ -37,10 +37,40 @@ const args = process.argv.slice(2);
|
|
|
37
37
|
// Normalize 'p' → 'policies' (shorthand alias)
|
|
38
38
|
if (args[0] === "p") args[0] = "policies";
|
|
39
39
|
|
|
40
|
-
// --
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
40
|
+
// --hook <event> — called by Claude Code hooks; fast path, outside runCli()
|
|
41
|
+
// because it has its own exit code contract with Claude Code.
|
|
42
|
+
const hookIdx = args.indexOf("--hook");
|
|
43
|
+
if (hookIdx >= 0) {
|
|
44
|
+
if (!args[hookIdx + 1]) {
|
|
45
|
+
console.error("Error: Missing event type after --hook");
|
|
46
|
+
console.error("Usage: failproofai --hook <event> (e.g. PreToolUse, PostToolUse)");
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
try {
|
|
50
|
+
const { handleHookEvent } = await import("../src/hooks/handler");
|
|
51
|
+
const exitCode = await handleHookEvent(args[hookIdx + 1]);
|
|
52
|
+
process.exit(exitCode);
|
|
53
|
+
} catch (err) {
|
|
54
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
55
|
+
console.error(`Unexpected error: ${msg}`);
|
|
56
|
+
process.exit(2);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Centralised error handler for all CLI subcommands.
|
|
62
|
+
* CliError → clean message, no stack trace, exit exitCode (1 or 2)
|
|
63
|
+
* Error → unexpected; shows message only, exits 2
|
|
64
|
+
*/
|
|
65
|
+
async function runCli() {
|
|
66
|
+
// --help / -h (only when not inside a subcommand that handles its own --help)
|
|
67
|
+
const SUBCOMMANDS = ["policies"];
|
|
68
|
+
if ((args.includes("--help") || args.includes("-h")) && !SUBCOMMANDS.includes(args[0])) {
|
|
69
|
+
const extraArgs = args.filter((a) => a !== "--help" && a !== "-h");
|
|
70
|
+
if (extraArgs.length > 0) {
|
|
71
|
+
throw new CliError(`Unexpected argument: ${extraArgs[0]}\nRun \`failproofai --help\` for usage.`);
|
|
72
|
+
}
|
|
73
|
+
console.log(`
|
|
44
74
|
failproofai v${version}
|
|
45
75
|
|
|
46
76
|
USAGE
|
|
@@ -80,33 +110,29 @@ LINKS
|
|
|
80
110
|
⭐ Star us: https://github.com/exospherehost/failproofai
|
|
81
111
|
📖 Docs: https://befailproof.ai
|
|
82
112
|
`.trimStart());
|
|
83
|
-
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// --version / -v
|
|
87
|
-
if (args.includes("--version") || args.includes("-v")) {
|
|
88
|
-
console.log(version);
|
|
89
|
-
process.exit(0);
|
|
90
|
-
}
|
|
113
|
+
process.exit(0);
|
|
114
|
+
}
|
|
91
115
|
|
|
92
|
-
// --
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
116
|
+
// --version / -v
|
|
117
|
+
if ((args.includes("--version") || args.includes("-v")) && !SUBCOMMANDS.includes(args[0])) {
|
|
118
|
+
const extraArgs = args.filter((a) => a !== "--version" && a !== "-v");
|
|
119
|
+
if (extraArgs.length > 0) {
|
|
120
|
+
throw new CliError(`Unexpected argument: ${extraArgs[0]}\nRun \`failproofai --help\` for usage.`);
|
|
121
|
+
}
|
|
122
|
+
console.log(version);
|
|
123
|
+
process.exit(0);
|
|
124
|
+
}
|
|
99
125
|
|
|
100
|
-
// policies [--install|-i|--uninstall|-u|--help|-h] [names...] [--scope] [--beta] [--custom|-c <path>]
|
|
101
|
-
if (args[0] === "policies") {
|
|
102
|
-
|
|
126
|
+
// policies [--install|-i|--uninstall|-u|--help|-h] [names...] [--scope] [--beta] [--custom|-c <path>]
|
|
127
|
+
if (args[0] === "policies") {
|
|
128
|
+
const subArgs = args.slice(1);
|
|
103
129
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
130
|
+
const isInstall = subArgs.includes("--install") || subArgs.includes("-i");
|
|
131
|
+
const isUninstall = subArgs.includes("--uninstall") || subArgs.includes("-u");
|
|
132
|
+
const isHelp = subArgs.includes("--help") || subArgs.includes("-h");
|
|
107
133
|
|
|
108
|
-
|
|
109
|
-
|
|
134
|
+
if (isHelp) {
|
|
135
|
+
console.log(`
|
|
110
136
|
failproofai policies — manage Failproof AI policies
|
|
111
137
|
|
|
112
138
|
USAGE
|
|
@@ -137,118 +163,185 @@ EXAMPLES
|
|
|
137
163
|
failproofai policies -u
|
|
138
164
|
failproofai policies --uninstall --custom
|
|
139
165
|
`.trimStart());
|
|
166
|
+
process.exit(0);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (isInstall) {
|
|
170
|
+
const { installHooks } = await import("../src/hooks/manager");
|
|
171
|
+
|
|
172
|
+
const scopeIdx = subArgs.indexOf("--scope");
|
|
173
|
+
const scope = scopeIdx >= 0 ? subArgs[scopeIdx + 1] : "user";
|
|
174
|
+
if (scopeIdx >= 0 && (!scope || scope.startsWith("-"))) {
|
|
175
|
+
throw new CliError("Missing value for --scope. Valid values: user, project, local");
|
|
176
|
+
}
|
|
177
|
+
if (scopeIdx >= 0 && !["user", "project", "local"].includes(scope)) {
|
|
178
|
+
throw new CliError(`Invalid scope: ${scope}. Valid values: user, project, local`);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const customIdx = subArgs.includes("--custom") ? subArgs.indexOf("--custom")
|
|
182
|
+
: subArgs.includes("-c") ? subArgs.indexOf("-c")
|
|
183
|
+
: -1;
|
|
184
|
+
const customPoliciesPath = customIdx >= 0 ? subArgs[customIdx + 1] : undefined;
|
|
185
|
+
if (customIdx >= 0 && (!customPoliciesPath || customPoliciesPath.startsWith("-"))) {
|
|
186
|
+
throw new CliError("Missing path after --custom/-c\nUsage: --custom <path> (e.g. --custom ./my-policies.js)");
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const includeBeta = subArgs.includes("--beta");
|
|
190
|
+
|
|
191
|
+
// Collect positional policy names — args that don't start with - and aren't
|
|
192
|
+
// values consumed by --scope or --custom/-c (tracked by index, not value,
|
|
193
|
+
// so a policy named "user" isn't incorrectly dropped by the default scope).
|
|
194
|
+
const consumedIdxs = new Set();
|
|
195
|
+
if (scopeIdx >= 0) consumedIdxs.add(scopeIdx + 1);
|
|
196
|
+
if (customIdx >= 0) consumedIdxs.add(customIdx + 1);
|
|
197
|
+
const flags = new Set(["--install", "-i", "--scope", "--beta", "--custom", "-c"]);
|
|
198
|
+
const unknownInstallFlag = subArgs.find((a) => a.startsWith("-") && !flags.has(a));
|
|
199
|
+
if (unknownInstallFlag) {
|
|
200
|
+
throw new CliError(`Unknown flag: ${unknownInstallFlag}\nRun \`failproofai policies --help\` for usage.`);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const explicitPolicyNames = subArgs.filter(
|
|
204
|
+
(a, idx) => !a.startsWith("-") && !consumedIdxs.has(idx)
|
|
205
|
+
);
|
|
206
|
+
|
|
207
|
+
// When --custom/-c is present but no explicit policy names, pass [] so
|
|
208
|
+
// installHooks uses the existing enabled policies and skips the interactive
|
|
209
|
+
// prompt — validation of the custom file happens inside installHooks.
|
|
210
|
+
const policyNames =
|
|
211
|
+
explicitPolicyNames.length > 0 ? explicitPolicyNames
|
|
212
|
+
: customPoliciesPath !== undefined ? []
|
|
213
|
+
: undefined;
|
|
214
|
+
|
|
215
|
+
await installHooks(
|
|
216
|
+
policyNames,
|
|
217
|
+
scope,
|
|
218
|
+
undefined,
|
|
219
|
+
includeBeta,
|
|
220
|
+
undefined,
|
|
221
|
+
customPoliciesPath,
|
|
222
|
+
);
|
|
223
|
+
process.exit(0);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if (isUninstall) {
|
|
227
|
+
const { removeHooks } = await import("../src/hooks/manager");
|
|
228
|
+
|
|
229
|
+
const scopeIdx = subArgs.indexOf("--scope");
|
|
230
|
+
const scope = scopeIdx >= 0 ? subArgs[scopeIdx + 1] : "user";
|
|
231
|
+
if (scopeIdx >= 0 && (!scope || scope.startsWith("-"))) {
|
|
232
|
+
throw new CliError("Missing value for --scope. Valid values: user, project, local, all");
|
|
233
|
+
}
|
|
234
|
+
if (scopeIdx >= 0 && !["user", "project", "local", "all"].includes(scope)) {
|
|
235
|
+
throw new CliError(`Invalid scope: ${scope}. Valid values: user, project, local, all`);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const betaOnly = subArgs.includes("--beta");
|
|
239
|
+
const removeCustomHooks = subArgs.includes("--custom") || subArgs.includes("-c");
|
|
240
|
+
|
|
241
|
+
const consumedIdxs = new Set();
|
|
242
|
+
if (scopeIdx >= 0) consumedIdxs.add(scopeIdx + 1);
|
|
243
|
+
const flags = new Set(["--uninstall", "-u", "--scope", "--beta", "--custom", "-c"]);
|
|
244
|
+
const unknownUninstallFlag = subArgs.find((a) => a.startsWith("-") && !flags.has(a));
|
|
245
|
+
if (unknownUninstallFlag) {
|
|
246
|
+
throw new CliError(`Unknown flag: ${unknownUninstallFlag}\nRun \`failproofai policies --help\` for usage.`);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const policyNames = subArgs.filter(
|
|
250
|
+
(a, idx) => !a.startsWith("-") && !consumedIdxs.has(idx)
|
|
251
|
+
);
|
|
252
|
+
|
|
253
|
+
await removeHooks(
|
|
254
|
+
policyNames.length > 0 ? policyNames : undefined,
|
|
255
|
+
scope,
|
|
256
|
+
undefined,
|
|
257
|
+
{ betaOnly, removeCustomHooks },
|
|
258
|
+
);
|
|
259
|
+
process.exit(0);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Default: list policies
|
|
263
|
+
// Accept --list as a no-op alias (common intuition), reject all other unknown flags
|
|
264
|
+
// and unexpected positional args (e.g. "hi").
|
|
265
|
+
const knownListFlags = new Set(["--install", "-i", "--uninstall", "-u", "--help", "-h", "--list"]);
|
|
266
|
+
const unknownListArg = subArgs.find((a) => a.startsWith("-") && !knownListFlags.has(a));
|
|
267
|
+
if (unknownListArg) {
|
|
268
|
+
throw new CliError(
|
|
269
|
+
`Unknown flag: ${unknownListArg}\n` +
|
|
270
|
+
`Run \`failproofai policies --help\` for usage.`
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
const positionalArgs = subArgs.filter((a) => !a.startsWith("-"));
|
|
274
|
+
if (positionalArgs.length > 0) {
|
|
275
|
+
throw new CliError(
|
|
276
|
+
`Unexpected argument: ${positionalArgs[0]}\n` +
|
|
277
|
+
`Run \`failproofai policies --help\` for usage.`
|
|
278
|
+
);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const { listHooks } = await import("../src/hooks/manager");
|
|
282
|
+
await listHooks();
|
|
140
283
|
process.exit(0);
|
|
141
284
|
}
|
|
142
285
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
)
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
await installHooks(
|
|
173
|
-
policyNames,
|
|
174
|
-
scope,
|
|
175
|
-
undefined,
|
|
176
|
-
includeBeta,
|
|
177
|
-
undefined,
|
|
178
|
-
customPoliciesPath,
|
|
286
|
+
// Unknown flag guard — must appear after all known-flag branches
|
|
287
|
+
const knownFlags = ["--version", "-v", "--help", "-h", "--hook"];
|
|
288
|
+
const unknownFlag = args.find(a => a.startsWith("-") && !knownFlags.includes(a));
|
|
289
|
+
|
|
290
|
+
if (unknownFlag) {
|
|
291
|
+
function levenshtein(a, b) {
|
|
292
|
+
const m = a.length, n = b.length;
|
|
293
|
+
const dp = Array.from({ length: m + 1 }, (_, i) =>
|
|
294
|
+
Array.from({ length: n + 1 }, (_, j) => (i === 0 ? j : j === 0 ? i : 0))
|
|
295
|
+
);
|
|
296
|
+
for (let i = 1; i <= m; i++)
|
|
297
|
+
for (let j = 1; j <= n; j++)
|
|
298
|
+
dp[i][j] = a[i - 1] === b[j - 1]
|
|
299
|
+
? dp[i - 1][j - 1]
|
|
300
|
+
: 1 + Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]);
|
|
301
|
+
return dp[m][n];
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
const primary = ["--version", "--help", "--hook", "policies"];
|
|
305
|
+
const closest = primary.reduce((best, flag) => {
|
|
306
|
+
const dist = levenshtein(unknownFlag, flag);
|
|
307
|
+
return dist < best.dist ? { flag, dist } : best;
|
|
308
|
+
}, { flag: primary[0], dist: Infinity });
|
|
309
|
+
|
|
310
|
+
throw new CliError(
|
|
311
|
+
`Unknown flag: ${unknownFlag}\n` +
|
|
312
|
+
`Did you mean: ${closest.flag}?\n` +
|
|
313
|
+
`Run \`failproofai --help\` for usage details.`
|
|
179
314
|
);
|
|
180
|
-
process.exit(0);
|
|
181
315
|
}
|
|
182
316
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
const removeCustomHooks = subArgs.includes("--custom") || subArgs.includes("-c");
|
|
191
|
-
|
|
192
|
-
const consumed = new Set([scope].filter(Boolean));
|
|
193
|
-
const flags = new Set(["--uninstall", "-u", "--scope", "--beta", "--custom", "-c"]);
|
|
194
|
-
const policyNames = subArgs.filter(
|
|
195
|
-
(a) => !a.startsWith("-") && !flags.has(a) && !consumed.has(a)
|
|
317
|
+
// Unknown subcommand guard (non-flag args that aren't "policies")
|
|
318
|
+
const unknownSubcommand = args.find(a => !a.startsWith("-") && a !== "policies");
|
|
319
|
+
if (unknownSubcommand) {
|
|
320
|
+
throw new CliError(
|
|
321
|
+
`Unknown command: ${unknownSubcommand}\n` +
|
|
322
|
+
`Did you mean: failproofai policies?\n` +
|
|
323
|
+
`Run \`failproofai --help\` for usage details.`
|
|
196
324
|
);
|
|
197
|
-
|
|
198
|
-
await removeHooks(
|
|
199
|
-
policyNames.length > 0 ? policyNames : undefined,
|
|
200
|
-
scope,
|
|
201
|
-
undefined,
|
|
202
|
-
{ betaOnly, removeCustomHooks },
|
|
203
|
-
);
|
|
204
|
-
process.exit(0);
|
|
205
325
|
}
|
|
206
326
|
|
|
207
|
-
//
|
|
208
|
-
const {
|
|
209
|
-
|
|
210
|
-
process.exit(0);
|
|
327
|
+
// Dashboard launch — always production mode
|
|
328
|
+
const { launch } = await import("../scripts/launch");
|
|
329
|
+
launch("start");
|
|
211
330
|
}
|
|
212
331
|
|
|
213
|
-
//
|
|
214
|
-
const
|
|
215
|
-
const unknownFlag = args.find(a => a.startsWith("-") && !knownFlags.includes(a));
|
|
332
|
+
// ── Import CliError for use in the guard above ────────────────────────────────
|
|
333
|
+
const { CliError } = await import("../src/cli-error");
|
|
216
334
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
);
|
|
223
|
-
|
|
224
|
-
for (let j = 1; j <= n; j++)
|
|
225
|
-
dp[i][j] = a[i - 1] === b[j - 1]
|
|
226
|
-
? dp[i - 1][j - 1]
|
|
227
|
-
: 1 + Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]);
|
|
228
|
-
return dp[m][n];
|
|
335
|
+
// ── Run ───────────────────────────────────────────────────────────────────────
|
|
336
|
+
try {
|
|
337
|
+
await runCli();
|
|
338
|
+
} catch (err) {
|
|
339
|
+
if (err instanceof CliError) {
|
|
340
|
+
console.error(`Error: ${err.message}`);
|
|
341
|
+
process.exit(err.exitCode);
|
|
229
342
|
}
|
|
230
|
-
|
|
231
|
-
const
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
return dist < best.dist ? { flag, dist } : best;
|
|
235
|
-
}, { flag: primary[0], dist: Infinity });
|
|
236
|
-
|
|
237
|
-
console.error(`Unknown flag: ${unknownFlag}`);
|
|
238
|
-
console.error(`Did you mean: ${closest.flag}?`);
|
|
239
|
-
console.error(`Run \`failproofai --help\` for usage details.`);
|
|
240
|
-
process.exit(1);
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
// Unknown subcommand guard (non-flag args that aren't "policies")
|
|
244
|
-
const unknownSubcommand = args.find(a => !a.startsWith("-") && a !== "policies");
|
|
245
|
-
if (unknownSubcommand) {
|
|
246
|
-
console.error(`Unknown command: ${unknownSubcommand}`);
|
|
247
|
-
console.error(`Did you mean: failproofai policies?`);
|
|
248
|
-
console.error(`Run \`failproofai --help\` for usage details.`);
|
|
249
|
-
process.exit(1);
|
|
343
|
+
// Unexpected internal error — show message only, no stack trace
|
|
344
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
345
|
+
console.error(`Unexpected error: ${msg}`);
|
|
346
|
+
process.exit(2);
|
|
250
347
|
}
|
|
251
|
-
|
|
252
|
-
// Dashboard launch — always production mode
|
|
253
|
-
const { launch } = await import("../scripts/launch");
|
|
254
|
-
launch("start");
|