viberails 0.5.2 → 0.5.4
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/dist/index.cjs +66 -37
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +66 -37
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
package/dist/index.cjs
CHANGED
|
@@ -66,7 +66,7 @@ var clack5 = __toESM(require("@clack/prompts"), 1);
|
|
|
66
66
|
// src/utils/prompt-integrations.ts
|
|
67
67
|
var import_node_child_process = require("child_process");
|
|
68
68
|
var clack = __toESM(require("@clack/prompts"), 1);
|
|
69
|
-
async function promptHookManagerInstall(projectRoot, packageManager) {
|
|
69
|
+
async function promptHookManagerInstall(projectRoot, packageManager, isWorkspace) {
|
|
70
70
|
const choice = await clack.select({
|
|
71
71
|
message: "No git hook manager detected. Install Lefthook for shareable pre-commit hooks?",
|
|
72
72
|
options: [
|
|
@@ -85,7 +85,7 @@ async function promptHookManagerInstall(projectRoot, packageManager) {
|
|
|
85
85
|
assertNotCancelled(choice);
|
|
86
86
|
if (choice !== "install") return void 0;
|
|
87
87
|
const pm = packageManager || "npm";
|
|
88
|
-
const installCmd = pm === "yarn" ? "yarn add -D lefthook" : pm === "pnpm" ?
|
|
88
|
+
const installCmd = pm === "yarn" ? "yarn add -D lefthook" : pm === "pnpm" ? `pnpm add -D${isWorkspace ? " -w" : ""} lefthook` : "npm install -D lefthook";
|
|
89
89
|
const s = clack.spinner();
|
|
90
90
|
s.start("Installing Lefthook...");
|
|
91
91
|
const result = (0, import_node_child_process.spawnSync)(installCmd, {
|
|
@@ -113,7 +113,8 @@ async function promptIntegrations(projectRoot, hookManager, tools) {
|
|
|
113
113
|
if (!resolvedHookManager) {
|
|
114
114
|
resolvedHookManager = await promptHookManagerInstall(
|
|
115
115
|
projectRoot,
|
|
116
|
-
tools?.packageManager ?? "npm"
|
|
116
|
+
tools?.packageManager ?? "npm",
|
|
117
|
+
tools?.isWorkspace
|
|
117
118
|
);
|
|
118
119
|
}
|
|
119
120
|
const isBareHook = !resolvedHookManager;
|
|
@@ -1683,13 +1684,15 @@ function displayInitSummary(config, exemptedPackages) {
|
|
|
1683
1684
|
console.log("");
|
|
1684
1685
|
console.log(` ${import_chalk4.default.bold("Rules to apply:")}`);
|
|
1685
1686
|
console.log(` ${ok} Max file size: ${import_chalk4.default.cyan(`${config.rules.maxFileLines} lines`)}`);
|
|
1686
|
-
|
|
1687
|
-
|
|
1687
|
+
const fileNaming = root?.conventions?.fileNaming ?? config.packages.find((p) => p.conventions?.fileNaming)?.conventions?.fileNaming;
|
|
1688
|
+
if (config.rules.enforceNaming && fileNaming) {
|
|
1689
|
+
console.log(` ${ok} File naming: ${import_chalk4.default.cyan(fileNaming)}`);
|
|
1688
1690
|
} else {
|
|
1689
1691
|
console.log(` ${off} File naming: ${import_chalk4.default.dim("not enforced")}`);
|
|
1690
1692
|
}
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
+
const testPattern = root?.structure?.testPattern ?? config.packages.find((p) => p.structure?.testPattern)?.structure?.testPattern;
|
|
1694
|
+
if (config.rules.enforceMissingTests && testPattern) {
|
|
1695
|
+
console.log(` ${ok} Missing tests: ${import_chalk4.default.cyan(`enforced (${testPattern})`)}`);
|
|
1693
1696
|
} else if (config.rules.enforceMissingTests) {
|
|
1694
1697
|
console.log(` ${ok} Missing tests: ${import_chalk4.default.cyan("enforced")}`);
|
|
1695
1698
|
} else {
|
|
@@ -2487,30 +2490,36 @@ var path14 = __toESM(require("path"), 1);
|
|
|
2487
2490
|
var clack7 = __toESM(require("@clack/prompts"), 1);
|
|
2488
2491
|
var import_chalk8 = __toESM(require("chalk"), 1);
|
|
2489
2492
|
function checkCoveragePrereqs(projectRoot, scanResult) {
|
|
2490
|
-
const testRunner = scanResult.stack.testRunner;
|
|
2491
|
-
if (!testRunner) return [];
|
|
2492
|
-
const runner = testRunner.name;
|
|
2493
2493
|
const pm = scanResult.stack.packageManager.name;
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
installCommand: installed ? void 0 : `${addCmd} @vitest/coverage-v8`,
|
|
2504
|
-
reason: "Required for coverage percentage checks with vitest"
|
|
2505
|
-
}
|
|
2506
|
-
];
|
|
2494
|
+
const vitestPackages = scanResult.packages.filter((pkg) => pkg.stack.testRunner?.name === "vitest").map((pkg) => pkg.relativePath);
|
|
2495
|
+
const hasVitest = vitestPackages.length > 0 || scanResult.stack.testRunner?.name === "vitest";
|
|
2496
|
+
if (!hasVitest) return [];
|
|
2497
|
+
let installed = hasDependency(projectRoot, "@vitest/coverage-v8") || hasDependency(projectRoot, "@vitest/coverage-istanbul");
|
|
2498
|
+
if (!installed && vitestPackages.length > 0) {
|
|
2499
|
+
installed = vitestPackages.every((rel) => {
|
|
2500
|
+
const pkgDir = path14.join(projectRoot, rel);
|
|
2501
|
+
return hasDependency(pkgDir, "@vitest/coverage-v8") || hasDependency(pkgDir, "@vitest/coverage-istanbul");
|
|
2502
|
+
});
|
|
2507
2503
|
}
|
|
2508
|
-
|
|
2504
|
+
const isWorkspace = scanResult.packages.length > 1;
|
|
2505
|
+
const addCmd = pm === "yarn" ? "yarn add -D" : pm === "pnpm" && isWorkspace ? "pnpm add -D -w" : pm === "npm" ? "npm install -D" : `${pm} add -D`;
|
|
2506
|
+
const affectedPackages = vitestPackages.length > 1 ? vitestPackages : void 0;
|
|
2507
|
+
const reason = affectedPackages ? `Required for coverage in: ${affectedPackages.join(", ")}` : "Required for coverage percentage checks with vitest";
|
|
2508
|
+
return [
|
|
2509
|
+
{
|
|
2510
|
+
label: "@vitest/coverage-v8",
|
|
2511
|
+
installed,
|
|
2512
|
+
installCommand: installed ? void 0 : `${addCmd} @vitest/coverage-v8`,
|
|
2513
|
+
reason,
|
|
2514
|
+
affectedPackages
|
|
2515
|
+
}
|
|
2516
|
+
];
|
|
2509
2517
|
}
|
|
2510
2518
|
function displayMissingPrereqs(prereqs) {
|
|
2511
2519
|
const missing = prereqs.filter((p) => !p.installed);
|
|
2512
2520
|
for (const m of missing) {
|
|
2513
|
-
|
|
2521
|
+
const suffix = m.affectedPackages ? ` \u2014 needed for coverage in: ${m.affectedPackages.join(", ")}` : ` \u2014 ${m.reason}`;
|
|
2522
|
+
console.log(` ${import_chalk8.default.yellow("!")} ${m.label} not installed${suffix}`);
|
|
2514
2523
|
if (m.installCommand) {
|
|
2515
2524
|
console.log(` Install: ${import_chalk8.default.cyan(m.installCommand)}`);
|
|
2516
2525
|
}
|
|
@@ -2519,15 +2528,19 @@ function displayMissingPrereqs(prereqs) {
|
|
|
2519
2528
|
async function promptMissingPrereqs(projectRoot, prereqs) {
|
|
2520
2529
|
const missing = prereqs.filter((p) => !p.installed);
|
|
2521
2530
|
if (missing.length === 0) return { disableCoverage: false };
|
|
2522
|
-
const prereqLines = prereqs.map(
|
|
2523
|
-
(p
|
|
2524
|
-
|
|
2531
|
+
const prereqLines = prereqs.map((p) => {
|
|
2532
|
+
if (p.installed) return `\u2713 ${p.label}`;
|
|
2533
|
+
const detail = p.affectedPackages ? `needed by: ${p.affectedPackages.join(", ")}` : p.reason;
|
|
2534
|
+
return `\u2717 ${p.label} \u2014 ${detail}`;
|
|
2535
|
+
}).join("\n");
|
|
2525
2536
|
clack7.note(prereqLines, "Coverage prerequisites");
|
|
2526
2537
|
let disableCoverage = false;
|
|
2527
2538
|
for (const m of missing) {
|
|
2528
2539
|
if (!m.installCommand) continue;
|
|
2540
|
+
const pkgCount = m.affectedPackages?.length;
|
|
2541
|
+
const message = pkgCount ? `${m.label} is not installed. Required for coverage in ${pkgCount} packages using vitest.` : `${m.label} is not installed. It is required for coverage percentage checks.`;
|
|
2529
2542
|
const choice = await clack7.select({
|
|
2530
|
-
message
|
|
2543
|
+
message,
|
|
2531
2544
|
options: [
|
|
2532
2545
|
{
|
|
2533
2546
|
value: "install",
|
|
@@ -2690,7 +2703,6 @@ function addLefthookPreCommit(lefthookPath) {
|
|
|
2690
2703
|
function detectHookManager(projectRoot) {
|
|
2691
2704
|
if (fs16.existsSync(path16.join(projectRoot, "lefthook.yml"))) return "Lefthook";
|
|
2692
2705
|
if (fs16.existsSync(path16.join(projectRoot, ".husky"))) return "Husky";
|
|
2693
|
-
if (fs16.existsSync(path16.join(projectRoot, ".git"))) return "git hook";
|
|
2694
2706
|
return void 0;
|
|
2695
2707
|
}
|
|
2696
2708
|
function setupClaudeCodeHook(projectRoot) {
|
|
@@ -2744,7 +2756,7 @@ function setupClaudeMdReference(projectRoot) {
|
|
|
2744
2756
|
fs16.writeFileSync(claudeMdPath, prefix + ref);
|
|
2745
2757
|
console.log(` ${import_chalk9.default.green("\u2713")} CLAUDE.md \u2014 added @.viberails/context.md reference`);
|
|
2746
2758
|
}
|
|
2747
|
-
function setupGithubAction(projectRoot, packageManager) {
|
|
2759
|
+
function setupGithubAction(projectRoot, packageManager, options) {
|
|
2748
2760
|
const workflowDir = path16.join(projectRoot, ".github", "workflows");
|
|
2749
2761
|
const workflowPath = path16.join(workflowDir, "viberails.yml");
|
|
2750
2762
|
if (fs16.existsSync(workflowPath)) {
|
|
@@ -2780,7 +2792,16 @@ function setupGithubAction(projectRoot, packageManager) {
|
|
|
2780
2792
|
" node-version: 22",
|
|
2781
2793
|
pm !== "npm" ? ` cache: ${pm}` : "",
|
|
2782
2794
|
"",
|
|
2783
|
-
` - run: ${installCmd}
|
|
2795
|
+
` - run: ${installCmd}`
|
|
2796
|
+
);
|
|
2797
|
+
if (options?.typecheck) {
|
|
2798
|
+
lines.push(` - run: ${runPrefix} tsc --noEmit`);
|
|
2799
|
+
}
|
|
2800
|
+
if (options?.linter) {
|
|
2801
|
+
const lintCmd = options.linter === "biome" ? "biome check ." : "eslint .";
|
|
2802
|
+
lines.push(` - run: ${runPrefix} ${lintCmd}`);
|
|
2803
|
+
}
|
|
2804
|
+
lines.push(
|
|
2784
2805
|
` - run: ${runPrefix} viberails check --enforce --diff-base origin/\${{ github.event.pull_request.base.ref }}`,
|
|
2785
2806
|
""
|
|
2786
2807
|
);
|
|
@@ -2901,7 +2922,10 @@ function setupSelectedIntegrations(projectRoot, integrations, opts) {
|
|
|
2901
2922
|
created.push("CLAUDE.md \u2014 added @.viberails/context.md reference");
|
|
2902
2923
|
}
|
|
2903
2924
|
if (integrations.githubAction) {
|
|
2904
|
-
const t = setupGithubAction(projectRoot, opts.packageManager ?? "npm"
|
|
2925
|
+
const t = setupGithubAction(projectRoot, opts.packageManager ?? "npm", {
|
|
2926
|
+
linter: integrations.lintHook ? opts.linter : void 0,
|
|
2927
|
+
typecheck: integrations.typecheckHook
|
|
2928
|
+
});
|
|
2905
2929
|
if (t) created.push(`${t} \u2014 blocks PRs on violations`);
|
|
2906
2930
|
}
|
|
2907
2931
|
return created;
|
|
@@ -2969,11 +2993,15 @@ async function initNonInteractive(projectRoot, configPath) {
|
|
|
2969
2993
|
setupClaudeMdReference(projectRoot);
|
|
2970
2994
|
const rootPkg = config.packages[0];
|
|
2971
2995
|
const rootPkgPm = rootPkg?.stack?.packageManager ?? "npm";
|
|
2972
|
-
const
|
|
2996
|
+
const linter = rootPkg?.stack?.linter?.split("@")[0];
|
|
2997
|
+
const isTypeScript = rootPkg?.stack?.language === "typescript";
|
|
2998
|
+
const actionTarget = setupGithubAction(projectRoot, rootPkgPm, {
|
|
2999
|
+
linter,
|
|
3000
|
+
typecheck: isTypeScript
|
|
3001
|
+
});
|
|
2973
3002
|
const hookManager = detectHookManager(projectRoot);
|
|
2974
3003
|
const hasHookManager = hookManager === "Lefthook" || hookManager === "Husky";
|
|
2975
3004
|
const preCommitTarget = hasHookManager ? setupPreCommitHook(projectRoot) : void 0;
|
|
2976
|
-
const linter = rootPkg?.stack?.linter?.split("@")[0];
|
|
2977
3005
|
const ok = import_chalk11.default.green("\u2713");
|
|
2978
3006
|
const created = [
|
|
2979
3007
|
`${ok} ${path18.basename(configPath)}`,
|
|
@@ -3066,7 +3094,8 @@ async function initInteractive(projectRoot, configPath, options) {
|
|
|
3066
3094
|
const integrations = await promptIntegrations(projectRoot, hookManager, {
|
|
3067
3095
|
isTypeScript: rootPkgStack?.language === "typescript",
|
|
3068
3096
|
linter: rootPkgStack?.linter?.split("@")[0],
|
|
3069
|
-
packageManager: rootPkgStack?.packageManager
|
|
3097
|
+
packageManager: rootPkgStack?.packageManager,
|
|
3098
|
+
isWorkspace: config.packages.length > 1
|
|
3070
3099
|
});
|
|
3071
3100
|
const shouldWrite = await confirm3("Write configuration and set up selected integrations?");
|
|
3072
3101
|
if (!shouldWrite) {
|
|
@@ -3202,7 +3231,7 @@ ${import_chalk12.default.bold("Synced:")}`);
|
|
|
3202
3231
|
}
|
|
3203
3232
|
|
|
3204
3233
|
// src/index.ts
|
|
3205
|
-
var VERSION = "0.5.
|
|
3234
|
+
var VERSION = "0.5.4";
|
|
3206
3235
|
var program = new import_commander.Command();
|
|
3207
3236
|
program.name("viberails").description("Guardrails for vibe coding").version(VERSION);
|
|
3208
3237
|
program.command("init", { isDefault: true }).description("Scan your project and set up enforcement guardrails").option("-y, --yes", "Non-interactive mode (use defaults, high-confidence only)").option("-f, --force", "Re-initialize, replacing existing config").action(async (options) => {
|