archforge-x 1.0.4 → 1.0.7

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.
Files changed (57) hide show
  1. package/README.md +51 -155
  2. package/dist/analyzers/dependency.js +5 -48
  3. package/dist/api/routes/user.routes.js +18 -0
  4. package/dist/cli/commands/init-template.js +105 -0
  5. package/dist/cli/commands/sync.js +11 -3
  6. package/dist/cli/commands/template-create.js +377 -0
  7. package/dist/cli/commands/templates.js +152 -0
  8. package/dist/cli/commands/validate-template.js +179 -0
  9. package/dist/cli/init.js +74 -0
  10. package/dist/cli/interactive-init.js +257 -0
  11. package/dist/cli/interactive.js +53 -82
  12. package/dist/config/env.schema.js +11 -0
  13. package/dist/config/index.js +27 -0
  14. package/dist/core/VersionManifest.js +80 -0
  15. package/dist/core/architecture/defaults.js +148 -0
  16. package/dist/core/architecture/parser.js +12 -4
  17. package/dist/core/architecture/schema.js +2 -2
  18. package/dist/core/architecture/validator.js +96 -37
  19. package/dist/core/templates/model.js +3 -0
  20. package/dist/core/templates/validator.js +163 -0
  21. package/dist/core/types/user.js +2 -0
  22. package/dist/discovery/local-registry.js +137 -0
  23. package/dist/discovery/registry.js +170 -0
  24. package/dist/discovery/resolver.js +212 -0
  25. package/dist/generators/base.js +195 -68
  26. package/dist/generators/generator.js +17 -15
  27. package/dist/generators/go/gin.js +15 -94
  28. package/dist/generators/node/express.js +238 -706
  29. package/dist/generators/node/nestjs.js +76 -677
  30. package/dist/generators/node/nextjs.js +15 -78
  31. package/dist/generators/python/django.js +15 -103
  32. package/dist/generators/python/fastapi.js +17 -98
  33. package/dist/generators/templates/ci.js +129 -0
  34. package/dist/generators/templates/docker.js +184 -0
  35. package/dist/generators/templates/index.js +13 -0
  36. package/dist/generators/templates/package-versions.js +132 -0
  37. package/dist/generators/templates/version-validator.js +103 -0
  38. package/dist/generators/verification/index.js +11 -0
  39. package/dist/generators/verification/verifier.js +281 -0
  40. package/dist/index.js +43 -13
  41. package/dist/infrastructure/cache/cache.interface.js +2 -0
  42. package/dist/infrastructure/cache/memory.cache.js +26 -0
  43. package/dist/infrastructure/cache/redis.cache.js +32 -0
  44. package/dist/infrastructure/database/prisma.js +5 -0
  45. package/dist/infrastructure/errors/app.error.js +26 -0
  46. package/dist/infrastructure/logger.js +16 -0
  47. package/dist/infrastructure/middleware/error.middleware.js +23 -0
  48. package/dist/interface-adapters/controllers/health.controller.js +29 -0
  49. package/dist/main.js +27 -0
  50. package/dist/orchestration/configurator.js +282 -0
  51. package/dist/orchestration/fetcher.js +90 -0
  52. package/dist/orchestration/installer.js +155 -0
  53. package/dist/services/user.service.js +27 -0
  54. package/dist/utils/git.js +204 -0
  55. package/dist/utils/package-manager.js +236 -0
  56. package/dist/validation/compatibility.js +233 -0
  57. package/package.json +1 -1
package/README.md CHANGED
@@ -1,190 +1,86 @@
1
- # ArchForge X
1
+ # ArchForge X - Enterprise Architecture Engine
2
2
 
3
- A configuration-driven architecture engine for generating and enforcing production-grade project structures across multiple languages and frameworks.
4
-
5
- ## Why This Exists
6
-
7
- Modern software development often suffers from two primary issues: **setup fatigue** and **architecture drift**. Developers spend hours configuring boilerplate for logging, caching, and database layers, only for the project's architectural boundaries to erode over time as the team grows.
8
-
9
- ArchForge X solves this by moving architecture from "documentation" to "executable configuration." By defining your project's structure and rules in a central `archforge.yaml`, you ensure that every project starts with production-ready defaults and stays compliant throughout its lifecycle.
3
+ ArchForge X is a CLI tool designed to turn software architecture into executable code. It enables teams to scaffold, validate, audit, and visualize project architecture using a configuration-driven approach.
10
4
 
11
5
  ## Key Features
12
6
 
13
- - **Config-Driven Generation**: Generate entire project skeletons from a single YAML definition.
14
- - **Architecture Enforcement**: Automatically validate naming conventions and import boundaries.
15
- - **Production-Ready Defaults**: Built-in support for structured logging, health checks, and global error handling.
16
- - **Multi-Stack Support**: Consistent patterns across Node.js, Python, and Go.
17
- - **Zero-Drift Sync**: Re-apply architectural rules to existing projects without losing custom logic.
18
-
19
- ## Supported Capabilities
20
-
21
- - **Architectures**: Clean Architecture (DDD), Layered Architecture, MVC.
22
- - **Frameworks**: NestJS, Express, FastAPI, Django, Go Gin, Next.js.
23
- - **ORMs & Databases**: Prisma, SQLAlchemy, GORM, PostgreSQL, MySQL, SQLite, MongoDB.
24
- - **DevOps**: Automated Dockerfile and Docker Compose generation, GitHub Actions CI/CD workflows.
7
+ * **Policy-Driven Scaffolding**: Generate production-ready projects (Clean Architecture, DDD, Hexagonal) for Node.js (Express, NestJS).
8
+ * **Strict Validation**: Enforce dependency rules between layers (e.g., Domain cannot import Infrastructure).
9
+ * **Automated Audits**: Scan codebase for architectural violations and receive fix suggestions.
10
+ * **Visualization**: Generate SVG dependency graphs to visualize project structure.
11
+ * **Configuration as Code**: Define architecture in `archforge.yaml` or `archforge.json`.
25
12
 
26
13
  ## Installation
27
14
 
28
- Install ArchForge X globally via npm:
29
-
30
15
  ```bash
31
- npm install -g archforge
16
+ npm install -g archforge-x
32
17
  ```
33
18
 
34
- ## CLI Commands
35
-
36
- ### init
19
+ ## Quick Start
37
20
 
38
- The `init` command starts an interactive wizard to bootstrap a new project.
21
+ ### 1. Initialize a Project
22
+ Start the interactive wizard to create a new project or generate a config for an existing one.
39
23
 
40
24
  ```bash
41
25
  archforge init
42
26
  ```
43
27
 
44
- During initialization, you will select:
45
- - **Architecture Style**: Choose between Clean, Layered, or MVC.
46
- - **Framework**: Select your preferred backend or frontend framework.
47
- - **ORM & Database**: Configure your data persistence layer.
48
- - **Optional Modules**: Add Docker support, CI/CD workflows, Caching (Redis), and more.
49
-
50
- ### sync
51
-
52
- The `sync` command re-applies the architectural rules defined in `archforge.yaml` to your project.
53
-
54
- ```bash
55
- archforge sync
56
- ```
57
-
58
- - **What it changes**: Updates configuration files, architecture guardrails (e.g., ESLint rules), and missing infrastructure layers.
59
- - **What it never changes**: Your business logic, use cases, or custom implementation files.
60
-
61
- ### validate
62
-
63
- The `validate` command checks your project against the rules defined in `archforge.yaml`.
64
-
65
- ```bash
66
- archforge validate
67
- ```
68
-
69
- - **Validation**: Checks naming conventions, directory structure, and restricted import paths.
70
- - **Usage**: Used locally during development or in CI pipelines to prevent architectural violations.
71
- - **Behavior**: Returns a non-zero exit code on failure, making it ideal for blocking invalid PRs.
72
-
73
- ### upgrade
74
-
75
- The `upgrade` command adds new production-grade features to an existing ArchForge project.
76
-
77
- ```bash
78
- archforge upgrade
79
- ```
80
-
81
- - **Purpose**: Safely introduces enhancements like new logging providers or health check endpoints without breaking existing code.
82
-
83
- ### generate
84
-
85
- The `generate` command creates specific architectural components within an existing project.
86
-
87
- ```bash
88
- archforge generate module user
89
- ```
90
-
91
- - **Usage**: Use this to quickly add new features, layers, or modules that follow the project's established patterns.
92
- - **Alias**: `create`
93
-
94
- ### graph
95
-
96
- The `graph` command generates a visual representation of your project's architecture.
97
-
98
- ```bash
99
- archforge graph
100
- ```
101
-
102
- - **Output**: Generates an `architecture-graph.svg` file showing the relationships and dependencies between your project's layers.
103
- - **Alias**: `visualize`
104
-
105
- ## Configuration (archforge.yaml)
106
-
107
- The `archforge.yaml` file is the single source of truth for your project's architecture. It defines the structure, naming conventions, and enforcement policies.
28
+ ### 2. Define Your Architecture
29
+ Create an `archforge.yaml` file to define your layers and rules.
108
30
 
109
31
  ```yaml
110
- name: my-production-app
111
- architecture: clean
112
- framework: nestjs
113
- orm: prisma
114
- database: postgresql
115
-
116
- structure:
117
- layers:
118
- - name: domain
119
- path: src/domain
120
- canImport: []
121
- - name: application
122
- path: src/application
123
- canImport: [domain]
124
- - name: infrastructure
125
- path: src/infrastructure
126
- canImport: [domain, application]
127
- - name: presentation
128
- path: src/presentation
129
- canImport: [domain, application]
130
-
131
- naming:
132
- controllers: "{name}.controller.ts"
133
- useCases: "{name}.use-case.ts"
134
- repositories: "{name}.repository.ts"
135
-
136
- enforcement:
137
- strictImports: true
138
- namingConvention: pascalCase
32
+ version: "1.0"
33
+ project:
34
+ name: "my-service"
35
+ layers:
36
+ - name: "domain"
37
+ path: "src/domain"
38
+ canImport: []
39
+ - name: "application"
40
+ path: "src/application"
41
+ canImport: ["domain"]
42
+ - name: "infrastructure"
43
+ path: "src/infrastructure"
44
+ canImport: ["domain", "application"]
45
+ rules:
46
+ enforceLayerBoundaries: true
139
47
  ```
140
48
 
141
- ## Rule Enforcement & Verification
142
-
143
- ArchForge X enforces rules through a combination of static analysis and framework-specific configurations:
144
-
145
- 1. **Local Enforcement**: During `sync`, ArchForge configures tools like ESLint with `import/no-restricted-paths` to provide real-time feedback in your IDE.
146
- 2. **CI Verification**: Running `archforge validate` in your CI pipeline ensures that no code violating the architecture is merged.
147
- 3. **Fixing Violations**: If a violation is detected (e.g., a Domain entity importing from Infrastructure), the CLI will provide a detailed report pointing to the offending file and rule.
148
-
149
- ## Running the Project
150
-
151
- ### Local Development
49
+ ### 3. Validate Your Code
50
+ Check if your code adheres to the defined architecture.
152
51
 
153
52
  ```bash
154
- # Install dependencies
155
- npm install
156
-
157
- # Start in development mode with hot-reload
158
- npm run start:dev
53
+ archforge validate
159
54
  ```
160
55
 
161
- ### Docker-Based Development
56
+ ### 4. Visualize Dependencies
57
+ Generate a graph of your project's architecture.
162
58
 
163
59
  ```bash
164
- # Build and start all services (App, Database, Redis)
165
- docker-compose up --build
60
+ archforge graph --output architecture.svg
166
61
  ```
167
62
 
168
- ### Environment Variables
63
+ ## Documentation
169
64
 
170
- ArchForge generates a `.env.example` file. Copy it to `.env` and configure your secrets:
171
- - `PORT`: Server port (default: 3000)
172
- - `DATABASE_URL`: Connection string for your database.
173
- - `REDIS_URL`: Connection string for Redis caching.
65
+ For a deep dive into defining rules and best practices, check out the [Rules & Validation Guide](docs/RULES_GUIDE.md).
174
66
 
175
- ## Team & Company Usage
67
+ ## CLI Commands
176
68
 
177
- ArchForge X is designed for engineering organizations to:
178
- - **Standardize**: Ensure every microservice or project follows the same structural patterns.
179
- - **Onboard**: New developers can navigate any project instantly because the structure is predictable.
180
- - **Scale**: Enforce best practices across hundreds of repositories without manual code reviews for "folder structure."
69
+ | Command | Description |
70
+ | :--- | :--- |
71
+ | `archforge init` | Interactive wizard to setup a project. |
72
+ | `archforge generate` | Scaffold a new project based on the config. |
73
+ | `archforge validate` | Check for architectural violations. |
74
+ | `archforge audit` | Deep scan with auto-fix suggestions. |
75
+ | `archforge graph` | Generate a visual dependency graph (SVG). |
76
+ | `archforge sync` | Sync project structure with the config. |
181
77
 
182
- ## Design Philosophy
78
+ ## Supported Frameworks
183
79
 
184
- - **Enforcement over Documentation**: Rules that aren't enforced will eventually be broken.
185
- - **Production-Ready by Default**: Every project starts with the scaffolding needed for a real-world deployment.
186
- - **Config-Driven Flexibility**: The tool adapts to your team's preferred patterns, not the other way around.
80
+ Currently, ArchForge X specializes in TypeScript backends:
81
+ * Express.js (Clean Architecture / DDD)
82
+ * NestJS (Modular / Hexagonal)
187
83
 
188
- ## Contributing & License
84
+ ## License
189
85
 
190
- ArchForge X is open-source software licensed under the MIT License. Contributions are welcome via GitHub Pull Requests.
86
+ MIT
@@ -27,36 +27,6 @@ const parseImportsTS = (content, filePath) => {
27
27
  });
28
28
  return imports;
29
29
  };
30
- const parseImportsPython = (content) => {
31
- const imports = [];
32
- const lines = content.split("\n");
33
- for (const line of lines) {
34
- const trimmed = line.trim();
35
- const fromMatch = trimmed.match(/^from\s+([\w\.]+)\s+import/);
36
- if (fromMatch)
37
- imports.push(fromMatch[1].replace(/\./g, "/"));
38
- const importMatch = trimmed.match(/^import\s+([\w\.]+)/);
39
- if (importMatch)
40
- imports.push(importMatch[1].replace(/\./g, "/"));
41
- }
42
- return imports;
43
- };
44
- const parseImportsGo = (content) => {
45
- const imports = [];
46
- const singleMatch = content.matchAll(/import\s+"(.+)"/g);
47
- for (const m of singleMatch)
48
- imports.push(m[1]);
49
- const multiBlock = content.match(/import\s+\(([\s\S]*?)\)/);
50
- if (multiBlock) {
51
- const lines = multiBlock[1].split("\n");
52
- for (const line of lines) {
53
- const clean = line.trim().replace(/"/g, "");
54
- if (clean)
55
- imports.push(clean);
56
- }
57
- }
58
- return imports;
59
- };
60
30
  // --- CORE ANALYZER ---
61
31
  function analyzeDependencies(arch, options = {}) {
62
32
  const violations = [];
@@ -96,15 +66,15 @@ function analyzeDependencies(arch, options = {}) {
96
66
  const fullPath = path_1.default.join(absoluteFolderPath, entry);
97
67
  const stat = fs_extra_1.default.statSync(fullPath);
98
68
  if (stat.isDirectory()) {
99
- if (["node_modules", "__pycache__", ".git", "dist"].includes(entry))
69
+ if (["node_modules", ".git", "dist"].includes(entry))
100
70
  continue;
101
71
  scanFolder(fullPath);
102
72
  }
103
73
  else if (stat.isFile()) {
104
- if (options.ignoreTests && (entry.includes(".spec") || entry.includes("_test")))
74
+ if (options.ignoreTests && (entry.includes(".spec") || entry.includes(".test")))
105
75
  continue;
106
76
  const ext = path_1.default.extname(entry);
107
- if ([".ts", ".js", ".py", ".go", ".tsx", ".jsx"].includes(ext)) {
77
+ if ([".ts", ".js", ".tsx", ".jsx"].includes(ext)) {
108
78
  checkFileImports(fullPath, ext);
109
79
  }
110
80
  }
@@ -118,15 +88,12 @@ function analyzeDependencies(arch, options = {}) {
118
88
  let imports = [];
119
89
  if ([".ts", ".tsx", ".js", ".jsx"].includes(ext))
120
90
  imports = parseImportsTS(content, filePath);
121
- else if (ext === ".py")
122
- imports = parseImportsPython(content);
123
- else if (ext === ".go")
124
- imports = parseImportsGo(content);
125
91
  for (const importStr of imports) {
126
92
  const importedLayer = resolveImportedLayer(filePath, importStr);
127
93
  if (!importedLayer || importedLayer.name === currentLayer.name)
128
94
  continue;
129
- if (currentLayer.forbiddenImports?.includes(importedLayer.name)) {
95
+ const canImport = currentLayer.canImport || currentLayer.allowedImports || [];
96
+ if (!canImport.includes(importedLayer.name)) {
130
97
  violations.push({
131
98
  file: path_1.default.relative(projectRoot, filePath),
132
99
  fromLayer: currentLayer.name,
@@ -136,16 +103,6 @@ function analyzeDependencies(arch, options = {}) {
136
103
  severity: "error"
137
104
  });
138
105
  }
139
- if (currentLayer.allowedImports && !currentLayer.allowedImports.includes(importedLayer.name)) {
140
- violations.push({
141
- file: path_1.default.relative(projectRoot, filePath),
142
- fromLayer: currentLayer.name,
143
- importedLayer: importedLayer.name,
144
- importPath: importStr,
145
- type: "allowed",
146
- severity: "warning"
147
- });
148
- }
149
106
  }
150
107
  }
151
108
  arch.layers.forEach((layer) => scanFolder(layer.path));
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const express_1 = require("express");
4
+ const user_service_1 = require("../../services/user.service");
5
+ const memory_cache_1 = require("../../infrastructure/cache/memory.cache");
6
+ const http_status_codes_1 = require("http-status-codes");
7
+ const router = (0, express_1.Router)();
8
+ const cache = new memory_cache_1.MemoryCache();
9
+ const userService = new user_service_1.UserService(cache);
10
+ router.post("/", async (req, res) => {
11
+ const user = await userService.create(req.body.name, req.body.email);
12
+ res.status(http_status_codes_1.StatusCodes.CREATED).json(user);
13
+ });
14
+ router.get("/:id", async (req, res) => {
15
+ const user = await userService.getById(req.params.id);
16
+ res.status(http_status_codes_1.StatusCodes.OK).json(user);
17
+ });
18
+ exports.default = router;
@@ -0,0 +1,105 @@
1
+ "use strict";
2
+ // src/cli/commands/init-template.ts
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.initTemplateCommand = initTemplateCommand;
8
+ const chalk_1 = __importDefault(require("chalk"));
9
+ const path_1 = __importDefault(require("path"));
10
+ const resolver_1 = require("../../discovery/resolver");
11
+ const fetcher_1 = require("../../orchestration/fetcher");
12
+ const configurator_1 = require("../../orchestration/configurator");
13
+ const installer_1 = require("../../orchestration/installer");
14
+ const compatibility_1 = require("../../validation/compatibility");
15
+ async function initTemplateCommand(options) {
16
+ try {
17
+ console.log(chalk_1.default.blue.bold('\nšŸš€ ArchForge X - Template Initialization\n'));
18
+ // Step 1: Resolve template
19
+ console.log(chalk_1.default.cyan('šŸ“‹ Step 1: Resolving template...'));
20
+ const resolver = new resolver_1.TemplateResolver();
21
+ const resolved = await resolver.resolve({
22
+ language: options.language,
23
+ framework: options.framework,
24
+ architecture: options.architecture,
25
+ orm: options.orm,
26
+ database: options.database,
27
+ templateId: options.templateId,
28
+ templateUrl: options.templateUrl,
29
+ version: options.version,
30
+ });
31
+ // Step 2: Fetch template
32
+ console.log(chalk_1.default.cyan('\nšŸ“„ Step 2: Fetching template...'));
33
+ const fetcher = new fetcher_1.TemplateFetcher();
34
+ const { templatePath, metadata } = await fetcher.fetch(resolved, {
35
+ cache: true,
36
+ shallow: true,
37
+ });
38
+ // Step 3: Check compatibility
39
+ console.log(chalk_1.default.cyan('\nšŸ” Step 3: Checking compatibility...'));
40
+ const checker = new compatibility_1.CompatibilityChecker();
41
+ const compatibility = await checker.checkCompatibility(metadata, { strict: false });
42
+ checker.displayReport(compatibility, metadata);
43
+ if (!compatibility.compatible) {
44
+ console.log(chalk_1.default.red('\nāŒ Compatibility check failed. Use --skip-compatibility to proceed anyway.'));
45
+ if (!options.skipInstall) {
46
+ process.exit(1);
47
+ }
48
+ }
49
+ // Step 4: Configure template
50
+ console.log(chalk_1.default.cyan('\nšŸ”§ Step 4: Configuring template...'));
51
+ const configurator = new configurator_1.TemplateConfigurator();
52
+ const projectName = options.projectName || 'my-project';
53
+ const projectConfig = {
54
+ projectName,
55
+ language: options.language,
56
+ framework: options.framework,
57
+ architecture: options.architecture,
58
+ orm: options.orm,
59
+ database: options.database,
60
+ modules: options.modules,
61
+ authorName: options.authorName,
62
+ authorEmail: options.authorEmail,
63
+ license: options.license,
64
+ };
65
+ const { configuredPath } = await configurator.configure(templatePath, projectConfig, path_1.default.resolve(projectName));
66
+ // Step 5: Install dependencies
67
+ if (!options.skipInstall) {
68
+ console.log(chalk_1.default.cyan('\nšŸ“¦ Step 5: Installing dependencies...'));
69
+ const installer = new installer_1.DependencyInstaller();
70
+ const installResult = await installer.install(configuredPath, metadata, {
71
+ packageManager: options.packageManager,
72
+ production: false,
73
+ skipPostInstall: options.skipPostInstall,
74
+ });
75
+ if (!installResult.success) {
76
+ console.log(chalk_1.default.yellow('\nāš ļø Dependency installation had issues. You may need to install manually.'));
77
+ }
78
+ // Display post-install instructions
79
+ installer.displayInstructions(metadata);
80
+ }
81
+ else {
82
+ console.log(chalk_1.default.yellow('\nā­ļø Skipping dependency installation'));
83
+ }
84
+ // Success message
85
+ console.log(chalk_1.default.green.bold(`\nāœ… Project "${projectName}" created successfully!`));
86
+ console.log(chalk_1.default.blue('\nšŸ“ Location:'), path_1.default.resolve(configuredPath));
87
+ console.log(chalk_1.default.blue('\nšŸ“ Next steps:'));
88
+ console.log(chalk_1.default.gray(` cd ${projectName}`));
89
+ if (options.skipInstall) {
90
+ console.log(chalk_1.default.gray(` npm install`));
91
+ }
92
+ // Get start command from template or use default
93
+ const startCommand = metadata.postInstall?.scripts?.find((s) => s.includes('start')) || 'npm run start:dev';
94
+ console.log(chalk_1.default.gray(` ${startCommand}`));
95
+ console.log(chalk_1.default.blue('\nšŸ’” Tip: Run "archforge validate" to check your project architecture\n'));
96
+ }
97
+ catch (error) {
98
+ console.error(chalk_1.default.red.bold('\nāŒ Initialization failed:'));
99
+ console.error(chalk_1.default.red(error.message));
100
+ if (error.stack) {
101
+ console.error(chalk_1.default.gray(error.stack));
102
+ }
103
+ process.exit(1);
104
+ }
105
+ }
@@ -9,14 +9,22 @@ const chalk_1 = __importDefault(require("chalk"));
9
9
  async function syncCommand() {
10
10
  const projectRoot = process.cwd();
11
11
  const validator = new validator_1.ArchitectureValidator();
12
- console.log(chalk_1.default.blue("šŸ”„ Syncing architecture with archforge.yaml..."));
12
+ console.log(chalk_1.default.blue("šŸ”„ Syncing architecture with architecture-rules.json..."));
13
13
  const result = await validator.validate(projectRoot);
14
+ if (result.warnings.length > 0) {
15
+ console.log(chalk_1.default.yellow("\nāš ļø Warnings:"));
16
+ result.warnings.forEach(warn => console.log(chalk_1.default.yellow(` - ${warn}`)));
17
+ }
14
18
  if (result.success) {
15
- console.log(chalk_1.default.green.bold("āœ… Architecture is valid and in sync!"));
19
+ console.log(chalk_1.default.green.bold("\nāœ… Architecture is valid and in sync!"));
20
+ if (result.warnings.length > 0) {
21
+ console.log(chalk_1.default.gray(" (Some warnings were found but do not block sync)"));
22
+ }
16
23
  }
17
24
  else {
18
- console.log(chalk_1.default.red.bold("āŒ Architecture violations found:"));
25
+ console.log(chalk_1.default.red.bold("\nāŒ Architecture violations found:"));
19
26
  result.errors.forEach(err => console.log(chalk_1.default.red(` - ${err}`)));
27
+ console.log(chalk_1.default.yellow("\nšŸ’” Tip: Fix these violations to ensure architectural compliance."));
20
28
  process.exit(1);
21
29
  }
22
30
  }