viberails 0.2.1 → 0.2.2
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 +17 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +17 -4
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
package/dist/index.cjs
CHANGED
|
@@ -256,6 +256,19 @@ function resolveIgnoreForFile(relPath, config) {
|
|
|
256
256
|
var import_node_child_process = require("child_process");
|
|
257
257
|
var fs4 = __toESM(require("fs"), 1);
|
|
258
258
|
var path4 = __toESM(require("path"), 1);
|
|
259
|
+
var ALWAYS_SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
260
|
+
"node_modules",
|
|
261
|
+
".git",
|
|
262
|
+
"dist",
|
|
263
|
+
"build",
|
|
264
|
+
".next",
|
|
265
|
+
".expo",
|
|
266
|
+
".output",
|
|
267
|
+
".svelte-kit",
|
|
268
|
+
".turbo",
|
|
269
|
+
"coverage",
|
|
270
|
+
".viberails"
|
|
271
|
+
]);
|
|
259
272
|
var SOURCE_EXTS = /* @__PURE__ */ new Set([
|
|
260
273
|
".ts",
|
|
261
274
|
".tsx",
|
|
@@ -304,7 +317,7 @@ function checkNaming(relPath, conventions) {
|
|
|
304
317
|
const filename = path4.basename(relPath);
|
|
305
318
|
const ext = path4.extname(filename);
|
|
306
319
|
if (!SOURCE_EXTS.has(ext)) return void 0;
|
|
307
|
-
if (filename.startsWith("index.") || filename.includes(".config.") || filename.includes(".test.") || filename.includes(".spec.") || filename.startsWith(".")) {
|
|
320
|
+
if (filename.startsWith("index.") || filename.includes(".config.") || filename.includes(".test.") || filename.includes(".spec.") || filename.startsWith(".") || filename.startsWith("_") || filename.startsWith("+") || filename.startsWith("$") || filename.startsWith("[")) {
|
|
308
321
|
return void 0;
|
|
309
322
|
}
|
|
310
323
|
const bare = filename.slice(0, filename.indexOf("."));
|
|
@@ -337,7 +350,7 @@ function getAllSourceFiles(projectRoot, config) {
|
|
|
337
350
|
for (const entry of entries) {
|
|
338
351
|
const rel = path4.relative(projectRoot, path4.join(dir, entry.name));
|
|
339
352
|
if (entry.isDirectory()) {
|
|
340
|
-
if (
|
|
353
|
+
if (ALWAYS_SKIP_DIRS.has(entry.name)) {
|
|
341
354
|
continue;
|
|
342
355
|
}
|
|
343
356
|
if (isIgnored(rel, config.ignore)) continue;
|
|
@@ -812,7 +825,7 @@ async function fixCommand(options, cwd) {
|
|
|
812
825
|
return 1;
|
|
813
826
|
}
|
|
814
827
|
const config = await (0, import_config3.loadConfig)(configPath);
|
|
815
|
-
if (!options.
|
|
828
|
+
if (!options.dryRun) {
|
|
816
829
|
const isDirty = checkGitDirty(projectRoot);
|
|
817
830
|
if (isDirty) {
|
|
818
831
|
console.log(
|
|
@@ -1343,7 +1356,7 @@ ${import_chalk9.default.bold("Synced:")}`);
|
|
|
1343
1356
|
}
|
|
1344
1357
|
|
|
1345
1358
|
// src/index.ts
|
|
1346
|
-
var VERSION = "0.2.
|
|
1359
|
+
var VERSION = "0.2.2";
|
|
1347
1360
|
var program = new import_commander.Command();
|
|
1348
1361
|
program.name("viberails").description("Guardrails for vibe coding").version(VERSION);
|
|
1349
1362
|
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) => {
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/commands/boundaries.ts","../src/utils/find-project-root.ts","../src/utils/prompt.ts","../src/utils/resolve-workspace-packages.ts","../src/commands/check.ts","../src/commands/check-config.ts","../src/commands/check-files.ts","../src/commands/check-tests.ts","../src/commands/fix.ts","../src/commands/fix-helpers.ts","../src/commands/fix-imports.ts","../src/commands/fix-naming.ts","../src/commands/convert-name.ts","../src/commands/fix-tests.ts","../src/commands/init.ts","../src/display.ts","../src/display-helpers.ts","../src/display-monorepo.ts","../src/utils/write-generated-files.ts","../src/commands/init-hooks.ts","../src/commands/sync.ts"],"sourcesContent":["import chalk from 'chalk';\nimport { Command } from 'commander';\nimport { boundariesCommand } from './commands/boundaries.js';\nimport { checkCommand } from './commands/check.js';\nimport { fixCommand } from './commands/fix.js';\nimport { initCommand } from './commands/init.js';\nimport { syncCommand } from './commands/sync.js';\n\nexport const VERSION = '0.2.1';\n\nconst program = new Command();\n\nprogram.name('viberails').description('Guardrails for vibe coding').version(VERSION);\n\nprogram\n .command('init', { isDefault: true })\n .description('Scan your project and set up enforcement guardrails')\n .option('-y, --yes', 'Non-interactive mode (use defaults, high-confidence only)')\n .action(async (options: { yes?: boolean }) => {\n try {\n await initCommand(options);\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n console.error(`${chalk.red('Error:')} ${message}`);\n process.exit(1);\n }\n });\n\nprogram\n .command('sync')\n .description('Re-scan and update generated files')\n .action(async () => {\n try {\n await syncCommand();\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n console.error(`${chalk.red('Error:')} ${message}`);\n process.exit(1);\n }\n });\n\nprogram\n .command('check')\n .description('Check files against enforced rules')\n .option('--staged', 'Check only staged files (for pre-commit hooks)')\n .option('--files <files...>', 'Check specific files')\n .option('--no-boundaries', 'Skip boundary checking')\n .action(async (options: { staged?: boolean; files?: string[]; boundaries?: boolean }) => {\n try {\n const exitCode = await checkCommand({\n ...options,\n noBoundaries: options.boundaries === false,\n });\n process.exit(exitCode);\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n console.error(`${chalk.red('Error:')} ${message}`);\n process.exit(1);\n }\n });\n\nprogram\n .command('fix')\n .description('Auto-fix file naming violations and generate missing test stubs')\n .option('--dry-run', 'Show planned fixes without applying them')\n .option('--rule <rules...>', 'Fix only specific rules (file-naming, missing-test)')\n .option('-y, --yes', 'Skip confirmation prompt')\n .action(async (options: { dryRun?: boolean; rule?: string[]; yes?: boolean }) => {\n try {\n const exitCode = await fixCommand(options);\n process.exit(exitCode);\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n console.error(`${chalk.red('Error:')} ${message}`);\n process.exit(1);\n }\n });\n\nprogram\n .command('boundaries')\n .description('Display, infer, or inspect import boundary rules')\n .option('--infer', 'Infer boundary rules from current import patterns')\n .option('--graph', 'Display import graph summary')\n .action(async (options: { infer?: boolean; graph?: boolean }) => {\n try {\n await boundariesCommand(options);\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n console.error(`${chalk.red('Error:')} ${message}`);\n process.exit(1);\n }\n });\n\nprogram.parse();\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { loadConfig } from '@viberails/config';\nimport type { ViberailsConfig } from '@viberails/types';\nimport chalk from 'chalk';\nimport { findProjectRoot } from '../utils/find-project-root.js';\nimport { confirm } from '../utils/prompt.js';\nimport { resolveWorkspacePackages } from '../utils/resolve-workspace-packages.js';\n\nconst CONFIG_FILE = 'viberails.config.json';\n\nexport interface BoundariesOptions {\n infer?: boolean;\n graph?: boolean;\n}\n\n/**\n * Display, infer, or inspect import boundary rules.\n *\n * @param options - CLI options\n * @param cwd - Working directory override (for testing)\n */\nexport async function boundariesCommand(options: BoundariesOptions, cwd?: string): Promise<void> {\n const startDir = cwd ?? process.cwd();\n const projectRoot = findProjectRoot(startDir);\n if (!projectRoot) {\n throw new Error('No package.json found. Are you in a JS/TS project?');\n }\n\n const configPath = path.join(projectRoot, CONFIG_FILE);\n if (!fs.existsSync(configPath)) {\n throw new Error('No viberails.config.json found. Run `viberails init` first.');\n }\n\n const config = await loadConfig(configPath);\n\n if (options.graph) {\n await showGraph(projectRoot, config);\n return;\n }\n\n if (options.infer) {\n await inferAndDisplay(projectRoot, config, configPath);\n return;\n }\n\n displayRules(config);\n}\n\n/** Display configured boundary rules. */\nfunction displayRules(config: ViberailsConfig): void {\n if (!config.boundaries || config.boundaries.length === 0) {\n console.log(chalk.yellow('No boundary rules configured.'));\n console.log(`Run ${chalk.cyan('viberails boundaries --infer')} to generate rules.`);\n return;\n }\n\n const allowRules = config.boundaries.filter((r) => r.allow);\n const denyRules = config.boundaries.filter((r) => !r.allow);\n\n console.log(`\\n${chalk.bold(`Boundary rules (${config.boundaries.length} rules):`)}\\n`);\n\n for (const r of allowRules) {\n console.log(` ${chalk.green('✓')} ${r.from} → ${r.to}`);\n }\n\n for (const r of denyRules) {\n const reason = r.reason ? chalk.dim(` (${r.reason})`) : '';\n console.log(` ${chalk.red('✗')} ${r.from} → ${r.to}${reason}`);\n }\n\n console.log(\n `\\nEnforcement: ${config.rules.enforceBoundaries ? chalk.green('on') : chalk.yellow('off')}`,\n );\n}\n\n/** Infer boundary rules from import patterns and optionally save. */\nasync function inferAndDisplay(\n projectRoot: string,\n config: ViberailsConfig,\n configPath: string,\n): Promise<void> {\n console.log(chalk.dim('Analyzing imports...'));\n const { buildImportGraph, inferBoundaries } = await import('@viberails/graph');\n\n const packages = config.workspace\n ? resolveWorkspacePackages(projectRoot, config.workspace)\n : undefined;\n\n const graph = await buildImportGraph(projectRoot, {\n packages,\n ignore: config.ignore,\n });\n\n console.log(chalk.dim(`${graph.nodes.length} files, ${graph.edges.length} edges`));\n\n const inferred = inferBoundaries(graph);\n\n if (inferred.length === 0) {\n console.log(chalk.yellow('No boundary rules could be inferred.'));\n return;\n }\n\n const allow = inferred.filter((r) => r.allow);\n const deny = inferred.filter((r) => !r.allow);\n\n console.log(`\\n${chalk.bold('Inferred boundary rules:')}\\n`);\n\n for (const r of allow) {\n console.log(` ${chalk.green('✓')} ${r.from} → ${r.to}`);\n }\n\n for (const r of deny) {\n const reason = r.reason ? chalk.dim(` (${r.reason})`) : '';\n console.log(` ${chalk.red('✗')} ${r.from} → ${r.to}${reason}`);\n }\n\n console.log(`\\n ${allow.length} allowed, ${deny.length} denied`);\n\n const shouldSave = await confirm('\\nSave to viberails.config.json?');\n if (shouldSave) {\n config.boundaries = inferred;\n config.rules.enforceBoundaries = true;\n fs.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\\n`);\n console.log(`${chalk.green('✓')} Saved ${inferred.length} rules`);\n }\n}\n\n/** Display import graph summary. */\nasync function showGraph(projectRoot: string, config: ViberailsConfig): Promise<void> {\n console.log(chalk.dim('Building import graph...'));\n const { buildImportGraph } = await import('@viberails/graph');\n\n const packages = config.workspace\n ? resolveWorkspacePackages(projectRoot, config.workspace)\n : undefined;\n\n const graph = await buildImportGraph(projectRoot, {\n packages,\n ignore: config.ignore,\n });\n\n console.log(`\\n${chalk.bold('Import dependency graph:')}\\n`);\n console.log(` ${graph.nodes.length} files, ${graph.edges.length} imports\\n`);\n\n if (graph.packages.length > 0) {\n for (const pkg of graph.packages) {\n const deps =\n pkg.internalDeps.length > 0\n ? `\\n${pkg.internalDeps.map((d) => ` → ${d}`).join('\\n')}`\n : chalk.dim(' (no internal deps)');\n console.log(` ${pkg.name}${deps}`);\n }\n }\n\n if (graph.cycles.length > 0) {\n console.log(`\\n${chalk.yellow('Cycles detected:')}`);\n for (const cycle of graph.cycles) {\n const paths = cycle.map((f) => path.relative(projectRoot, f));\n console.log(` ${paths.join(' → ')}`);\n }\n }\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\n\n/**\n * Walk up from startDir looking for a directory containing package.json.\n *\n * @param startDir - The directory to start searching from\n * @returns The project root path, or null if no package.json is found\n */\nexport function findProjectRoot(startDir: string): string | null {\n let dir = path.resolve(startDir);\n\n while (true) {\n if (fs.existsSync(path.join(dir, 'package.json'))) {\n return dir;\n }\n\n const parent = path.dirname(dir);\n if (parent === dir) {\n return null;\n }\n dir = parent;\n }\n}\n","import * as readline from 'node:readline';\n\n/**\n * Prompt the user for a yes/no confirmation.\n *\n * @param message - The question to display (without the Y/n suffix)\n * @returns true if the user confirms, false otherwise\n */\nexport async function confirm(message: string): Promise<boolean> {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n return new Promise<boolean>((resolve) => {\n rl.question(`${message} (Y/n) `, (answer) => {\n rl.close();\n const trimmed = answer.trim().toLowerCase();\n resolve(trimmed === '' || trimmed === 'y' || trimmed === 'yes');\n });\n });\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { WorkspaceConfig, WorkspacePackage } from '@viberails/types';\n\n/**\n * Resolve WorkspacePackage[] from config workspace relative paths.\n *\n * Reads each package's package.json to get the name and dependencies,\n * then filters internalDeps to only include workspace-internal packages.\n *\n * @param projectRoot - Absolute path to the project root\n * @param workspace - The workspace config from viberails.config.json\n * @returns Array of resolved WorkspacePackage objects\n */\nexport function resolveWorkspacePackages(\n projectRoot: string,\n workspace: WorkspaceConfig,\n): WorkspacePackage[] {\n const packages: WorkspacePackage[] = [];\n\n for (const relativePath of workspace.packages) {\n const absPath = path.join(projectRoot, relativePath);\n const pkgJsonPath = path.join(absPath, 'package.json');\n\n if (!fs.existsSync(pkgJsonPath)) continue;\n\n let pkg: Record<string, unknown>;\n try {\n pkg = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8'));\n } catch {\n continue;\n }\n\n const name = pkg.name as string;\n if (!name) continue;\n\n const allDeps = [\n ...Object.keys((pkg.dependencies as Record<string, unknown>) ?? {}),\n ...Object.keys((pkg.devDependencies as Record<string, unknown>) ?? {}),\n ];\n\n packages.push({ name, path: absPath, relativePath, internalDeps: allDeps });\n }\n\n // Filter internalDeps to only workspace-internal package names\n const packageNames = new Set(packages.map((p) => p.name));\n for (const pkg of packages) {\n pkg.internalDeps = pkg.internalDeps.filter((dep) => packageNames.has(dep));\n }\n\n return packages;\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { loadConfig } from '@viberails/config';\nimport type { CheckViolation } from '@viberails/types';\nimport chalk from 'chalk';\nimport { findProjectRoot } from '../utils/find-project-root.js';\nimport { resolveWorkspacePackages } from '../utils/resolve-workspace-packages.js';\nimport { resolveConfigForFile, resolveIgnoreForFile } from './check-config.js';\nimport {\n checkNaming,\n countFileLines,\n getAllSourceFiles,\n getStagedFiles,\n isIgnored,\n} from './check-files.js';\nimport { checkMissingTests } from './check-tests.js';\n\nexport { resolveConfigForFile } from './check-config.js';\n\nconst CONFIG_FILE = 'viberails.config.json';\n\nexport interface CheckOptions {\n files?: string[];\n staged?: boolean;\n noBoundaries?: boolean;\n}\n\n/**\n * Run the viberails check command.\n * Returns exit code: 0 = pass or warn-mode, 1 = violations in enforce mode.\n */\nexport async function checkCommand(options: CheckOptions, cwd?: string): Promise<number> {\n const startDir = cwd ?? process.cwd();\n\n const projectRoot = findProjectRoot(startDir);\n if (!projectRoot) {\n console.error(`${chalk.red('Error:')} No package.json found. Are you in a JS/TS project?`);\n return 1;\n }\n\n const configPath = path.join(projectRoot, CONFIG_FILE);\n if (!fs.existsSync(configPath)) {\n console.error(\n `${chalk.red('Error:')} No viberails.config.json found. Run \\`viberails init\\` first.`,\n );\n return 1;\n }\n\n const config = await loadConfig(configPath);\n\n // Determine which files to check\n let filesToCheck: string[];\n if (options.staged) {\n filesToCheck = getStagedFiles(projectRoot);\n } else if (options.files && options.files.length > 0) {\n filesToCheck = options.files;\n } else {\n filesToCheck = getAllSourceFiles(projectRoot, config);\n }\n\n if (filesToCheck.length === 0) {\n console.log(`${chalk.green('✓')} No files to check.`);\n return 0;\n }\n\n const violations: CheckViolation[] = [];\n const severity = config.enforcement === 'enforce' ? 'error' : 'warn';\n\n for (const file of filesToCheck) {\n const absPath = path.isAbsolute(file) ? file : path.join(projectRoot, file);\n const relPath = path.relative(projectRoot, absPath);\n\n const effectiveIgnore = resolveIgnoreForFile(relPath, config);\n if (isIgnored(relPath, effectiveIgnore)) continue;\n if (!fs.existsSync(absPath)) continue;\n\n const resolved = resolveConfigForFile(relPath, config);\n\n // Check 1: File size\n if (resolved.rules.maxFileLines > 0) {\n const lines = countFileLines(absPath);\n if (lines !== null && lines > resolved.rules.maxFileLines) {\n violations.push({\n file: relPath,\n rule: 'file-size',\n message: `${lines} lines (max ${resolved.rules.maxFileLines}). Split into focused modules.`,\n severity,\n });\n }\n }\n\n // Check 2: File naming convention\n if (resolved.rules.enforceNaming && resolved.conventions.fileNaming) {\n const namingViolation = checkNaming(relPath, resolved.conventions);\n if (namingViolation) {\n violations.push({\n file: relPath,\n rule: 'file-naming',\n message: namingViolation,\n severity,\n });\n }\n }\n }\n\n // Check 3: Missing tests (only on full project check, not staged/specific files)\n if (config.rules.requireTests && !options.staged && !options.files) {\n const testViolations = checkMissingTests(projectRoot, config, severity);\n violations.push(...testViolations);\n }\n\n // Check 4: Boundary violations\n if (\n config.rules.enforceBoundaries &&\n config.boundaries &&\n config.boundaries.length > 0 &&\n !options.noBoundaries\n ) {\n const startTime = Date.now();\n const { buildImportGraph, checkBoundaries } = await import('@viberails/graph');\n\n const packages = config.workspace\n ? resolveWorkspacePackages(projectRoot, config.workspace)\n : undefined;\n\n const graph = await buildImportGraph(projectRoot, {\n packages,\n ignore: config.ignore,\n });\n\n const boundaryViolations = checkBoundaries(graph, config.boundaries);\n\n // In staged/files mode, only report violations in those files\n const filterSet =\n options.staged || options.files\n ? new Set(filesToCheck.map((f) => path.resolve(projectRoot, f)))\n : null;\n\n for (const bv of boundaryViolations) {\n if (filterSet && !filterSet.has(bv.file)) continue;\n\n const relFile = path.relative(projectRoot, bv.file);\n violations.push({\n file: relFile,\n rule: 'boundary-violation',\n message: `Imports \"${bv.specifier}\" violating boundary: ${bv.rule.from} → ${bv.rule.to}${bv.rule.reason ? ` (${bv.rule.reason})` : ''}`,\n severity,\n });\n }\n\n const elapsed = Date.now() - startTime;\n console.log(chalk.dim(` Boundary check: ${graph.nodes.length} files in ${elapsed}ms`));\n }\n\n // Output results\n if (violations.length === 0) {\n console.log(`${chalk.green('✓')} ${filesToCheck.length} files checked — no violations`);\n return 0;\n }\n\n for (const v of violations) {\n const icon = v.severity === 'error' ? chalk.red('✗') : chalk.yellow('!');\n console.log(`${icon} ${chalk.dim(v.rule)} ${v.file}: ${v.message}`);\n }\n\n const word = violations.length === 1 ? 'violation' : 'violations';\n console.log(`\\n${violations.length} ${word} found.`);\n\n if (config.enforcement === 'enforce') {\n console.log(chalk.red('Fix violations before committing.'));\n return 1;\n }\n\n return 0;\n}\n","import type { ConfigConventions, ConfigRules, ViberailsConfig } from '@viberails/types';\n\nexport interface ResolvedConfig {\n rules: ConfigRules;\n conventions: ConfigConventions;\n}\n\n/**\n * Resolve the effective config for a file by finding its package override.\n * Returns the global config merged with any matching package overrides.\n */\nexport function resolveConfigForFile(relPath: string, config: ViberailsConfig): ResolvedConfig {\n if (!config.packages || config.packages.length === 0) {\n return { rules: config.rules, conventions: config.conventions };\n }\n\n // Sort by path length descending to match the most specific package first\n const sortedPackages = [...config.packages].sort((a, b) => b.path.length - a.path.length);\n\n for (const pkg of sortedPackages) {\n if (relPath.startsWith(`${pkg.path}/`) || relPath === pkg.path) {\n return {\n rules: { ...config.rules, ...pkg.rules },\n conventions: { ...config.conventions, ...pkg.conventions },\n };\n }\n }\n\n return { rules: config.rules, conventions: config.conventions };\n}\n\n/**\n * Resolve ignore patterns for a file, appending any package-specific patterns.\n */\nexport function resolveIgnoreForFile(relPath: string, config: ViberailsConfig): string[] {\n const globalIgnore = config.ignore;\n if (!config.packages) return globalIgnore;\n\n for (const pkg of config.packages) {\n if (pkg.ignore && relPath.startsWith(`${pkg.path}/`)) {\n return [...globalIgnore, ...pkg.ignore];\n }\n }\n return globalIgnore;\n}\n","import { execSync } from 'node:child_process';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { ConfigConventions, ConventionValue, ViberailsConfig } from '@viberails/types';\n\nexport const SOURCE_EXTS = new Set([\n '.ts',\n '.tsx',\n '.js',\n '.jsx',\n '.mjs',\n '.cjs',\n '.vue',\n '.svelte',\n '.astro',\n]);\n\nexport const NAMING_PATTERNS: Record<string, RegExp> = {\n 'kebab-case': /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/,\n camelCase: /^[a-z][a-zA-Z0-9]*$/,\n PascalCase: /^[A-Z][a-zA-Z0-9]*$/,\n snake_case: /^[a-z][a-z0-9]*(_[a-z0-9]+)*$/,\n};\n\n/** Check if a path matches any ignore pattern. */\nexport function isIgnored(relPath: string, ignorePatterns: string[]): boolean {\n for (const pattern of ignorePatterns) {\n if (pattern.endsWith('/**')) {\n const prefix = pattern.slice(0, -3);\n if (relPath.startsWith(`${prefix}/`) || relPath === prefix) return true;\n } else if (pattern.startsWith('**/')) {\n const suffix = pattern.slice(3);\n if (relPath.endsWith(suffix)) return true;\n } else if (relPath === pattern || relPath.startsWith(`${pattern}/`)) {\n return true;\n }\n }\n return false;\n}\n\n/** Count lines in a file. Returns null if the file can't be read. */\nexport function countFileLines(filePath: string): number | null {\n try {\n const content = fs.readFileSync(filePath, 'utf-8');\n if (content.length === 0) return 0;\n let count = 1;\n for (let i = 0; i < content.length; i++) {\n if (content.charCodeAt(i) === 10) count++;\n }\n return count;\n } catch {\n return null;\n }\n}\n\n/** Check whether a file's name violates the configured naming convention. */\nexport function checkNaming(relPath: string, conventions: ConfigConventions): string | undefined {\n const filename = path.basename(relPath);\n\n // Skip non-source files\n const ext = path.extname(filename);\n if (!SOURCE_EXTS.has(ext)) return undefined;\n\n // Skip special files\n if (\n filename.startsWith('index.') ||\n filename.includes('.config.') ||\n filename.includes('.test.') ||\n filename.includes('.spec.') ||\n filename.startsWith('.')\n ) {\n return undefined;\n }\n\n const bare = filename.slice(0, filename.indexOf('.'));\n const convention =\n typeof conventions.fileNaming === 'string'\n ? conventions.fileNaming\n : (conventions.fileNaming as Exclude<ConventionValue, string> | undefined)?.value;\n\n if (!convention) return undefined;\n\n const pattern = NAMING_PATTERNS[convention];\n if (!pattern || pattern.test(bare)) return undefined;\n\n return `File name \"${filename}\" does not follow ${convention} convention.`;\n}\n\n/** Get staged files from git. */\nexport function getStagedFiles(projectRoot: string): string[] {\n try {\n const output = execSync('git diff --cached --name-only --diff-filter=ACM', {\n cwd: projectRoot,\n encoding: 'utf-8',\n });\n return output.trim().split('\\n').filter(Boolean);\n } catch {\n return [];\n }\n}\n\n/** Get all source files in the project. */\nexport function getAllSourceFiles(projectRoot: string, config: ViberailsConfig): string[] {\n const files: string[] = [];\n const walk = (dir: string) => {\n let entries: fs.Dirent[];\n try {\n entries = fs.readdirSync(dir, { withFileTypes: true });\n } catch {\n return;\n }\n for (const entry of entries) {\n const rel = path.relative(projectRoot, path.join(dir, entry.name));\n if (entry.isDirectory()) {\n if (entry.name === 'node_modules' || entry.name === '.git' || entry.name === 'dist') {\n continue;\n }\n if (isIgnored(rel, config.ignore)) continue;\n walk(path.join(dir, entry.name));\n } else if (entry.isFile()) {\n const ext = path.extname(entry.name);\n if (SOURCE_EXTS.has(ext) && !isIgnored(rel, config.ignore)) {\n files.push(rel);\n }\n }\n }\n };\n walk(projectRoot);\n return files;\n}\n\n/** Collect source files from a directory recursively. */\nexport function collectSourceFiles(dir: string, projectRoot: string): string[] {\n const files: string[] = [];\n const walk = (d: string) => {\n let entries: fs.Dirent[];\n try {\n entries = fs.readdirSync(d, { withFileTypes: true });\n } catch {\n return;\n }\n for (const entry of entries) {\n if (entry.isDirectory()) {\n if (entry.name === 'node_modules') continue;\n walk(path.join(d, entry.name));\n } else if (entry.isFile()) {\n files.push(path.relative(projectRoot, path.join(d, entry.name)));\n }\n }\n };\n walk(dir);\n return files;\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { CheckViolation, ViberailsConfig } from '@viberails/types';\nimport { collectSourceFiles } from './check-files.js';\n\nconst SOURCE_EXTS = new Set([\n '.ts',\n '.tsx',\n '.js',\n '.jsx',\n '.mjs',\n '.cjs',\n '.vue',\n '.svelte',\n '.astro',\n]);\n\n/** Check for source files without corresponding test files. */\nexport function checkMissingTests(\n projectRoot: string,\n config: ViberailsConfig,\n severity: 'error' | 'warn',\n): CheckViolation[] {\n const violations: CheckViolation[] = [];\n const { testPattern } = config.structure;\n if (!testPattern) return violations;\n\n const srcDir = config.structure.srcDir;\n if (!srcDir) return violations;\n\n const srcPath = path.join(projectRoot, srcDir);\n if (!fs.existsSync(srcPath)) return violations;\n\n const testSuffix = testPattern.replace('*', '');\n const sourceFiles = collectSourceFiles(srcPath, projectRoot);\n\n for (const relFile of sourceFiles) {\n const basename = path.basename(relFile);\n\n // Skip test files, index files, type definition files\n if (\n basename.includes('.test.') ||\n basename.includes('.spec.') ||\n basename.startsWith('index.') ||\n basename.endsWith('.d.ts')\n ) {\n continue;\n }\n\n const ext = path.extname(basename);\n if (!SOURCE_EXTS.has(ext)) continue;\n\n const stem = basename.slice(0, basename.indexOf('.'));\n const expectedTestFile = `${stem}${testSuffix}`;\n\n // Look for the test file next to the source or in the tests directory\n const dir = path.dirname(path.join(projectRoot, relFile));\n const colocatedTest = path.join(dir, expectedTestFile);\n const testsDir = config.structure.tests;\n const dedicatedTest = testsDir ? path.join(projectRoot, testsDir, expectedTestFile) : null;\n\n const hasTest =\n fs.existsSync(colocatedTest) || (dedicatedTest !== null && fs.existsSync(dedicatedTest));\n\n if (!hasTest) {\n violations.push({\n file: relFile,\n rule: 'missing-test',\n message: `No test file found. Expected \\`${expectedTestFile}\\`.`,\n severity,\n });\n }\n }\n\n return violations;\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { loadConfig } from '@viberails/config';\nimport chalk from 'chalk';\nimport { findProjectRoot } from '../utils/find-project-root.js';\nimport { resolveConfigForFile } from './check-config.js';\nimport { checkNaming, getAllSourceFiles } from './check-files.js';\nimport { checkMissingTests } from './check-tests.js';\nimport { checkGitDirty, getConventionValue, printPlan, promptConfirm } from './fix-helpers.js';\nimport { updateImportsAfterRenames } from './fix-imports.js';\nimport {\n computeRename,\n deduplicateRenames,\n executeRename,\n type RenameRecord,\n} from './fix-naming.js';\nimport { generateTestStub, type TestStubRecord, writeTestStub } from './fix-tests.js';\n\nconst CONFIG_FILE = 'viberails.config.json';\n\nexport interface FixOptions {\n dryRun?: boolean;\n rule?: string[];\n yes?: boolean;\n}\n\n/**\n * Run the viberails fix command.\n * Detects violations, computes fixes, optionally confirms, then applies.\n */\nexport async function fixCommand(options: FixOptions, cwd?: string): Promise<number> {\n const startDir = cwd ?? process.cwd();\n const projectRoot = findProjectRoot(startDir);\n\n if (!projectRoot) {\n console.error(`${chalk.red('Error:')} No package.json found. Are you in a JS/TS project?`);\n return 1;\n }\n\n const configPath = path.join(projectRoot, CONFIG_FILE);\n if (!fs.existsSync(configPath)) {\n console.error(\n `${chalk.red('Error:')} No viberails.config.json found. Run \\`viberails init\\` first.`,\n );\n return 1;\n }\n\n const config = await loadConfig(configPath);\n\n // Git dirty check — warn but don't block\n if (!options.yes && !options.dryRun) {\n const isDirty = checkGitDirty(projectRoot);\n if (isDirty) {\n console.log(\n chalk.yellow('Warning: You have uncommitted changes. Consider committing first.'),\n );\n }\n }\n\n const shouldFixNaming = !options.rule || options.rule.includes('file-naming');\n const shouldFixTests = !options.rule || options.rule.includes('missing-test');\n\n // Collect source files\n const allFiles = getAllSourceFiles(projectRoot, config);\n\n // Compute naming renames\n const renames: RenameRecord[] = [];\n if (shouldFixNaming) {\n for (const file of allFiles) {\n const resolved = resolveConfigForFile(file, config);\n if (!resolved.rules.enforceNaming || !resolved.conventions.fileNaming) continue;\n\n const violation = checkNaming(file, resolved.conventions);\n if (!violation) continue;\n\n const convention = getConventionValue(resolved.conventions.fileNaming);\n if (!convention) continue;\n\n const rename = computeRename(file, convention, projectRoot);\n if (rename) renames.push(rename);\n }\n }\n\n const dedupedRenames = deduplicateRenames(renames);\n\n // Compute test stubs\n const testStubs: TestStubRecord[] = [];\n if (shouldFixTests && config.rules.requireTests) {\n const testViolations = checkMissingTests(projectRoot, config, 'warn');\n for (const v of testViolations) {\n const stub = generateTestStub(v.file, config, projectRoot);\n if (stub) testStubs.push(stub);\n }\n }\n\n // Nothing to fix\n if (dedupedRenames.length === 0 && testStubs.length === 0) {\n console.log(`${chalk.green('✓')} No fixable violations found.`);\n return 0;\n }\n\n // Display plan\n printPlan(dedupedRenames, testStubs);\n\n if (options.dryRun) {\n console.log(chalk.dim('\\nDry run — no changes applied.'));\n return 0;\n }\n\n // Confirm\n if (!options.yes) {\n const confirmed = await promptConfirm('Apply these fixes?');\n if (!confirmed) {\n console.log('Aborted.');\n return 0;\n }\n }\n\n // Apply: 1. Renames\n let renameCount = 0;\n for (const rename of dedupedRenames) {\n if (executeRename(rename)) {\n renameCount++;\n }\n }\n\n // Apply: 2. Import updates\n let importUpdateCount = 0;\n if (renameCount > 0) {\n const appliedRenames = dedupedRenames.filter((r) => fs.existsSync(r.newAbsPath));\n const updates = await updateImportsAfterRenames(appliedRenames, projectRoot);\n importUpdateCount = updates.length;\n }\n\n // Apply: 3. Test stubs\n let stubCount = 0;\n for (const stub of testStubs) {\n if (!fs.existsSync(stub.absPath)) {\n writeTestStub(stub, config);\n stubCount++;\n }\n }\n\n // Summary\n console.log('');\n if (renameCount > 0) {\n console.log(`${chalk.green('✓')} Renamed ${renameCount} file${renameCount > 1 ? 's' : ''}`);\n }\n if (importUpdateCount > 0) {\n console.log(\n `${chalk.green('✓')} Updated ${importUpdateCount} import${importUpdateCount > 1 ? 's' : ''}`,\n );\n }\n if (stubCount > 0) {\n console.log(`${chalk.green('✓')} Generated ${stubCount} test stub${stubCount > 1 ? 's' : ''}`);\n }\n\n return 0;\n}\n","import { execSync } from 'node:child_process';\nimport { createInterface } from 'node:readline';\nimport chalk from 'chalk';\nimport type { RenameRecord } from './fix-naming.js';\nimport type { TestStubRecord } from './fix-tests.js';\n\n/**\n * Display the planned renames and test stubs.\n */\nexport function printPlan(renames: RenameRecord[], stubs: TestStubRecord[]): void {\n if (renames.length > 0) {\n console.log(chalk.bold('\\nFile renames:'));\n for (const r of renames) {\n console.log(` ${chalk.red(r.oldPath)} → ${chalk.green(r.newPath)}`);\n }\n }\n\n if (stubs.length > 0) {\n console.log(chalk.bold('\\nTest stubs to create:'));\n for (const s of stubs) {\n console.log(` ${chalk.green('+')} ${s.path}`);\n }\n }\n}\n\n/**\n * Check if the git working tree has uncommitted changes.\n */\nexport function checkGitDirty(projectRoot: string): boolean {\n try {\n const output = execSync('git status --porcelain', {\n cwd: projectRoot,\n encoding: 'utf-8',\n });\n return output.trim().length > 0;\n } catch {\n return false;\n }\n}\n\n/**\n * Extract the string value from a convention (which may be a string or an object with a value property).\n */\nexport function getConventionValue(convention: unknown): string | undefined {\n if (typeof convention === 'string') return convention;\n if (convention && typeof convention === 'object' && 'value' in convention) {\n return (convention as { value: string }).value;\n }\n return undefined;\n}\n\n/**\n * Prompt the user to confirm an action.\n */\nexport function promptConfirm(question: string): Promise<boolean> {\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n return new Promise((resolve) => {\n rl.question(`${question} (y/N) `, (answer) => {\n rl.close();\n resolve(answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes');\n });\n });\n}\n","import * as path from 'node:path';\nimport type { RenameRecord } from './fix-naming.js';\n\nexport interface ImportUpdateRecord {\n file: string;\n oldSpecifier: string;\n newSpecifier: string;\n line: number;\n}\n\n/**\n * Strip known JS/TS extensions from a file path for specifier comparison.\n * E.g. \"/foo/bar.ts\" → \"/foo/bar\", \"/foo/bar.js\" → \"/foo/bar\"\n */\nfunction stripExtension(filePath: string): string {\n return filePath.replace(/\\.(tsx?|jsx?|mjs|cjs)$/, '');\n}\n\n/**\n * Compute the new import specifier given the old specifier and the rename.\n * Preserves `.js` suffix if present.\n */\nfunction computeNewSpecifier(oldSpecifier: string, newBare: string): string {\n const hasJsExt = oldSpecifier.endsWith('.js');\n const base = hasJsExt ? oldSpecifier.slice(0, -3) : oldSpecifier;\n\n // Replace the last path segment\n const dir = base.lastIndexOf('/');\n const prefix = dir >= 0 ? base.slice(0, dir + 1) : '';\n const newSpec = prefix + newBare;\n\n return hasJsExt ? `${newSpec}.js` : newSpec;\n}\n\n/**\n * Update import specifiers in all source files after renames.\n * Uses ts-morph for AST-accurate rewriting.\n *\n * @param renames - The renames that were applied\n * @param projectRoot - Absolute path to project root\n * @returns Records of all import updates made\n */\nexport async function updateImportsAfterRenames(\n renames: RenameRecord[],\n projectRoot: string,\n): Promise<ImportUpdateRecord[]> {\n if (renames.length === 0) return [];\n\n // Lazy import ts-morph to avoid startup cost\n const { Project, SyntaxKind } = await import('ts-morph');\n\n // Build rename map: stripped old abs path → { newBare }\n const renameMap = new Map<string, { newBare: string }>();\n for (const r of renames) {\n const oldStripped = stripExtension(r.oldAbsPath);\n const newFilename = path.basename(r.newPath);\n const newName = newFilename.slice(0, newFilename.indexOf('.'));\n renameMap.set(oldStripped, { newBare: newName });\n }\n\n const project = new Project({\n tsConfigFilePath: undefined,\n skipAddingFilesFromTsConfig: true,\n });\n\n // Add all TS/JS source files\n project.addSourceFilesAtPaths(path.join(projectRoot, '**/*.{ts,tsx,js,jsx,mjs,cjs}'));\n\n const updates: ImportUpdateRecord[] = [];\n const extensions = ['', '.ts', '.tsx', '.js', '.jsx', '/index.ts', '/index.tsx', '/index.js'];\n\n for (const sourceFile of project.getSourceFiles()) {\n const filePath = sourceFile.getFilePath();\n // Skip node_modules and dist\n if (filePath.includes('/node_modules/') || filePath.includes('/dist/')) continue;\n\n const fileDir = path.dirname(filePath);\n\n // Process static imports\n for (const decl of sourceFile.getImportDeclarations()) {\n const specifier = decl.getModuleSpecifierValue();\n if (!specifier.startsWith('.')) continue;\n\n const match = resolveToRenamedFile(specifier, fileDir, renameMap, extensions);\n if (!match) continue;\n\n const newSpec = computeNewSpecifier(specifier, match.newBare);\n updates.push({\n file: filePath,\n oldSpecifier: specifier,\n newSpecifier: newSpec,\n line: decl.getStartLineNumber(),\n });\n decl.setModuleSpecifier(newSpec);\n }\n\n // Process re-exports\n for (const decl of sourceFile.getExportDeclarations()) {\n const specifier = decl.getModuleSpecifierValue();\n if (!specifier || !specifier.startsWith('.')) continue;\n\n const match = resolveToRenamedFile(specifier, fileDir, renameMap, extensions);\n if (!match) continue;\n\n const newSpec = computeNewSpecifier(specifier, match.newBare);\n updates.push({\n file: filePath,\n oldSpecifier: specifier,\n newSpecifier: newSpec,\n line: decl.getStartLineNumber(),\n });\n decl.setModuleSpecifier(newSpec);\n }\n\n // Process dynamic imports\n for (const call of sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression)) {\n if (call.getExpression().getKind() !== SyntaxKind.ImportKeyword) continue;\n\n const args = call.getArguments();\n if (args.length === 0) continue;\n\n const arg = args[0];\n if (arg.getKind() !== SyntaxKind.StringLiteral) continue;\n\n const specifier = arg.getText().slice(1, -1);\n if (!specifier.startsWith('.')) continue;\n\n const match = resolveToRenamedFile(specifier, fileDir, renameMap, extensions);\n if (!match) continue;\n\n const newSpec = computeNewSpecifier(specifier, match.newBare);\n updates.push({\n file: filePath,\n oldSpecifier: specifier,\n newSpecifier: newSpec,\n line: call.getStartLineNumber(),\n });\n // Replace the string literal content\n const quote = arg.getText()[0];\n arg.replaceWithText(`${quote}${newSpec}${quote}`);\n }\n }\n\n if (updates.length > 0) {\n await project.save();\n }\n\n return updates;\n}\n\n/**\n * Try to resolve a relative specifier to a renamed file.\n * Returns the rename info if matched, undefined otherwise.\n */\nfunction resolveToRenamedFile(\n specifier: string,\n fromDir: string,\n renameMap: Map<string, { newBare: string }>,\n extensions: string[],\n): { newBare: string } | undefined {\n // Strip .js extension for resolution (TypeScript convention)\n const cleanSpec = specifier.endsWith('.js') ? specifier.slice(0, -3) : specifier;\n const resolved = path.resolve(fromDir, cleanSpec);\n\n for (const ext of extensions) {\n const candidate = resolved + ext;\n const stripped = stripExtension(candidate);\n const match = renameMap.get(stripped);\n if (match) return match;\n }\n\n return undefined;\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { convertName } from './convert-name.js';\n\nexport interface RenameRecord {\n oldPath: string;\n newPath: string;\n oldAbsPath: string;\n newAbsPath: string;\n}\n\n/**\n * Compute the rename for a file that violates the naming convention.\n * Returns null if no rename is needed or the target already exists.\n */\nexport function computeRename(\n relPath: string,\n targetConvention: string,\n projectRoot: string,\n): RenameRecord | null {\n const filename = path.basename(relPath);\n const dir = path.dirname(relPath);\n\n // Extract bare name (before first dot) — matches checkNaming logic\n const dotIndex = filename.indexOf('.');\n if (dotIndex === -1) return null;\n\n const bare = filename.slice(0, dotIndex);\n const suffix = filename.slice(dotIndex); // e.g. \".tsx\" or \".test.ts\"\n\n const newBare = convertName(bare, targetConvention);\n if (newBare === bare) return null;\n\n const newFilename = newBare + suffix;\n const newRelPath = path.join(dir, newFilename);\n const oldAbsPath = path.join(projectRoot, relPath);\n const newAbsPath = path.join(projectRoot, newRelPath);\n\n // Skip if target already exists\n if (fs.existsSync(newAbsPath)) return null;\n\n return { oldPath: relPath, newPath: newRelPath, oldAbsPath, newAbsPath };\n}\n\n/**\n * Execute a single rename on disk.\n * Returns true if successful, false if skipped (target exists).\n */\nexport function executeRename(rename: RenameRecord): boolean {\n if (fs.existsSync(rename.newAbsPath)) return false;\n fs.renameSync(rename.oldAbsPath, rename.newAbsPath);\n return true;\n}\n\n/**\n * Detect and deduplicate rename collisions.\n * If two planned renames target the same path, the second is removed.\n */\nexport function deduplicateRenames(renames: RenameRecord[]): RenameRecord[] {\n const seen = new Set<string>();\n const result: RenameRecord[] = [];\n for (const r of renames) {\n if (seen.has(r.newAbsPath)) continue;\n seen.add(r.newAbsPath);\n result.push(r);\n }\n return result;\n}\n","/**\n * Split a bare filename into its constituent words.\n *\n * Handles kebab-case, camelCase, PascalCase, and snake_case inputs.\n * Consecutive uppercase letters (acronyms like \"URL\") are kept together.\n */\nexport function splitIntoWords(name: string): string[] {\n // First, split on explicit separators (hyphens and underscores)\n const parts = name.split(/[-_]/);\n\n const words: string[] = [];\n for (const part of parts) {\n if (part === '') continue;\n\n // Split camelCase and PascalCase boundaries\n // \"UserProfile\" → [\"User\", \"Profile\"]\n // \"parseJSON\" → [\"parse\", \"JSON\"]\n // \"XMLParser\" → [\"XML\", \"Parser\"]\n let current = '';\n for (let i = 0; i < part.length; i++) {\n const ch = part[i];\n const isUpper = ch >= 'A' && ch <= 'Z';\n\n if (isUpper && current.length > 0) {\n const prevIsUpper =\n current[current.length - 1] >= 'A' && current[current.length - 1] <= 'Z';\n const nextIsLower = i + 1 < part.length && part[i + 1] >= 'a' && part[i + 1] <= 'z';\n\n if (!prevIsUpper || nextIsLower) {\n words.push(current.toLowerCase());\n current = '';\n }\n }\n current += ch;\n }\n if (current) words.push(current.toLowerCase());\n }\n\n return words;\n}\n\n/**\n * Convert a bare filename to the specified naming convention.\n *\n * @param bare - The bare filename without extension (e.g. \"UserProfile\")\n * @param target - The target convention (kebab-case, camelCase, PascalCase, snake_case)\n * @returns The converted name\n */\nexport function convertName(bare: string, target: string): string {\n const words = splitIntoWords(bare);\n if (words.length === 0) return bare;\n\n switch (target) {\n case 'kebab-case':\n return words.join('-');\n case 'camelCase':\n return words[0] + words.slice(1).map(capitalize).join('');\n case 'PascalCase':\n return words.map(capitalize).join('');\n case 'snake_case':\n return words.join('_');\n default:\n return bare;\n }\n}\n\nfunction capitalize(word: string): string {\n if (word.length === 0) return word;\n return word[0].toUpperCase() + word.slice(1);\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { ViberailsConfig } from '@viberails/types';\n\nexport interface TestStubRecord {\n path: string;\n absPath: string;\n moduleName: string;\n}\n\n/**\n * Generate a test stub record for a source file that is missing tests.\n * Returns null if the test file already exists.\n */\nexport function generateTestStub(\n sourceRelPath: string,\n config: ViberailsConfig,\n projectRoot: string,\n): TestStubRecord | null {\n const { testPattern } = config.structure;\n if (!testPattern) return null;\n\n const basename = path.basename(sourceRelPath);\n const stem = basename.slice(0, basename.indexOf('.'));\n const testSuffix = testPattern.replace('*', '');\n const testFilename = `${stem}${testSuffix}`;\n\n const dir = path.dirname(path.join(projectRoot, sourceRelPath));\n const testAbsPath = path.join(dir, testFilename);\n\n if (fs.existsSync(testAbsPath)) return null;\n\n return {\n path: path.relative(projectRoot, testAbsPath),\n absPath: testAbsPath,\n moduleName: stem,\n };\n}\n\n/**\n * Write a test stub file to disk.\n */\nexport function writeTestStub(stub: TestStubRecord, config: ViberailsConfig): void {\n const runner = config.stack.testRunner === 'jest' ? 'jest' : 'vitest';\n const importLine =\n runner === 'jest'\n ? '' // jest globals are available without import\n : \"import { describe, it, expect } from 'vitest';\\n\\n\";\n\n const content = `${importLine}describe('${stub.moduleName}', () => {\\n it.todo('add tests');\\n});\\n`;\n\n fs.mkdirSync(path.dirname(stub.absPath), { recursive: true });\n fs.writeFileSync(stub.absPath, content);\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { generateConfig } from '@viberails/config';\nimport { scan } from '@viberails/scanner';\nimport type { ConfigConventions, ConventionValue } from '@viberails/types';\nimport chalk from 'chalk';\nimport { displayScanResults } from '../display.js';\nimport { findProjectRoot } from '../utils/find-project-root.js';\nimport { confirm } from '../utils/prompt.js';\nimport { resolveWorkspacePackages } from '../utils/resolve-workspace-packages.js';\nimport { writeGeneratedFiles } from '../utils/write-generated-files.js';\nimport { setupPreCommitHook } from './init-hooks.js';\n\nconst CONFIG_FILE = 'viberails.config.json';\n\n/**\n * Filter a ConfigConventions object to only include high-confidence entries.\n */\nfunction filterHighConfidence(conventions: ConfigConventions): ConfigConventions {\n const filtered: ConfigConventions = {};\n for (const [key, value] of Object.entries(conventions)) {\n if (value === undefined) continue;\n if (typeof value === 'string') {\n filtered[key as keyof ConfigConventions] = value;\n } else if (value._confidence === 'high') {\n filtered[key as keyof ConfigConventions] = value as ConventionValue;\n }\n }\n return filtered;\n}\n\n/**\n * Run the viberails init flow.\n *\n * @param options - CLI options\n * @param cwd - Working directory override (for testing)\n */\nexport async function initCommand(options: { yes?: boolean }, cwd?: string): Promise<void> {\n const startDir = cwd ?? process.cwd();\n\n // 1. Find project root\n const projectRoot = findProjectRoot(startDir);\n if (!projectRoot) {\n throw new Error(\n 'No package.json found in this directory or any parent.\\n\\n' +\n 'Make sure you are inside a JavaScript or TypeScript project, then run:\\n' +\n ' npx viberails',\n );\n }\n\n // 2. Check for existing config\n const configPath = path.join(projectRoot, CONFIG_FILE);\n if (fs.existsSync(configPath)) {\n console.log(\n chalk.yellow('!') +\n ' viberails is already initialized in this project.\\n' +\n ' Run ' +\n chalk.cyan('viberails sync') +\n ' to update the generated files.',\n );\n return;\n }\n\n // 3. Run scanner\n console.log(chalk.dim('Scanning project...'));\n const scanResult = await scan(projectRoot);\n\n // 4. Display results\n displayScanResults(scanResult);\n\n // 5. Sparse project notice\n if (scanResult.statistics.totalFiles === 0) {\n console.log(\n chalk.yellow('!') +\n ' No source files detected. viberails will generate context with minimal content.\\n' +\n ' Run ' +\n chalk.cyan('viberails sync') +\n ' after adding source files.\\n',\n );\n }\n\n // 6. Interactive confirmation\n if (!options.yes) {\n const accepted = await confirm('Does this look right?');\n if (!accepted) {\n console.log('Aborted.');\n return;\n }\n }\n\n // 7. Generate config\n const config = generateConfig(scanResult);\n if (options.yes) {\n config.conventions = filterHighConfidence(config.conventions);\n }\n\n // 7b. Infer boundary rules for workspace projects\n if (config.workspace && config.workspace.packages.length > 0) {\n let shouldInfer = options.yes;\n if (!options.yes) {\n shouldInfer = await confirm('Infer boundary rules from import patterns?');\n }\n\n if (shouldInfer) {\n console.log(chalk.dim('Building import graph...'));\n const { buildImportGraph, inferBoundaries } = await import('@viberails/graph');\n const packages = resolveWorkspacePackages(projectRoot, config.workspace);\n const graph = await buildImportGraph(projectRoot, { packages, ignore: config.ignore });\n const inferred = inferBoundaries(graph);\n if (inferred.length > 0) {\n config.boundaries = inferred;\n config.rules.enforceBoundaries = true;\n console.log(` ${chalk.green('✓')} Inferred ${inferred.length} boundary rules`);\n }\n }\n }\n\n fs.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\\n`);\n\n // 8. Generate context and scan-result.json\n writeGeneratedFiles(projectRoot, config, scanResult);\n\n // 9. Update .gitignore\n updateGitignore(projectRoot);\n\n // 10. Set up pre-commit hook\n setupPreCommitHook(projectRoot);\n\n // 11. Print summary\n console.log(`\\n${chalk.bold('Created:')}`);\n console.log(` ${chalk.green('✓')} ${CONFIG_FILE}`);\n console.log(` ${chalk.green('✓')} .viberails/context.md`);\n console.log(` ${chalk.green('✓')} .viberails/scan-result.json`);\n console.log(`\\n${chalk.bold('Next steps:')}`);\n console.log(` 1. Review ${chalk.cyan('viberails.config.json')} and adjust rules`);\n console.log(\n ` 2. Commit ${chalk.cyan('viberails.config.json')} and ${chalk.cyan('.viberails/context.md')}`,\n );\n console.log(` 3. Run ${chalk.cyan('viberails check')} to verify your project passes`);\n}\n\n/**\n * Append viberails entries to .gitignore if not already present.\n * Only scan-result.json is ignored — context.md should be committed\n * so AI agents can read the enforced rules.\n */\nfunction updateGitignore(projectRoot: string): void {\n const gitignorePath = path.join(projectRoot, '.gitignore');\n let content = '';\n\n if (fs.existsSync(gitignorePath)) {\n content = fs.readFileSync(gitignorePath, 'utf-8');\n }\n\n if (!content.includes('.viberails/scan-result.json')) {\n const block = '\\n# viberails\\n.viberails/scan-result.json\\n';\n fs.writeFileSync(gitignorePath, `${content.trimEnd()}\\n${block}`);\n }\n}\n","import type { DetectedConvention, ScanResult, StackItem } from '@viberails/types';\nimport { FRAMEWORK_NAMES, LIBRARY_NAMES, STYLING_NAMES } from '@viberails/types';\nimport chalk from 'chalk';\nimport {\n formatExtensions,\n formatRoleGroup,\n formatSummary,\n groupByRole,\n} from './display-helpers.js';\nimport { displayMonorepoResults } from './display-monorepo.js';\n\n/** Labels for convention keys. */\nconst CONVENTION_LABELS: Record<string, string> = {\n fileNaming: 'File naming',\n componentNaming: 'Component naming',\n hookNaming: 'Hook naming',\n importAlias: 'Import alias',\n};\n\n/**\n * Format a StackItem for display: \"DisplayName Version\".\n */\nexport function formatItem(item: StackItem, nameMap?: Record<string, string>): string {\n const name = nameMap?.[item.name] ?? item.name;\n return item.version ? `${name} ${item.version}` : name;\n}\n\n/**\n * Format a confidence label for display.\n */\nexport function confidenceLabel(convention: DetectedConvention): string {\n const pct = Math.round(convention.consistency);\n if (convention.confidence === 'high') {\n return `${pct}% — high confidence, will enforce`;\n }\n return `${pct}% — medium confidence, suggested only`;\n}\n\n/**\n * Display conventions section, shared between single-package and monorepo.\n */\nexport function displayConventions(scanResult: ScanResult): void {\n const conventionEntries = Object.entries(scanResult.conventions);\n if (conventionEntries.length === 0) return;\n\n console.log(`\\n${chalk.bold('Conventions:')}`);\n for (const [key, convention] of conventionEntries) {\n if (convention.confidence === 'low') continue;\n const label = CONVENTION_LABELS[key] ?? key;\n\n if (scanResult.packages.length > 1) {\n const pkgValues = scanResult.packages\n .filter((pkg) => pkg.conventions[key] && pkg.conventions[key].confidence !== 'low')\n .map((pkg) => ({ relativePath: pkg.relativePath, convention: pkg.conventions[key] }));\n\n const allSame = pkgValues.every((pv) => pv.convention.value === convention.value);\n\n if (allSame || pkgValues.length <= 1) {\n const ind = convention.confidence === 'high' ? chalk.green('✓') : chalk.yellow('~');\n const detail = chalk.dim(`(${confidenceLabel(convention)})`);\n console.log(` ${ind} ${label}: ${convention.value} ${detail}`);\n } else {\n console.log(` ${chalk.yellow('~')} ${label}: varies by package`);\n for (const pv of pkgValues) {\n const pct = Math.round(pv.convention.consistency);\n console.log(` ${pv.relativePath}: ${pv.convention.value} (${pct}%)`);\n }\n }\n } else {\n const ind = convention.confidence === 'high' ? chalk.green('✓') : chalk.yellow('~');\n const detail = chalk.dim(`(${confidenceLabel(convention)})`);\n console.log(` ${ind} ${label}: ${convention.value} ${detail}`);\n }\n }\n}\n\n/**\n * Display summary section with statistics.\n */\nexport function displaySummarySection(scanResult: ScanResult): void {\n const pkgCount = scanResult.packages.length > 1 ? scanResult.packages.length : undefined;\n console.log(`\\n${chalk.bold('Summary:')}`);\n console.log(` ${formatSummary(scanResult.statistics, pkgCount)}`);\n const ext = formatExtensions(scanResult.statistics.filesByExtension);\n if (ext) {\n console.log(` ${ext}`);\n }\n}\n\n/**\n * Display scan results to the console with confidence indicators.\n *\n * @param scanResult - The scan result to display\n */\nexport function displayScanResults(scanResult: ScanResult): void {\n if (scanResult.packages.length > 1) {\n displayMonorepoResults(scanResult);\n return;\n }\n\n const { stack } = scanResult;\n\n console.log(`\\n${chalk.bold('Detected:')}`);\n\n if (stack.framework) {\n console.log(` ${chalk.green('✓')} ${formatItem(stack.framework, FRAMEWORK_NAMES)}`);\n }\n console.log(` ${chalk.green('✓')} ${formatItem(stack.language)}`);\n if (stack.styling) {\n console.log(` ${chalk.green('✓')} ${formatItem(stack.styling, STYLING_NAMES)}`);\n }\n if (stack.backend) {\n console.log(` ${chalk.green('✓')} ${formatItem(stack.backend, FRAMEWORK_NAMES)}`);\n }\n if (stack.linter) {\n console.log(` ${chalk.green('✓')} ${formatItem(stack.linter)}`);\n }\n if (stack.formatter) {\n console.log(` ${chalk.green('✓')} ${formatItem(stack.formatter)}`);\n }\n if (stack.testRunner) {\n console.log(` ${chalk.green('✓')} ${formatItem(stack.testRunner)}`);\n }\n if (stack.packageManager) {\n console.log(` ${chalk.green('✓')} ${formatItem(stack.packageManager)}`);\n }\n if (stack.libraries.length > 0) {\n for (const lib of stack.libraries) {\n console.log(` ${chalk.green('✓')} ${formatItem(lib, LIBRARY_NAMES)}`);\n }\n }\n\n // Structure grouped by role\n const groups = groupByRole(scanResult.structure.directories);\n if (groups.length > 0) {\n console.log(`\\n${chalk.bold('Structure:')}`);\n for (const group of groups) {\n console.log(` ${chalk.green('✓')} ${formatRoleGroup(group)}`);\n }\n }\n\n displayConventions(scanResult);\n displaySummarySection(scanResult);\n console.log('');\n}\n","import type { CodebaseStatistics, DirectoryInfo, DirectoryRole } from '@viberails/types';\nimport { ROLE_DESCRIPTIONS } from '@viberails/types';\n\n/**\n * A group of directories sharing the same role within a package.\n */\nexport interface RoleGroup {\n role: DirectoryRole;\n label: string;\n dirCount: number;\n totalFiles: number;\n singlePath?: string;\n}\n\n/**\n * Groups a package's directories by role, merging file counts.\n * Filters out `unknown` role. For single-directory roles, sets `singlePath`.\n *\n * @param directories - The directories to group.\n * @returns Array of RoleGroup entries sorted by role label.\n */\nexport function groupByRole(directories: DirectoryInfo[]): RoleGroup[] {\n const map = new Map<DirectoryRole, { dirs: DirectoryInfo[] }>();\n\n for (const dir of directories) {\n if (dir.role === 'unknown') continue;\n const existing = map.get(dir.role);\n if (existing) {\n existing.dirs.push(dir);\n } else {\n map.set(dir.role, { dirs: [dir] });\n }\n }\n\n const groups: RoleGroup[] = [];\n for (const [role, { dirs }] of map) {\n const label = ROLE_DESCRIPTIONS[role] ?? role;\n const totalFiles = dirs.reduce((sum, d) => sum + d.fileCount, 0);\n groups.push({\n role,\n label,\n dirCount: dirs.length,\n totalFiles,\n singlePath: dirs.length === 1 ? dirs[0].path : undefined,\n });\n }\n\n return groups;\n}\n\n/**\n * Format a summary line from CodebaseStatistics.\n *\n * @param stats - The codebase statistics.\n * @param packageCount - Number of packages (shown for monorepos with > 1).\n * @returns Formatted summary string, e.g. \"3 packages · 743 source files · 48,200 lines · avg 65 lines/file\"\n */\nexport function formatSummary(stats: CodebaseStatistics, packageCount?: number): string {\n const parts: string[] = [];\n if (packageCount && packageCount > 1) {\n parts.push(`${packageCount} packages`);\n }\n parts.push(`${stats.totalFiles.toLocaleString()} source files`);\n parts.push(`${stats.totalLines.toLocaleString()} lines`);\n parts.push(`avg ${Math.round(stats.averageFileLines)} lines/file`);\n return parts.join(' \\u00b7 ');\n}\n\n/**\n * Format top extensions by count, e.g. \".tsx 312 · .ts 289 · .js 142\".\n *\n * @param filesByExtension - Extension counts from CodebaseStatistics.\n * @param maxEntries - Maximum number of extensions to show (default 4).\n * @returns Formatted extension string.\n */\nexport function formatExtensions(\n filesByExtension: Record<string, number>,\n maxEntries: number = 4,\n): string {\n return Object.entries(filesByExtension)\n .sort(([, a], [, b]) => b - a)\n .slice(0, maxEntries)\n .map(([ext, count]) => `${ext} ${count}`)\n .join(' \\u00b7 ');\n}\n\n/**\n * Format a RoleGroup for display.\n *\n * @param group - The role group.\n * @returns Formatted string, e.g. \"Hooks — 4 dirs (55 files)\" or \"Pages / Routes — app (12 files)\"\n */\nexport function formatRoleGroup(group: RoleGroup): string {\n const files = group.totalFiles === 1 ? '1 file' : `${group.totalFiles} files`;\n if (group.singlePath) {\n return `${group.label} — ${group.singlePath} (${files})`;\n }\n const dirs = group.dirCount === 1 ? '1 dir' : `${group.dirCount} dirs`;\n return `${group.label} — ${dirs} (${files})`;\n}\n","import type { PackageScanResult, ScanResult } from '@viberails/types';\nimport { FRAMEWORK_NAMES, STYLING_NAMES } from '@viberails/types';\nimport chalk from 'chalk';\nimport { displayConventions, displaySummarySection, formatItem } from './display.js';\nimport { formatRoleGroup, groupByRole } from './display-helpers.js';\n\n/**\n * Format a package summary line for monorepo display.\n */\nexport function formatPackageSummary(pkg: PackageScanResult): string {\n const parts: string[] = [];\n if (pkg.stack.framework) {\n parts.push(formatItem(pkg.stack.framework, FRAMEWORK_NAMES));\n }\n if (pkg.stack.styling) {\n parts.push(formatItem(pkg.stack.styling, STYLING_NAMES));\n }\n const files = `${pkg.statistics.totalFiles} files`;\n const detail = parts.length > 0 ? `${parts.join(', ')} (${files})` : `(${files})`;\n return ` ${pkg.relativePath} — ${detail}`;\n}\n\n/**\n * Display scan results for a monorepo with per-package summaries.\n */\nexport function displayMonorepoResults(scanResult: ScanResult): void {\n const { stack, packages } = scanResult;\n\n console.log(`\\n${chalk.bold(`Detected: (monorepo, ${packages.length} packages)`)}`);\n\n // Shared stack items at the top\n console.log(` ${chalk.green('✓')} ${formatItem(stack.language)}`);\n if (stack.packageManager) {\n console.log(` ${chalk.green('✓')} ${formatItem(stack.packageManager)}`);\n }\n if (stack.linter) {\n console.log(` ${chalk.green('✓')} ${formatItem(stack.linter)}`);\n }\n if (stack.formatter) {\n console.log(` ${chalk.green('✓')} ${formatItem(stack.formatter)}`);\n }\n if (stack.testRunner) {\n console.log(` ${chalk.green('✓')} ${formatItem(stack.testRunner)}`);\n }\n\n // Per-package summaries\n console.log('');\n for (const pkg of packages) {\n console.log(formatPackageSummary(pkg));\n }\n\n // Structure grouped by role per package\n const packagesWithDirs = packages.filter((pkg) =>\n pkg.structure.directories.some((d) => d.role !== 'unknown'),\n );\n if (packagesWithDirs.length > 0) {\n console.log(`\\n${chalk.bold('Structure:')}`);\n for (const pkg of packagesWithDirs) {\n const groups = groupByRole(pkg.structure.directories);\n if (groups.length === 0) continue;\n console.log(` ${pkg.relativePath}:`);\n for (const group of groups) {\n console.log(` ${chalk.green('✓')} ${formatRoleGroup(group)}`);\n }\n }\n }\n\n displayConventions(scanResult);\n displaySummarySection(scanResult);\n console.log('');\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { generateContext } from '@viberails/context';\nimport type { ScanResult, ViberailsConfig } from '@viberails/types';\n\nconst CONTEXT_DIR = '.viberails';\nconst CONTEXT_FILE = 'context.md';\nconst SCAN_RESULT_FILE = 'scan-result.json';\n\n/**\n * Write all generated files: context.md and scan-result.json.\n *\n * @param projectRoot - Absolute path to the project root\n * @param config - The viberails configuration\n * @param scanResult - The raw scan result\n */\nexport function writeGeneratedFiles(\n projectRoot: string,\n config: ViberailsConfig,\n scanResult: ScanResult,\n): void {\n const contextDir = path.join(projectRoot, CONTEXT_DIR);\n\n try {\n if (!fs.existsSync(contextDir)) {\n fs.mkdirSync(contextDir, { recursive: true });\n }\n\n const context = generateContext(config);\n fs.writeFileSync(path.join(contextDir, CONTEXT_FILE), context);\n\n fs.writeFileSync(\n path.join(contextDir, SCAN_RESULT_FILE),\n `${JSON.stringify(scanResult, null, 2)}\\n`,\n );\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n throw new Error(`Failed to write generated files to ${contextDir}: ${message}`);\n }\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport chalk from 'chalk';\n\n/**\n * Set up a pre-commit hook that runs viberails check on staged files.\n * Detects Lefthook, Husky, or falls back to a raw git hook.\n */\nexport function setupPreCommitHook(projectRoot: string): void {\n // Check for Lefthook\n const lefthookPath = path.join(projectRoot, 'lefthook.yml');\n if (fs.existsSync(lefthookPath)) {\n addLefthookPreCommit(lefthookPath);\n console.log(` ${chalk.green('✓')} lefthook.yml — added viberails pre-commit`);\n return;\n }\n\n // Check for Husky\n const huskyDir = path.join(projectRoot, '.husky');\n if (fs.existsSync(huskyDir)) {\n writeHuskyPreCommit(huskyDir);\n console.log(` ${chalk.green('✓')} .husky/pre-commit — added viberails check`);\n return;\n }\n\n // Fall back to raw git hook\n const gitDir = path.join(projectRoot, '.git');\n if (fs.existsSync(gitDir)) {\n const hooksDir = path.join(gitDir, 'hooks');\n if (!fs.existsSync(hooksDir)) {\n fs.mkdirSync(hooksDir, { recursive: true });\n }\n writeGitHookPreCommit(hooksDir);\n console.log(` ${chalk.green('✓')} .git/hooks/pre-commit`);\n }\n}\n\nfunction writeGitHookPreCommit(hooksDir: string): void {\n const hookPath = path.join(hooksDir, 'pre-commit');\n if (fs.existsSync(hookPath)) {\n const existing = fs.readFileSync(hookPath, 'utf-8');\n if (existing.includes('viberails')) return;\n fs.writeFileSync(\n hookPath,\n `${existing.trimEnd()}\\n\\n# viberails check\\nnpx viberails check --staged\\n`,\n );\n return;\n }\n const script = [\n '#!/bin/sh',\n '# Generated by viberails — https://viberails.sh',\n '',\n 'npx viberails check --staged',\n '',\n ].join('\\n');\n fs.writeFileSync(hookPath, script, { mode: 0o755 });\n}\n\nfunction addLefthookPreCommit(lefthookPath: string): void {\n const content = fs.readFileSync(lefthookPath, 'utf-8');\n if (content.includes('viberails')) return;\n const addition = ['', ' viberails:', ' run: npx viberails check --staged'].join('\\n');\n fs.writeFileSync(lefthookPath, `${content.trimEnd()}\\n${addition}\\n`);\n}\n\nfunction writeHuskyPreCommit(huskyDir: string): void {\n const hookPath = path.join(huskyDir, 'pre-commit');\n if (fs.existsSync(hookPath)) {\n const existing = fs.readFileSync(hookPath, 'utf-8');\n if (!existing.includes('viberails')) {\n fs.writeFileSync(hookPath, `${existing.trimEnd()}\\nnpx viberails check --staged\\n`);\n }\n return;\n }\n fs.writeFileSync(hookPath, '#!/bin/sh\\nnpx viberails check --staged\\n', { mode: 0o755 });\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { loadConfig, mergeConfig } from '@viberails/config';\nimport { scan } from '@viberails/scanner';\nimport chalk from 'chalk';\nimport { findProjectRoot } from '../utils/find-project-root.js';\nimport { writeGeneratedFiles } from '../utils/write-generated-files.js';\n\nconst CONFIG_FILE = 'viberails.config.json';\n\n/**\n * Run the viberails sync flow: re-scan, merge config, regenerate context.\n *\n * @param cwd - Working directory override (for testing)\n */\nexport async function syncCommand(cwd?: string): Promise<void> {\n const startDir = cwd ?? process.cwd();\n\n // 1. Find project root\n const projectRoot = findProjectRoot(startDir);\n if (!projectRoot) {\n throw new Error(\n 'No package.json found in this directory or any parent.\\n\\n' +\n 'Make sure you are inside a JavaScript or TypeScript project, then run:\\n' +\n ' npx viberails',\n );\n }\n\n // 2. Load existing config\n const configPath = path.join(projectRoot, CONFIG_FILE);\n const existing = await loadConfig(configPath);\n\n // 3. Re-scan\n console.log(chalk.dim('Scanning project...'));\n const scanResult = await scan(projectRoot);\n\n // 4. Merge config\n const merged = mergeConfig(existing, scanResult);\n fs.writeFileSync(configPath, `${JSON.stringify(merged, null, 2)}\\n`);\n\n // 5. Regenerate context and scan-result.json\n writeGeneratedFiles(projectRoot, merged, scanResult);\n\n console.log(`\\n${chalk.bold('Synced:')}`);\n console.log(` ${chalk.green('✓')} ${CONFIG_FILE} — updated`);\n console.log(` ${chalk.green('✓')} .viberails/context.md — regenerated`);\n console.log(` ${chalk.green('✓')} .viberails/scan-result.json — updated`);\n}\n"],"mappings":"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","names":["import_chalk","fs","path","resolve","fs","path","chalk","fs","path","import_config","import_chalk","fs","path","fs","path","SOURCE_EXTS","basename","CONFIG_FILE","chalk","fs","path","import_config","import_chalk","import_node_child_process","import_chalk","chalk","resolve","path","fs","path","fs","path","basename","CONFIG_FILE","chalk","fs","path","import_config","import_chalk","import_types","import_chalk","import_types","import_chalk","chalk","chalk","fs","path","fs","path","import_chalk","chalk","CONFIG_FILE","chalk","fs","path","import_config","import_scanner","import_chalk","CONFIG_FILE","chalk","chalk"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/commands/boundaries.ts","../src/utils/find-project-root.ts","../src/utils/prompt.ts","../src/utils/resolve-workspace-packages.ts","../src/commands/check.ts","../src/commands/check-config.ts","../src/commands/check-files.ts","../src/commands/check-tests.ts","../src/commands/fix.ts","../src/commands/fix-helpers.ts","../src/commands/fix-imports.ts","../src/commands/fix-naming.ts","../src/commands/convert-name.ts","../src/commands/fix-tests.ts","../src/commands/init.ts","../src/display.ts","../src/display-helpers.ts","../src/display-monorepo.ts","../src/utils/write-generated-files.ts","../src/commands/init-hooks.ts","../src/commands/sync.ts"],"sourcesContent":["import chalk from 'chalk';\nimport { Command } from 'commander';\nimport { boundariesCommand } from './commands/boundaries.js';\nimport { checkCommand } from './commands/check.js';\nimport { fixCommand } from './commands/fix.js';\nimport { initCommand } from './commands/init.js';\nimport { syncCommand } from './commands/sync.js';\n\ndeclare const __PACKAGE_VERSION__: string;\nexport const VERSION: string = __PACKAGE_VERSION__;\n\nconst program = new Command();\n\nprogram.name('viberails').description('Guardrails for vibe coding').version(VERSION);\n\nprogram\n .command('init', { isDefault: true })\n .description('Scan your project and set up enforcement guardrails')\n .option('-y, --yes', 'Non-interactive mode (use defaults, high-confidence only)')\n .action(async (options: { yes?: boolean }) => {\n try {\n await initCommand(options);\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n console.error(`${chalk.red('Error:')} ${message}`);\n process.exit(1);\n }\n });\n\nprogram\n .command('sync')\n .description('Re-scan and update generated files')\n .action(async () => {\n try {\n await syncCommand();\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n console.error(`${chalk.red('Error:')} ${message}`);\n process.exit(1);\n }\n });\n\nprogram\n .command('check')\n .description('Check files against enforced rules')\n .option('--staged', 'Check only staged files (for pre-commit hooks)')\n .option('--files <files...>', 'Check specific files')\n .option('--no-boundaries', 'Skip boundary checking')\n .action(async (options: { staged?: boolean; files?: string[]; boundaries?: boolean }) => {\n try {\n const exitCode = await checkCommand({\n ...options,\n noBoundaries: options.boundaries === false,\n });\n process.exit(exitCode);\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n console.error(`${chalk.red('Error:')} ${message}`);\n process.exit(1);\n }\n });\n\nprogram\n .command('fix')\n .description('Auto-fix file naming violations and generate missing test stubs')\n .option('--dry-run', 'Show planned fixes without applying them')\n .option('--rule <rules...>', 'Fix only specific rules (file-naming, missing-test)')\n .option('-y, --yes', 'Skip confirmation prompt')\n .action(async (options: { dryRun?: boolean; rule?: string[]; yes?: boolean }) => {\n try {\n const exitCode = await fixCommand(options);\n process.exit(exitCode);\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n console.error(`${chalk.red('Error:')} ${message}`);\n process.exit(1);\n }\n });\n\nprogram\n .command('boundaries')\n .description('Display, infer, or inspect import boundary rules')\n .option('--infer', 'Infer boundary rules from current import patterns')\n .option('--graph', 'Display import graph summary')\n .action(async (options: { infer?: boolean; graph?: boolean }) => {\n try {\n await boundariesCommand(options);\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n console.error(`${chalk.red('Error:')} ${message}`);\n process.exit(1);\n }\n });\n\nprogram.parse();\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { loadConfig } from '@viberails/config';\nimport type { ViberailsConfig } from '@viberails/types';\nimport chalk from 'chalk';\nimport { findProjectRoot } from '../utils/find-project-root.js';\nimport { confirm } from '../utils/prompt.js';\nimport { resolveWorkspacePackages } from '../utils/resolve-workspace-packages.js';\n\nconst CONFIG_FILE = 'viberails.config.json';\n\nexport interface BoundariesOptions {\n infer?: boolean;\n graph?: boolean;\n}\n\n/**\n * Display, infer, or inspect import boundary rules.\n *\n * @param options - CLI options\n * @param cwd - Working directory override (for testing)\n */\nexport async function boundariesCommand(options: BoundariesOptions, cwd?: string): Promise<void> {\n const startDir = cwd ?? process.cwd();\n const projectRoot = findProjectRoot(startDir);\n if (!projectRoot) {\n throw new Error('No package.json found. Are you in a JS/TS project?');\n }\n\n const configPath = path.join(projectRoot, CONFIG_FILE);\n if (!fs.existsSync(configPath)) {\n throw new Error('No viberails.config.json found. Run `viberails init` first.');\n }\n\n const config = await loadConfig(configPath);\n\n if (options.graph) {\n await showGraph(projectRoot, config);\n return;\n }\n\n if (options.infer) {\n await inferAndDisplay(projectRoot, config, configPath);\n return;\n }\n\n displayRules(config);\n}\n\n/** Display configured boundary rules. */\nfunction displayRules(config: ViberailsConfig): void {\n if (!config.boundaries || config.boundaries.length === 0) {\n console.log(chalk.yellow('No boundary rules configured.'));\n console.log(`Run ${chalk.cyan('viberails boundaries --infer')} to generate rules.`);\n return;\n }\n\n const allowRules = config.boundaries.filter((r) => r.allow);\n const denyRules = config.boundaries.filter((r) => !r.allow);\n\n console.log(`\\n${chalk.bold(`Boundary rules (${config.boundaries.length} rules):`)}\\n`);\n\n for (const r of allowRules) {\n console.log(` ${chalk.green('✓')} ${r.from} → ${r.to}`);\n }\n\n for (const r of denyRules) {\n const reason = r.reason ? chalk.dim(` (${r.reason})`) : '';\n console.log(` ${chalk.red('✗')} ${r.from} → ${r.to}${reason}`);\n }\n\n console.log(\n `\\nEnforcement: ${config.rules.enforceBoundaries ? chalk.green('on') : chalk.yellow('off')}`,\n );\n}\n\n/** Infer boundary rules from import patterns and optionally save. */\nasync function inferAndDisplay(\n projectRoot: string,\n config: ViberailsConfig,\n configPath: string,\n): Promise<void> {\n console.log(chalk.dim('Analyzing imports...'));\n const { buildImportGraph, inferBoundaries } = await import('@viberails/graph');\n\n const packages = config.workspace\n ? resolveWorkspacePackages(projectRoot, config.workspace)\n : undefined;\n\n const graph = await buildImportGraph(projectRoot, {\n packages,\n ignore: config.ignore,\n });\n\n console.log(chalk.dim(`${graph.nodes.length} files, ${graph.edges.length} edges`));\n\n const inferred = inferBoundaries(graph);\n\n if (inferred.length === 0) {\n console.log(chalk.yellow('No boundary rules could be inferred.'));\n return;\n }\n\n const allow = inferred.filter((r) => r.allow);\n const deny = inferred.filter((r) => !r.allow);\n\n console.log(`\\n${chalk.bold('Inferred boundary rules:')}\\n`);\n\n for (const r of allow) {\n console.log(` ${chalk.green('✓')} ${r.from} → ${r.to}`);\n }\n\n for (const r of deny) {\n const reason = r.reason ? chalk.dim(` (${r.reason})`) : '';\n console.log(` ${chalk.red('✗')} ${r.from} → ${r.to}${reason}`);\n }\n\n console.log(`\\n ${allow.length} allowed, ${deny.length} denied`);\n\n const shouldSave = await confirm('\\nSave to viberails.config.json?');\n if (shouldSave) {\n config.boundaries = inferred;\n config.rules.enforceBoundaries = true;\n fs.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\\n`);\n console.log(`${chalk.green('✓')} Saved ${inferred.length} rules`);\n }\n}\n\n/** Display import graph summary. */\nasync function showGraph(projectRoot: string, config: ViberailsConfig): Promise<void> {\n console.log(chalk.dim('Building import graph...'));\n const { buildImportGraph } = await import('@viberails/graph');\n\n const packages = config.workspace\n ? resolveWorkspacePackages(projectRoot, config.workspace)\n : undefined;\n\n const graph = await buildImportGraph(projectRoot, {\n packages,\n ignore: config.ignore,\n });\n\n console.log(`\\n${chalk.bold('Import dependency graph:')}\\n`);\n console.log(` ${graph.nodes.length} files, ${graph.edges.length} imports\\n`);\n\n if (graph.packages.length > 0) {\n for (const pkg of graph.packages) {\n const deps =\n pkg.internalDeps.length > 0\n ? `\\n${pkg.internalDeps.map((d) => ` → ${d}`).join('\\n')}`\n : chalk.dim(' (no internal deps)');\n console.log(` ${pkg.name}${deps}`);\n }\n }\n\n if (graph.cycles.length > 0) {\n console.log(`\\n${chalk.yellow('Cycles detected:')}`);\n for (const cycle of graph.cycles) {\n const paths = cycle.map((f) => path.relative(projectRoot, f));\n console.log(` ${paths.join(' → ')}`);\n }\n }\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\n\n/**\n * Walk up from startDir looking for a directory containing package.json.\n *\n * @param startDir - The directory to start searching from\n * @returns The project root path, or null if no package.json is found\n */\nexport function findProjectRoot(startDir: string): string | null {\n let dir = path.resolve(startDir);\n\n while (true) {\n if (fs.existsSync(path.join(dir, 'package.json'))) {\n return dir;\n }\n\n const parent = path.dirname(dir);\n if (parent === dir) {\n return null;\n }\n dir = parent;\n }\n}\n","import * as readline from 'node:readline';\n\n/**\n * Prompt the user for a yes/no confirmation.\n *\n * @param message - The question to display (without the Y/n suffix)\n * @returns true if the user confirms, false otherwise\n */\nexport async function confirm(message: string): Promise<boolean> {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n return new Promise<boolean>((resolve) => {\n rl.question(`${message} (Y/n) `, (answer) => {\n rl.close();\n const trimmed = answer.trim().toLowerCase();\n resolve(trimmed === '' || trimmed === 'y' || trimmed === 'yes');\n });\n });\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { WorkspaceConfig, WorkspacePackage } from '@viberails/types';\n\n/**\n * Resolve WorkspacePackage[] from config workspace relative paths.\n *\n * Reads each package's package.json to get the name and dependencies,\n * then filters internalDeps to only include workspace-internal packages.\n *\n * @param projectRoot - Absolute path to the project root\n * @param workspace - The workspace config from viberails.config.json\n * @returns Array of resolved WorkspacePackage objects\n */\nexport function resolveWorkspacePackages(\n projectRoot: string,\n workspace: WorkspaceConfig,\n): WorkspacePackage[] {\n const packages: WorkspacePackage[] = [];\n\n for (const relativePath of workspace.packages) {\n const absPath = path.join(projectRoot, relativePath);\n const pkgJsonPath = path.join(absPath, 'package.json');\n\n if (!fs.existsSync(pkgJsonPath)) continue;\n\n let pkg: Record<string, unknown>;\n try {\n pkg = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8'));\n } catch {\n continue;\n }\n\n const name = pkg.name as string;\n if (!name) continue;\n\n const allDeps = [\n ...Object.keys((pkg.dependencies as Record<string, unknown>) ?? {}),\n ...Object.keys((pkg.devDependencies as Record<string, unknown>) ?? {}),\n ];\n\n packages.push({ name, path: absPath, relativePath, internalDeps: allDeps });\n }\n\n // Filter internalDeps to only workspace-internal package names\n const packageNames = new Set(packages.map((p) => p.name));\n for (const pkg of packages) {\n pkg.internalDeps = pkg.internalDeps.filter((dep) => packageNames.has(dep));\n }\n\n return packages;\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { loadConfig } from '@viberails/config';\nimport type { CheckViolation } from '@viberails/types';\nimport chalk from 'chalk';\nimport { findProjectRoot } from '../utils/find-project-root.js';\nimport { resolveWorkspacePackages } from '../utils/resolve-workspace-packages.js';\nimport { resolveConfigForFile, resolveIgnoreForFile } from './check-config.js';\nimport {\n checkNaming,\n countFileLines,\n getAllSourceFiles,\n getStagedFiles,\n isIgnored,\n} from './check-files.js';\nimport { checkMissingTests } from './check-tests.js';\n\nexport { resolveConfigForFile } from './check-config.js';\n\nconst CONFIG_FILE = 'viberails.config.json';\n\nexport interface CheckOptions {\n files?: string[];\n staged?: boolean;\n noBoundaries?: boolean;\n}\n\n/**\n * Run the viberails check command.\n * Returns exit code: 0 = pass or warn-mode, 1 = violations in enforce mode.\n */\nexport async function checkCommand(options: CheckOptions, cwd?: string): Promise<number> {\n const startDir = cwd ?? process.cwd();\n\n const projectRoot = findProjectRoot(startDir);\n if (!projectRoot) {\n console.error(`${chalk.red('Error:')} No package.json found. Are you in a JS/TS project?`);\n return 1;\n }\n\n const configPath = path.join(projectRoot, CONFIG_FILE);\n if (!fs.existsSync(configPath)) {\n console.error(\n `${chalk.red('Error:')} No viberails.config.json found. Run \\`viberails init\\` first.`,\n );\n return 1;\n }\n\n const config = await loadConfig(configPath);\n\n // Determine which files to check\n let filesToCheck: string[];\n if (options.staged) {\n filesToCheck = getStagedFiles(projectRoot);\n } else if (options.files && options.files.length > 0) {\n filesToCheck = options.files;\n } else {\n filesToCheck = getAllSourceFiles(projectRoot, config);\n }\n\n if (filesToCheck.length === 0) {\n console.log(`${chalk.green('✓')} No files to check.`);\n return 0;\n }\n\n const violations: CheckViolation[] = [];\n const severity = config.enforcement === 'enforce' ? 'error' : 'warn';\n\n for (const file of filesToCheck) {\n const absPath = path.isAbsolute(file) ? file : path.join(projectRoot, file);\n const relPath = path.relative(projectRoot, absPath);\n\n const effectiveIgnore = resolveIgnoreForFile(relPath, config);\n if (isIgnored(relPath, effectiveIgnore)) continue;\n if (!fs.existsSync(absPath)) continue;\n\n const resolved = resolveConfigForFile(relPath, config);\n\n // Check 1: File size\n if (resolved.rules.maxFileLines > 0) {\n const lines = countFileLines(absPath);\n if (lines !== null && lines > resolved.rules.maxFileLines) {\n violations.push({\n file: relPath,\n rule: 'file-size',\n message: `${lines} lines (max ${resolved.rules.maxFileLines}). Split into focused modules.`,\n severity,\n });\n }\n }\n\n // Check 2: File naming convention\n if (resolved.rules.enforceNaming && resolved.conventions.fileNaming) {\n const namingViolation = checkNaming(relPath, resolved.conventions);\n if (namingViolation) {\n violations.push({\n file: relPath,\n rule: 'file-naming',\n message: namingViolation,\n severity,\n });\n }\n }\n }\n\n // Check 3: Missing tests (only on full project check, not staged/specific files)\n if (config.rules.requireTests && !options.staged && !options.files) {\n const testViolations = checkMissingTests(projectRoot, config, severity);\n violations.push(...testViolations);\n }\n\n // Check 4: Boundary violations\n if (\n config.rules.enforceBoundaries &&\n config.boundaries &&\n config.boundaries.length > 0 &&\n !options.noBoundaries\n ) {\n const startTime = Date.now();\n const { buildImportGraph, checkBoundaries } = await import('@viberails/graph');\n\n const packages = config.workspace\n ? resolveWorkspacePackages(projectRoot, config.workspace)\n : undefined;\n\n const graph = await buildImportGraph(projectRoot, {\n packages,\n ignore: config.ignore,\n });\n\n const boundaryViolations = checkBoundaries(graph, config.boundaries);\n\n // In staged/files mode, only report violations in those files\n const filterSet =\n options.staged || options.files\n ? new Set(filesToCheck.map((f) => path.resolve(projectRoot, f)))\n : null;\n\n for (const bv of boundaryViolations) {\n if (filterSet && !filterSet.has(bv.file)) continue;\n\n const relFile = path.relative(projectRoot, bv.file);\n violations.push({\n file: relFile,\n rule: 'boundary-violation',\n message: `Imports \"${bv.specifier}\" violating boundary: ${bv.rule.from} → ${bv.rule.to}${bv.rule.reason ? ` (${bv.rule.reason})` : ''}`,\n severity,\n });\n }\n\n const elapsed = Date.now() - startTime;\n console.log(chalk.dim(` Boundary check: ${graph.nodes.length} files in ${elapsed}ms`));\n }\n\n // Output results\n if (violations.length === 0) {\n console.log(`${chalk.green('✓')} ${filesToCheck.length} files checked — no violations`);\n return 0;\n }\n\n for (const v of violations) {\n const icon = v.severity === 'error' ? chalk.red('✗') : chalk.yellow('!');\n console.log(`${icon} ${chalk.dim(v.rule)} ${v.file}: ${v.message}`);\n }\n\n const word = violations.length === 1 ? 'violation' : 'violations';\n console.log(`\\n${violations.length} ${word} found.`);\n\n if (config.enforcement === 'enforce') {\n console.log(chalk.red('Fix violations before committing.'));\n return 1;\n }\n\n return 0;\n}\n","import type { ConfigConventions, ConfigRules, ViberailsConfig } from '@viberails/types';\n\nexport interface ResolvedConfig {\n rules: ConfigRules;\n conventions: ConfigConventions;\n}\n\n/**\n * Resolve the effective config for a file by finding its package override.\n * Returns the global config merged with any matching package overrides.\n */\nexport function resolveConfigForFile(relPath: string, config: ViberailsConfig): ResolvedConfig {\n if (!config.packages || config.packages.length === 0) {\n return { rules: config.rules, conventions: config.conventions };\n }\n\n // Sort by path length descending to match the most specific package first\n const sortedPackages = [...config.packages].sort((a, b) => b.path.length - a.path.length);\n\n for (const pkg of sortedPackages) {\n if (relPath.startsWith(`${pkg.path}/`) || relPath === pkg.path) {\n return {\n rules: { ...config.rules, ...pkg.rules },\n conventions: { ...config.conventions, ...pkg.conventions },\n };\n }\n }\n\n return { rules: config.rules, conventions: config.conventions };\n}\n\n/**\n * Resolve ignore patterns for a file, appending any package-specific patterns.\n */\nexport function resolveIgnoreForFile(relPath: string, config: ViberailsConfig): string[] {\n const globalIgnore = config.ignore;\n if (!config.packages) return globalIgnore;\n\n for (const pkg of config.packages) {\n if (pkg.ignore && relPath.startsWith(`${pkg.path}/`)) {\n return [...globalIgnore, ...pkg.ignore];\n }\n }\n return globalIgnore;\n}\n","import { execSync } from 'node:child_process';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { ConfigConventions, ConventionValue, ViberailsConfig } from '@viberails/types';\n\nconst ALWAYS_SKIP_DIRS = new Set([\n 'node_modules',\n '.git',\n 'dist',\n 'build',\n '.next',\n '.expo',\n '.output',\n '.svelte-kit',\n '.turbo',\n 'coverage',\n '.viberails',\n]);\n\nexport const SOURCE_EXTS = new Set([\n '.ts',\n '.tsx',\n '.js',\n '.jsx',\n '.mjs',\n '.cjs',\n '.vue',\n '.svelte',\n '.astro',\n]);\n\nexport const NAMING_PATTERNS: Record<string, RegExp> = {\n 'kebab-case': /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/,\n camelCase: /^[a-z][a-zA-Z0-9]*$/,\n PascalCase: /^[A-Z][a-zA-Z0-9]*$/,\n snake_case: /^[a-z][a-z0-9]*(_[a-z0-9]+)*$/,\n};\n\n/** Check if a path matches any ignore pattern. */\nexport function isIgnored(relPath: string, ignorePatterns: string[]): boolean {\n for (const pattern of ignorePatterns) {\n if (pattern.endsWith('/**')) {\n const prefix = pattern.slice(0, -3);\n if (relPath.startsWith(`${prefix}/`) || relPath === prefix) return true;\n } else if (pattern.startsWith('**/')) {\n const suffix = pattern.slice(3);\n if (relPath.endsWith(suffix)) return true;\n } else if (relPath === pattern || relPath.startsWith(`${pattern}/`)) {\n return true;\n }\n }\n return false;\n}\n\n/** Count lines in a file. Returns null if the file can't be read. */\nexport function countFileLines(filePath: string): number | null {\n try {\n const content = fs.readFileSync(filePath, 'utf-8');\n if (content.length === 0) return 0;\n let count = 1;\n for (let i = 0; i < content.length; i++) {\n if (content.charCodeAt(i) === 10) count++;\n }\n return count;\n } catch {\n return null;\n }\n}\n\n/** Check whether a file's name violates the configured naming convention. */\nexport function checkNaming(relPath: string, conventions: ConfigConventions): string | undefined {\n const filename = path.basename(relPath);\n\n // Skip non-source files\n const ext = path.extname(filename);\n if (!SOURCE_EXTS.has(ext)) return undefined;\n\n // Skip special files\n if (\n filename.startsWith('index.') ||\n filename.includes('.config.') ||\n filename.includes('.test.') ||\n filename.includes('.spec.') ||\n filename.startsWith('.') ||\n filename.startsWith('_') ||\n filename.startsWith('+') ||\n filename.startsWith('$') ||\n filename.startsWith('[')\n ) {\n return undefined;\n }\n\n const bare = filename.slice(0, filename.indexOf('.'));\n const convention =\n typeof conventions.fileNaming === 'string'\n ? conventions.fileNaming\n : (conventions.fileNaming as Exclude<ConventionValue, string> | undefined)?.value;\n\n if (!convention) return undefined;\n\n const pattern = NAMING_PATTERNS[convention];\n if (!pattern || pattern.test(bare)) return undefined;\n\n return `File name \"${filename}\" does not follow ${convention} convention.`;\n}\n\n/** Get staged files from git. */\nexport function getStagedFiles(projectRoot: string): string[] {\n try {\n const output = execSync('git diff --cached --name-only --diff-filter=ACM', {\n cwd: projectRoot,\n encoding: 'utf-8',\n });\n return output.trim().split('\\n').filter(Boolean);\n } catch {\n return [];\n }\n}\n\n/** Get all source files in the project. */\nexport function getAllSourceFiles(projectRoot: string, config: ViberailsConfig): string[] {\n const files: string[] = [];\n const walk = (dir: string) => {\n let entries: fs.Dirent[];\n try {\n entries = fs.readdirSync(dir, { withFileTypes: true });\n } catch {\n return;\n }\n for (const entry of entries) {\n const rel = path.relative(projectRoot, path.join(dir, entry.name));\n if (entry.isDirectory()) {\n if (ALWAYS_SKIP_DIRS.has(entry.name)) {\n continue;\n }\n if (isIgnored(rel, config.ignore)) continue;\n walk(path.join(dir, entry.name));\n } else if (entry.isFile()) {\n const ext = path.extname(entry.name);\n if (SOURCE_EXTS.has(ext) && !isIgnored(rel, config.ignore)) {\n files.push(rel);\n }\n }\n }\n };\n walk(projectRoot);\n return files;\n}\n\n/** Collect source files from a directory recursively. */\nexport function collectSourceFiles(dir: string, projectRoot: string): string[] {\n const files: string[] = [];\n const walk = (d: string) => {\n let entries: fs.Dirent[];\n try {\n entries = fs.readdirSync(d, { withFileTypes: true });\n } catch {\n return;\n }\n for (const entry of entries) {\n if (entry.isDirectory()) {\n if (entry.name === 'node_modules') continue;\n walk(path.join(d, entry.name));\n } else if (entry.isFile()) {\n files.push(path.relative(projectRoot, path.join(d, entry.name)));\n }\n }\n };\n walk(dir);\n return files;\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { CheckViolation, ViberailsConfig } from '@viberails/types';\nimport { collectSourceFiles } from './check-files.js';\n\nconst SOURCE_EXTS = new Set([\n '.ts',\n '.tsx',\n '.js',\n '.jsx',\n '.mjs',\n '.cjs',\n '.vue',\n '.svelte',\n '.astro',\n]);\n\n/** Check for source files without corresponding test files. */\nexport function checkMissingTests(\n projectRoot: string,\n config: ViberailsConfig,\n severity: 'error' | 'warn',\n): CheckViolation[] {\n const violations: CheckViolation[] = [];\n const { testPattern } = config.structure;\n if (!testPattern) return violations;\n\n const srcDir = config.structure.srcDir;\n if (!srcDir) return violations;\n\n const srcPath = path.join(projectRoot, srcDir);\n if (!fs.existsSync(srcPath)) return violations;\n\n const testSuffix = testPattern.replace('*', '');\n const sourceFiles = collectSourceFiles(srcPath, projectRoot);\n\n for (const relFile of sourceFiles) {\n const basename = path.basename(relFile);\n\n // Skip test files, index files, type definition files\n if (\n basename.includes('.test.') ||\n basename.includes('.spec.') ||\n basename.startsWith('index.') ||\n basename.endsWith('.d.ts')\n ) {\n continue;\n }\n\n const ext = path.extname(basename);\n if (!SOURCE_EXTS.has(ext)) continue;\n\n const stem = basename.slice(0, basename.indexOf('.'));\n const expectedTestFile = `${stem}${testSuffix}`;\n\n // Look for the test file next to the source or in the tests directory\n const dir = path.dirname(path.join(projectRoot, relFile));\n const colocatedTest = path.join(dir, expectedTestFile);\n const testsDir = config.structure.tests;\n const dedicatedTest = testsDir ? path.join(projectRoot, testsDir, expectedTestFile) : null;\n\n const hasTest =\n fs.existsSync(colocatedTest) || (dedicatedTest !== null && fs.existsSync(dedicatedTest));\n\n if (!hasTest) {\n violations.push({\n file: relFile,\n rule: 'missing-test',\n message: `No test file found. Expected \\`${expectedTestFile}\\`.`,\n severity,\n });\n }\n }\n\n return violations;\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { loadConfig } from '@viberails/config';\nimport chalk from 'chalk';\nimport { findProjectRoot } from '../utils/find-project-root.js';\nimport { resolveConfigForFile } from './check-config.js';\nimport { checkNaming, getAllSourceFiles } from './check-files.js';\nimport { checkMissingTests } from './check-tests.js';\nimport { checkGitDirty, getConventionValue, printPlan, promptConfirm } from './fix-helpers.js';\nimport { updateImportsAfterRenames } from './fix-imports.js';\nimport {\n computeRename,\n deduplicateRenames,\n executeRename,\n type RenameRecord,\n} from './fix-naming.js';\nimport { generateTestStub, type TestStubRecord, writeTestStub } from './fix-tests.js';\n\nconst CONFIG_FILE = 'viberails.config.json';\n\nexport interface FixOptions {\n dryRun?: boolean;\n rule?: string[];\n yes?: boolean;\n}\n\n/**\n * Run the viberails fix command.\n * Detects violations, computes fixes, optionally confirms, then applies.\n */\nexport async function fixCommand(options: FixOptions, cwd?: string): Promise<number> {\n const startDir = cwd ?? process.cwd();\n const projectRoot = findProjectRoot(startDir);\n\n if (!projectRoot) {\n console.error(`${chalk.red('Error:')} No package.json found. Are you in a JS/TS project?`);\n return 1;\n }\n\n const configPath = path.join(projectRoot, CONFIG_FILE);\n if (!fs.existsSync(configPath)) {\n console.error(\n `${chalk.red('Error:')} No viberails.config.json found. Run \\`viberails init\\` first.`,\n );\n return 1;\n }\n\n const config = await loadConfig(configPath);\n\n // Git dirty check — warn but don't block\n if (!options.dryRun) {\n const isDirty = checkGitDirty(projectRoot);\n if (isDirty) {\n console.log(\n chalk.yellow('Warning: You have uncommitted changes. Consider committing first.'),\n );\n }\n }\n\n const shouldFixNaming = !options.rule || options.rule.includes('file-naming');\n const shouldFixTests = !options.rule || options.rule.includes('missing-test');\n\n // Collect source files\n const allFiles = getAllSourceFiles(projectRoot, config);\n\n // Compute naming renames\n const renames: RenameRecord[] = [];\n if (shouldFixNaming) {\n for (const file of allFiles) {\n const resolved = resolveConfigForFile(file, config);\n if (!resolved.rules.enforceNaming || !resolved.conventions.fileNaming) continue;\n\n const violation = checkNaming(file, resolved.conventions);\n if (!violation) continue;\n\n const convention = getConventionValue(resolved.conventions.fileNaming);\n if (!convention) continue;\n\n const rename = computeRename(file, convention, projectRoot);\n if (rename) renames.push(rename);\n }\n }\n\n const dedupedRenames = deduplicateRenames(renames);\n\n // Compute test stubs\n const testStubs: TestStubRecord[] = [];\n if (shouldFixTests && config.rules.requireTests) {\n const testViolations = checkMissingTests(projectRoot, config, 'warn');\n for (const v of testViolations) {\n const stub = generateTestStub(v.file, config, projectRoot);\n if (stub) testStubs.push(stub);\n }\n }\n\n // Nothing to fix\n if (dedupedRenames.length === 0 && testStubs.length === 0) {\n console.log(`${chalk.green('✓')} No fixable violations found.`);\n return 0;\n }\n\n // Display plan\n printPlan(dedupedRenames, testStubs);\n\n if (options.dryRun) {\n console.log(chalk.dim('\\nDry run — no changes applied.'));\n return 0;\n }\n\n // Confirm\n if (!options.yes) {\n const confirmed = await promptConfirm('Apply these fixes?');\n if (!confirmed) {\n console.log('Aborted.');\n return 0;\n }\n }\n\n // Apply: 1. Renames\n let renameCount = 0;\n for (const rename of dedupedRenames) {\n if (executeRename(rename)) {\n renameCount++;\n }\n }\n\n // Apply: 2. Import updates\n let importUpdateCount = 0;\n if (renameCount > 0) {\n const appliedRenames = dedupedRenames.filter((r) => fs.existsSync(r.newAbsPath));\n const updates = await updateImportsAfterRenames(appliedRenames, projectRoot);\n importUpdateCount = updates.length;\n }\n\n // Apply: 3. Test stubs\n let stubCount = 0;\n for (const stub of testStubs) {\n if (!fs.existsSync(stub.absPath)) {\n writeTestStub(stub, config);\n stubCount++;\n }\n }\n\n // Summary\n console.log('');\n if (renameCount > 0) {\n console.log(`${chalk.green('✓')} Renamed ${renameCount} file${renameCount > 1 ? 's' : ''}`);\n }\n if (importUpdateCount > 0) {\n console.log(\n `${chalk.green('✓')} Updated ${importUpdateCount} import${importUpdateCount > 1 ? 's' : ''}`,\n );\n }\n if (stubCount > 0) {\n console.log(`${chalk.green('✓')} Generated ${stubCount} test stub${stubCount > 1 ? 's' : ''}`);\n }\n\n return 0;\n}\n","import { execSync } from 'node:child_process';\nimport { createInterface } from 'node:readline';\nimport chalk from 'chalk';\nimport type { RenameRecord } from './fix-naming.js';\nimport type { TestStubRecord } from './fix-tests.js';\n\n/**\n * Display the planned renames and test stubs.\n */\nexport function printPlan(renames: RenameRecord[], stubs: TestStubRecord[]): void {\n if (renames.length > 0) {\n console.log(chalk.bold('\\nFile renames:'));\n for (const r of renames) {\n console.log(` ${chalk.red(r.oldPath)} → ${chalk.green(r.newPath)}`);\n }\n }\n\n if (stubs.length > 0) {\n console.log(chalk.bold('\\nTest stubs to create:'));\n for (const s of stubs) {\n console.log(` ${chalk.green('+')} ${s.path}`);\n }\n }\n}\n\n/**\n * Check if the git working tree has uncommitted changes.\n */\nexport function checkGitDirty(projectRoot: string): boolean {\n try {\n const output = execSync('git status --porcelain', {\n cwd: projectRoot,\n encoding: 'utf-8',\n });\n return output.trim().length > 0;\n } catch {\n return false;\n }\n}\n\n/**\n * Extract the string value from a convention (which may be a string or an object with a value property).\n */\nexport function getConventionValue(convention: unknown): string | undefined {\n if (typeof convention === 'string') return convention;\n if (convention && typeof convention === 'object' && 'value' in convention) {\n return (convention as { value: string }).value;\n }\n return undefined;\n}\n\n/**\n * Prompt the user to confirm an action.\n */\nexport function promptConfirm(question: string): Promise<boolean> {\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n return new Promise((resolve) => {\n rl.question(`${question} (y/N) `, (answer) => {\n rl.close();\n resolve(answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes');\n });\n });\n}\n","import * as path from 'node:path';\nimport type { RenameRecord } from './fix-naming.js';\n\nexport interface ImportUpdateRecord {\n file: string;\n oldSpecifier: string;\n newSpecifier: string;\n line: number;\n}\n\n/**\n * Strip known JS/TS extensions from a file path for specifier comparison.\n * E.g. \"/foo/bar.ts\" → \"/foo/bar\", \"/foo/bar.js\" → \"/foo/bar\"\n */\nfunction stripExtension(filePath: string): string {\n return filePath.replace(/\\.(tsx?|jsx?|mjs|cjs)$/, '');\n}\n\n/**\n * Compute the new import specifier given the old specifier and the rename.\n * Preserves `.js` suffix if present.\n */\nfunction computeNewSpecifier(oldSpecifier: string, newBare: string): string {\n const hasJsExt = oldSpecifier.endsWith('.js');\n const base = hasJsExt ? oldSpecifier.slice(0, -3) : oldSpecifier;\n\n // Replace the last path segment\n const dir = base.lastIndexOf('/');\n const prefix = dir >= 0 ? base.slice(0, dir + 1) : '';\n const newSpec = prefix + newBare;\n\n return hasJsExt ? `${newSpec}.js` : newSpec;\n}\n\n/**\n * Update import specifiers in all source files after renames.\n * Uses ts-morph for AST-accurate rewriting.\n *\n * @param renames - The renames that were applied\n * @param projectRoot - Absolute path to project root\n * @returns Records of all import updates made\n */\nexport async function updateImportsAfterRenames(\n renames: RenameRecord[],\n projectRoot: string,\n): Promise<ImportUpdateRecord[]> {\n if (renames.length === 0) return [];\n\n // Lazy import ts-morph to avoid startup cost\n const { Project, SyntaxKind } = await import('ts-morph');\n\n // Build rename map: stripped old abs path → { newBare }\n const renameMap = new Map<string, { newBare: string }>();\n for (const r of renames) {\n const oldStripped = stripExtension(r.oldAbsPath);\n const newFilename = path.basename(r.newPath);\n const newName = newFilename.slice(0, newFilename.indexOf('.'));\n renameMap.set(oldStripped, { newBare: newName });\n }\n\n const project = new Project({\n tsConfigFilePath: undefined,\n skipAddingFilesFromTsConfig: true,\n });\n\n // Add all TS/JS source files\n project.addSourceFilesAtPaths(path.join(projectRoot, '**/*.{ts,tsx,js,jsx,mjs,cjs}'));\n\n const updates: ImportUpdateRecord[] = [];\n const extensions = ['', '.ts', '.tsx', '.js', '.jsx', '/index.ts', '/index.tsx', '/index.js'];\n\n for (const sourceFile of project.getSourceFiles()) {\n const filePath = sourceFile.getFilePath();\n // Skip node_modules and dist\n if (filePath.includes('/node_modules/') || filePath.includes('/dist/')) continue;\n\n const fileDir = path.dirname(filePath);\n\n // Process static imports\n for (const decl of sourceFile.getImportDeclarations()) {\n const specifier = decl.getModuleSpecifierValue();\n if (!specifier.startsWith('.')) continue;\n\n const match = resolveToRenamedFile(specifier, fileDir, renameMap, extensions);\n if (!match) continue;\n\n const newSpec = computeNewSpecifier(specifier, match.newBare);\n updates.push({\n file: filePath,\n oldSpecifier: specifier,\n newSpecifier: newSpec,\n line: decl.getStartLineNumber(),\n });\n decl.setModuleSpecifier(newSpec);\n }\n\n // Process re-exports\n for (const decl of sourceFile.getExportDeclarations()) {\n const specifier = decl.getModuleSpecifierValue();\n if (!specifier || !specifier.startsWith('.')) continue;\n\n const match = resolveToRenamedFile(specifier, fileDir, renameMap, extensions);\n if (!match) continue;\n\n const newSpec = computeNewSpecifier(specifier, match.newBare);\n updates.push({\n file: filePath,\n oldSpecifier: specifier,\n newSpecifier: newSpec,\n line: decl.getStartLineNumber(),\n });\n decl.setModuleSpecifier(newSpec);\n }\n\n // Process dynamic imports\n for (const call of sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression)) {\n if (call.getExpression().getKind() !== SyntaxKind.ImportKeyword) continue;\n\n const args = call.getArguments();\n if (args.length === 0) continue;\n\n const arg = args[0];\n if (arg.getKind() !== SyntaxKind.StringLiteral) continue;\n\n const specifier = arg.getText().slice(1, -1);\n if (!specifier.startsWith('.')) continue;\n\n const match = resolveToRenamedFile(specifier, fileDir, renameMap, extensions);\n if (!match) continue;\n\n const newSpec = computeNewSpecifier(specifier, match.newBare);\n updates.push({\n file: filePath,\n oldSpecifier: specifier,\n newSpecifier: newSpec,\n line: call.getStartLineNumber(),\n });\n // Replace the string literal content\n const quote = arg.getText()[0];\n arg.replaceWithText(`${quote}${newSpec}${quote}`);\n }\n }\n\n if (updates.length > 0) {\n await project.save();\n }\n\n return updates;\n}\n\n/**\n * Try to resolve a relative specifier to a renamed file.\n * Returns the rename info if matched, undefined otherwise.\n */\nfunction resolveToRenamedFile(\n specifier: string,\n fromDir: string,\n renameMap: Map<string, { newBare: string }>,\n extensions: string[],\n): { newBare: string } | undefined {\n // Strip .js extension for resolution (TypeScript convention)\n const cleanSpec = specifier.endsWith('.js') ? specifier.slice(0, -3) : specifier;\n const resolved = path.resolve(fromDir, cleanSpec);\n\n for (const ext of extensions) {\n const candidate = resolved + ext;\n const stripped = stripExtension(candidate);\n const match = renameMap.get(stripped);\n if (match) return match;\n }\n\n return undefined;\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { convertName } from './convert-name.js';\n\nexport interface RenameRecord {\n oldPath: string;\n newPath: string;\n oldAbsPath: string;\n newAbsPath: string;\n}\n\n/**\n * Compute the rename for a file that violates the naming convention.\n * Returns null if no rename is needed or the target already exists.\n */\nexport function computeRename(\n relPath: string,\n targetConvention: string,\n projectRoot: string,\n): RenameRecord | null {\n const filename = path.basename(relPath);\n const dir = path.dirname(relPath);\n\n // Extract bare name (before first dot) — matches checkNaming logic\n const dotIndex = filename.indexOf('.');\n if (dotIndex === -1) return null;\n\n const bare = filename.slice(0, dotIndex);\n const suffix = filename.slice(dotIndex); // e.g. \".tsx\" or \".test.ts\"\n\n const newBare = convertName(bare, targetConvention);\n if (newBare === bare) return null;\n\n const newFilename = newBare + suffix;\n const newRelPath = path.join(dir, newFilename);\n const oldAbsPath = path.join(projectRoot, relPath);\n const newAbsPath = path.join(projectRoot, newRelPath);\n\n // Skip if target already exists\n if (fs.existsSync(newAbsPath)) return null;\n\n return { oldPath: relPath, newPath: newRelPath, oldAbsPath, newAbsPath };\n}\n\n/**\n * Execute a single rename on disk.\n * Returns true if successful, false if skipped (target exists).\n */\nexport function executeRename(rename: RenameRecord): boolean {\n if (fs.existsSync(rename.newAbsPath)) return false;\n fs.renameSync(rename.oldAbsPath, rename.newAbsPath);\n return true;\n}\n\n/**\n * Detect and deduplicate rename collisions.\n * If two planned renames target the same path, the second is removed.\n */\nexport function deduplicateRenames(renames: RenameRecord[]): RenameRecord[] {\n const seen = new Set<string>();\n const result: RenameRecord[] = [];\n for (const r of renames) {\n if (seen.has(r.newAbsPath)) continue;\n seen.add(r.newAbsPath);\n result.push(r);\n }\n return result;\n}\n","/**\n * Split a bare filename into its constituent words.\n *\n * Handles kebab-case, camelCase, PascalCase, and snake_case inputs.\n * Consecutive uppercase letters (acronyms like \"URL\") are kept together.\n */\nexport function splitIntoWords(name: string): string[] {\n // First, split on explicit separators (hyphens and underscores)\n const parts = name.split(/[-_]/);\n\n const words: string[] = [];\n for (const part of parts) {\n if (part === '') continue;\n\n // Split camelCase and PascalCase boundaries\n // \"UserProfile\" → [\"User\", \"Profile\"]\n // \"parseJSON\" → [\"parse\", \"JSON\"]\n // \"XMLParser\" → [\"XML\", \"Parser\"]\n let current = '';\n for (let i = 0; i < part.length; i++) {\n const ch = part[i];\n const isUpper = ch >= 'A' && ch <= 'Z';\n\n if (isUpper && current.length > 0) {\n const prevIsUpper =\n current[current.length - 1] >= 'A' && current[current.length - 1] <= 'Z';\n const nextIsLower = i + 1 < part.length && part[i + 1] >= 'a' && part[i + 1] <= 'z';\n\n if (!prevIsUpper || nextIsLower) {\n words.push(current.toLowerCase());\n current = '';\n }\n }\n current += ch;\n }\n if (current) words.push(current.toLowerCase());\n }\n\n return words;\n}\n\n/**\n * Convert a bare filename to the specified naming convention.\n *\n * @param bare - The bare filename without extension (e.g. \"UserProfile\")\n * @param target - The target convention (kebab-case, camelCase, PascalCase, snake_case)\n * @returns The converted name\n */\nexport function convertName(bare: string, target: string): string {\n const words = splitIntoWords(bare);\n if (words.length === 0) return bare;\n\n switch (target) {\n case 'kebab-case':\n return words.join('-');\n case 'camelCase':\n return words[0] + words.slice(1).map(capitalize).join('');\n case 'PascalCase':\n return words.map(capitalize).join('');\n case 'snake_case':\n return words.join('_');\n default:\n return bare;\n }\n}\n\nfunction capitalize(word: string): string {\n if (word.length === 0) return word;\n return word[0].toUpperCase() + word.slice(1);\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { ViberailsConfig } from '@viberails/types';\n\nexport interface TestStubRecord {\n path: string;\n absPath: string;\n moduleName: string;\n}\n\n/**\n * Generate a test stub record for a source file that is missing tests.\n * Returns null if the test file already exists.\n */\nexport function generateTestStub(\n sourceRelPath: string,\n config: ViberailsConfig,\n projectRoot: string,\n): TestStubRecord | null {\n const { testPattern } = config.structure;\n if (!testPattern) return null;\n\n const basename = path.basename(sourceRelPath);\n const stem = basename.slice(0, basename.indexOf('.'));\n const testSuffix = testPattern.replace('*', '');\n const testFilename = `${stem}${testSuffix}`;\n\n const dir = path.dirname(path.join(projectRoot, sourceRelPath));\n const testAbsPath = path.join(dir, testFilename);\n\n if (fs.existsSync(testAbsPath)) return null;\n\n return {\n path: path.relative(projectRoot, testAbsPath),\n absPath: testAbsPath,\n moduleName: stem,\n };\n}\n\n/**\n * Write a test stub file to disk.\n */\nexport function writeTestStub(stub: TestStubRecord, config: ViberailsConfig): void {\n const runner = config.stack.testRunner === 'jest' ? 'jest' : 'vitest';\n const importLine =\n runner === 'jest'\n ? '' // jest globals are available without import\n : \"import { describe, it, expect } from 'vitest';\\n\\n\";\n\n const content = `${importLine}describe('${stub.moduleName}', () => {\\n it.todo('add tests');\\n});\\n`;\n\n fs.mkdirSync(path.dirname(stub.absPath), { recursive: true });\n fs.writeFileSync(stub.absPath, content);\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { generateConfig } from '@viberails/config';\nimport { scan } from '@viberails/scanner';\nimport type { ConfigConventions, ConventionValue } from '@viberails/types';\nimport chalk from 'chalk';\nimport { displayScanResults } from '../display.js';\nimport { findProjectRoot } from '../utils/find-project-root.js';\nimport { confirm } from '../utils/prompt.js';\nimport { resolveWorkspacePackages } from '../utils/resolve-workspace-packages.js';\nimport { writeGeneratedFiles } from '../utils/write-generated-files.js';\nimport { setupPreCommitHook } from './init-hooks.js';\n\nconst CONFIG_FILE = 'viberails.config.json';\n\n/**\n * Filter a ConfigConventions object to only include high-confidence entries.\n */\nfunction filterHighConfidence(conventions: ConfigConventions): ConfigConventions {\n const filtered: ConfigConventions = {};\n for (const [key, value] of Object.entries(conventions)) {\n if (value === undefined) continue;\n if (typeof value === 'string') {\n filtered[key as keyof ConfigConventions] = value;\n } else if (value._confidence === 'high') {\n filtered[key as keyof ConfigConventions] = value as ConventionValue;\n }\n }\n return filtered;\n}\n\n/**\n * Run the viberails init flow.\n *\n * @param options - CLI options\n * @param cwd - Working directory override (for testing)\n */\nexport async function initCommand(options: { yes?: boolean }, cwd?: string): Promise<void> {\n const startDir = cwd ?? process.cwd();\n\n // 1. Find project root\n const projectRoot = findProjectRoot(startDir);\n if (!projectRoot) {\n throw new Error(\n 'No package.json found in this directory or any parent.\\n\\n' +\n 'Make sure you are inside a JavaScript or TypeScript project, then run:\\n' +\n ' npx viberails',\n );\n }\n\n // 2. Check for existing config\n const configPath = path.join(projectRoot, CONFIG_FILE);\n if (fs.existsSync(configPath)) {\n console.log(\n chalk.yellow('!') +\n ' viberails is already initialized in this project.\\n' +\n ' Run ' +\n chalk.cyan('viberails sync') +\n ' to update the generated files.',\n );\n return;\n }\n\n // 3. Run scanner\n console.log(chalk.dim('Scanning project...'));\n const scanResult = await scan(projectRoot);\n\n // 4. Display results\n displayScanResults(scanResult);\n\n // 5. Sparse project notice\n if (scanResult.statistics.totalFiles === 0) {\n console.log(\n chalk.yellow('!') +\n ' No source files detected. viberails will generate context with minimal content.\\n' +\n ' Run ' +\n chalk.cyan('viberails sync') +\n ' after adding source files.\\n',\n );\n }\n\n // 6. Interactive confirmation\n if (!options.yes) {\n const accepted = await confirm('Does this look right?');\n if (!accepted) {\n console.log('Aborted.');\n return;\n }\n }\n\n // 7. Generate config\n const config = generateConfig(scanResult);\n if (options.yes) {\n config.conventions = filterHighConfidence(config.conventions);\n }\n\n // 7b. Infer boundary rules for workspace projects\n if (config.workspace && config.workspace.packages.length > 0) {\n let shouldInfer = options.yes;\n if (!options.yes) {\n shouldInfer = await confirm('Infer boundary rules from import patterns?');\n }\n\n if (shouldInfer) {\n console.log(chalk.dim('Building import graph...'));\n const { buildImportGraph, inferBoundaries } = await import('@viberails/graph');\n const packages = resolveWorkspacePackages(projectRoot, config.workspace);\n const graph = await buildImportGraph(projectRoot, { packages, ignore: config.ignore });\n const inferred = inferBoundaries(graph);\n if (inferred.length > 0) {\n config.boundaries = inferred;\n config.rules.enforceBoundaries = true;\n console.log(` ${chalk.green('✓')} Inferred ${inferred.length} boundary rules`);\n }\n }\n }\n\n fs.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\\n`);\n\n // 8. Generate context and scan-result.json\n writeGeneratedFiles(projectRoot, config, scanResult);\n\n // 9. Update .gitignore\n updateGitignore(projectRoot);\n\n // 10. Set up pre-commit hook\n setupPreCommitHook(projectRoot);\n\n // 11. Print summary\n console.log(`\\n${chalk.bold('Created:')}`);\n console.log(` ${chalk.green('✓')} ${CONFIG_FILE}`);\n console.log(` ${chalk.green('✓')} .viberails/context.md`);\n console.log(` ${chalk.green('✓')} .viberails/scan-result.json`);\n console.log(`\\n${chalk.bold('Next steps:')}`);\n console.log(` 1. Review ${chalk.cyan('viberails.config.json')} and adjust rules`);\n console.log(\n ` 2. Commit ${chalk.cyan('viberails.config.json')} and ${chalk.cyan('.viberails/context.md')}`,\n );\n console.log(` 3. Run ${chalk.cyan('viberails check')} to verify your project passes`);\n}\n\n/**\n * Append viberails entries to .gitignore if not already present.\n * Only scan-result.json is ignored — context.md should be committed\n * so AI agents can read the enforced rules.\n */\nfunction updateGitignore(projectRoot: string): void {\n const gitignorePath = path.join(projectRoot, '.gitignore');\n let content = '';\n\n if (fs.existsSync(gitignorePath)) {\n content = fs.readFileSync(gitignorePath, 'utf-8');\n }\n\n if (!content.includes('.viberails/scan-result.json')) {\n const block = '\\n# viberails\\n.viberails/scan-result.json\\n';\n fs.writeFileSync(gitignorePath, `${content.trimEnd()}\\n${block}`);\n }\n}\n","import type { DetectedConvention, ScanResult, StackItem } from '@viberails/types';\nimport { FRAMEWORK_NAMES, LIBRARY_NAMES, STYLING_NAMES } from '@viberails/types';\nimport chalk from 'chalk';\nimport {\n formatExtensions,\n formatRoleGroup,\n formatSummary,\n groupByRole,\n} from './display-helpers.js';\nimport { displayMonorepoResults } from './display-monorepo.js';\n\n/** Labels for convention keys. */\nconst CONVENTION_LABELS: Record<string, string> = {\n fileNaming: 'File naming',\n componentNaming: 'Component naming',\n hookNaming: 'Hook naming',\n importAlias: 'Import alias',\n};\n\n/**\n * Format a StackItem for display: \"DisplayName Version\".\n */\nexport function formatItem(item: StackItem, nameMap?: Record<string, string>): string {\n const name = nameMap?.[item.name] ?? item.name;\n return item.version ? `${name} ${item.version}` : name;\n}\n\n/**\n * Format a confidence label for display.\n */\nexport function confidenceLabel(convention: DetectedConvention): string {\n const pct = Math.round(convention.consistency);\n if (convention.confidence === 'high') {\n return `${pct}% — high confidence, will enforce`;\n }\n return `${pct}% — medium confidence, suggested only`;\n}\n\n/**\n * Display conventions section, shared between single-package and monorepo.\n */\nexport function displayConventions(scanResult: ScanResult): void {\n const conventionEntries = Object.entries(scanResult.conventions);\n if (conventionEntries.length === 0) return;\n\n console.log(`\\n${chalk.bold('Conventions:')}`);\n for (const [key, convention] of conventionEntries) {\n if (convention.confidence === 'low') continue;\n const label = CONVENTION_LABELS[key] ?? key;\n\n if (scanResult.packages.length > 1) {\n const pkgValues = scanResult.packages\n .filter((pkg) => pkg.conventions[key] && pkg.conventions[key].confidence !== 'low')\n .map((pkg) => ({ relativePath: pkg.relativePath, convention: pkg.conventions[key] }));\n\n const allSame = pkgValues.every((pv) => pv.convention.value === convention.value);\n\n if (allSame || pkgValues.length <= 1) {\n const ind = convention.confidence === 'high' ? chalk.green('✓') : chalk.yellow('~');\n const detail = chalk.dim(`(${confidenceLabel(convention)})`);\n console.log(` ${ind} ${label}: ${convention.value} ${detail}`);\n } else {\n console.log(` ${chalk.yellow('~')} ${label}: varies by package`);\n for (const pv of pkgValues) {\n const pct = Math.round(pv.convention.consistency);\n console.log(` ${pv.relativePath}: ${pv.convention.value} (${pct}%)`);\n }\n }\n } else {\n const ind = convention.confidence === 'high' ? chalk.green('✓') : chalk.yellow('~');\n const detail = chalk.dim(`(${confidenceLabel(convention)})`);\n console.log(` ${ind} ${label}: ${convention.value} ${detail}`);\n }\n }\n}\n\n/**\n * Display summary section with statistics.\n */\nexport function displaySummarySection(scanResult: ScanResult): void {\n const pkgCount = scanResult.packages.length > 1 ? scanResult.packages.length : undefined;\n console.log(`\\n${chalk.bold('Summary:')}`);\n console.log(` ${formatSummary(scanResult.statistics, pkgCount)}`);\n const ext = formatExtensions(scanResult.statistics.filesByExtension);\n if (ext) {\n console.log(` ${ext}`);\n }\n}\n\n/**\n * Display scan results to the console with confidence indicators.\n *\n * @param scanResult - The scan result to display\n */\nexport function displayScanResults(scanResult: ScanResult): void {\n if (scanResult.packages.length > 1) {\n displayMonorepoResults(scanResult);\n return;\n }\n\n const { stack } = scanResult;\n\n console.log(`\\n${chalk.bold('Detected:')}`);\n\n if (stack.framework) {\n console.log(` ${chalk.green('✓')} ${formatItem(stack.framework, FRAMEWORK_NAMES)}`);\n }\n console.log(` ${chalk.green('✓')} ${formatItem(stack.language)}`);\n if (stack.styling) {\n console.log(` ${chalk.green('✓')} ${formatItem(stack.styling, STYLING_NAMES)}`);\n }\n if (stack.backend) {\n console.log(` ${chalk.green('✓')} ${formatItem(stack.backend, FRAMEWORK_NAMES)}`);\n }\n if (stack.linter) {\n console.log(` ${chalk.green('✓')} ${formatItem(stack.linter)}`);\n }\n if (stack.formatter) {\n console.log(` ${chalk.green('✓')} ${formatItem(stack.formatter)}`);\n }\n if (stack.testRunner) {\n console.log(` ${chalk.green('✓')} ${formatItem(stack.testRunner)}`);\n }\n if (stack.packageManager) {\n console.log(` ${chalk.green('✓')} ${formatItem(stack.packageManager)}`);\n }\n if (stack.libraries.length > 0) {\n for (const lib of stack.libraries) {\n console.log(` ${chalk.green('✓')} ${formatItem(lib, LIBRARY_NAMES)}`);\n }\n }\n\n // Structure grouped by role\n const groups = groupByRole(scanResult.structure.directories);\n if (groups.length > 0) {\n console.log(`\\n${chalk.bold('Structure:')}`);\n for (const group of groups) {\n console.log(` ${chalk.green('✓')} ${formatRoleGroup(group)}`);\n }\n }\n\n displayConventions(scanResult);\n displaySummarySection(scanResult);\n console.log('');\n}\n","import type { CodebaseStatistics, DirectoryInfo, DirectoryRole } from '@viberails/types';\nimport { ROLE_DESCRIPTIONS } from '@viberails/types';\n\n/**\n * A group of directories sharing the same role within a package.\n */\nexport interface RoleGroup {\n role: DirectoryRole;\n label: string;\n dirCount: number;\n totalFiles: number;\n singlePath?: string;\n}\n\n/**\n * Groups a package's directories by role, merging file counts.\n * Filters out `unknown` role. For single-directory roles, sets `singlePath`.\n *\n * @param directories - The directories to group.\n * @returns Array of RoleGroup entries sorted by role label.\n */\nexport function groupByRole(directories: DirectoryInfo[]): RoleGroup[] {\n const map = new Map<DirectoryRole, { dirs: DirectoryInfo[] }>();\n\n for (const dir of directories) {\n if (dir.role === 'unknown') continue;\n const existing = map.get(dir.role);\n if (existing) {\n existing.dirs.push(dir);\n } else {\n map.set(dir.role, { dirs: [dir] });\n }\n }\n\n const groups: RoleGroup[] = [];\n for (const [role, { dirs }] of map) {\n const label = ROLE_DESCRIPTIONS[role] ?? role;\n const totalFiles = dirs.reduce((sum, d) => sum + d.fileCount, 0);\n groups.push({\n role,\n label,\n dirCount: dirs.length,\n totalFiles,\n singlePath: dirs.length === 1 ? dirs[0].path : undefined,\n });\n }\n\n return groups;\n}\n\n/**\n * Format a summary line from CodebaseStatistics.\n *\n * @param stats - The codebase statistics.\n * @param packageCount - Number of packages (shown for monorepos with > 1).\n * @returns Formatted summary string, e.g. \"3 packages · 743 source files · 48,200 lines · avg 65 lines/file\"\n */\nexport function formatSummary(stats: CodebaseStatistics, packageCount?: number): string {\n const parts: string[] = [];\n if (packageCount && packageCount > 1) {\n parts.push(`${packageCount} packages`);\n }\n parts.push(`${stats.totalFiles.toLocaleString()} source files`);\n parts.push(`${stats.totalLines.toLocaleString()} lines`);\n parts.push(`avg ${Math.round(stats.averageFileLines)} lines/file`);\n return parts.join(' \\u00b7 ');\n}\n\n/**\n * Format top extensions by count, e.g. \".tsx 312 · .ts 289 · .js 142\".\n *\n * @param filesByExtension - Extension counts from CodebaseStatistics.\n * @param maxEntries - Maximum number of extensions to show (default 4).\n * @returns Formatted extension string.\n */\nexport function formatExtensions(\n filesByExtension: Record<string, number>,\n maxEntries: number = 4,\n): string {\n return Object.entries(filesByExtension)\n .sort(([, a], [, b]) => b - a)\n .slice(0, maxEntries)\n .map(([ext, count]) => `${ext} ${count}`)\n .join(' \\u00b7 ');\n}\n\n/**\n * Format a RoleGroup for display.\n *\n * @param group - The role group.\n * @returns Formatted string, e.g. \"Hooks — 4 dirs (55 files)\" or \"Pages / Routes — app (12 files)\"\n */\nexport function formatRoleGroup(group: RoleGroup): string {\n const files = group.totalFiles === 1 ? '1 file' : `${group.totalFiles} files`;\n if (group.singlePath) {\n return `${group.label} — ${group.singlePath} (${files})`;\n }\n const dirs = group.dirCount === 1 ? '1 dir' : `${group.dirCount} dirs`;\n return `${group.label} — ${dirs} (${files})`;\n}\n","import type { PackageScanResult, ScanResult } from '@viberails/types';\nimport { FRAMEWORK_NAMES, STYLING_NAMES } from '@viberails/types';\nimport chalk from 'chalk';\nimport { displayConventions, displaySummarySection, formatItem } from './display.js';\nimport { formatRoleGroup, groupByRole } from './display-helpers.js';\n\n/**\n * Format a package summary line for monorepo display.\n */\nexport function formatPackageSummary(pkg: PackageScanResult): string {\n const parts: string[] = [];\n if (pkg.stack.framework) {\n parts.push(formatItem(pkg.stack.framework, FRAMEWORK_NAMES));\n }\n if (pkg.stack.styling) {\n parts.push(formatItem(pkg.stack.styling, STYLING_NAMES));\n }\n const files = `${pkg.statistics.totalFiles} files`;\n const detail = parts.length > 0 ? `${parts.join(', ')} (${files})` : `(${files})`;\n return ` ${pkg.relativePath} — ${detail}`;\n}\n\n/**\n * Display scan results for a monorepo with per-package summaries.\n */\nexport function displayMonorepoResults(scanResult: ScanResult): void {\n const { stack, packages } = scanResult;\n\n console.log(`\\n${chalk.bold(`Detected: (monorepo, ${packages.length} packages)`)}`);\n\n // Shared stack items at the top\n console.log(` ${chalk.green('✓')} ${formatItem(stack.language)}`);\n if (stack.packageManager) {\n console.log(` ${chalk.green('✓')} ${formatItem(stack.packageManager)}`);\n }\n if (stack.linter) {\n console.log(` ${chalk.green('✓')} ${formatItem(stack.linter)}`);\n }\n if (stack.formatter) {\n console.log(` ${chalk.green('✓')} ${formatItem(stack.formatter)}`);\n }\n if (stack.testRunner) {\n console.log(` ${chalk.green('✓')} ${formatItem(stack.testRunner)}`);\n }\n\n // Per-package summaries\n console.log('');\n for (const pkg of packages) {\n console.log(formatPackageSummary(pkg));\n }\n\n // Structure grouped by role per package\n const packagesWithDirs = packages.filter((pkg) =>\n pkg.structure.directories.some((d) => d.role !== 'unknown'),\n );\n if (packagesWithDirs.length > 0) {\n console.log(`\\n${chalk.bold('Structure:')}`);\n for (const pkg of packagesWithDirs) {\n const groups = groupByRole(pkg.structure.directories);\n if (groups.length === 0) continue;\n console.log(` ${pkg.relativePath}:`);\n for (const group of groups) {\n console.log(` ${chalk.green('✓')} ${formatRoleGroup(group)}`);\n }\n }\n }\n\n displayConventions(scanResult);\n displaySummarySection(scanResult);\n console.log('');\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { generateContext } from '@viberails/context';\nimport type { ScanResult, ViberailsConfig } from '@viberails/types';\n\nconst CONTEXT_DIR = '.viberails';\nconst CONTEXT_FILE = 'context.md';\nconst SCAN_RESULT_FILE = 'scan-result.json';\n\n/**\n * Write all generated files: context.md and scan-result.json.\n *\n * @param projectRoot - Absolute path to the project root\n * @param config - The viberails configuration\n * @param scanResult - The raw scan result\n */\nexport function writeGeneratedFiles(\n projectRoot: string,\n config: ViberailsConfig,\n scanResult: ScanResult,\n): void {\n const contextDir = path.join(projectRoot, CONTEXT_DIR);\n\n try {\n if (!fs.existsSync(contextDir)) {\n fs.mkdirSync(contextDir, { recursive: true });\n }\n\n const context = generateContext(config);\n fs.writeFileSync(path.join(contextDir, CONTEXT_FILE), context);\n\n fs.writeFileSync(\n path.join(contextDir, SCAN_RESULT_FILE),\n `${JSON.stringify(scanResult, null, 2)}\\n`,\n );\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n throw new Error(`Failed to write generated files to ${contextDir}: ${message}`);\n }\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport chalk from 'chalk';\n\n/**\n * Set up a pre-commit hook that runs viberails check on staged files.\n * Detects Lefthook, Husky, or falls back to a raw git hook.\n */\nexport function setupPreCommitHook(projectRoot: string): void {\n // Check for Lefthook\n const lefthookPath = path.join(projectRoot, 'lefthook.yml');\n if (fs.existsSync(lefthookPath)) {\n addLefthookPreCommit(lefthookPath);\n console.log(` ${chalk.green('✓')} lefthook.yml — added viberails pre-commit`);\n return;\n }\n\n // Check for Husky\n const huskyDir = path.join(projectRoot, '.husky');\n if (fs.existsSync(huskyDir)) {\n writeHuskyPreCommit(huskyDir);\n console.log(` ${chalk.green('✓')} .husky/pre-commit — added viberails check`);\n return;\n }\n\n // Fall back to raw git hook\n const gitDir = path.join(projectRoot, '.git');\n if (fs.existsSync(gitDir)) {\n const hooksDir = path.join(gitDir, 'hooks');\n if (!fs.existsSync(hooksDir)) {\n fs.mkdirSync(hooksDir, { recursive: true });\n }\n writeGitHookPreCommit(hooksDir);\n console.log(` ${chalk.green('✓')} .git/hooks/pre-commit`);\n }\n}\n\nfunction writeGitHookPreCommit(hooksDir: string): void {\n const hookPath = path.join(hooksDir, 'pre-commit');\n if (fs.existsSync(hookPath)) {\n const existing = fs.readFileSync(hookPath, 'utf-8');\n if (existing.includes('viberails')) return;\n fs.writeFileSync(\n hookPath,\n `${existing.trimEnd()}\\n\\n# viberails check\\nnpx viberails check --staged\\n`,\n );\n return;\n }\n const script = [\n '#!/bin/sh',\n '# Generated by viberails — https://viberails.sh',\n '',\n 'npx viberails check --staged',\n '',\n ].join('\\n');\n fs.writeFileSync(hookPath, script, { mode: 0o755 });\n}\n\nfunction addLefthookPreCommit(lefthookPath: string): void {\n const content = fs.readFileSync(lefthookPath, 'utf-8');\n if (content.includes('viberails')) return;\n const addition = ['', ' viberails:', ' run: npx viberails check --staged'].join('\\n');\n fs.writeFileSync(lefthookPath, `${content.trimEnd()}\\n${addition}\\n`);\n}\n\nfunction writeHuskyPreCommit(huskyDir: string): void {\n const hookPath = path.join(huskyDir, 'pre-commit');\n if (fs.existsSync(hookPath)) {\n const existing = fs.readFileSync(hookPath, 'utf-8');\n if (!existing.includes('viberails')) {\n fs.writeFileSync(hookPath, `${existing.trimEnd()}\\nnpx viberails check --staged\\n`);\n }\n return;\n }\n fs.writeFileSync(hookPath, '#!/bin/sh\\nnpx viberails check --staged\\n', { mode: 0o755 });\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { loadConfig, mergeConfig } from '@viberails/config';\nimport { scan } from '@viberails/scanner';\nimport chalk from 'chalk';\nimport { findProjectRoot } from '../utils/find-project-root.js';\nimport { writeGeneratedFiles } from '../utils/write-generated-files.js';\n\nconst CONFIG_FILE = 'viberails.config.json';\n\n/**\n * Run the viberails sync flow: re-scan, merge config, regenerate context.\n *\n * @param cwd - Working directory override (for testing)\n */\nexport async function syncCommand(cwd?: string): Promise<void> {\n const startDir = cwd ?? process.cwd();\n\n // 1. Find project root\n const projectRoot = findProjectRoot(startDir);\n if (!projectRoot) {\n throw new Error(\n 'No package.json found in this directory or any parent.\\n\\n' +\n 'Make sure you are inside a JavaScript or TypeScript project, then run:\\n' +\n ' npx viberails',\n );\n }\n\n // 2. Load existing config\n const configPath = path.join(projectRoot, CONFIG_FILE);\n const existing = await loadConfig(configPath);\n\n // 3. Re-scan\n console.log(chalk.dim('Scanning project...'));\n const scanResult = await scan(projectRoot);\n\n // 4. Merge config\n const merged = mergeConfig(existing, scanResult);\n fs.writeFileSync(configPath, `${JSON.stringify(merged, null, 2)}\\n`);\n\n // 5. Regenerate context and scan-result.json\n writeGeneratedFiles(projectRoot, merged, scanResult);\n\n console.log(`\\n${chalk.bold('Synced:')}`);\n console.log(` ${chalk.green('✓')} ${CONFIG_FILE} — updated`);\n console.log(` ${chalk.green('✓')} .viberails/context.md — regenerated`);\n console.log(` ${chalk.green('✓')} .viberails/scan-result.json — updated`);\n}\n"],"mappings":"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","names":["import_chalk","fs","path","resolve","fs","path","chalk","fs","path","import_config","import_chalk","fs","path","fs","path","SOURCE_EXTS","basename","CONFIG_FILE","chalk","fs","path","import_config","import_chalk","import_node_child_process","import_chalk","chalk","resolve","path","fs","path","fs","path","basename","CONFIG_FILE","chalk","fs","path","import_config","import_chalk","import_types","import_chalk","import_types","import_chalk","chalk","chalk","fs","path","fs","path","import_chalk","chalk","CONFIG_FILE","chalk","fs","path","import_config","import_scanner","import_chalk","CONFIG_FILE","chalk","chalk"]}
|
package/dist/index.d.cts
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -223,6 +223,19 @@ function resolveIgnoreForFile(relPath, config) {
|
|
|
223
223
|
import { execSync } from "child_process";
|
|
224
224
|
import * as fs4 from "fs";
|
|
225
225
|
import * as path4 from "path";
|
|
226
|
+
var ALWAYS_SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
227
|
+
"node_modules",
|
|
228
|
+
".git",
|
|
229
|
+
"dist",
|
|
230
|
+
"build",
|
|
231
|
+
".next",
|
|
232
|
+
".expo",
|
|
233
|
+
".output",
|
|
234
|
+
".svelte-kit",
|
|
235
|
+
".turbo",
|
|
236
|
+
"coverage",
|
|
237
|
+
".viberails"
|
|
238
|
+
]);
|
|
226
239
|
var SOURCE_EXTS = /* @__PURE__ */ new Set([
|
|
227
240
|
".ts",
|
|
228
241
|
".tsx",
|
|
@@ -271,7 +284,7 @@ function checkNaming(relPath, conventions) {
|
|
|
271
284
|
const filename = path4.basename(relPath);
|
|
272
285
|
const ext = path4.extname(filename);
|
|
273
286
|
if (!SOURCE_EXTS.has(ext)) return void 0;
|
|
274
|
-
if (filename.startsWith("index.") || filename.includes(".config.") || filename.includes(".test.") || filename.includes(".spec.") || filename.startsWith(".")) {
|
|
287
|
+
if (filename.startsWith("index.") || filename.includes(".config.") || filename.includes(".test.") || filename.includes(".spec.") || filename.startsWith(".") || filename.startsWith("_") || filename.startsWith("+") || filename.startsWith("$") || filename.startsWith("[")) {
|
|
275
288
|
return void 0;
|
|
276
289
|
}
|
|
277
290
|
const bare = filename.slice(0, filename.indexOf("."));
|
|
@@ -304,7 +317,7 @@ function getAllSourceFiles(projectRoot, config) {
|
|
|
304
317
|
for (const entry of entries) {
|
|
305
318
|
const rel = path4.relative(projectRoot, path4.join(dir, entry.name));
|
|
306
319
|
if (entry.isDirectory()) {
|
|
307
|
-
if (
|
|
320
|
+
if (ALWAYS_SKIP_DIRS.has(entry.name)) {
|
|
308
321
|
continue;
|
|
309
322
|
}
|
|
310
323
|
if (isIgnored(rel, config.ignore)) continue;
|
|
@@ -779,7 +792,7 @@ async function fixCommand(options, cwd) {
|
|
|
779
792
|
return 1;
|
|
780
793
|
}
|
|
781
794
|
const config = await loadConfig3(configPath);
|
|
782
|
-
if (!options.
|
|
795
|
+
if (!options.dryRun) {
|
|
783
796
|
const isDirty = checkGitDirty(projectRoot);
|
|
784
797
|
if (isDirty) {
|
|
785
798
|
console.log(
|
|
@@ -1310,7 +1323,7 @@ ${chalk9.bold("Synced:")}`);
|
|
|
1310
1323
|
}
|
|
1311
1324
|
|
|
1312
1325
|
// src/index.ts
|
|
1313
|
-
var VERSION = "0.2.
|
|
1326
|
+
var VERSION = "0.2.2";
|
|
1314
1327
|
var program = new Command();
|
|
1315
1328
|
program.name("viberails").description("Guardrails for vibe coding").version(VERSION);
|
|
1316
1329
|
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) => {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/commands/boundaries.ts","../src/utils/find-project-root.ts","../src/utils/prompt.ts","../src/utils/resolve-workspace-packages.ts","../src/commands/check.ts","../src/commands/check-config.ts","../src/commands/check-files.ts","../src/commands/check-tests.ts","../src/commands/fix.ts","../src/commands/fix-helpers.ts","../src/commands/fix-imports.ts","../src/commands/fix-naming.ts","../src/commands/convert-name.ts","../src/commands/fix-tests.ts","../src/commands/init.ts","../src/display.ts","../src/display-helpers.ts","../src/display-monorepo.ts","../src/utils/write-generated-files.ts","../src/commands/init-hooks.ts","../src/commands/sync.ts"],"sourcesContent":["import chalk from 'chalk';\nimport { Command } from 'commander';\nimport { boundariesCommand } from './commands/boundaries.js';\nimport { checkCommand } from './commands/check.js';\nimport { fixCommand } from './commands/fix.js';\nimport { initCommand } from './commands/init.js';\nimport { syncCommand } from './commands/sync.js';\n\nexport const VERSION = '0.2.1';\n\nconst program = new Command();\n\nprogram.name('viberails').description('Guardrails for vibe coding').version(VERSION);\n\nprogram\n .command('init', { isDefault: true })\n .description('Scan your project and set up enforcement guardrails')\n .option('-y, --yes', 'Non-interactive mode (use defaults, high-confidence only)')\n .action(async (options: { yes?: boolean }) => {\n try {\n await initCommand(options);\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n console.error(`${chalk.red('Error:')} ${message}`);\n process.exit(1);\n }\n });\n\nprogram\n .command('sync')\n .description('Re-scan and update generated files')\n .action(async () => {\n try {\n await syncCommand();\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n console.error(`${chalk.red('Error:')} ${message}`);\n process.exit(1);\n }\n });\n\nprogram\n .command('check')\n .description('Check files against enforced rules')\n .option('--staged', 'Check only staged files (for pre-commit hooks)')\n .option('--files <files...>', 'Check specific files')\n .option('--no-boundaries', 'Skip boundary checking')\n .action(async (options: { staged?: boolean; files?: string[]; boundaries?: boolean }) => {\n try {\n const exitCode = await checkCommand({\n ...options,\n noBoundaries: options.boundaries === false,\n });\n process.exit(exitCode);\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n console.error(`${chalk.red('Error:')} ${message}`);\n process.exit(1);\n }\n });\n\nprogram\n .command('fix')\n .description('Auto-fix file naming violations and generate missing test stubs')\n .option('--dry-run', 'Show planned fixes without applying them')\n .option('--rule <rules...>', 'Fix only specific rules (file-naming, missing-test)')\n .option('-y, --yes', 'Skip confirmation prompt')\n .action(async (options: { dryRun?: boolean; rule?: string[]; yes?: boolean }) => {\n try {\n const exitCode = await fixCommand(options);\n process.exit(exitCode);\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n console.error(`${chalk.red('Error:')} ${message}`);\n process.exit(1);\n }\n });\n\nprogram\n .command('boundaries')\n .description('Display, infer, or inspect import boundary rules')\n .option('--infer', 'Infer boundary rules from current import patterns')\n .option('--graph', 'Display import graph summary')\n .action(async (options: { infer?: boolean; graph?: boolean }) => {\n try {\n await boundariesCommand(options);\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n console.error(`${chalk.red('Error:')} ${message}`);\n process.exit(1);\n }\n });\n\nprogram.parse();\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { loadConfig } from '@viberails/config';\nimport type { ViberailsConfig } from '@viberails/types';\nimport chalk from 'chalk';\nimport { findProjectRoot } from '../utils/find-project-root.js';\nimport { confirm } from '../utils/prompt.js';\nimport { resolveWorkspacePackages } from '../utils/resolve-workspace-packages.js';\n\nconst CONFIG_FILE = 'viberails.config.json';\n\nexport interface BoundariesOptions {\n infer?: boolean;\n graph?: boolean;\n}\n\n/**\n * Display, infer, or inspect import boundary rules.\n *\n * @param options - CLI options\n * @param cwd - Working directory override (for testing)\n */\nexport async function boundariesCommand(options: BoundariesOptions, cwd?: string): Promise<void> {\n const startDir = cwd ?? process.cwd();\n const projectRoot = findProjectRoot(startDir);\n if (!projectRoot) {\n throw new Error('No package.json found. Are you in a JS/TS project?');\n }\n\n const configPath = path.join(projectRoot, CONFIG_FILE);\n if (!fs.existsSync(configPath)) {\n throw new Error('No viberails.config.json found. Run `viberails init` first.');\n }\n\n const config = await loadConfig(configPath);\n\n if (options.graph) {\n await showGraph(projectRoot, config);\n return;\n }\n\n if (options.infer) {\n await inferAndDisplay(projectRoot, config, configPath);\n return;\n }\n\n displayRules(config);\n}\n\n/** Display configured boundary rules. */\nfunction displayRules(config: ViberailsConfig): void {\n if (!config.boundaries || config.boundaries.length === 0) {\n console.log(chalk.yellow('No boundary rules configured.'));\n console.log(`Run ${chalk.cyan('viberails boundaries --infer')} to generate rules.`);\n return;\n }\n\n const allowRules = config.boundaries.filter((r) => r.allow);\n const denyRules = config.boundaries.filter((r) => !r.allow);\n\n console.log(`\\n${chalk.bold(`Boundary rules (${config.boundaries.length} rules):`)}\\n`);\n\n for (const r of allowRules) {\n console.log(` ${chalk.green('✓')} ${r.from} → ${r.to}`);\n }\n\n for (const r of denyRules) {\n const reason = r.reason ? chalk.dim(` (${r.reason})`) : '';\n console.log(` ${chalk.red('✗')} ${r.from} → ${r.to}${reason}`);\n }\n\n console.log(\n `\\nEnforcement: ${config.rules.enforceBoundaries ? chalk.green('on') : chalk.yellow('off')}`,\n );\n}\n\n/** Infer boundary rules from import patterns and optionally save. */\nasync function inferAndDisplay(\n projectRoot: string,\n config: ViberailsConfig,\n configPath: string,\n): Promise<void> {\n console.log(chalk.dim('Analyzing imports...'));\n const { buildImportGraph, inferBoundaries } = await import('@viberails/graph');\n\n const packages = config.workspace\n ? resolveWorkspacePackages(projectRoot, config.workspace)\n : undefined;\n\n const graph = await buildImportGraph(projectRoot, {\n packages,\n ignore: config.ignore,\n });\n\n console.log(chalk.dim(`${graph.nodes.length} files, ${graph.edges.length} edges`));\n\n const inferred = inferBoundaries(graph);\n\n if (inferred.length === 0) {\n console.log(chalk.yellow('No boundary rules could be inferred.'));\n return;\n }\n\n const allow = inferred.filter((r) => r.allow);\n const deny = inferred.filter((r) => !r.allow);\n\n console.log(`\\n${chalk.bold('Inferred boundary rules:')}\\n`);\n\n for (const r of allow) {\n console.log(` ${chalk.green('✓')} ${r.from} → ${r.to}`);\n }\n\n for (const r of deny) {\n const reason = r.reason ? chalk.dim(` (${r.reason})`) : '';\n console.log(` ${chalk.red('✗')} ${r.from} → ${r.to}${reason}`);\n }\n\n console.log(`\\n ${allow.length} allowed, ${deny.length} denied`);\n\n const shouldSave = await confirm('\\nSave to viberails.config.json?');\n if (shouldSave) {\n config.boundaries = inferred;\n config.rules.enforceBoundaries = true;\n fs.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\\n`);\n console.log(`${chalk.green('✓')} Saved ${inferred.length} rules`);\n }\n}\n\n/** Display import graph summary. */\nasync function showGraph(projectRoot: string, config: ViberailsConfig): Promise<void> {\n console.log(chalk.dim('Building import graph...'));\n const { buildImportGraph } = await import('@viberails/graph');\n\n const packages = config.workspace\n ? resolveWorkspacePackages(projectRoot, config.workspace)\n : undefined;\n\n const graph = await buildImportGraph(projectRoot, {\n packages,\n ignore: config.ignore,\n });\n\n console.log(`\\n${chalk.bold('Import dependency graph:')}\\n`);\n console.log(` ${graph.nodes.length} files, ${graph.edges.length} imports\\n`);\n\n if (graph.packages.length > 0) {\n for (const pkg of graph.packages) {\n const deps =\n pkg.internalDeps.length > 0\n ? `\\n${pkg.internalDeps.map((d) => ` → ${d}`).join('\\n')}`\n : chalk.dim(' (no internal deps)');\n console.log(` ${pkg.name}${deps}`);\n }\n }\n\n if (graph.cycles.length > 0) {\n console.log(`\\n${chalk.yellow('Cycles detected:')}`);\n for (const cycle of graph.cycles) {\n const paths = cycle.map((f) => path.relative(projectRoot, f));\n console.log(` ${paths.join(' → ')}`);\n }\n }\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\n\n/**\n * Walk up from startDir looking for a directory containing package.json.\n *\n * @param startDir - The directory to start searching from\n * @returns The project root path, or null if no package.json is found\n */\nexport function findProjectRoot(startDir: string): string | null {\n let dir = path.resolve(startDir);\n\n while (true) {\n if (fs.existsSync(path.join(dir, 'package.json'))) {\n return dir;\n }\n\n const parent = path.dirname(dir);\n if (parent === dir) {\n return null;\n }\n dir = parent;\n }\n}\n","import * as readline from 'node:readline';\n\n/**\n * Prompt the user for a yes/no confirmation.\n *\n * @param message - The question to display (without the Y/n suffix)\n * @returns true if the user confirms, false otherwise\n */\nexport async function confirm(message: string): Promise<boolean> {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n return new Promise<boolean>((resolve) => {\n rl.question(`${message} (Y/n) `, (answer) => {\n rl.close();\n const trimmed = answer.trim().toLowerCase();\n resolve(trimmed === '' || trimmed === 'y' || trimmed === 'yes');\n });\n });\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { WorkspaceConfig, WorkspacePackage } from '@viberails/types';\n\n/**\n * Resolve WorkspacePackage[] from config workspace relative paths.\n *\n * Reads each package's package.json to get the name and dependencies,\n * then filters internalDeps to only include workspace-internal packages.\n *\n * @param projectRoot - Absolute path to the project root\n * @param workspace - The workspace config from viberails.config.json\n * @returns Array of resolved WorkspacePackage objects\n */\nexport function resolveWorkspacePackages(\n projectRoot: string,\n workspace: WorkspaceConfig,\n): WorkspacePackage[] {\n const packages: WorkspacePackage[] = [];\n\n for (const relativePath of workspace.packages) {\n const absPath = path.join(projectRoot, relativePath);\n const pkgJsonPath = path.join(absPath, 'package.json');\n\n if (!fs.existsSync(pkgJsonPath)) continue;\n\n let pkg: Record<string, unknown>;\n try {\n pkg = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8'));\n } catch {\n continue;\n }\n\n const name = pkg.name as string;\n if (!name) continue;\n\n const allDeps = [\n ...Object.keys((pkg.dependencies as Record<string, unknown>) ?? {}),\n ...Object.keys((pkg.devDependencies as Record<string, unknown>) ?? {}),\n ];\n\n packages.push({ name, path: absPath, relativePath, internalDeps: allDeps });\n }\n\n // Filter internalDeps to only workspace-internal package names\n const packageNames = new Set(packages.map((p) => p.name));\n for (const pkg of packages) {\n pkg.internalDeps = pkg.internalDeps.filter((dep) => packageNames.has(dep));\n }\n\n return packages;\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { loadConfig } from '@viberails/config';\nimport type { CheckViolation } from '@viberails/types';\nimport chalk from 'chalk';\nimport { findProjectRoot } from '../utils/find-project-root.js';\nimport { resolveWorkspacePackages } from '../utils/resolve-workspace-packages.js';\nimport { resolveConfigForFile, resolveIgnoreForFile } from './check-config.js';\nimport {\n checkNaming,\n countFileLines,\n getAllSourceFiles,\n getStagedFiles,\n isIgnored,\n} from './check-files.js';\nimport { checkMissingTests } from './check-tests.js';\n\nexport { resolveConfigForFile } from './check-config.js';\n\nconst CONFIG_FILE = 'viberails.config.json';\n\nexport interface CheckOptions {\n files?: string[];\n staged?: boolean;\n noBoundaries?: boolean;\n}\n\n/**\n * Run the viberails check command.\n * Returns exit code: 0 = pass or warn-mode, 1 = violations in enforce mode.\n */\nexport async function checkCommand(options: CheckOptions, cwd?: string): Promise<number> {\n const startDir = cwd ?? process.cwd();\n\n const projectRoot = findProjectRoot(startDir);\n if (!projectRoot) {\n console.error(`${chalk.red('Error:')} No package.json found. Are you in a JS/TS project?`);\n return 1;\n }\n\n const configPath = path.join(projectRoot, CONFIG_FILE);\n if (!fs.existsSync(configPath)) {\n console.error(\n `${chalk.red('Error:')} No viberails.config.json found. Run \\`viberails init\\` first.`,\n );\n return 1;\n }\n\n const config = await loadConfig(configPath);\n\n // Determine which files to check\n let filesToCheck: string[];\n if (options.staged) {\n filesToCheck = getStagedFiles(projectRoot);\n } else if (options.files && options.files.length > 0) {\n filesToCheck = options.files;\n } else {\n filesToCheck = getAllSourceFiles(projectRoot, config);\n }\n\n if (filesToCheck.length === 0) {\n console.log(`${chalk.green('✓')} No files to check.`);\n return 0;\n }\n\n const violations: CheckViolation[] = [];\n const severity = config.enforcement === 'enforce' ? 'error' : 'warn';\n\n for (const file of filesToCheck) {\n const absPath = path.isAbsolute(file) ? file : path.join(projectRoot, file);\n const relPath = path.relative(projectRoot, absPath);\n\n const effectiveIgnore = resolveIgnoreForFile(relPath, config);\n if (isIgnored(relPath, effectiveIgnore)) continue;\n if (!fs.existsSync(absPath)) continue;\n\n const resolved = resolveConfigForFile(relPath, config);\n\n // Check 1: File size\n if (resolved.rules.maxFileLines > 0) {\n const lines = countFileLines(absPath);\n if (lines !== null && lines > resolved.rules.maxFileLines) {\n violations.push({\n file: relPath,\n rule: 'file-size',\n message: `${lines} lines (max ${resolved.rules.maxFileLines}). Split into focused modules.`,\n severity,\n });\n }\n }\n\n // Check 2: File naming convention\n if (resolved.rules.enforceNaming && resolved.conventions.fileNaming) {\n const namingViolation = checkNaming(relPath, resolved.conventions);\n if (namingViolation) {\n violations.push({\n file: relPath,\n rule: 'file-naming',\n message: namingViolation,\n severity,\n });\n }\n }\n }\n\n // Check 3: Missing tests (only on full project check, not staged/specific files)\n if (config.rules.requireTests && !options.staged && !options.files) {\n const testViolations = checkMissingTests(projectRoot, config, severity);\n violations.push(...testViolations);\n }\n\n // Check 4: Boundary violations\n if (\n config.rules.enforceBoundaries &&\n config.boundaries &&\n config.boundaries.length > 0 &&\n !options.noBoundaries\n ) {\n const startTime = Date.now();\n const { buildImportGraph, checkBoundaries } = await import('@viberails/graph');\n\n const packages = config.workspace\n ? resolveWorkspacePackages(projectRoot, config.workspace)\n : undefined;\n\n const graph = await buildImportGraph(projectRoot, {\n packages,\n ignore: config.ignore,\n });\n\n const boundaryViolations = checkBoundaries(graph, config.boundaries);\n\n // In staged/files mode, only report violations in those files\n const filterSet =\n options.staged || options.files\n ? new Set(filesToCheck.map((f) => path.resolve(projectRoot, f)))\n : null;\n\n for (const bv of boundaryViolations) {\n if (filterSet && !filterSet.has(bv.file)) continue;\n\n const relFile = path.relative(projectRoot, bv.file);\n violations.push({\n file: relFile,\n rule: 'boundary-violation',\n message: `Imports \"${bv.specifier}\" violating boundary: ${bv.rule.from} → ${bv.rule.to}${bv.rule.reason ? ` (${bv.rule.reason})` : ''}`,\n severity,\n });\n }\n\n const elapsed = Date.now() - startTime;\n console.log(chalk.dim(` Boundary check: ${graph.nodes.length} files in ${elapsed}ms`));\n }\n\n // Output results\n if (violations.length === 0) {\n console.log(`${chalk.green('✓')} ${filesToCheck.length} files checked — no violations`);\n return 0;\n }\n\n for (const v of violations) {\n const icon = v.severity === 'error' ? chalk.red('✗') : chalk.yellow('!');\n console.log(`${icon} ${chalk.dim(v.rule)} ${v.file}: ${v.message}`);\n }\n\n const word = violations.length === 1 ? 'violation' : 'violations';\n console.log(`\\n${violations.length} ${word} found.`);\n\n if (config.enforcement === 'enforce') {\n console.log(chalk.red('Fix violations before committing.'));\n return 1;\n }\n\n return 0;\n}\n","import type { ConfigConventions, ConfigRules, ViberailsConfig } from '@viberails/types';\n\nexport interface ResolvedConfig {\n rules: ConfigRules;\n conventions: ConfigConventions;\n}\n\n/**\n * Resolve the effective config for a file by finding its package override.\n * Returns the global config merged with any matching package overrides.\n */\nexport function resolveConfigForFile(relPath: string, config: ViberailsConfig): ResolvedConfig {\n if (!config.packages || config.packages.length === 0) {\n return { rules: config.rules, conventions: config.conventions };\n }\n\n // Sort by path length descending to match the most specific package first\n const sortedPackages = [...config.packages].sort((a, b) => b.path.length - a.path.length);\n\n for (const pkg of sortedPackages) {\n if (relPath.startsWith(`${pkg.path}/`) || relPath === pkg.path) {\n return {\n rules: { ...config.rules, ...pkg.rules },\n conventions: { ...config.conventions, ...pkg.conventions },\n };\n }\n }\n\n return { rules: config.rules, conventions: config.conventions };\n}\n\n/**\n * Resolve ignore patterns for a file, appending any package-specific patterns.\n */\nexport function resolveIgnoreForFile(relPath: string, config: ViberailsConfig): string[] {\n const globalIgnore = config.ignore;\n if (!config.packages) return globalIgnore;\n\n for (const pkg of config.packages) {\n if (pkg.ignore && relPath.startsWith(`${pkg.path}/`)) {\n return [...globalIgnore, ...pkg.ignore];\n }\n }\n return globalIgnore;\n}\n","import { execSync } from 'node:child_process';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { ConfigConventions, ConventionValue, ViberailsConfig } from '@viberails/types';\n\nexport const SOURCE_EXTS = new Set([\n '.ts',\n '.tsx',\n '.js',\n '.jsx',\n '.mjs',\n '.cjs',\n '.vue',\n '.svelte',\n '.astro',\n]);\n\nexport const NAMING_PATTERNS: Record<string, RegExp> = {\n 'kebab-case': /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/,\n camelCase: /^[a-z][a-zA-Z0-9]*$/,\n PascalCase: /^[A-Z][a-zA-Z0-9]*$/,\n snake_case: /^[a-z][a-z0-9]*(_[a-z0-9]+)*$/,\n};\n\n/** Check if a path matches any ignore pattern. */\nexport function isIgnored(relPath: string, ignorePatterns: string[]): boolean {\n for (const pattern of ignorePatterns) {\n if (pattern.endsWith('/**')) {\n const prefix = pattern.slice(0, -3);\n if (relPath.startsWith(`${prefix}/`) || relPath === prefix) return true;\n } else if (pattern.startsWith('**/')) {\n const suffix = pattern.slice(3);\n if (relPath.endsWith(suffix)) return true;\n } else if (relPath === pattern || relPath.startsWith(`${pattern}/`)) {\n return true;\n }\n }\n return false;\n}\n\n/** Count lines in a file. Returns null if the file can't be read. */\nexport function countFileLines(filePath: string): number | null {\n try {\n const content = fs.readFileSync(filePath, 'utf-8');\n if (content.length === 0) return 0;\n let count = 1;\n for (let i = 0; i < content.length; i++) {\n if (content.charCodeAt(i) === 10) count++;\n }\n return count;\n } catch {\n return null;\n }\n}\n\n/** Check whether a file's name violates the configured naming convention. */\nexport function checkNaming(relPath: string, conventions: ConfigConventions): string | undefined {\n const filename = path.basename(relPath);\n\n // Skip non-source files\n const ext = path.extname(filename);\n if (!SOURCE_EXTS.has(ext)) return undefined;\n\n // Skip special files\n if (\n filename.startsWith('index.') ||\n filename.includes('.config.') ||\n filename.includes('.test.') ||\n filename.includes('.spec.') ||\n filename.startsWith('.')\n ) {\n return undefined;\n }\n\n const bare = filename.slice(0, filename.indexOf('.'));\n const convention =\n typeof conventions.fileNaming === 'string'\n ? conventions.fileNaming\n : (conventions.fileNaming as Exclude<ConventionValue, string> | undefined)?.value;\n\n if (!convention) return undefined;\n\n const pattern = NAMING_PATTERNS[convention];\n if (!pattern || pattern.test(bare)) return undefined;\n\n return `File name \"${filename}\" does not follow ${convention} convention.`;\n}\n\n/** Get staged files from git. */\nexport function getStagedFiles(projectRoot: string): string[] {\n try {\n const output = execSync('git diff --cached --name-only --diff-filter=ACM', {\n cwd: projectRoot,\n encoding: 'utf-8',\n });\n return output.trim().split('\\n').filter(Boolean);\n } catch {\n return [];\n }\n}\n\n/** Get all source files in the project. */\nexport function getAllSourceFiles(projectRoot: string, config: ViberailsConfig): string[] {\n const files: string[] = [];\n const walk = (dir: string) => {\n let entries: fs.Dirent[];\n try {\n entries = fs.readdirSync(dir, { withFileTypes: true });\n } catch {\n return;\n }\n for (const entry of entries) {\n const rel = path.relative(projectRoot, path.join(dir, entry.name));\n if (entry.isDirectory()) {\n if (entry.name === 'node_modules' || entry.name === '.git' || entry.name === 'dist') {\n continue;\n }\n if (isIgnored(rel, config.ignore)) continue;\n walk(path.join(dir, entry.name));\n } else if (entry.isFile()) {\n const ext = path.extname(entry.name);\n if (SOURCE_EXTS.has(ext) && !isIgnored(rel, config.ignore)) {\n files.push(rel);\n }\n }\n }\n };\n walk(projectRoot);\n return files;\n}\n\n/** Collect source files from a directory recursively. */\nexport function collectSourceFiles(dir: string, projectRoot: string): string[] {\n const files: string[] = [];\n const walk = (d: string) => {\n let entries: fs.Dirent[];\n try {\n entries = fs.readdirSync(d, { withFileTypes: true });\n } catch {\n return;\n }\n for (const entry of entries) {\n if (entry.isDirectory()) {\n if (entry.name === 'node_modules') continue;\n walk(path.join(d, entry.name));\n } else if (entry.isFile()) {\n files.push(path.relative(projectRoot, path.join(d, entry.name)));\n }\n }\n };\n walk(dir);\n return files;\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { CheckViolation, ViberailsConfig } from '@viberails/types';\nimport { collectSourceFiles } from './check-files.js';\n\nconst SOURCE_EXTS = new Set([\n '.ts',\n '.tsx',\n '.js',\n '.jsx',\n '.mjs',\n '.cjs',\n '.vue',\n '.svelte',\n '.astro',\n]);\n\n/** Check for source files without corresponding test files. */\nexport function checkMissingTests(\n projectRoot: string,\n config: ViberailsConfig,\n severity: 'error' | 'warn',\n): CheckViolation[] {\n const violations: CheckViolation[] = [];\n const { testPattern } = config.structure;\n if (!testPattern) return violations;\n\n const srcDir = config.structure.srcDir;\n if (!srcDir) return violations;\n\n const srcPath = path.join(projectRoot, srcDir);\n if (!fs.existsSync(srcPath)) return violations;\n\n const testSuffix = testPattern.replace('*', '');\n const sourceFiles = collectSourceFiles(srcPath, projectRoot);\n\n for (const relFile of sourceFiles) {\n const basename = path.basename(relFile);\n\n // Skip test files, index files, type definition files\n if (\n basename.includes('.test.') ||\n basename.includes('.spec.') ||\n basename.startsWith('index.') ||\n basename.endsWith('.d.ts')\n ) {\n continue;\n }\n\n const ext = path.extname(basename);\n if (!SOURCE_EXTS.has(ext)) continue;\n\n const stem = basename.slice(0, basename.indexOf('.'));\n const expectedTestFile = `${stem}${testSuffix}`;\n\n // Look for the test file next to the source or in the tests directory\n const dir = path.dirname(path.join(projectRoot, relFile));\n const colocatedTest = path.join(dir, expectedTestFile);\n const testsDir = config.structure.tests;\n const dedicatedTest = testsDir ? path.join(projectRoot, testsDir, expectedTestFile) : null;\n\n const hasTest =\n fs.existsSync(colocatedTest) || (dedicatedTest !== null && fs.existsSync(dedicatedTest));\n\n if (!hasTest) {\n violations.push({\n file: relFile,\n rule: 'missing-test',\n message: `No test file found. Expected \\`${expectedTestFile}\\`.`,\n severity,\n });\n }\n }\n\n return violations;\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { loadConfig } from '@viberails/config';\nimport chalk from 'chalk';\nimport { findProjectRoot } from '../utils/find-project-root.js';\nimport { resolveConfigForFile } from './check-config.js';\nimport { checkNaming, getAllSourceFiles } from './check-files.js';\nimport { checkMissingTests } from './check-tests.js';\nimport { checkGitDirty, getConventionValue, printPlan, promptConfirm } from './fix-helpers.js';\nimport { updateImportsAfterRenames } from './fix-imports.js';\nimport {\n computeRename,\n deduplicateRenames,\n executeRename,\n type RenameRecord,\n} from './fix-naming.js';\nimport { generateTestStub, type TestStubRecord, writeTestStub } from './fix-tests.js';\n\nconst CONFIG_FILE = 'viberails.config.json';\n\nexport interface FixOptions {\n dryRun?: boolean;\n rule?: string[];\n yes?: boolean;\n}\n\n/**\n * Run the viberails fix command.\n * Detects violations, computes fixes, optionally confirms, then applies.\n */\nexport async function fixCommand(options: FixOptions, cwd?: string): Promise<number> {\n const startDir = cwd ?? process.cwd();\n const projectRoot = findProjectRoot(startDir);\n\n if (!projectRoot) {\n console.error(`${chalk.red('Error:')} No package.json found. Are you in a JS/TS project?`);\n return 1;\n }\n\n const configPath = path.join(projectRoot, CONFIG_FILE);\n if (!fs.existsSync(configPath)) {\n console.error(\n `${chalk.red('Error:')} No viberails.config.json found. Run \\`viberails init\\` first.`,\n );\n return 1;\n }\n\n const config = await loadConfig(configPath);\n\n // Git dirty check — warn but don't block\n if (!options.yes && !options.dryRun) {\n const isDirty = checkGitDirty(projectRoot);\n if (isDirty) {\n console.log(\n chalk.yellow('Warning: You have uncommitted changes. Consider committing first.'),\n );\n }\n }\n\n const shouldFixNaming = !options.rule || options.rule.includes('file-naming');\n const shouldFixTests = !options.rule || options.rule.includes('missing-test');\n\n // Collect source files\n const allFiles = getAllSourceFiles(projectRoot, config);\n\n // Compute naming renames\n const renames: RenameRecord[] = [];\n if (shouldFixNaming) {\n for (const file of allFiles) {\n const resolved = resolveConfigForFile(file, config);\n if (!resolved.rules.enforceNaming || !resolved.conventions.fileNaming) continue;\n\n const violation = checkNaming(file, resolved.conventions);\n if (!violation) continue;\n\n const convention = getConventionValue(resolved.conventions.fileNaming);\n if (!convention) continue;\n\n const rename = computeRename(file, convention, projectRoot);\n if (rename) renames.push(rename);\n }\n }\n\n const dedupedRenames = deduplicateRenames(renames);\n\n // Compute test stubs\n const testStubs: TestStubRecord[] = [];\n if (shouldFixTests && config.rules.requireTests) {\n const testViolations = checkMissingTests(projectRoot, config, 'warn');\n for (const v of testViolations) {\n const stub = generateTestStub(v.file, config, projectRoot);\n if (stub) testStubs.push(stub);\n }\n }\n\n // Nothing to fix\n if (dedupedRenames.length === 0 && testStubs.length === 0) {\n console.log(`${chalk.green('✓')} No fixable violations found.`);\n return 0;\n }\n\n // Display plan\n printPlan(dedupedRenames, testStubs);\n\n if (options.dryRun) {\n console.log(chalk.dim('\\nDry run — no changes applied.'));\n return 0;\n }\n\n // Confirm\n if (!options.yes) {\n const confirmed = await promptConfirm('Apply these fixes?');\n if (!confirmed) {\n console.log('Aborted.');\n return 0;\n }\n }\n\n // Apply: 1. Renames\n let renameCount = 0;\n for (const rename of dedupedRenames) {\n if (executeRename(rename)) {\n renameCount++;\n }\n }\n\n // Apply: 2. Import updates\n let importUpdateCount = 0;\n if (renameCount > 0) {\n const appliedRenames = dedupedRenames.filter((r) => fs.existsSync(r.newAbsPath));\n const updates = await updateImportsAfterRenames(appliedRenames, projectRoot);\n importUpdateCount = updates.length;\n }\n\n // Apply: 3. Test stubs\n let stubCount = 0;\n for (const stub of testStubs) {\n if (!fs.existsSync(stub.absPath)) {\n writeTestStub(stub, config);\n stubCount++;\n }\n }\n\n // Summary\n console.log('');\n if (renameCount > 0) {\n console.log(`${chalk.green('✓')} Renamed ${renameCount} file${renameCount > 1 ? 's' : ''}`);\n }\n if (importUpdateCount > 0) {\n console.log(\n `${chalk.green('✓')} Updated ${importUpdateCount} import${importUpdateCount > 1 ? 's' : ''}`,\n );\n }\n if (stubCount > 0) {\n console.log(`${chalk.green('✓')} Generated ${stubCount} test stub${stubCount > 1 ? 's' : ''}`);\n }\n\n return 0;\n}\n","import { execSync } from 'node:child_process';\nimport { createInterface } from 'node:readline';\nimport chalk from 'chalk';\nimport type { RenameRecord } from './fix-naming.js';\nimport type { TestStubRecord } from './fix-tests.js';\n\n/**\n * Display the planned renames and test stubs.\n */\nexport function printPlan(renames: RenameRecord[], stubs: TestStubRecord[]): void {\n if (renames.length > 0) {\n console.log(chalk.bold('\\nFile renames:'));\n for (const r of renames) {\n console.log(` ${chalk.red(r.oldPath)} → ${chalk.green(r.newPath)}`);\n }\n }\n\n if (stubs.length > 0) {\n console.log(chalk.bold('\\nTest stubs to create:'));\n for (const s of stubs) {\n console.log(` ${chalk.green('+')} ${s.path}`);\n }\n }\n}\n\n/**\n * Check if the git working tree has uncommitted changes.\n */\nexport function checkGitDirty(projectRoot: string): boolean {\n try {\n const output = execSync('git status --porcelain', {\n cwd: projectRoot,\n encoding: 'utf-8',\n });\n return output.trim().length > 0;\n } catch {\n return false;\n }\n}\n\n/**\n * Extract the string value from a convention (which may be a string or an object with a value property).\n */\nexport function getConventionValue(convention: unknown): string | undefined {\n if (typeof convention === 'string') return convention;\n if (convention && typeof convention === 'object' && 'value' in convention) {\n return (convention as { value: string }).value;\n }\n return undefined;\n}\n\n/**\n * Prompt the user to confirm an action.\n */\nexport function promptConfirm(question: string): Promise<boolean> {\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n return new Promise((resolve) => {\n rl.question(`${question} (y/N) `, (answer) => {\n rl.close();\n resolve(answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes');\n });\n });\n}\n","import * as path from 'node:path';\nimport type { RenameRecord } from './fix-naming.js';\n\nexport interface ImportUpdateRecord {\n file: string;\n oldSpecifier: string;\n newSpecifier: string;\n line: number;\n}\n\n/**\n * Strip known JS/TS extensions from a file path for specifier comparison.\n * E.g. \"/foo/bar.ts\" → \"/foo/bar\", \"/foo/bar.js\" → \"/foo/bar\"\n */\nfunction stripExtension(filePath: string): string {\n return filePath.replace(/\\.(tsx?|jsx?|mjs|cjs)$/, '');\n}\n\n/**\n * Compute the new import specifier given the old specifier and the rename.\n * Preserves `.js` suffix if present.\n */\nfunction computeNewSpecifier(oldSpecifier: string, newBare: string): string {\n const hasJsExt = oldSpecifier.endsWith('.js');\n const base = hasJsExt ? oldSpecifier.slice(0, -3) : oldSpecifier;\n\n // Replace the last path segment\n const dir = base.lastIndexOf('/');\n const prefix = dir >= 0 ? base.slice(0, dir + 1) : '';\n const newSpec = prefix + newBare;\n\n return hasJsExt ? `${newSpec}.js` : newSpec;\n}\n\n/**\n * Update import specifiers in all source files after renames.\n * Uses ts-morph for AST-accurate rewriting.\n *\n * @param renames - The renames that were applied\n * @param projectRoot - Absolute path to project root\n * @returns Records of all import updates made\n */\nexport async function updateImportsAfterRenames(\n renames: RenameRecord[],\n projectRoot: string,\n): Promise<ImportUpdateRecord[]> {\n if (renames.length === 0) return [];\n\n // Lazy import ts-morph to avoid startup cost\n const { Project, SyntaxKind } = await import('ts-morph');\n\n // Build rename map: stripped old abs path → { newBare }\n const renameMap = new Map<string, { newBare: string }>();\n for (const r of renames) {\n const oldStripped = stripExtension(r.oldAbsPath);\n const newFilename = path.basename(r.newPath);\n const newName = newFilename.slice(0, newFilename.indexOf('.'));\n renameMap.set(oldStripped, { newBare: newName });\n }\n\n const project = new Project({\n tsConfigFilePath: undefined,\n skipAddingFilesFromTsConfig: true,\n });\n\n // Add all TS/JS source files\n project.addSourceFilesAtPaths(path.join(projectRoot, '**/*.{ts,tsx,js,jsx,mjs,cjs}'));\n\n const updates: ImportUpdateRecord[] = [];\n const extensions = ['', '.ts', '.tsx', '.js', '.jsx', '/index.ts', '/index.tsx', '/index.js'];\n\n for (const sourceFile of project.getSourceFiles()) {\n const filePath = sourceFile.getFilePath();\n // Skip node_modules and dist\n if (filePath.includes('/node_modules/') || filePath.includes('/dist/')) continue;\n\n const fileDir = path.dirname(filePath);\n\n // Process static imports\n for (const decl of sourceFile.getImportDeclarations()) {\n const specifier = decl.getModuleSpecifierValue();\n if (!specifier.startsWith('.')) continue;\n\n const match = resolveToRenamedFile(specifier, fileDir, renameMap, extensions);\n if (!match) continue;\n\n const newSpec = computeNewSpecifier(specifier, match.newBare);\n updates.push({\n file: filePath,\n oldSpecifier: specifier,\n newSpecifier: newSpec,\n line: decl.getStartLineNumber(),\n });\n decl.setModuleSpecifier(newSpec);\n }\n\n // Process re-exports\n for (const decl of sourceFile.getExportDeclarations()) {\n const specifier = decl.getModuleSpecifierValue();\n if (!specifier || !specifier.startsWith('.')) continue;\n\n const match = resolveToRenamedFile(specifier, fileDir, renameMap, extensions);\n if (!match) continue;\n\n const newSpec = computeNewSpecifier(specifier, match.newBare);\n updates.push({\n file: filePath,\n oldSpecifier: specifier,\n newSpecifier: newSpec,\n line: decl.getStartLineNumber(),\n });\n decl.setModuleSpecifier(newSpec);\n }\n\n // Process dynamic imports\n for (const call of sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression)) {\n if (call.getExpression().getKind() !== SyntaxKind.ImportKeyword) continue;\n\n const args = call.getArguments();\n if (args.length === 0) continue;\n\n const arg = args[0];\n if (arg.getKind() !== SyntaxKind.StringLiteral) continue;\n\n const specifier = arg.getText().slice(1, -1);\n if (!specifier.startsWith('.')) continue;\n\n const match = resolveToRenamedFile(specifier, fileDir, renameMap, extensions);\n if (!match) continue;\n\n const newSpec = computeNewSpecifier(specifier, match.newBare);\n updates.push({\n file: filePath,\n oldSpecifier: specifier,\n newSpecifier: newSpec,\n line: call.getStartLineNumber(),\n });\n // Replace the string literal content\n const quote = arg.getText()[0];\n arg.replaceWithText(`${quote}${newSpec}${quote}`);\n }\n }\n\n if (updates.length > 0) {\n await project.save();\n }\n\n return updates;\n}\n\n/**\n * Try to resolve a relative specifier to a renamed file.\n * Returns the rename info if matched, undefined otherwise.\n */\nfunction resolveToRenamedFile(\n specifier: string,\n fromDir: string,\n renameMap: Map<string, { newBare: string }>,\n extensions: string[],\n): { newBare: string } | undefined {\n // Strip .js extension for resolution (TypeScript convention)\n const cleanSpec = specifier.endsWith('.js') ? specifier.slice(0, -3) : specifier;\n const resolved = path.resolve(fromDir, cleanSpec);\n\n for (const ext of extensions) {\n const candidate = resolved + ext;\n const stripped = stripExtension(candidate);\n const match = renameMap.get(stripped);\n if (match) return match;\n }\n\n return undefined;\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { convertName } from './convert-name.js';\n\nexport interface RenameRecord {\n oldPath: string;\n newPath: string;\n oldAbsPath: string;\n newAbsPath: string;\n}\n\n/**\n * Compute the rename for a file that violates the naming convention.\n * Returns null if no rename is needed or the target already exists.\n */\nexport function computeRename(\n relPath: string,\n targetConvention: string,\n projectRoot: string,\n): RenameRecord | null {\n const filename = path.basename(relPath);\n const dir = path.dirname(relPath);\n\n // Extract bare name (before first dot) — matches checkNaming logic\n const dotIndex = filename.indexOf('.');\n if (dotIndex === -1) return null;\n\n const bare = filename.slice(0, dotIndex);\n const suffix = filename.slice(dotIndex); // e.g. \".tsx\" or \".test.ts\"\n\n const newBare = convertName(bare, targetConvention);\n if (newBare === bare) return null;\n\n const newFilename = newBare + suffix;\n const newRelPath = path.join(dir, newFilename);\n const oldAbsPath = path.join(projectRoot, relPath);\n const newAbsPath = path.join(projectRoot, newRelPath);\n\n // Skip if target already exists\n if (fs.existsSync(newAbsPath)) return null;\n\n return { oldPath: relPath, newPath: newRelPath, oldAbsPath, newAbsPath };\n}\n\n/**\n * Execute a single rename on disk.\n * Returns true if successful, false if skipped (target exists).\n */\nexport function executeRename(rename: RenameRecord): boolean {\n if (fs.existsSync(rename.newAbsPath)) return false;\n fs.renameSync(rename.oldAbsPath, rename.newAbsPath);\n return true;\n}\n\n/**\n * Detect and deduplicate rename collisions.\n * If two planned renames target the same path, the second is removed.\n */\nexport function deduplicateRenames(renames: RenameRecord[]): RenameRecord[] {\n const seen = new Set<string>();\n const result: RenameRecord[] = [];\n for (const r of renames) {\n if (seen.has(r.newAbsPath)) continue;\n seen.add(r.newAbsPath);\n result.push(r);\n }\n return result;\n}\n","/**\n * Split a bare filename into its constituent words.\n *\n * Handles kebab-case, camelCase, PascalCase, and snake_case inputs.\n * Consecutive uppercase letters (acronyms like \"URL\") are kept together.\n */\nexport function splitIntoWords(name: string): string[] {\n // First, split on explicit separators (hyphens and underscores)\n const parts = name.split(/[-_]/);\n\n const words: string[] = [];\n for (const part of parts) {\n if (part === '') continue;\n\n // Split camelCase and PascalCase boundaries\n // \"UserProfile\" → [\"User\", \"Profile\"]\n // \"parseJSON\" → [\"parse\", \"JSON\"]\n // \"XMLParser\" → [\"XML\", \"Parser\"]\n let current = '';\n for (let i = 0; i < part.length; i++) {\n const ch = part[i];\n const isUpper = ch >= 'A' && ch <= 'Z';\n\n if (isUpper && current.length > 0) {\n const prevIsUpper =\n current[current.length - 1] >= 'A' && current[current.length - 1] <= 'Z';\n const nextIsLower = i + 1 < part.length && part[i + 1] >= 'a' && part[i + 1] <= 'z';\n\n if (!prevIsUpper || nextIsLower) {\n words.push(current.toLowerCase());\n current = '';\n }\n }\n current += ch;\n }\n if (current) words.push(current.toLowerCase());\n }\n\n return words;\n}\n\n/**\n * Convert a bare filename to the specified naming convention.\n *\n * @param bare - The bare filename without extension (e.g. \"UserProfile\")\n * @param target - The target convention (kebab-case, camelCase, PascalCase, snake_case)\n * @returns The converted name\n */\nexport function convertName(bare: string, target: string): string {\n const words = splitIntoWords(bare);\n if (words.length === 0) return bare;\n\n switch (target) {\n case 'kebab-case':\n return words.join('-');\n case 'camelCase':\n return words[0] + words.slice(1).map(capitalize).join('');\n case 'PascalCase':\n return words.map(capitalize).join('');\n case 'snake_case':\n return words.join('_');\n default:\n return bare;\n }\n}\n\nfunction capitalize(word: string): string {\n if (word.length === 0) return word;\n return word[0].toUpperCase() + word.slice(1);\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { ViberailsConfig } from '@viberails/types';\n\nexport interface TestStubRecord {\n path: string;\n absPath: string;\n moduleName: string;\n}\n\n/**\n * Generate a test stub record for a source file that is missing tests.\n * Returns null if the test file already exists.\n */\nexport function generateTestStub(\n sourceRelPath: string,\n config: ViberailsConfig,\n projectRoot: string,\n): TestStubRecord | null {\n const { testPattern } = config.structure;\n if (!testPattern) return null;\n\n const basename = path.basename(sourceRelPath);\n const stem = basename.slice(0, basename.indexOf('.'));\n const testSuffix = testPattern.replace('*', '');\n const testFilename = `${stem}${testSuffix}`;\n\n const dir = path.dirname(path.join(projectRoot, sourceRelPath));\n const testAbsPath = path.join(dir, testFilename);\n\n if (fs.existsSync(testAbsPath)) return null;\n\n return {\n path: path.relative(projectRoot, testAbsPath),\n absPath: testAbsPath,\n moduleName: stem,\n };\n}\n\n/**\n * Write a test stub file to disk.\n */\nexport function writeTestStub(stub: TestStubRecord, config: ViberailsConfig): void {\n const runner = config.stack.testRunner === 'jest' ? 'jest' : 'vitest';\n const importLine =\n runner === 'jest'\n ? '' // jest globals are available without import\n : \"import { describe, it, expect } from 'vitest';\\n\\n\";\n\n const content = `${importLine}describe('${stub.moduleName}', () => {\\n it.todo('add tests');\\n});\\n`;\n\n fs.mkdirSync(path.dirname(stub.absPath), { recursive: true });\n fs.writeFileSync(stub.absPath, content);\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { generateConfig } from '@viberails/config';\nimport { scan } from '@viberails/scanner';\nimport type { ConfigConventions, ConventionValue } from '@viberails/types';\nimport chalk from 'chalk';\nimport { displayScanResults } from '../display.js';\nimport { findProjectRoot } from '../utils/find-project-root.js';\nimport { confirm } from '../utils/prompt.js';\nimport { resolveWorkspacePackages } from '../utils/resolve-workspace-packages.js';\nimport { writeGeneratedFiles } from '../utils/write-generated-files.js';\nimport { setupPreCommitHook } from './init-hooks.js';\n\nconst CONFIG_FILE = 'viberails.config.json';\n\n/**\n * Filter a ConfigConventions object to only include high-confidence entries.\n */\nfunction filterHighConfidence(conventions: ConfigConventions): ConfigConventions {\n const filtered: ConfigConventions = {};\n for (const [key, value] of Object.entries(conventions)) {\n if (value === undefined) continue;\n if (typeof value === 'string') {\n filtered[key as keyof ConfigConventions] = value;\n } else if (value._confidence === 'high') {\n filtered[key as keyof ConfigConventions] = value as ConventionValue;\n }\n }\n return filtered;\n}\n\n/**\n * Run the viberails init flow.\n *\n * @param options - CLI options\n * @param cwd - Working directory override (for testing)\n */\nexport async function initCommand(options: { yes?: boolean }, cwd?: string): Promise<void> {\n const startDir = cwd ?? process.cwd();\n\n // 1. Find project root\n const projectRoot = findProjectRoot(startDir);\n if (!projectRoot) {\n throw new Error(\n 'No package.json found in this directory or any parent.\\n\\n' +\n 'Make sure you are inside a JavaScript or TypeScript project, then run:\\n' +\n ' npx viberails',\n );\n }\n\n // 2. Check for existing config\n const configPath = path.join(projectRoot, CONFIG_FILE);\n if (fs.existsSync(configPath)) {\n console.log(\n chalk.yellow('!') +\n ' viberails is already initialized in this project.\\n' +\n ' Run ' +\n chalk.cyan('viberails sync') +\n ' to update the generated files.',\n );\n return;\n }\n\n // 3. Run scanner\n console.log(chalk.dim('Scanning project...'));\n const scanResult = await scan(projectRoot);\n\n // 4. Display results\n displayScanResults(scanResult);\n\n // 5. Sparse project notice\n if (scanResult.statistics.totalFiles === 0) {\n console.log(\n chalk.yellow('!') +\n ' No source files detected. viberails will generate context with minimal content.\\n' +\n ' Run ' +\n chalk.cyan('viberails sync') +\n ' after adding source files.\\n',\n );\n }\n\n // 6. Interactive confirmation\n if (!options.yes) {\n const accepted = await confirm('Does this look right?');\n if (!accepted) {\n console.log('Aborted.');\n return;\n }\n }\n\n // 7. Generate config\n const config = generateConfig(scanResult);\n if (options.yes) {\n config.conventions = filterHighConfidence(config.conventions);\n }\n\n // 7b. Infer boundary rules for workspace projects\n if (config.workspace && config.workspace.packages.length > 0) {\n let shouldInfer = options.yes;\n if (!options.yes) {\n shouldInfer = await confirm('Infer boundary rules from import patterns?');\n }\n\n if (shouldInfer) {\n console.log(chalk.dim('Building import graph...'));\n const { buildImportGraph, inferBoundaries } = await import('@viberails/graph');\n const packages = resolveWorkspacePackages(projectRoot, config.workspace);\n const graph = await buildImportGraph(projectRoot, { packages, ignore: config.ignore });\n const inferred = inferBoundaries(graph);\n if (inferred.length > 0) {\n config.boundaries = inferred;\n config.rules.enforceBoundaries = true;\n console.log(` ${chalk.green('✓')} Inferred ${inferred.length} boundary rules`);\n }\n }\n }\n\n fs.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\\n`);\n\n // 8. Generate context and scan-result.json\n writeGeneratedFiles(projectRoot, config, scanResult);\n\n // 9. Update .gitignore\n updateGitignore(projectRoot);\n\n // 10. Set up pre-commit hook\n setupPreCommitHook(projectRoot);\n\n // 11. Print summary\n console.log(`\\n${chalk.bold('Created:')}`);\n console.log(` ${chalk.green('✓')} ${CONFIG_FILE}`);\n console.log(` ${chalk.green('✓')} .viberails/context.md`);\n console.log(` ${chalk.green('✓')} .viberails/scan-result.json`);\n console.log(`\\n${chalk.bold('Next steps:')}`);\n console.log(` 1. Review ${chalk.cyan('viberails.config.json')} and adjust rules`);\n console.log(\n ` 2. Commit ${chalk.cyan('viberails.config.json')} and ${chalk.cyan('.viberails/context.md')}`,\n );\n console.log(` 3. Run ${chalk.cyan('viberails check')} to verify your project passes`);\n}\n\n/**\n * Append viberails entries to .gitignore if not already present.\n * Only scan-result.json is ignored — context.md should be committed\n * so AI agents can read the enforced rules.\n */\nfunction updateGitignore(projectRoot: string): void {\n const gitignorePath = path.join(projectRoot, '.gitignore');\n let content = '';\n\n if (fs.existsSync(gitignorePath)) {\n content = fs.readFileSync(gitignorePath, 'utf-8');\n }\n\n if (!content.includes('.viberails/scan-result.json')) {\n const block = '\\n# viberails\\n.viberails/scan-result.json\\n';\n fs.writeFileSync(gitignorePath, `${content.trimEnd()}\\n${block}`);\n }\n}\n","import type { DetectedConvention, ScanResult, StackItem } from '@viberails/types';\nimport { FRAMEWORK_NAMES, LIBRARY_NAMES, STYLING_NAMES } from '@viberails/types';\nimport chalk from 'chalk';\nimport {\n formatExtensions,\n formatRoleGroup,\n formatSummary,\n groupByRole,\n} from './display-helpers.js';\nimport { displayMonorepoResults } from './display-monorepo.js';\n\n/** Labels for convention keys. */\nconst CONVENTION_LABELS: Record<string, string> = {\n fileNaming: 'File naming',\n componentNaming: 'Component naming',\n hookNaming: 'Hook naming',\n importAlias: 'Import alias',\n};\n\n/**\n * Format a StackItem for display: \"DisplayName Version\".\n */\nexport function formatItem(item: StackItem, nameMap?: Record<string, string>): string {\n const name = nameMap?.[item.name] ?? item.name;\n return item.version ? `${name} ${item.version}` : name;\n}\n\n/**\n * Format a confidence label for display.\n */\nexport function confidenceLabel(convention: DetectedConvention): string {\n const pct = Math.round(convention.consistency);\n if (convention.confidence === 'high') {\n return `${pct}% — high confidence, will enforce`;\n }\n return `${pct}% — medium confidence, suggested only`;\n}\n\n/**\n * Display conventions section, shared between single-package and monorepo.\n */\nexport function displayConventions(scanResult: ScanResult): void {\n const conventionEntries = Object.entries(scanResult.conventions);\n if (conventionEntries.length === 0) return;\n\n console.log(`\\n${chalk.bold('Conventions:')}`);\n for (const [key, convention] of conventionEntries) {\n if (convention.confidence === 'low') continue;\n const label = CONVENTION_LABELS[key] ?? key;\n\n if (scanResult.packages.length > 1) {\n const pkgValues = scanResult.packages\n .filter((pkg) => pkg.conventions[key] && pkg.conventions[key].confidence !== 'low')\n .map((pkg) => ({ relativePath: pkg.relativePath, convention: pkg.conventions[key] }));\n\n const allSame = pkgValues.every((pv) => pv.convention.value === convention.value);\n\n if (allSame || pkgValues.length <= 1) {\n const ind = convention.confidence === 'high' ? chalk.green('✓') : chalk.yellow('~');\n const detail = chalk.dim(`(${confidenceLabel(convention)})`);\n console.log(` ${ind} ${label}: ${convention.value} ${detail}`);\n } else {\n console.log(` ${chalk.yellow('~')} ${label}: varies by package`);\n for (const pv of pkgValues) {\n const pct = Math.round(pv.convention.consistency);\n console.log(` ${pv.relativePath}: ${pv.convention.value} (${pct}%)`);\n }\n }\n } else {\n const ind = convention.confidence === 'high' ? chalk.green('✓') : chalk.yellow('~');\n const detail = chalk.dim(`(${confidenceLabel(convention)})`);\n console.log(` ${ind} ${label}: ${convention.value} ${detail}`);\n }\n }\n}\n\n/**\n * Display summary section with statistics.\n */\nexport function displaySummarySection(scanResult: ScanResult): void {\n const pkgCount = scanResult.packages.length > 1 ? scanResult.packages.length : undefined;\n console.log(`\\n${chalk.bold('Summary:')}`);\n console.log(` ${formatSummary(scanResult.statistics, pkgCount)}`);\n const ext = formatExtensions(scanResult.statistics.filesByExtension);\n if (ext) {\n console.log(` ${ext}`);\n }\n}\n\n/**\n * Display scan results to the console with confidence indicators.\n *\n * @param scanResult - The scan result to display\n */\nexport function displayScanResults(scanResult: ScanResult): void {\n if (scanResult.packages.length > 1) {\n displayMonorepoResults(scanResult);\n return;\n }\n\n const { stack } = scanResult;\n\n console.log(`\\n${chalk.bold('Detected:')}`);\n\n if (stack.framework) {\n console.log(` ${chalk.green('✓')} ${formatItem(stack.framework, FRAMEWORK_NAMES)}`);\n }\n console.log(` ${chalk.green('✓')} ${formatItem(stack.language)}`);\n if (stack.styling) {\n console.log(` ${chalk.green('✓')} ${formatItem(stack.styling, STYLING_NAMES)}`);\n }\n if (stack.backend) {\n console.log(` ${chalk.green('✓')} ${formatItem(stack.backend, FRAMEWORK_NAMES)}`);\n }\n if (stack.linter) {\n console.log(` ${chalk.green('✓')} ${formatItem(stack.linter)}`);\n }\n if (stack.formatter) {\n console.log(` ${chalk.green('✓')} ${formatItem(stack.formatter)}`);\n }\n if (stack.testRunner) {\n console.log(` ${chalk.green('✓')} ${formatItem(stack.testRunner)}`);\n }\n if (stack.packageManager) {\n console.log(` ${chalk.green('✓')} ${formatItem(stack.packageManager)}`);\n }\n if (stack.libraries.length > 0) {\n for (const lib of stack.libraries) {\n console.log(` ${chalk.green('✓')} ${formatItem(lib, LIBRARY_NAMES)}`);\n }\n }\n\n // Structure grouped by role\n const groups = groupByRole(scanResult.structure.directories);\n if (groups.length > 0) {\n console.log(`\\n${chalk.bold('Structure:')}`);\n for (const group of groups) {\n console.log(` ${chalk.green('✓')} ${formatRoleGroup(group)}`);\n }\n }\n\n displayConventions(scanResult);\n displaySummarySection(scanResult);\n console.log('');\n}\n","import type { CodebaseStatistics, DirectoryInfo, DirectoryRole } from '@viberails/types';\nimport { ROLE_DESCRIPTIONS } from '@viberails/types';\n\n/**\n * A group of directories sharing the same role within a package.\n */\nexport interface RoleGroup {\n role: DirectoryRole;\n label: string;\n dirCount: number;\n totalFiles: number;\n singlePath?: string;\n}\n\n/**\n * Groups a package's directories by role, merging file counts.\n * Filters out `unknown` role. For single-directory roles, sets `singlePath`.\n *\n * @param directories - The directories to group.\n * @returns Array of RoleGroup entries sorted by role label.\n */\nexport function groupByRole(directories: DirectoryInfo[]): RoleGroup[] {\n const map = new Map<DirectoryRole, { dirs: DirectoryInfo[] }>();\n\n for (const dir of directories) {\n if (dir.role === 'unknown') continue;\n const existing = map.get(dir.role);\n if (existing) {\n existing.dirs.push(dir);\n } else {\n map.set(dir.role, { dirs: [dir] });\n }\n }\n\n const groups: RoleGroup[] = [];\n for (const [role, { dirs }] of map) {\n const label = ROLE_DESCRIPTIONS[role] ?? role;\n const totalFiles = dirs.reduce((sum, d) => sum + d.fileCount, 0);\n groups.push({\n role,\n label,\n dirCount: dirs.length,\n totalFiles,\n singlePath: dirs.length === 1 ? dirs[0].path : undefined,\n });\n }\n\n return groups;\n}\n\n/**\n * Format a summary line from CodebaseStatistics.\n *\n * @param stats - The codebase statistics.\n * @param packageCount - Number of packages (shown for monorepos with > 1).\n * @returns Formatted summary string, e.g. \"3 packages · 743 source files · 48,200 lines · avg 65 lines/file\"\n */\nexport function formatSummary(stats: CodebaseStatistics, packageCount?: number): string {\n const parts: string[] = [];\n if (packageCount && packageCount > 1) {\n parts.push(`${packageCount} packages`);\n }\n parts.push(`${stats.totalFiles.toLocaleString()} source files`);\n parts.push(`${stats.totalLines.toLocaleString()} lines`);\n parts.push(`avg ${Math.round(stats.averageFileLines)} lines/file`);\n return parts.join(' \\u00b7 ');\n}\n\n/**\n * Format top extensions by count, e.g. \".tsx 312 · .ts 289 · .js 142\".\n *\n * @param filesByExtension - Extension counts from CodebaseStatistics.\n * @param maxEntries - Maximum number of extensions to show (default 4).\n * @returns Formatted extension string.\n */\nexport function formatExtensions(\n filesByExtension: Record<string, number>,\n maxEntries: number = 4,\n): string {\n return Object.entries(filesByExtension)\n .sort(([, a], [, b]) => b - a)\n .slice(0, maxEntries)\n .map(([ext, count]) => `${ext} ${count}`)\n .join(' \\u00b7 ');\n}\n\n/**\n * Format a RoleGroup for display.\n *\n * @param group - The role group.\n * @returns Formatted string, e.g. \"Hooks — 4 dirs (55 files)\" or \"Pages / Routes — app (12 files)\"\n */\nexport function formatRoleGroup(group: RoleGroup): string {\n const files = group.totalFiles === 1 ? '1 file' : `${group.totalFiles} files`;\n if (group.singlePath) {\n return `${group.label} — ${group.singlePath} (${files})`;\n }\n const dirs = group.dirCount === 1 ? '1 dir' : `${group.dirCount} dirs`;\n return `${group.label} — ${dirs} (${files})`;\n}\n","import type { PackageScanResult, ScanResult } from '@viberails/types';\nimport { FRAMEWORK_NAMES, STYLING_NAMES } from '@viberails/types';\nimport chalk from 'chalk';\nimport { displayConventions, displaySummarySection, formatItem } from './display.js';\nimport { formatRoleGroup, groupByRole } from './display-helpers.js';\n\n/**\n * Format a package summary line for monorepo display.\n */\nexport function formatPackageSummary(pkg: PackageScanResult): string {\n const parts: string[] = [];\n if (pkg.stack.framework) {\n parts.push(formatItem(pkg.stack.framework, FRAMEWORK_NAMES));\n }\n if (pkg.stack.styling) {\n parts.push(formatItem(pkg.stack.styling, STYLING_NAMES));\n }\n const files = `${pkg.statistics.totalFiles} files`;\n const detail = parts.length > 0 ? `${parts.join(', ')} (${files})` : `(${files})`;\n return ` ${pkg.relativePath} — ${detail}`;\n}\n\n/**\n * Display scan results for a monorepo with per-package summaries.\n */\nexport function displayMonorepoResults(scanResult: ScanResult): void {\n const { stack, packages } = scanResult;\n\n console.log(`\\n${chalk.bold(`Detected: (monorepo, ${packages.length} packages)`)}`);\n\n // Shared stack items at the top\n console.log(` ${chalk.green('✓')} ${formatItem(stack.language)}`);\n if (stack.packageManager) {\n console.log(` ${chalk.green('✓')} ${formatItem(stack.packageManager)}`);\n }\n if (stack.linter) {\n console.log(` ${chalk.green('✓')} ${formatItem(stack.linter)}`);\n }\n if (stack.formatter) {\n console.log(` ${chalk.green('✓')} ${formatItem(stack.formatter)}`);\n }\n if (stack.testRunner) {\n console.log(` ${chalk.green('✓')} ${formatItem(stack.testRunner)}`);\n }\n\n // Per-package summaries\n console.log('');\n for (const pkg of packages) {\n console.log(formatPackageSummary(pkg));\n }\n\n // Structure grouped by role per package\n const packagesWithDirs = packages.filter((pkg) =>\n pkg.structure.directories.some((d) => d.role !== 'unknown'),\n );\n if (packagesWithDirs.length > 0) {\n console.log(`\\n${chalk.bold('Structure:')}`);\n for (const pkg of packagesWithDirs) {\n const groups = groupByRole(pkg.structure.directories);\n if (groups.length === 0) continue;\n console.log(` ${pkg.relativePath}:`);\n for (const group of groups) {\n console.log(` ${chalk.green('✓')} ${formatRoleGroup(group)}`);\n }\n }\n }\n\n displayConventions(scanResult);\n displaySummarySection(scanResult);\n console.log('');\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { generateContext } from '@viberails/context';\nimport type { ScanResult, ViberailsConfig } from '@viberails/types';\n\nconst CONTEXT_DIR = '.viberails';\nconst CONTEXT_FILE = 'context.md';\nconst SCAN_RESULT_FILE = 'scan-result.json';\n\n/**\n * Write all generated files: context.md and scan-result.json.\n *\n * @param projectRoot - Absolute path to the project root\n * @param config - The viberails configuration\n * @param scanResult - The raw scan result\n */\nexport function writeGeneratedFiles(\n projectRoot: string,\n config: ViberailsConfig,\n scanResult: ScanResult,\n): void {\n const contextDir = path.join(projectRoot, CONTEXT_DIR);\n\n try {\n if (!fs.existsSync(contextDir)) {\n fs.mkdirSync(contextDir, { recursive: true });\n }\n\n const context = generateContext(config);\n fs.writeFileSync(path.join(contextDir, CONTEXT_FILE), context);\n\n fs.writeFileSync(\n path.join(contextDir, SCAN_RESULT_FILE),\n `${JSON.stringify(scanResult, null, 2)}\\n`,\n );\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n throw new Error(`Failed to write generated files to ${contextDir}: ${message}`);\n }\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport chalk from 'chalk';\n\n/**\n * Set up a pre-commit hook that runs viberails check on staged files.\n * Detects Lefthook, Husky, or falls back to a raw git hook.\n */\nexport function setupPreCommitHook(projectRoot: string): void {\n // Check for Lefthook\n const lefthookPath = path.join(projectRoot, 'lefthook.yml');\n if (fs.existsSync(lefthookPath)) {\n addLefthookPreCommit(lefthookPath);\n console.log(` ${chalk.green('✓')} lefthook.yml — added viberails pre-commit`);\n return;\n }\n\n // Check for Husky\n const huskyDir = path.join(projectRoot, '.husky');\n if (fs.existsSync(huskyDir)) {\n writeHuskyPreCommit(huskyDir);\n console.log(` ${chalk.green('✓')} .husky/pre-commit — added viberails check`);\n return;\n }\n\n // Fall back to raw git hook\n const gitDir = path.join(projectRoot, '.git');\n if (fs.existsSync(gitDir)) {\n const hooksDir = path.join(gitDir, 'hooks');\n if (!fs.existsSync(hooksDir)) {\n fs.mkdirSync(hooksDir, { recursive: true });\n }\n writeGitHookPreCommit(hooksDir);\n console.log(` ${chalk.green('✓')} .git/hooks/pre-commit`);\n }\n}\n\nfunction writeGitHookPreCommit(hooksDir: string): void {\n const hookPath = path.join(hooksDir, 'pre-commit');\n if (fs.existsSync(hookPath)) {\n const existing = fs.readFileSync(hookPath, 'utf-8');\n if (existing.includes('viberails')) return;\n fs.writeFileSync(\n hookPath,\n `${existing.trimEnd()}\\n\\n# viberails check\\nnpx viberails check --staged\\n`,\n );\n return;\n }\n const script = [\n '#!/bin/sh',\n '# Generated by viberails — https://viberails.sh',\n '',\n 'npx viberails check --staged',\n '',\n ].join('\\n');\n fs.writeFileSync(hookPath, script, { mode: 0o755 });\n}\n\nfunction addLefthookPreCommit(lefthookPath: string): void {\n const content = fs.readFileSync(lefthookPath, 'utf-8');\n if (content.includes('viberails')) return;\n const addition = ['', ' viberails:', ' run: npx viberails check --staged'].join('\\n');\n fs.writeFileSync(lefthookPath, `${content.trimEnd()}\\n${addition}\\n`);\n}\n\nfunction writeHuskyPreCommit(huskyDir: string): void {\n const hookPath = path.join(huskyDir, 'pre-commit');\n if (fs.existsSync(hookPath)) {\n const existing = fs.readFileSync(hookPath, 'utf-8');\n if (!existing.includes('viberails')) {\n fs.writeFileSync(hookPath, `${existing.trimEnd()}\\nnpx viberails check --staged\\n`);\n }\n return;\n }\n fs.writeFileSync(hookPath, '#!/bin/sh\\nnpx viberails check --staged\\n', { mode: 0o755 });\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { loadConfig, mergeConfig } from '@viberails/config';\nimport { scan } from '@viberails/scanner';\nimport chalk from 'chalk';\nimport { findProjectRoot } from '../utils/find-project-root.js';\nimport { writeGeneratedFiles } from '../utils/write-generated-files.js';\n\nconst CONFIG_FILE = 'viberails.config.json';\n\n/**\n * Run the viberails sync flow: re-scan, merge config, regenerate context.\n *\n * @param cwd - Working directory override (for testing)\n */\nexport async function syncCommand(cwd?: string): Promise<void> {\n const startDir = cwd ?? process.cwd();\n\n // 1. Find project root\n const projectRoot = findProjectRoot(startDir);\n if (!projectRoot) {\n throw new Error(\n 'No package.json found in this directory or any parent.\\n\\n' +\n 'Make sure you are inside a JavaScript or TypeScript project, then run:\\n' +\n ' npx viberails',\n );\n }\n\n // 2. Load existing config\n const configPath = path.join(projectRoot, CONFIG_FILE);\n const existing = await loadConfig(configPath);\n\n // 3. Re-scan\n console.log(chalk.dim('Scanning project...'));\n const scanResult = await scan(projectRoot);\n\n // 4. Merge config\n const merged = mergeConfig(existing, scanResult);\n fs.writeFileSync(configPath, `${JSON.stringify(merged, null, 2)}\\n`);\n\n // 5. Regenerate context and scan-result.json\n writeGeneratedFiles(projectRoot, merged, scanResult);\n\n console.log(`\\n${chalk.bold('Synced:')}`);\n console.log(` ${chalk.green('✓')} ${CONFIG_FILE} — updated`);\n console.log(` ${chalk.green('✓')} .viberails/context.md — regenerated`);\n console.log(` ${chalk.green('✓')} .viberails/scan-result.json — updated`);\n}\n"],"mappings":"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","names":["chalk","fs","path","resolve","fs","path","fs","path","loadConfig","chalk","fs","path","fs","path","SOURCE_EXTS","basename","CONFIG_FILE","chalk","loadConfig","fs","path","loadConfig","chalk","execSync","createInterface","chalk","resolve","path","fs","path","fs","path","basename","CONFIG_FILE","chalk","loadConfig","fs","path","chalk","FRAMEWORK_NAMES","STYLING_NAMES","chalk","chalk","chalk","chalk","FRAMEWORK_NAMES","STYLING_NAMES","fs","path","fs","path","chalk","CONFIG_FILE","chalk","fs","path","loadConfig","scan","chalk","CONFIG_FILE","loadConfig","chalk","scan","chalk"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/commands/boundaries.ts","../src/utils/find-project-root.ts","../src/utils/prompt.ts","../src/utils/resolve-workspace-packages.ts","../src/commands/check.ts","../src/commands/check-config.ts","../src/commands/check-files.ts","../src/commands/check-tests.ts","../src/commands/fix.ts","../src/commands/fix-helpers.ts","../src/commands/fix-imports.ts","../src/commands/fix-naming.ts","../src/commands/convert-name.ts","../src/commands/fix-tests.ts","../src/commands/init.ts","../src/display.ts","../src/display-helpers.ts","../src/display-monorepo.ts","../src/utils/write-generated-files.ts","../src/commands/init-hooks.ts","../src/commands/sync.ts"],"sourcesContent":["import chalk from 'chalk';\nimport { Command } from 'commander';\nimport { boundariesCommand } from './commands/boundaries.js';\nimport { checkCommand } from './commands/check.js';\nimport { fixCommand } from './commands/fix.js';\nimport { initCommand } from './commands/init.js';\nimport { syncCommand } from './commands/sync.js';\n\ndeclare const __PACKAGE_VERSION__: string;\nexport const VERSION: string = __PACKAGE_VERSION__;\n\nconst program = new Command();\n\nprogram.name('viberails').description('Guardrails for vibe coding').version(VERSION);\n\nprogram\n .command('init', { isDefault: true })\n .description('Scan your project and set up enforcement guardrails')\n .option('-y, --yes', 'Non-interactive mode (use defaults, high-confidence only)')\n .action(async (options: { yes?: boolean }) => {\n try {\n await initCommand(options);\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n console.error(`${chalk.red('Error:')} ${message}`);\n process.exit(1);\n }\n });\n\nprogram\n .command('sync')\n .description('Re-scan and update generated files')\n .action(async () => {\n try {\n await syncCommand();\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n console.error(`${chalk.red('Error:')} ${message}`);\n process.exit(1);\n }\n });\n\nprogram\n .command('check')\n .description('Check files against enforced rules')\n .option('--staged', 'Check only staged files (for pre-commit hooks)')\n .option('--files <files...>', 'Check specific files')\n .option('--no-boundaries', 'Skip boundary checking')\n .action(async (options: { staged?: boolean; files?: string[]; boundaries?: boolean }) => {\n try {\n const exitCode = await checkCommand({\n ...options,\n noBoundaries: options.boundaries === false,\n });\n process.exit(exitCode);\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n console.error(`${chalk.red('Error:')} ${message}`);\n process.exit(1);\n }\n });\n\nprogram\n .command('fix')\n .description('Auto-fix file naming violations and generate missing test stubs')\n .option('--dry-run', 'Show planned fixes without applying them')\n .option('--rule <rules...>', 'Fix only specific rules (file-naming, missing-test)')\n .option('-y, --yes', 'Skip confirmation prompt')\n .action(async (options: { dryRun?: boolean; rule?: string[]; yes?: boolean }) => {\n try {\n const exitCode = await fixCommand(options);\n process.exit(exitCode);\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n console.error(`${chalk.red('Error:')} ${message}`);\n process.exit(1);\n }\n });\n\nprogram\n .command('boundaries')\n .description('Display, infer, or inspect import boundary rules')\n .option('--infer', 'Infer boundary rules from current import patterns')\n .option('--graph', 'Display import graph summary')\n .action(async (options: { infer?: boolean; graph?: boolean }) => {\n try {\n await boundariesCommand(options);\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n console.error(`${chalk.red('Error:')} ${message}`);\n process.exit(1);\n }\n });\n\nprogram.parse();\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { loadConfig } from '@viberails/config';\nimport type { ViberailsConfig } from '@viberails/types';\nimport chalk from 'chalk';\nimport { findProjectRoot } from '../utils/find-project-root.js';\nimport { confirm } from '../utils/prompt.js';\nimport { resolveWorkspacePackages } from '../utils/resolve-workspace-packages.js';\n\nconst CONFIG_FILE = 'viberails.config.json';\n\nexport interface BoundariesOptions {\n infer?: boolean;\n graph?: boolean;\n}\n\n/**\n * Display, infer, or inspect import boundary rules.\n *\n * @param options - CLI options\n * @param cwd - Working directory override (for testing)\n */\nexport async function boundariesCommand(options: BoundariesOptions, cwd?: string): Promise<void> {\n const startDir = cwd ?? process.cwd();\n const projectRoot = findProjectRoot(startDir);\n if (!projectRoot) {\n throw new Error('No package.json found. Are you in a JS/TS project?');\n }\n\n const configPath = path.join(projectRoot, CONFIG_FILE);\n if (!fs.existsSync(configPath)) {\n throw new Error('No viberails.config.json found. Run `viberails init` first.');\n }\n\n const config = await loadConfig(configPath);\n\n if (options.graph) {\n await showGraph(projectRoot, config);\n return;\n }\n\n if (options.infer) {\n await inferAndDisplay(projectRoot, config, configPath);\n return;\n }\n\n displayRules(config);\n}\n\n/** Display configured boundary rules. */\nfunction displayRules(config: ViberailsConfig): void {\n if (!config.boundaries || config.boundaries.length === 0) {\n console.log(chalk.yellow('No boundary rules configured.'));\n console.log(`Run ${chalk.cyan('viberails boundaries --infer')} to generate rules.`);\n return;\n }\n\n const allowRules = config.boundaries.filter((r) => r.allow);\n const denyRules = config.boundaries.filter((r) => !r.allow);\n\n console.log(`\\n${chalk.bold(`Boundary rules (${config.boundaries.length} rules):`)}\\n`);\n\n for (const r of allowRules) {\n console.log(` ${chalk.green('✓')} ${r.from} → ${r.to}`);\n }\n\n for (const r of denyRules) {\n const reason = r.reason ? chalk.dim(` (${r.reason})`) : '';\n console.log(` ${chalk.red('✗')} ${r.from} → ${r.to}${reason}`);\n }\n\n console.log(\n `\\nEnforcement: ${config.rules.enforceBoundaries ? chalk.green('on') : chalk.yellow('off')}`,\n );\n}\n\n/** Infer boundary rules from import patterns and optionally save. */\nasync function inferAndDisplay(\n projectRoot: string,\n config: ViberailsConfig,\n configPath: string,\n): Promise<void> {\n console.log(chalk.dim('Analyzing imports...'));\n const { buildImportGraph, inferBoundaries } = await import('@viberails/graph');\n\n const packages = config.workspace\n ? resolveWorkspacePackages(projectRoot, config.workspace)\n : undefined;\n\n const graph = await buildImportGraph(projectRoot, {\n packages,\n ignore: config.ignore,\n });\n\n console.log(chalk.dim(`${graph.nodes.length} files, ${graph.edges.length} edges`));\n\n const inferred = inferBoundaries(graph);\n\n if (inferred.length === 0) {\n console.log(chalk.yellow('No boundary rules could be inferred.'));\n return;\n }\n\n const allow = inferred.filter((r) => r.allow);\n const deny = inferred.filter((r) => !r.allow);\n\n console.log(`\\n${chalk.bold('Inferred boundary rules:')}\\n`);\n\n for (const r of allow) {\n console.log(` ${chalk.green('✓')} ${r.from} → ${r.to}`);\n }\n\n for (const r of deny) {\n const reason = r.reason ? chalk.dim(` (${r.reason})`) : '';\n console.log(` ${chalk.red('✗')} ${r.from} → ${r.to}${reason}`);\n }\n\n console.log(`\\n ${allow.length} allowed, ${deny.length} denied`);\n\n const shouldSave = await confirm('\\nSave to viberails.config.json?');\n if (shouldSave) {\n config.boundaries = inferred;\n config.rules.enforceBoundaries = true;\n fs.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\\n`);\n console.log(`${chalk.green('✓')} Saved ${inferred.length} rules`);\n }\n}\n\n/** Display import graph summary. */\nasync function showGraph(projectRoot: string, config: ViberailsConfig): Promise<void> {\n console.log(chalk.dim('Building import graph...'));\n const { buildImportGraph } = await import('@viberails/graph');\n\n const packages = config.workspace\n ? resolveWorkspacePackages(projectRoot, config.workspace)\n : undefined;\n\n const graph = await buildImportGraph(projectRoot, {\n packages,\n ignore: config.ignore,\n });\n\n console.log(`\\n${chalk.bold('Import dependency graph:')}\\n`);\n console.log(` ${graph.nodes.length} files, ${graph.edges.length} imports\\n`);\n\n if (graph.packages.length > 0) {\n for (const pkg of graph.packages) {\n const deps =\n pkg.internalDeps.length > 0\n ? `\\n${pkg.internalDeps.map((d) => ` → ${d}`).join('\\n')}`\n : chalk.dim(' (no internal deps)');\n console.log(` ${pkg.name}${deps}`);\n }\n }\n\n if (graph.cycles.length > 0) {\n console.log(`\\n${chalk.yellow('Cycles detected:')}`);\n for (const cycle of graph.cycles) {\n const paths = cycle.map((f) => path.relative(projectRoot, f));\n console.log(` ${paths.join(' → ')}`);\n }\n }\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\n\n/**\n * Walk up from startDir looking for a directory containing package.json.\n *\n * @param startDir - The directory to start searching from\n * @returns The project root path, or null if no package.json is found\n */\nexport function findProjectRoot(startDir: string): string | null {\n let dir = path.resolve(startDir);\n\n while (true) {\n if (fs.existsSync(path.join(dir, 'package.json'))) {\n return dir;\n }\n\n const parent = path.dirname(dir);\n if (parent === dir) {\n return null;\n }\n dir = parent;\n }\n}\n","import * as readline from 'node:readline';\n\n/**\n * Prompt the user for a yes/no confirmation.\n *\n * @param message - The question to display (without the Y/n suffix)\n * @returns true if the user confirms, false otherwise\n */\nexport async function confirm(message: string): Promise<boolean> {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n return new Promise<boolean>((resolve) => {\n rl.question(`${message} (Y/n) `, (answer) => {\n rl.close();\n const trimmed = answer.trim().toLowerCase();\n resolve(trimmed === '' || trimmed === 'y' || trimmed === 'yes');\n });\n });\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { WorkspaceConfig, WorkspacePackage } from '@viberails/types';\n\n/**\n * Resolve WorkspacePackage[] from config workspace relative paths.\n *\n * Reads each package's package.json to get the name and dependencies,\n * then filters internalDeps to only include workspace-internal packages.\n *\n * @param projectRoot - Absolute path to the project root\n * @param workspace - The workspace config from viberails.config.json\n * @returns Array of resolved WorkspacePackage objects\n */\nexport function resolveWorkspacePackages(\n projectRoot: string,\n workspace: WorkspaceConfig,\n): WorkspacePackage[] {\n const packages: WorkspacePackage[] = [];\n\n for (const relativePath of workspace.packages) {\n const absPath = path.join(projectRoot, relativePath);\n const pkgJsonPath = path.join(absPath, 'package.json');\n\n if (!fs.existsSync(pkgJsonPath)) continue;\n\n let pkg: Record<string, unknown>;\n try {\n pkg = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8'));\n } catch {\n continue;\n }\n\n const name = pkg.name as string;\n if (!name) continue;\n\n const allDeps = [\n ...Object.keys((pkg.dependencies as Record<string, unknown>) ?? {}),\n ...Object.keys((pkg.devDependencies as Record<string, unknown>) ?? {}),\n ];\n\n packages.push({ name, path: absPath, relativePath, internalDeps: allDeps });\n }\n\n // Filter internalDeps to only workspace-internal package names\n const packageNames = new Set(packages.map((p) => p.name));\n for (const pkg of packages) {\n pkg.internalDeps = pkg.internalDeps.filter((dep) => packageNames.has(dep));\n }\n\n return packages;\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { loadConfig } from '@viberails/config';\nimport type { CheckViolation } from '@viberails/types';\nimport chalk from 'chalk';\nimport { findProjectRoot } from '../utils/find-project-root.js';\nimport { resolveWorkspacePackages } from '../utils/resolve-workspace-packages.js';\nimport { resolveConfigForFile, resolveIgnoreForFile } from './check-config.js';\nimport {\n checkNaming,\n countFileLines,\n getAllSourceFiles,\n getStagedFiles,\n isIgnored,\n} from './check-files.js';\nimport { checkMissingTests } from './check-tests.js';\n\nexport { resolveConfigForFile } from './check-config.js';\n\nconst CONFIG_FILE = 'viberails.config.json';\n\nexport interface CheckOptions {\n files?: string[];\n staged?: boolean;\n noBoundaries?: boolean;\n}\n\n/**\n * Run the viberails check command.\n * Returns exit code: 0 = pass or warn-mode, 1 = violations in enforce mode.\n */\nexport async function checkCommand(options: CheckOptions, cwd?: string): Promise<number> {\n const startDir = cwd ?? process.cwd();\n\n const projectRoot = findProjectRoot(startDir);\n if (!projectRoot) {\n console.error(`${chalk.red('Error:')} No package.json found. Are you in a JS/TS project?`);\n return 1;\n }\n\n const configPath = path.join(projectRoot, CONFIG_FILE);\n if (!fs.existsSync(configPath)) {\n console.error(\n `${chalk.red('Error:')} No viberails.config.json found. Run \\`viberails init\\` first.`,\n );\n return 1;\n }\n\n const config = await loadConfig(configPath);\n\n // Determine which files to check\n let filesToCheck: string[];\n if (options.staged) {\n filesToCheck = getStagedFiles(projectRoot);\n } else if (options.files && options.files.length > 0) {\n filesToCheck = options.files;\n } else {\n filesToCheck = getAllSourceFiles(projectRoot, config);\n }\n\n if (filesToCheck.length === 0) {\n console.log(`${chalk.green('✓')} No files to check.`);\n return 0;\n }\n\n const violations: CheckViolation[] = [];\n const severity = config.enforcement === 'enforce' ? 'error' : 'warn';\n\n for (const file of filesToCheck) {\n const absPath = path.isAbsolute(file) ? file : path.join(projectRoot, file);\n const relPath = path.relative(projectRoot, absPath);\n\n const effectiveIgnore = resolveIgnoreForFile(relPath, config);\n if (isIgnored(relPath, effectiveIgnore)) continue;\n if (!fs.existsSync(absPath)) continue;\n\n const resolved = resolveConfigForFile(relPath, config);\n\n // Check 1: File size\n if (resolved.rules.maxFileLines > 0) {\n const lines = countFileLines(absPath);\n if (lines !== null && lines > resolved.rules.maxFileLines) {\n violations.push({\n file: relPath,\n rule: 'file-size',\n message: `${lines} lines (max ${resolved.rules.maxFileLines}). Split into focused modules.`,\n severity,\n });\n }\n }\n\n // Check 2: File naming convention\n if (resolved.rules.enforceNaming && resolved.conventions.fileNaming) {\n const namingViolation = checkNaming(relPath, resolved.conventions);\n if (namingViolation) {\n violations.push({\n file: relPath,\n rule: 'file-naming',\n message: namingViolation,\n severity,\n });\n }\n }\n }\n\n // Check 3: Missing tests (only on full project check, not staged/specific files)\n if (config.rules.requireTests && !options.staged && !options.files) {\n const testViolations = checkMissingTests(projectRoot, config, severity);\n violations.push(...testViolations);\n }\n\n // Check 4: Boundary violations\n if (\n config.rules.enforceBoundaries &&\n config.boundaries &&\n config.boundaries.length > 0 &&\n !options.noBoundaries\n ) {\n const startTime = Date.now();\n const { buildImportGraph, checkBoundaries } = await import('@viberails/graph');\n\n const packages = config.workspace\n ? resolveWorkspacePackages(projectRoot, config.workspace)\n : undefined;\n\n const graph = await buildImportGraph(projectRoot, {\n packages,\n ignore: config.ignore,\n });\n\n const boundaryViolations = checkBoundaries(graph, config.boundaries);\n\n // In staged/files mode, only report violations in those files\n const filterSet =\n options.staged || options.files\n ? new Set(filesToCheck.map((f) => path.resolve(projectRoot, f)))\n : null;\n\n for (const bv of boundaryViolations) {\n if (filterSet && !filterSet.has(bv.file)) continue;\n\n const relFile = path.relative(projectRoot, bv.file);\n violations.push({\n file: relFile,\n rule: 'boundary-violation',\n message: `Imports \"${bv.specifier}\" violating boundary: ${bv.rule.from} → ${bv.rule.to}${bv.rule.reason ? ` (${bv.rule.reason})` : ''}`,\n severity,\n });\n }\n\n const elapsed = Date.now() - startTime;\n console.log(chalk.dim(` Boundary check: ${graph.nodes.length} files in ${elapsed}ms`));\n }\n\n // Output results\n if (violations.length === 0) {\n console.log(`${chalk.green('✓')} ${filesToCheck.length} files checked — no violations`);\n return 0;\n }\n\n for (const v of violations) {\n const icon = v.severity === 'error' ? chalk.red('✗') : chalk.yellow('!');\n console.log(`${icon} ${chalk.dim(v.rule)} ${v.file}: ${v.message}`);\n }\n\n const word = violations.length === 1 ? 'violation' : 'violations';\n console.log(`\\n${violations.length} ${word} found.`);\n\n if (config.enforcement === 'enforce') {\n console.log(chalk.red('Fix violations before committing.'));\n return 1;\n }\n\n return 0;\n}\n","import type { ConfigConventions, ConfigRules, ViberailsConfig } from '@viberails/types';\n\nexport interface ResolvedConfig {\n rules: ConfigRules;\n conventions: ConfigConventions;\n}\n\n/**\n * Resolve the effective config for a file by finding its package override.\n * Returns the global config merged with any matching package overrides.\n */\nexport function resolveConfigForFile(relPath: string, config: ViberailsConfig): ResolvedConfig {\n if (!config.packages || config.packages.length === 0) {\n return { rules: config.rules, conventions: config.conventions };\n }\n\n // Sort by path length descending to match the most specific package first\n const sortedPackages = [...config.packages].sort((a, b) => b.path.length - a.path.length);\n\n for (const pkg of sortedPackages) {\n if (relPath.startsWith(`${pkg.path}/`) || relPath === pkg.path) {\n return {\n rules: { ...config.rules, ...pkg.rules },\n conventions: { ...config.conventions, ...pkg.conventions },\n };\n }\n }\n\n return { rules: config.rules, conventions: config.conventions };\n}\n\n/**\n * Resolve ignore patterns for a file, appending any package-specific patterns.\n */\nexport function resolveIgnoreForFile(relPath: string, config: ViberailsConfig): string[] {\n const globalIgnore = config.ignore;\n if (!config.packages) return globalIgnore;\n\n for (const pkg of config.packages) {\n if (pkg.ignore && relPath.startsWith(`${pkg.path}/`)) {\n return [...globalIgnore, ...pkg.ignore];\n }\n }\n return globalIgnore;\n}\n","import { execSync } from 'node:child_process';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { ConfigConventions, ConventionValue, ViberailsConfig } from '@viberails/types';\n\nconst ALWAYS_SKIP_DIRS = new Set([\n 'node_modules',\n '.git',\n 'dist',\n 'build',\n '.next',\n '.expo',\n '.output',\n '.svelte-kit',\n '.turbo',\n 'coverage',\n '.viberails',\n]);\n\nexport const SOURCE_EXTS = new Set([\n '.ts',\n '.tsx',\n '.js',\n '.jsx',\n '.mjs',\n '.cjs',\n '.vue',\n '.svelte',\n '.astro',\n]);\n\nexport const NAMING_PATTERNS: Record<string, RegExp> = {\n 'kebab-case': /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/,\n camelCase: /^[a-z][a-zA-Z0-9]*$/,\n PascalCase: /^[A-Z][a-zA-Z0-9]*$/,\n snake_case: /^[a-z][a-z0-9]*(_[a-z0-9]+)*$/,\n};\n\n/** Check if a path matches any ignore pattern. */\nexport function isIgnored(relPath: string, ignorePatterns: string[]): boolean {\n for (const pattern of ignorePatterns) {\n if (pattern.endsWith('/**')) {\n const prefix = pattern.slice(0, -3);\n if (relPath.startsWith(`${prefix}/`) || relPath === prefix) return true;\n } else if (pattern.startsWith('**/')) {\n const suffix = pattern.slice(3);\n if (relPath.endsWith(suffix)) return true;\n } else if (relPath === pattern || relPath.startsWith(`${pattern}/`)) {\n return true;\n }\n }\n return false;\n}\n\n/** Count lines in a file. Returns null if the file can't be read. */\nexport function countFileLines(filePath: string): number | null {\n try {\n const content = fs.readFileSync(filePath, 'utf-8');\n if (content.length === 0) return 0;\n let count = 1;\n for (let i = 0; i < content.length; i++) {\n if (content.charCodeAt(i) === 10) count++;\n }\n return count;\n } catch {\n return null;\n }\n}\n\n/** Check whether a file's name violates the configured naming convention. */\nexport function checkNaming(relPath: string, conventions: ConfigConventions): string | undefined {\n const filename = path.basename(relPath);\n\n // Skip non-source files\n const ext = path.extname(filename);\n if (!SOURCE_EXTS.has(ext)) return undefined;\n\n // Skip special files\n if (\n filename.startsWith('index.') ||\n filename.includes('.config.') ||\n filename.includes('.test.') ||\n filename.includes('.spec.') ||\n filename.startsWith('.') ||\n filename.startsWith('_') ||\n filename.startsWith('+') ||\n filename.startsWith('$') ||\n filename.startsWith('[')\n ) {\n return undefined;\n }\n\n const bare = filename.slice(0, filename.indexOf('.'));\n const convention =\n typeof conventions.fileNaming === 'string'\n ? conventions.fileNaming\n : (conventions.fileNaming as Exclude<ConventionValue, string> | undefined)?.value;\n\n if (!convention) return undefined;\n\n const pattern = NAMING_PATTERNS[convention];\n if (!pattern || pattern.test(bare)) return undefined;\n\n return `File name \"${filename}\" does not follow ${convention} convention.`;\n}\n\n/** Get staged files from git. */\nexport function getStagedFiles(projectRoot: string): string[] {\n try {\n const output = execSync('git diff --cached --name-only --diff-filter=ACM', {\n cwd: projectRoot,\n encoding: 'utf-8',\n });\n return output.trim().split('\\n').filter(Boolean);\n } catch {\n return [];\n }\n}\n\n/** Get all source files in the project. */\nexport function getAllSourceFiles(projectRoot: string, config: ViberailsConfig): string[] {\n const files: string[] = [];\n const walk = (dir: string) => {\n let entries: fs.Dirent[];\n try {\n entries = fs.readdirSync(dir, { withFileTypes: true });\n } catch {\n return;\n }\n for (const entry of entries) {\n const rel = path.relative(projectRoot, path.join(dir, entry.name));\n if (entry.isDirectory()) {\n if (ALWAYS_SKIP_DIRS.has(entry.name)) {\n continue;\n }\n if (isIgnored(rel, config.ignore)) continue;\n walk(path.join(dir, entry.name));\n } else if (entry.isFile()) {\n const ext = path.extname(entry.name);\n if (SOURCE_EXTS.has(ext) && !isIgnored(rel, config.ignore)) {\n files.push(rel);\n }\n }\n }\n };\n walk(projectRoot);\n return files;\n}\n\n/** Collect source files from a directory recursively. */\nexport function collectSourceFiles(dir: string, projectRoot: string): string[] {\n const files: string[] = [];\n const walk = (d: string) => {\n let entries: fs.Dirent[];\n try {\n entries = fs.readdirSync(d, { withFileTypes: true });\n } catch {\n return;\n }\n for (const entry of entries) {\n if (entry.isDirectory()) {\n if (entry.name === 'node_modules') continue;\n walk(path.join(d, entry.name));\n } else if (entry.isFile()) {\n files.push(path.relative(projectRoot, path.join(d, entry.name)));\n }\n }\n };\n walk(dir);\n return files;\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { CheckViolation, ViberailsConfig } from '@viberails/types';\nimport { collectSourceFiles } from './check-files.js';\n\nconst SOURCE_EXTS = new Set([\n '.ts',\n '.tsx',\n '.js',\n '.jsx',\n '.mjs',\n '.cjs',\n '.vue',\n '.svelte',\n '.astro',\n]);\n\n/** Check for source files without corresponding test files. */\nexport function checkMissingTests(\n projectRoot: string,\n config: ViberailsConfig,\n severity: 'error' | 'warn',\n): CheckViolation[] {\n const violations: CheckViolation[] = [];\n const { testPattern } = config.structure;\n if (!testPattern) return violations;\n\n const srcDir = config.structure.srcDir;\n if (!srcDir) return violations;\n\n const srcPath = path.join(projectRoot, srcDir);\n if (!fs.existsSync(srcPath)) return violations;\n\n const testSuffix = testPattern.replace('*', '');\n const sourceFiles = collectSourceFiles(srcPath, projectRoot);\n\n for (const relFile of sourceFiles) {\n const basename = path.basename(relFile);\n\n // Skip test files, index files, type definition files\n if (\n basename.includes('.test.') ||\n basename.includes('.spec.') ||\n basename.startsWith('index.') ||\n basename.endsWith('.d.ts')\n ) {\n continue;\n }\n\n const ext = path.extname(basename);\n if (!SOURCE_EXTS.has(ext)) continue;\n\n const stem = basename.slice(0, basename.indexOf('.'));\n const expectedTestFile = `${stem}${testSuffix}`;\n\n // Look for the test file next to the source or in the tests directory\n const dir = path.dirname(path.join(projectRoot, relFile));\n const colocatedTest = path.join(dir, expectedTestFile);\n const testsDir = config.structure.tests;\n const dedicatedTest = testsDir ? path.join(projectRoot, testsDir, expectedTestFile) : null;\n\n const hasTest =\n fs.existsSync(colocatedTest) || (dedicatedTest !== null && fs.existsSync(dedicatedTest));\n\n if (!hasTest) {\n violations.push({\n file: relFile,\n rule: 'missing-test',\n message: `No test file found. Expected \\`${expectedTestFile}\\`.`,\n severity,\n });\n }\n }\n\n return violations;\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { loadConfig } from '@viberails/config';\nimport chalk from 'chalk';\nimport { findProjectRoot } from '../utils/find-project-root.js';\nimport { resolveConfigForFile } from './check-config.js';\nimport { checkNaming, getAllSourceFiles } from './check-files.js';\nimport { checkMissingTests } from './check-tests.js';\nimport { checkGitDirty, getConventionValue, printPlan, promptConfirm } from './fix-helpers.js';\nimport { updateImportsAfterRenames } from './fix-imports.js';\nimport {\n computeRename,\n deduplicateRenames,\n executeRename,\n type RenameRecord,\n} from './fix-naming.js';\nimport { generateTestStub, type TestStubRecord, writeTestStub } from './fix-tests.js';\n\nconst CONFIG_FILE = 'viberails.config.json';\n\nexport interface FixOptions {\n dryRun?: boolean;\n rule?: string[];\n yes?: boolean;\n}\n\n/**\n * Run the viberails fix command.\n * Detects violations, computes fixes, optionally confirms, then applies.\n */\nexport async function fixCommand(options: FixOptions, cwd?: string): Promise<number> {\n const startDir = cwd ?? process.cwd();\n const projectRoot = findProjectRoot(startDir);\n\n if (!projectRoot) {\n console.error(`${chalk.red('Error:')} No package.json found. Are you in a JS/TS project?`);\n return 1;\n }\n\n const configPath = path.join(projectRoot, CONFIG_FILE);\n if (!fs.existsSync(configPath)) {\n console.error(\n `${chalk.red('Error:')} No viberails.config.json found. Run \\`viberails init\\` first.`,\n );\n return 1;\n }\n\n const config = await loadConfig(configPath);\n\n // Git dirty check — warn but don't block\n if (!options.dryRun) {\n const isDirty = checkGitDirty(projectRoot);\n if (isDirty) {\n console.log(\n chalk.yellow('Warning: You have uncommitted changes. Consider committing first.'),\n );\n }\n }\n\n const shouldFixNaming = !options.rule || options.rule.includes('file-naming');\n const shouldFixTests = !options.rule || options.rule.includes('missing-test');\n\n // Collect source files\n const allFiles = getAllSourceFiles(projectRoot, config);\n\n // Compute naming renames\n const renames: RenameRecord[] = [];\n if (shouldFixNaming) {\n for (const file of allFiles) {\n const resolved = resolveConfigForFile(file, config);\n if (!resolved.rules.enforceNaming || !resolved.conventions.fileNaming) continue;\n\n const violation = checkNaming(file, resolved.conventions);\n if (!violation) continue;\n\n const convention = getConventionValue(resolved.conventions.fileNaming);\n if (!convention) continue;\n\n const rename = computeRename(file, convention, projectRoot);\n if (rename) renames.push(rename);\n }\n }\n\n const dedupedRenames = deduplicateRenames(renames);\n\n // Compute test stubs\n const testStubs: TestStubRecord[] = [];\n if (shouldFixTests && config.rules.requireTests) {\n const testViolations = checkMissingTests(projectRoot, config, 'warn');\n for (const v of testViolations) {\n const stub = generateTestStub(v.file, config, projectRoot);\n if (stub) testStubs.push(stub);\n }\n }\n\n // Nothing to fix\n if (dedupedRenames.length === 0 && testStubs.length === 0) {\n console.log(`${chalk.green('✓')} No fixable violations found.`);\n return 0;\n }\n\n // Display plan\n printPlan(dedupedRenames, testStubs);\n\n if (options.dryRun) {\n console.log(chalk.dim('\\nDry run — no changes applied.'));\n return 0;\n }\n\n // Confirm\n if (!options.yes) {\n const confirmed = await promptConfirm('Apply these fixes?');\n if (!confirmed) {\n console.log('Aborted.');\n return 0;\n }\n }\n\n // Apply: 1. Renames\n let renameCount = 0;\n for (const rename of dedupedRenames) {\n if (executeRename(rename)) {\n renameCount++;\n }\n }\n\n // Apply: 2. Import updates\n let importUpdateCount = 0;\n if (renameCount > 0) {\n const appliedRenames = dedupedRenames.filter((r) => fs.existsSync(r.newAbsPath));\n const updates = await updateImportsAfterRenames(appliedRenames, projectRoot);\n importUpdateCount = updates.length;\n }\n\n // Apply: 3. Test stubs\n let stubCount = 0;\n for (const stub of testStubs) {\n if (!fs.existsSync(stub.absPath)) {\n writeTestStub(stub, config);\n stubCount++;\n }\n }\n\n // Summary\n console.log('');\n if (renameCount > 0) {\n console.log(`${chalk.green('✓')} Renamed ${renameCount} file${renameCount > 1 ? 's' : ''}`);\n }\n if (importUpdateCount > 0) {\n console.log(\n `${chalk.green('✓')} Updated ${importUpdateCount} import${importUpdateCount > 1 ? 's' : ''}`,\n );\n }\n if (stubCount > 0) {\n console.log(`${chalk.green('✓')} Generated ${stubCount} test stub${stubCount > 1 ? 's' : ''}`);\n }\n\n return 0;\n}\n","import { execSync } from 'node:child_process';\nimport { createInterface } from 'node:readline';\nimport chalk from 'chalk';\nimport type { RenameRecord } from './fix-naming.js';\nimport type { TestStubRecord } from './fix-tests.js';\n\n/**\n * Display the planned renames and test stubs.\n */\nexport function printPlan(renames: RenameRecord[], stubs: TestStubRecord[]): void {\n if (renames.length > 0) {\n console.log(chalk.bold('\\nFile renames:'));\n for (const r of renames) {\n console.log(` ${chalk.red(r.oldPath)} → ${chalk.green(r.newPath)}`);\n }\n }\n\n if (stubs.length > 0) {\n console.log(chalk.bold('\\nTest stubs to create:'));\n for (const s of stubs) {\n console.log(` ${chalk.green('+')} ${s.path}`);\n }\n }\n}\n\n/**\n * Check if the git working tree has uncommitted changes.\n */\nexport function checkGitDirty(projectRoot: string): boolean {\n try {\n const output = execSync('git status --porcelain', {\n cwd: projectRoot,\n encoding: 'utf-8',\n });\n return output.trim().length > 0;\n } catch {\n return false;\n }\n}\n\n/**\n * Extract the string value from a convention (which may be a string or an object with a value property).\n */\nexport function getConventionValue(convention: unknown): string | undefined {\n if (typeof convention === 'string') return convention;\n if (convention && typeof convention === 'object' && 'value' in convention) {\n return (convention as { value: string }).value;\n }\n return undefined;\n}\n\n/**\n * Prompt the user to confirm an action.\n */\nexport function promptConfirm(question: string): Promise<boolean> {\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n return new Promise((resolve) => {\n rl.question(`${question} (y/N) `, (answer) => {\n rl.close();\n resolve(answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes');\n });\n });\n}\n","import * as path from 'node:path';\nimport type { RenameRecord } from './fix-naming.js';\n\nexport interface ImportUpdateRecord {\n file: string;\n oldSpecifier: string;\n newSpecifier: string;\n line: number;\n}\n\n/**\n * Strip known JS/TS extensions from a file path for specifier comparison.\n * E.g. \"/foo/bar.ts\" → \"/foo/bar\", \"/foo/bar.js\" → \"/foo/bar\"\n */\nfunction stripExtension(filePath: string): string {\n return filePath.replace(/\\.(tsx?|jsx?|mjs|cjs)$/, '');\n}\n\n/**\n * Compute the new import specifier given the old specifier and the rename.\n * Preserves `.js` suffix if present.\n */\nfunction computeNewSpecifier(oldSpecifier: string, newBare: string): string {\n const hasJsExt = oldSpecifier.endsWith('.js');\n const base = hasJsExt ? oldSpecifier.slice(0, -3) : oldSpecifier;\n\n // Replace the last path segment\n const dir = base.lastIndexOf('/');\n const prefix = dir >= 0 ? base.slice(0, dir + 1) : '';\n const newSpec = prefix + newBare;\n\n return hasJsExt ? `${newSpec}.js` : newSpec;\n}\n\n/**\n * Update import specifiers in all source files after renames.\n * Uses ts-morph for AST-accurate rewriting.\n *\n * @param renames - The renames that were applied\n * @param projectRoot - Absolute path to project root\n * @returns Records of all import updates made\n */\nexport async function updateImportsAfterRenames(\n renames: RenameRecord[],\n projectRoot: string,\n): Promise<ImportUpdateRecord[]> {\n if (renames.length === 0) return [];\n\n // Lazy import ts-morph to avoid startup cost\n const { Project, SyntaxKind } = await import('ts-morph');\n\n // Build rename map: stripped old abs path → { newBare }\n const renameMap = new Map<string, { newBare: string }>();\n for (const r of renames) {\n const oldStripped = stripExtension(r.oldAbsPath);\n const newFilename = path.basename(r.newPath);\n const newName = newFilename.slice(0, newFilename.indexOf('.'));\n renameMap.set(oldStripped, { newBare: newName });\n }\n\n const project = new Project({\n tsConfigFilePath: undefined,\n skipAddingFilesFromTsConfig: true,\n });\n\n // Add all TS/JS source files\n project.addSourceFilesAtPaths(path.join(projectRoot, '**/*.{ts,tsx,js,jsx,mjs,cjs}'));\n\n const updates: ImportUpdateRecord[] = [];\n const extensions = ['', '.ts', '.tsx', '.js', '.jsx', '/index.ts', '/index.tsx', '/index.js'];\n\n for (const sourceFile of project.getSourceFiles()) {\n const filePath = sourceFile.getFilePath();\n // Skip node_modules and dist\n if (filePath.includes('/node_modules/') || filePath.includes('/dist/')) continue;\n\n const fileDir = path.dirname(filePath);\n\n // Process static imports\n for (const decl of sourceFile.getImportDeclarations()) {\n const specifier = decl.getModuleSpecifierValue();\n if (!specifier.startsWith('.')) continue;\n\n const match = resolveToRenamedFile(specifier, fileDir, renameMap, extensions);\n if (!match) continue;\n\n const newSpec = computeNewSpecifier(specifier, match.newBare);\n updates.push({\n file: filePath,\n oldSpecifier: specifier,\n newSpecifier: newSpec,\n line: decl.getStartLineNumber(),\n });\n decl.setModuleSpecifier(newSpec);\n }\n\n // Process re-exports\n for (const decl of sourceFile.getExportDeclarations()) {\n const specifier = decl.getModuleSpecifierValue();\n if (!specifier || !specifier.startsWith('.')) continue;\n\n const match = resolveToRenamedFile(specifier, fileDir, renameMap, extensions);\n if (!match) continue;\n\n const newSpec = computeNewSpecifier(specifier, match.newBare);\n updates.push({\n file: filePath,\n oldSpecifier: specifier,\n newSpecifier: newSpec,\n line: decl.getStartLineNumber(),\n });\n decl.setModuleSpecifier(newSpec);\n }\n\n // Process dynamic imports\n for (const call of sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression)) {\n if (call.getExpression().getKind() !== SyntaxKind.ImportKeyword) continue;\n\n const args = call.getArguments();\n if (args.length === 0) continue;\n\n const arg = args[0];\n if (arg.getKind() !== SyntaxKind.StringLiteral) continue;\n\n const specifier = arg.getText().slice(1, -1);\n if (!specifier.startsWith('.')) continue;\n\n const match = resolveToRenamedFile(specifier, fileDir, renameMap, extensions);\n if (!match) continue;\n\n const newSpec = computeNewSpecifier(specifier, match.newBare);\n updates.push({\n file: filePath,\n oldSpecifier: specifier,\n newSpecifier: newSpec,\n line: call.getStartLineNumber(),\n });\n // Replace the string literal content\n const quote = arg.getText()[0];\n arg.replaceWithText(`${quote}${newSpec}${quote}`);\n }\n }\n\n if (updates.length > 0) {\n await project.save();\n }\n\n return updates;\n}\n\n/**\n * Try to resolve a relative specifier to a renamed file.\n * Returns the rename info if matched, undefined otherwise.\n */\nfunction resolveToRenamedFile(\n specifier: string,\n fromDir: string,\n renameMap: Map<string, { newBare: string }>,\n extensions: string[],\n): { newBare: string } | undefined {\n // Strip .js extension for resolution (TypeScript convention)\n const cleanSpec = specifier.endsWith('.js') ? specifier.slice(0, -3) : specifier;\n const resolved = path.resolve(fromDir, cleanSpec);\n\n for (const ext of extensions) {\n const candidate = resolved + ext;\n const stripped = stripExtension(candidate);\n const match = renameMap.get(stripped);\n if (match) return match;\n }\n\n return undefined;\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { convertName } from './convert-name.js';\n\nexport interface RenameRecord {\n oldPath: string;\n newPath: string;\n oldAbsPath: string;\n newAbsPath: string;\n}\n\n/**\n * Compute the rename for a file that violates the naming convention.\n * Returns null if no rename is needed or the target already exists.\n */\nexport function computeRename(\n relPath: string,\n targetConvention: string,\n projectRoot: string,\n): RenameRecord | null {\n const filename = path.basename(relPath);\n const dir = path.dirname(relPath);\n\n // Extract bare name (before first dot) — matches checkNaming logic\n const dotIndex = filename.indexOf('.');\n if (dotIndex === -1) return null;\n\n const bare = filename.slice(0, dotIndex);\n const suffix = filename.slice(dotIndex); // e.g. \".tsx\" or \".test.ts\"\n\n const newBare = convertName(bare, targetConvention);\n if (newBare === bare) return null;\n\n const newFilename = newBare + suffix;\n const newRelPath = path.join(dir, newFilename);\n const oldAbsPath = path.join(projectRoot, relPath);\n const newAbsPath = path.join(projectRoot, newRelPath);\n\n // Skip if target already exists\n if (fs.existsSync(newAbsPath)) return null;\n\n return { oldPath: relPath, newPath: newRelPath, oldAbsPath, newAbsPath };\n}\n\n/**\n * Execute a single rename on disk.\n * Returns true if successful, false if skipped (target exists).\n */\nexport function executeRename(rename: RenameRecord): boolean {\n if (fs.existsSync(rename.newAbsPath)) return false;\n fs.renameSync(rename.oldAbsPath, rename.newAbsPath);\n return true;\n}\n\n/**\n * Detect and deduplicate rename collisions.\n * If two planned renames target the same path, the second is removed.\n */\nexport function deduplicateRenames(renames: RenameRecord[]): RenameRecord[] {\n const seen = new Set<string>();\n const result: RenameRecord[] = [];\n for (const r of renames) {\n if (seen.has(r.newAbsPath)) continue;\n seen.add(r.newAbsPath);\n result.push(r);\n }\n return result;\n}\n","/**\n * Split a bare filename into its constituent words.\n *\n * Handles kebab-case, camelCase, PascalCase, and snake_case inputs.\n * Consecutive uppercase letters (acronyms like \"URL\") are kept together.\n */\nexport function splitIntoWords(name: string): string[] {\n // First, split on explicit separators (hyphens and underscores)\n const parts = name.split(/[-_]/);\n\n const words: string[] = [];\n for (const part of parts) {\n if (part === '') continue;\n\n // Split camelCase and PascalCase boundaries\n // \"UserProfile\" → [\"User\", \"Profile\"]\n // \"parseJSON\" → [\"parse\", \"JSON\"]\n // \"XMLParser\" → [\"XML\", \"Parser\"]\n let current = '';\n for (let i = 0; i < part.length; i++) {\n const ch = part[i];\n const isUpper = ch >= 'A' && ch <= 'Z';\n\n if (isUpper && current.length > 0) {\n const prevIsUpper =\n current[current.length - 1] >= 'A' && current[current.length - 1] <= 'Z';\n const nextIsLower = i + 1 < part.length && part[i + 1] >= 'a' && part[i + 1] <= 'z';\n\n if (!prevIsUpper || nextIsLower) {\n words.push(current.toLowerCase());\n current = '';\n }\n }\n current += ch;\n }\n if (current) words.push(current.toLowerCase());\n }\n\n return words;\n}\n\n/**\n * Convert a bare filename to the specified naming convention.\n *\n * @param bare - The bare filename without extension (e.g. \"UserProfile\")\n * @param target - The target convention (kebab-case, camelCase, PascalCase, snake_case)\n * @returns The converted name\n */\nexport function convertName(bare: string, target: string): string {\n const words = splitIntoWords(bare);\n if (words.length === 0) return bare;\n\n switch (target) {\n case 'kebab-case':\n return words.join('-');\n case 'camelCase':\n return words[0] + words.slice(1).map(capitalize).join('');\n case 'PascalCase':\n return words.map(capitalize).join('');\n case 'snake_case':\n return words.join('_');\n default:\n return bare;\n }\n}\n\nfunction capitalize(word: string): string {\n if (word.length === 0) return word;\n return word[0].toUpperCase() + word.slice(1);\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { ViberailsConfig } from '@viberails/types';\n\nexport interface TestStubRecord {\n path: string;\n absPath: string;\n moduleName: string;\n}\n\n/**\n * Generate a test stub record for a source file that is missing tests.\n * Returns null if the test file already exists.\n */\nexport function generateTestStub(\n sourceRelPath: string,\n config: ViberailsConfig,\n projectRoot: string,\n): TestStubRecord | null {\n const { testPattern } = config.structure;\n if (!testPattern) return null;\n\n const basename = path.basename(sourceRelPath);\n const stem = basename.slice(0, basename.indexOf('.'));\n const testSuffix = testPattern.replace('*', '');\n const testFilename = `${stem}${testSuffix}`;\n\n const dir = path.dirname(path.join(projectRoot, sourceRelPath));\n const testAbsPath = path.join(dir, testFilename);\n\n if (fs.existsSync(testAbsPath)) return null;\n\n return {\n path: path.relative(projectRoot, testAbsPath),\n absPath: testAbsPath,\n moduleName: stem,\n };\n}\n\n/**\n * Write a test stub file to disk.\n */\nexport function writeTestStub(stub: TestStubRecord, config: ViberailsConfig): void {\n const runner = config.stack.testRunner === 'jest' ? 'jest' : 'vitest';\n const importLine =\n runner === 'jest'\n ? '' // jest globals are available without import\n : \"import { describe, it, expect } from 'vitest';\\n\\n\";\n\n const content = `${importLine}describe('${stub.moduleName}', () => {\\n it.todo('add tests');\\n});\\n`;\n\n fs.mkdirSync(path.dirname(stub.absPath), { recursive: true });\n fs.writeFileSync(stub.absPath, content);\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { generateConfig } from '@viberails/config';\nimport { scan } from '@viberails/scanner';\nimport type { ConfigConventions, ConventionValue } from '@viberails/types';\nimport chalk from 'chalk';\nimport { displayScanResults } from '../display.js';\nimport { findProjectRoot } from '../utils/find-project-root.js';\nimport { confirm } from '../utils/prompt.js';\nimport { resolveWorkspacePackages } from '../utils/resolve-workspace-packages.js';\nimport { writeGeneratedFiles } from '../utils/write-generated-files.js';\nimport { setupPreCommitHook } from './init-hooks.js';\n\nconst CONFIG_FILE = 'viberails.config.json';\n\n/**\n * Filter a ConfigConventions object to only include high-confidence entries.\n */\nfunction filterHighConfidence(conventions: ConfigConventions): ConfigConventions {\n const filtered: ConfigConventions = {};\n for (const [key, value] of Object.entries(conventions)) {\n if (value === undefined) continue;\n if (typeof value === 'string') {\n filtered[key as keyof ConfigConventions] = value;\n } else if (value._confidence === 'high') {\n filtered[key as keyof ConfigConventions] = value as ConventionValue;\n }\n }\n return filtered;\n}\n\n/**\n * Run the viberails init flow.\n *\n * @param options - CLI options\n * @param cwd - Working directory override (for testing)\n */\nexport async function initCommand(options: { yes?: boolean }, cwd?: string): Promise<void> {\n const startDir = cwd ?? process.cwd();\n\n // 1. Find project root\n const projectRoot = findProjectRoot(startDir);\n if (!projectRoot) {\n throw new Error(\n 'No package.json found in this directory or any parent.\\n\\n' +\n 'Make sure you are inside a JavaScript or TypeScript project, then run:\\n' +\n ' npx viberails',\n );\n }\n\n // 2. Check for existing config\n const configPath = path.join(projectRoot, CONFIG_FILE);\n if (fs.existsSync(configPath)) {\n console.log(\n chalk.yellow('!') +\n ' viberails is already initialized in this project.\\n' +\n ' Run ' +\n chalk.cyan('viberails sync') +\n ' to update the generated files.',\n );\n return;\n }\n\n // 3. Run scanner\n console.log(chalk.dim('Scanning project...'));\n const scanResult = await scan(projectRoot);\n\n // 4. Display results\n displayScanResults(scanResult);\n\n // 5. Sparse project notice\n if (scanResult.statistics.totalFiles === 0) {\n console.log(\n chalk.yellow('!') +\n ' No source files detected. viberails will generate context with minimal content.\\n' +\n ' Run ' +\n chalk.cyan('viberails sync') +\n ' after adding source files.\\n',\n );\n }\n\n // 6. Interactive confirmation\n if (!options.yes) {\n const accepted = await confirm('Does this look right?');\n if (!accepted) {\n console.log('Aborted.');\n return;\n }\n }\n\n // 7. Generate config\n const config = generateConfig(scanResult);\n if (options.yes) {\n config.conventions = filterHighConfidence(config.conventions);\n }\n\n // 7b. Infer boundary rules for workspace projects\n if (config.workspace && config.workspace.packages.length > 0) {\n let shouldInfer = options.yes;\n if (!options.yes) {\n shouldInfer = await confirm('Infer boundary rules from import patterns?');\n }\n\n if (shouldInfer) {\n console.log(chalk.dim('Building import graph...'));\n const { buildImportGraph, inferBoundaries } = await import('@viberails/graph');\n const packages = resolveWorkspacePackages(projectRoot, config.workspace);\n const graph = await buildImportGraph(projectRoot, { packages, ignore: config.ignore });\n const inferred = inferBoundaries(graph);\n if (inferred.length > 0) {\n config.boundaries = inferred;\n config.rules.enforceBoundaries = true;\n console.log(` ${chalk.green('✓')} Inferred ${inferred.length} boundary rules`);\n }\n }\n }\n\n fs.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\\n`);\n\n // 8. Generate context and scan-result.json\n writeGeneratedFiles(projectRoot, config, scanResult);\n\n // 9. Update .gitignore\n updateGitignore(projectRoot);\n\n // 10. Set up pre-commit hook\n setupPreCommitHook(projectRoot);\n\n // 11. Print summary\n console.log(`\\n${chalk.bold('Created:')}`);\n console.log(` ${chalk.green('✓')} ${CONFIG_FILE}`);\n console.log(` ${chalk.green('✓')} .viberails/context.md`);\n console.log(` ${chalk.green('✓')} .viberails/scan-result.json`);\n console.log(`\\n${chalk.bold('Next steps:')}`);\n console.log(` 1. Review ${chalk.cyan('viberails.config.json')} and adjust rules`);\n console.log(\n ` 2. Commit ${chalk.cyan('viberails.config.json')} and ${chalk.cyan('.viberails/context.md')}`,\n );\n console.log(` 3. Run ${chalk.cyan('viberails check')} to verify your project passes`);\n}\n\n/**\n * Append viberails entries to .gitignore if not already present.\n * Only scan-result.json is ignored — context.md should be committed\n * so AI agents can read the enforced rules.\n */\nfunction updateGitignore(projectRoot: string): void {\n const gitignorePath = path.join(projectRoot, '.gitignore');\n let content = '';\n\n if (fs.existsSync(gitignorePath)) {\n content = fs.readFileSync(gitignorePath, 'utf-8');\n }\n\n if (!content.includes('.viberails/scan-result.json')) {\n const block = '\\n# viberails\\n.viberails/scan-result.json\\n';\n fs.writeFileSync(gitignorePath, `${content.trimEnd()}\\n${block}`);\n }\n}\n","import type { DetectedConvention, ScanResult, StackItem } from '@viberails/types';\nimport { FRAMEWORK_NAMES, LIBRARY_NAMES, STYLING_NAMES } from '@viberails/types';\nimport chalk from 'chalk';\nimport {\n formatExtensions,\n formatRoleGroup,\n formatSummary,\n groupByRole,\n} from './display-helpers.js';\nimport { displayMonorepoResults } from './display-monorepo.js';\n\n/** Labels for convention keys. */\nconst CONVENTION_LABELS: Record<string, string> = {\n fileNaming: 'File naming',\n componentNaming: 'Component naming',\n hookNaming: 'Hook naming',\n importAlias: 'Import alias',\n};\n\n/**\n * Format a StackItem for display: \"DisplayName Version\".\n */\nexport function formatItem(item: StackItem, nameMap?: Record<string, string>): string {\n const name = nameMap?.[item.name] ?? item.name;\n return item.version ? `${name} ${item.version}` : name;\n}\n\n/**\n * Format a confidence label for display.\n */\nexport function confidenceLabel(convention: DetectedConvention): string {\n const pct = Math.round(convention.consistency);\n if (convention.confidence === 'high') {\n return `${pct}% — high confidence, will enforce`;\n }\n return `${pct}% — medium confidence, suggested only`;\n}\n\n/**\n * Display conventions section, shared between single-package and monorepo.\n */\nexport function displayConventions(scanResult: ScanResult): void {\n const conventionEntries = Object.entries(scanResult.conventions);\n if (conventionEntries.length === 0) return;\n\n console.log(`\\n${chalk.bold('Conventions:')}`);\n for (const [key, convention] of conventionEntries) {\n if (convention.confidence === 'low') continue;\n const label = CONVENTION_LABELS[key] ?? key;\n\n if (scanResult.packages.length > 1) {\n const pkgValues = scanResult.packages\n .filter((pkg) => pkg.conventions[key] && pkg.conventions[key].confidence !== 'low')\n .map((pkg) => ({ relativePath: pkg.relativePath, convention: pkg.conventions[key] }));\n\n const allSame = pkgValues.every((pv) => pv.convention.value === convention.value);\n\n if (allSame || pkgValues.length <= 1) {\n const ind = convention.confidence === 'high' ? chalk.green('✓') : chalk.yellow('~');\n const detail = chalk.dim(`(${confidenceLabel(convention)})`);\n console.log(` ${ind} ${label}: ${convention.value} ${detail}`);\n } else {\n console.log(` ${chalk.yellow('~')} ${label}: varies by package`);\n for (const pv of pkgValues) {\n const pct = Math.round(pv.convention.consistency);\n console.log(` ${pv.relativePath}: ${pv.convention.value} (${pct}%)`);\n }\n }\n } else {\n const ind = convention.confidence === 'high' ? chalk.green('✓') : chalk.yellow('~');\n const detail = chalk.dim(`(${confidenceLabel(convention)})`);\n console.log(` ${ind} ${label}: ${convention.value} ${detail}`);\n }\n }\n}\n\n/**\n * Display summary section with statistics.\n */\nexport function displaySummarySection(scanResult: ScanResult): void {\n const pkgCount = scanResult.packages.length > 1 ? scanResult.packages.length : undefined;\n console.log(`\\n${chalk.bold('Summary:')}`);\n console.log(` ${formatSummary(scanResult.statistics, pkgCount)}`);\n const ext = formatExtensions(scanResult.statistics.filesByExtension);\n if (ext) {\n console.log(` ${ext}`);\n }\n}\n\n/**\n * Display scan results to the console with confidence indicators.\n *\n * @param scanResult - The scan result to display\n */\nexport function displayScanResults(scanResult: ScanResult): void {\n if (scanResult.packages.length > 1) {\n displayMonorepoResults(scanResult);\n return;\n }\n\n const { stack } = scanResult;\n\n console.log(`\\n${chalk.bold('Detected:')}`);\n\n if (stack.framework) {\n console.log(` ${chalk.green('✓')} ${formatItem(stack.framework, FRAMEWORK_NAMES)}`);\n }\n console.log(` ${chalk.green('✓')} ${formatItem(stack.language)}`);\n if (stack.styling) {\n console.log(` ${chalk.green('✓')} ${formatItem(stack.styling, STYLING_NAMES)}`);\n }\n if (stack.backend) {\n console.log(` ${chalk.green('✓')} ${formatItem(stack.backend, FRAMEWORK_NAMES)}`);\n }\n if (stack.linter) {\n console.log(` ${chalk.green('✓')} ${formatItem(stack.linter)}`);\n }\n if (stack.formatter) {\n console.log(` ${chalk.green('✓')} ${formatItem(stack.formatter)}`);\n }\n if (stack.testRunner) {\n console.log(` ${chalk.green('✓')} ${formatItem(stack.testRunner)}`);\n }\n if (stack.packageManager) {\n console.log(` ${chalk.green('✓')} ${formatItem(stack.packageManager)}`);\n }\n if (stack.libraries.length > 0) {\n for (const lib of stack.libraries) {\n console.log(` ${chalk.green('✓')} ${formatItem(lib, LIBRARY_NAMES)}`);\n }\n }\n\n // Structure grouped by role\n const groups = groupByRole(scanResult.structure.directories);\n if (groups.length > 0) {\n console.log(`\\n${chalk.bold('Structure:')}`);\n for (const group of groups) {\n console.log(` ${chalk.green('✓')} ${formatRoleGroup(group)}`);\n }\n }\n\n displayConventions(scanResult);\n displaySummarySection(scanResult);\n console.log('');\n}\n","import type { CodebaseStatistics, DirectoryInfo, DirectoryRole } from '@viberails/types';\nimport { ROLE_DESCRIPTIONS } from '@viberails/types';\n\n/**\n * A group of directories sharing the same role within a package.\n */\nexport interface RoleGroup {\n role: DirectoryRole;\n label: string;\n dirCount: number;\n totalFiles: number;\n singlePath?: string;\n}\n\n/**\n * Groups a package's directories by role, merging file counts.\n * Filters out `unknown` role. For single-directory roles, sets `singlePath`.\n *\n * @param directories - The directories to group.\n * @returns Array of RoleGroup entries sorted by role label.\n */\nexport function groupByRole(directories: DirectoryInfo[]): RoleGroup[] {\n const map = new Map<DirectoryRole, { dirs: DirectoryInfo[] }>();\n\n for (const dir of directories) {\n if (dir.role === 'unknown') continue;\n const existing = map.get(dir.role);\n if (existing) {\n existing.dirs.push(dir);\n } else {\n map.set(dir.role, { dirs: [dir] });\n }\n }\n\n const groups: RoleGroup[] = [];\n for (const [role, { dirs }] of map) {\n const label = ROLE_DESCRIPTIONS[role] ?? role;\n const totalFiles = dirs.reduce((sum, d) => sum + d.fileCount, 0);\n groups.push({\n role,\n label,\n dirCount: dirs.length,\n totalFiles,\n singlePath: dirs.length === 1 ? dirs[0].path : undefined,\n });\n }\n\n return groups;\n}\n\n/**\n * Format a summary line from CodebaseStatistics.\n *\n * @param stats - The codebase statistics.\n * @param packageCount - Number of packages (shown for monorepos with > 1).\n * @returns Formatted summary string, e.g. \"3 packages · 743 source files · 48,200 lines · avg 65 lines/file\"\n */\nexport function formatSummary(stats: CodebaseStatistics, packageCount?: number): string {\n const parts: string[] = [];\n if (packageCount && packageCount > 1) {\n parts.push(`${packageCount} packages`);\n }\n parts.push(`${stats.totalFiles.toLocaleString()} source files`);\n parts.push(`${stats.totalLines.toLocaleString()} lines`);\n parts.push(`avg ${Math.round(stats.averageFileLines)} lines/file`);\n return parts.join(' \\u00b7 ');\n}\n\n/**\n * Format top extensions by count, e.g. \".tsx 312 · .ts 289 · .js 142\".\n *\n * @param filesByExtension - Extension counts from CodebaseStatistics.\n * @param maxEntries - Maximum number of extensions to show (default 4).\n * @returns Formatted extension string.\n */\nexport function formatExtensions(\n filesByExtension: Record<string, number>,\n maxEntries: number = 4,\n): string {\n return Object.entries(filesByExtension)\n .sort(([, a], [, b]) => b - a)\n .slice(0, maxEntries)\n .map(([ext, count]) => `${ext} ${count}`)\n .join(' \\u00b7 ');\n}\n\n/**\n * Format a RoleGroup for display.\n *\n * @param group - The role group.\n * @returns Formatted string, e.g. \"Hooks — 4 dirs (55 files)\" or \"Pages / Routes — app (12 files)\"\n */\nexport function formatRoleGroup(group: RoleGroup): string {\n const files = group.totalFiles === 1 ? '1 file' : `${group.totalFiles} files`;\n if (group.singlePath) {\n return `${group.label} — ${group.singlePath} (${files})`;\n }\n const dirs = group.dirCount === 1 ? '1 dir' : `${group.dirCount} dirs`;\n return `${group.label} — ${dirs} (${files})`;\n}\n","import type { PackageScanResult, ScanResult } from '@viberails/types';\nimport { FRAMEWORK_NAMES, STYLING_NAMES } from '@viberails/types';\nimport chalk from 'chalk';\nimport { displayConventions, displaySummarySection, formatItem } from './display.js';\nimport { formatRoleGroup, groupByRole } from './display-helpers.js';\n\n/**\n * Format a package summary line for monorepo display.\n */\nexport function formatPackageSummary(pkg: PackageScanResult): string {\n const parts: string[] = [];\n if (pkg.stack.framework) {\n parts.push(formatItem(pkg.stack.framework, FRAMEWORK_NAMES));\n }\n if (pkg.stack.styling) {\n parts.push(formatItem(pkg.stack.styling, STYLING_NAMES));\n }\n const files = `${pkg.statistics.totalFiles} files`;\n const detail = parts.length > 0 ? `${parts.join(', ')} (${files})` : `(${files})`;\n return ` ${pkg.relativePath} — ${detail}`;\n}\n\n/**\n * Display scan results for a monorepo with per-package summaries.\n */\nexport function displayMonorepoResults(scanResult: ScanResult): void {\n const { stack, packages } = scanResult;\n\n console.log(`\\n${chalk.bold(`Detected: (monorepo, ${packages.length} packages)`)}`);\n\n // Shared stack items at the top\n console.log(` ${chalk.green('✓')} ${formatItem(stack.language)}`);\n if (stack.packageManager) {\n console.log(` ${chalk.green('✓')} ${formatItem(stack.packageManager)}`);\n }\n if (stack.linter) {\n console.log(` ${chalk.green('✓')} ${formatItem(stack.linter)}`);\n }\n if (stack.formatter) {\n console.log(` ${chalk.green('✓')} ${formatItem(stack.formatter)}`);\n }\n if (stack.testRunner) {\n console.log(` ${chalk.green('✓')} ${formatItem(stack.testRunner)}`);\n }\n\n // Per-package summaries\n console.log('');\n for (const pkg of packages) {\n console.log(formatPackageSummary(pkg));\n }\n\n // Structure grouped by role per package\n const packagesWithDirs = packages.filter((pkg) =>\n pkg.structure.directories.some((d) => d.role !== 'unknown'),\n );\n if (packagesWithDirs.length > 0) {\n console.log(`\\n${chalk.bold('Structure:')}`);\n for (const pkg of packagesWithDirs) {\n const groups = groupByRole(pkg.structure.directories);\n if (groups.length === 0) continue;\n console.log(` ${pkg.relativePath}:`);\n for (const group of groups) {\n console.log(` ${chalk.green('✓')} ${formatRoleGroup(group)}`);\n }\n }\n }\n\n displayConventions(scanResult);\n displaySummarySection(scanResult);\n console.log('');\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { generateContext } from '@viberails/context';\nimport type { ScanResult, ViberailsConfig } from '@viberails/types';\n\nconst CONTEXT_DIR = '.viberails';\nconst CONTEXT_FILE = 'context.md';\nconst SCAN_RESULT_FILE = 'scan-result.json';\n\n/**\n * Write all generated files: context.md and scan-result.json.\n *\n * @param projectRoot - Absolute path to the project root\n * @param config - The viberails configuration\n * @param scanResult - The raw scan result\n */\nexport function writeGeneratedFiles(\n projectRoot: string,\n config: ViberailsConfig,\n scanResult: ScanResult,\n): void {\n const contextDir = path.join(projectRoot, CONTEXT_DIR);\n\n try {\n if (!fs.existsSync(contextDir)) {\n fs.mkdirSync(contextDir, { recursive: true });\n }\n\n const context = generateContext(config);\n fs.writeFileSync(path.join(contextDir, CONTEXT_FILE), context);\n\n fs.writeFileSync(\n path.join(contextDir, SCAN_RESULT_FILE),\n `${JSON.stringify(scanResult, null, 2)}\\n`,\n );\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n throw new Error(`Failed to write generated files to ${contextDir}: ${message}`);\n }\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport chalk from 'chalk';\n\n/**\n * Set up a pre-commit hook that runs viberails check on staged files.\n * Detects Lefthook, Husky, or falls back to a raw git hook.\n */\nexport function setupPreCommitHook(projectRoot: string): void {\n // Check for Lefthook\n const lefthookPath = path.join(projectRoot, 'lefthook.yml');\n if (fs.existsSync(lefthookPath)) {\n addLefthookPreCommit(lefthookPath);\n console.log(` ${chalk.green('✓')} lefthook.yml — added viberails pre-commit`);\n return;\n }\n\n // Check for Husky\n const huskyDir = path.join(projectRoot, '.husky');\n if (fs.existsSync(huskyDir)) {\n writeHuskyPreCommit(huskyDir);\n console.log(` ${chalk.green('✓')} .husky/pre-commit — added viberails check`);\n return;\n }\n\n // Fall back to raw git hook\n const gitDir = path.join(projectRoot, '.git');\n if (fs.existsSync(gitDir)) {\n const hooksDir = path.join(gitDir, 'hooks');\n if (!fs.existsSync(hooksDir)) {\n fs.mkdirSync(hooksDir, { recursive: true });\n }\n writeGitHookPreCommit(hooksDir);\n console.log(` ${chalk.green('✓')} .git/hooks/pre-commit`);\n }\n}\n\nfunction writeGitHookPreCommit(hooksDir: string): void {\n const hookPath = path.join(hooksDir, 'pre-commit');\n if (fs.existsSync(hookPath)) {\n const existing = fs.readFileSync(hookPath, 'utf-8');\n if (existing.includes('viberails')) return;\n fs.writeFileSync(\n hookPath,\n `${existing.trimEnd()}\\n\\n# viberails check\\nnpx viberails check --staged\\n`,\n );\n return;\n }\n const script = [\n '#!/bin/sh',\n '# Generated by viberails — https://viberails.sh',\n '',\n 'npx viberails check --staged',\n '',\n ].join('\\n');\n fs.writeFileSync(hookPath, script, { mode: 0o755 });\n}\n\nfunction addLefthookPreCommit(lefthookPath: string): void {\n const content = fs.readFileSync(lefthookPath, 'utf-8');\n if (content.includes('viberails')) return;\n const addition = ['', ' viberails:', ' run: npx viberails check --staged'].join('\\n');\n fs.writeFileSync(lefthookPath, `${content.trimEnd()}\\n${addition}\\n`);\n}\n\nfunction writeHuskyPreCommit(huskyDir: string): void {\n const hookPath = path.join(huskyDir, 'pre-commit');\n if (fs.existsSync(hookPath)) {\n const existing = fs.readFileSync(hookPath, 'utf-8');\n if (!existing.includes('viberails')) {\n fs.writeFileSync(hookPath, `${existing.trimEnd()}\\nnpx viberails check --staged\\n`);\n }\n return;\n }\n fs.writeFileSync(hookPath, '#!/bin/sh\\nnpx viberails check --staged\\n', { mode: 0o755 });\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { loadConfig, mergeConfig } from '@viberails/config';\nimport { scan } from '@viberails/scanner';\nimport chalk from 'chalk';\nimport { findProjectRoot } from '../utils/find-project-root.js';\nimport { writeGeneratedFiles } from '../utils/write-generated-files.js';\n\nconst CONFIG_FILE = 'viberails.config.json';\n\n/**\n * Run the viberails sync flow: re-scan, merge config, regenerate context.\n *\n * @param cwd - Working directory override (for testing)\n */\nexport async function syncCommand(cwd?: string): Promise<void> {\n const startDir = cwd ?? process.cwd();\n\n // 1. Find project root\n const projectRoot = findProjectRoot(startDir);\n if (!projectRoot) {\n throw new Error(\n 'No package.json found in this directory or any parent.\\n\\n' +\n 'Make sure you are inside a JavaScript or TypeScript project, then run:\\n' +\n ' npx viberails',\n );\n }\n\n // 2. Load existing config\n const configPath = path.join(projectRoot, CONFIG_FILE);\n const existing = await loadConfig(configPath);\n\n // 3. Re-scan\n console.log(chalk.dim('Scanning project...'));\n const scanResult = await scan(projectRoot);\n\n // 4. Merge config\n const merged = mergeConfig(existing, scanResult);\n fs.writeFileSync(configPath, `${JSON.stringify(merged, null, 2)}\\n`);\n\n // 5. Regenerate context and scan-result.json\n writeGeneratedFiles(projectRoot, merged, scanResult);\n\n console.log(`\\n${chalk.bold('Synced:')}`);\n console.log(` ${chalk.green('✓')} ${CONFIG_FILE} — updated`);\n console.log(` ${chalk.green('✓')} .viberails/context.md — regenerated`);\n console.log(` ${chalk.green('✓')} .viberails/scan-result.json — updated`);\n}\n"],"mappings":"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","names":["chalk","fs","path","resolve","fs","path","fs","path","loadConfig","chalk","fs","path","fs","path","SOURCE_EXTS","basename","CONFIG_FILE","chalk","loadConfig","fs","path","loadConfig","chalk","execSync","createInterface","chalk","resolve","path","fs","path","fs","path","basename","CONFIG_FILE","chalk","loadConfig","fs","path","chalk","FRAMEWORK_NAMES","STYLING_NAMES","chalk","chalk","chalk","chalk","FRAMEWORK_NAMES","STYLING_NAMES","fs","path","fs","path","chalk","CONFIG_FILE","chalk","fs","path","loadConfig","scan","chalk","CONFIG_FILE","loadConfig","chalk","scan","chalk"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "viberails",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "CLI tool for scanning JS/TS projects and generating AI context",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -28,11 +28,11 @@
|
|
|
28
28
|
"chalk": "^5.6.2",
|
|
29
29
|
"commander": "^14.0.3",
|
|
30
30
|
"ts-morph": "^27.0.2",
|
|
31
|
-
"@viberails/config": "0.2.
|
|
32
|
-
"@viberails/context": "0.2.
|
|
33
|
-
"@viberails/graph": "0.2.
|
|
34
|
-
"@viberails/scanner": "0.2.
|
|
35
|
-
"@viberails/types": "0.2.
|
|
31
|
+
"@viberails/config": "0.2.2",
|
|
32
|
+
"@viberails/context": "0.2.2",
|
|
33
|
+
"@viberails/graph": "0.2.2",
|
|
34
|
+
"@viberails/scanner": "0.2.2",
|
|
35
|
+
"@viberails/types": "0.2.2"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"@types/node": "^25.3.5"
|