@mandujs/cli 0.9.45 โ 0.10.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.
- package/package.json +1 -1
- package/src/commands/build.ts +27 -19
- package/src/commands/check.ts +290 -238
- package/src/commands/dev.ts +486 -440
- package/src/commands/init.ts +128 -21
- package/src/commands/lock.ts +434 -0
- package/src/main.ts +445 -428
package/src/main.ts
CHANGED
|
@@ -1,428 +1,445 @@
|
|
|
1
|
-
#!/usr/bin/env bun
|
|
2
|
-
|
|
3
|
-
import { specUpsert } from "./commands/spec-upsert";
|
|
4
|
-
import { generateApply } from "./commands/generate-apply";
|
|
5
|
-
import { guardCheck } from "./commands/guard-check";
|
|
6
|
-
import { guardArch } from "./commands/guard-arch";
|
|
7
|
-
import { check } from "./commands/check";
|
|
8
|
-
import { dev } from "./commands/dev";
|
|
9
|
-
import { init } from "./commands/init";
|
|
10
|
-
import { build } from "./commands/build";
|
|
11
|
-
import { contractCreate, contractValidate, contractBuild, contractDiff } from "./commands/contract";
|
|
12
|
-
import { openAPIGenerate, openAPIServe } from "./commands/openapi";
|
|
13
|
-
import {
|
|
14
|
-
changeBegin,
|
|
15
|
-
changeCommit,
|
|
16
|
-
changeRollback,
|
|
17
|
-
changeStatus,
|
|
18
|
-
changeList,
|
|
19
|
-
changePrune,
|
|
20
|
-
} from "./commands/change";
|
|
21
|
-
import { doctor } from "./commands/doctor";
|
|
22
|
-
import { watch } from "./commands/watch";
|
|
23
|
-
import { brainSetup, brainStatus } from "./commands/brain";
|
|
24
|
-
import { routesGenerate, routesList, routesWatch } from "./commands/routes";
|
|
25
|
-
import { monitor } from "./commands/monitor";
|
|
26
|
-
import {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
routes
|
|
38
|
-
routes
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
guard
|
|
43
|
-
guard
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
brain
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
contract
|
|
56
|
-
contract
|
|
57
|
-
contract
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
openapi
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
change
|
|
64
|
-
change
|
|
65
|
-
change
|
|
66
|
-
change
|
|
67
|
-
change
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
--
|
|
72
|
-
--
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
--
|
|
76
|
-
--
|
|
77
|
-
--
|
|
78
|
-
--
|
|
79
|
-
--
|
|
80
|
-
--
|
|
81
|
-
--
|
|
82
|
-
--
|
|
83
|
-
--
|
|
84
|
-
--
|
|
85
|
-
--
|
|
86
|
-
--
|
|
87
|
-
--
|
|
88
|
-
--
|
|
89
|
-
--
|
|
90
|
-
--
|
|
91
|
-
--
|
|
92
|
-
--
|
|
93
|
-
--
|
|
94
|
-
--
|
|
95
|
-
--
|
|
96
|
-
--
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
bunx mandu
|
|
117
|
-
bunx mandu
|
|
118
|
-
bunx mandu
|
|
119
|
-
bunx mandu
|
|
120
|
-
bunx mandu
|
|
121
|
-
bunx mandu
|
|
122
|
-
bunx mandu
|
|
123
|
-
bunx mandu
|
|
124
|
-
bunx mandu
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
case "
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
import { specUpsert } from "./commands/spec-upsert";
|
|
4
|
+
import { generateApply } from "./commands/generate-apply";
|
|
5
|
+
import { guardCheck } from "./commands/guard-check";
|
|
6
|
+
import { guardArch } from "./commands/guard-arch";
|
|
7
|
+
import { check } from "./commands/check";
|
|
8
|
+
import { dev } from "./commands/dev";
|
|
9
|
+
import { init } from "./commands/init";
|
|
10
|
+
import { build } from "./commands/build";
|
|
11
|
+
import { contractCreate, contractValidate, contractBuild, contractDiff } from "./commands/contract";
|
|
12
|
+
import { openAPIGenerate, openAPIServe } from "./commands/openapi";
|
|
13
|
+
import {
|
|
14
|
+
changeBegin,
|
|
15
|
+
changeCommit,
|
|
16
|
+
changeRollback,
|
|
17
|
+
changeStatus,
|
|
18
|
+
changeList,
|
|
19
|
+
changePrune,
|
|
20
|
+
} from "./commands/change";
|
|
21
|
+
import { doctor } from "./commands/doctor";
|
|
22
|
+
import { watch } from "./commands/watch";
|
|
23
|
+
import { brainSetup, brainStatus } from "./commands/brain";
|
|
24
|
+
import { routesGenerate, routesList, routesWatch } from "./commands/routes";
|
|
25
|
+
import { monitor } from "./commands/monitor";
|
|
26
|
+
import { runLockCommand, lockHelp } from "./commands/lock";
|
|
27
|
+
import { CLI_ERROR_CODES, handleCLIError, printCLIError } from "./errors";
|
|
28
|
+
|
|
29
|
+
const HELP_TEXT = `
|
|
30
|
+
๐ฅ Mandu CLI - Agent-Native Fullstack Framework
|
|
31
|
+
|
|
32
|
+
Usage: bunx mandu <command> [options]
|
|
33
|
+
|
|
34
|
+
Commands:
|
|
35
|
+
init ์ ํ๋ก์ ํธ ์์ฑ (Tailwind + shadcn/ui ๊ธฐ๋ณธ ํฌํจ)
|
|
36
|
+
check FS Routes + Guard ํตํฉ ๊ฒ์ฌ
|
|
37
|
+
routes generate FS Routes ์ค์บ ๋ฐ ๋งค๋ํ์คํธ ์์ฑ
|
|
38
|
+
routes list ํ์ฌ ๋ผ์ฐํธ ๋ชฉ๋ก ์ถ๋ ฅ
|
|
39
|
+
routes watch ์ค์๊ฐ ๋ผ์ฐํธ ๊ฐ์
|
|
40
|
+
dev ๊ฐ๋ฐ ์๋ฒ ์คํ (FS Routes + Guard ๊ธฐ๋ณธ)
|
|
41
|
+
build ํด๋ผ์ด์ธํธ ๋ฒ๋ค ๋น๋ (Hydration)
|
|
42
|
+
guard ์ํคํ
์ฒ ์๋ฐ ๊ฒ์ฌ (๊ธฐ๋ณธ)
|
|
43
|
+
guard arch ์ํคํ
์ฒ ์๋ฐ ๊ฒ์ฌ (FSD/Clean/Hexagonal)
|
|
44
|
+
guard legacy ๋ ๊ฑฐ์ Spec Guard ๊ฒ์ฌ
|
|
45
|
+
spec-upsert Spec ํ์ผ ๊ฒ์ฆ ๋ฐ lock ๊ฐฑ์ (๋ ๊ฑฐ์)
|
|
46
|
+
generate Spec์์ ์ฝ๋ ์์ฑ (๋ ๊ฑฐ์)
|
|
47
|
+
|
|
48
|
+
doctor Guard ์คํจ ๋ถ์ + ํจ์น ์ ์ (Brain)
|
|
49
|
+
watch ์ค์๊ฐ ํ์ผ ๊ฐ์ - ๊ฒฝ๊ณ ๋ง (Brain)
|
|
50
|
+
monitor MCP Activity Monitor ๋ก๊ทธ ์คํธ๋ฆผ
|
|
51
|
+
|
|
52
|
+
brain setup sLLM ์ค์ (์ ํ)
|
|
53
|
+
brain status Brain ์ํ ํ์ธ
|
|
54
|
+
|
|
55
|
+
contract create <routeId> ๋ผ์ฐํธ์ ๋ํ Contract ์์ฑ
|
|
56
|
+
contract validate Contract-Slot ์ผ๊ด์ฑ ๊ฒ์ฆ
|
|
57
|
+
contract build Contract ๋ ์ง์คํธ๋ฆฌ ์์ฑ
|
|
58
|
+
contract diff Contract ๋ณ๊ฒฝ์ฌํญ ๋น๊ต
|
|
59
|
+
|
|
60
|
+
openapi generate OpenAPI 3.0 ์คํ ์์ฑ
|
|
61
|
+
openapi serve Swagger UI ๋ก์ปฌ ์๋ฒ ์คํ
|
|
62
|
+
|
|
63
|
+
change begin ๋ณ๊ฒฝ ํธ๋์ญ์
์์ (์ค๋
์ท ์์ฑ)
|
|
64
|
+
change commit ๋ณ๊ฒฝ ํ์
|
|
65
|
+
change rollback ์ค๋
์ท์ผ๋ก ๋ณต์
|
|
66
|
+
change status ํ์ฌ ํธ๋์ญ์
์ํ
|
|
67
|
+
change list ๋ณ๊ฒฝ ์ด๋ ฅ ์กฐํ
|
|
68
|
+
change prune ์ค๋๋ ์ค๋
์ท ์ ๋ฆฌ
|
|
69
|
+
|
|
70
|
+
lock Lockfile ์์ฑ/๊ฐฑ์
|
|
71
|
+
lock --verify Lockfile ๊ฒ์ฆ (์ค์ ๋ฌด๊ฒฐ์ฑ ํ์ธ)
|
|
72
|
+
lock --diff Lockfile๊ณผ ํ์ฌ ์ค์ ๋น๊ต
|
|
73
|
+
|
|
74
|
+
Options:
|
|
75
|
+
--name <name> init ์ ํ๋ก์ ํธ ์ด๋ฆ (๊ธฐ๋ณธ: my-mandu-app)
|
|
76
|
+
--css <framework> init ์ CSS ํ๋ ์์ํฌ: tailwind, panda, none (๊ธฐ๋ณธ: tailwind)
|
|
77
|
+
--ui <library> init ์ UI ๋ผ์ด๋ธ๋ฌ๋ฆฌ: shadcn, ark, none (๊ธฐ๋ณธ: shadcn)
|
|
78
|
+
--theme init ์ ๋คํฌ๋ชจ๋ ํ
๋ง ์์คํ
์ถ๊ฐ
|
|
79
|
+
--minimal init ์ CSS/UI ์์ด ์ต์ ํ
ํ๋ฆฟ ์์ฑ (--css none --ui none)
|
|
80
|
+
--file <path> spec-upsert spec ํ์ผ/monitor ๋ก๊ทธ ํ์ผ ๊ฒฝ๋ก
|
|
81
|
+
--watch build/guard arch ํ์ผ ๊ฐ์ ๋ชจ๋
|
|
82
|
+
--output <path> routes/openapi/doctor/contract/guard ์ถ๋ ฅ ๊ฒฝ๋ก
|
|
83
|
+
--verbose routes list/watch, contract validate, brain status ์์ธ ์ถ๋ ฅ
|
|
84
|
+
--from <path> contract diff ๊ธฐ์ค ๋ ์ง์คํธ๋ฆฌ ๊ฒฝ๋ก
|
|
85
|
+
--to <path> contract diff ๋์ ๋ ์ง์คํธ๋ฆฌ ๊ฒฝ๋ก
|
|
86
|
+
--json contract diff ๊ฒฐ๊ณผ JSON ์ถ๋ ฅ
|
|
87
|
+
--title <title> openapi generate title
|
|
88
|
+
--version <ver> openapi generate version
|
|
89
|
+
--summary monitor ์์ฝ ์ถ๋ ฅ (JSON ๋ก๊ทธ์์๋ง)
|
|
90
|
+
--since <duration> monitor ์์ฝ ๊ธฐ๊ฐ (์: 5m, 30s, 1h)
|
|
91
|
+
--follow <bool> monitor follow ๋ชจ๋ (๊ธฐ๋ณธ: true)
|
|
92
|
+
--message <msg> change begin ์ ์ค๋ช
๋ฉ์์ง
|
|
93
|
+
--id <id> change rollback ์ ํน์ ๋ณ๊ฒฝ ID
|
|
94
|
+
--keep <n> change prune ์ ์ ์งํ ์ค๋
์ท ์ (๊ธฐ๋ณธ: 5)
|
|
95
|
+
--verify, -v lock ์ lockfile ๊ฒ์ฆ๋ง ์ํ
|
|
96
|
+
--diff, -d lock ์ lockfile๊ณผ ํ์ฌ ์ค์ ๋น๊ต
|
|
97
|
+
--show-secrets lock diff ์ ๋ฏผ๊ฐ์ ๋ณด ์ถ๋ ฅ ํ์ฉ
|
|
98
|
+
--include-snapshot lock ์ ์ค์ ์ค๋
์ท ํฌํจ (diff ๊ธฐ๋ฅ์ ํ์)
|
|
99
|
+
--mode <mode> lock verify ์ ๋ชจ๋ (development|build|ci|production)
|
|
100
|
+
--no-llm doctor์์ LLM ์ฌ์ฉ ์ ํจ (ํ
ํ๋ฆฟ ๋ชจ๋)
|
|
101
|
+
--status watch ์ํ๋ง ์ถ๋ ฅ
|
|
102
|
+
--debounce <ms> watch debounce (ms)
|
|
103
|
+
--model <name> brain setup ์ ๋ชจ๋ธ ์ด๋ฆ (๊ธฐ๋ณธ: llama3.2)
|
|
104
|
+
--url <url> brain setup ์ Ollama URL
|
|
105
|
+
--skip-check brain setup ์ ๋ชจ๋ธ/์๋ฒ ์ฒดํฌ ๊ฑด๋๋
|
|
106
|
+
--help, -h ๋์๋ง ํ์
|
|
107
|
+
|
|
108
|
+
Notes:
|
|
109
|
+
- ์ถ๋ ฅ ํฌ๋งท์ ํ๊ฒฝ์ ๋ฐ๋ผ ์๋ ๊ฒฐ์ ๋ฉ๋๋ค (TTY/CI/MANDU_OUTPUT).
|
|
110
|
+
- doctor ์ถ๋ ฅ์ .json์ด๋ฉด JSON, ๊ทธ ์ธ๋ markdown์ผ๋ก ์ ์ฅ๋ฉ๋๋ค.
|
|
111
|
+
- guard arch ๋ฆฌํฌํธ๋ .json/.html/.md ํ์ฅ์๋ฅผ ์๋ ์ถ๋ก ํฉ๋๋ค.
|
|
112
|
+
- ํฌํธ๋ PORT ํ๊ฒฝ๋ณ์ ๋๋ mandu.config์ server.port๋ก ์ค์ ํฉ๋๋ค.
|
|
113
|
+
- ํฌํธ ์ถฉ๋ ์ ๋ค์ ์ฌ์ฉ ๊ฐ๋ฅํ ํฌํธ๋ก ์๋ ๋ณ๊ฒฝ๋ฉ๋๋ค.
|
|
114
|
+
|
|
115
|
+
Examples:
|
|
116
|
+
bunx mandu init --name my-app # Tailwind + shadcn/ui ๊ธฐ๋ณธ
|
|
117
|
+
bunx mandu init my-app --minimal # CSS/UI ์์ด ์ต์ ํ
ํ๋ฆฟ
|
|
118
|
+
bunx mandu dev
|
|
119
|
+
bunx mandu build --watch
|
|
120
|
+
bunx mandu guard
|
|
121
|
+
bunx mandu guard arch --watch
|
|
122
|
+
bunx mandu guard arch --output guard-report.md
|
|
123
|
+
bunx mandu check
|
|
124
|
+
bunx mandu routes list --verbose
|
|
125
|
+
bunx mandu contract create users
|
|
126
|
+
bunx mandu contract validate --verbose
|
|
127
|
+
bunx mandu contract build --output .mandu/contracts.json
|
|
128
|
+
bunx mandu contract diff --json
|
|
129
|
+
bunx mandu openapi generate --output docs/openapi.json
|
|
130
|
+
bunx mandu openapi serve
|
|
131
|
+
bunx mandu monitor --summary --since 5m
|
|
132
|
+
bunx mandu doctor --output reports/doctor.json
|
|
133
|
+
bunx mandu brain setup --model codellama
|
|
134
|
+
bunx mandu change begin --message "Add new route"
|
|
135
|
+
bunx mandu lock # Lockfile ์์ฑ/๊ฐฑ์
|
|
136
|
+
bunx mandu lock --verify # ์ค์ ๋ฌด๊ฒฐ์ฑ ๊ฒ์ฆ
|
|
137
|
+
bunx mandu lock --diff --show-secrets # ๋ณ๊ฒฝ์ฌํญ ์์ธ ๋น๊ต
|
|
138
|
+
|
|
139
|
+
FS Routes Workflow (๊ถ์ฅ):
|
|
140
|
+
1. init โ 2. app/ ํด๋์ page.tsx ์์ฑ โ 3. dev โ 4. build
|
|
141
|
+
|
|
142
|
+
Legacy Workflow:
|
|
143
|
+
1. init โ 2. spec-upsert โ 3. generate โ 4. build โ 5. guard โ 6. dev
|
|
144
|
+
|
|
145
|
+
Contract-first Workflow:
|
|
146
|
+
1. contract create โ 2. Edit contract โ 3. generate โ 4. Edit slot โ 5. contract validate
|
|
147
|
+
|
|
148
|
+
Brain (sLLM) Workflow:
|
|
149
|
+
1. brain setup โ 2. doctor (๋ถ์) โ 3. watch (๊ฐ์)
|
|
150
|
+
`;
|
|
151
|
+
|
|
152
|
+
function parseArgs(args: string[]): { command: string; options: Record<string, string> } {
|
|
153
|
+
const command = args[0] || "";
|
|
154
|
+
const options: Record<string, string> = {};
|
|
155
|
+
|
|
156
|
+
for (let i = 1; i < args.length; i++) {
|
|
157
|
+
const arg = args[i];
|
|
158
|
+
if (arg.startsWith("--")) {
|
|
159
|
+
const key = arg.slice(2);
|
|
160
|
+
const value = args[i + 1] && !args[i + 1].startsWith("--") ? args[++i] : "true";
|
|
161
|
+
options[key] = value;
|
|
162
|
+
} else if (arg === "-h") {
|
|
163
|
+
options["help"] = "true";
|
|
164
|
+
} else if (!options._positional) {
|
|
165
|
+
// First non-flag argument after command is positional (e.g., project name)
|
|
166
|
+
options._positional = arg;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return { command, options };
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
async function main(): Promise<void> {
|
|
174
|
+
const args = process.argv.slice(2);
|
|
175
|
+
const { command, options } = parseArgs(args);
|
|
176
|
+
|
|
177
|
+
if (options.help || command === "help" || !command) {
|
|
178
|
+
console.log(HELP_TEXT);
|
|
179
|
+
process.exit(0);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
let success = true;
|
|
183
|
+
|
|
184
|
+
switch (command) {
|
|
185
|
+
case "init":
|
|
186
|
+
success = await init({
|
|
187
|
+
name: options.name || options._positional,
|
|
188
|
+
css: options.css as any,
|
|
189
|
+
ui: options.ui as any,
|
|
190
|
+
theme: options.theme === "true",
|
|
191
|
+
minimal: options.minimal === "true",
|
|
192
|
+
});
|
|
193
|
+
break;
|
|
194
|
+
|
|
195
|
+
case "spec-upsert":
|
|
196
|
+
success = await specUpsert({ file: options.file });
|
|
197
|
+
break;
|
|
198
|
+
|
|
199
|
+
case "generate":
|
|
200
|
+
success = await generateApply();
|
|
201
|
+
break;
|
|
202
|
+
|
|
203
|
+
case "check":
|
|
204
|
+
success = await check();
|
|
205
|
+
break;
|
|
206
|
+
|
|
207
|
+
case "guard": {
|
|
208
|
+
const subCommand = args[1];
|
|
209
|
+
const hasSubCommand = subCommand && !subCommand.startsWith("--");
|
|
210
|
+
const guardArchOptions = {
|
|
211
|
+
watch: options.watch === "true",
|
|
212
|
+
output: options.output,
|
|
213
|
+
};
|
|
214
|
+
switch (subCommand) {
|
|
215
|
+
case "arch":
|
|
216
|
+
success = await guardArch(guardArchOptions);
|
|
217
|
+
break;
|
|
218
|
+
case "legacy":
|
|
219
|
+
case "spec":
|
|
220
|
+
success = await guardCheck();
|
|
221
|
+
break;
|
|
222
|
+
default:
|
|
223
|
+
if (hasSubCommand) {
|
|
224
|
+
printCLIError(CLI_ERROR_CODES.UNKNOWN_SUBCOMMAND, {
|
|
225
|
+
command: "guard",
|
|
226
|
+
subcommand,
|
|
227
|
+
});
|
|
228
|
+
console.log("\nUsage: bunx mandu guard <arch|legacy>");
|
|
229
|
+
process.exit(1);
|
|
230
|
+
}
|
|
231
|
+
// ๊ธฐ๋ณธ๊ฐ: architecture guard
|
|
232
|
+
success = await guardArch(guardArchOptions);
|
|
233
|
+
}
|
|
234
|
+
break;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
case "build":
|
|
238
|
+
success = await build({
|
|
239
|
+
watch: options.watch === "true",
|
|
240
|
+
});
|
|
241
|
+
break;
|
|
242
|
+
|
|
243
|
+
case "dev":
|
|
244
|
+
await dev();
|
|
245
|
+
break;
|
|
246
|
+
|
|
247
|
+
case "routes": {
|
|
248
|
+
const subCommand = args[1];
|
|
249
|
+
switch (subCommand) {
|
|
250
|
+
case "generate":
|
|
251
|
+
success = await routesGenerate({
|
|
252
|
+
output: options.output,
|
|
253
|
+
verbose: options.verbose === "true",
|
|
254
|
+
});
|
|
255
|
+
break;
|
|
256
|
+
case "list":
|
|
257
|
+
success = await routesList({
|
|
258
|
+
verbose: options.verbose === "true",
|
|
259
|
+
});
|
|
260
|
+
break;
|
|
261
|
+
case "watch":
|
|
262
|
+
success = await routesWatch({
|
|
263
|
+
output: options.output,
|
|
264
|
+
verbose: options.verbose === "true",
|
|
265
|
+
});
|
|
266
|
+
break;
|
|
267
|
+
default:
|
|
268
|
+
// ๊ธฐ๋ณธ๊ฐ: list
|
|
269
|
+
if (!subCommand) {
|
|
270
|
+
success = await routesList({
|
|
271
|
+
verbose: options.verbose === "true",
|
|
272
|
+
});
|
|
273
|
+
} else {
|
|
274
|
+
printCLIError(CLI_ERROR_CODES.UNKNOWN_SUBCOMMAND, {
|
|
275
|
+
command: "routes",
|
|
276
|
+
subcommand,
|
|
277
|
+
});
|
|
278
|
+
console.log("\nUsage: bunx mandu routes <generate|list|watch>");
|
|
279
|
+
process.exit(1);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
break;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
case "contract": {
|
|
286
|
+
const subCommand = args[1];
|
|
287
|
+
switch (subCommand) {
|
|
288
|
+
case "create": {
|
|
289
|
+
const routeId = args[2] || options._positional;
|
|
290
|
+
if (!routeId) {
|
|
291
|
+
printCLIError(CLI_ERROR_CODES.MISSING_ARGUMENT, { argument: "routeId" });
|
|
292
|
+
console.log("\nUsage: bunx mandu contract create <routeId>");
|
|
293
|
+
process.exit(1);
|
|
294
|
+
}
|
|
295
|
+
success = await contractCreate({ routeId });
|
|
296
|
+
break;
|
|
297
|
+
}
|
|
298
|
+
case "validate":
|
|
299
|
+
success = await contractValidate({ verbose: options.verbose === "true" });
|
|
300
|
+
break;
|
|
301
|
+
case "build":
|
|
302
|
+
success = await contractBuild({ output: options.output });
|
|
303
|
+
break;
|
|
304
|
+
case "diff":
|
|
305
|
+
success = await contractDiff({
|
|
306
|
+
from: options.from,
|
|
307
|
+
to: options.to,
|
|
308
|
+
output: options.output,
|
|
309
|
+
json: options.json === "true",
|
|
310
|
+
});
|
|
311
|
+
break;
|
|
312
|
+
default:
|
|
313
|
+
printCLIError(CLI_ERROR_CODES.UNKNOWN_SUBCOMMAND, {
|
|
314
|
+
command: "contract",
|
|
315
|
+
subcommand,
|
|
316
|
+
});
|
|
317
|
+
console.log("\nUsage: bunx mandu contract <create|validate|build|diff>");
|
|
318
|
+
process.exit(1);
|
|
319
|
+
}
|
|
320
|
+
break;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
case "openapi": {
|
|
324
|
+
const subCommand = args[1];
|
|
325
|
+
switch (subCommand) {
|
|
326
|
+
case "generate":
|
|
327
|
+
success = await openAPIGenerate({
|
|
328
|
+
output: options.output,
|
|
329
|
+
title: options.title,
|
|
330
|
+
version: options.version,
|
|
331
|
+
});
|
|
332
|
+
break;
|
|
333
|
+
case "serve":
|
|
334
|
+
success = await openAPIServe();
|
|
335
|
+
break;
|
|
336
|
+
default:
|
|
337
|
+
printCLIError(CLI_ERROR_CODES.UNKNOWN_SUBCOMMAND, {
|
|
338
|
+
command: "openapi",
|
|
339
|
+
subcommand,
|
|
340
|
+
});
|
|
341
|
+
console.log("\nUsage: bunx mandu openapi <generate|serve>");
|
|
342
|
+
process.exit(1);
|
|
343
|
+
}
|
|
344
|
+
break;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
case "change": {
|
|
348
|
+
const subCommand = args[1];
|
|
349
|
+
switch (subCommand) {
|
|
350
|
+
case "begin":
|
|
351
|
+
success = await changeBegin({ message: options.message });
|
|
352
|
+
break;
|
|
353
|
+
case "commit":
|
|
354
|
+
success = await changeCommit();
|
|
355
|
+
break;
|
|
356
|
+
case "rollback":
|
|
357
|
+
success = await changeRollback({ id: options.id });
|
|
358
|
+
break;
|
|
359
|
+
case "status":
|
|
360
|
+
success = await changeStatus();
|
|
361
|
+
break;
|
|
362
|
+
case "list":
|
|
363
|
+
success = await changeList();
|
|
364
|
+
break;
|
|
365
|
+
case "prune":
|
|
366
|
+
success = await changePrune({
|
|
367
|
+
keep: options.keep ? Number(options.keep) : undefined,
|
|
368
|
+
});
|
|
369
|
+
break;
|
|
370
|
+
default:
|
|
371
|
+
printCLIError(CLI_ERROR_CODES.UNKNOWN_SUBCOMMAND, {
|
|
372
|
+
command: "change",
|
|
373
|
+
subcommand,
|
|
374
|
+
});
|
|
375
|
+
console.log(`\nUsage: bunx mandu change <begin|commit|rollback|status|list|prune>`);
|
|
376
|
+
process.exit(1);
|
|
377
|
+
}
|
|
378
|
+
break;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
case "doctor":
|
|
382
|
+
success = await doctor({
|
|
383
|
+
useLLM: options["no-llm"] !== "true",
|
|
384
|
+
output: options.output,
|
|
385
|
+
});
|
|
386
|
+
break;
|
|
387
|
+
|
|
388
|
+
case "watch":
|
|
389
|
+
success = await watch({
|
|
390
|
+
status: options.status === "true",
|
|
391
|
+
debounce: options.debounce ? Number(options.debounce) : undefined,
|
|
392
|
+
});
|
|
393
|
+
break;
|
|
394
|
+
|
|
395
|
+
case "monitor":
|
|
396
|
+
success = await monitor({
|
|
397
|
+
summary: options.summary === "true",
|
|
398
|
+
since: options.since,
|
|
399
|
+
follow: options.follow === "false" ? false : true,
|
|
400
|
+
file: options.file,
|
|
401
|
+
});
|
|
402
|
+
break;
|
|
403
|
+
|
|
404
|
+
case "brain": {
|
|
405
|
+
const subCommand = args[1];
|
|
406
|
+
switch (subCommand) {
|
|
407
|
+
case "setup":
|
|
408
|
+
success = await brainSetup({
|
|
409
|
+
model: options.model,
|
|
410
|
+
url: options.url,
|
|
411
|
+
skipCheck: options["skip-check"] === "true",
|
|
412
|
+
});
|
|
413
|
+
break;
|
|
414
|
+
case "status":
|
|
415
|
+
success = await brainStatus({
|
|
416
|
+
verbose: options.verbose === "true",
|
|
417
|
+
});
|
|
418
|
+
break;
|
|
419
|
+
default:
|
|
420
|
+
printCLIError(CLI_ERROR_CODES.UNKNOWN_SUBCOMMAND, {
|
|
421
|
+
command: "brain",
|
|
422
|
+
subcommand,
|
|
423
|
+
});
|
|
424
|
+
console.log("\nUsage: bunx mandu brain <setup|status>");
|
|
425
|
+
process.exit(1);
|
|
426
|
+
}
|
|
427
|
+
break;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
case "lock":
|
|
431
|
+
success = await runLockCommand(args.slice(1));
|
|
432
|
+
break;
|
|
433
|
+
|
|
434
|
+
default:
|
|
435
|
+
printCLIError(CLI_ERROR_CODES.UNKNOWN_COMMAND, { command });
|
|
436
|
+
console.log(HELP_TEXT);
|
|
437
|
+
process.exit(1);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
if (!success) {
|
|
441
|
+
process.exit(1);
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
main().catch((error) => handleCLIError(error));
|