diff --git a/bin/failproofai.mjs b/bin/failproofai.mjs old mode 100644 new mode 100755 index e6f4d0e7..9295f2cc --- a/bin/failproofai.mjs +++ b/bin/failproofai.mjs @@ -89,6 +89,37 @@ if (args.includes("--list-policies")) { process.exit(0); } +// Unknown flag guard — must appear after all known-flag branches +const knownFlags = ["--version", "-v", "--hook", "--install-policies", + "--remove-policies", "--list-policies"]; +const unknownFlag = args.find(a => a.startsWith("-") && !knownFlags.includes(a)); + +if (unknownFlag) { + function levenshtein(a, b) { + const m = a.length, n = b.length; + const dp = Array.from({ length: m + 1 }, (_, i) => + Array.from({ length: n + 1 }, (_, j) => (i === 0 ? j : j === 0 ? i : 0)) + ); + for (let i = 1; i <= m; i++) + for (let j = 1; j <= n; j++) + 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]); + return dp[m][n]; + } + + const primary = ["--version", "--hook", "--install-policies", + "--remove-policies", "--list-policies"]; + const closest = primary.reduce((best, flag) => { + const dist = levenshtein(unknownFlag, flag); + return dist < best.dist ? { flag, dist } : best; + }, { flag: primary[0], dist: Infinity }); + + console.error(`Unknown flag: ${unknownFlag}`); + console.error(`Did you mean: ${closest.flag}?`); + process.exit(1); +} + // Dashboard launch — always production mode const { launch } = await import("../scripts/launch"); launch("start"); diff --git a/package.json b/package.json index 40023c3b..1893526a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "failproofai", - "version": "0.0.1-beta.1", + "version": "0.0.1-beta.2", "description": "Open-source hooks, policies, and project visualization for Claude Code & Agents SDK", "bin": { "failproofai": "./bin/failproofai.mjs"