@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 CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  <p align="center">
8
8
  <strong>Agent-Native Fullstack Framework CLI</strong><br/>
9
- A development OS where architecture stays intact even when AI agents write your code
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
- ## Quick Start
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
- ## Commands
35
-
36
- ### `mandu init <project-name>`
28
+ ## Quick Start
37
29
 
38
- Creates a new Mandu project.
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
- Generated structure:
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
- ### `mandu spec`
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
- Validates the spec file and updates the lock file.
58
+ ### 4. Build for Production
70
59
 
71
60
  ```bash
72
- bun run spec
61
+ bunx mandu build
73
62
  ```
74
63
 
75
- ### `mandu generate`
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
- Generates code based on the spec.
126
+ ## Workflow
127
+
128
+ ### Modern Workflow (Recommended)
78
129
 
79
130
  ```bash
80
- bun run generate
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
- ### `mandu guard`
140
+ # 3. Start development
141
+ bun run dev
142
+ ```
84
143
 
85
- Checks architecture rules and auto-corrects violations.
144
+ ### With Architecture Guard
86
145
 
87
146
  ```bash
88
- bun run guard
147
+ # Development with Guard watching
148
+ bunx mandu dev --guard
89
149
 
90
- # Disable auto-correction
91
- bunx mandu guard --no-auto-correct
150
+ # Or run Guard separately
151
+ bunx mandu guard arch --watch
92
152
  ```
93
153
 
94
- Auto-correctable rules:
95
- - `SPEC_HASH_MISMATCH` → Updates lock file
96
- - `GENERATED_MANUAL_EDIT` → Regenerates code
97
- - `SLOT_NOT_FOUND` Creates slot file
98
-
99
- ## Writing Spec Files
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
- ### Slot System (v0.2.0+)
162
+ ---
125
163
 
126
- Add `slotModule` to separate business logic:
164
+ ## FS Routes
127
165
 
128
- ```json
129
- {
130
- "id": "getUsers",
131
- "pattern": "/api/users",
132
- "kind": "api",
133
- "module": "apps/server/api/users.generated.ts",
134
- "slotModule": "apps/server/api/users.slot.ts"
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
- - `*.generated.ts` - Managed by framework (do not modify)
139
- - `*.slot.ts` - Business logic written by developers
185
+ ### Special Files
140
186
 
141
- ## Development Workflow
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
- ```bash
144
- # 1. Edit spec
145
- # 2. Validate spec and update lock
146
- bun run spec
197
+ ---
147
198
 
148
- # 3. Generate code
149
- bun run generate
199
+ ## Guard Presets
150
200
 
151
- # 4. Check architecture
152
- bun run guard
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
- # 5. Run tests
155
- bun test
209
+ ```bash
210
+ # List all presets
211
+ bunx mandu guard arch --list-presets
156
212
 
157
- # 6. Start dev server
158
- bun run dev
213
+ # Use specific preset
214
+ bunx mandu guard arch --preset fsd
159
215
  ```
160
216
 
161
- ## Testing
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
- Built-in support for Bun test framework.
261
+ ## Examples
164
262
 
165
263
  ```bash
166
- bun test # Run tests
167
- bun test --watch # Watch mode
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.12",
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.10"
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
+ }