viberails 0.6.2 → 0.6.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +215 -55
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +212 -52
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
package/dist/index.cjs
CHANGED
|
@@ -64,11 +64,34 @@ function findProjectRoot(startDir) {
|
|
|
64
64
|
var clack5 = __toESM(require("@clack/prompts"), 1);
|
|
65
65
|
|
|
66
66
|
// src/utils/prompt-integrations.ts
|
|
67
|
-
var import_node_child_process = require("child_process");
|
|
68
67
|
var clack = __toESM(require("@clack/prompts"), 1);
|
|
68
|
+
|
|
69
|
+
// src/utils/spawn-async.ts
|
|
70
|
+
var import_node_child_process = require("child_process");
|
|
71
|
+
function spawnAsync(command, cwd) {
|
|
72
|
+
return new Promise((resolve4) => {
|
|
73
|
+
const child = (0, import_node_child_process.spawn)(command, { cwd, shell: true, stdio: "pipe" });
|
|
74
|
+
let stdout = "";
|
|
75
|
+
let stderr = "";
|
|
76
|
+
child.stdout.on("data", (d) => {
|
|
77
|
+
stdout += d.toString();
|
|
78
|
+
});
|
|
79
|
+
child.stderr.on("data", (d) => {
|
|
80
|
+
stderr += d.toString();
|
|
81
|
+
});
|
|
82
|
+
child.on("close", (status) => {
|
|
83
|
+
resolve4({ status, stdout, stderr });
|
|
84
|
+
});
|
|
85
|
+
child.on("error", () => {
|
|
86
|
+
resolve4({ status: 1, stdout, stderr });
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// src/utils/prompt-integrations.ts
|
|
69
92
|
async function promptHookManagerInstall(projectRoot, packageManager, isWorkspace) {
|
|
70
93
|
const choice = await clack.select({
|
|
71
|
-
message: "No git hook manager detected. Install Lefthook
|
|
94
|
+
message: "No shared git hook manager detected. Install Lefthook?",
|
|
72
95
|
options: [
|
|
73
96
|
{
|
|
74
97
|
value: "install",
|
|
@@ -88,12 +111,7 @@ async function promptHookManagerInstall(projectRoot, packageManager, isWorkspace
|
|
|
88
111
|
const installCmd = pm === "yarn" ? "yarn add -D lefthook" : pm === "pnpm" ? `pnpm add -D${isWorkspace ? " -w" : ""} lefthook` : "npm install -D lefthook";
|
|
89
112
|
const s = clack.spinner();
|
|
90
113
|
s.start("Installing Lefthook...");
|
|
91
|
-
const result =
|
|
92
|
-
cwd: projectRoot,
|
|
93
|
-
shell: true,
|
|
94
|
-
encoding: "utf-8",
|
|
95
|
-
stdio: "pipe"
|
|
96
|
-
});
|
|
114
|
+
const result = await spawnAsync(installCmd, projectRoot);
|
|
97
115
|
if (result.status === 0) {
|
|
98
116
|
const fs21 = await import("fs");
|
|
99
117
|
const path21 = await import("path");
|
|
@@ -161,7 +179,7 @@ async function promptIntegrations(projectRoot, hookManager, tools) {
|
|
|
161
179
|
);
|
|
162
180
|
const initialValues = isBareHook ? options.filter((o) => o.value !== "preCommit").map((o) => o.value) : options.map((o) => o.value);
|
|
163
181
|
const result = await clack.multiselect({
|
|
164
|
-
message: "
|
|
182
|
+
message: "Optional integrations",
|
|
165
183
|
options,
|
|
166
184
|
initialValues,
|
|
167
185
|
required: false
|
|
@@ -568,16 +586,49 @@ async function confirmDangerous(message) {
|
|
|
568
586
|
assertNotCancelled(result);
|
|
569
587
|
return result;
|
|
570
588
|
}
|
|
589
|
+
async function promptExistingConfigAction(configFile) {
|
|
590
|
+
const result = await clack5.select({
|
|
591
|
+
message: `${configFile} already exists. What do you want to do?`,
|
|
592
|
+
options: [
|
|
593
|
+
{
|
|
594
|
+
value: "edit",
|
|
595
|
+
label: "Edit existing config",
|
|
596
|
+
hint: "open the current rules and save updates in place"
|
|
597
|
+
},
|
|
598
|
+
{
|
|
599
|
+
value: "replace",
|
|
600
|
+
label: "Replace with a fresh scan",
|
|
601
|
+
hint: "re-scan the project and overwrite the current config"
|
|
602
|
+
},
|
|
603
|
+
{
|
|
604
|
+
value: "cancel",
|
|
605
|
+
label: "Cancel",
|
|
606
|
+
hint: "leave the current setup unchanged"
|
|
607
|
+
}
|
|
608
|
+
]
|
|
609
|
+
});
|
|
610
|
+
assertNotCancelled(result);
|
|
611
|
+
return result;
|
|
612
|
+
}
|
|
571
613
|
async function promptInitDecision() {
|
|
572
614
|
const result = await clack5.select({
|
|
573
|
-
message: "
|
|
615
|
+
message: "How do you want to proceed?",
|
|
574
616
|
options: [
|
|
575
617
|
{
|
|
576
618
|
value: "accept",
|
|
577
|
-
label: "
|
|
578
|
-
hint: "
|
|
619
|
+
label: "Accept defaults",
|
|
620
|
+
hint: "writes the config with these defaults; use --enforce in CI to block"
|
|
579
621
|
},
|
|
580
|
-
{
|
|
622
|
+
{
|
|
623
|
+
value: "customize",
|
|
624
|
+
label: "Customize rules",
|
|
625
|
+
hint: "edit limits, naming, test coverage, and package overrides"
|
|
626
|
+
},
|
|
627
|
+
{
|
|
628
|
+
value: "review",
|
|
629
|
+
label: "Review detected details",
|
|
630
|
+
hint: "show the full scan report with package and structure details"
|
|
631
|
+
}
|
|
581
632
|
]
|
|
582
633
|
});
|
|
583
634
|
assertNotCancelled(result);
|
|
@@ -1624,6 +1675,15 @@ function formatMonorepoResultsText(scanResult) {
|
|
|
1624
1675
|
}
|
|
1625
1676
|
|
|
1626
1677
|
// src/display.ts
|
|
1678
|
+
var INIT_OVERVIEW_NAMES = {
|
|
1679
|
+
typescript: "TypeScript",
|
|
1680
|
+
javascript: "JavaScript",
|
|
1681
|
+
eslint: "ESLint",
|
|
1682
|
+
prettier: "Prettier",
|
|
1683
|
+
jest: "Jest",
|
|
1684
|
+
vitest: "Vitest",
|
|
1685
|
+
biome: "Biome"
|
|
1686
|
+
};
|
|
1627
1687
|
function formatItem(item, nameMap) {
|
|
1628
1688
|
const name = nameMap?.[item.name] ?? item.name;
|
|
1629
1689
|
return item.version ? `${name} ${item.version}` : name;
|
|
@@ -1753,11 +1813,40 @@ function displayRulesPreview(config) {
|
|
|
1753
1813
|
);
|
|
1754
1814
|
console.log("");
|
|
1755
1815
|
}
|
|
1756
|
-
function
|
|
1816
|
+
function formatDetectedOverview(scanResult) {
|
|
1817
|
+
const { stack } = scanResult;
|
|
1818
|
+
const primaryParts = [];
|
|
1819
|
+
const secondaryParts = [];
|
|
1820
|
+
const formatOverviewItem = (item, nameMap) => formatItem(item, { ...INIT_OVERVIEW_NAMES, ...nameMap });
|
|
1821
|
+
if (scanResult.packages.length > 1) {
|
|
1822
|
+
primaryParts.push("monorepo");
|
|
1823
|
+
primaryParts.push(`${scanResult.packages.length} packages`);
|
|
1824
|
+
} else if (stack.framework) {
|
|
1825
|
+
primaryParts.push(formatItem(stack.framework, import_types3.FRAMEWORK_NAMES));
|
|
1826
|
+
} else {
|
|
1827
|
+
primaryParts.push("single package");
|
|
1828
|
+
}
|
|
1829
|
+
primaryParts.push(formatOverviewItem(stack.language));
|
|
1830
|
+
if (stack.styling) {
|
|
1831
|
+
primaryParts.push(formatOverviewItem(stack.styling, import_types3.STYLING_NAMES));
|
|
1832
|
+
}
|
|
1833
|
+
if (stack.packageManager) secondaryParts.push(formatOverviewItem(stack.packageManager));
|
|
1834
|
+
if (stack.linter) secondaryParts.push(formatOverviewItem(stack.linter));
|
|
1835
|
+
if (stack.formatter) secondaryParts.push(formatOverviewItem(stack.formatter));
|
|
1836
|
+
if (stack.testRunner) secondaryParts.push(formatOverviewItem(stack.testRunner));
|
|
1837
|
+
const primary = primaryParts.map((part) => import_chalk5.default.cyan(part)).join(import_chalk5.default.dim(" \xB7 "));
|
|
1838
|
+
const secondary = secondaryParts.join(import_chalk5.default.dim(" \xB7 "));
|
|
1839
|
+
return secondary ? `${primary}
|
|
1840
|
+
${import_chalk5.default.dim(secondary)}` : primary;
|
|
1841
|
+
}
|
|
1842
|
+
function displayInitOverview(scanResult, config, exemptedPackages) {
|
|
1757
1843
|
const root = config.packages.find((p) => p.path === ".") ?? config.packages[0];
|
|
1758
1844
|
const isMonorepo = config.packages.length > 1;
|
|
1759
1845
|
const ok = import_chalk5.default.green("\u2713");
|
|
1760
|
-
const
|
|
1846
|
+
const info = import_chalk5.default.yellow("~");
|
|
1847
|
+
console.log("");
|
|
1848
|
+
console.log(` ${import_chalk5.default.bold("Ready to initialize:")}`);
|
|
1849
|
+
console.log(` ${formatDetectedOverview(scanResult)}`);
|
|
1761
1850
|
console.log("");
|
|
1762
1851
|
console.log(` ${import_chalk5.default.bold("Rules to apply:")}`);
|
|
1763
1852
|
console.log(` ${ok} Max file size: ${import_chalk5.default.cyan(`${config.rules.maxFileLines} lines`)}`);
|
|
@@ -1765,7 +1854,7 @@ function displayInitSummary(config, exemptedPackages) {
|
|
|
1765
1854
|
if (config.rules.enforceNaming && fileNaming) {
|
|
1766
1855
|
console.log(` ${ok} File naming: ${import_chalk5.default.cyan(fileNaming)}`);
|
|
1767
1856
|
} else {
|
|
1768
|
-
console.log(` ${
|
|
1857
|
+
console.log(` ${info} File naming: ${import_chalk5.default.dim("not enforced")}`);
|
|
1769
1858
|
}
|
|
1770
1859
|
const testPattern = root?.structure?.testPattern ?? config.packages.find((p) => p.structure?.testPattern)?.structure?.testPattern;
|
|
1771
1860
|
if (config.rules.enforceMissingTests && testPattern) {
|
|
@@ -1773,7 +1862,7 @@ function displayInitSummary(config, exemptedPackages) {
|
|
|
1773
1862
|
} else if (config.rules.enforceMissingTests) {
|
|
1774
1863
|
console.log(` ${ok} Missing tests: ${import_chalk5.default.cyan("enforced")}`);
|
|
1775
1864
|
} else {
|
|
1776
|
-
console.log(` ${
|
|
1865
|
+
console.log(` ${info} Missing tests: ${import_chalk5.default.dim("not enforced")}`);
|
|
1777
1866
|
}
|
|
1778
1867
|
if (config.rules.testCoverage > 0) {
|
|
1779
1868
|
if (isMonorepo) {
|
|
@@ -1787,21 +1876,68 @@ function displayInitSummary(config, exemptedPackages) {
|
|
|
1787
1876
|
console.log(` ${ok} Coverage: ${import_chalk5.default.cyan(`${config.rules.testCoverage}%`)}`);
|
|
1788
1877
|
}
|
|
1789
1878
|
} else {
|
|
1790
|
-
console.log(` ${
|
|
1879
|
+
console.log(` ${info} Coverage: ${import_chalk5.default.dim("disabled")}`);
|
|
1791
1880
|
}
|
|
1792
1881
|
if (exemptedPackages.length > 0) {
|
|
1793
1882
|
console.log(
|
|
1794
1883
|
` ${import_chalk5.default.dim(" exempted:")} ${import_chalk5.default.dim(exemptedPackages.join(", "))} ${import_chalk5.default.dim("(types-only)")}`
|
|
1795
1884
|
);
|
|
1796
1885
|
}
|
|
1886
|
+
console.log("");
|
|
1887
|
+
console.log(` ${import_chalk5.default.bold("Also available:")}`);
|
|
1797
1888
|
if (isMonorepo) {
|
|
1798
|
-
console.log(
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1889
|
+
console.log(` ${info} Infer boundaries from current imports`);
|
|
1890
|
+
}
|
|
1891
|
+
console.log(` ${info} Set up hooks, Claude integration, and CI checks`);
|
|
1892
|
+
console.log(
|
|
1893
|
+
`
|
|
1894
|
+
${import_chalk5.default.dim("Defaults warn locally. Use --enforce in CI when you want failures to block.")}`
|
|
1895
|
+
);
|
|
1896
|
+
console.log("");
|
|
1897
|
+
}
|
|
1898
|
+
function summarizeSelectedIntegrations(integrations, opts) {
|
|
1899
|
+
const lines = [];
|
|
1900
|
+
if (opts.hasBoundaries) {
|
|
1901
|
+
lines.push("\u2713 Boundary rules: inferred from current imports");
|
|
1802
1902
|
} else {
|
|
1803
|
-
|
|
1804
|
-
|
|
1903
|
+
lines.push("~ Boundary rules: not enabled");
|
|
1904
|
+
}
|
|
1905
|
+
if (opts.hasCoverage) {
|
|
1906
|
+
lines.push("\u2713 Coverage checks: enabled");
|
|
1907
|
+
} else {
|
|
1908
|
+
lines.push("~ Coverage checks: disabled");
|
|
1909
|
+
}
|
|
1910
|
+
const selectedIntegrations = [
|
|
1911
|
+
integrations.preCommitHook ? "pre-commit hook" : void 0,
|
|
1912
|
+
integrations.typecheckHook ? "typecheck" : void 0,
|
|
1913
|
+
integrations.lintHook ? "lint check" : void 0,
|
|
1914
|
+
integrations.claudeCodeHook ? "Claude Code hook" : void 0,
|
|
1915
|
+
integrations.claudeMdRef ? "CLAUDE.md reference" : void 0,
|
|
1916
|
+
integrations.githubAction ? "GitHub Actions workflow" : void 0
|
|
1917
|
+
].filter(Boolean);
|
|
1918
|
+
if (selectedIntegrations.length > 0) {
|
|
1919
|
+
lines.push(`\u2713 Integrations: ${selectedIntegrations.join(" \xB7 ")}`);
|
|
1920
|
+
} else {
|
|
1921
|
+
lines.push("~ Integrations: none selected");
|
|
1922
|
+
}
|
|
1923
|
+
return lines;
|
|
1924
|
+
}
|
|
1925
|
+
function displaySetupPlan(config, integrations, opts = {}) {
|
|
1926
|
+
const configFile = opts.configFile ?? "viberails.config.json";
|
|
1927
|
+
const lines = summarizeSelectedIntegrations(integrations, {
|
|
1928
|
+
hasBoundaries: config.rules.enforceBoundaries,
|
|
1929
|
+
hasCoverage: config.rules.testCoverage > 0
|
|
1930
|
+
});
|
|
1931
|
+
console.log("");
|
|
1932
|
+
console.log(` ${import_chalk5.default.bold("Ready to write:")}`);
|
|
1933
|
+
console.log(
|
|
1934
|
+
` ${opts.replacingExistingConfig ? import_chalk5.default.yellow("!") : import_chalk5.default.green("\u2713")} ${configFile}${opts.replacingExistingConfig ? import_chalk5.default.dim(" (replacing existing config)") : ""}`
|
|
1935
|
+
);
|
|
1936
|
+
console.log(` ${import_chalk5.default.green("\u2713")} .viberails/context.md`);
|
|
1937
|
+
console.log(` ${import_chalk5.default.green("\u2713")} .viberails/scan-result.json`);
|
|
1938
|
+
for (const line of lines) {
|
|
1939
|
+
const icon = line.startsWith("\u2713") ? import_chalk5.default.green("\u2713") : import_chalk5.default.yellow("~");
|
|
1940
|
+
console.log(` ${icon} ${line.slice(2)}`);
|
|
1805
1941
|
}
|
|
1806
1942
|
console.log("");
|
|
1807
1943
|
}
|
|
@@ -2113,10 +2249,12 @@ async function configCommand(options, cwd) {
|
|
|
2113
2249
|
}
|
|
2114
2250
|
const configPath = path9.join(projectRoot, CONFIG_FILE3);
|
|
2115
2251
|
if (!fs10.existsSync(configPath)) {
|
|
2116
|
-
console.log(`${import_chalk6.default.yellow("!")} No config found. Run ${import_chalk6.default.cyan("viberails
|
|
2252
|
+
console.log(`${import_chalk6.default.yellow("!")} No config found. Run ${import_chalk6.default.cyan("viberails")} first.`);
|
|
2117
2253
|
return;
|
|
2118
2254
|
}
|
|
2119
|
-
|
|
2255
|
+
if (!options.suppressIntro) {
|
|
2256
|
+
clack6.intro("viberails config");
|
|
2257
|
+
}
|
|
2120
2258
|
const config = await (0, import_config6.loadConfig)(configPath);
|
|
2121
2259
|
let scanResult = options.rescan ? await rescanAndMerge(projectRoot, config) : void 0;
|
|
2122
2260
|
clack6.note(formatRulesText(config).join("\n"), "Current rules");
|
|
@@ -2690,7 +2828,6 @@ var import_scanner2 = require("@viberails/scanner");
|
|
|
2690
2828
|
var import_chalk12 = __toESM(require("chalk"), 1);
|
|
2691
2829
|
|
|
2692
2830
|
// src/utils/check-prerequisites.ts
|
|
2693
|
-
var import_node_child_process5 = require("child_process");
|
|
2694
2831
|
var fs14 = __toESM(require("fs"), 1);
|
|
2695
2832
|
var path14 = __toESM(require("path"), 1);
|
|
2696
2833
|
var clack7 = __toESM(require("@clack/prompts"), 1);
|
|
@@ -2739,7 +2876,7 @@ async function promptMissingPrereqs(projectRoot, prereqs) {
|
|
|
2739
2876
|
const detail = p.affectedPackages ? `needed by: ${p.affectedPackages.join(", ")}` : p.reason;
|
|
2740
2877
|
return `\u2717 ${p.label} \u2014 ${detail}`;
|
|
2741
2878
|
}).join("\n");
|
|
2742
|
-
clack7.note(prereqLines, "Coverage
|
|
2879
|
+
clack7.note(prereqLines, "Coverage support");
|
|
2743
2880
|
let disableCoverage = false;
|
|
2744
2881
|
for (const m of missing) {
|
|
2745
2882
|
if (!m.installCommand) continue;
|
|
@@ -2750,13 +2887,13 @@ async function promptMissingPrereqs(projectRoot, prereqs) {
|
|
|
2750
2887
|
options: [
|
|
2751
2888
|
{
|
|
2752
2889
|
value: "install",
|
|
2753
|
-
label:
|
|
2890
|
+
label: "Install now",
|
|
2754
2891
|
hint: m.installCommand
|
|
2755
2892
|
},
|
|
2756
2893
|
{
|
|
2757
2894
|
value: "disable",
|
|
2758
|
-
label: "
|
|
2759
|
-
hint: "missing-test checks still active"
|
|
2895
|
+
label: "Disable coverage checks",
|
|
2896
|
+
hint: "missing-test checks still stay active"
|
|
2760
2897
|
},
|
|
2761
2898
|
{
|
|
2762
2899
|
value: "skip",
|
|
@@ -2769,12 +2906,7 @@ async function promptMissingPrereqs(projectRoot, prereqs) {
|
|
|
2769
2906
|
if (choice === "install") {
|
|
2770
2907
|
const is = clack7.spinner();
|
|
2771
2908
|
is.start(`Installing ${m.label}...`);
|
|
2772
|
-
const result =
|
|
2773
|
-
cwd: projectRoot,
|
|
2774
|
-
shell: true,
|
|
2775
|
-
encoding: "utf-8",
|
|
2776
|
-
stdio: "pipe"
|
|
2777
|
-
});
|
|
2909
|
+
const result = await spawnAsync(m.installCommand, projectRoot);
|
|
2778
2910
|
if (result.status === 0) {
|
|
2779
2911
|
is.stop(`Installed ${m.label}`);
|
|
2780
2912
|
} else {
|
|
@@ -3221,9 +3353,12 @@ async function initCommand(options, cwd) {
|
|
|
3221
3353
|
}
|
|
3222
3354
|
const configPath = path19.join(projectRoot, CONFIG_FILE5);
|
|
3223
3355
|
if (fs19.existsSync(configPath) && !options.force) {
|
|
3356
|
+
if (!options.yes) {
|
|
3357
|
+
return initInteractive(projectRoot, configPath, options);
|
|
3358
|
+
}
|
|
3224
3359
|
console.log(
|
|
3225
3360
|
`${import_chalk12.default.yellow("!")} viberails is already initialized.
|
|
3226
|
-
Run ${import_chalk12.default.cyan("viberails
|
|
3361
|
+
Run ${import_chalk12.default.cyan("viberails")} to review or edit the existing setup, ${import_chalk12.default.cyan("viberails sync")} to update generated files, or ${import_chalk12.default.cyan("viberails init --force")} to replace it.`
|
|
3227
3362
|
);
|
|
3228
3363
|
return;
|
|
3229
3364
|
}
|
|
@@ -3301,6 +3436,19 @@ ${created.map((f) => ` ${f}`).join("\n")}`);
|
|
|
3301
3436
|
}
|
|
3302
3437
|
async function initInteractive(projectRoot, configPath, options) {
|
|
3303
3438
|
clack8.intro("viberails");
|
|
3439
|
+
const replacingExistingConfig = fs19.existsSync(configPath);
|
|
3440
|
+
if (fs19.existsSync(configPath) && !options.force) {
|
|
3441
|
+
const action = await promptExistingConfigAction(path19.basename(configPath));
|
|
3442
|
+
if (action === "cancel") {
|
|
3443
|
+
clack8.outro("Aborted. No files were written.");
|
|
3444
|
+
return;
|
|
3445
|
+
}
|
|
3446
|
+
if (action === "edit") {
|
|
3447
|
+
await configCommand({ suppressIntro: true }, projectRoot);
|
|
3448
|
+
return;
|
|
3449
|
+
}
|
|
3450
|
+
options.force = true;
|
|
3451
|
+
}
|
|
3304
3452
|
if (fs19.existsSync(configPath) && options.force) {
|
|
3305
3453
|
const replace = await confirmDangerous(
|
|
3306
3454
|
`${path19.basename(configPath)} already exists and will be replaced. Continue?`
|
|
@@ -3320,10 +3468,18 @@ async function initInteractive(projectRoot, configPath, options) {
|
|
|
3320
3468
|
"No source files detected. Try running from the project root,\nor check that source files exist. Run viberails sync after adding files."
|
|
3321
3469
|
);
|
|
3322
3470
|
}
|
|
3323
|
-
clack8.note(formatScanResultsText(scanResult), "Scan results");
|
|
3324
3471
|
const exemptedPkgs = getExemptedPackages(config);
|
|
3325
|
-
|
|
3326
|
-
|
|
3472
|
+
let decision;
|
|
3473
|
+
while (true) {
|
|
3474
|
+
displayInitOverview(scanResult, config, exemptedPkgs);
|
|
3475
|
+
const nextDecision = await promptInitDecision();
|
|
3476
|
+
if (nextDecision === "review") {
|
|
3477
|
+
clack8.note(formatScanResultsText(scanResult), "Detected details");
|
|
3478
|
+
continue;
|
|
3479
|
+
}
|
|
3480
|
+
decision = nextDecision;
|
|
3481
|
+
break;
|
|
3482
|
+
}
|
|
3327
3483
|
if (decision === "customize") {
|
|
3328
3484
|
const rootPkg = config.packages.find((p) => p.path === ".") ?? config.packages[0];
|
|
3329
3485
|
const overrides = await promptRuleMenu({
|
|
@@ -3340,10 +3496,10 @@ async function initInteractive(projectRoot, configPath, options) {
|
|
|
3340
3496
|
}
|
|
3341
3497
|
if (config.packages.length > 1) {
|
|
3342
3498
|
clack8.note(
|
|
3343
|
-
"
|
|
3499
|
+
"Optional for monorepos. viberails can infer package boundaries\nfrom imports that already work today, so you start with rules\nthat match the current codebase.",
|
|
3344
3500
|
"Boundaries"
|
|
3345
3501
|
);
|
|
3346
|
-
const shouldInfer = await confirm3("Infer boundary rules from import patterns?");
|
|
3502
|
+
const shouldInfer = await confirm3("Infer boundary rules from current import patterns?");
|
|
3347
3503
|
if (shouldInfer) {
|
|
3348
3504
|
const bs = clack8.spinner();
|
|
3349
3505
|
bs.start("Building import graph...");
|
|
@@ -3379,27 +3535,31 @@ async function initInteractive(projectRoot, configPath, options) {
|
|
|
3379
3535
|
packageManager: rootPkgStack?.packageManager?.split("@")[0],
|
|
3380
3536
|
isWorkspace: config.packages.length > 1
|
|
3381
3537
|
});
|
|
3382
|
-
|
|
3538
|
+
displaySetupPlan(config, integrations, {
|
|
3539
|
+
replacingExistingConfig,
|
|
3540
|
+
configFile: path19.basename(configPath)
|
|
3541
|
+
});
|
|
3542
|
+
const shouldWrite = await confirm3("Apply this setup?");
|
|
3383
3543
|
if (!shouldWrite) {
|
|
3384
3544
|
clack8.outro("Aborted. No files were written.");
|
|
3385
3545
|
return;
|
|
3386
3546
|
}
|
|
3387
3547
|
const ws = clack8.spinner();
|
|
3388
|
-
ws.start("Writing configuration
|
|
3548
|
+
ws.start("Writing configuration...");
|
|
3389
3549
|
const compacted = (0, import_config8.compactConfig)(config);
|
|
3390
3550
|
fs19.writeFileSync(configPath, `${JSON.stringify(compacted, null, 2)}
|
|
3391
3551
|
`);
|
|
3392
3552
|
writeGeneratedFiles(projectRoot, config, scanResult);
|
|
3393
3553
|
updateGitignore(projectRoot);
|
|
3394
|
-
setupSelectedIntegrations(projectRoot, integrations, {
|
|
3395
|
-
linter: rootPkgStack?.linter?.split("@")[0],
|
|
3396
|
-
packageManager: rootPkgStack?.packageManager?.split("@")[0]
|
|
3397
|
-
});
|
|
3398
3554
|
ws.stop("Configuration written");
|
|
3399
3555
|
const ok = import_chalk12.default.green("\u2713");
|
|
3400
3556
|
clack8.log.step(`${ok} ${path19.basename(configPath)}`);
|
|
3401
3557
|
clack8.log.step(`${ok} .viberails/context.md`);
|
|
3402
3558
|
clack8.log.step(`${ok} .viberails/scan-result.json`);
|
|
3559
|
+
setupSelectedIntegrations(projectRoot, integrations, {
|
|
3560
|
+
linter: rootPkgStack?.linter?.split("@")[0],
|
|
3561
|
+
packageManager: rootPkgStack?.packageManager?.split("@")[0]
|
|
3562
|
+
});
|
|
3403
3563
|
clack8.outro(
|
|
3404
3564
|
`Done! Next: review viberails.config.json, then run viberails check
|
|
3405
3565
|
${import_chalk12.default.dim("Tip: use")} ${import_chalk12.default.cyan("viberails check --enforce")} ${import_chalk12.default.dim("in CI to block PRs on violations.")}`
|
|
@@ -3410,7 +3570,7 @@ async function initInteractive(projectRoot, configPath, options) {
|
|
|
3410
3570
|
var fs20 = __toESM(require("fs"), 1);
|
|
3411
3571
|
var path20 = __toESM(require("path"), 1);
|
|
3412
3572
|
var clack9 = __toESM(require("@clack/prompts"), 1);
|
|
3413
|
-
var
|
|
3573
|
+
var import_config10 = require("@viberails/config");
|
|
3414
3574
|
var import_scanner3 = require("@viberails/scanner");
|
|
3415
3575
|
var import_chalk13 = __toESM(require("chalk"), 1);
|
|
3416
3576
|
var CONFIG_FILE6 = "viberails.config.json";
|
|
@@ -3436,14 +3596,14 @@ async function syncCommand(options, cwd) {
|
|
|
3436
3596
|
);
|
|
3437
3597
|
}
|
|
3438
3598
|
const configPath = path20.join(projectRoot, CONFIG_FILE6);
|
|
3439
|
-
const existing = await (0,
|
|
3599
|
+
const existing = await (0, import_config10.loadConfig)(configPath);
|
|
3440
3600
|
const previousStats = loadPreviousStats(projectRoot);
|
|
3441
3601
|
const s = clack9.spinner();
|
|
3442
3602
|
s.start("Scanning project...");
|
|
3443
3603
|
const scanResult = await (0, import_scanner3.scan)(projectRoot);
|
|
3444
3604
|
s.stop("Scan complete");
|
|
3445
|
-
const merged = (0,
|
|
3446
|
-
const compacted = (0,
|
|
3605
|
+
const merged = (0, import_config10.mergeConfig)(existing, scanResult);
|
|
3606
|
+
const compacted = (0, import_config10.compactConfig)(merged);
|
|
3447
3607
|
const compactedJson = JSON.stringify(compacted, null, 2);
|
|
3448
3608
|
const rawDisk = fs20.readFileSync(configPath, "utf-8").trim();
|
|
3449
3609
|
const diskWithoutSync = rawDisk.replace(/"lastSync":\s*"[^"]*"/, '"lastSync": ""');
|
|
@@ -3491,7 +3651,7 @@ ${import_chalk13.default.bold("Changes:")}`);
|
|
|
3491
3651
|
packageOverrides: merged.packages
|
|
3492
3652
|
});
|
|
3493
3653
|
applyRuleOverrides(merged, overrides);
|
|
3494
|
-
const recompacted = (0,
|
|
3654
|
+
const recompacted = (0, import_config10.compactConfig)(merged);
|
|
3495
3655
|
fs20.writeFileSync(configPath, `${JSON.stringify(recompacted, null, 2)}
|
|
3496
3656
|
`);
|
|
3497
3657
|
writeGeneratedFiles(projectRoot, merged, scanResult);
|
|
@@ -3515,7 +3675,7 @@ ${import_chalk13.default.bold("Synced:")}`);
|
|
|
3515
3675
|
}
|
|
3516
3676
|
|
|
3517
3677
|
// src/index.ts
|
|
3518
|
-
var VERSION = "0.6.
|
|
3678
|
+
var VERSION = "0.6.4";
|
|
3519
3679
|
var program = new import_commander.Command();
|
|
3520
3680
|
program.name("viberails").description("Guardrails for vibe coding").version(VERSION);
|
|
3521
3681
|
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) => {
|