viberails 0.6.7 → 0.6.8
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 +162 -155
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +162 -155
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
package/dist/index.cjs
CHANGED
|
@@ -34,14 +34,14 @@ __export(index_exports, {
|
|
|
34
34
|
VERSION: () => VERSION
|
|
35
35
|
});
|
|
36
36
|
module.exports = __toCommonJS(index_exports);
|
|
37
|
-
var
|
|
37
|
+
var import_chalk17 = __toESM(require("chalk"), 1);
|
|
38
38
|
var import_commander = require("commander");
|
|
39
39
|
|
|
40
40
|
// src/commands/boundaries.ts
|
|
41
41
|
var fs3 = __toESM(require("fs"), 1);
|
|
42
42
|
var path3 = __toESM(require("path"), 1);
|
|
43
43
|
var import_config = require("@viberails/config");
|
|
44
|
-
var
|
|
44
|
+
var import_chalk2 = __toESM(require("chalk"), 1);
|
|
45
45
|
|
|
46
46
|
// src/utils/find-project-root.ts
|
|
47
47
|
var fs = __toESM(require("fs"), 1);
|
|
@@ -90,6 +90,7 @@ var HINT_AUTO_DETECT = "auto-detect";
|
|
|
90
90
|
|
|
91
91
|
// src/utils/prompt-submenus.ts
|
|
92
92
|
var clack = __toESM(require("@clack/prompts"), 1);
|
|
93
|
+
var import_chalk = __toESM(require("chalk"), 1);
|
|
93
94
|
var FILE_NAMING_OPTIONS = [
|
|
94
95
|
{ value: "kebab-case", label: "kebab-case" },
|
|
95
96
|
{ value: "camelCase", label: "camelCase" },
|
|
@@ -153,7 +154,7 @@ async function promptNamingMenu(state) {
|
|
|
153
154
|
{
|
|
154
155
|
value: "enforceNaming",
|
|
155
156
|
label: "Enforce file naming",
|
|
156
|
-
hint: state.enforceNaming ? "yes" : "no"
|
|
157
|
+
hint: state.enforceNaming ? import_chalk.default.green("yes") : import_chalk.default.dim("no")
|
|
157
158
|
}
|
|
158
159
|
];
|
|
159
160
|
if (state.enforceNaming) {
|
|
@@ -271,7 +272,7 @@ async function promptTestingMenu(state) {
|
|
|
271
272
|
{
|
|
272
273
|
value: "enforceMissingTests",
|
|
273
274
|
label: "Enforce missing tests",
|
|
274
|
-
hint: state.enforceMissingTests ? "yes" : "no"
|
|
275
|
+
hint: state.enforceMissingTests ? import_chalk.default.green("yes") : import_chalk.default.dim("no")
|
|
275
276
|
},
|
|
276
277
|
{
|
|
277
278
|
value: "testCoverage",
|
|
@@ -767,48 +768,48 @@ async function boundariesCommand(options, cwd) {
|
|
|
767
768
|
}
|
|
768
769
|
function displayRules(config) {
|
|
769
770
|
if (!config.boundaries || Object.keys(config.boundaries.deny).length === 0) {
|
|
770
|
-
console.log(
|
|
771
|
-
console.log(`Run ${
|
|
771
|
+
console.log(import_chalk2.default.yellow("No boundary rules configured."));
|
|
772
|
+
console.log(`Run ${import_chalk2.default.cyan("viberails boundaries --infer")} to generate rules.`);
|
|
772
773
|
return;
|
|
773
774
|
}
|
|
774
775
|
const { deny } = config.boundaries;
|
|
775
776
|
const sources = Object.keys(deny).filter((k) => deny[k].length > 0);
|
|
776
777
|
const totalRules = sources.reduce((sum, k) => sum + deny[k].length, 0);
|
|
777
778
|
console.log(`
|
|
778
|
-
${
|
|
779
|
+
${import_chalk2.default.bold(`Boundary rules (${totalRules} deny rules):`)}
|
|
779
780
|
`);
|
|
780
781
|
for (const source of sources) {
|
|
781
782
|
for (const target of deny[source]) {
|
|
782
|
-
console.log(` ${
|
|
783
|
+
console.log(` ${import_chalk2.default.red("\u2717")} ${source} \u2192 ${target}`);
|
|
783
784
|
}
|
|
784
785
|
}
|
|
785
786
|
console.log(
|
|
786
787
|
`
|
|
787
|
-
Enforcement: ${config.rules.enforceBoundaries ?
|
|
788
|
+
Enforcement: ${config.rules.enforceBoundaries ? import_chalk2.default.green("on") : import_chalk2.default.yellow("off")}`
|
|
788
789
|
);
|
|
789
790
|
}
|
|
790
791
|
async function inferAndDisplay(projectRoot, config, configPath) {
|
|
791
|
-
console.log(
|
|
792
|
+
console.log(import_chalk2.default.dim("Analyzing imports..."));
|
|
792
793
|
const { buildImportGraph, inferBoundaries } = await import("@viberails/graph");
|
|
793
794
|
const packages = config.packages.length > 1 ? resolveWorkspacePackages(projectRoot, config.packages) : void 0;
|
|
794
795
|
const graph = await buildImportGraph(projectRoot, {
|
|
795
796
|
packages,
|
|
796
797
|
ignore: config.ignore
|
|
797
798
|
});
|
|
798
|
-
console.log(
|
|
799
|
+
console.log(import_chalk2.default.dim(`${graph.nodes.length} files, ${graph.edges.length} edges`));
|
|
799
800
|
const inferred = inferBoundaries(graph);
|
|
800
801
|
const sources = Object.keys(inferred.deny).filter((k) => inferred.deny[k].length > 0);
|
|
801
802
|
const totalRules = sources.reduce((sum, k) => sum + inferred.deny[k].length, 0);
|
|
802
803
|
if (totalRules === 0) {
|
|
803
|
-
console.log(
|
|
804
|
+
console.log(import_chalk2.default.yellow("No boundary rules could be inferred."));
|
|
804
805
|
return;
|
|
805
806
|
}
|
|
806
807
|
console.log(`
|
|
807
|
-
${
|
|
808
|
+
${import_chalk2.default.bold("Inferred boundary rules:")}
|
|
808
809
|
`);
|
|
809
810
|
for (const source of sources) {
|
|
810
811
|
for (const target of inferred.deny[source]) {
|
|
811
|
-
console.log(` ${
|
|
812
|
+
console.log(` ${import_chalk2.default.red("\u2717")} ${source} \u2192 ${target}`);
|
|
812
813
|
}
|
|
813
814
|
}
|
|
814
815
|
console.log(`
|
|
@@ -820,11 +821,11 @@ ${import_chalk.default.bold("Inferred boundary rules:")}
|
|
|
820
821
|
config.rules.enforceBoundaries = true;
|
|
821
822
|
fs3.writeFileSync(configPath, `${JSON.stringify((0, import_config.compactConfig)(config), null, 2)}
|
|
822
823
|
`);
|
|
823
|
-
console.log(`${
|
|
824
|
+
console.log(`${import_chalk2.default.green("\u2713")} Saved ${totalRules} rules`);
|
|
824
825
|
}
|
|
825
826
|
}
|
|
826
827
|
async function showGraph(projectRoot, config) {
|
|
827
|
-
console.log(
|
|
828
|
+
console.log(import_chalk2.default.dim("Building import graph..."));
|
|
828
829
|
const { buildImportGraph } = await import("@viberails/graph");
|
|
829
830
|
const packages = config.packages.length > 1 ? resolveWorkspacePackages(projectRoot, config.packages) : void 0;
|
|
830
831
|
const graph = await buildImportGraph(projectRoot, {
|
|
@@ -832,20 +833,20 @@ async function showGraph(projectRoot, config) {
|
|
|
832
833
|
ignore: config.ignore
|
|
833
834
|
});
|
|
834
835
|
console.log(`
|
|
835
|
-
${
|
|
836
|
+
${import_chalk2.default.bold("Import dependency graph:")}
|
|
836
837
|
`);
|
|
837
838
|
console.log(` ${graph.nodes.length} files, ${graph.edges.length} imports
|
|
838
839
|
`);
|
|
839
840
|
if (graph.packages.length > 0) {
|
|
840
841
|
for (const pkg of graph.packages) {
|
|
841
842
|
const deps = pkg.internalDeps.length > 0 ? `
|
|
842
|
-
${pkg.internalDeps.map((d) => ` \u2192 ${d}`).join("\n")}` :
|
|
843
|
+
${pkg.internalDeps.map((d) => ` \u2192 ${d}`).join("\n")}` : import_chalk2.default.dim(" (no internal deps)");
|
|
843
844
|
console.log(` ${pkg.name}${deps}`);
|
|
844
845
|
}
|
|
845
846
|
}
|
|
846
847
|
if (graph.cycles.length > 0) {
|
|
847
848
|
console.log(`
|
|
848
|
-
${
|
|
849
|
+
${import_chalk2.default.yellow("Cycles detected:")}`);
|
|
849
850
|
for (const cycle of graph.cycles) {
|
|
850
851
|
const paths = cycle.map((f) => path3.relative(projectRoot, f));
|
|
851
852
|
console.log(` ${paths.join(" \u2192 ")}`);
|
|
@@ -857,7 +858,7 @@ ${import_chalk.default.yellow("Cycles detected:")}`);
|
|
|
857
858
|
var fs7 = __toESM(require("fs"), 1);
|
|
858
859
|
var path7 = __toESM(require("path"), 1);
|
|
859
860
|
var import_config5 = require("@viberails/config");
|
|
860
|
-
var
|
|
861
|
+
var import_chalk4 = __toESM(require("chalk"), 1);
|
|
861
862
|
|
|
862
863
|
// src/commands/check-config.ts
|
|
863
864
|
var import_config2 = require("@viberails/config");
|
|
@@ -1249,7 +1250,7 @@ function collectSourceFiles(dir, projectRoot) {
|
|
|
1249
1250
|
}
|
|
1250
1251
|
|
|
1251
1252
|
// src/commands/check-print.ts
|
|
1252
|
-
var
|
|
1253
|
+
var import_chalk3 = __toESM(require("chalk"), 1);
|
|
1253
1254
|
function printGroupedViolations(violations, limit) {
|
|
1254
1255
|
const groups = /* @__PURE__ */ new Map();
|
|
1255
1256
|
for (const v of violations) {
|
|
@@ -1277,12 +1278,12 @@ function printGroupedViolations(violations, limit) {
|
|
|
1277
1278
|
const toShow = group.slice(0, remaining);
|
|
1278
1279
|
const hidden = group.length - toShow.length;
|
|
1279
1280
|
for (const v of toShow) {
|
|
1280
|
-
const icon = v.severity === "error" ?
|
|
1281
|
-
console.log(`${icon} ${
|
|
1281
|
+
const icon = v.severity === "error" ? import_chalk3.default.red("\u2717") : import_chalk3.default.yellow("!");
|
|
1282
|
+
console.log(`${icon} ${import_chalk3.default.dim(v.rule)} ${v.file}: ${v.message}`);
|
|
1282
1283
|
}
|
|
1283
1284
|
totalShown += toShow.length;
|
|
1284
1285
|
if (hidden > 0) {
|
|
1285
|
-
console.log(
|
|
1286
|
+
console.log(import_chalk3.default.dim(` ... and ${hidden} more ${rule} violations`));
|
|
1286
1287
|
}
|
|
1287
1288
|
}
|
|
1288
1289
|
}
|
|
@@ -1372,13 +1373,13 @@ async function checkCommand(options, cwd) {
|
|
|
1372
1373
|
const startDir = cwd ?? process.cwd();
|
|
1373
1374
|
const projectRoot = findProjectRoot(startDir);
|
|
1374
1375
|
if (!projectRoot) {
|
|
1375
|
-
console.error(`${
|
|
1376
|
+
console.error(`${import_chalk4.default.red("Error:")} No package.json found. Are you in a JS/TS project?`);
|
|
1376
1377
|
return 1;
|
|
1377
1378
|
}
|
|
1378
1379
|
const configPath = path7.join(projectRoot, CONFIG_FILE2);
|
|
1379
1380
|
if (!fs7.existsSync(configPath)) {
|
|
1380
1381
|
console.error(
|
|
1381
|
-
`${
|
|
1382
|
+
`${import_chalk4.default.red("Error:")} No viberails.config.json found. Run \`viberails init\` first.`
|
|
1382
1383
|
);
|
|
1383
1384
|
return 1;
|
|
1384
1385
|
}
|
|
@@ -1392,7 +1393,7 @@ async function checkCommand(options, cwd) {
|
|
|
1392
1393
|
} else if (options.diffBase) {
|
|
1393
1394
|
const diff = getDiffFiles(projectRoot, options.diffBase);
|
|
1394
1395
|
if (diff.error && options.enforce) {
|
|
1395
|
-
console.error(`${
|
|
1396
|
+
console.error(`${import_chalk4.default.red("Error:")} ${diff.error}`);
|
|
1396
1397
|
return 1;
|
|
1397
1398
|
}
|
|
1398
1399
|
filesToCheck = diff.all.filter((f) => SOURCE_EXTS.has(path7.extname(f)));
|
|
@@ -1407,13 +1408,13 @@ async function checkCommand(options, cwd) {
|
|
|
1407
1408
|
if (options.format === "json") {
|
|
1408
1409
|
console.log(JSON.stringify({ violations: [], checkedFiles: 0 }));
|
|
1409
1410
|
} else {
|
|
1410
|
-
console.log(`${
|
|
1411
|
+
console.log(`${import_chalk4.default.green("\u2713")} No files to check.`);
|
|
1411
1412
|
}
|
|
1412
1413
|
return 0;
|
|
1413
1414
|
}
|
|
1414
1415
|
const violations = [];
|
|
1415
1416
|
const severity = options.enforce ? "error" : "warn";
|
|
1416
|
-
const log9 = options.format !== "json" && !options.hook && !options.quiet ? (msg) => process.stderr.write(
|
|
1417
|
+
const log9 = options.format !== "json" && !options.hook && !options.quiet ? (msg) => process.stderr.write(import_chalk4.default.dim(msg)) : () => {
|
|
1417
1418
|
};
|
|
1418
1419
|
log9(" Checking files...");
|
|
1419
1420
|
for (const file of filesToCheck) {
|
|
@@ -1508,7 +1509,7 @@ async function checkCommand(options, cwd) {
|
|
|
1508
1509
|
return options.enforce && violations.length > 0 ? 1 : 0;
|
|
1509
1510
|
}
|
|
1510
1511
|
if (violations.length === 0) {
|
|
1511
|
-
console.log(`${
|
|
1512
|
+
console.log(`${import_chalk4.default.green("\u2713")} ${filesToCheck.length} files checked \u2014 no violations`);
|
|
1512
1513
|
return 0;
|
|
1513
1514
|
}
|
|
1514
1515
|
if (!options.quiet) {
|
|
@@ -1516,7 +1517,7 @@ async function checkCommand(options, cwd) {
|
|
|
1516
1517
|
}
|
|
1517
1518
|
printSummary(violations);
|
|
1518
1519
|
if (options.enforce) {
|
|
1519
|
-
console.log(
|
|
1520
|
+
console.log(import_chalk4.default.red("Fix violations before committing."));
|
|
1520
1521
|
return 1;
|
|
1521
1522
|
}
|
|
1522
1523
|
return 0;
|
|
@@ -1574,14 +1575,14 @@ var path9 = __toESM(require("path"), 1);
|
|
|
1574
1575
|
var clack6 = __toESM(require("@clack/prompts"), 1);
|
|
1575
1576
|
var import_config6 = require("@viberails/config");
|
|
1576
1577
|
var import_scanner = require("@viberails/scanner");
|
|
1577
|
-
var
|
|
1578
|
+
var import_chalk7 = __toESM(require("chalk"), 1);
|
|
1578
1579
|
|
|
1579
1580
|
// src/display-text.ts
|
|
1580
1581
|
var import_types4 = require("@viberails/types");
|
|
1581
1582
|
|
|
1582
1583
|
// src/display.ts
|
|
1583
1584
|
var import_types3 = require("@viberails/types");
|
|
1584
|
-
var
|
|
1585
|
+
var import_chalk6 = __toESM(require("chalk"), 1);
|
|
1585
1586
|
|
|
1586
1587
|
// src/display-helpers.ts
|
|
1587
1588
|
var import_types = require("@viberails/types");
|
|
@@ -1634,7 +1635,7 @@ function formatRoleGroup(group) {
|
|
|
1634
1635
|
|
|
1635
1636
|
// src/display-monorepo.ts
|
|
1636
1637
|
var import_types2 = require("@viberails/types");
|
|
1637
|
-
var
|
|
1638
|
+
var import_chalk5 = __toESM(require("chalk"), 1);
|
|
1638
1639
|
function formatPackageSummary(pkg) {
|
|
1639
1640
|
const parts = [];
|
|
1640
1641
|
if (pkg.stack.framework) {
|
|
@@ -1651,23 +1652,23 @@ function formatPackageSummary(pkg) {
|
|
|
1651
1652
|
function displayMonorepoResults(scanResult) {
|
|
1652
1653
|
const { stack, packages } = scanResult;
|
|
1653
1654
|
console.log(`
|
|
1654
|
-
${
|
|
1655
|
-
console.log(` ${
|
|
1655
|
+
${import_chalk5.default.bold(`Detected: (monorepo, ${packages.length} packages)`)}`);
|
|
1656
|
+
console.log(` ${import_chalk5.default.green("\u2713")} ${formatItem(stack.language)}`);
|
|
1656
1657
|
if (stack.packageManager) {
|
|
1657
|
-
console.log(` ${
|
|
1658
|
+
console.log(` ${import_chalk5.default.green("\u2713")} ${formatItem(stack.packageManager)}`);
|
|
1658
1659
|
}
|
|
1659
1660
|
if (stack.linter && stack.formatter && stack.linter.name === stack.formatter.name) {
|
|
1660
|
-
console.log(` ${
|
|
1661
|
+
console.log(` ${import_chalk5.default.green("\u2713")} ${formatItem(stack.linter)} (lint + format)`);
|
|
1661
1662
|
} else {
|
|
1662
1663
|
if (stack.linter) {
|
|
1663
|
-
console.log(` ${
|
|
1664
|
+
console.log(` ${import_chalk5.default.green("\u2713")} ${formatItem(stack.linter)}`);
|
|
1664
1665
|
}
|
|
1665
1666
|
if (stack.formatter) {
|
|
1666
|
-
console.log(` ${
|
|
1667
|
+
console.log(` ${import_chalk5.default.green("\u2713")} ${formatItem(stack.formatter)}`);
|
|
1667
1668
|
}
|
|
1668
1669
|
}
|
|
1669
1670
|
if (stack.testRunner) {
|
|
1670
|
-
console.log(` ${
|
|
1671
|
+
console.log(` ${import_chalk5.default.green("\u2713")} ${formatItem(stack.testRunner)}`);
|
|
1671
1672
|
}
|
|
1672
1673
|
console.log("");
|
|
1673
1674
|
for (const pkg of packages) {
|
|
@@ -1678,13 +1679,13 @@ ${import_chalk4.default.bold(`Detected: (monorepo, ${packages.length} packages)`
|
|
|
1678
1679
|
);
|
|
1679
1680
|
if (packagesWithDirs.length > 0) {
|
|
1680
1681
|
console.log(`
|
|
1681
|
-
${
|
|
1682
|
+
${import_chalk5.default.bold("Structure:")}`);
|
|
1682
1683
|
for (const pkg of packagesWithDirs) {
|
|
1683
1684
|
const groups = groupByRole(pkg.structure.directories);
|
|
1684
1685
|
if (groups.length === 0) continue;
|
|
1685
1686
|
console.log(` ${pkg.relativePath}:`);
|
|
1686
1687
|
for (const group of groups) {
|
|
1687
|
-
console.log(` ${
|
|
1688
|
+
console.log(` ${import_chalk5.default.green("\u2713")} ${formatRoleGroup(group)}`);
|
|
1688
1689
|
}
|
|
1689
1690
|
}
|
|
1690
1691
|
}
|
|
@@ -1765,7 +1766,7 @@ function displayConventions(scanResult) {
|
|
|
1765
1766
|
const conventionEntries = Object.entries(scanResult.conventions);
|
|
1766
1767
|
if (conventionEntries.length === 0) return;
|
|
1767
1768
|
console.log(`
|
|
1768
|
-
${
|
|
1769
|
+
${import_chalk6.default.bold("Conventions:")}`);
|
|
1769
1770
|
for (const [key, convention] of conventionEntries) {
|
|
1770
1771
|
if (convention.confidence === "low") continue;
|
|
1771
1772
|
const label = import_types3.CONVENTION_LABELS[key] ?? key;
|
|
@@ -1773,19 +1774,19 @@ ${import_chalk5.default.bold("Conventions:")}`);
|
|
|
1773
1774
|
const pkgValues = scanResult.packages.filter((pkg) => pkg.conventions[key] && pkg.conventions[key].confidence !== "low").map((pkg) => ({ relativePath: pkg.relativePath, convention: pkg.conventions[key] }));
|
|
1774
1775
|
const allSame = pkgValues.every((pv) => pv.convention.value === convention.value);
|
|
1775
1776
|
if (allSame || pkgValues.length <= 1) {
|
|
1776
|
-
const ind = convention.confidence === "high" ?
|
|
1777
|
-
const detail =
|
|
1777
|
+
const ind = convention.confidence === "high" ? import_chalk6.default.green("\u2713") : import_chalk6.default.yellow("~");
|
|
1778
|
+
const detail = import_chalk6.default.dim(`(${confidenceLabel(convention)})`);
|
|
1778
1779
|
console.log(` ${ind} ${label}: ${convention.value} ${detail}`);
|
|
1779
1780
|
} else {
|
|
1780
|
-
console.log(` ${
|
|
1781
|
+
console.log(` ${import_chalk6.default.yellow("~")} ${label}: varies by package`);
|
|
1781
1782
|
for (const pv of pkgValues) {
|
|
1782
1783
|
const pct = Math.round(pv.convention.consistency);
|
|
1783
1784
|
console.log(` ${pv.relativePath}: ${pv.convention.value} (${pct}%)`);
|
|
1784
1785
|
}
|
|
1785
1786
|
}
|
|
1786
1787
|
} else {
|
|
1787
|
-
const ind = convention.confidence === "high" ?
|
|
1788
|
-
const detail =
|
|
1788
|
+
const ind = convention.confidence === "high" ? import_chalk6.default.green("\u2713") : import_chalk6.default.yellow("~");
|
|
1789
|
+
const detail = import_chalk6.default.dim(`(${confidenceLabel(convention)})`);
|
|
1789
1790
|
console.log(` ${ind} ${label}: ${convention.value} ${detail}`);
|
|
1790
1791
|
}
|
|
1791
1792
|
}
|
|
@@ -1793,7 +1794,7 @@ ${import_chalk5.default.bold("Conventions:")}`);
|
|
|
1793
1794
|
function displaySummarySection(scanResult) {
|
|
1794
1795
|
const pkgCount = scanResult.packages.length > 1 ? scanResult.packages.length : void 0;
|
|
1795
1796
|
console.log(`
|
|
1796
|
-
${
|
|
1797
|
+
${import_chalk6.default.bold("Summary:")}`);
|
|
1797
1798
|
console.log(` ${formatSummary(scanResult.statistics, pkgCount)}`);
|
|
1798
1799
|
const ext = formatExtensions(scanResult.statistics.filesByExtension);
|
|
1799
1800
|
if (ext) {
|
|
@@ -1807,47 +1808,47 @@ function displayScanResults(scanResult) {
|
|
|
1807
1808
|
}
|
|
1808
1809
|
const { stack } = scanResult;
|
|
1809
1810
|
console.log(`
|
|
1810
|
-
${
|
|
1811
|
+
${import_chalk6.default.bold("Detected:")}`);
|
|
1811
1812
|
if (stack.framework) {
|
|
1812
|
-
console.log(` ${
|
|
1813
|
+
console.log(` ${import_chalk6.default.green("\u2713")} ${formatItem(stack.framework, import_types3.FRAMEWORK_NAMES)}`);
|
|
1813
1814
|
}
|
|
1814
|
-
console.log(` ${
|
|
1815
|
+
console.log(` ${import_chalk6.default.green("\u2713")} ${formatItem(stack.language)}`);
|
|
1815
1816
|
if (stack.styling) {
|
|
1816
|
-
console.log(` ${
|
|
1817
|
+
console.log(` ${import_chalk6.default.green("\u2713")} ${formatItem(stack.styling, import_types3.STYLING_NAMES)}`);
|
|
1817
1818
|
}
|
|
1818
1819
|
if (stack.backend) {
|
|
1819
|
-
console.log(` ${
|
|
1820
|
+
console.log(` ${import_chalk6.default.green("\u2713")} ${formatItem(stack.backend, import_types3.FRAMEWORK_NAMES)}`);
|
|
1820
1821
|
}
|
|
1821
1822
|
if (stack.orm) {
|
|
1822
|
-
console.log(` ${
|
|
1823
|
+
console.log(` ${import_chalk6.default.green("\u2713")} ${formatItem(stack.orm, import_types3.ORM_NAMES)}`);
|
|
1823
1824
|
}
|
|
1824
1825
|
if (stack.linter && stack.formatter && stack.linter.name === stack.formatter.name) {
|
|
1825
|
-
console.log(` ${
|
|
1826
|
+
console.log(` ${import_chalk6.default.green("\u2713")} ${formatItem(stack.linter)} (lint + format)`);
|
|
1826
1827
|
} else {
|
|
1827
1828
|
if (stack.linter) {
|
|
1828
|
-
console.log(` ${
|
|
1829
|
+
console.log(` ${import_chalk6.default.green("\u2713")} ${formatItem(stack.linter)}`);
|
|
1829
1830
|
}
|
|
1830
1831
|
if (stack.formatter) {
|
|
1831
|
-
console.log(` ${
|
|
1832
|
+
console.log(` ${import_chalk6.default.green("\u2713")} ${formatItem(stack.formatter)}`);
|
|
1832
1833
|
}
|
|
1833
1834
|
}
|
|
1834
1835
|
if (stack.testRunner) {
|
|
1835
|
-
console.log(` ${
|
|
1836
|
+
console.log(` ${import_chalk6.default.green("\u2713")} ${formatItem(stack.testRunner)}`);
|
|
1836
1837
|
}
|
|
1837
1838
|
if (stack.packageManager) {
|
|
1838
|
-
console.log(` ${
|
|
1839
|
+
console.log(` ${import_chalk6.default.green("\u2713")} ${formatItem(stack.packageManager)}`);
|
|
1839
1840
|
}
|
|
1840
1841
|
if (stack.libraries.length > 0) {
|
|
1841
1842
|
for (const lib of stack.libraries) {
|
|
1842
|
-
console.log(` ${
|
|
1843
|
+
console.log(` ${import_chalk6.default.green("\u2713")} ${formatItem(lib, import_types3.LIBRARY_NAMES)}`);
|
|
1843
1844
|
}
|
|
1844
1845
|
}
|
|
1845
1846
|
const groups = groupByRole(scanResult.structure.directories);
|
|
1846
1847
|
if (groups.length > 0) {
|
|
1847
1848
|
console.log(`
|
|
1848
|
-
${
|
|
1849
|
+
${import_chalk6.default.bold("Structure:")}`);
|
|
1849
1850
|
for (const group of groups) {
|
|
1850
|
-
console.log(` ${
|
|
1851
|
+
console.log(` ${import_chalk6.default.green("\u2713")} ${formatRoleGroup(group)}`);
|
|
1851
1852
|
}
|
|
1852
1853
|
}
|
|
1853
1854
|
displayConventions(scanResult);
|
|
@@ -1857,25 +1858,25 @@ ${import_chalk5.default.bold("Structure:")}`);
|
|
|
1857
1858
|
function displayRulesPreview(config) {
|
|
1858
1859
|
const root = config.packages.find((p) => p.path === ".") ?? config.packages[0];
|
|
1859
1860
|
console.log(
|
|
1860
|
-
`${
|
|
1861
|
+
`${import_chalk6.default.bold("Rules:")} ${import_chalk6.default.dim("(warns on violation; use --enforce in CI to block)")}`
|
|
1861
1862
|
);
|
|
1862
|
-
console.log(` ${
|
|
1863
|
+
console.log(` ${import_chalk6.default.dim("\u2022")} Max file size: ${config.rules.maxFileLines} lines`);
|
|
1863
1864
|
if (config.rules.testCoverage > 0 && root?.structure?.testPattern) {
|
|
1864
1865
|
console.log(
|
|
1865
|
-
` ${
|
|
1866
|
+
` ${import_chalk6.default.dim("\u2022")} Test coverage target: ${config.rules.testCoverage}% (${root.structure.testPattern})`
|
|
1866
1867
|
);
|
|
1867
1868
|
} else if (config.rules.testCoverage > 0) {
|
|
1868
|
-
console.log(` ${
|
|
1869
|
+
console.log(` ${import_chalk6.default.dim("\u2022")} Test coverage target: ${config.rules.testCoverage}%`);
|
|
1869
1870
|
} else {
|
|
1870
|
-
console.log(` ${
|
|
1871
|
+
console.log(` ${import_chalk6.default.dim("\u2022")} Test coverage target: disabled`);
|
|
1871
1872
|
}
|
|
1872
1873
|
if (config.rules.enforceNaming && root?.conventions?.fileNaming) {
|
|
1873
|
-
console.log(` ${
|
|
1874
|
+
console.log(` ${import_chalk6.default.dim("\u2022")} Enforce file naming: ${root.conventions.fileNaming}`);
|
|
1874
1875
|
} else {
|
|
1875
|
-
console.log(` ${
|
|
1876
|
+
console.log(` ${import_chalk6.default.dim("\u2022")} Enforce file naming: no`);
|
|
1876
1877
|
}
|
|
1877
1878
|
console.log(
|
|
1878
|
-
` ${
|
|
1879
|
+
` ${import_chalk6.default.dim("\u2022")} Enforce boundaries: ${config.rules.enforceBoundaries ? "yes" : "no"}`
|
|
1879
1880
|
);
|
|
1880
1881
|
console.log("");
|
|
1881
1882
|
}
|
|
@@ -2200,7 +2201,7 @@ async function configCommand(options, cwd) {
|
|
|
2200
2201
|
}
|
|
2201
2202
|
const configPath = path9.join(projectRoot, CONFIG_FILE3);
|
|
2202
2203
|
if (!fs10.existsSync(configPath)) {
|
|
2203
|
-
console.log(`${
|
|
2204
|
+
console.log(`${import_chalk7.default.yellow("!")} No config found. Run ${import_chalk7.default.cyan("viberails")} first.`);
|
|
2204
2205
|
return;
|
|
2205
2206
|
}
|
|
2206
2207
|
if (!options.suppressIntro) {
|
|
@@ -2291,22 +2292,22 @@ async function rescanAndMerge(projectRoot, config) {
|
|
|
2291
2292
|
var fs13 = __toESM(require("fs"), 1);
|
|
2292
2293
|
var path13 = __toESM(require("path"), 1);
|
|
2293
2294
|
var import_config7 = require("@viberails/config");
|
|
2294
|
-
var
|
|
2295
|
+
var import_chalk9 = __toESM(require("chalk"), 1);
|
|
2295
2296
|
|
|
2296
2297
|
// src/commands/fix-helpers.ts
|
|
2297
2298
|
var import_node_child_process3 = require("child_process");
|
|
2298
|
-
var
|
|
2299
|
+
var import_chalk8 = __toESM(require("chalk"), 1);
|
|
2299
2300
|
function printPlan(renames, stubs) {
|
|
2300
2301
|
if (renames.length > 0) {
|
|
2301
|
-
console.log(
|
|
2302
|
+
console.log(import_chalk8.default.bold("\nFile renames:"));
|
|
2302
2303
|
for (const r of renames) {
|
|
2303
|
-
console.log(` ${
|
|
2304
|
+
console.log(` ${import_chalk8.default.red(r.oldPath)} \u2192 ${import_chalk8.default.green(r.newPath)}`);
|
|
2304
2305
|
}
|
|
2305
2306
|
}
|
|
2306
2307
|
if (stubs.length > 0) {
|
|
2307
|
-
console.log(
|
|
2308
|
+
console.log(import_chalk8.default.bold("\nTest stubs to create:"));
|
|
2308
2309
|
for (const s of stubs) {
|
|
2309
|
-
console.log(` ${
|
|
2310
|
+
console.log(` ${import_chalk8.default.green("+")} ${s.path}`);
|
|
2310
2311
|
}
|
|
2311
2312
|
}
|
|
2312
2313
|
}
|
|
@@ -2634,13 +2635,13 @@ async function fixCommand(options, cwd) {
|
|
|
2634
2635
|
const startDir = cwd ?? process.cwd();
|
|
2635
2636
|
const projectRoot = findProjectRoot(startDir);
|
|
2636
2637
|
if (!projectRoot) {
|
|
2637
|
-
console.error(`${
|
|
2638
|
+
console.error(`${import_chalk9.default.red("Error:")} No package.json found. Are you in a JS/TS project?`);
|
|
2638
2639
|
return 1;
|
|
2639
2640
|
}
|
|
2640
2641
|
const configPath = path13.join(projectRoot, CONFIG_FILE4);
|
|
2641
2642
|
if (!fs13.existsSync(configPath)) {
|
|
2642
2643
|
console.error(
|
|
2643
|
-
`${
|
|
2644
|
+
`${import_chalk9.default.red("Error:")} No viberails.config.json found. Run \`viberails init\` first.`
|
|
2644
2645
|
);
|
|
2645
2646
|
return 1;
|
|
2646
2647
|
}
|
|
@@ -2649,7 +2650,7 @@ async function fixCommand(options, cwd) {
|
|
|
2649
2650
|
const isDirty = checkGitDirty(projectRoot);
|
|
2650
2651
|
if (isDirty) {
|
|
2651
2652
|
console.log(
|
|
2652
|
-
|
|
2653
|
+
import_chalk9.default.yellow("Warning: You have uncommitted changes. Consider committing first.")
|
|
2653
2654
|
);
|
|
2654
2655
|
}
|
|
2655
2656
|
}
|
|
@@ -2696,41 +2697,41 @@ async function fixCommand(options, cwd) {
|
|
|
2696
2697
|
return blockedOldBareNames.has(bare);
|
|
2697
2698
|
});
|
|
2698
2699
|
if (safeRenames.length === 0 && testStubs.length === 0 && skippedRenames.length === 0) {
|
|
2699
|
-
console.log(`${
|
|
2700
|
+
console.log(`${import_chalk9.default.green("\u2713")} No fixable violations found.`);
|
|
2700
2701
|
return 0;
|
|
2701
2702
|
}
|
|
2702
2703
|
printPlan(safeRenames, testStubs);
|
|
2703
2704
|
if (skippedRenames.length > 0) {
|
|
2704
2705
|
console.log("");
|
|
2705
2706
|
console.log(
|
|
2706
|
-
|
|
2707
|
+
import_chalk9.default.yellow(
|
|
2707
2708
|
`Skipping ${skippedRenames.length} rename${skippedRenames.length > 1 ? "s" : ""} \u2014 aliased imports would break:`
|
|
2708
2709
|
)
|
|
2709
2710
|
);
|
|
2710
2711
|
for (const r of skippedRenames.slice(0, 5)) {
|
|
2711
|
-
console.log(
|
|
2712
|
+
console.log(import_chalk9.default.dim(` ${r.oldPath} \u2192 ${r.newPath}`));
|
|
2712
2713
|
}
|
|
2713
2714
|
if (skippedRenames.length > 5) {
|
|
2714
|
-
console.log(
|
|
2715
|
+
console.log(import_chalk9.default.dim(` ... and ${skippedRenames.length - 5} more`));
|
|
2715
2716
|
}
|
|
2716
2717
|
console.log("");
|
|
2717
|
-
console.log(
|
|
2718
|
+
console.log(import_chalk9.default.yellow("Affected aliased imports:"));
|
|
2718
2719
|
for (const alias of aliasImports.slice(0, 5)) {
|
|
2719
2720
|
const relFile = path13.relative(projectRoot, alias.file);
|
|
2720
|
-
console.log(
|
|
2721
|
+
console.log(import_chalk9.default.dim(` ${relFile}:${alias.line} \u2014 ${alias.specifier}`));
|
|
2721
2722
|
}
|
|
2722
2723
|
if (aliasImports.length > 5) {
|
|
2723
|
-
console.log(
|
|
2724
|
+
console.log(import_chalk9.default.dim(` ... and ${aliasImports.length - 5} more`));
|
|
2724
2725
|
}
|
|
2725
|
-
console.log(
|
|
2726
|
+
console.log(import_chalk9.default.dim(" Update these imports to relative paths first, then re-run fix."));
|
|
2726
2727
|
}
|
|
2727
2728
|
if (safeRenames.length === 0 && testStubs.length === 0) {
|
|
2728
2729
|
console.log(`
|
|
2729
|
-
${
|
|
2730
|
+
${import_chalk9.default.yellow("!")} No safe fixes to apply. Resolve aliased imports first.`);
|
|
2730
2731
|
return 0;
|
|
2731
2732
|
}
|
|
2732
2733
|
if (options.dryRun) {
|
|
2733
|
-
console.log(
|
|
2734
|
+
console.log(import_chalk9.default.dim("\nDry run \u2014 no changes applied."));
|
|
2734
2735
|
return 0;
|
|
2735
2736
|
}
|
|
2736
2737
|
if (!options.yes) {
|
|
@@ -2761,15 +2762,15 @@ ${import_chalk8.default.yellow("!")} No safe fixes to apply. Resolve aliased imp
|
|
|
2761
2762
|
}
|
|
2762
2763
|
console.log("");
|
|
2763
2764
|
if (renameCount > 0) {
|
|
2764
|
-
console.log(`${
|
|
2765
|
+
console.log(`${import_chalk9.default.green("\u2713")} Renamed ${renameCount} file${renameCount > 1 ? "s" : ""}`);
|
|
2765
2766
|
}
|
|
2766
2767
|
if (importUpdateCount > 0) {
|
|
2767
2768
|
console.log(
|
|
2768
|
-
`${
|
|
2769
|
+
`${import_chalk9.default.green("\u2713")} Updated ${importUpdateCount} import${importUpdateCount > 1 ? "s" : ""}`
|
|
2769
2770
|
);
|
|
2770
2771
|
}
|
|
2771
2772
|
if (stubCount > 0) {
|
|
2772
|
-
console.log(`${
|
|
2773
|
+
console.log(`${import_chalk9.default.green("\u2713")} Generated ${stubCount} test stub${stubCount > 1 ? "s" : ""}`);
|
|
2773
2774
|
}
|
|
2774
2775
|
return 0;
|
|
2775
2776
|
}
|
|
@@ -2780,13 +2781,13 @@ var path21 = __toESM(require("path"), 1);
|
|
|
2780
2781
|
var clack13 = __toESM(require("@clack/prompts"), 1);
|
|
2781
2782
|
var import_config9 = require("@viberails/config");
|
|
2782
2783
|
var import_scanner3 = require("@viberails/scanner");
|
|
2783
|
-
var
|
|
2784
|
+
var import_chalk15 = __toESM(require("chalk"), 1);
|
|
2784
2785
|
|
|
2785
2786
|
// src/utils/check-prerequisites.ts
|
|
2786
2787
|
var fs14 = __toESM(require("fs"), 1);
|
|
2787
2788
|
var path14 = __toESM(require("path"), 1);
|
|
2788
2789
|
var clack7 = __toESM(require("@clack/prompts"), 1);
|
|
2789
|
-
var
|
|
2790
|
+
var import_chalk10 = __toESM(require("chalk"), 1);
|
|
2790
2791
|
|
|
2791
2792
|
// src/utils/spawn-async.ts
|
|
2792
2793
|
var import_node_child_process4 = require("child_process");
|
|
@@ -2841,9 +2842,9 @@ function displayMissingPrereqs(prereqs) {
|
|
|
2841
2842
|
const missing = prereqs.filter((p) => !p.installed);
|
|
2842
2843
|
for (const m of missing) {
|
|
2843
2844
|
const suffix = m.affectedPackages ? ` \u2014 needed for coverage in: ${m.affectedPackages.join(", ")}` : ` \u2014 ${m.reason}`;
|
|
2844
|
-
console.log(` ${
|
|
2845
|
+
console.log(` ${import_chalk10.default.yellow("!")} ${m.label} not installed${suffix}`);
|
|
2845
2846
|
if (m.installCommand) {
|
|
2846
|
-
console.log(` Install: ${
|
|
2847
|
+
console.log(` Install: ${import_chalk10.default.cyan(m.installCommand)}`);
|
|
2847
2848
|
}
|
|
2848
2849
|
}
|
|
2849
2850
|
}
|
|
@@ -3168,7 +3169,7 @@ async function handleIntegrations(state, opts) {
|
|
|
3168
3169
|
}
|
|
3169
3170
|
|
|
3170
3171
|
// src/utils/prompt-main-menu-hints.ts
|
|
3171
|
-
var
|
|
3172
|
+
var import_chalk11 = __toESM(require("chalk"), 1);
|
|
3172
3173
|
function fileLimitsHint(config) {
|
|
3173
3174
|
const max = config.rules.maxFileLines;
|
|
3174
3175
|
const test = config.rules.maxTestFileLines;
|
|
@@ -3213,24 +3214,29 @@ function coverageHint(config, hasTestRunner) {
|
|
|
3213
3214
|
}
|
|
3214
3215
|
function advancedNamingHint(config) {
|
|
3215
3216
|
const rootPkg = getRootPackage(config.packages);
|
|
3217
|
+
if (!config.rules.enforceNaming) return "not enforced";
|
|
3216
3218
|
const parts = [];
|
|
3217
|
-
|
|
3218
|
-
|
|
3219
|
-
|
|
3220
|
-
|
|
3221
|
-
|
|
3219
|
+
const naming = rootPkg.conventions?.fileNaming;
|
|
3220
|
+
if (naming) parts.push(import_chalk11.default.green(naming));
|
|
3221
|
+
const comp = rootPkg.conventions?.componentNaming;
|
|
3222
|
+
parts.push(comp ? import_chalk11.default.green(`${comp} components`) : import_chalk11.default.dim("components"));
|
|
3223
|
+
const hook = rootPkg.conventions?.hookNaming;
|
|
3224
|
+
parts.push(hook ? import_chalk11.default.green(`${hook} hooks`) : import_chalk11.default.dim("hooks"));
|
|
3225
|
+
const alias = rootPkg.conventions?.importAlias;
|
|
3226
|
+
parts.push(alias ? import_chalk11.default.green(alias) : import_chalk11.default.dim("alias"));
|
|
3227
|
+
return parts.join(import_chalk11.default.dim(", "));
|
|
3222
3228
|
}
|
|
3223
3229
|
function integrationsHint(state) {
|
|
3224
3230
|
if (!state.visited.integrations || !state.integrations)
|
|
3225
3231
|
return "not configured \u2014 select to set up";
|
|
3226
3232
|
const items = [];
|
|
3227
|
-
if (state.integrations.preCommitHook) items.push("pre-commit");
|
|
3228
|
-
if (state.integrations.typecheckHook) items.push("typecheck");
|
|
3229
|
-
if (state.integrations.lintHook) items.push("lint");
|
|
3230
|
-
if (state.integrations.claudeCodeHook) items.push("Claude");
|
|
3231
|
-
if (state.integrations.claudeMdRef) items.push("CLAUDE.md");
|
|
3232
|
-
if (state.integrations.githubAction) items.push("CI");
|
|
3233
|
-
return items.length > 0 ? items.join(" \xB7 ") : "none selected";
|
|
3233
|
+
if (state.integrations.preCommitHook) items.push(import_chalk11.default.green("pre-commit"));
|
|
3234
|
+
if (state.integrations.typecheckHook) items.push(import_chalk11.default.green("typecheck"));
|
|
3235
|
+
if (state.integrations.lintHook) items.push(import_chalk11.default.green("lint"));
|
|
3236
|
+
if (state.integrations.claudeCodeHook) items.push(import_chalk11.default.green("Claude"));
|
|
3237
|
+
if (state.integrations.claudeMdRef) items.push(import_chalk11.default.green("CLAUDE.md"));
|
|
3238
|
+
if (state.integrations.githubAction) items.push(import_chalk11.default.green("CI"));
|
|
3239
|
+
return items.length > 0 ? items.join(import_chalk11.default.dim(" \xB7 ")) : "none selected";
|
|
3234
3240
|
}
|
|
3235
3241
|
function packageOverridesHint(config) {
|
|
3236
3242
|
const rootNaming = getRootPackage(config.packages).conventions?.fileNaming;
|
|
@@ -3249,8 +3255,9 @@ function boundariesHint(config, state) {
|
|
|
3249
3255
|
return `${ruleCount} rules across ${pkgCount} packages`;
|
|
3250
3256
|
}
|
|
3251
3257
|
function advancedNamingStatus(config) {
|
|
3258
|
+
if (!config.rules.enforceNaming) return "disabled";
|
|
3252
3259
|
const rootPkg = getRootPackage(config.packages);
|
|
3253
|
-
const hasAny = !!rootPkg.conventions?.componentNaming || !!rootPkg.conventions?.hookNaming || !!rootPkg.conventions?.importAlias;
|
|
3260
|
+
const hasAny = !!rootPkg.conventions?.fileNaming || !!rootPkg.conventions?.componentNaming || !!rootPkg.conventions?.hookNaming || !!rootPkg.conventions?.importAlias;
|
|
3254
3261
|
return hasAny ? "ok" : "unconfigured";
|
|
3255
3262
|
}
|
|
3256
3263
|
function packageOverridesStatus(config) {
|
|
@@ -3262,10 +3269,10 @@ function packageOverridesStatus(config) {
|
|
|
3262
3269
|
return customized ? "ok" : "unconfigured";
|
|
3263
3270
|
}
|
|
3264
3271
|
function statusIcon(status) {
|
|
3265
|
-
if (status === "ok") return
|
|
3266
|
-
if (status === "needs-input") return
|
|
3267
|
-
if (status === "unconfigured") return
|
|
3268
|
-
return
|
|
3272
|
+
if (status === "ok") return import_chalk11.default.green("\u2713");
|
|
3273
|
+
if (status === "needs-input") return import_chalk11.default.yellow("?");
|
|
3274
|
+
if (status === "unconfigured") return import_chalk11.default.dim("-");
|
|
3275
|
+
return import_chalk11.default.yellow("~");
|
|
3269
3276
|
}
|
|
3270
3277
|
function buildMainMenuOptions(config, scanResult, state) {
|
|
3271
3278
|
const namingStatus = fileNamingStatus(config);
|
|
@@ -3316,7 +3323,7 @@ function buildMainMenuOptions(config, scanResult, state) {
|
|
|
3316
3323
|
options.push(
|
|
3317
3324
|
{ value: "integrations", label: `${iIcon} Integrations`, hint: integrationsHint(state) },
|
|
3318
3325
|
{ value: "reset", label: " Reset all to defaults" },
|
|
3319
|
-
{ value: "review", label: " Review scan details" },
|
|
3326
|
+
{ value: "review", label: " Review scan details", hint: "detected stack & conventions" },
|
|
3320
3327
|
{ value: "done", label: " Done \u2014 write config" }
|
|
3321
3328
|
);
|
|
3322
3329
|
return options;
|
|
@@ -3396,7 +3403,7 @@ function updateGitignore(projectRoot) {
|
|
|
3396
3403
|
// src/commands/init-hooks.ts
|
|
3397
3404
|
var fs18 = __toESM(require("fs"), 1);
|
|
3398
3405
|
var path18 = __toESM(require("path"), 1);
|
|
3399
|
-
var
|
|
3406
|
+
var import_chalk12 = __toESM(require("chalk"), 1);
|
|
3400
3407
|
var import_yaml = require("yaml");
|
|
3401
3408
|
|
|
3402
3409
|
// src/commands/resolve-typecheck.ts
|
|
@@ -3441,13 +3448,13 @@ function setupPreCommitHook(projectRoot) {
|
|
|
3441
3448
|
const lefthookPath = path18.join(projectRoot, "lefthook.yml");
|
|
3442
3449
|
if (fs18.existsSync(lefthookPath)) {
|
|
3443
3450
|
addLefthookPreCommit(lefthookPath);
|
|
3444
|
-
console.log(` ${
|
|
3451
|
+
console.log(` ${import_chalk12.default.green("\u2713")} lefthook.yml \u2014 added viberails pre-commit`);
|
|
3445
3452
|
return "lefthook.yml";
|
|
3446
3453
|
}
|
|
3447
3454
|
const huskyDir = path18.join(projectRoot, ".husky");
|
|
3448
3455
|
if (fs18.existsSync(huskyDir)) {
|
|
3449
3456
|
writeHuskyPreCommit(huskyDir);
|
|
3450
|
-
console.log(` ${
|
|
3457
|
+
console.log(` ${import_chalk12.default.green("\u2713")} .husky/pre-commit \u2014 added viberails check`);
|
|
3451
3458
|
return ".husky/pre-commit";
|
|
3452
3459
|
}
|
|
3453
3460
|
const gitDir = path18.join(projectRoot, ".git");
|
|
@@ -3457,7 +3464,7 @@ function setupPreCommitHook(projectRoot) {
|
|
|
3457
3464
|
fs18.mkdirSync(hooksDir, { recursive: true });
|
|
3458
3465
|
}
|
|
3459
3466
|
writeGitHookPreCommit(hooksDir);
|
|
3460
|
-
console.log(` ${
|
|
3467
|
+
console.log(` ${import_chalk12.default.green("\u2713")} .git/hooks/pre-commit`);
|
|
3461
3468
|
return ".git/hooks/pre-commit";
|
|
3462
3469
|
}
|
|
3463
3470
|
return void 0;
|
|
@@ -3518,9 +3525,9 @@ function setupClaudeCodeHook(projectRoot) {
|
|
|
3518
3525
|
settings = JSON.parse(fs18.readFileSync(settingsPath, "utf-8"));
|
|
3519
3526
|
} catch {
|
|
3520
3527
|
console.warn(
|
|
3521
|
-
` ${
|
|
3528
|
+
` ${import_chalk12.default.yellow("!")} .claude/settings.json contains invalid JSON \u2014 skipping hook setup`
|
|
3522
3529
|
);
|
|
3523
|
-
console.warn(` Fix the JSON manually, then re-run ${
|
|
3530
|
+
console.warn(` Fix the JSON manually, then re-run ${import_chalk12.default.cyan("viberails init --force")}`);
|
|
3524
3531
|
return;
|
|
3525
3532
|
}
|
|
3526
3533
|
}
|
|
@@ -3543,7 +3550,7 @@ function setupClaudeCodeHook(projectRoot) {
|
|
|
3543
3550
|
settings.hooks = hooks;
|
|
3544
3551
|
fs18.writeFileSync(settingsPath, `${JSON.stringify(settings, null, 2)}
|
|
3545
3552
|
`);
|
|
3546
|
-
console.log(` ${
|
|
3553
|
+
console.log(` ${import_chalk12.default.green("\u2713")} .claude/settings.json \u2014 added viberails PostToolUse hook`);
|
|
3547
3554
|
}
|
|
3548
3555
|
function setupClaudeMdReference(projectRoot) {
|
|
3549
3556
|
const claudeMdPath = path18.join(projectRoot, "CLAUDE.md");
|
|
@@ -3555,7 +3562,7 @@ function setupClaudeMdReference(projectRoot) {
|
|
|
3555
3562
|
const ref = "\n@.viberails/context.md\n";
|
|
3556
3563
|
const prefix = content.length === 0 ? "" : content.trimEnd();
|
|
3557
3564
|
fs18.writeFileSync(claudeMdPath, prefix + ref);
|
|
3558
|
-
console.log(` ${
|
|
3565
|
+
console.log(` ${import_chalk12.default.green("\u2713")} CLAUDE.md \u2014 added @.viberails/context.md reference`);
|
|
3559
3566
|
}
|
|
3560
3567
|
function setupGithubAction(projectRoot, packageManager, options) {
|
|
3561
3568
|
const workflowDir = path18.join(projectRoot, ".github", "workflows");
|
|
@@ -3641,7 +3648,7 @@ ${cmd}
|
|
|
3641
3648
|
// src/commands/init-hooks-extra.ts
|
|
3642
3649
|
var fs19 = __toESM(require("fs"), 1);
|
|
3643
3650
|
var path19 = __toESM(require("path"), 1);
|
|
3644
|
-
var
|
|
3651
|
+
var import_chalk13 = __toESM(require("chalk"), 1);
|
|
3645
3652
|
var import_yaml2 = require("yaml");
|
|
3646
3653
|
function addPreCommitStep(projectRoot, name, command, marker, lefthookExtra) {
|
|
3647
3654
|
const lefthookPath = path19.join(projectRoot, "lefthook.yml");
|
|
@@ -3701,12 +3708,12 @@ ${command}
|
|
|
3701
3708
|
function setupTypecheckHook(projectRoot, packageManager) {
|
|
3702
3709
|
const resolved = resolveTypecheckCommand(projectRoot, packageManager);
|
|
3703
3710
|
if (!resolved.command) {
|
|
3704
|
-
console.log(` ${
|
|
3711
|
+
console.log(` ${import_chalk13.default.yellow("!")} Skipped typecheck hook: ${resolved.reason}`);
|
|
3705
3712
|
return void 0;
|
|
3706
3713
|
}
|
|
3707
3714
|
const target = addPreCommitStep(projectRoot, "typecheck", resolved.command, "typecheck");
|
|
3708
3715
|
if (target) {
|
|
3709
|
-
console.log(` ${
|
|
3716
|
+
console.log(` ${import_chalk13.default.green("\u2713")} ${target} \u2014 added typecheck (${resolved.label})`);
|
|
3710
3717
|
}
|
|
3711
3718
|
return target;
|
|
3712
3719
|
}
|
|
@@ -3727,7 +3734,7 @@ function setupLintHook(projectRoot, linter) {
|
|
|
3727
3734
|
}
|
|
3728
3735
|
const target = addPreCommitStep(projectRoot, "lint", command, linter, lefthookExtra);
|
|
3729
3736
|
if (target) {
|
|
3730
|
-
console.log(` ${
|
|
3737
|
+
console.log(` ${import_chalk13.default.green("\u2713")} ${target} \u2014 added ${linterName} lint check`);
|
|
3731
3738
|
}
|
|
3732
3739
|
return target;
|
|
3733
3740
|
}
|
|
@@ -3736,7 +3743,7 @@ function setupSelectedIntegrations(projectRoot, integrations, opts) {
|
|
|
3736
3743
|
if (integrations.preCommitHook) {
|
|
3737
3744
|
const t = setupPreCommitHook(projectRoot);
|
|
3738
3745
|
if (t && opts.lefthookExpected && !t.includes("lefthook")) {
|
|
3739
|
-
console.log(` ${
|
|
3746
|
+
console.log(` ${import_chalk13.default.yellow("!")} Lefthook install failed \u2014 fell back to ${t}`);
|
|
3740
3747
|
}
|
|
3741
3748
|
created.push(t ? `${t} \u2014 added viberails pre-commit` : "pre-commit hook skipped");
|
|
3742
3749
|
}
|
|
@@ -3772,7 +3779,7 @@ var path20 = __toESM(require("path"), 1);
|
|
|
3772
3779
|
var clack12 = __toESM(require("@clack/prompts"), 1);
|
|
3773
3780
|
var import_config8 = require("@viberails/config");
|
|
3774
3781
|
var import_scanner2 = require("@viberails/scanner");
|
|
3775
|
-
var
|
|
3782
|
+
var import_chalk14 = __toESM(require("chalk"), 1);
|
|
3776
3783
|
|
|
3777
3784
|
// src/utils/filter-confidence.ts
|
|
3778
3785
|
function filterHighConfidence(conventions, meta) {
|
|
@@ -3808,7 +3815,7 @@ async function initNonInteractive(projectRoot, configPath) {
|
|
|
3808
3815
|
const exempted = getExemptedPackages(config);
|
|
3809
3816
|
if (exempted.length > 0) {
|
|
3810
3817
|
console.log(
|
|
3811
|
-
` ${
|
|
3818
|
+
` ${import_chalk14.default.dim("Auto-exempted from coverage:")} ${exempted.join(", ")} ${import_chalk14.default.dim("(types-only)")}`
|
|
3812
3819
|
);
|
|
3813
3820
|
}
|
|
3814
3821
|
if (config.packages.length > 1) {
|
|
@@ -3845,14 +3852,14 @@ async function initNonInteractive(projectRoot, configPath) {
|
|
|
3845
3852
|
const hookManager = detectHookManager(projectRoot);
|
|
3846
3853
|
const hasHookManager = hookManager === "Lefthook" || hookManager === "Husky";
|
|
3847
3854
|
const preCommitTarget = hasHookManager ? setupPreCommitHook(projectRoot) : void 0;
|
|
3848
|
-
const ok =
|
|
3855
|
+
const ok = import_chalk14.default.green("\u2713");
|
|
3849
3856
|
const created = [
|
|
3850
3857
|
`${ok} ${path20.basename(configPath)}`,
|
|
3851
3858
|
`${ok} .viberails/context.md`,
|
|
3852
3859
|
`${ok} .viberails/scan-result.json`,
|
|
3853
3860
|
`${ok} .claude/settings.json \u2014 added viberails hook`,
|
|
3854
3861
|
`${ok} CLAUDE.md \u2014 added @.viberails/context.md reference`,
|
|
3855
|
-
preCommitTarget ? `${ok} ${preCommitTarget}` : `${
|
|
3862
|
+
preCommitTarget ? `${ok} ${preCommitTarget}` : `${import_chalk14.default.yellow("!")} pre-commit hook skipped (install lefthook or husky)`,
|
|
3856
3863
|
actionTarget ? `${ok} ${actionTarget} \u2014 blocks PRs on violations` : ""
|
|
3857
3864
|
].filter(Boolean);
|
|
3858
3865
|
if (hasHookManager && isTypeScript) setupTypecheckHook(projectRoot, rootPkgPm);
|
|
@@ -3877,8 +3884,8 @@ async function initCommand(options, cwd) {
|
|
|
3877
3884
|
return initInteractive(projectRoot, configPath, options);
|
|
3878
3885
|
}
|
|
3879
3886
|
console.log(
|
|
3880
|
-
`${
|
|
3881
|
-
Run ${
|
|
3887
|
+
`${import_chalk15.default.yellow("!")} viberails is already initialized.
|
|
3888
|
+
Run ${import_chalk15.default.cyan("viberails")} to review or edit the existing setup, ${import_chalk15.default.cyan("viberails sync")} to update generated files, or ${import_chalk15.default.cyan("viberails init --force")} to replace it.`
|
|
3882
3889
|
);
|
|
3883
3890
|
return;
|
|
3884
3891
|
}
|
|
@@ -3955,7 +3962,7 @@ async function initInteractive(projectRoot, configPath, options) {
|
|
|
3955
3962
|
writeGeneratedFiles(projectRoot, config, scanResult);
|
|
3956
3963
|
updateGitignore(projectRoot);
|
|
3957
3964
|
ws.stop("Configuration written");
|
|
3958
|
-
const ok =
|
|
3965
|
+
const ok = import_chalk15.default.green("\u2713");
|
|
3959
3966
|
clack13.log.step(`${ok} ${path21.basename(configPath)}`);
|
|
3960
3967
|
clack13.log.step(`${ok} .viberails/context.md`);
|
|
3961
3968
|
clack13.log.step(`${ok} .viberails/scan-result.json`);
|
|
@@ -3969,7 +3976,7 @@ async function initInteractive(projectRoot, configPath, options) {
|
|
|
3969
3976
|
}
|
|
3970
3977
|
clack13.outro(
|
|
3971
3978
|
`Done! Next: review viberails.config.json, then run viberails check
|
|
3972
|
-
${
|
|
3979
|
+
${import_chalk15.default.dim("Tip: use")} ${import_chalk15.default.cyan("viberails check --enforce")} ${import_chalk15.default.dim("in CI to block PRs on violations.")}`
|
|
3973
3980
|
);
|
|
3974
3981
|
}
|
|
3975
3982
|
|
|
@@ -3979,7 +3986,7 @@ var path22 = __toESM(require("path"), 1);
|
|
|
3979
3986
|
var clack14 = __toESM(require("@clack/prompts"), 1);
|
|
3980
3987
|
var import_config11 = require("@viberails/config");
|
|
3981
3988
|
var import_scanner4 = require("@viberails/scanner");
|
|
3982
|
-
var
|
|
3989
|
+
var import_chalk16 = __toESM(require("chalk"), 1);
|
|
3983
3990
|
var CONFIG_FILE6 = "viberails.config.json";
|
|
3984
3991
|
var SCAN_RESULT_FILE2 = ".viberails/scan-result.json";
|
|
3985
3992
|
function loadPreviousStats(projectRoot) {
|
|
@@ -4020,13 +4027,13 @@ async function syncCommand(options, cwd) {
|
|
|
4020
4027
|
const statsDelta = previousStats ? formatStatsDelta(previousStats, scanResult.statistics) : void 0;
|
|
4021
4028
|
if (changes.length > 0 || statsDelta) {
|
|
4022
4029
|
console.log(`
|
|
4023
|
-
${
|
|
4030
|
+
${import_chalk16.default.bold("Changes:")}`);
|
|
4024
4031
|
for (const change of changes) {
|
|
4025
|
-
const icon = change.type === "removed" ?
|
|
4032
|
+
const icon = change.type === "removed" ? import_chalk16.default.red("-") : import_chalk16.default.green("+");
|
|
4026
4033
|
console.log(` ${icon} ${change.description}`);
|
|
4027
4034
|
}
|
|
4028
4035
|
if (statsDelta) {
|
|
4029
|
-
console.log(` ${
|
|
4036
|
+
console.log(` ${import_chalk16.default.dim(statsDelta)}`);
|
|
4030
4037
|
}
|
|
4031
4038
|
}
|
|
4032
4039
|
if (options?.interactive) {
|
|
@@ -4075,18 +4082,18 @@ ${import_chalk15.default.bold("Changes:")}`);
|
|
|
4075
4082
|
`);
|
|
4076
4083
|
writeGeneratedFiles(projectRoot, merged, scanResult);
|
|
4077
4084
|
console.log(`
|
|
4078
|
-
${
|
|
4085
|
+
${import_chalk16.default.bold("Synced:")}`);
|
|
4079
4086
|
if (configChanged) {
|
|
4080
|
-
console.log(` ${
|
|
4087
|
+
console.log(` ${import_chalk16.default.yellow("!")} ${CONFIG_FILE6} \u2014 updated (review changes)`);
|
|
4081
4088
|
} else {
|
|
4082
|
-
console.log(` ${
|
|
4089
|
+
console.log(` ${import_chalk16.default.green("\u2713")} ${CONFIG_FILE6} \u2014 unchanged`);
|
|
4083
4090
|
}
|
|
4084
|
-
console.log(` ${
|
|
4085
|
-
console.log(` ${
|
|
4091
|
+
console.log(` ${import_chalk16.default.green("\u2713")} .viberails/context.md \u2014 regenerated`);
|
|
4092
|
+
console.log(` ${import_chalk16.default.green("\u2713")} .viberails/scan-result.json \u2014 updated`);
|
|
4086
4093
|
}
|
|
4087
4094
|
|
|
4088
4095
|
// src/index.ts
|
|
4089
|
-
var VERSION = "0.6.
|
|
4096
|
+
var VERSION = "0.6.8";
|
|
4090
4097
|
var program = new import_commander.Command();
|
|
4091
4098
|
program.name("viberails").description("Guardrails for vibe coding").version(VERSION);
|
|
4092
4099
|
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) => {
|
|
@@ -4094,7 +4101,7 @@ program.command("init", { isDefault: true }).description("Scan your project and
|
|
|
4094
4101
|
await initCommand(options);
|
|
4095
4102
|
} catch (err) {
|
|
4096
4103
|
const message = err instanceof Error ? err.message : String(err);
|
|
4097
|
-
console.error(`${
|
|
4104
|
+
console.error(`${import_chalk17.default.red("Error:")} ${message}`);
|
|
4098
4105
|
process.exit(1);
|
|
4099
4106
|
}
|
|
4100
4107
|
});
|
|
@@ -4103,7 +4110,7 @@ program.command("sync").description("Re-scan and update generated files").option
|
|
|
4103
4110
|
await syncCommand(options);
|
|
4104
4111
|
} catch (err) {
|
|
4105
4112
|
const message = err instanceof Error ? err.message : String(err);
|
|
4106
|
-
console.error(`${
|
|
4113
|
+
console.error(`${import_chalk17.default.red("Error:")} ${message}`);
|
|
4107
4114
|
process.exit(1);
|
|
4108
4115
|
}
|
|
4109
4116
|
});
|
|
@@ -4112,7 +4119,7 @@ program.command("config").description("Interactively edit existing config rules"
|
|
|
4112
4119
|
await configCommand(options);
|
|
4113
4120
|
} catch (err) {
|
|
4114
4121
|
const message = err instanceof Error ? err.message : String(err);
|
|
4115
|
-
console.error(`${
|
|
4122
|
+
console.error(`${import_chalk17.default.red("Error:")} ${message}`);
|
|
4116
4123
|
process.exit(1);
|
|
4117
4124
|
}
|
|
4118
4125
|
});
|
|
@@ -4133,7 +4140,7 @@ program.command("check").description("Check files against enforced rules").optio
|
|
|
4133
4140
|
process.exit(exitCode);
|
|
4134
4141
|
} catch (err) {
|
|
4135
4142
|
const message = err instanceof Error ? err.message : String(err);
|
|
4136
|
-
console.error(`${
|
|
4143
|
+
console.error(`${import_chalk17.default.red("Error:")} ${message}`);
|
|
4137
4144
|
process.exit(1);
|
|
4138
4145
|
}
|
|
4139
4146
|
}
|
|
@@ -4144,7 +4151,7 @@ program.command("fix").description("Auto-fix file naming violations and generate
|
|
|
4144
4151
|
process.exit(exitCode);
|
|
4145
4152
|
} catch (err) {
|
|
4146
4153
|
const message = err instanceof Error ? err.message : String(err);
|
|
4147
|
-
console.error(`${
|
|
4154
|
+
console.error(`${import_chalk17.default.red("Error:")} ${message}`);
|
|
4148
4155
|
process.exit(1);
|
|
4149
4156
|
}
|
|
4150
4157
|
});
|
|
@@ -4153,7 +4160,7 @@ program.command("boundaries").description("Display, infer, or inspect import bou
|
|
|
4153
4160
|
await boundariesCommand(options);
|
|
4154
4161
|
} catch (err) {
|
|
4155
4162
|
const message = err instanceof Error ? err.message : String(err);
|
|
4156
|
-
console.error(`${
|
|
4163
|
+
console.error(`${import_chalk17.default.red("Error:")} ${message}`);
|
|
4157
4164
|
process.exit(1);
|
|
4158
4165
|
}
|
|
4159
4166
|
});
|