@mandujs/cli 0.12.2 → 0.13.0

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 (51) hide show
  1. package/README.ko.md +234 -234
  2. package/README.md +354 -354
  3. package/package.json +2 -2
  4. package/src/commands/contract.ts +173 -173
  5. package/src/commands/dev.ts +8 -68
  6. package/src/commands/doctor.ts +27 -27
  7. package/src/commands/guard-arch.ts +303 -303
  8. package/src/commands/guard-check.ts +3 -3
  9. package/src/commands/monitor.ts +300 -300
  10. package/src/commands/openapi.ts +107 -107
  11. package/src/commands/registry.ts +367 -357
  12. package/src/commands/routes.ts +228 -228
  13. package/src/commands/start.ts +184 -0
  14. package/src/errors/codes.ts +35 -35
  15. package/src/errors/index.ts +2 -2
  16. package/src/errors/messages.ts +143 -143
  17. package/src/hooks/index.ts +17 -17
  18. package/src/hooks/preaction.ts +256 -256
  19. package/src/main.ts +37 -34
  20. package/src/terminal/banner.ts +166 -166
  21. package/src/terminal/help.ts +306 -306
  22. package/src/terminal/index.ts +71 -71
  23. package/src/terminal/output.ts +295 -295
  24. package/src/terminal/palette.ts +30 -30
  25. package/src/terminal/progress.ts +327 -327
  26. package/src/terminal/stream-writer.ts +214 -214
  27. package/src/terminal/table.ts +354 -354
  28. package/src/terminal/theme.ts +142 -142
  29. package/src/util/bun.ts +6 -6
  30. package/src/util/fs.ts +23 -23
  31. package/src/util/handlers.ts +96 -0
  32. package/src/util/manifest.ts +52 -52
  33. package/src/util/output.ts +22 -22
  34. package/src/util/port.ts +71 -71
  35. package/templates/default/AGENTS.md +96 -96
  36. package/templates/default/app/api/health/route.ts +13 -13
  37. package/templates/default/app/globals.css +49 -49
  38. package/templates/default/app/layout.tsx +27 -27
  39. package/templates/default/app/page.tsx +38 -38
  40. package/templates/default/package.json +1 -0
  41. package/templates/default/src/client/shared/lib/utils.ts +16 -16
  42. package/templates/default/src/client/shared/ui/button.tsx +57 -57
  43. package/templates/default/src/client/shared/ui/card.tsx +78 -78
  44. package/templates/default/src/client/shared/ui/index.ts +21 -21
  45. package/templates/default/src/client/shared/ui/input.tsx +24 -24
  46. package/templates/default/tests/example.test.ts +58 -58
  47. package/templates/default/tests/helpers.ts +52 -52
  48. package/templates/default/tests/setup.ts +9 -9
  49. package/templates/default/tsconfig.json +12 -14
  50. package/templates/default/apps/server/main.ts +0 -67
  51. package/templates/default/apps/web/entry.tsx +0 -35
@@ -1,306 +1,306 @@
1
- /**
2
- * DNA-015: Semantic Help System
3
- *
4
- * 시맨틱 도움말 포맷팅
5
- * - 예제 기반 도움말
6
- * - 테마 적용 출력
7
- * - 섹션별 구조화
8
- */
9
-
10
- import { theme, colorize, isRich } from "./theme.js";
11
-
12
- /**
13
- * 도움말 예제 타입
14
- * [명령어, 설명]
15
- */
16
- export type HelpExample = readonly [command: string, description: string];
17
-
18
- /**
19
- * 명령어 옵션 정의
20
- */
21
- export interface HelpOption {
22
- /** 플래그 (예: "--port", "-p, --port") */
23
- flags: string;
24
- /** 설명 */
25
- description: string;
26
- /** 기본값 */
27
- default?: string;
28
- /** 필수 여부 */
29
- required?: boolean;
30
- }
31
-
32
- /**
33
- * 서브커맨드 정의
34
- */
35
- export interface HelpSubcommand {
36
- /** 서브커맨드 이름 */
37
- name: string;
38
- /** 설명 */
39
- description: string;
40
- /** 별칭 */
41
- aliases?: string[];
42
- }
43
-
44
- /**
45
- * 도움말 섹션
46
- */
47
- export interface HelpSection {
48
- /** 섹션 제목 */
49
- title: string;
50
- /** 섹션 내용 */
51
- content: string;
52
- }
53
-
54
- /**
55
- * 도움말 정의
56
- */
57
- export interface HelpDefinition {
58
- /** 명령어 이름 */
59
- name: string;
60
- /** 짧은 설명 */
61
- description: string;
62
- /** 사용법 */
63
- usage?: string;
64
- /** 옵션 목록 */
65
- options?: HelpOption[];
66
- /** 서브커맨드 목록 */
67
- subcommands?: HelpSubcommand[];
68
- /** 예제 목록 */
69
- examples?: HelpExample[];
70
- /** 추가 섹션 */
71
- sections?: HelpSection[];
72
- /** 참조 링크 */
73
- seeAlso?: string[];
74
- }
75
-
76
- /**
77
- * 예제 포맷팅
78
- *
79
- * @example
80
- * ```ts
81
- * formatHelpExample("mandu dev", "Start development server");
82
- * // " mandu dev"
83
- * // " Start development server"
84
- * ```
85
- */
86
- export function formatHelpExample(command: string, description: string): string {
87
- const rich = isRich();
88
- const cmd = rich ? theme.accent(command) : command;
89
- const desc = rich ? theme.muted(description) : description;
90
-
91
- return ` ${cmd}\n ${desc}`;
92
- }
93
-
94
- /**
95
- * 예제 그룹 포맷팅
96
- *
97
- * @example
98
- * ```ts
99
- * formatHelpExampleGroup("Examples:", [
100
- * ["mandu dev", "Start development server"],
101
- * ["mandu build --prod", "Build for production"],
102
- * ]);
103
- * ```
104
- */
105
- export function formatHelpExampleGroup(
106
- label: string,
107
- examples: ReadonlyArray<HelpExample>
108
- ): string {
109
- const rich = isRich();
110
- const heading = rich ? theme.heading(label) : label;
111
- const formatted = examples
112
- .map(([cmd, desc]) => formatHelpExample(cmd, desc))
113
- .join("\n\n");
114
-
115
- return `${heading}\n${formatted}`;
116
- }
117
-
118
- /**
119
- * 옵션 포맷팅
120
- */
121
- export function formatHelpOption(option: HelpOption): string {
122
- const rich = isRich();
123
- const flags = rich ? theme.option(option.flags) : option.flags;
124
-
125
- let desc = option.description;
126
- if (option.default) {
127
- desc += rich
128
- ? ` ${theme.muted(`(default: ${option.default})`)}`
129
- : ` (default: ${option.default})`;
130
- }
131
- if (option.required) {
132
- desc += rich ? ` ${theme.warn("[required]")}` : " [required]";
133
- }
134
-
135
- // 플래그와 설명 정렬
136
- const padding = Math.max(0, 24 - option.flags.length);
137
- return ` ${flags}${" ".repeat(padding)}${desc}`;
138
- }
139
-
140
- /**
141
- * 서브커맨드 포맷팅
142
- */
143
- export function formatHelpSubcommand(subcommand: HelpSubcommand): string {
144
- const rich = isRich();
145
- let name = subcommand.name;
146
-
147
- if (subcommand.aliases && subcommand.aliases.length > 0) {
148
- name += `, ${subcommand.aliases.join(", ")}`;
149
- }
150
-
151
- const cmd = rich ? theme.command(name) : name;
152
- const desc = rich ? subcommand.description : subcommand.description;
153
-
154
- const padding = Math.max(0, 20 - name.length);
155
- return ` ${cmd}${" ".repeat(padding)}${desc}`;
156
- }
157
-
158
- /**
159
- * 섹션 제목 포맷팅
160
- */
161
- export function formatSectionTitle(title: string): string {
162
- const rich = isRich();
163
- return rich ? theme.heading(title) : title;
164
- }
165
-
166
- /**
167
- * 전체 도움말 렌더링
168
- */
169
- export function renderHelp(def: HelpDefinition): string {
170
- const lines: string[] = [];
171
- const rich = isRich();
172
-
173
- // 헤더
174
- const name = rich ? theme.accent(def.name) : def.name;
175
- lines.push(`${name} - ${def.description}`);
176
- lines.push("");
177
-
178
- // 사용법
179
- if (def.usage) {
180
- lines.push(formatSectionTitle("Usage:"));
181
- lines.push(` ${def.usage}`);
182
- lines.push("");
183
- }
184
-
185
- // 서브커맨드
186
- if (def.subcommands && def.subcommands.length > 0) {
187
- lines.push(formatSectionTitle("Commands:"));
188
- for (const sub of def.subcommands) {
189
- lines.push(formatHelpSubcommand(sub));
190
- }
191
- lines.push("");
192
- }
193
-
194
- // 옵션
195
- if (def.options && def.options.length > 0) {
196
- lines.push(formatSectionTitle("Options:"));
197
- for (const opt of def.options) {
198
- lines.push(formatHelpOption(opt));
199
- }
200
- lines.push("");
201
- }
202
-
203
- // 예제
204
- if (def.examples && def.examples.length > 0) {
205
- lines.push(formatHelpExampleGroup("Examples:", def.examples));
206
- lines.push("");
207
- }
208
-
209
- // 추가 섹션
210
- if (def.sections) {
211
- for (const section of def.sections) {
212
- lines.push(formatSectionTitle(section.title));
213
- lines.push(section.content);
214
- lines.push("");
215
- }
216
- }
217
-
218
- // 참조
219
- if (def.seeAlso && def.seeAlso.length > 0) {
220
- lines.push(formatSectionTitle("See Also:"));
221
- for (const ref of def.seeAlso) {
222
- lines.push(` ${ref}`);
223
- }
224
- lines.push("");
225
- }
226
-
227
- return lines.join("\n");
228
- }
229
-
230
- /**
231
- * Mandu CLI 기본 도움말 정의
232
- */
233
- export const MANDU_HELP: HelpDefinition = {
234
- name: "mandu",
235
- description: "Agent-Native Web Framework",
236
- usage: "mandu <command> [options]",
237
- subcommands: [
238
- { name: "init", description: "Create a new Mandu project" },
239
- { name: "dev", description: "Start development server with HMR" },
240
- { name: "build", description: "Build for production" },
241
- { name: "start", description: "Start production server" },
242
- { name: "guard", description: "Check architecture violations", aliases: ["g"] },
243
- { name: "routes", description: "Manage file-system routes" },
244
- { name: "openapi", description: "Generate OpenAPI spec" },
245
- { name: "brain", description: "Setup local AI with Ollama" },
246
- ],
247
- options: [
248
- { flags: "--version, -v", description: "Show version number" },
249
- { flags: "--help, -h", description: "Show help" },
250
- { flags: "--json", description: "Output in JSON format" },
251
- { flags: "--no-color", description: "Disable colored output" },
252
- { flags: "--verbose", description: "Enable verbose logging" },
253
- ],
254
- examples: [
255
- ["mandu init my-app", "Create a new project"],
256
- ["mandu dev --port 4000", "Start dev server on port 4000"],
257
- ["mandu build --prod", "Build for production"],
258
- ["mandu guard --fix", "Check and auto-fix violations"],
259
- ],
260
- sections: [
261
- {
262
- title: "Environment Variables:",
263
- content: ` MANDU_OUTPUT Output format (json|pretty|plain)
264
- NO_COLOR Disable colors (set to any value)
265
- FORCE_COLOR Force colors even in non-TTY`,
266
- },
267
- ],
268
- seeAlso: [
269
- "https://mandujs.com/docs",
270
- "https://github.com/mandujs/mandu",
271
- ],
272
- };
273
-
274
- /**
275
- * 명령어별 도움말 렌더링
276
- */
277
- export function renderCommandHelp(
278
- commandName: string,
279
- def: Partial<HelpDefinition>
280
- ): string {
281
- return renderHelp({
282
- name: `mandu ${commandName}`,
283
- description: def.description ?? "",
284
- ...def,
285
- });
286
- }
287
-
288
- /**
289
- * 간단한 사용법 힌트
290
- */
291
- export function formatUsageHint(command: string, hint: string): string {
292
- const rich = isRich();
293
- const cmd = rich ? theme.accent(command) : command;
294
- const tip = rich ? theme.muted(hint) : hint;
295
- return `${tip}\n ${cmd}`;
296
- }
297
-
298
- /**
299
- * 에러 후 도움말 힌트
300
- */
301
- export function formatErrorHint(errorMessage: string, helpCommand: string): string {
302
- const rich = isRich();
303
- const error = rich ? theme.error(errorMessage) : errorMessage;
304
- const help = rich ? theme.muted(`Run '${helpCommand}' for more information.`) : `Run '${helpCommand}' for more information.`;
305
- return `${error}\n\n${help}`;
306
- }
1
+ /**
2
+ * DNA-015: Semantic Help System
3
+ *
4
+ * 시맨틱 도움말 포맷팅
5
+ * - 예제 기반 도움말
6
+ * - 테마 적용 출력
7
+ * - 섹션별 구조화
8
+ */
9
+
10
+ import { theme, colorize, isRich } from "./theme.js";
11
+
12
+ /**
13
+ * 도움말 예제 타입
14
+ * [명령어, 설명]
15
+ */
16
+ export type HelpExample = readonly [command: string, description: string];
17
+
18
+ /**
19
+ * 명령어 옵션 정의
20
+ */
21
+ export interface HelpOption {
22
+ /** 플래그 (예: "--port", "-p, --port") */
23
+ flags: string;
24
+ /** 설명 */
25
+ description: string;
26
+ /** 기본값 */
27
+ default?: string;
28
+ /** 필수 여부 */
29
+ required?: boolean;
30
+ }
31
+
32
+ /**
33
+ * 서브커맨드 정의
34
+ */
35
+ export interface HelpSubcommand {
36
+ /** 서브커맨드 이름 */
37
+ name: string;
38
+ /** 설명 */
39
+ description: string;
40
+ /** 별칭 */
41
+ aliases?: string[];
42
+ }
43
+
44
+ /**
45
+ * 도움말 섹션
46
+ */
47
+ export interface HelpSection {
48
+ /** 섹션 제목 */
49
+ title: string;
50
+ /** 섹션 내용 */
51
+ content: string;
52
+ }
53
+
54
+ /**
55
+ * 도움말 정의
56
+ */
57
+ export interface HelpDefinition {
58
+ /** 명령어 이름 */
59
+ name: string;
60
+ /** 짧은 설명 */
61
+ description: string;
62
+ /** 사용법 */
63
+ usage?: string;
64
+ /** 옵션 목록 */
65
+ options?: HelpOption[];
66
+ /** 서브커맨드 목록 */
67
+ subcommands?: HelpSubcommand[];
68
+ /** 예제 목록 */
69
+ examples?: HelpExample[];
70
+ /** 추가 섹션 */
71
+ sections?: HelpSection[];
72
+ /** 참조 링크 */
73
+ seeAlso?: string[];
74
+ }
75
+
76
+ /**
77
+ * 예제 포맷팅
78
+ *
79
+ * @example
80
+ * ```ts
81
+ * formatHelpExample("mandu dev", "Start development server");
82
+ * // " mandu dev"
83
+ * // " Start development server"
84
+ * ```
85
+ */
86
+ export function formatHelpExample(command: string, description: string): string {
87
+ const rich = isRich();
88
+ const cmd = rich ? theme.accent(command) : command;
89
+ const desc = rich ? theme.muted(description) : description;
90
+
91
+ return ` ${cmd}\n ${desc}`;
92
+ }
93
+
94
+ /**
95
+ * 예제 그룹 포맷팅
96
+ *
97
+ * @example
98
+ * ```ts
99
+ * formatHelpExampleGroup("Examples:", [
100
+ * ["mandu dev", "Start development server"],
101
+ * ["mandu build --prod", "Build for production"],
102
+ * ]);
103
+ * ```
104
+ */
105
+ export function formatHelpExampleGroup(
106
+ label: string,
107
+ examples: ReadonlyArray<HelpExample>
108
+ ): string {
109
+ const rich = isRich();
110
+ const heading = rich ? theme.heading(label) : label;
111
+ const formatted = examples
112
+ .map(([cmd, desc]) => formatHelpExample(cmd, desc))
113
+ .join("\n\n");
114
+
115
+ return `${heading}\n${formatted}`;
116
+ }
117
+
118
+ /**
119
+ * 옵션 포맷팅
120
+ */
121
+ export function formatHelpOption(option: HelpOption): string {
122
+ const rich = isRich();
123
+ const flags = rich ? theme.option(option.flags) : option.flags;
124
+
125
+ let desc = option.description;
126
+ if (option.default) {
127
+ desc += rich
128
+ ? ` ${theme.muted(`(default: ${option.default})`)}`
129
+ : ` (default: ${option.default})`;
130
+ }
131
+ if (option.required) {
132
+ desc += rich ? ` ${theme.warn("[required]")}` : " [required]";
133
+ }
134
+
135
+ // 플래그와 설명 정렬
136
+ const padding = Math.max(0, 24 - option.flags.length);
137
+ return ` ${flags}${" ".repeat(padding)}${desc}`;
138
+ }
139
+
140
+ /**
141
+ * 서브커맨드 포맷팅
142
+ */
143
+ export function formatHelpSubcommand(subcommand: HelpSubcommand): string {
144
+ const rich = isRich();
145
+ let name = subcommand.name;
146
+
147
+ if (subcommand.aliases && subcommand.aliases.length > 0) {
148
+ name += `, ${subcommand.aliases.join(", ")}`;
149
+ }
150
+
151
+ const cmd = rich ? theme.command(name) : name;
152
+ const desc = rich ? subcommand.description : subcommand.description;
153
+
154
+ const padding = Math.max(0, 20 - name.length);
155
+ return ` ${cmd}${" ".repeat(padding)}${desc}`;
156
+ }
157
+
158
+ /**
159
+ * 섹션 제목 포맷팅
160
+ */
161
+ export function formatSectionTitle(title: string): string {
162
+ const rich = isRich();
163
+ return rich ? theme.heading(title) : title;
164
+ }
165
+
166
+ /**
167
+ * 전체 도움말 렌더링
168
+ */
169
+ export function renderHelp(def: HelpDefinition): string {
170
+ const lines: string[] = [];
171
+ const rich = isRich();
172
+
173
+ // 헤더
174
+ const name = rich ? theme.accent(def.name) : def.name;
175
+ lines.push(`${name} - ${def.description}`);
176
+ lines.push("");
177
+
178
+ // 사용법
179
+ if (def.usage) {
180
+ lines.push(formatSectionTitle("Usage:"));
181
+ lines.push(` ${def.usage}`);
182
+ lines.push("");
183
+ }
184
+
185
+ // 서브커맨드
186
+ if (def.subcommands && def.subcommands.length > 0) {
187
+ lines.push(formatSectionTitle("Commands:"));
188
+ for (const sub of def.subcommands) {
189
+ lines.push(formatHelpSubcommand(sub));
190
+ }
191
+ lines.push("");
192
+ }
193
+
194
+ // 옵션
195
+ if (def.options && def.options.length > 0) {
196
+ lines.push(formatSectionTitle("Options:"));
197
+ for (const opt of def.options) {
198
+ lines.push(formatHelpOption(opt));
199
+ }
200
+ lines.push("");
201
+ }
202
+
203
+ // 예제
204
+ if (def.examples && def.examples.length > 0) {
205
+ lines.push(formatHelpExampleGroup("Examples:", def.examples));
206
+ lines.push("");
207
+ }
208
+
209
+ // 추가 섹션
210
+ if (def.sections) {
211
+ for (const section of def.sections) {
212
+ lines.push(formatSectionTitle(section.title));
213
+ lines.push(section.content);
214
+ lines.push("");
215
+ }
216
+ }
217
+
218
+ // 참조
219
+ if (def.seeAlso && def.seeAlso.length > 0) {
220
+ lines.push(formatSectionTitle("See Also:"));
221
+ for (const ref of def.seeAlso) {
222
+ lines.push(` ${ref}`);
223
+ }
224
+ lines.push("");
225
+ }
226
+
227
+ return lines.join("\n");
228
+ }
229
+
230
+ /**
231
+ * Mandu CLI 기본 도움말 정의
232
+ */
233
+ export const MANDU_HELP: HelpDefinition = {
234
+ name: "mandu",
235
+ description: "Agent-Native Web Framework",
236
+ usage: "mandu <command> [options]",
237
+ subcommands: [
238
+ { name: "init", description: "Create a new Mandu project" },
239
+ { name: "dev", description: "Start development server with HMR" },
240
+ { name: "build", description: "Build for production" },
241
+ { name: "start", description: "Start production server" },
242
+ { name: "guard", description: "Check architecture violations", aliases: ["g"] },
243
+ { name: "routes", description: "Manage file-system routes" },
244
+ { name: "openapi", description: "Generate OpenAPI spec" },
245
+ { name: "brain", description: "Setup local AI with Ollama" },
246
+ ],
247
+ options: [
248
+ { flags: "--version, -v", description: "Show version number" },
249
+ { flags: "--help, -h", description: "Show help" },
250
+ { flags: "--json", description: "Output in JSON format" },
251
+ { flags: "--no-color", description: "Disable colored output" },
252
+ { flags: "--verbose", description: "Enable verbose logging" },
253
+ ],
254
+ examples: [
255
+ ["mandu init my-app", "Create a new project"],
256
+ ["mandu dev --port 4000", "Start dev server on port 4000"],
257
+ ["mandu build --prod", "Build for production"],
258
+ ["mandu guard --fix", "Check and auto-fix violations"],
259
+ ],
260
+ sections: [
261
+ {
262
+ title: "Environment Variables:",
263
+ content: ` MANDU_OUTPUT Output format (json|pretty|plain)
264
+ NO_COLOR Disable colors (set to any value)
265
+ FORCE_COLOR Force colors even in non-TTY`,
266
+ },
267
+ ],
268
+ seeAlso: [
269
+ "https://mandujs.com/docs",
270
+ "https://github.com/mandujs/mandu",
271
+ ],
272
+ };
273
+
274
+ /**
275
+ * 명령어별 도움말 렌더링
276
+ */
277
+ export function renderCommandHelp(
278
+ commandName: string,
279
+ def: Partial<HelpDefinition>
280
+ ): string {
281
+ return renderHelp({
282
+ name: `mandu ${commandName}`,
283
+ description: def.description ?? "",
284
+ ...def,
285
+ });
286
+ }
287
+
288
+ /**
289
+ * 간단한 사용법 힌트
290
+ */
291
+ export function formatUsageHint(command: string, hint: string): string {
292
+ const rich = isRich();
293
+ const cmd = rich ? theme.accent(command) : command;
294
+ const tip = rich ? theme.muted(hint) : hint;
295
+ return `${tip}\n ${cmd}`;
296
+ }
297
+
298
+ /**
299
+ * 에러 후 도움말 힌트
300
+ */
301
+ export function formatErrorHint(errorMessage: string, helpCommand: string): string {
302
+ const rich = isRich();
303
+ const error = rich ? theme.error(errorMessage) : errorMessage;
304
+ const help = rich ? theme.muted(`Run '${helpCommand}' for more information.`) : `Run '${helpCommand}' for more information.`;
305
+ return `${error}\n\n${help}`;
306
+ }