@mandujs/cli 0.8.1 → 0.8.3
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.ko.md +181 -181
- package/README.md +181 -181
- package/package.json +40 -40
- package/src/commands/init.ts +88 -88
- package/src/util/fs.ts +9 -9
- package/templates/default/apps/web/entry.tsx +35 -35
- package/templates/default/spec/routes.manifest.json +18 -18
- package/templates/default/tests/example.test.ts +58 -58
- package/templates/default/tests/helpers.ts +52 -52
- package/templates/default/tests/setup.ts +9 -9
- package/templates/default/tsconfig.json +14 -14
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,40 +1,40 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@mandujs/cli",
|
|
3
|
-
"version": "0.8.
|
|
4
|
-
"description": "Agent-Native Fullstack Framework - 에이전트가 코딩해도 아키텍처가 무너지지 않는 개발 OS",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"main": "./src/main.ts",
|
|
7
|
-
"bin": {
|
|
8
|
-
"mandu": "src/main.ts"
|
|
9
|
-
},
|
|
10
|
-
"files": [
|
|
11
|
-
"src/**/*",
|
|
12
|
-
"templates/**/*"
|
|
13
|
-
],
|
|
14
|
-
"keywords": [
|
|
15
|
-
"ai",
|
|
16
|
-
"agent",
|
|
17
|
-
"framework",
|
|
18
|
-
"fullstack",
|
|
19
|
-
"bun",
|
|
20
|
-
"typescript",
|
|
21
|
-
"react",
|
|
22
|
-
"ssr",
|
|
23
|
-
"code-generation"
|
|
24
|
-
],
|
|
25
|
-
"repository": {
|
|
26
|
-
"type": "git",
|
|
27
|
-
"url": "git+https://github.com/konamgil/mandu.git"
|
|
28
|
-
},
|
|
29
|
-
"author": "konamgil",
|
|
30
|
-
"license": "MIT",
|
|
31
|
-
"publishConfig": {
|
|
32
|
-
"access": "public"
|
|
33
|
-
},
|
|
34
|
-
"dependencies": {
|
|
35
|
-
"@mandujs/core": "
|
|
36
|
-
},
|
|
37
|
-
"engines": {
|
|
38
|
-
"bun": ">=1.0.0"
|
|
39
|
-
}
|
|
40
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@mandujs/cli",
|
|
3
|
+
"version": "0.8.3",
|
|
4
|
+
"description": "Agent-Native Fullstack Framework - 에이전트가 코딩해도 아키텍처가 무너지지 않는 개발 OS",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./src/main.ts",
|
|
7
|
+
"bin": {
|
|
8
|
+
"mandu": "src/main.ts"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"src/**/*",
|
|
12
|
+
"templates/**/*"
|
|
13
|
+
],
|
|
14
|
+
"keywords": [
|
|
15
|
+
"ai",
|
|
16
|
+
"agent",
|
|
17
|
+
"framework",
|
|
18
|
+
"fullstack",
|
|
19
|
+
"bun",
|
|
20
|
+
"typescript",
|
|
21
|
+
"react",
|
|
22
|
+
"ssr",
|
|
23
|
+
"code-generation"
|
|
24
|
+
],
|
|
25
|
+
"repository": {
|
|
26
|
+
"type": "git",
|
|
27
|
+
"url": "git+https://github.com/konamgil/mandu.git"
|
|
28
|
+
},
|
|
29
|
+
"author": "konamgil",
|
|
30
|
+
"license": "MIT",
|
|
31
|
+
"publishConfig": {
|
|
32
|
+
"access": "public"
|
|
33
|
+
},
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"@mandujs/core": "0.8.2"
|
|
36
|
+
},
|
|
37
|
+
"engines": {
|
|
38
|
+
"bun": ">=1.0.0"
|
|
39
|
+
}
|
|
40
|
+
}
|
package/src/commands/init.ts
CHANGED
|
@@ -1,88 +1,88 @@
|
|
|
1
|
-
import path from "path";
|
|
2
|
-
import fs from "fs/promises";
|
|
3
|
-
|
|
4
|
-
export interface InitOptions {
|
|
5
|
-
name?: string;
|
|
6
|
-
template?: string;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
async function copyDir(src: string, dest: string, projectName: string): Promise<void> {
|
|
10
|
-
await fs.mkdir(dest, { recursive: true });
|
|
11
|
-
const entries = await fs.readdir(src, { withFileTypes: true });
|
|
12
|
-
|
|
13
|
-
for (const entry of entries) {
|
|
14
|
-
const srcPath = path.join(src, entry.name);
|
|
15
|
-
const destPath = path.join(dest, entry.name);
|
|
16
|
-
|
|
17
|
-
if (entry.isDirectory()) {
|
|
18
|
-
await copyDir(srcPath, destPath, projectName);
|
|
19
|
-
} else {
|
|
20
|
-
let content = await fs.readFile(srcPath, "utf-8");
|
|
21
|
-
// Replace template variables
|
|
22
|
-
content = content.replace(/\{\{PROJECT_NAME\}\}/g, projectName);
|
|
23
|
-
await fs.writeFile(destPath, content);
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function getTemplatesDir(): string {
|
|
29
|
-
// When installed via npm, templates are in the CLI package
|
|
30
|
-
const commandsDir = import.meta.dir;
|
|
31
|
-
// packages/cli/src/commands -> go up 2 levels to cli package root
|
|
32
|
-
return path.resolve(commandsDir, "../../templates");
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export async function init(options: InitOptions = {}): Promise<boolean> {
|
|
36
|
-
const projectName = options.name || "my-mandu-app";
|
|
37
|
-
const template = options.template || "default";
|
|
38
|
-
const targetDir = path.resolve(process.cwd(), projectName);
|
|
39
|
-
|
|
40
|
-
console.log(`🥟 Mandu Init`);
|
|
41
|
-
console.log(`📁 프로젝트: ${projectName}`);
|
|
42
|
-
console.log(`📦 템플릿: ${template}\n`);
|
|
43
|
-
|
|
44
|
-
// Check if target directory exists
|
|
45
|
-
try {
|
|
46
|
-
await fs.access(targetDir);
|
|
47
|
-
console.error(`❌ 디렉토리가 이미 존재합니다: ${targetDir}`);
|
|
48
|
-
return false;
|
|
49
|
-
} catch {
|
|
50
|
-
// Directory doesn't exist, good to proceed
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const templatesDir = getTemplatesDir();
|
|
54
|
-
const templateDir = path.join(templatesDir, template);
|
|
55
|
-
|
|
56
|
-
// Check if template exists
|
|
57
|
-
try {
|
|
58
|
-
await fs.access(templateDir);
|
|
59
|
-
} catch {
|
|
60
|
-
console.error(`❌ 템플릿을 찾을 수 없습니다: ${template}`);
|
|
61
|
-
console.error(` 사용 가능한 템플릿: default`);
|
|
62
|
-
return false;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
console.log(`📋 템플릿 복사 중...`);
|
|
66
|
-
|
|
67
|
-
try {
|
|
68
|
-
await copyDir(templateDir, targetDir, projectName);
|
|
69
|
-
} catch (error) {
|
|
70
|
-
console.error(`❌ 템플릿 복사 실패:`, error);
|
|
71
|
-
return false;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// Create empty generated directories
|
|
75
|
-
await fs.mkdir(path.join(targetDir, "apps/server/generated/routes"), { recursive: true });
|
|
76
|
-
await fs.mkdir(path.join(targetDir, "apps/web/generated/routes"), { recursive: true });
|
|
77
|
-
|
|
78
|
-
console.log(`\n✅ 프로젝트 생성 완료!\n`);
|
|
79
|
-
console.log(`📍 위치: ${targetDir}`);
|
|
80
|
-
console.log(`\n🚀 시작하기:`);
|
|
81
|
-
console.log(` cd ${projectName}`);
|
|
82
|
-
console.log(` bun install`);
|
|
83
|
-
console.log(` bun run spec`);
|
|
84
|
-
console.log(` bun run generate`);
|
|
85
|
-
console.log(` bun run dev`);
|
|
86
|
-
|
|
87
|
-
return true;
|
|
88
|
-
}
|
|
1
|
+
import path from "path";
|
|
2
|
+
import fs from "fs/promises";
|
|
3
|
+
|
|
4
|
+
export interface InitOptions {
|
|
5
|
+
name?: string;
|
|
6
|
+
template?: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
async function copyDir(src: string, dest: string, projectName: string): Promise<void> {
|
|
10
|
+
await fs.mkdir(dest, { recursive: true });
|
|
11
|
+
const entries = await fs.readdir(src, { withFileTypes: true });
|
|
12
|
+
|
|
13
|
+
for (const entry of entries) {
|
|
14
|
+
const srcPath = path.join(src, entry.name);
|
|
15
|
+
const destPath = path.join(dest, entry.name);
|
|
16
|
+
|
|
17
|
+
if (entry.isDirectory()) {
|
|
18
|
+
await copyDir(srcPath, destPath, projectName);
|
|
19
|
+
} else {
|
|
20
|
+
let content = await fs.readFile(srcPath, "utf-8");
|
|
21
|
+
// Replace template variables
|
|
22
|
+
content = content.replace(/\{\{PROJECT_NAME\}\}/g, projectName);
|
|
23
|
+
await fs.writeFile(destPath, content);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function getTemplatesDir(): string {
|
|
29
|
+
// When installed via npm, templates are in the CLI package
|
|
30
|
+
const commandsDir = import.meta.dir;
|
|
31
|
+
// packages/cli/src/commands -> go up 2 levels to cli package root
|
|
32
|
+
return path.resolve(commandsDir, "../../templates");
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export async function init(options: InitOptions = {}): Promise<boolean> {
|
|
36
|
+
const projectName = options.name || "my-mandu-app";
|
|
37
|
+
const template = options.template || "default";
|
|
38
|
+
const targetDir = path.resolve(process.cwd(), projectName);
|
|
39
|
+
|
|
40
|
+
console.log(`🥟 Mandu Init`);
|
|
41
|
+
console.log(`📁 프로젝트: ${projectName}`);
|
|
42
|
+
console.log(`📦 템플릿: ${template}\n`);
|
|
43
|
+
|
|
44
|
+
// Check if target directory exists
|
|
45
|
+
try {
|
|
46
|
+
await fs.access(targetDir);
|
|
47
|
+
console.error(`❌ 디렉토리가 이미 존재합니다: ${targetDir}`);
|
|
48
|
+
return false;
|
|
49
|
+
} catch {
|
|
50
|
+
// Directory doesn't exist, good to proceed
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const templatesDir = getTemplatesDir();
|
|
54
|
+
const templateDir = path.join(templatesDir, template);
|
|
55
|
+
|
|
56
|
+
// Check if template exists
|
|
57
|
+
try {
|
|
58
|
+
await fs.access(templateDir);
|
|
59
|
+
} catch {
|
|
60
|
+
console.error(`❌ 템플릿을 찾을 수 없습니다: ${template}`);
|
|
61
|
+
console.error(` 사용 가능한 템플릿: default`);
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
console.log(`📋 템플릿 복사 중...`);
|
|
66
|
+
|
|
67
|
+
try {
|
|
68
|
+
await copyDir(templateDir, targetDir, projectName);
|
|
69
|
+
} catch (error) {
|
|
70
|
+
console.error(`❌ 템플릿 복사 실패:`, error);
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Create empty generated directories
|
|
75
|
+
await fs.mkdir(path.join(targetDir, "apps/server/generated/routes"), { recursive: true });
|
|
76
|
+
await fs.mkdir(path.join(targetDir, "apps/web/generated/routes"), { recursive: true });
|
|
77
|
+
|
|
78
|
+
console.log(`\n✅ 프로젝트 생성 완료!\n`);
|
|
79
|
+
console.log(`📍 위치: ${targetDir}`);
|
|
80
|
+
console.log(`\n🚀 시작하기:`);
|
|
81
|
+
console.log(` cd ${projectName}`);
|
|
82
|
+
console.log(` bun install`);
|
|
83
|
+
console.log(` bun run spec`);
|
|
84
|
+
console.log(` bun run generate`);
|
|
85
|
+
console.log(` bun run dev`);
|
|
86
|
+
|
|
87
|
+
return true;
|
|
88
|
+
}
|
package/src/util/fs.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import path from "path";
|
|
2
|
-
|
|
3
|
-
export function resolveFromCwd(...paths: string[]): string {
|
|
4
|
-
return path.resolve(process.cwd(), ...paths);
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
export function getRootDir(): string {
|
|
8
|
-
return process.cwd();
|
|
9
|
-
}
|
|
1
|
+
import path from "path";
|
|
2
|
+
|
|
3
|
+
export function resolveFromCwd(...paths: string[]): string {
|
|
4
|
+
return path.resolve(process.cwd(), ...paths);
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function getRootDir(): string {
|
|
8
|
+
return process.cwd();
|
|
9
|
+
}
|