@mandujs/cli 0.3.2 → 0.3.4

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
@@ -1,181 +1,181 @@
1
- <p align="center">
2
- <img src="https://raw.githubusercontent.com/konamgil/mandu/main/mandu_only_simbol.png" alt="Mandu" width="200" />
3
- </p>
4
-
5
- <h1 align="center">@mandujs/cli</h1>
6
-
7
- <p align="center">
8
- <strong>Agent-Native Fullstack Framework CLI</strong><br/>
9
- A development OS where architecture stays intact even when AI agents write your code
10
- </p>
11
-
12
- <p align="center">
13
- English | <a href="./README.ko.md"><strong>한국어</strong></a>
14
- </p>
15
-
16
- ## Installation
17
-
18
- ```bash
19
- # Bun required
20
- bun add -D @mandujs/cli
21
- ```
22
-
23
- ## Quick Start
24
-
25
- ```bash
26
- # Create a new project
27
- bunx @mandujs/cli init my-app
28
- cd my-app
29
-
30
- # Start development server
31
- bun run dev
32
- ```
33
-
34
- ## Commands
35
-
36
- ### `mandu init <project-name>`
37
-
38
- Creates a new Mandu project.
39
-
40
- ```bash
41
- bunx @mandujs/cli init my-app
42
- ```
43
-
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).
60
-
61
- ```bash
62
- bun run dev
63
- # or
64
- bunx mandu dev
65
- ```
66
-
67
- ### `mandu spec`
68
-
69
- Validates the spec file and updates the lock file.
70
-
71
- ```bash
72
- bun run spec
73
- ```
74
-
75
- ### `mandu generate`
76
-
77
- Generates code based on the spec.
78
-
79
- ```bash
80
- bun run generate
81
- ```
82
-
83
- ### `mandu guard`
84
-
85
- Checks architecture rules and auto-corrects violations.
86
-
87
- ```bash
88
- bun run guard
89
-
90
- # Disable auto-correction
91
- bunx mandu guard --no-auto-correct
92
- ```
93
-
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
- }
122
- ```
123
-
124
- ### Slot System (v0.2.0+)
125
-
126
- Add `slotModule` to separate business logic:
127
-
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
- }
136
- ```
137
-
138
- - `*.generated.ts` - Managed by framework (do not modify)
139
- - `*.slot.ts` - Business logic written by developers
140
-
141
- ## Development Workflow
142
-
143
- ```bash
144
- # 1. Edit spec
145
- # 2. Validate spec and update lock
146
- bun run spec
147
-
148
- # 3. Generate code
149
- bun run generate
150
-
151
- # 4. Check architecture
152
- bun run guard
153
-
154
- # 5. Run tests
155
- bun test
156
-
157
- # 6. Start dev server
158
- bun run dev
159
- ```
160
-
161
- ## Testing
162
-
163
- Built-in support for Bun test framework.
164
-
165
- ```bash
166
- bun test # Run tests
167
- bun test --watch # Watch mode
168
- ```
169
-
170
- ## Requirements
171
-
172
- - Bun >= 1.0.0
173
- - React >= 18.0.0
174
-
175
- ## Related Packages
176
-
177
- - [@mandujs/core](https://www.npmjs.com/package/@mandujs/core) - Core runtime
178
-
179
- ## License
180
-
181
- MIT
1
+ <p align="center">
2
+ <img src="https://raw.githubusercontent.com/konamgil/mandu/main/mandu_only_simbol.png" alt="Mandu" width="200" />
3
+ </p>
4
+
5
+ <h1 align="center">@mandujs/cli</h1>
6
+
7
+ <p align="center">
8
+ <strong>Agent-Native Fullstack Framework CLI</strong><br/>
9
+ A development OS where architecture stays intact even when AI agents write your code
10
+ </p>
11
+
12
+ <p align="center">
13
+ English | <a href="./README.ko.md"><strong>한국어</strong></a>
14
+ </p>
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ # Bun required
20
+ bun add -D @mandujs/cli
21
+ ```
22
+
23
+ ## Quick Start
24
+
25
+ ```bash
26
+ # Create a new project
27
+ bunx @mandujs/cli init my-app
28
+ cd my-app
29
+
30
+ # Start development server
31
+ bun run dev
32
+ ```
33
+
34
+ ## Commands
35
+
36
+ ### `mandu init <project-name>`
37
+
38
+ Creates a new Mandu project.
39
+
40
+ ```bash
41
+ bunx @mandujs/cli init my-app
42
+ ```
43
+
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).
60
+
61
+ ```bash
62
+ bun run dev
63
+ # or
64
+ bunx mandu dev
65
+ ```
66
+
67
+ ### `mandu spec`
68
+
69
+ Validates the spec file and updates the lock file.
70
+
71
+ ```bash
72
+ bun run spec
73
+ ```
74
+
75
+ ### `mandu generate`
76
+
77
+ Generates code based on the spec.
78
+
79
+ ```bash
80
+ bun run generate
81
+ ```
82
+
83
+ ### `mandu guard`
84
+
85
+ Checks architecture rules and auto-corrects violations.
86
+
87
+ ```bash
88
+ bun run guard
89
+
90
+ # Disable auto-correction
91
+ bunx mandu guard --no-auto-correct
92
+ ```
93
+
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
+ }
122
+ ```
123
+
124
+ ### Slot System (v0.2.0+)
125
+
126
+ Add `slotModule` to separate business logic:
127
+
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
+ }
136
+ ```
137
+
138
+ - `*.generated.ts` - Managed by framework (do not modify)
139
+ - `*.slot.ts` - Business logic written by developers
140
+
141
+ ## Development Workflow
142
+
143
+ ```bash
144
+ # 1. Edit spec
145
+ # 2. Validate spec and update lock
146
+ bun run spec
147
+
148
+ # 3. Generate code
149
+ bun run generate
150
+
151
+ # 4. Check architecture
152
+ bun run guard
153
+
154
+ # 5. Run tests
155
+ bun test
156
+
157
+ # 6. Start dev server
158
+ bun run dev
159
+ ```
160
+
161
+ ## Testing
162
+
163
+ Built-in support for Bun test framework.
164
+
165
+ ```bash
166
+ bun test # Run tests
167
+ bun test --watch # Watch mode
168
+ ```
169
+
170
+ ## Requirements
171
+
172
+ - Bun >= 1.0.0
173
+ - React >= 18.0.0
174
+
175
+ ## Related Packages
176
+
177
+ - [@mandujs/core](https://www.npmjs.com/package/@mandujs/core) - Core runtime
178
+
179
+ ## License
180
+
181
+ MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mandujs/cli",
3
- "version": "0.3.2",
3
+ "version": "0.3.4",
4
4
  "description": "Agent-Native Fullstack Framework - 에이전트가 코딩해도 아키텍처가 무너지지 않는 개발 OS",
5
5
  "type": "module",
6
6
  "main": "./src/main.ts",
@@ -32,9 +32,9 @@
32
32
  "access": "public"
33
33
  },
34
34
  "dependencies": {
35
- "@mandujs/core": "^0.2.0"
35
+ "@mandujs/core": "^0.3.3"
36
36
  },
37
- "peerDependencies": {
37
+ "engines": {
38
38
  "bun": ">=1.0.0"
39
39
  }
40
40
  }
@@ -0,0 +1,33 @@
1
+ import { beginChange } from "@mandujs/core";
2
+ import { getRootDir } from "../../util/fs";
3
+
4
+ export interface ChangeBeginOptions {
5
+ message?: string;
6
+ }
7
+
8
+ export async function changeBegin(options: ChangeBeginOptions = {}): Promise<boolean> {
9
+ const rootDir = getRootDir();
10
+
11
+ console.log(`🥟 Mandu Change Begin`);
12
+
13
+ try {
14
+ const change = await beginChange(rootDir, {
15
+ message: options.message,
16
+ });
17
+
18
+ console.log(`✅ 트랜잭션 시작됨`);
19
+ console.log(` ID: ${change.id}`);
20
+ console.log(` 스냅샷: ${change.snapshotId}`);
21
+ if (change.message) {
22
+ console.log(` 메시지: ${change.message}`);
23
+ }
24
+ console.log(`\n💡 변경 작업 후 다음 명령을 실행하세요:`);
25
+ console.log(` 확정: bunx mandu change commit`);
26
+ console.log(` 롤백: bunx mandu change rollback`);
27
+
28
+ return true;
29
+ } catch (error) {
30
+ console.error(`❌ 트랜잭션 시작 실패: ${error instanceof Error ? error.message : String(error)}`);
31
+ return false;
32
+ }
33
+ }
@@ -0,0 +1,23 @@
1
+ import { commitChange } from "@mandujs/core";
2
+ import { getRootDir } from "../../util/fs";
3
+
4
+ export async function changeCommit(): Promise<boolean> {
5
+ const rootDir = getRootDir();
6
+
7
+ console.log(`🥟 Mandu Change Commit`);
8
+
9
+ try {
10
+ const result = await commitChange(rootDir);
11
+
12
+ console.log(`✅ 변경 확정됨`);
13
+ console.log(` ID: ${result.changeId}`);
14
+ if (result.message) {
15
+ console.log(` 메시지: ${result.message}`);
16
+ }
17
+
18
+ return true;
19
+ } catch (error) {
20
+ console.error(`❌ 커밋 실패: ${error instanceof Error ? error.message : String(error)}`);
21
+ return false;
22
+ }
23
+ }
@@ -0,0 +1,6 @@
1
+ export { changeBegin, type ChangeBeginOptions } from "./begin";
2
+ export { changeCommit } from "./commit";
3
+ export { changeRollback, type ChangeRollbackOptions } from "./rollback";
4
+ export { changeStatus } from "./status";
5
+ export { changeList } from "./list";
6
+ export { changePrune, type ChangePruneOptions } from "./prune";
@@ -0,0 +1,57 @@
1
+ import { listChanges, getChangeStats } from "@mandujs/core";
2
+ import { getRootDir } from "../../util/fs";
3
+
4
+ export async function changeList(): Promise<boolean> {
5
+ const rootDir = getRootDir();
6
+
7
+ console.log(`🥟 Mandu Change List\n`);
8
+
9
+ try {
10
+ const changes = await listChanges(rootDir);
11
+ const stats = await getChangeStats(rootDir);
12
+
13
+ if (changes.length === 0) {
14
+ console.log(`📭 변경 이력이 없습니다`);
15
+ console.log(`\n💡 새 트랜잭션 시작: bunx mandu change begin`);
16
+ return true;
17
+ }
18
+
19
+ // 통계
20
+ console.log(`📊 통계:`);
21
+ console.log(` 총 기록: ${stats.total}개`);
22
+ console.log(` 활성: ${stats.active}개 | 확정: ${stats.committed}개 | 롤백: ${stats.rolledBack}개`);
23
+ console.log(` 스냅샷: ${stats.snapshotCount}개\n`);
24
+
25
+ // 최근 기록 (최신 순)
26
+ console.log(`📜 변경 이력:`);
27
+
28
+ const sortedChanges = [...changes].reverse(); // 최신 순
29
+
30
+ for (const change of sortedChanges) {
31
+ const statusIcon =
32
+ change.status === "active"
33
+ ? "🔄"
34
+ : change.status === "committed"
35
+ ? "✅"
36
+ : "↩️";
37
+
38
+ const date = new Date(change.createdAt).toLocaleString();
39
+
40
+ console.log(` ${statusIcon} ${change.id}`);
41
+ console.log(` 상태: ${change.status}`);
42
+ console.log(` 시간: ${date}`);
43
+ if (change.message) {
44
+ console.log(` 메시지: ${change.message}`);
45
+ }
46
+ if (change.autoGenerated) {
47
+ console.log(` 생성: Auto-correct`);
48
+ }
49
+ console.log("");
50
+ }
51
+
52
+ return true;
53
+ } catch (error) {
54
+ console.error(`❌ 이력 조회 실패: ${error instanceof Error ? error.message : String(error)}`);
55
+ return false;
56
+ }
57
+ }
@@ -0,0 +1,32 @@
1
+ import { pruneHistory, DEFAULT_HISTORY_CONFIG } from "@mandujs/core";
2
+ import { getRootDir } from "../../util/fs";
3
+
4
+ export interface ChangePruneOptions {
5
+ keep?: number;
6
+ }
7
+
8
+ export async function changePrune(options: ChangePruneOptions = {}): Promise<boolean> {
9
+ const rootDir = getRootDir();
10
+ const keepCount = options.keep ?? DEFAULT_HISTORY_CONFIG.maxSnapshots;
11
+
12
+ console.log(`🥟 Mandu Change Prune`);
13
+ console.log(` 유지할 스냅샷: ${keepCount}개\n`);
14
+
15
+ try {
16
+ const deletedIds = await pruneHistory(rootDir, keepCount);
17
+
18
+ if (deletedIds.length === 0) {
19
+ console.log(`✅ 정리할 스냅샷이 없습니다`);
20
+ } else {
21
+ console.log(`🗑️ 삭제된 스냅샷: ${deletedIds.length}개`);
22
+ for (const id of deletedIds) {
23
+ console.log(` - ${id}`);
24
+ }
25
+ }
26
+
27
+ return true;
28
+ } catch (error) {
29
+ console.error(`❌ 정리 실패: ${error instanceof Error ? error.message : String(error)}`);
30
+ return false;
31
+ }
32
+ }
@@ -0,0 +1,40 @@
1
+ import { rollbackChange } from "@mandujs/core";
2
+ import { getRootDir } from "../../util/fs";
3
+
4
+ export interface ChangeRollbackOptions {
5
+ id?: string;
6
+ }
7
+
8
+ export async function changeRollback(options: ChangeRollbackOptions = {}): Promise<boolean> {
9
+ const rootDir = getRootDir();
10
+
11
+ console.log(`🥟 Mandu Change Rollback`);
12
+
13
+ try {
14
+ const result = await rollbackChange(rootDir, options.id);
15
+
16
+ if (result.success) {
17
+ console.log(`✅ 롤백 완료`);
18
+ console.log(` ID: ${result.changeId}`);
19
+ console.log(` 복원된 파일: ${result.restoreResult.restoredFiles.length}개`);
20
+
21
+ for (const file of result.restoreResult.restoredFiles) {
22
+ console.log(` - ${file}`);
23
+ }
24
+ } else {
25
+ console.log(`⚠️ 롤백 부분 완료`);
26
+ console.log(` ID: ${result.changeId}`);
27
+ console.log(` 복원된 파일: ${result.restoreResult.restoredFiles.length}개`);
28
+ console.log(` 실패한 파일: ${result.restoreResult.failedFiles.length}개`);
29
+
30
+ for (const error of result.restoreResult.errors) {
31
+ console.error(` - ${error}`);
32
+ }
33
+ }
34
+
35
+ return result.success;
36
+ } catch (error) {
37
+ console.error(`❌ 롤백 실패: ${error instanceof Error ? error.message : String(error)}`);
38
+ return false;
39
+ }
40
+ }
@@ -0,0 +1,36 @@
1
+ import { getTransactionStatus } from "@mandujs/core";
2
+ import { getRootDir } from "../../util/fs";
3
+
4
+ export async function changeStatus(): Promise<boolean> {
5
+ const rootDir = getRootDir();
6
+
7
+ console.log(`🥟 Mandu Change Status\n`);
8
+
9
+ try {
10
+ const { state, change } = await getTransactionStatus(rootDir);
11
+
12
+ if (state.active && change) {
13
+ console.log(`🔄 활성 트랜잭션:`);
14
+ console.log(` ID: ${change.id}`);
15
+ console.log(` 스냅샷: ${change.snapshotId}`);
16
+ console.log(` 시작: ${new Date(change.createdAt).toLocaleString()}`);
17
+ if (change.message) {
18
+ console.log(` 메시지: ${change.message}`);
19
+ }
20
+ if (change.autoGenerated) {
21
+ console.log(` 생성: Auto-correct`);
22
+ }
23
+ console.log(`\n💡 사용 가능한 명령:`);
24
+ console.log(` 확정: bunx mandu change commit`);
25
+ console.log(` 롤백: bunx mandu change rollback`);
26
+ } else {
27
+ console.log(`✅ 활성 트랜잭션 없음`);
28
+ console.log(`\n💡 새 트랜잭션 시작: bunx mandu change begin`);
29
+ }
30
+
31
+ return true;
32
+ } catch (error) {
33
+ console.error(`❌ 상태 조회 실패: ${error instanceof Error ? error.message : String(error)}`);
34
+ return false;
35
+ }
36
+ }
@@ -58,9 +58,36 @@ export async function guardCheck(options: GuardCheckOptions = {}): Promise<boole
58
58
 
59
59
  if (autoCorrectResult.fixed) {
60
60
  console.log(`\n✅ Auto-correct 완료 (${autoCorrectResult.retriedCount}회 재시도)`);
61
+ if (autoCorrectResult.changeId) {
62
+ console.log(` 트랜잭션: ${autoCorrectResult.changeId} (커밋됨)`);
63
+ }
61
64
 
62
65
  // 최종 Guard 재검사
63
66
  checkResult = await runGuardCheck(result.data, rootDir);
67
+ } else if (autoCorrectResult.rolledBack) {
68
+ console.log(`\n⚠️ Auto-correct 실패 - 롤백됨`);
69
+ if (autoCorrectResult.changeId) {
70
+ console.log(` 트랜잭션: ${autoCorrectResult.changeId} (롤백됨)`);
71
+ }
72
+ console.log(` 원래 상태로 복원되었습니다.`);
73
+
74
+ const manualViolations = autoCorrectResult.remainingViolations.filter(
75
+ (v) => !isAutoCorrectableViolation(v)
76
+ );
77
+
78
+ if (manualViolations.length > 0) {
79
+ console.log(`\n⚠️ 수동 수정이 필요한 위반:`);
80
+ for (const v of manualViolations) {
81
+ console.log(` - [${v.ruleId}] ${v.file}`);
82
+ console.log(` 💡 ${v.suggestion}`);
83
+ }
84
+ }
85
+
86
+ // 남은 위반으로 업데이트
87
+ checkResult = {
88
+ passed: false,
89
+ violations: autoCorrectResult.remainingViolations,
90
+ };
64
91
  } else {
65
92
  console.log(`\n⚠️ 일부 위반은 수동 수정이 필요합니다:`);
66
93