@mandujs/cli 0.9.12 → 0.9.18
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/README.md +224 -98
- package/package.json +2 -2
- package/src/commands/check.ts +204 -0
- package/src/commands/dev.ts +204 -67
- package/src/commands/doctor.ts +2 -2
- package/src/commands/guard-arch.ts +256 -0
- package/src/commands/routes.ts +218 -0
- package/src/main.ts +138 -42
- package/src/util/fs.ts +23 -4
- package/src/util/output.ts +41 -0
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
<p align="center">
|
|
8
8
|
<strong>Agent-Native Fullstack Framework CLI</strong><br/>
|
|
9
|
-
|
|
9
|
+
Architecture stays intact even when AI agents write your code
|
|
10
10
|
</p>
|
|
11
11
|
|
|
12
12
|
<p align="center">
|
|
@@ -16,47 +16,26 @@
|
|
|
16
16
|
## Installation
|
|
17
17
|
|
|
18
18
|
```bash
|
|
19
|
-
# Bun required
|
|
20
19
|
bun add -D @mandujs/cli
|
|
21
20
|
```
|
|
22
21
|
|
|
23
|
-
|
|
22
|
+
Or use directly with `bunx`:
|
|
24
23
|
|
|
25
24
|
```bash
|
|
26
|
-
# Create a new project
|
|
27
25
|
bunx @mandujs/cli init my-app
|
|
28
|
-
cd my-app
|
|
29
|
-
|
|
30
|
-
# Start development server
|
|
31
|
-
bun run dev
|
|
32
26
|
```
|
|
33
27
|
|
|
34
|
-
##
|
|
35
|
-
|
|
36
|
-
### `mandu init <project-name>`
|
|
28
|
+
## Quick Start
|
|
37
29
|
|
|
38
|
-
|
|
30
|
+
### 1. Create a New Project
|
|
39
31
|
|
|
40
32
|
```bash
|
|
41
33
|
bunx @mandujs/cli init my-app
|
|
34
|
+
cd my-app
|
|
35
|
+
bun install
|
|
42
36
|
```
|
|
43
37
|
|
|
44
|
-
|
|
45
|
-
```
|
|
46
|
-
my-app/
|
|
47
|
-
├── apps/
|
|
48
|
-
│ ├── server/main.ts # Server entry point
|
|
49
|
-
│ └── web/entry.tsx # Client entry point
|
|
50
|
-
├── spec/
|
|
51
|
-
│ └── routes.manifest.json # SSOT - Route definitions
|
|
52
|
-
├── tests/ # Test templates
|
|
53
|
-
├── package.json
|
|
54
|
-
└── tsconfig.json
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
### `mandu dev`
|
|
58
|
-
|
|
59
|
-
Starts the development server (with HMR support).
|
|
38
|
+
### 2. Start Development Server
|
|
60
39
|
|
|
61
40
|
```bash
|
|
62
41
|
bun run dev
|
|
@@ -64,117 +43,264 @@ bun run dev
|
|
|
64
43
|
bunx mandu dev
|
|
65
44
|
```
|
|
66
45
|
|
|
67
|
-
|
|
46
|
+
Your app is now running at `http://localhost:3000`.
|
|
47
|
+
|
|
48
|
+
### 3. Create Pages in `app/` Directory
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
app/
|
|
52
|
+
├── page.tsx → /
|
|
53
|
+
├── about/page.tsx → /about
|
|
54
|
+
├── users/[id]/page.tsx → /users/:id
|
|
55
|
+
└── api/hello/route.ts → /api/hello
|
|
56
|
+
```
|
|
68
57
|
|
|
69
|
-
|
|
58
|
+
### 4. Build for Production
|
|
70
59
|
|
|
71
60
|
```bash
|
|
72
|
-
|
|
61
|
+
bunx mandu build
|
|
73
62
|
```
|
|
74
63
|
|
|
75
|
-
|
|
64
|
+
That's it!
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Commands
|
|
69
|
+
|
|
70
|
+
### Core Commands
|
|
71
|
+
|
|
72
|
+
| Command | Description |
|
|
73
|
+
|---------|-------------|
|
|
74
|
+
| `mandu init [name]` | Create new project |
|
|
75
|
+
| `mandu dev` | Start dev server (FS Routes + HMR) |
|
|
76
|
+
| `mandu build` | Build for production |
|
|
77
|
+
|
|
78
|
+
### FS Routes Commands
|
|
79
|
+
|
|
80
|
+
| Command | Description |
|
|
81
|
+
|---------|-------------|
|
|
82
|
+
| `mandu routes list` | Show all routes |
|
|
83
|
+
| `mandu routes generate` | Generate routes manifest |
|
|
84
|
+
| `mandu routes watch` | Watch for route changes |
|
|
85
|
+
|
|
86
|
+
### Guard Commands
|
|
87
|
+
|
|
88
|
+
| Command | Description |
|
|
89
|
+
|---------|-------------|
|
|
90
|
+
| `mandu guard arch` | Run architecture check (default: mandu preset) |
|
|
91
|
+
| `mandu guard arch --watch` | Watch mode |
|
|
92
|
+
| `mandu guard arch --ci` | CI mode (exit 1 on errors) |
|
|
93
|
+
| `mandu guard arch --preset fsd` | Use specific preset |
|
|
94
|
+
| `mandu guard arch --output report.md` | Generate report |
|
|
95
|
+
|
|
96
|
+
### Transaction Commands
|
|
97
|
+
|
|
98
|
+
| Command | Description |
|
|
99
|
+
|---------|-------------|
|
|
100
|
+
| `mandu change begin` | Start transaction (creates snapshot) |
|
|
101
|
+
| `mandu change commit` | Finalize changes |
|
|
102
|
+
| `mandu change rollback` | Restore from snapshot |
|
|
103
|
+
| `mandu change status` | Show current state |
|
|
104
|
+
| `mandu change list` | View history |
|
|
105
|
+
|
|
106
|
+
### Brain Commands
|
|
107
|
+
|
|
108
|
+
| Command | Description |
|
|
109
|
+
|---------|-------------|
|
|
110
|
+
| `mandu doctor` | Analyze Guard failures + suggest patches |
|
|
111
|
+
| `mandu watch` | Real-time file monitoring |
|
|
112
|
+
| `mandu brain setup` | Configure sLLM (optional) |
|
|
113
|
+
| `mandu brain status` | Check Brain status |
|
|
114
|
+
|
|
115
|
+
### Contract & OpenAPI Commands
|
|
116
|
+
|
|
117
|
+
| Command | Description |
|
|
118
|
+
|---------|-------------|
|
|
119
|
+
| `mandu contract create <routeId>` | Create contract for route |
|
|
120
|
+
| `mandu contract validate` | Validate contract-slot consistency |
|
|
121
|
+
| `mandu openapi generate` | Generate OpenAPI 3.0 spec |
|
|
122
|
+
| `mandu openapi serve` | Start Swagger UI server |
|
|
123
|
+
|
|
124
|
+
---
|
|
76
125
|
|
|
77
|
-
|
|
126
|
+
## Workflow
|
|
127
|
+
|
|
128
|
+
### Modern Workflow (Recommended)
|
|
78
129
|
|
|
79
130
|
```bash
|
|
80
|
-
|
|
81
|
-
|
|
131
|
+
# 1. Create project
|
|
132
|
+
bunx @mandujs/cli init my-app
|
|
133
|
+
cd my-app && bun install
|
|
134
|
+
|
|
135
|
+
# 2. Create pages
|
|
136
|
+
# app/page.tsx → /
|
|
137
|
+
# app/users/page.tsx → /users
|
|
138
|
+
# app/api/users/route.ts → /api/users
|
|
82
139
|
|
|
83
|
-
|
|
140
|
+
# 3. Start development
|
|
141
|
+
bun run dev
|
|
142
|
+
```
|
|
84
143
|
|
|
85
|
-
|
|
144
|
+
### With Architecture Guard
|
|
86
145
|
|
|
87
146
|
```bash
|
|
88
|
-
|
|
147
|
+
# Development with Guard watching
|
|
148
|
+
bunx mandu dev --guard
|
|
89
149
|
|
|
90
|
-
#
|
|
91
|
-
bunx mandu guard --
|
|
150
|
+
# Or run Guard separately
|
|
151
|
+
bunx mandu guard arch --watch
|
|
92
152
|
```
|
|
93
153
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
`spec/routes.manifest.json` is the Single Source of Truth (SSOT) for all routes.
|
|
102
|
-
|
|
103
|
-
```json
|
|
104
|
-
{
|
|
105
|
-
"version": "1.0.0",
|
|
106
|
-
"routes": [
|
|
107
|
-
{
|
|
108
|
-
"id": "getUsers",
|
|
109
|
-
"pattern": "/api/users",
|
|
110
|
-
"kind": "api",
|
|
111
|
-
"module": "apps/server/api/users.ts"
|
|
112
|
-
},
|
|
113
|
-
{
|
|
114
|
-
"id": "homePage",
|
|
115
|
-
"pattern": "/",
|
|
116
|
-
"kind": "page",
|
|
117
|
-
"module": "apps/server/pages/home.ts",
|
|
118
|
-
"componentModule": "apps/web/pages/Home.tsx"
|
|
119
|
-
}
|
|
120
|
-
]
|
|
121
|
-
}
|
|
154
|
+
### CI/CD Integration
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
# Build and check
|
|
158
|
+
bunx mandu build --minify
|
|
159
|
+
bunx mandu guard arch --ci --format json
|
|
122
160
|
```
|
|
123
161
|
|
|
124
|
-
|
|
162
|
+
---
|
|
125
163
|
|
|
126
|
-
|
|
164
|
+
## FS Routes
|
|
127
165
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
166
|
+
Create routes by adding files to `app/`:
|
|
167
|
+
|
|
168
|
+
```
|
|
169
|
+
app/
|
|
170
|
+
├── page.tsx → /
|
|
171
|
+
├── layout.tsx → Layout for all pages
|
|
172
|
+
├── users/
|
|
173
|
+
│ ├── page.tsx → /users
|
|
174
|
+
│ ├── [id]/
|
|
175
|
+
│ │ └── page.tsx → /users/:id
|
|
176
|
+
│ └── [...slug]/
|
|
177
|
+
│ └── page.tsx → /users/*
|
|
178
|
+
├── api/
|
|
179
|
+
│ └── users/
|
|
180
|
+
│ └── route.ts → /api/users
|
|
181
|
+
└── (auth)/ → Group (no URL segment)
|
|
182
|
+
└── login/page.tsx → /login
|
|
136
183
|
```
|
|
137
184
|
|
|
138
|
-
|
|
139
|
-
- `*.slot.ts` - Business logic written by developers
|
|
185
|
+
### Special Files
|
|
140
186
|
|
|
141
|
-
|
|
187
|
+
| File | Purpose |
|
|
188
|
+
|------|---------|
|
|
189
|
+
| `page.tsx` | Page component |
|
|
190
|
+
| `layout.tsx` | Shared layout |
|
|
191
|
+
| `route.ts` | API endpoint |
|
|
192
|
+
| `loading.tsx` | Loading state |
|
|
193
|
+
| `error.tsx` | Error boundary |
|
|
194
|
+
| `slot.ts` | Business logic |
|
|
195
|
+
| `client.tsx` | Interactive component (Island) |
|
|
142
196
|
|
|
143
|
-
|
|
144
|
-
# 1. Edit spec
|
|
145
|
-
# 2. Validate spec and update lock
|
|
146
|
-
bun run spec
|
|
197
|
+
---
|
|
147
198
|
|
|
148
|
-
|
|
149
|
-
bun run generate
|
|
199
|
+
## Guard Presets
|
|
150
200
|
|
|
151
|
-
|
|
152
|
-
|
|
201
|
+
| Preset | Description |
|
|
202
|
+
|--------|-------------|
|
|
203
|
+
| `mandu` | FSD + Clean Architecture (default) |
|
|
204
|
+
| `fsd` | Feature-Sliced Design |
|
|
205
|
+
| `clean` | Clean Architecture |
|
|
206
|
+
| `hexagonal` | Hexagonal Architecture |
|
|
207
|
+
| `atomic` | Atomic Design |
|
|
153
208
|
|
|
154
|
-
|
|
155
|
-
|
|
209
|
+
```bash
|
|
210
|
+
# List all presets
|
|
211
|
+
bunx mandu guard arch --list-presets
|
|
156
212
|
|
|
157
|
-
#
|
|
158
|
-
|
|
213
|
+
# Use specific preset
|
|
214
|
+
bunx mandu guard arch --preset fsd
|
|
159
215
|
```
|
|
160
216
|
|
|
161
|
-
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## Options Reference
|
|
220
|
+
|
|
221
|
+
### `mandu dev`
|
|
222
|
+
|
|
223
|
+
| Option | Description |
|
|
224
|
+
|--------|-------------|
|
|
225
|
+
| `--port <n>` | Server port (default: 3000) |
|
|
226
|
+
| `--guard` | Enable Guard watching |
|
|
227
|
+
| `--guard-preset <p>` | Guard preset (default: mandu) |
|
|
228
|
+
|
|
229
|
+
### `mandu build`
|
|
230
|
+
|
|
231
|
+
| Option | Description |
|
|
232
|
+
|--------|-------------|
|
|
233
|
+
| `--minify` | Minify output |
|
|
234
|
+
| `--sourcemap` | Generate sourcemaps |
|
|
235
|
+
| `--watch` | Watch mode |
|
|
236
|
+
|
|
237
|
+
### `mandu guard arch`
|
|
238
|
+
|
|
239
|
+
| Option | Description |
|
|
240
|
+
|--------|-------------|
|
|
241
|
+
| `--preset <p>` | Preset: fsd, clean, hexagonal, atomic, mandu |
|
|
242
|
+
| `--watch` | Watch mode |
|
|
243
|
+
| `--ci` | CI mode (exit 1 on errors) |
|
|
244
|
+
| `--quiet` | Summary only |
|
|
245
|
+
| `--format <f>` | Output: console, agent, json |
|
|
246
|
+
| `--output <path>` | Report file path |
|
|
247
|
+
| `--report-format <f>` | Report: json, markdown, html |
|
|
248
|
+
| `--save-stats` | Save for trend analysis |
|
|
249
|
+
| `--show-trend` | Show trend analysis |
|
|
250
|
+
|
|
251
|
+
### `mandu doctor`
|
|
252
|
+
|
|
253
|
+
| Option | Description |
|
|
254
|
+
|--------|-------------|
|
|
255
|
+
| `--format <f>` | Output: console, json, markdown |
|
|
256
|
+
| `--no-llm` | Template mode (no LLM) |
|
|
257
|
+
| `--output <path>` | Output file path |
|
|
258
|
+
|
|
259
|
+
---
|
|
162
260
|
|
|
163
|
-
|
|
261
|
+
## Examples
|
|
164
262
|
|
|
165
263
|
```bash
|
|
166
|
-
|
|
167
|
-
|
|
264
|
+
# Initialize project
|
|
265
|
+
bunx @mandujs/cli init my-app
|
|
266
|
+
|
|
267
|
+
# Development
|
|
268
|
+
bunx mandu dev --port 3000
|
|
269
|
+
bunx mandu dev --guard
|
|
270
|
+
|
|
271
|
+
# Routes
|
|
272
|
+
bunx mandu routes list
|
|
273
|
+
bunx mandu routes generate
|
|
274
|
+
|
|
275
|
+
# Guard
|
|
276
|
+
bunx mandu guard arch
|
|
277
|
+
bunx mandu guard arch --watch
|
|
278
|
+
bunx mandu guard arch --ci --format json
|
|
279
|
+
bunx mandu guard arch --output report.md
|
|
280
|
+
|
|
281
|
+
# Transactions
|
|
282
|
+
bunx mandu change begin --message "Add users API"
|
|
283
|
+
bunx mandu change commit
|
|
284
|
+
bunx mandu change rollback
|
|
285
|
+
|
|
286
|
+
# Doctor
|
|
287
|
+
bunx mandu doctor
|
|
288
|
+
bunx mandu doctor --format json
|
|
289
|
+
|
|
290
|
+
# Build
|
|
291
|
+
bunx mandu build --minify --sourcemap
|
|
168
292
|
```
|
|
169
293
|
|
|
294
|
+
---
|
|
295
|
+
|
|
170
296
|
## Requirements
|
|
171
297
|
|
|
172
298
|
- Bun >= 1.0.0
|
|
173
|
-
- React >= 18.0.0
|
|
174
299
|
|
|
175
300
|
## Related Packages
|
|
176
301
|
|
|
177
302
|
- [@mandujs/core](https://www.npmjs.com/package/@mandujs/core) - Core runtime
|
|
303
|
+
- [@mandujs/mcp](https://www.npmjs.com/package/@mandujs/mcp) - MCP server
|
|
178
304
|
|
|
179
305
|
## License
|
|
180
306
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mandujs/cli",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.18",
|
|
4
4
|
"description": "Agent-Native Fullstack Framework - 에이전트가 코딩해도 아키텍처가 무너지지 않는 개발 OS",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/main.ts",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"access": "public"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@mandujs/core": "0.9.
|
|
35
|
+
"@mandujs/core": "0.9.38"
|
|
36
36
|
},
|
|
37
37
|
"engines": {
|
|
38
38
|
"bun": ">=1.0.0"
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mandu check - Workflow Check Command
|
|
3
|
+
*
|
|
4
|
+
* FS Routes + Architecture Guard + Legacy Guard 통합 검사
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
generateManifest,
|
|
9
|
+
scanRoutes,
|
|
10
|
+
checkDirectory,
|
|
11
|
+
printReport,
|
|
12
|
+
getPreset,
|
|
13
|
+
loadManifest,
|
|
14
|
+
runGuardCheck,
|
|
15
|
+
buildGuardReport,
|
|
16
|
+
printReportSummary,
|
|
17
|
+
type GuardConfig,
|
|
18
|
+
type GuardPreset,
|
|
19
|
+
} from "@mandujs/core";
|
|
20
|
+
import path from "path";
|
|
21
|
+
import { resolveFromCwd, isDirectory, pathExists } from "../util/fs";
|
|
22
|
+
import { resolveOutputFormat, type OutputFormat } from "../util/output";
|
|
23
|
+
|
|
24
|
+
export interface CheckOptions {
|
|
25
|
+
preset?: GuardPreset;
|
|
26
|
+
format?: OutputFormat;
|
|
27
|
+
ci?: boolean;
|
|
28
|
+
quiet?: boolean;
|
|
29
|
+
legacy?: boolean;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export async function check(options: CheckOptions = {}): Promise<boolean> {
|
|
33
|
+
const rootDir = resolveFromCwd(".");
|
|
34
|
+
const preset = options.preset ?? "mandu";
|
|
35
|
+
const format = resolveOutputFormat(options.format);
|
|
36
|
+
const quiet = options.quiet === true;
|
|
37
|
+
const enableFsRoutes = !options.legacy && await isDirectory(path.resolve(rootDir, "app"));
|
|
38
|
+
const specPath = resolveFromCwd("spec/routes.manifest.json");
|
|
39
|
+
const hasSpec = await pathExists(specPath);
|
|
40
|
+
|
|
41
|
+
let success = true;
|
|
42
|
+
|
|
43
|
+
const log = (message: string) => {
|
|
44
|
+
if (format === "console" && !quiet) {
|
|
45
|
+
console.log(message);
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const print = (message: string) => {
|
|
50
|
+
if (format === "console") {
|
|
51
|
+
console.log(message);
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
if (format === "console") {
|
|
56
|
+
log("🥟 Mandu Check\n");
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// 1) FS Routes 검사
|
|
60
|
+
let routesSummary: { enabled: boolean; count: number; warnings: string[] } = {
|
|
61
|
+
enabled: false,
|
|
62
|
+
count: 0,
|
|
63
|
+
warnings: [],
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
if (enableFsRoutes) {
|
|
67
|
+
routesSummary.enabled = true;
|
|
68
|
+
|
|
69
|
+
try {
|
|
70
|
+
if (format === "console") {
|
|
71
|
+
const result = await generateManifest(rootDir, {
|
|
72
|
+
outputPath: ".mandu/routes.manifest.json",
|
|
73
|
+
skipLegacy: true,
|
|
74
|
+
});
|
|
75
|
+
routesSummary.count = result.manifest.routes.length;
|
|
76
|
+
routesSummary.warnings = result.warnings;
|
|
77
|
+
|
|
78
|
+
if (quiet) {
|
|
79
|
+
print(`✅ FS Routes: ${routesSummary.count}개`);
|
|
80
|
+
} else {
|
|
81
|
+
log(`✅ FS Routes: ${routesSummary.count}개`);
|
|
82
|
+
}
|
|
83
|
+
if (routesSummary.warnings.length > 0) {
|
|
84
|
+
if (!quiet) {
|
|
85
|
+
log("⚠️ 경고:");
|
|
86
|
+
}
|
|
87
|
+
for (const warning of routesSummary.warnings) {
|
|
88
|
+
if (!quiet) {
|
|
89
|
+
log(` - ${warning}`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
if (!quiet) {
|
|
94
|
+
log("");
|
|
95
|
+
}
|
|
96
|
+
} else {
|
|
97
|
+
const scan = await scanRoutes(rootDir);
|
|
98
|
+
routesSummary.count = scan.routes.length;
|
|
99
|
+
routesSummary.warnings = scan.errors.map((e) => `${e.type}: ${e.message}`);
|
|
100
|
+
}
|
|
101
|
+
} catch (error) {
|
|
102
|
+
success = false;
|
|
103
|
+
routesSummary.warnings.push(
|
|
104
|
+
error instanceof Error ? error.message : String(error)
|
|
105
|
+
);
|
|
106
|
+
if (format === "console") {
|
|
107
|
+
console.error("❌ FS Routes 검사 실패:", error);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
} else {
|
|
111
|
+
if (quiet) {
|
|
112
|
+
print("ℹ️ app/ 폴더 없음 - FS Routes 검사 스킵");
|
|
113
|
+
} else {
|
|
114
|
+
log("ℹ️ app/ 폴더 없음 - FS Routes 검사 스킵\n");
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// 2) Architecture Guard 검사
|
|
119
|
+
const guardConfig: GuardConfig = {
|
|
120
|
+
preset,
|
|
121
|
+
srcDir: "src",
|
|
122
|
+
fsRoutes: enableFsRoutes
|
|
123
|
+
? {
|
|
124
|
+
noPageToPage: true,
|
|
125
|
+
pageCanImport: ["widgets", "features", "entities", "shared"],
|
|
126
|
+
layoutCanImport: ["widgets", "shared"],
|
|
127
|
+
}
|
|
128
|
+
: undefined,
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
const report = await checkDirectory(guardConfig, rootDir);
|
|
132
|
+
if (report.bySeverity.error > 0) {
|
|
133
|
+
success = false;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (format === "console") {
|
|
137
|
+
const presetDef = getPreset(preset);
|
|
138
|
+
if (quiet) {
|
|
139
|
+
print(`📊 Architecture: ${report.totalViolations}개 위반 (Errors: ${report.bySeverity.error})`);
|
|
140
|
+
} else {
|
|
141
|
+
printReport(report, presetDef.hierarchy);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// 3) Legacy Guard 검사 (spec 파일이 있을 때만)
|
|
146
|
+
let legacySummary: { enabled: boolean; passed: boolean; violations: number; errors?: string[] } = {
|
|
147
|
+
enabled: false,
|
|
148
|
+
passed: true,
|
|
149
|
+
violations: 0,
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
if (hasSpec) {
|
|
153
|
+
legacySummary.enabled = true;
|
|
154
|
+
|
|
155
|
+
const manifestResult = await loadManifest(specPath);
|
|
156
|
+
if (!manifestResult.success || !manifestResult.data) {
|
|
157
|
+
legacySummary.passed = false;
|
|
158
|
+
legacySummary.errors = manifestResult.errors ?? ["Spec 로드 실패"];
|
|
159
|
+
success = false;
|
|
160
|
+
|
|
161
|
+
if (format === "console") {
|
|
162
|
+
console.error("❌ Spec 로드 실패:");
|
|
163
|
+
manifestResult.errors?.forEach((e) => console.error(` - ${e}`));
|
|
164
|
+
}
|
|
165
|
+
} else {
|
|
166
|
+
const checkResult = await runGuardCheck(manifestResult.data, rootDir);
|
|
167
|
+
legacySummary.passed = checkResult.passed;
|
|
168
|
+
legacySummary.violations = checkResult.violations.length;
|
|
169
|
+
success = success && checkResult.passed;
|
|
170
|
+
|
|
171
|
+
if (format === "console") {
|
|
172
|
+
const legacyReport = buildGuardReport(checkResult);
|
|
173
|
+
if (quiet) {
|
|
174
|
+
print(`📊 Legacy Guard: ${legacySummary.violations}개 위반`);
|
|
175
|
+
} else {
|
|
176
|
+
printReportSummary(legacyReport);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
} else {
|
|
181
|
+
if (quiet) {
|
|
182
|
+
print("ℹ️ spec/routes.manifest.json 없음 - 레거시 Guard 스킵");
|
|
183
|
+
} else {
|
|
184
|
+
log("ℹ️ spec/routes.manifest.json 없음 - 레거시 Guard 스킵");
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (format !== "console") {
|
|
189
|
+
const summary = {
|
|
190
|
+
ok: success,
|
|
191
|
+
routes: routesSummary,
|
|
192
|
+
architecture: {
|
|
193
|
+
totalViolations: report.totalViolations,
|
|
194
|
+
bySeverity: report.bySeverity,
|
|
195
|
+
byType: report.byType,
|
|
196
|
+
report,
|
|
197
|
+
},
|
|
198
|
+
legacy: legacySummary,
|
|
199
|
+
};
|
|
200
|
+
console.log(JSON.stringify(summary, null, 2));
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
return options.ci ? success : success;
|
|
204
|
+
}
|