viberails 0.5.3 → 0.5.5
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 +55 -37
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +55 -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;
|
|
@@ -130,7 +131,7 @@ async function promptIntegrations(projectRoot, hookManager, tools) {
|
|
|
130
131
|
options.push({
|
|
131
132
|
value: "typecheck",
|
|
132
133
|
label: "Typecheck (tsc --noEmit)",
|
|
133
|
-
hint: "
|
|
134
|
+
hint: "pre-commit hook + CI check"
|
|
134
135
|
});
|
|
135
136
|
}
|
|
136
137
|
if (tools?.linter) {
|
|
@@ -138,7 +139,7 @@ async function promptIntegrations(projectRoot, hookManager, tools) {
|
|
|
138
139
|
options.push({
|
|
139
140
|
value: "lint",
|
|
140
141
|
label: `Lint check (${linterName})`,
|
|
141
|
-
hint: "
|
|
142
|
+
hint: "pre-commit hook + CI check"
|
|
142
143
|
});
|
|
143
144
|
}
|
|
144
145
|
options.push(
|
|
@@ -1441,7 +1442,8 @@ function formatPackageSummary(pkg) {
|
|
|
1441
1442
|
if (pkg.stack.styling) {
|
|
1442
1443
|
parts.push(formatItem(pkg.stack.styling, import_types2.STYLING_NAMES));
|
|
1443
1444
|
}
|
|
1444
|
-
const
|
|
1445
|
+
const n = pkg.statistics.totalFiles;
|
|
1446
|
+
const files = `${n} ${n === 1 ? "file" : "files"}`;
|
|
1445
1447
|
const detail = parts.length > 0 ? `${parts.join(", ")} (${files})` : `(${files})`;
|
|
1446
1448
|
return ` ${pkg.relativePath} \u2014 ${detail}`;
|
|
1447
1449
|
}
|
|
@@ -1497,7 +1499,8 @@ function formatPackageSummaryPlain(pkg) {
|
|
|
1497
1499
|
if (pkg.stack.styling) {
|
|
1498
1500
|
parts.push(formatItem(pkg.stack.styling, import_types2.STYLING_NAMES));
|
|
1499
1501
|
}
|
|
1500
|
-
const
|
|
1502
|
+
const n = pkg.statistics.totalFiles;
|
|
1503
|
+
const files = `${n} ${n === 1 ? "file" : "files"}`;
|
|
1501
1504
|
const detail = parts.length > 0 ? `${parts.join(", ")} (${files})` : `(${files})`;
|
|
1502
1505
|
return ` ${pkg.relativePath} \u2014 ${detail}`;
|
|
1503
1506
|
}
|
|
@@ -2500,7 +2503,8 @@ function checkCoveragePrereqs(projectRoot, scanResult) {
|
|
|
2500
2503
|
return hasDependency(pkgDir, "@vitest/coverage-v8") || hasDependency(pkgDir, "@vitest/coverage-istanbul");
|
|
2501
2504
|
});
|
|
2502
2505
|
}
|
|
2503
|
-
const
|
|
2506
|
+
const isWorkspace = scanResult.packages.length > 1;
|
|
2507
|
+
const addCmd = pm === "yarn" ? "yarn add -D" : pm === "pnpm" && isWorkspace ? "pnpm add -D -w" : pm === "npm" ? "npm install -D" : `${pm} add -D`;
|
|
2504
2508
|
const affectedPackages = vitestPackages.length > 1 ? vitestPackages : void 0;
|
|
2505
2509
|
const reason = affectedPackages ? `Required for coverage in: ${affectedPackages.join(", ")}` : "Required for coverage percentage checks with vitest";
|
|
2506
2510
|
return [
|
|
@@ -2701,7 +2705,6 @@ function addLefthookPreCommit(lefthookPath) {
|
|
|
2701
2705
|
function detectHookManager(projectRoot) {
|
|
2702
2706
|
if (fs16.existsSync(path16.join(projectRoot, "lefthook.yml"))) return "Lefthook";
|
|
2703
2707
|
if (fs16.existsSync(path16.join(projectRoot, ".husky"))) return "Husky";
|
|
2704
|
-
if (fs16.existsSync(path16.join(projectRoot, ".git"))) return "git hook";
|
|
2705
2708
|
return void 0;
|
|
2706
2709
|
}
|
|
2707
2710
|
function setupClaudeCodeHook(projectRoot) {
|
|
@@ -2755,7 +2758,7 @@ function setupClaudeMdReference(projectRoot) {
|
|
|
2755
2758
|
fs16.writeFileSync(claudeMdPath, prefix + ref);
|
|
2756
2759
|
console.log(` ${import_chalk9.default.green("\u2713")} CLAUDE.md \u2014 added @.viberails/context.md reference`);
|
|
2757
2760
|
}
|
|
2758
|
-
function setupGithubAction(projectRoot, packageManager) {
|
|
2761
|
+
function setupGithubAction(projectRoot, packageManager, options) {
|
|
2759
2762
|
const workflowDir = path16.join(projectRoot, ".github", "workflows");
|
|
2760
2763
|
const workflowPath = path16.join(workflowDir, "viberails.yml");
|
|
2761
2764
|
if (fs16.existsSync(workflowPath)) {
|
|
@@ -2791,7 +2794,16 @@ function setupGithubAction(projectRoot, packageManager) {
|
|
|
2791
2794
|
" node-version: 22",
|
|
2792
2795
|
pm !== "npm" ? ` cache: ${pm}` : "",
|
|
2793
2796
|
"",
|
|
2794
|
-
` - run: ${installCmd}
|
|
2797
|
+
` - run: ${installCmd}`
|
|
2798
|
+
);
|
|
2799
|
+
if (options?.typecheck) {
|
|
2800
|
+
lines.push(` - run: ${runPrefix} tsc --noEmit`);
|
|
2801
|
+
}
|
|
2802
|
+
if (options?.linter) {
|
|
2803
|
+
const lintCmd = options.linter === "biome" ? "biome check ." : "eslint .";
|
|
2804
|
+
lines.push(` - run: ${runPrefix} ${lintCmd}`);
|
|
2805
|
+
}
|
|
2806
|
+
lines.push(
|
|
2795
2807
|
` - run: ${runPrefix} viberails check --enforce --diff-base origin/\${{ github.event.pull_request.base.ref }}`,
|
|
2796
2808
|
""
|
|
2797
2809
|
);
|
|
@@ -2912,7 +2924,10 @@ function setupSelectedIntegrations(projectRoot, integrations, opts) {
|
|
|
2912
2924
|
created.push("CLAUDE.md \u2014 added @.viberails/context.md reference");
|
|
2913
2925
|
}
|
|
2914
2926
|
if (integrations.githubAction) {
|
|
2915
|
-
const t = setupGithubAction(projectRoot, opts.packageManager ?? "npm"
|
|
2927
|
+
const t = setupGithubAction(projectRoot, opts.packageManager ?? "npm", {
|
|
2928
|
+
linter: integrations.lintHook ? opts.linter : void 0,
|
|
2929
|
+
typecheck: integrations.typecheckHook
|
|
2930
|
+
});
|
|
2916
2931
|
if (t) created.push(`${t} \u2014 blocks PRs on violations`);
|
|
2917
2932
|
}
|
|
2918
2933
|
return created;
|
|
@@ -2980,11 +2995,15 @@ async function initNonInteractive(projectRoot, configPath) {
|
|
|
2980
2995
|
setupClaudeMdReference(projectRoot);
|
|
2981
2996
|
const rootPkg = config.packages[0];
|
|
2982
2997
|
const rootPkgPm = rootPkg?.stack?.packageManager ?? "npm";
|
|
2983
|
-
const
|
|
2998
|
+
const linter = rootPkg?.stack?.linter?.split("@")[0];
|
|
2999
|
+
const isTypeScript = rootPkg?.stack?.language === "typescript";
|
|
3000
|
+
const actionTarget = setupGithubAction(projectRoot, rootPkgPm, {
|
|
3001
|
+
linter,
|
|
3002
|
+
typecheck: isTypeScript
|
|
3003
|
+
});
|
|
2984
3004
|
const hookManager = detectHookManager(projectRoot);
|
|
2985
3005
|
const hasHookManager = hookManager === "Lefthook" || hookManager === "Husky";
|
|
2986
3006
|
const preCommitTarget = hasHookManager ? setupPreCommitHook(projectRoot) : void 0;
|
|
2987
|
-
const linter = rootPkg?.stack?.linter?.split("@")[0];
|
|
2988
3007
|
const ok = import_chalk11.default.green("\u2713");
|
|
2989
3008
|
const created = [
|
|
2990
3009
|
`${ok} ${path18.basename(configPath)}`,
|
|
@@ -3017,13 +3036,6 @@ async function initInteractive(projectRoot, configPath, options) {
|
|
|
3017
3036
|
const scanResult = await (0, import_scanner2.scan)(projectRoot);
|
|
3018
3037
|
const config = (0, import_config8.generateConfig)(scanResult);
|
|
3019
3038
|
s.stop("Scan complete");
|
|
3020
|
-
const prereqResult = await promptMissingPrereqs(
|
|
3021
|
-
projectRoot,
|
|
3022
|
-
checkCoveragePrereqs(projectRoot, scanResult)
|
|
3023
|
-
);
|
|
3024
|
-
if (prereqResult.disableCoverage) {
|
|
3025
|
-
config.rules.testCoverage = 0;
|
|
3026
|
-
}
|
|
3027
3039
|
if (scanResult.statistics.totalFiles === 0) {
|
|
3028
3040
|
clack8.log.warn(
|
|
3029
3041
|
"No source files detected. Try running from the project root,\nor check that source files exist. Run viberails sync after adding files."
|
|
@@ -3064,20 +3076,29 @@ async function initInteractive(projectRoot, configPath, options) {
|
|
|
3064
3076
|
if (denyCount > 0) {
|
|
3065
3077
|
config.boundaries = inferred;
|
|
3066
3078
|
config.rules.enforceBoundaries = true;
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
clack8.note(boundaryLines, "Boundary rules");
|
|
3079
|
+
const pkgCount = Object.keys(inferred.deny).length;
|
|
3080
|
+
bs.stop(`Inferred ${denyCount} boundary rules across ${pkgCount} packages`);
|
|
3070
3081
|
} else {
|
|
3071
3082
|
bs.stop("No boundary rules inferred");
|
|
3072
3083
|
}
|
|
3073
3084
|
}
|
|
3074
3085
|
}
|
|
3075
3086
|
const hookManager = detectHookManager(projectRoot);
|
|
3087
|
+
const coveragePrereqs = checkCoveragePrereqs(projectRoot, scanResult);
|
|
3088
|
+
const hasMissingPrereqs = coveragePrereqs.some((p) => !p.installed) || !hookManager;
|
|
3089
|
+
if (hasMissingPrereqs) {
|
|
3090
|
+
clack8.log.info("Some dependencies are needed for full functionality.");
|
|
3091
|
+
}
|
|
3092
|
+
const prereqResult = await promptMissingPrereqs(projectRoot, coveragePrereqs);
|
|
3093
|
+
if (prereqResult.disableCoverage) {
|
|
3094
|
+
config.rules.testCoverage = 0;
|
|
3095
|
+
}
|
|
3076
3096
|
const rootPkgStack = (config.packages.find((p) => p.path === ".") ?? config.packages[0])?.stack;
|
|
3077
3097
|
const integrations = await promptIntegrations(projectRoot, hookManager, {
|
|
3078
3098
|
isTypeScript: rootPkgStack?.language === "typescript",
|
|
3079
3099
|
linter: rootPkgStack?.linter?.split("@")[0],
|
|
3080
|
-
packageManager: rootPkgStack?.packageManager
|
|
3100
|
+
packageManager: rootPkgStack?.packageManager,
|
|
3101
|
+
isWorkspace: config.packages.length > 1
|
|
3081
3102
|
});
|
|
3082
3103
|
const shouldWrite = await confirm3("Write configuration and set up selected integrations?");
|
|
3083
3104
|
if (!shouldWrite) {
|
|
@@ -3089,17 +3110,14 @@ async function initInteractive(projectRoot, configPath, options) {
|
|
|
3089
3110
|
`);
|
|
3090
3111
|
writeGeneratedFiles(projectRoot, config, scanResult);
|
|
3091
3112
|
updateGitignore(projectRoot);
|
|
3092
|
-
const
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
];
|
|
3101
|
-
clack8.log.success(`Created:
|
|
3102
|
-
${createdFiles.map((f) => ` ${f}`).join("\n")}`);
|
|
3113
|
+
const ok = import_chalk11.default.green("\u2713");
|
|
3114
|
+
clack8.log.step(`${ok} ${path18.basename(configPath)}`);
|
|
3115
|
+
clack8.log.step(`${ok} .viberails/context.md`);
|
|
3116
|
+
clack8.log.step(`${ok} .viberails/scan-result.json`);
|
|
3117
|
+
setupSelectedIntegrations(projectRoot, integrations, {
|
|
3118
|
+
linter: rootPkgStack?.linter?.split("@")[0],
|
|
3119
|
+
packageManager: rootPkgStack?.packageManager
|
|
3120
|
+
});
|
|
3103
3121
|
clack8.outro(
|
|
3104
3122
|
`Done! Next: review viberails.config.json, then run viberails check
|
|
3105
3123
|
${import_chalk11.default.dim("Tip: use")} ${import_chalk11.default.cyan("viberails check --enforce")} ${import_chalk11.default.dim("in CI to block PRs on violations.")}`
|
|
@@ -3213,7 +3231,7 @@ ${import_chalk12.default.bold("Synced:")}`);
|
|
|
3213
3231
|
}
|
|
3214
3232
|
|
|
3215
3233
|
// src/index.ts
|
|
3216
|
-
var VERSION = "0.5.
|
|
3234
|
+
var VERSION = "0.5.5";
|
|
3217
3235
|
var program = new import_commander.Command();
|
|
3218
3236
|
program.name("viberails").description("Guardrails for vibe coding").version(VERSION);
|
|
3219
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) => {
|