@solid-stack/mason 1.0.22 → 1.0.23

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.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import fs4 from 'fs';
2
2
  import path2 from 'path';
3
3
  import * as p14 from '@clack/prompts';
4
- import pc15 from 'picocolors';
4
+ import pc14 from 'picocolors';
5
5
  import { fileURLToPath } from 'url';
6
6
  import { execSync } from 'child_process';
7
7
  import { createHash } from 'crypto';
@@ -112,17 +112,17 @@ function writeFileSafely(absolutePath, content, options = {}) {
112
112
  function printGeneratedFiles(files, isDryRun = false) {
113
113
  console.log("");
114
114
  if (isDryRun) {
115
- p14.log.warn(pc15.yellow(pc15.bold("[DRY RUN PREVIEW] No files were written to disk.")));
115
+ p14.log.warn(pc14.yellow(pc14.bold("[DRY RUN PREVIEW] No files were written to disk.")));
116
116
  }
117
117
  for (const f of files) {
118
118
  if (f.action === "created") {
119
- p14.log.success(`${pc15.bold(f.relativePath)} ${pc15.dim("(created)")}`);
119
+ p14.log.success(`${pc14.bold(f.relativePath)} ${pc14.dim("(created)")}`);
120
120
  } else if (f.action === "overwritten") {
121
- p14.log.warn(`${pc15.bold(f.relativePath)} ${pc15.dim("(overwritten)")}`);
121
+ p14.log.warn(`${pc14.bold(f.relativePath)} ${pc14.dim("(overwritten)")}`);
122
122
  } else if (f.action === "skipped") {
123
- p14.log.info(`${pc15.dim(f.relativePath)} ${pc15.dim("(skipped - already exists, pass -o to overwrite)")}`);
123
+ p14.log.info(`${pc14.dim(f.relativePath)} ${pc14.dim("(skipped - already exists, pass -o to overwrite)")}`);
124
124
  } else {
125
- p14.log.info(`${pc15.bold(f.relativePath)} ${pc15.dim("(preview)")}`);
125
+ p14.log.info(`${pc14.bold(f.relativePath)} ${pc14.dim("(preview)")}`);
126
126
  }
127
127
  }
128
128
  }
@@ -332,13 +332,13 @@ function handleCancel(result) {
332
332
  }
333
333
  function printBanner() {
334
334
  console.log("");
335
- p14.intro(pc15.bgCyan(pc15.black(" @solid-stack/mason ")));
335
+ p14.intro(pc14.bgCyan(pc14.black(" @solid-stack/mason ")));
336
336
  }
337
337
  async function promptProperties(options = {}) {
338
338
  const properties = options.defaults ? [...options.defaults] : [];
339
339
  if (properties.length > 0) {
340
340
  const summary = properties.map((p16) => `${p16.name}: ${p16.type}${p16.optional ? "?" : ""}`).join(", ");
341
- p14.log.info(pc15.dim(`Pre-configured fields: ${summary}`));
341
+ p14.log.info(pc14.dim(`Pre-configured fields: ${summary}`));
342
342
  const addMore = handleCancel(
343
343
  await p14.confirm({
344
344
  message: "Would you like to add custom fields/properties?",
@@ -349,7 +349,7 @@ async function promptProperties(options = {}) {
349
349
  return properties;
350
350
  }
351
351
  }
352
- p14.log.info(pc15.cyan("Enter properties (leave name blank when finished):"));
352
+ p14.log.info(pc14.cyan("Enter properties (leave name blank when finished):"));
353
353
  while (true) {
354
354
  const name = handleCancel(
355
355
  await p14.text({
@@ -397,7 +397,7 @@ async function promptProperties(options = {}) {
397
397
  optional
398
398
  });
399
399
  p14.log.success(
400
- pc15.green(`Added: ${name.trim()}${optional ? "?" : ""}: ${finalType.trim()}`)
400
+ pc14.green(`Added: ${name.trim()}${optional ? "?" : ""}: ${finalType.trim()}`)
401
401
  );
402
402
  }
403
403
  return properties;
@@ -631,7 +631,7 @@ function installNpmPackages(projectRoot, packages, pm) {
631
631
  installCmd = `npm install ${packages.join(" ")}`;
632
632
  break;
633
633
  }
634
- p14.log.info(`Installing missing dependencies with ${manager}: ${pc15.cyan(packages.join(", "))}`);
634
+ p14.log.info(`Installing missing dependencies with ${manager}: ${pc14.cyan(packages.join(", "))}`);
635
635
  execSync(installCmd, {
636
636
  cwd: projectRoot,
637
637
  stdio: "inherit"
@@ -2348,7 +2348,7 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
2348
2348
  }
2349
2349
  }
2350
2350
  const s = p14.spinner();
2351
- s.start(`Generating feature '${pc15.cyan(normalizedName)}'...`);
2351
+ s.start(`Generating feature '${pc14.cyan(normalizedName)}'...`);
2352
2352
  const options = {
2353
2353
  name: normalizedName,
2354
2354
  projectRoot,
@@ -2395,7 +2395,7 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
2395
2395
  s.stop("Feature scaffolded successfully!");
2396
2396
  printGeneratedFiles(files, options.dryRun);
2397
2397
  p14.outro(
2398
- pc15.green(
2398
+ pc14.green(
2399
2399
  `\u2713 Feature '${normalizedName}' initialized in ${path2.relative(projectRoot, targetDir)} (uncommitted, unregistered)`
2400
2400
  )
2401
2401
  );
@@ -2551,7 +2551,7 @@ async function runSharedCommand(sharedNameArg, flags = {}) {
2551
2551
  );
2552
2552
  }
2553
2553
  const s = p14.spinner();
2554
- s.start(`Generating shared module '${pc15.cyan(normalizedName)}'...`);
2554
+ s.start(`Generating shared module '${pc14.cyan(normalizedName)}'...`);
2555
2555
  const files = generateShared({
2556
2556
  name: normalizedName,
2557
2557
  description,
@@ -2565,7 +2565,7 @@ async function runSharedCommand(sharedNameArg, flags = {}) {
2565
2565
  s.stop("Shared module generated successfully!");
2566
2566
  printGeneratedFiles(files, Boolean(flags.dryRun));
2567
2567
  p14.outro(
2568
- pc15.green(
2568
+ pc14.green(
2569
2569
  `\u2713 Shared module '${normalizedName}' initialized in ${path2.relative(projectRoot, targetDir)} (uncommitted, unregistered)`
2570
2570
  )
2571
2571
  );
@@ -2693,7 +2693,7 @@ async function runUseCaseCommand(useCaseNameArg, flags = {}) {
2693
2693
  }
2694
2694
  }
2695
2695
  const s = p14.spinner();
2696
- s.start(`Generating use case '${pc15.cyan(ucName)}'...`);
2696
+ s.start(`Generating use case '${pc14.cyan(ucName)}'...`);
2697
2697
  const options = {
2698
2698
  name: ucName,
2699
2699
  feature,
@@ -2725,7 +2725,7 @@ async function runUseCaseCommand(useCaseNameArg, flags = {}) {
2725
2725
  }
2726
2726
  s.stop("Use case generated successfully!");
2727
2727
  printGeneratedFiles(files, options.dryRun);
2728
- p14.outro(pc15.green(`Use case '${ucName}' created in feature '${feature}'!`));
2728
+ p14.outro(pc14.green(`Use case '${ucName}' created in feature '${feature}'!`));
2729
2729
  }
2730
2730
  async function runDomainCommand(domainNameArg, flags = {}) {
2731
2731
  const projectRoot = findProjectRoot();
@@ -2796,7 +2796,7 @@ async function runDomainCommand(domainNameArg, flags = {}) {
2796
2796
  });
2797
2797
  }
2798
2798
  const s = p14.spinner();
2799
- s.start(`Generating domain model '${pc15.cyan(entityName)}'...`);
2799
+ s.start(`Generating domain model '${pc14.cyan(entityName)}'...`);
2800
2800
  const options = {
2801
2801
  name: entityName,
2802
2802
  feature,
@@ -2809,7 +2809,7 @@ async function runDomainCommand(domainNameArg, flags = {}) {
2809
2809
  const file = generateDomain(options);
2810
2810
  s.stop("Domain model generated successfully!");
2811
2811
  printGeneratedFiles([file], options.dryRun);
2812
- p14.outro(pc15.green(`Domain model '${entityName}' created in feature '${feature}'!`));
2812
+ p14.outro(pc14.green(`Domain model '${entityName}' created in feature '${feature}'!`));
2813
2813
  }
2814
2814
  async function runInfrastructureCommand(classNameArg, flags = {}) {
2815
2815
  const projectRoot = findProjectRoot();
@@ -2978,7 +2978,7 @@ async function runInfrastructureCommand(classNameArg, flags = {}) {
2978
2978
  registerInProvider = !flags.noProvider;
2979
2979
  }
2980
2980
  const s = p14.spinner();
2981
- s.start(`Generating infrastructure class '${pc15.cyan(className)}'...`);
2981
+ s.start(`Generating infrastructure class '${pc14.cyan(className)}'...`);
2982
2982
  const files = [];
2983
2983
  const options = {
2984
2984
  name: className,
@@ -3013,7 +3013,7 @@ async function runInfrastructureCommand(classNameArg, flags = {}) {
3013
3013
  }
3014
3014
  s.stop("Infrastructure class generated successfully!");
3015
3015
  printGeneratedFiles(files, options.dryRun);
3016
- p14.outro(pc15.green(`Infrastructure class '${className}' created!`));
3016
+ p14.outro(pc14.green(`Infrastructure class '${className}' created!`));
3017
3017
  }
3018
3018
  async function runInterfaceCommand(interfaceNameArg, flags = {}) {
3019
3019
  const projectRoot = findProjectRoot();
@@ -3126,7 +3126,7 @@ async function runInterfaceCommand(interfaceNameArg, flags = {}) {
3126
3126
  }
3127
3127
  }
3128
3128
  const s = p14.spinner();
3129
- s.start(`Generating interface '${pc15.cyan(ifaceName)}'...`);
3129
+ s.start(`Generating interface '${pc14.cyan(ifaceName)}'...`);
3130
3130
  const files = [];
3131
3131
  const options = {
3132
3132
  name: ifaceName,
@@ -3175,7 +3175,7 @@ async function runInterfaceCommand(interfaceNameArg, flags = {}) {
3175
3175
  }
3176
3176
  s.stop("Interface generated successfully!");
3177
3177
  printGeneratedFiles(files, options.dryRun);
3178
- p14.outro(pc15.green(`Interface '${ifaceName}' created in feature '${feature}'!`));
3178
+ p14.outro(pc14.green(`Interface '${ifaceName}' created in feature '${feature}'!`));
3179
3179
  }
3180
3180
  async function runHttpHandlerCommand(handlerNameArg, flags = {}) {
3181
3181
  const projectRoot = findProjectRoot();
@@ -3292,7 +3292,7 @@ async function runHttpHandlerCommand(handlerNameArg, flags = {}) {
3292
3292
  }
3293
3293
  }
3294
3294
  const s = p14.spinner();
3295
- s.start(`Generating HTTP handler '${pc15.cyan(className)}'...`);
3295
+ s.start(`Generating HTTP handler '${pc14.cyan(className)}'...`);
3296
3296
  const options = {
3297
3297
  name: className,
3298
3298
  feature,
@@ -3310,7 +3310,7 @@ async function runHttpHandlerCommand(handlerNameArg, flags = {}) {
3310
3310
  const files = generateHttpHandler(options);
3311
3311
  s.stop("HTTP handler generated successfully!");
3312
3312
  printGeneratedFiles(files, options.dryRun);
3313
- p14.outro(pc15.green(`HTTP handler '${className}' created in feature '${feature}'!`));
3313
+ p14.outro(pc14.green(`HTTP handler '${className}' created in feature '${feature}'!`));
3314
3314
  }
3315
3315
  function generateInjectableCode(className, dependencies = [], methods = [], implementsInterface) {
3316
3316
  const formattedDeps = dependencies.map((dep) => ({
@@ -3466,7 +3466,7 @@ async function runInjectableCommand(classNameArg, flags = {}) {
3466
3466
  );
3467
3467
  }
3468
3468
  const s = p14.spinner();
3469
- s.start(`Generating injectable '${pc15.cyan(className)}'...`);
3469
+ s.start(`Generating injectable '${pc14.cyan(className)}'...`);
3470
3470
  const options = {
3471
3471
  name: className,
3472
3472
  feature,
@@ -3480,7 +3480,7 @@ async function runInjectableCommand(classNameArg, flags = {}) {
3480
3480
  const files = generateInjectable(options);
3481
3481
  s.stop("Injectable class generated successfully!");
3482
3482
  printGeneratedFiles(files, options.dryRun);
3483
- p14.outro(pc15.green(`Injectable '${className}' created successfully!`));
3483
+ p14.outro(pc14.green(`Injectable '${className}' created successfully!`));
3484
3484
  }
3485
3485
  async function runInteractiveMenu(flags = {}) {
3486
3486
  printBanner();
@@ -3594,7 +3594,7 @@ async function handleCreate(type, name, flags = {}) {
3594
3594
  break;
3595
3595
  default:
3596
3596
  p14.log.error(
3597
- pc15.red(
3597
+ pc14.red(
3598
3598
  `Unknown component type: "${type}". Allowed types: feature, shared, usecase, domain, infrastructure, interface, httpHandler, injectable.`
3599
3599
  )
3600
3600
  );
@@ -3714,19 +3714,19 @@ async function handleImport(typeArg, nameArg, flags = {}) {
3714
3714
  );
3715
3715
  }
3716
3716
  if (type !== "shared" && type !== "feature") {
3717
- p14.log.error(pc15.red(`Invalid module type: "${typeArg}". Must be "shared" or "feature".`));
3717
+ p14.log.error(pc14.red(`Invalid module type: "${typeArg}". Must be "shared" or "feature".`));
3718
3718
  process.exit(1);
3719
3719
  }
3720
3720
  const registryBase = getRegistryBase(projectRoot, flags.registry);
3721
3721
  const s = p14.spinner();
3722
- s.start(`Connecting to registry at ${pc15.dim(registryBase)}...`);
3722
+ s.start(`Connecting to registry at ${pc14.dim(registryBase)}...`);
3723
3723
  let index;
3724
3724
  try {
3725
3725
  index = await fetchRegistryIndex(registryBase);
3726
3726
  s.stop("Registry index loaded.");
3727
3727
  } catch (err) {
3728
- s.stop(pc15.red("Failed to load registry index."));
3729
- p14.log.error(pc15.red(err.message || String(err)));
3728
+ s.stop(pc14.red("Failed to load registry index."));
3729
+ p14.log.error(pc14.red(err.message || String(err)));
3730
3730
  process.exit(1);
3731
3731
  }
3732
3732
  const availableList = type === "shared" ? index.shared : index.features;
@@ -3750,9 +3750,9 @@ async function handleImport(typeArg, nameArg, flags = {}) {
3750
3750
  }
3751
3751
  if (!candidateNames.includes(name)) {
3752
3752
  const closest = findClosestMatch(name, candidateNames);
3753
- p14.log.error(pc15.red(`\u274C Module '${name}' not found in the ${type} registry.`));
3753
+ p14.log.error(pc14.red(`\u274C Module '${name}' not found in the ${type} registry.`));
3754
3754
  if (closest) {
3755
- p14.log.info(pc15.yellow(`Did you mean '${pc15.cyan(closest)}'?`));
3755
+ p14.log.info(pc14.yellow(`Did you mean '${pc14.cyan(closest)}'?`));
3756
3756
  }
3757
3757
  process.exit(1);
3758
3758
  }
@@ -3764,7 +3764,7 @@ async function handleImport(typeArg, nameArg, flags = {}) {
3764
3764
  try {
3765
3765
  manifest = await fetchModuleManifest(registryBase, modType, modName);
3766
3766
  } catch (err) {
3767
- p14.log.error(pc15.red(`Failed to fetch manifest for ${modType} '${modName}': ${err.message}`));
3767
+ p14.log.error(pc14.red(`Failed to fetch manifest for ${modType} '${modName}': ${err.message}`));
3768
3768
  process.exit(1);
3769
3769
  }
3770
3770
  nodes.set(key, {
@@ -3804,7 +3804,7 @@ async function handleImport(typeArg, nameArg, flags = {}) {
3804
3804
  buildTopologicalOrder(rootKey);
3805
3805
  const resolutions = /* @__PURE__ */ new Map();
3806
3806
  const globalAliasMap = /* @__PURE__ */ new Map();
3807
- p14.log.step(`Importing ${type}: ${pc15.cyan(name)}...`);
3807
+ p14.log.step(`Importing ${type}: ${pc14.cyan(name)}...`);
3808
3808
  for (const key of orderedKeys) {
3809
3809
  const node = nodes.get(key);
3810
3810
  const { type: modType, name: registryName, manifest } = node;
@@ -3837,7 +3837,7 @@ async function handleImport(typeArg, nameArg, flags = {}) {
3837
3837
  if (programmaticPointTo) {
3838
3838
  if (!checkModuleExists(projectRoot, modType, programmaticPointTo)) {
3839
3839
  p14.log.error(
3840
- pc15.red(
3840
+ pc14.red(
3841
3841
  `Module '${programmaticPointTo}' specified in --point-to does not exist in ${folder}.`
3842
3842
  )
3843
3843
  );
@@ -3873,7 +3873,7 @@ async function handleImport(typeArg, nameArg, flags = {}) {
3873
3873
  }
3874
3874
  const existingDir = getExistingModuleDir(projectRoot, modType, registryName);
3875
3875
  if (!existingDir) {
3876
- p14.log.info(` \u21B3 Resolving required ${modType} dependency: ${pc15.cyan(registryName)}`);
3876
+ p14.log.info(` \u21B3 Resolving required ${modType} dependency: ${pc14.cyan(registryName)}`);
3877
3877
  resolutions.set(key, {
3878
3878
  type: modType,
3879
3879
  registryName,
@@ -4104,7 +4104,7 @@ async function handleImport(typeArg, nameArg, flags = {}) {
4104
4104
  const isOverwrite = Boolean(flags.overwrite || res.action === "overwrite");
4105
4105
  if (key !== rootKey) {
4106
4106
  p14.log.step(
4107
- `Importing ${res.type}: ${pc15.cyan(res.targetName)}${res.targetName !== res.registryName ? pc15.dim(` (from ${res.registryName})`) : ""}...`
4107
+ `Importing ${res.type}: ${pc14.cyan(res.targetName)}${res.targetName !== res.registryName ? pc14.dim(` (from ${res.registryName})`) : ""}...`
4108
4108
  );
4109
4109
  }
4110
4110
  if (res.action === "overwrite" && !flags.dryRun) {
@@ -4123,7 +4123,7 @@ async function handleImport(typeArg, nameArg, flags = {}) {
4123
4123
  const localFilePath = path2.join(targetDir, file);
4124
4124
  if (fs4.existsSync(localFilePath) && !isOverwrite) {
4125
4125
  p14.log.warn(
4126
- ` \u21B3 Skipping existing file: ${pc15.dim(path2.relative(projectRoot, localFilePath))} (use --overwrite to replace)`
4126
+ ` \u21B3 Skipping existing file: ${pc14.dim(path2.relative(projectRoot, localFilePath))} (use --overwrite to replace)`
4127
4127
  );
4128
4128
  continue;
4129
4129
  }
@@ -4135,13 +4135,13 @@ async function handleImport(typeArg, nameArg, flags = {}) {
4135
4135
  }
4136
4136
  const displayPath = path2.relative(projectRoot, localFilePath);
4137
4137
  totalWrittenFiles.push(displayPath);
4138
- p14.log.message(` ${pc15.green("+")} ${displayPath}`);
4138
+ p14.log.message(` ${pc14.green("+")} ${displayPath}`);
4139
4139
  }
4140
4140
  }
4141
4141
  const missingNpm = getMissingNpmPackages(projectRoot, Array.from(requiredNpmPackages));
4142
4142
  if (missingNpm.length > 0) {
4143
4143
  if (flags.skipInstall || flags.dryRun) {
4144
- p14.log.info(`Required npm dependencies to install: ${pc15.cyan(missingNpm.join(", "))}`);
4144
+ p14.log.info(`Required npm dependencies to install: ${pc14.cyan(missingNpm.join(", "))}`);
4145
4145
  } else {
4146
4146
  try {
4147
4147
  installNpmPackages(projectRoot, missingNpm);
@@ -4155,13 +4155,13 @@ async function handleImport(typeArg, nameArg, flags = {}) {
4155
4155
  }
4156
4156
  }
4157
4157
  if (flags.dryRun) {
4158
- p14.log.info(pc15.yellow("Dry run complete: No files were written to disk."));
4158
+ p14.log.info(pc14.yellow("Dry run complete: No files were written to disk."));
4159
4159
  } else {
4160
4160
  const rootRes = resolutions.get(rootKey);
4161
4161
  const baseDir = getModuleBaseDir(projectRoot, type);
4162
4162
  const displayTarget = path2.relative(projectRoot, path2.join(baseDir, rootRes.targetName));
4163
4163
  p14.log.success(
4164
- pc15.green(
4164
+ pc14.green(
4165
4165
  `Successfully imported ${type} '${name}' (${totalWrittenFiles.length} file${totalWrittenFiles.length === 1 ? "" : "s"} placed in ${displayTarget})`
4166
4166
  )
4167
4167
  );
@@ -4427,13 +4427,9 @@ function lintCodebase(options = {}) {
4427
4427
  featureResult.passed = false;
4428
4428
  }
4429
4429
  if (failFast) {
4430
- const errorMsg = `[FAIL FAST] Dependency rule violation detected:
4431
- Feature: ${v.feature}
4432
- Category: ${v.category}
4433
- Rule: ${v.ruleId}
4434
- Location: ${v.relativePath}:${v.line}
4435
- Code: ${v.code}
4436
- Explanation: ${v.advice}`;
4430
+ const errorMsg = `Dependency rule violation detected in ${v.relativePath}:${v.line}:
4431
+ [${v.category}] ${v.advice}
4432
+ Code: ${v.code}`;
4437
4433
  throw new DependencyRuleError(errorMsg, [v], true);
4438
4434
  }
4439
4435
  };
@@ -4921,87 +4917,23 @@ ${compiledDetails}
4921
4917
  }
4922
4918
 
4923
4919
  // src/commands/lint.ts
4924
- function printLintBanner(mode) {
4925
- console.log("");
4926
- const title = " Mason Clean Architecture Dependency Linter ";
4927
- const line = "\u2501".repeat(title.length + 2);
4928
- console.log(pc15.cyan(` \u250F${line}\u2513`));
4929
- console.log(` ${pc15.cyan("\u2503")} ${pc15.bgCyan(pc15.black(title))} ${pc15.cyan("\u2503")}`);
4930
- console.log(pc15.cyan(` \u2517${line}\u251B`));
4931
- const modeText = mode === "failFast" ? `${pc15.yellow("Fail-Fast")} ${pc15.dim("(default: stops at first error)")}` : `${pc15.magenta("Complete")} ${pc15.dim("(--complete: compiles all errors)")}`;
4932
- console.log(` Mode: ${modeText}`);
4933
- console.log("");
4934
- }
4935
- function formatViolation(v, showFixHint = true) {
4936
- const lines = [];
4937
- const categoryBadge = pc15.red(pc15.bold(`[${v.category}]`));
4938
- const location = pc15.white(`${v.relativePath}:${pc15.yellow(String(v.line))}`);
4939
- lines.push(` ${categoryBadge} ${location}`);
4940
- lines.push(` ${pc15.dim("Rule ID:")} ${pc15.yellow(v.ruleId)}`);
4941
- lines.push(` ${pc15.dim("Code:")} ${pc15.magenta(v.code)}`);
4942
- lines.push(` ${pc15.dim("Advice:")} ${pc15.cyan(v.advice)}`);
4943
- if (showFixHint && v.fixExample) {
4944
- lines.push(` ${pc15.dim("Example:")}`);
4945
- lines.push(` ${pc15.red(`- ${v.fixExample.bad}`)}`);
4946
- lines.push(` ${pc15.green(`+ ${v.fixExample.good}`)}`);
4947
- }
4948
- return lines.join("\n");
4949
- }
4950
- function formatFeatureResult(res, options = {}) {
4920
+ function formatViolation(v) {
4951
4921
  const lines = [];
4952
- if (res.passed) {
4953
- lines.push(
4954
- ` ${pc15.green("\u2714")} ${pc15.bold(res.featureName)} ${pc15.dim(
4955
- `(${res.scannedFilesCount} files checked - clean)`
4956
- )}`
4957
- );
4958
- return lines.join("\n");
4959
- }
4960
- const countBadge = pc15.red(
4961
- `(${res.violations.length} violation${res.violations.length > 1 ? "s" : ""})`
4922
+ lines.push(pc14.underline(pc14.cyan(v.relativePath)) + pc14.dim(":") + pc14.yellow(String(v.line)));
4923
+ const gutter = `${String(v.line).padStart(4, " ")} | `;
4924
+ lines.push(pc14.dim(gutter) + v.code);
4925
+ const categoryShort = v.category.replace(" Violation", "");
4926
+ lines.push(
4927
+ " " + pc14.red(pc14.bold("\u2716")) + " " + pc14.red(`[${categoryShort}]`) + " " + v.advice
4962
4928
  );
4963
- lines.push(`
4964
- ${pc15.red("\u2716")} ${pc15.bold(pc15.white(res.featureName))} ${countBadge}`);
4965
- lines.push(` ${pc15.dim("Path:")} ${res.featureDir}`);
4966
- lines.push("");
4967
- for (const v of res.violations) {
4968
- lines.push(formatViolation(v, options.fixHint !== false));
4969
- lines.push("");
4929
+ if (v.fixExample?.good) {
4930
+ lines.push(" " + pc14.dim("\u2192") + " " + pc14.dim(v.fixExample.good));
4970
4931
  }
4971
4932
  return lines.join("\n");
4972
4933
  }
4973
- function printTerminalReport(summary, options = {}) {
4974
- for (const res of summary.results) {
4975
- const formatted = formatFeatureResult(res, options);
4976
- if (formatted.trim()) {
4977
- console.log(formatted);
4978
- }
4979
- }
4980
- console.log("\u2501".repeat(70));
4981
- const statusIcon = summary.totalViolations === 0 ? pc15.green("\u2714 PASS") : pc15.red("\u2716 FAIL");
4982
- console.log(
4983
- ` ${statusIcon} ${pc15.bold("Dependency Rules Audit Result")} ${pc15.dim(
4984
- `(${summary.durationMs}ms)`
4985
- )}`
4986
- );
4987
- console.log(
4988
- ` ${pc15.bold("Features:")} ${pc15.cyan(String(summary.totalFeatures))} total | ${pc15.green(
4989
- String(summary.cleanFeatures)
4990
- )} clean | ${summary.violatedFeatures > 0 ? pc15.red(String(summary.violatedFeatures)) : pc15.green("0")} with violations`
4991
- );
4992
- console.log(
4993
- ` ${pc15.bold("Violations:")} ${summary.totalViolations > 0 ? pc15.red(pc15.bold(String(summary.totalViolations))) : pc15.green("0")} rule violations found`
4994
- );
4995
- console.log("\u2501".repeat(70));
4996
- console.log("");
4997
- }
4998
4934
  async function handleLint(flags = {}) {
4999
4935
  const complete = Boolean(flags.complete);
5000
- const mode = complete ? "complete" : "failFast";
5001
4936
  const quiet = Boolean(flags.quiet);
5002
- if (!quiet) {
5003
- printLintBanner(mode);
5004
- }
5005
4937
  const options = {
5006
4938
  complete,
5007
4939
  quiet,
@@ -5012,14 +4944,23 @@ async function handleLint(flags = {}) {
5012
4944
  };
5013
4945
  try {
5014
4946
  const summary = lintCodebase(options);
5015
- if (!quiet) {
5016
- printTerminalReport(summary, options);
5017
- }
5018
4947
  if (summary.totalViolations > 0) {
4948
+ if (!quiet) {
4949
+ console.log("");
4950
+ for (const v of summary.allViolations) {
4951
+ console.log(formatViolation(v));
4952
+ console.log("");
4953
+ }
4954
+ console.log(
4955
+ pc14.red(
4956
+ `\u2716 Dependency rules check failed with ${summary.totalViolations} error${summary.totalViolations > 1 ? "s" : ""} across ${summary.violatedFeatures} feature${summary.violatedFeatures > 1 ? "s" : ""} (${summary.totalFeatures} features scanned).`
4957
+ )
4958
+ );
4959
+ console.log("");
4960
+ }
5019
4961
  const errorHeader = `Dependency rule audit failed with ${summary.totalViolations} violation(s) across ${summary.violatedFeatures} feature(s):`;
5020
4962
  const compiledDetails = summary.allViolations.map(
5021
4963
  (v, i) => `${i + 1}. [${v.category}] ${v.relativePath}:${v.line}
5022
- Rule: ${v.ruleId}
5023
4964
  Code: ${v.code}
5024
4965
  Advice: ${v.advice}`
5025
4966
  ).join("\n\n");
@@ -5030,20 +4971,22 @@ ${compiledDetails}
5030
4971
  }
5031
4972
  if (!quiet) {
5032
4973
  console.log(
5033
- pc15.green(`\u2714 All dependency rules are being followed! (${summary.totalFeatures} features checked)`)
4974
+ pc14.green(
4975
+ `\u2714 Dependency rules verified across ${summary.totalFeatures} feature${summary.totalFeatures === 1 ? "" : "s"}.`
4976
+ )
5034
4977
  );
5035
- console.log("");
5036
4978
  }
5037
4979
  return summary;
5038
4980
  } catch (err) {
5039
4981
  if (err instanceof DependencyRuleError && err.isFailFast) {
5040
4982
  if (!quiet) {
5041
- console.log(pc15.red(`
5042
- \u2716 [FAIL FAST] Terminating on first detected dependency rule violation:`));
4983
+ console.log("");
5043
4984
  const v = err.violations[0];
5044
4985
  if (v) {
5045
- console.log(formatViolation(v, options.fixHint !== false));
4986
+ console.log(formatViolation(v));
4987
+ console.log("");
5046
4988
  }
4989
+ console.log(pc14.red(`\u2716 Dependency rules check failed (1 error).`));
5047
4990
  console.log("");
5048
4991
  }
5049
4992
  }
@@ -5057,7 +5000,7 @@ function createCli() {
5057
5000
  cli.command("[...args]", "Interactive scaffolding and import wizard").option("-d, --dry-run", "Preview changes without writing to disk").option("-o, --overwrite", "Overwrite existing files").option("-y, --yes", "Accept defaults and skip interactive prompts").option("--registry", "Run in registry mode").option("--point-to <mapping>", "Point a dependency to an existing local module (e.g. --point-to time:mytime)").option("--alias <mapping>", "Import a dependency fresh under an alias name (e.g. --alias time:time-mason)").option("--tests", "Include test files (use --no-tests to exclude)").action(async (args, flags) => {
5058
5001
  if (args && args.length > 0) {
5059
5002
  p14.log.error(
5060
- pc15.red(
5003
+ pc14.red(
5061
5004
  `Unknown command: "${args.join(" ")}". Use --help to list available commands.`
5062
5005
  )
5063
5006
  );
@@ -5176,6 +5119,12 @@ function createCli() {
5176
5119
  targetDir: target || flags.target || flags.dest
5177
5120
  });
5178
5121
  } catch (err) {
5122
+ if (err instanceof DependencyRuleError) {
5123
+ if (process.env.VITEST) {
5124
+ throw err;
5125
+ }
5126
+ process.exit(1);
5127
+ }
5179
5128
  handleCliError(err);
5180
5129
  }
5181
5130
  });
@@ -5210,7 +5159,7 @@ function handleCliError(err) {
5210
5159
  process.exit(0);
5211
5160
  }
5212
5161
  const message = err instanceof Error ? err.message : String(err);
5213
- p14.log.error(pc15.red(`Error: ${message}`));
5162
+ p14.log.error(pc14.red(`Error: ${message}`));
5214
5163
  if (process.env.VITEST) {
5215
5164
  throw err;
5216
5165
  }