viberails 0.2.3 → 0.3.0
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 +329 -294
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +329 -294
- package/dist/index.js.map +1 -1
- package/package.json +7 -6
package/dist/index.cjs
CHANGED
|
@@ -34,7 +34,7 @@ __export(index_exports, {
|
|
|
34
34
|
VERSION: () => VERSION
|
|
35
35
|
});
|
|
36
36
|
module.exports = __toCommonJS(index_exports);
|
|
37
|
-
var
|
|
37
|
+
var import_chalk11 = __toESM(require("chalk"), 1);
|
|
38
38
|
var import_commander = require("commander");
|
|
39
39
|
|
|
40
40
|
// src/commands/boundaries.ts
|
|
@@ -99,7 +99,7 @@ function resolveWorkspacePackages(projectRoot, workspace) {
|
|
|
99
99
|
];
|
|
100
100
|
packages.push({ name, path: absPath, relativePath, internalDeps: allDeps });
|
|
101
101
|
}
|
|
102
|
-
const packageNames = new Set(packages.map((
|
|
102
|
+
const packageNames = new Set(packages.map((p3) => p3.name));
|
|
103
103
|
for (const pkg of packages) {
|
|
104
104
|
pkg.internalDeps = pkg.internalDeps.filter((dep) => packageNames.has(dep));
|
|
105
105
|
}
|
|
@@ -129,23 +129,37 @@ async function boundariesCommand(options, cwd) {
|
|
|
129
129
|
}
|
|
130
130
|
displayRules(config);
|
|
131
131
|
}
|
|
132
|
+
function countBoundaries(boundaries) {
|
|
133
|
+
if (!boundaries) return 0;
|
|
134
|
+
if (Array.isArray(boundaries)) return boundaries.length;
|
|
135
|
+
return Object.values(boundaries).reduce((sum, denied) => sum + denied.length, 0);
|
|
136
|
+
}
|
|
132
137
|
function displayRules(config) {
|
|
133
|
-
|
|
138
|
+
const total = countBoundaries(config.boundaries);
|
|
139
|
+
if (total === 0) {
|
|
134
140
|
console.log(import_chalk.default.yellow("No boundary rules configured."));
|
|
135
141
|
console.log(`Run ${import_chalk.default.cyan("viberails boundaries --infer")} to generate rules.`);
|
|
136
142
|
return;
|
|
137
143
|
}
|
|
138
|
-
const allowRules = config.boundaries.filter((r) => r.allow);
|
|
139
|
-
const denyRules = config.boundaries.filter((r) => !r.allow);
|
|
140
144
|
console.log(`
|
|
141
|
-
${import_chalk.default.bold(`Boundary rules (${
|
|
145
|
+
${import_chalk.default.bold(`Boundary rules (${total} rules):`)}
|
|
142
146
|
`);
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
147
|
+
if (Array.isArray(config.boundaries)) {
|
|
148
|
+
const allowRules = config.boundaries.filter((r) => r.allow);
|
|
149
|
+
const denyRules = config.boundaries.filter((r) => !r.allow);
|
|
150
|
+
for (const r of allowRules) {
|
|
151
|
+
console.log(` ${import_chalk.default.green("\u2713")} ${r.from} \u2192 ${r.to}`);
|
|
152
|
+
}
|
|
153
|
+
for (const r of denyRules) {
|
|
154
|
+
const reason = r.reason ? import_chalk.default.dim(` (${r.reason})`) : "";
|
|
155
|
+
console.log(` ${import_chalk.default.red("\u2717")} ${r.from} \u2192 ${r.to}${reason}`);
|
|
156
|
+
}
|
|
157
|
+
} else if (config.boundaries) {
|
|
158
|
+
for (const [from, denied] of Object.entries(config.boundaries)) {
|
|
159
|
+
for (const to of denied) {
|
|
160
|
+
console.log(` ${import_chalk.default.red("\u2717")} ${from} \u2192 ${to}`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
149
163
|
}
|
|
150
164
|
console.log(
|
|
151
165
|
`
|
|
@@ -162,31 +176,29 @@ async function inferAndDisplay(projectRoot, config, configPath) {
|
|
|
162
176
|
});
|
|
163
177
|
console.log(import_chalk.default.dim(`${graph.nodes.length} files, ${graph.edges.length} edges`));
|
|
164
178
|
const inferred = inferBoundaries(graph);
|
|
165
|
-
|
|
179
|
+
const entries = Object.entries(inferred);
|
|
180
|
+
if (entries.length === 0) {
|
|
166
181
|
console.log(import_chalk.default.yellow("No boundary rules could be inferred."));
|
|
167
182
|
return;
|
|
168
183
|
}
|
|
169
|
-
const
|
|
170
|
-
const deny = inferred.filter((r) => !r.allow);
|
|
184
|
+
const totalRules = entries.reduce((sum, [, denied]) => sum + denied.length, 0);
|
|
171
185
|
console.log(`
|
|
172
186
|
${import_chalk.default.bold("Inferred boundary rules:")}
|
|
173
187
|
`);
|
|
174
|
-
for (const
|
|
175
|
-
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
const reason = r.reason ? import_chalk.default.dim(` (${r.reason})`) : "";
|
|
179
|
-
console.log(` ${import_chalk.default.red("\u2717")} ${r.from} \u2192 ${r.to}${reason}`);
|
|
188
|
+
for (const [from, denied] of entries) {
|
|
189
|
+
for (const to of denied) {
|
|
190
|
+
console.log(` ${import_chalk.default.red("\u2717")} ${from} \u2192 ${to}`);
|
|
191
|
+
}
|
|
180
192
|
}
|
|
181
193
|
console.log(`
|
|
182
|
-
${
|
|
194
|
+
${totalRules} deny rules`);
|
|
183
195
|
const shouldSave = await confirm("\nSave to viberails.config.json?");
|
|
184
196
|
if (shouldSave) {
|
|
185
197
|
config.boundaries = inferred;
|
|
186
198
|
config.rules.enforceBoundaries = true;
|
|
187
199
|
fs3.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}
|
|
188
200
|
`);
|
|
189
|
-
console.log(`${import_chalk.default.green("\u2713")} Saved ${
|
|
201
|
+
console.log(`${import_chalk.default.green("\u2713")} Saved ${totalRules} rules`);
|
|
190
202
|
}
|
|
191
203
|
}
|
|
192
204
|
async function showGraph(projectRoot, config) {
|
|
@@ -560,7 +572,8 @@ async function checkCommand(options, cwd) {
|
|
|
560
572
|
const testViolations = checkMissingTests(projectRoot, config, severity);
|
|
561
573
|
violations.push(...testViolations);
|
|
562
574
|
}
|
|
563
|
-
|
|
575
|
+
const hasBoundaries = config.boundaries ? Array.isArray(config.boundaries) ? config.boundaries.length > 0 : Object.keys(config.boundaries).length > 0 : false;
|
|
576
|
+
if (config.rules.enforceBoundaries && hasBoundaries && !options.noBoundaries) {
|
|
564
577
|
const startTime = Date.now();
|
|
565
578
|
const { buildImportGraph, checkBoundaries } = await import("@viberails/graph");
|
|
566
579
|
const packages = config.workspace ? resolveWorkspacePackages(projectRoot, config.workspace) : void 0;
|
|
@@ -965,223 +978,10 @@ async function fixCommand(options, cwd) {
|
|
|
965
978
|
// src/commands/init.ts
|
|
966
979
|
var fs12 = __toESM(require("fs"), 1);
|
|
967
980
|
var path13 = __toESM(require("path"), 1);
|
|
981
|
+
var p2 = __toESM(require("@clack/prompts"), 1);
|
|
968
982
|
var import_config4 = require("@viberails/config");
|
|
969
983
|
var import_scanner = require("@viberails/scanner");
|
|
970
|
-
var
|
|
971
|
-
|
|
972
|
-
// src/display.ts
|
|
973
|
-
var import_types3 = require("@viberails/types");
|
|
974
|
-
var import_chalk6 = __toESM(require("chalk"), 1);
|
|
975
|
-
|
|
976
|
-
// src/display-helpers.ts
|
|
977
|
-
var import_types = require("@viberails/types");
|
|
978
|
-
function groupByRole(directories) {
|
|
979
|
-
const map = /* @__PURE__ */ new Map();
|
|
980
|
-
for (const dir of directories) {
|
|
981
|
-
if (dir.role === "unknown") continue;
|
|
982
|
-
const existing = map.get(dir.role);
|
|
983
|
-
if (existing) {
|
|
984
|
-
existing.dirs.push(dir);
|
|
985
|
-
} else {
|
|
986
|
-
map.set(dir.role, { dirs: [dir] });
|
|
987
|
-
}
|
|
988
|
-
}
|
|
989
|
-
const groups = [];
|
|
990
|
-
for (const [role, { dirs }] of map) {
|
|
991
|
-
const label = import_types.ROLE_DESCRIPTIONS[role] ?? role;
|
|
992
|
-
const totalFiles = dirs.reduce((sum, d) => sum + d.fileCount, 0);
|
|
993
|
-
groups.push({
|
|
994
|
-
role,
|
|
995
|
-
label,
|
|
996
|
-
dirCount: dirs.length,
|
|
997
|
-
totalFiles,
|
|
998
|
-
singlePath: dirs.length === 1 ? dirs[0].path : void 0
|
|
999
|
-
});
|
|
1000
|
-
}
|
|
1001
|
-
return groups;
|
|
1002
|
-
}
|
|
1003
|
-
function formatSummary(stats, packageCount) {
|
|
1004
|
-
const parts = [];
|
|
1005
|
-
if (packageCount && packageCount > 1) {
|
|
1006
|
-
parts.push(`${packageCount} packages`);
|
|
1007
|
-
}
|
|
1008
|
-
parts.push(`${stats.totalFiles.toLocaleString()} source files`);
|
|
1009
|
-
parts.push(`${stats.totalLines.toLocaleString()} lines`);
|
|
1010
|
-
parts.push(`avg ${Math.round(stats.averageFileLines)} lines/file`);
|
|
1011
|
-
return parts.join(" \xB7 ");
|
|
1012
|
-
}
|
|
1013
|
-
function formatExtensions(filesByExtension, maxEntries = 4) {
|
|
1014
|
-
return Object.entries(filesByExtension).sort(([, a], [, b]) => b - a).slice(0, maxEntries).map(([ext, count]) => `${ext} ${count}`).join(" \xB7 ");
|
|
1015
|
-
}
|
|
1016
|
-
function formatRoleGroup(group) {
|
|
1017
|
-
const files = group.totalFiles === 1 ? "1 file" : `${group.totalFiles} files`;
|
|
1018
|
-
if (group.singlePath) {
|
|
1019
|
-
return `${group.label} \u2014 ${group.singlePath} (${files})`;
|
|
1020
|
-
}
|
|
1021
|
-
const dirs = group.dirCount === 1 ? "1 dir" : `${group.dirCount} dirs`;
|
|
1022
|
-
return `${group.label} \u2014 ${dirs} (${files})`;
|
|
1023
|
-
}
|
|
1024
|
-
|
|
1025
|
-
// src/display-monorepo.ts
|
|
1026
|
-
var import_types2 = require("@viberails/types");
|
|
1027
|
-
var import_chalk5 = __toESM(require("chalk"), 1);
|
|
1028
|
-
function formatPackageSummary(pkg) {
|
|
1029
|
-
const parts = [];
|
|
1030
|
-
if (pkg.stack.framework) {
|
|
1031
|
-
parts.push(formatItem(pkg.stack.framework, import_types2.FRAMEWORK_NAMES));
|
|
1032
|
-
}
|
|
1033
|
-
if (pkg.stack.styling) {
|
|
1034
|
-
parts.push(formatItem(pkg.stack.styling, import_types2.STYLING_NAMES));
|
|
1035
|
-
}
|
|
1036
|
-
const files = `${pkg.statistics.totalFiles} files`;
|
|
1037
|
-
const detail = parts.length > 0 ? `${parts.join(", ")} (${files})` : `(${files})`;
|
|
1038
|
-
return ` ${pkg.relativePath} \u2014 ${detail}`;
|
|
1039
|
-
}
|
|
1040
|
-
function displayMonorepoResults(scanResult) {
|
|
1041
|
-
const { stack, packages } = scanResult;
|
|
1042
|
-
console.log(`
|
|
1043
|
-
${import_chalk5.default.bold(`Detected: (monorepo, ${packages.length} packages)`)}`);
|
|
1044
|
-
console.log(` ${import_chalk5.default.green("\u2713")} ${formatItem(stack.language)}`);
|
|
1045
|
-
if (stack.packageManager) {
|
|
1046
|
-
console.log(` ${import_chalk5.default.green("\u2713")} ${formatItem(stack.packageManager)}`);
|
|
1047
|
-
}
|
|
1048
|
-
if (stack.linter) {
|
|
1049
|
-
console.log(` ${import_chalk5.default.green("\u2713")} ${formatItem(stack.linter)}`);
|
|
1050
|
-
}
|
|
1051
|
-
if (stack.formatter) {
|
|
1052
|
-
console.log(` ${import_chalk5.default.green("\u2713")} ${formatItem(stack.formatter)}`);
|
|
1053
|
-
}
|
|
1054
|
-
if (stack.testRunner) {
|
|
1055
|
-
console.log(` ${import_chalk5.default.green("\u2713")} ${formatItem(stack.testRunner)}`);
|
|
1056
|
-
}
|
|
1057
|
-
console.log("");
|
|
1058
|
-
for (const pkg of packages) {
|
|
1059
|
-
console.log(formatPackageSummary(pkg));
|
|
1060
|
-
}
|
|
1061
|
-
const packagesWithDirs = packages.filter(
|
|
1062
|
-
(pkg) => pkg.structure.directories.some((d) => d.role !== "unknown")
|
|
1063
|
-
);
|
|
1064
|
-
if (packagesWithDirs.length > 0) {
|
|
1065
|
-
console.log(`
|
|
1066
|
-
${import_chalk5.default.bold("Structure:")}`);
|
|
1067
|
-
for (const pkg of packagesWithDirs) {
|
|
1068
|
-
const groups = groupByRole(pkg.structure.directories);
|
|
1069
|
-
if (groups.length === 0) continue;
|
|
1070
|
-
console.log(` ${pkg.relativePath}:`);
|
|
1071
|
-
for (const group of groups) {
|
|
1072
|
-
console.log(` ${import_chalk5.default.green("\u2713")} ${formatRoleGroup(group)}`);
|
|
1073
|
-
}
|
|
1074
|
-
}
|
|
1075
|
-
}
|
|
1076
|
-
displayConventions(scanResult);
|
|
1077
|
-
displaySummarySection(scanResult);
|
|
1078
|
-
console.log("");
|
|
1079
|
-
}
|
|
1080
|
-
|
|
1081
|
-
// src/display.ts
|
|
1082
|
-
var CONVENTION_LABELS = {
|
|
1083
|
-
fileNaming: "File naming",
|
|
1084
|
-
componentNaming: "Component naming",
|
|
1085
|
-
hookNaming: "Hook naming",
|
|
1086
|
-
importAlias: "Import alias"
|
|
1087
|
-
};
|
|
1088
|
-
function formatItem(item, nameMap) {
|
|
1089
|
-
const name = nameMap?.[item.name] ?? item.name;
|
|
1090
|
-
return item.version ? `${name} ${item.version}` : name;
|
|
1091
|
-
}
|
|
1092
|
-
function confidenceLabel(convention) {
|
|
1093
|
-
const pct = Math.round(convention.consistency);
|
|
1094
|
-
if (convention.confidence === "high") {
|
|
1095
|
-
return `${pct}% \u2014 high confidence, will enforce`;
|
|
1096
|
-
}
|
|
1097
|
-
return `${pct}% \u2014 medium confidence, suggested only`;
|
|
1098
|
-
}
|
|
1099
|
-
function displayConventions(scanResult) {
|
|
1100
|
-
const conventionEntries = Object.entries(scanResult.conventions);
|
|
1101
|
-
if (conventionEntries.length === 0) return;
|
|
1102
|
-
console.log(`
|
|
1103
|
-
${import_chalk6.default.bold("Conventions:")}`);
|
|
1104
|
-
for (const [key, convention] of conventionEntries) {
|
|
1105
|
-
if (convention.confidence === "low") continue;
|
|
1106
|
-
const label = CONVENTION_LABELS[key] ?? key;
|
|
1107
|
-
if (scanResult.packages.length > 1) {
|
|
1108
|
-
const pkgValues = scanResult.packages.filter((pkg) => pkg.conventions[key] && pkg.conventions[key].confidence !== "low").map((pkg) => ({ relativePath: pkg.relativePath, convention: pkg.conventions[key] }));
|
|
1109
|
-
const allSame = pkgValues.every((pv) => pv.convention.value === convention.value);
|
|
1110
|
-
if (allSame || pkgValues.length <= 1) {
|
|
1111
|
-
const ind = convention.confidence === "high" ? import_chalk6.default.green("\u2713") : import_chalk6.default.yellow("~");
|
|
1112
|
-
const detail = import_chalk6.default.dim(`(${confidenceLabel(convention)})`);
|
|
1113
|
-
console.log(` ${ind} ${label}: ${convention.value} ${detail}`);
|
|
1114
|
-
} else {
|
|
1115
|
-
console.log(` ${import_chalk6.default.yellow("~")} ${label}: varies by package`);
|
|
1116
|
-
for (const pv of pkgValues) {
|
|
1117
|
-
const pct = Math.round(pv.convention.consistency);
|
|
1118
|
-
console.log(` ${pv.relativePath}: ${pv.convention.value} (${pct}%)`);
|
|
1119
|
-
}
|
|
1120
|
-
}
|
|
1121
|
-
} else {
|
|
1122
|
-
const ind = convention.confidence === "high" ? import_chalk6.default.green("\u2713") : import_chalk6.default.yellow("~");
|
|
1123
|
-
const detail = import_chalk6.default.dim(`(${confidenceLabel(convention)})`);
|
|
1124
|
-
console.log(` ${ind} ${label}: ${convention.value} ${detail}`);
|
|
1125
|
-
}
|
|
1126
|
-
}
|
|
1127
|
-
}
|
|
1128
|
-
function displaySummarySection(scanResult) {
|
|
1129
|
-
const pkgCount = scanResult.packages.length > 1 ? scanResult.packages.length : void 0;
|
|
1130
|
-
console.log(`
|
|
1131
|
-
${import_chalk6.default.bold("Summary:")}`);
|
|
1132
|
-
console.log(` ${formatSummary(scanResult.statistics, pkgCount)}`);
|
|
1133
|
-
const ext = formatExtensions(scanResult.statistics.filesByExtension);
|
|
1134
|
-
if (ext) {
|
|
1135
|
-
console.log(` ${ext}`);
|
|
1136
|
-
}
|
|
1137
|
-
}
|
|
1138
|
-
function displayScanResults(scanResult) {
|
|
1139
|
-
if (scanResult.packages.length > 1) {
|
|
1140
|
-
displayMonorepoResults(scanResult);
|
|
1141
|
-
return;
|
|
1142
|
-
}
|
|
1143
|
-
const { stack } = scanResult;
|
|
1144
|
-
console.log(`
|
|
1145
|
-
${import_chalk6.default.bold("Detected:")}`);
|
|
1146
|
-
if (stack.framework) {
|
|
1147
|
-
console.log(` ${import_chalk6.default.green("\u2713")} ${formatItem(stack.framework, import_types3.FRAMEWORK_NAMES)}`);
|
|
1148
|
-
}
|
|
1149
|
-
console.log(` ${import_chalk6.default.green("\u2713")} ${formatItem(stack.language)}`);
|
|
1150
|
-
if (stack.styling) {
|
|
1151
|
-
console.log(` ${import_chalk6.default.green("\u2713")} ${formatItem(stack.styling, import_types3.STYLING_NAMES)}`);
|
|
1152
|
-
}
|
|
1153
|
-
if (stack.backend) {
|
|
1154
|
-
console.log(` ${import_chalk6.default.green("\u2713")} ${formatItem(stack.backend, import_types3.FRAMEWORK_NAMES)}`);
|
|
1155
|
-
}
|
|
1156
|
-
if (stack.linter) {
|
|
1157
|
-
console.log(` ${import_chalk6.default.green("\u2713")} ${formatItem(stack.linter)}`);
|
|
1158
|
-
}
|
|
1159
|
-
if (stack.formatter) {
|
|
1160
|
-
console.log(` ${import_chalk6.default.green("\u2713")} ${formatItem(stack.formatter)}`);
|
|
1161
|
-
}
|
|
1162
|
-
if (stack.testRunner) {
|
|
1163
|
-
console.log(` ${import_chalk6.default.green("\u2713")} ${formatItem(stack.testRunner)}`);
|
|
1164
|
-
}
|
|
1165
|
-
if (stack.packageManager) {
|
|
1166
|
-
console.log(` ${import_chalk6.default.green("\u2713")} ${formatItem(stack.packageManager)}`);
|
|
1167
|
-
}
|
|
1168
|
-
if (stack.libraries.length > 0) {
|
|
1169
|
-
for (const lib of stack.libraries) {
|
|
1170
|
-
console.log(` ${import_chalk6.default.green("\u2713")} ${formatItem(lib, import_types3.LIBRARY_NAMES)}`);
|
|
1171
|
-
}
|
|
1172
|
-
}
|
|
1173
|
-
const groups = groupByRole(scanResult.structure.directories);
|
|
1174
|
-
if (groups.length > 0) {
|
|
1175
|
-
console.log(`
|
|
1176
|
-
${import_chalk6.default.bold("Structure:")}`);
|
|
1177
|
-
for (const group of groups) {
|
|
1178
|
-
console.log(` ${import_chalk6.default.green("\u2713")} ${formatRoleGroup(group)}`);
|
|
1179
|
-
}
|
|
1180
|
-
}
|
|
1181
|
-
displayConventions(scanResult);
|
|
1182
|
-
displaySummarySection(scanResult);
|
|
1183
|
-
console.log("");
|
|
1184
|
-
}
|
|
984
|
+
var import_chalk9 = __toESM(require("chalk"), 1);
|
|
1185
985
|
|
|
1186
986
|
// src/utils/write-generated-files.ts
|
|
1187
987
|
var fs10 = __toESM(require("fs"), 1);
|
|
@@ -1212,18 +1012,60 @@ function writeGeneratedFiles(projectRoot, config, scanResult) {
|
|
|
1212
1012
|
// src/commands/init-hooks.ts
|
|
1213
1013
|
var fs11 = __toESM(require("fs"), 1);
|
|
1214
1014
|
var path12 = __toESM(require("path"), 1);
|
|
1215
|
-
var
|
|
1015
|
+
var import_chalk5 = __toESM(require("chalk"), 1);
|
|
1016
|
+
function setupClaudeCodeHook(projectRoot) {
|
|
1017
|
+
const claudeDir = path12.join(projectRoot, ".claude");
|
|
1018
|
+
if (!fs11.existsSync(claudeDir)) {
|
|
1019
|
+
fs11.mkdirSync(claudeDir, { recursive: true });
|
|
1020
|
+
}
|
|
1021
|
+
const settingsPath = path12.join(claudeDir, "settings.json");
|
|
1022
|
+
let settings = {};
|
|
1023
|
+
if (fs11.existsSync(settingsPath)) {
|
|
1024
|
+
try {
|
|
1025
|
+
settings = JSON.parse(fs11.readFileSync(settingsPath, "utf-8"));
|
|
1026
|
+
} catch {
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
const hooks = settings.hooks ?? {};
|
|
1030
|
+
const postToolUse = hooks.PostToolUse;
|
|
1031
|
+
if (Array.isArray(postToolUse)) {
|
|
1032
|
+
const hasViberails = postToolUse.some(
|
|
1033
|
+
(entry) => typeof entry === "object" && entry !== null && Array.isArray(entry.hooks) && entry.hooks.some(
|
|
1034
|
+
(h) => typeof h === "object" && h !== null && typeof h.command === "string" && h.command.includes("viberails")
|
|
1035
|
+
)
|
|
1036
|
+
);
|
|
1037
|
+
if (hasViberails) return;
|
|
1038
|
+
}
|
|
1039
|
+
const viberailsHook = {
|
|
1040
|
+
matcher: "Edit|Write",
|
|
1041
|
+
hooks: [
|
|
1042
|
+
{
|
|
1043
|
+
type: "command",
|
|
1044
|
+
command: "jq -r '.tool_input.file_path' | xargs npx viberails check --files"
|
|
1045
|
+
}
|
|
1046
|
+
]
|
|
1047
|
+
};
|
|
1048
|
+
if (!hooks.PostToolUse) {
|
|
1049
|
+
hooks.PostToolUse = [viberailsHook];
|
|
1050
|
+
} else if (Array.isArray(hooks.PostToolUse)) {
|
|
1051
|
+
hooks.PostToolUse.push(viberailsHook);
|
|
1052
|
+
}
|
|
1053
|
+
settings.hooks = hooks;
|
|
1054
|
+
fs11.writeFileSync(settingsPath, `${JSON.stringify(settings, null, 2)}
|
|
1055
|
+
`);
|
|
1056
|
+
console.log(` ${import_chalk5.default.green("\u2713")} .claude/settings.json \u2014 added viberails PostToolUse hook`);
|
|
1057
|
+
}
|
|
1216
1058
|
function setupPreCommitHook(projectRoot) {
|
|
1217
1059
|
const lefthookPath = path12.join(projectRoot, "lefthook.yml");
|
|
1218
1060
|
if (fs11.existsSync(lefthookPath)) {
|
|
1219
1061
|
addLefthookPreCommit(lefthookPath);
|
|
1220
|
-
console.log(` ${
|
|
1062
|
+
console.log(` ${import_chalk5.default.green("\u2713")} lefthook.yml \u2014 added viberails pre-commit`);
|
|
1221
1063
|
return;
|
|
1222
1064
|
}
|
|
1223
1065
|
const huskyDir = path12.join(projectRoot, ".husky");
|
|
1224
1066
|
if (fs11.existsSync(huskyDir)) {
|
|
1225
1067
|
writeHuskyPreCommit(huskyDir);
|
|
1226
|
-
console.log(` ${
|
|
1068
|
+
console.log(` ${import_chalk5.default.green("\u2713")} .husky/pre-commit \u2014 added viberails check`);
|
|
1227
1069
|
return;
|
|
1228
1070
|
}
|
|
1229
1071
|
const gitDir = path12.join(projectRoot, ".git");
|
|
@@ -1233,7 +1075,7 @@ function setupPreCommitHook(projectRoot) {
|
|
|
1233
1075
|
fs11.mkdirSync(hooksDir, { recursive: true });
|
|
1234
1076
|
}
|
|
1235
1077
|
writeGitHookPreCommit(hooksDir);
|
|
1236
|
-
console.log(` ${
|
|
1078
|
+
console.log(` ${import_chalk5.default.green("\u2713")} .git/hooks/pre-commit`);
|
|
1237
1079
|
}
|
|
1238
1080
|
}
|
|
1239
1081
|
function writeGitHookPreCommit(hooksDir) {
|
|
@@ -1282,6 +1124,187 @@ npx viberails check --staged
|
|
|
1282
1124
|
fs11.writeFileSync(hookPath, "#!/bin/sh\nnpx viberails check --staged\n", { mode: 493 });
|
|
1283
1125
|
}
|
|
1284
1126
|
|
|
1127
|
+
// src/commands/init-wizard.ts
|
|
1128
|
+
var p = __toESM(require("@clack/prompts"), 1);
|
|
1129
|
+
var import_types4 = require("@viberails/types");
|
|
1130
|
+
var import_chalk8 = __toESM(require("chalk"), 1);
|
|
1131
|
+
|
|
1132
|
+
// src/display.ts
|
|
1133
|
+
var import_types3 = require("@viberails/types");
|
|
1134
|
+
var import_chalk7 = __toESM(require("chalk"), 1);
|
|
1135
|
+
|
|
1136
|
+
// src/display-helpers.ts
|
|
1137
|
+
var import_types = require("@viberails/types");
|
|
1138
|
+
function groupByRole(directories) {
|
|
1139
|
+
const map = /* @__PURE__ */ new Map();
|
|
1140
|
+
for (const dir of directories) {
|
|
1141
|
+
if (dir.role === "unknown") continue;
|
|
1142
|
+
const existing = map.get(dir.role);
|
|
1143
|
+
if (existing) {
|
|
1144
|
+
existing.dirs.push(dir);
|
|
1145
|
+
} else {
|
|
1146
|
+
map.set(dir.role, { dirs: [dir] });
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
const groups = [];
|
|
1150
|
+
for (const [role, { dirs }] of map) {
|
|
1151
|
+
const label = import_types.ROLE_DESCRIPTIONS[role] ?? role;
|
|
1152
|
+
const totalFiles = dirs.reduce((sum, d) => sum + d.fileCount, 0);
|
|
1153
|
+
groups.push({
|
|
1154
|
+
role,
|
|
1155
|
+
label,
|
|
1156
|
+
dirCount: dirs.length,
|
|
1157
|
+
totalFiles,
|
|
1158
|
+
singlePath: dirs.length === 1 ? dirs[0].path : void 0
|
|
1159
|
+
});
|
|
1160
|
+
}
|
|
1161
|
+
return groups;
|
|
1162
|
+
}
|
|
1163
|
+
function formatSummary(stats, packageCount) {
|
|
1164
|
+
const parts = [];
|
|
1165
|
+
if (packageCount && packageCount > 1) {
|
|
1166
|
+
parts.push(`${packageCount} packages`);
|
|
1167
|
+
}
|
|
1168
|
+
parts.push(`${stats.totalFiles.toLocaleString()} source files`);
|
|
1169
|
+
parts.push(`${stats.totalLines.toLocaleString()} lines`);
|
|
1170
|
+
parts.push(`avg ${Math.round(stats.averageFileLines)} lines/file`);
|
|
1171
|
+
return parts.join(" \xB7 ");
|
|
1172
|
+
}
|
|
1173
|
+
function formatRoleGroup(group) {
|
|
1174
|
+
const files = group.totalFiles === 1 ? "1 file" : `${group.totalFiles} files`;
|
|
1175
|
+
if (group.singlePath) {
|
|
1176
|
+
return `${group.label} \u2014 ${group.singlePath} (${files})`;
|
|
1177
|
+
}
|
|
1178
|
+
const dirs = group.dirCount === 1 ? "1 dir" : `${group.dirCount} dirs`;
|
|
1179
|
+
return `${group.label} \u2014 ${dirs} (${files})`;
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
// src/display-monorepo.ts
|
|
1183
|
+
var import_types2 = require("@viberails/types");
|
|
1184
|
+
var import_chalk6 = __toESM(require("chalk"), 1);
|
|
1185
|
+
|
|
1186
|
+
// src/display.ts
|
|
1187
|
+
function formatItem(item, nameMap) {
|
|
1188
|
+
const name = nameMap?.[item.name] ?? item.name;
|
|
1189
|
+
return item.version ? `${name} ${item.version}` : name;
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
// src/commands/init-wizard.ts
|
|
1193
|
+
var DEFAULT_WIZARD_RESULT = {
|
|
1194
|
+
enforcement: "warn",
|
|
1195
|
+
checks: {
|
|
1196
|
+
fileSize: true,
|
|
1197
|
+
naming: true,
|
|
1198
|
+
tests: true,
|
|
1199
|
+
boundaries: false
|
|
1200
|
+
},
|
|
1201
|
+
integration: ["pre-commit"]
|
|
1202
|
+
};
|
|
1203
|
+
async function runWizard(scanResult) {
|
|
1204
|
+
const isMonorepo = scanResult.packages.length > 1;
|
|
1205
|
+
displayScanSummary(scanResult);
|
|
1206
|
+
const enforcement = await p.select({
|
|
1207
|
+
message: "How strict should viberails be?",
|
|
1208
|
+
initialValue: "warn",
|
|
1209
|
+
options: [
|
|
1210
|
+
{ value: "warn", label: "Warn", hint: "show issues, never block commits" },
|
|
1211
|
+
{ value: "enforce", label: "Enforce", hint: "block commits with violations" }
|
|
1212
|
+
]
|
|
1213
|
+
});
|
|
1214
|
+
if (p.isCancel(enforcement)) {
|
|
1215
|
+
p.cancel("Setup cancelled.");
|
|
1216
|
+
return null;
|
|
1217
|
+
}
|
|
1218
|
+
const checkOptions = [
|
|
1219
|
+
{ value: "fileSize", label: "File size limit (300 lines)" },
|
|
1220
|
+
{ value: "naming", label: "File naming conventions" },
|
|
1221
|
+
{ value: "tests", label: "Missing test files" }
|
|
1222
|
+
];
|
|
1223
|
+
if (isMonorepo) {
|
|
1224
|
+
checkOptions.push({ value: "boundaries", label: "Import boundaries" });
|
|
1225
|
+
}
|
|
1226
|
+
const enabledChecks = await p.multiselect({
|
|
1227
|
+
message: "Which checks should viberails run?",
|
|
1228
|
+
options: checkOptions,
|
|
1229
|
+
initialValues: ["fileSize", "naming", "tests"],
|
|
1230
|
+
required: false
|
|
1231
|
+
});
|
|
1232
|
+
if (p.isCancel(enabledChecks)) {
|
|
1233
|
+
p.cancel("Setup cancelled.");
|
|
1234
|
+
return null;
|
|
1235
|
+
}
|
|
1236
|
+
const checks = {
|
|
1237
|
+
fileSize: enabledChecks.includes("fileSize"),
|
|
1238
|
+
naming: enabledChecks.includes("naming"),
|
|
1239
|
+
tests: enabledChecks.includes("tests"),
|
|
1240
|
+
boundaries: enabledChecks.includes("boundaries")
|
|
1241
|
+
};
|
|
1242
|
+
const integrationOptions = [
|
|
1243
|
+
{ value: "pre-commit", label: "Git pre-commit hook", hint: "runs on every commit" },
|
|
1244
|
+
{
|
|
1245
|
+
value: "claude-hook",
|
|
1246
|
+
label: "Claude Code hook",
|
|
1247
|
+
hint: "checks files as Claude edits them"
|
|
1248
|
+
},
|
|
1249
|
+
{ value: "context-only", label: "Context files only", hint: "no hooks" }
|
|
1250
|
+
];
|
|
1251
|
+
const integration = await p.multiselect({
|
|
1252
|
+
message: "Where should checks run?",
|
|
1253
|
+
options: integrationOptions,
|
|
1254
|
+
initialValues: ["pre-commit"],
|
|
1255
|
+
required: true
|
|
1256
|
+
});
|
|
1257
|
+
if (p.isCancel(integration)) {
|
|
1258
|
+
p.cancel("Setup cancelled.");
|
|
1259
|
+
return null;
|
|
1260
|
+
}
|
|
1261
|
+
const finalIntegration = integration.includes("context-only") ? ["context-only"] : integration;
|
|
1262
|
+
return {
|
|
1263
|
+
enforcement,
|
|
1264
|
+
checks,
|
|
1265
|
+
integration: finalIntegration
|
|
1266
|
+
};
|
|
1267
|
+
}
|
|
1268
|
+
function displayScanSummary(scanResult) {
|
|
1269
|
+
const { stack } = scanResult;
|
|
1270
|
+
const parts = [];
|
|
1271
|
+
if (stack.framework) parts.push(formatItem(stack.framework, import_types4.FRAMEWORK_NAMES));
|
|
1272
|
+
parts.push(formatItem(stack.language));
|
|
1273
|
+
if (stack.styling) parts.push(formatItem(stack.styling, import_types4.STYLING_NAMES));
|
|
1274
|
+
if (stack.backend) parts.push(formatItem(stack.backend, import_types4.FRAMEWORK_NAMES));
|
|
1275
|
+
p.log.info(`${import_chalk8.default.bold("Stack:")} ${parts.join(", ")}`);
|
|
1276
|
+
if (stack.linter || stack.formatter || stack.testRunner || stack.packageManager) {
|
|
1277
|
+
const tools = [];
|
|
1278
|
+
if (stack.linter) tools.push(formatItem(stack.linter));
|
|
1279
|
+
if (stack.formatter && stack.formatter !== stack.linter)
|
|
1280
|
+
tools.push(formatItem(stack.formatter));
|
|
1281
|
+
if (stack.testRunner) tools.push(formatItem(stack.testRunner));
|
|
1282
|
+
if (stack.packageManager) tools.push(formatItem(stack.packageManager));
|
|
1283
|
+
p.log.info(`${import_chalk8.default.bold("Tools:")} ${tools.join(", ")}`);
|
|
1284
|
+
}
|
|
1285
|
+
if (stack.libraries.length > 0) {
|
|
1286
|
+
const libs = stack.libraries.map((lib) => formatItem(lib, import_types4.LIBRARY_NAMES)).join(", ");
|
|
1287
|
+
p.log.info(`${import_chalk8.default.bold("Libraries:")} ${libs}`);
|
|
1288
|
+
}
|
|
1289
|
+
const groups = groupByRole(scanResult.structure.directories);
|
|
1290
|
+
if (groups.length > 0) {
|
|
1291
|
+
const structParts = groups.map((g) => formatRoleGroup(g));
|
|
1292
|
+
p.log.info(`${import_chalk8.default.bold("Structure:")} ${structParts.join(", ")}`);
|
|
1293
|
+
}
|
|
1294
|
+
const conventionEntries = Object.entries(scanResult.conventions).filter(
|
|
1295
|
+
([, c]) => c.confidence !== "low"
|
|
1296
|
+
);
|
|
1297
|
+
if (conventionEntries.length > 0) {
|
|
1298
|
+
const convParts = conventionEntries.map(([, c]) => {
|
|
1299
|
+
const pct = Math.round(c.consistency);
|
|
1300
|
+
return `${c.value} (${pct}%)`;
|
|
1301
|
+
});
|
|
1302
|
+
p.log.info(`${import_chalk8.default.bold("Conventions:")} ${convParts.join(", ")}`);
|
|
1303
|
+
}
|
|
1304
|
+
const pkgCount = scanResult.packages.length > 1 ? scanResult.packages.length : void 0;
|
|
1305
|
+
p.log.info(`${import_chalk8.default.bold("Summary:")} ${formatSummary(scanResult.statistics, pkgCount)}`);
|
|
1306
|
+
}
|
|
1307
|
+
|
|
1285
1308
|
// src/commands/init.ts
|
|
1286
1309
|
var CONFIG_FILE4 = "viberails.config.json";
|
|
1287
1310
|
function filterHighConfidence(conventions) {
|
|
@@ -1296,6 +1319,13 @@ function filterHighConfidence(conventions) {
|
|
|
1296
1319
|
}
|
|
1297
1320
|
return filtered;
|
|
1298
1321
|
}
|
|
1322
|
+
function applyWizardResult(config, wizard) {
|
|
1323
|
+
config.enforcement = wizard.enforcement;
|
|
1324
|
+
if (!wizard.checks.fileSize) config.rules.maxFileLines = 0;
|
|
1325
|
+
config.rules.enforceNaming = wizard.checks.naming;
|
|
1326
|
+
config.rules.requireTests = wizard.checks.tests;
|
|
1327
|
+
config.rules.enforceBoundaries = wizard.checks.boundaries;
|
|
1328
|
+
}
|
|
1299
1329
|
async function initCommand(options, cwd) {
|
|
1300
1330
|
const startDir = cwd ?? process.cwd();
|
|
1301
1331
|
const projectRoot = findProjectRoot(startDir);
|
|
@@ -1307,64 +1337,69 @@ async function initCommand(options, cwd) {
|
|
|
1307
1337
|
const configPath = path13.join(projectRoot, CONFIG_FILE4);
|
|
1308
1338
|
if (fs12.existsSync(configPath)) {
|
|
1309
1339
|
console.log(
|
|
1310
|
-
|
|
1340
|
+
import_chalk9.default.yellow("!") + " viberails is already initialized in this project.\n Run " + import_chalk9.default.cyan("viberails sync") + " to update the generated files."
|
|
1311
1341
|
);
|
|
1312
1342
|
return;
|
|
1313
1343
|
}
|
|
1314
|
-
|
|
1344
|
+
p2.intro("viberails");
|
|
1345
|
+
const s = p2.spinner();
|
|
1346
|
+
s.start("Scanning project...");
|
|
1315
1347
|
const scanResult = await (0, import_scanner.scan)(projectRoot);
|
|
1316
|
-
|
|
1348
|
+
s.stop("Scan complete");
|
|
1317
1349
|
if (scanResult.statistics.totalFiles === 0) {
|
|
1318
|
-
|
|
1319
|
-
|
|
1350
|
+
p2.log.warn(
|
|
1351
|
+
`No source files detected. viberails will generate context with minimal content.
|
|
1352
|
+
Run ${import_chalk9.default.cyan("viberails sync")} after adding source files.`
|
|
1320
1353
|
);
|
|
1321
1354
|
}
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1355
|
+
let wizard;
|
|
1356
|
+
if (options.yes) {
|
|
1357
|
+
wizard = { ...DEFAULT_WIZARD_RESULT };
|
|
1358
|
+
} else {
|
|
1359
|
+
const result = await runWizard(scanResult);
|
|
1360
|
+
if (!result) return;
|
|
1361
|
+
wizard = result;
|
|
1328
1362
|
}
|
|
1329
1363
|
const config = (0, import_config4.generateConfig)(scanResult);
|
|
1330
1364
|
if (options.yes) {
|
|
1331
1365
|
config.conventions = filterHighConfidence(config.conventions);
|
|
1332
1366
|
}
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
console.log(` ${import_chalk8.default.green("\u2713")} Inferred ${inferred.length} boundary rules`);
|
|
1348
|
-
}
|
|
1367
|
+
applyWizardResult(config, wizard);
|
|
1368
|
+
if (wizard.checks.boundaries && config.workspace && config.workspace.packages.length > 0) {
|
|
1369
|
+
s.start("Inferring boundary rules...");
|
|
1370
|
+
const { buildImportGraph, inferBoundaries } = await import("@viberails/graph");
|
|
1371
|
+
const packages = resolveWorkspacePackages(projectRoot, config.workspace);
|
|
1372
|
+
const graph = await buildImportGraph(projectRoot, { packages, ignore: config.ignore });
|
|
1373
|
+
const inferred = inferBoundaries(graph);
|
|
1374
|
+
const ruleCount = Object.values(inferred).reduce((sum, denied) => sum + denied.length, 0);
|
|
1375
|
+
if (ruleCount > 0) {
|
|
1376
|
+
config.boundaries = inferred;
|
|
1377
|
+
s.stop(`Inferred ${ruleCount} boundary rules`);
|
|
1378
|
+
} else {
|
|
1379
|
+
s.stop("No boundary rules could be inferred");
|
|
1380
|
+
config.rules.enforceBoundaries = false;
|
|
1349
1381
|
}
|
|
1350
1382
|
}
|
|
1351
1383
|
fs12.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}
|
|
1352
1384
|
`);
|
|
1353
1385
|
writeGeneratedFiles(projectRoot, config, scanResult);
|
|
1354
1386
|
updateGitignore(projectRoot);
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
${
|
|
1363
|
-
console.log(`
|
|
1364
|
-
console.log(
|
|
1365
|
-
|
|
1387
|
+
if (wizard.integration.includes("pre-commit")) {
|
|
1388
|
+
setupPreCommitHook(projectRoot);
|
|
1389
|
+
}
|
|
1390
|
+
if (wizard.integration.includes("claude-hook")) {
|
|
1391
|
+
setupClaudeCodeHook(projectRoot);
|
|
1392
|
+
}
|
|
1393
|
+
p2.log.success(`${import_chalk9.default.bold("Created:")}`);
|
|
1394
|
+
console.log(` ${import_chalk9.default.green("\u2713")} ${CONFIG_FILE4}`);
|
|
1395
|
+
console.log(` ${import_chalk9.default.green("\u2713")} .viberails/context.md`);
|
|
1396
|
+
console.log(` ${import_chalk9.default.green("\u2713")} .viberails/scan-result.json`);
|
|
1397
|
+
p2.outro(
|
|
1398
|
+
`${import_chalk9.default.bold("Next steps:")}
|
|
1399
|
+
1. Review ${import_chalk9.default.cyan("viberails.config.json")} and adjust rules
|
|
1400
|
+
2. Commit ${import_chalk9.default.cyan("viberails.config.json")} and ${import_chalk9.default.cyan(".viberails/context.md")}
|
|
1401
|
+
3. Run ${import_chalk9.default.cyan("viberails check")} to verify your project passes`
|
|
1366
1402
|
);
|
|
1367
|
-
console.log(` 3. Run ${import_chalk8.default.cyan("viberails check")} to verify your project passes`);
|
|
1368
1403
|
}
|
|
1369
1404
|
function updateGitignore(projectRoot) {
|
|
1370
1405
|
const gitignorePath = path13.join(projectRoot, ".gitignore");
|
|
@@ -1384,7 +1419,7 @@ var fs13 = __toESM(require("fs"), 1);
|
|
|
1384
1419
|
var path14 = __toESM(require("path"), 1);
|
|
1385
1420
|
var import_config5 = require("@viberails/config");
|
|
1386
1421
|
var import_scanner2 = require("@viberails/scanner");
|
|
1387
|
-
var
|
|
1422
|
+
var import_chalk10 = __toESM(require("chalk"), 1);
|
|
1388
1423
|
var CONFIG_FILE5 = "viberails.config.json";
|
|
1389
1424
|
async function syncCommand(cwd) {
|
|
1390
1425
|
const startDir = cwd ?? process.cwd();
|
|
@@ -1396,21 +1431,21 @@ async function syncCommand(cwd) {
|
|
|
1396
1431
|
}
|
|
1397
1432
|
const configPath = path14.join(projectRoot, CONFIG_FILE5);
|
|
1398
1433
|
const existing = await (0, import_config5.loadConfig)(configPath);
|
|
1399
|
-
console.log(
|
|
1434
|
+
console.log(import_chalk10.default.dim("Scanning project..."));
|
|
1400
1435
|
const scanResult = await (0, import_scanner2.scan)(projectRoot);
|
|
1401
1436
|
const merged = (0, import_config5.mergeConfig)(existing, scanResult);
|
|
1402
1437
|
fs13.writeFileSync(configPath, `${JSON.stringify(merged, null, 2)}
|
|
1403
1438
|
`);
|
|
1404
1439
|
writeGeneratedFiles(projectRoot, merged, scanResult);
|
|
1405
1440
|
console.log(`
|
|
1406
|
-
${
|
|
1407
|
-
console.log(` ${
|
|
1408
|
-
console.log(` ${
|
|
1409
|
-
console.log(` ${
|
|
1441
|
+
${import_chalk10.default.bold("Synced:")}`);
|
|
1442
|
+
console.log(` ${import_chalk10.default.green("\u2713")} ${CONFIG_FILE5} \u2014 updated`);
|
|
1443
|
+
console.log(` ${import_chalk10.default.green("\u2713")} .viberails/context.md \u2014 regenerated`);
|
|
1444
|
+
console.log(` ${import_chalk10.default.green("\u2713")} .viberails/scan-result.json \u2014 updated`);
|
|
1410
1445
|
}
|
|
1411
1446
|
|
|
1412
1447
|
// src/index.ts
|
|
1413
|
-
var VERSION = "0.
|
|
1448
|
+
var VERSION = "0.3.0";
|
|
1414
1449
|
var program = new import_commander.Command();
|
|
1415
1450
|
program.name("viberails").description("Guardrails for vibe coding").version(VERSION);
|
|
1416
1451
|
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)").action(async (options) => {
|
|
@@ -1418,7 +1453,7 @@ program.command("init", { isDefault: true }).description("Scan your project and
|
|
|
1418
1453
|
await initCommand(options);
|
|
1419
1454
|
} catch (err) {
|
|
1420
1455
|
const message = err instanceof Error ? err.message : String(err);
|
|
1421
|
-
console.error(`${
|
|
1456
|
+
console.error(`${import_chalk11.default.red("Error:")} ${message}`);
|
|
1422
1457
|
process.exit(1);
|
|
1423
1458
|
}
|
|
1424
1459
|
});
|
|
@@ -1427,7 +1462,7 @@ program.command("sync").description("Re-scan and update generated files").action
|
|
|
1427
1462
|
await syncCommand();
|
|
1428
1463
|
} catch (err) {
|
|
1429
1464
|
const message = err instanceof Error ? err.message : String(err);
|
|
1430
|
-
console.error(`${
|
|
1465
|
+
console.error(`${import_chalk11.default.red("Error:")} ${message}`);
|
|
1431
1466
|
process.exit(1);
|
|
1432
1467
|
}
|
|
1433
1468
|
});
|
|
@@ -1441,7 +1476,7 @@ program.command("check").description("Check files against enforced rules").optio
|
|
|
1441
1476
|
process.exit(exitCode);
|
|
1442
1477
|
} catch (err) {
|
|
1443
1478
|
const message = err instanceof Error ? err.message : String(err);
|
|
1444
|
-
console.error(`${
|
|
1479
|
+
console.error(`${import_chalk11.default.red("Error:")} ${message}`);
|
|
1445
1480
|
process.exit(1);
|
|
1446
1481
|
}
|
|
1447
1482
|
}
|
|
@@ -1452,7 +1487,7 @@ program.command("fix").description("Auto-fix file naming violations and generate
|
|
|
1452
1487
|
process.exit(exitCode);
|
|
1453
1488
|
} catch (err) {
|
|
1454
1489
|
const message = err instanceof Error ? err.message : String(err);
|
|
1455
|
-
console.error(`${
|
|
1490
|
+
console.error(`${import_chalk11.default.red("Error:")} ${message}`);
|
|
1456
1491
|
process.exit(1);
|
|
1457
1492
|
}
|
|
1458
1493
|
});
|
|
@@ -1461,7 +1496,7 @@ program.command("boundaries").description("Display, infer, or inspect import bou
|
|
|
1461
1496
|
await boundariesCommand(options);
|
|
1462
1497
|
} catch (err) {
|
|
1463
1498
|
const message = err instanceof Error ? err.message : String(err);
|
|
1464
|
-
console.error(`${
|
|
1499
|
+
console.error(`${import_chalk11.default.red("Error:")} ${message}`);
|
|
1465
1500
|
process.exit(1);
|
|
1466
1501
|
}
|
|
1467
1502
|
});
|