@mandujs/cli 0.9.42 → 0.9.43

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.
@@ -15,20 +15,22 @@ import {
15
15
  getBrain,
16
16
  } from "../../../core/src/index";
17
17
  import { resolveFromCwd, getRootDir } from "../util/fs";
18
- import path from "path";
18
+ import path from "path";
19
19
  import fs from "fs/promises";
20
20
 
21
- export interface DoctorOptions {
22
- /** Output format: console, json, or markdown */
23
- format?: "console" | "json" | "markdown";
21
+ export interface DoctorOptions {
22
+ /** Output format: console, json, or markdown */
23
+ format?: "console" | "json" | "markdown";
24
24
  /** Whether to use LLM for enhanced analysis */
25
25
  useLLM?: boolean;
26
26
  /** Output file path (for json/markdown formats) */
27
- output?: string;
28
- }
29
-
30
- export async function doctor(options: DoctorOptions = {}): Promise<boolean> {
31
- const { format = "console", useLLM = true, output } = options;
27
+ output?: string;
28
+ }
29
+
30
+ export async function doctor(options: DoctorOptions = {}): Promise<boolean> {
31
+ const { format, useLLM = true, output } = options;
32
+ const inferredFormat = format ?? (output ? (path.extname(output).toLowerCase() === ".json" ? "json" : "markdown") : undefined);
33
+ const resolvedFormat = inferredFormat ?? "console";
32
34
 
33
35
  const specPath = resolveFromCwd("spec/routes.manifest.json");
34
36
  const rootDir = getRootDir();
@@ -80,12 +82,12 @@ export async function doctor(options: DoctorOptions = {}): Promise<boolean> {
80
82
  });
81
83
 
82
84
  // Output based on format
83
- switch (format) {
84
- case "console":
85
- printDoctorReport(analysis);
86
- break;
87
-
88
- case "json": {
85
+ switch (resolvedFormat) {
86
+ case "console":
87
+ printDoctorReport(analysis);
88
+ break;
89
+
90
+ case "json": {
89
91
  const json = JSON.stringify(
90
92
  {
91
93
  summary: analysis.summary,
@@ -104,10 +106,10 @@ export async function doctor(options: DoctorOptions = {}): Promise<boolean> {
104
106
  } else {
105
107
  console.log(json);
106
108
  }
107
- break;
108
- }
109
-
110
- case "markdown": {
109
+ break;
110
+ }
111
+
112
+ case "markdown": {
111
113
  const md = generateDoctorMarkdownReport(analysis);
112
114
 
113
115
  if (output) {
@@ -116,9 +118,9 @@ export async function doctor(options: DoctorOptions = {}): Promise<boolean> {
116
118
  } else {
117
119
  console.log(md);
118
120
  }
119
- break;
120
- }
121
- }
122
-
123
- return false;
124
- }
121
+ break;
122
+ }
123
+ }
124
+
125
+ return false;
126
+ }
@@ -53,16 +53,25 @@ export interface GuardArchOptions {
53
53
  showTrend?: boolean;
54
54
  }
55
55
 
56
+ function inferReportFormat(output?: string): "json" | "markdown" | "html" | undefined {
57
+ if (!output) return undefined;
58
+ const ext = path.extname(output).toLowerCase();
59
+ if (ext === ".json") return "json";
60
+ if (ext === ".html" || ext === ".htm") return "html";
61
+ if (ext === ".md" || ext === ".markdown") return "markdown";
62
+ return undefined;
63
+ }
64
+
56
65
  export async function guardArch(options: GuardArchOptions = {}): Promise<boolean> {
57
66
  const rootDir = resolveFromCwd(".");
58
67
  const {
59
68
  watch = false,
60
- ci = false,
69
+ ci = process.env.CI === "true",
61
70
  format,
62
71
  quiet = false,
63
72
  listPresets: showPresets = false,
64
73
  output,
65
- reportFormat = "markdown",
74
+ reportFormat = inferReportFormat(options.output) ?? "markdown",
66
75
  saveStats = false,
67
76
  showTrend = false,
68
77
  } = options;
@@ -84,7 +93,7 @@ export async function guardArch(options: GuardArchOptions = {}): Promise<boolean
84
93
  console.log("");
85
94
  }
86
95
 
87
- console.log("Usage: bunx mandu guard arch --preset <name>");
96
+ console.log("Usage: set guard.preset in mandu.config to choose a preset");
88
97
  return true;
89
98
  }
90
99
 
@@ -2,12 +2,11 @@ import fs from "fs/promises";
2
2
  import fsSync from "fs";
3
3
  import path from "path";
4
4
  import { resolveFromCwd, pathExists } from "../util/fs";
5
- import { resolveOutputFormat, type OutputFormat } from "../util/output";
5
+ import { resolveOutputFormat } from "../util/output";
6
6
 
7
7
  type MonitorOutput = "console" | "json";
8
8
 
9
9
  export interface MonitorOptions {
10
- format?: OutputFormat;
11
10
  follow?: boolean;
12
11
  summary?: boolean;
13
12
  since?: string;
@@ -263,7 +262,7 @@ async function followFile(
263
262
 
264
263
  export async function monitor(options: MonitorOptions = {}): Promise<boolean> {
265
264
  const rootDir = resolveFromCwd(".");
266
- const resolved = resolveOutputFormat(options.format);
265
+ const resolved = resolveOutputFormat();
267
266
  const output: MonitorOutput = resolved === "json" || resolved === "agent" ? "json" : "console";
268
267
  const filePath = await resolveLogFile(rootDir, output, options.file);
269
268
 
@@ -3,9 +3,10 @@
3
3
  * OpenAPI 스펙 생성 명령어
4
4
  */
5
5
 
6
- import { loadManifest, generateOpenAPIDocument, openAPIToJSON } from "@mandujs/core";
7
- import path from "path";
8
- import fs from "fs/promises";
6
+ import { generateOpenAPIDocument, openAPIToJSON, validateAndReport } from "@mandujs/core";
7
+ import path from "path";
8
+ import fs from "fs/promises";
9
+ import { resolveManifest } from "../util/manifest";
9
10
 
10
11
  interface OpenAPIGenerateOptions {
11
12
  output?: string;
@@ -13,27 +14,78 @@ interface OpenAPIGenerateOptions {
13
14
  version?: string;
14
15
  }
15
16
 
16
- interface OpenAPIServeOptions {
17
- port?: number;
18
- }
19
-
20
- /**
21
- * Generate OpenAPI specification from contracts
22
- */
23
- export async function openAPIGenerate(options: OpenAPIGenerateOptions = {}): Promise<boolean> {
24
- const rootDir = process.cwd();
25
- const manifestPath = path.join(rootDir, "spec/routes.manifest.json");
26
-
27
- console.log(`\n📄 Generating OpenAPI specification...\n`);
28
-
29
- // Load manifest
30
- const manifestResult = await loadManifest(manifestPath);
31
- if (!manifestResult.success) {
32
- console.error("❌ Failed to load manifest:", manifestResult.errors);
33
- return false;
34
- }
35
-
36
- const manifest = manifestResult.data!;
17
+ interface OpenAPIServeOptions {
18
+ port?: number;
19
+ }
20
+
21
+ function normalizePort(value: string | number | undefined, label: string): number | undefined {
22
+ if (value === undefined || value === null || value === "") {
23
+ return undefined;
24
+ }
25
+ const port = typeof value === "string" ? Number(value) : value;
26
+ if (!Number.isFinite(port) || !Number.isInteger(port)) {
27
+ console.warn(`⚠️ Invalid ${label} value: "${value}" (using default)`);
28
+ return undefined;
29
+ }
30
+ if (port < 1 || port > 65535) {
31
+ console.warn(`⚠️ Invalid ${label} range: ${port} (must be 1-65535, using default)`);
32
+ return undefined;
33
+ }
34
+ return port;
35
+ }
36
+
37
+ function isPortInUse(error: unknown): boolean {
38
+ if (!error || typeof error !== "object") return false;
39
+ const code = (error as { code?: string }).code;
40
+ const message = (error as { message?: string }).message ?? "";
41
+ return code === "EADDRINUSE" || message.includes("EADDRINUSE") || message.includes("address already in use");
42
+ }
43
+
44
+ function serveWithAutoPort(
45
+ startPort: number,
46
+ fetch: (req: Request) => Response
47
+ ): { server: ReturnType<typeof Bun.serve>; port: number; attempts: number } {
48
+ const maxAttempts = 10;
49
+ let lastError: unknown = null;
50
+
51
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
52
+ const candidate = startPort + attempt;
53
+ if (candidate < 1 || candidate > 65535) {
54
+ continue;
55
+ }
56
+ try {
57
+ const server = Bun.serve({ port: candidate, fetch });
58
+ return { server, port: server.port ?? candidate, attempts: attempt };
59
+ } catch (error) {
60
+ if (!isPortInUse(error)) {
61
+ throw error;
62
+ }
63
+ lastError = error;
64
+ }
65
+ }
66
+
67
+ throw lastError ?? new Error(`No available port found starting at ${startPort}`);
68
+ }
69
+
70
+ /**
71
+ * Generate OpenAPI specification from contracts
72
+ */
73
+ export async function openAPIGenerate(options: OpenAPIGenerateOptions = {}): Promise<boolean> {
74
+ const rootDir = process.cwd();
75
+
76
+ console.log(`\n📄 Generating OpenAPI specification...\n`);
77
+
78
+ // Load manifest (FS Routes 우선)
79
+ let manifest: Awaited<ReturnType<typeof resolveManifest>>["manifest"];
80
+ try {
81
+ const config = await validateAndReport(rootDir);
82
+ if (!config) return false;
83
+ const resolved = await resolveManifest(rootDir, { fsRoutes: config.fsRoutes });
84
+ manifest = resolved.manifest;
85
+ } catch (error) {
86
+ console.error("❌ Failed to load manifest:", error instanceof Error ? error.message : error);
87
+ return false;
88
+ }
37
89
 
38
90
  // Count routes with contracts
39
91
  const contractRoutes = manifest.routes.filter((r) => r.contractModule);
@@ -96,10 +148,16 @@ export async function openAPIGenerate(options: OpenAPIGenerateOptions = {}): Pro
96
148
  /**
97
149
  * Serve Swagger UI for OpenAPI documentation
98
150
  */
99
- export async function openAPIServe(options: OpenAPIServeOptions = {}): Promise<boolean> {
100
- const rootDir = process.cwd();
101
- const port = options.port || 8080;
102
- const openAPIPath = path.join(rootDir, "openapi.json");
151
+ export async function openAPIServe(options: OpenAPIServeOptions = {}): Promise<boolean> {
152
+ const rootDir = process.cwd();
153
+ const config = await validateAndReport(rootDir);
154
+ if (!config) return false;
155
+
156
+ const optionPort = normalizePort(options.port, "openapi.port");
157
+ const envPort = normalizePort(process.env.PORT, "PORT");
158
+ const configPort = normalizePort(config.server?.port, "mandu.config server.port");
159
+ const desiredPort = optionPort ?? envPort ?? configPort ?? 8080;
160
+ const openAPIPath = path.join(rootDir, "openapi.json");
103
161
 
104
162
  console.log(`\n🌐 Starting OpenAPI documentation server...\n`);
105
163
 
@@ -154,26 +212,27 @@ export async function openAPIServe(options: OpenAPIServeOptions = {}): Promise<b
154
212
  </html>
155
213
  `.trim();
156
214
 
157
- // Start server
158
- const server = Bun.serve({
159
- port,
160
- fetch(req) {
161
- const url = new URL(req.url);
162
-
163
- if (url.pathname === "/openapi.json") {
164
- return new Response(specContent, {
165
- headers: { "Content-Type": "application/json" },
166
- });
167
- }
168
-
169
- return new Response(swaggerHTML, {
170
- headers: { "Content-Type": "text/html" },
171
- });
172
- },
173
- });
174
-
175
- console.log(`✅ Swagger UI is running at http://localhost:${port}`);
176
- console.log(` OpenAPI spec: http://localhost:${port}/openapi.json`);
215
+ // Start server (auto port fallback)
216
+ const { port, attempts } = serveWithAutoPort(desiredPort, (req) => {
217
+ const url = new URL(req.url);
218
+
219
+ if (url.pathname === "/openapi.json") {
220
+ return new Response(specContent, {
221
+ headers: { "Content-Type": "application/json" },
222
+ });
223
+ }
224
+
225
+ return new Response(swaggerHTML, {
226
+ headers: { "Content-Type": "text/html" },
227
+ });
228
+ });
229
+
230
+ if (attempts > 0) {
231
+ console.warn(`⚠️ Port ${desiredPort} is in use. Using ${port} instead.`);
232
+ }
233
+
234
+ console.log(`✅ Swagger UI is running at http://localhost:${port}`);
235
+ console.log(` OpenAPI spec: http://localhost:${port}/openapi.json`);
177
236
  console.log(`\nPress Ctrl+C to stop.\n`);
178
237
 
179
238
  // Keep server running
@@ -21,7 +21,7 @@ export const ERROR_MESSAGES: Record<CLIErrorCode, ErrorInfo> = {
21
21
  },
22
22
  [CLI_ERROR_CODES.DEV_PORT_IN_USE]: {
23
23
  message: "Port {port} is already in use.",
24
- suggestion: "Use --port to pick a different port or stop the process using this port.",
24
+ suggestion: "Set PORT or mandu.config server.port to pick a different port, or stop the process using this port.",
25
25
  },
26
26
  [CLI_ERROR_CODES.DEV_MANIFEST_NOT_FOUND]: {
27
27
  message: "Routes manifest not found.",
@@ -41,7 +41,7 @@ export const ERROR_MESSAGES: Record<CLIErrorCode, ErrorInfo> = {
41
41
  },
42
42
  [CLI_ERROR_CODES.GUARD_VIOLATION_FOUND]: {
43
43
  message: "{count} architecture violation(s) found.",
44
- suggestion: "Fix violations above or run with --format agent for AI-friendly output.",
44
+ suggestion: "Fix violations above or set MANDU_OUTPUT=agent for AI-friendly output.",
45
45
  },
46
46
  [CLI_ERROR_CODES.BUILD_ENTRY_NOT_FOUND]: {
47
47
  message: "Build entry not found: {entry}",
package/src/main.ts CHANGED
@@ -31,30 +31,25 @@ const HELP_TEXT = `
31
31
  Usage: bunx mandu <command> [options]
32
32
 
33
33
  Commands:
34
- init 새 프로젝트 생성 (Tailwind + shadcn/ui 기본 포함)
35
- check FS Routes + Guard 통합 검사
36
- routes generate FS Routes 스캔 및 매니페스트 생성
37
- routes list 현재 라우트 목록 출력
38
- routes watch 실시간 라우트 감시
39
- dev 개발 서버 실행 (FS Routes + Guard 기본)
40
- dev --no-guard Guard 감시 비활성화
41
- build 클라이언트 번들 빌드 (Hydration)
42
- guard 아키텍처 위반 검사 (기본)
43
- guard arch 아키텍처 위반 검사 (FSD/Clean/Hexagonal)
44
- guard legacy 레거시 Spec Guard 검사
45
- guard arch --watch 실시간 아키텍처 감시
46
- guard arch --list-presets 사용 가능한 프리셋 목록
47
- guard arch --output report.md 리포트 파일 생성
48
- guard arch --show-trend 트렌드 분석 표시
49
- spec-upsert Spec 파일 검증 lock 갱신 (레거시)
50
- generate Spec에서 코드 생성 (레거시)
51
-
52
- doctor Guard 실패 분석 + 패치 제안 (Brain)
53
- watch 실시간 파일 감시 - 경고만 (Brain)
54
- monitor MCP Activity Monitor 로그 스트림
55
-
56
- brain setup sLLM 설정 (선택)
57
- brain status Brain 상태 확인
34
+ init 새 프로젝트 생성 (Tailwind + shadcn/ui 기본 포함)
35
+ check FS Routes + Guard 통합 검사
36
+ routes generate FS Routes 스캔 및 매니페스트 생성
37
+ routes list 현재 라우트 목록 출력
38
+ routes watch 실시간 라우트 감시
39
+ dev 개발 서버 실행 (FS Routes + Guard 기본)
40
+ build 클라이언트 번들 빌드 (Hydration)
41
+ guard 아키텍처 위반 검사 (기본)
42
+ guard arch 아키텍처 위반 검사 (FSD/Clean/Hexagonal)
43
+ guard legacy 레거시 Spec Guard 검사
44
+ spec-upsert Spec 파일 검증 lock 갱신 (레거시)
45
+ generate Spec에서 코드 생성 (레거시)
46
+
47
+ doctor Guard 실패 분석 + 패치 제안 (Brain)
48
+ watch 실시간 파일 감시 - 경고만 (Brain)
49
+ monitor MCP Activity Monitor 로그 스트림
50
+
51
+ brain setup sLLM 설정 (선택)
52
+ brain status Brain 상태 확인
58
53
 
59
54
  contract create <routeId> 라우트에 대한 Contract 생성
60
55
  contract validate Contract-Slot 일관성 검증
@@ -64,79 +59,68 @@ Commands:
64
59
  openapi generate OpenAPI 3.0 스펙 생성
65
60
  openapi serve Swagger UI 로컬 서버 실행
66
61
 
67
- change begin 변경 트랜잭션 시작 (스냅샷 생성)
68
- change commit 변경 확정
69
- change rollback 스냅샷으로 복원
70
- change status 현재 트랜잭션 상태
71
- change list 변경 이력 조회
72
- change prune 오래된 스냅샷 정리
62
+ change begin 변경 트랜잭션 시작 (스냅샷 생성)
63
+ change commit 변경 확정
64
+ change rollback 스냅샷으로 복원
65
+ change status 현재 트랜잭션 상태
66
+ change list 변경 이력 조회
67
+ change prune 오래된 스냅샷 정리
73
68
 
74
69
  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 파일 경로
81
- --port <port> dev/openapi serve 포트 (기본: 3000/8080)
82
- --guard dev Architecture Guard 실시간 감시 활성화 (기본: ON)
83
- --no-guard dev Guard 비활성화
84
- --guard-preset <p> dev --guard 프리셋 (기본: mandu)
85
- --guard-format <f> dev --guard 출력 형식: console, json, agent (기본: 자동)
86
- --legacy FS Routes 비활성화 (레거시 모드)
87
- --no-auto-correct guard 자동 수정 비활성화
88
- --preset <name> guard/check 프리셋 (기본: mandu) - fsd, clean, hexagonal, atomic 선택 가능
89
- --ci guard/check CI 모드 (warning도 실패 처리)
90
- --quiet guard/check 요약만 출력
91
- --report-format guard arch 리포트 형식: json, markdown, html
92
- --save-stats guard arch 통계 저장 (트렌드 분석용)
93
- --show-trend guard arch 트렌드 분석 표시
94
- --minify build코드 압축
95
- --sourcemap build 소스맵 생성
96
- --watch build/guard arch 파일 감시 모드
97
- --summary monitor 요약 출력 (JSON 로그에서만)
98
- --since <duration> monitor 요약 기간 (예: 5m, 30s, 1h)
99
- --follow <bool> monitor follow 모드 (기본: true)
100
- --file <path> monitor 로그 파일 직접 지정
101
- --message <msg> change begin 시 설명 메시지
102
- --id <id> change rollback 시 특정 변경 ID
103
- --keep <n> change prune 시 유지할 스냅샷 수 (기본: 5)
104
- --output <path> openapi/doctor 출력 경로
105
- --from <path> contract diff 기준 레지스트리 경로
106
- --to <path> contract diff 대상 레지스트리 경로
107
- --json contract diff 결과 JSON 출력
108
- --format <fmt> guard/check 출력 형식: console, json, agent (기본: 자동)
109
- --format <fmt> doctor 출력 형식: console, json, markdown (기본: console)
110
- --no-llm doctor에서 LLM 사용 안 함 (템플릿 모드)
111
- --model <name> brain setup 시 모델 이름 (기본: llama3.2)
112
- --url <url> brain setup 시 Ollama URL
113
- --verbose 상세 출력
114
- --help, -h 도움말 표시
70
+ --name <name> init 시 프로젝트 이름 (기본: my-mandu-app)
71
+ --css <framework> init 시 CSS 프레임워크: tailwind, panda, none (기본: tailwind)
72
+ --ui <library> init 시 UI 라이브러리: shadcn, ark, none (기본: shadcn)
73
+ --theme init 시 다크모드 테마 시스템 추가
74
+ --minimal init 시 CSS/UI 없이 최소 템플릿 생성 (--css none --ui none)
75
+ --file <path> spec-upsert spec 파일/monitor 로그 파일 경로
76
+ --watch build/guard arch 파일 감시 모드
77
+ --output <path> routes/openapi/doctor/contract/guard 출력 경로
78
+ --verbose routes list/watch, contract validate, brain status 상세 출력
79
+ --from <path> contract diff 기준 레지스트리 경로
80
+ --to <path> contract diff 대상 레지스트리 경로
81
+ --json contract diff 결과 JSON 출력
82
+ --title <title> openapi generate title
83
+ --version <ver> openapi generate version
84
+ --summary monitor 요약 출력 (JSON 로그에서만)
85
+ --since <duration> monitor 요약 기간 (예: 5m, 30s, 1h)
86
+ --follow <bool> monitor follow 모드 (기본: true)
87
+ --message <msg> change begin 설명 메시지
88
+ --id <id> change rollback 특정 변경 ID
89
+ --keep <n> change prune 유지할 스냅샷 수 (기본: 5)
90
+ --no-llm doctor에서 LLM 사용 안 함 (템플릿 모드)
91
+ --status watch 상태만 출력
92
+ --debounce <ms> watch debounce (ms)
93
+ --model <name> brain setup 모델 이름 (기본: llama3.2)
94
+ --url <url> brain setup Ollama URL
95
+ --skip-check brain setup 모델/서버 체크 건너뜀
96
+ --help, -h 도움말 표시
97
+
98
+ Notes:
99
+ - 출력 포맷은 환경에 따라 자동 결정됩니다 (TTY/CI/MANDU_OUTPUT).
100
+ - doctor 출력은 .json이면 JSON, 그 외는 markdown으로 저장됩니다.
101
+ - guard arch 리포트는 .json/.html/.md 확장자를 자동 추론합니다.
102
+ - 포트는 PORT 환경변수 또는 mandu.config의 server.port로 설정합니다.
103
+ - 포트 충돌 다음 사용 가능한 포트로 자동 변경됩니다.
115
104
 
116
105
  Examples:
117
106
  bunx mandu init --name my-app # Tailwind + shadcn/ui 기본
118
107
  bunx mandu init my-app --minimal # CSS/UI 없이 최소 템플릿
119
- bunx mandu init my-app --theme # 다크모드 테마 포함
120
- bunx mandu init my-app --ui none # UI 라이브러리 없이
121
- bunx mandu check
122
- bunx mandu routes list
123
- bunx mandu routes generate
124
- bunx mandu dev --port 3000
125
- bunx mandu dev --no-guard
126
- bunx mandu build --minify
108
+ bunx mandu dev
109
+ bunx mandu build --watch
127
110
  bunx mandu guard
128
- bunx mandu guard arch --preset fsd
129
111
  bunx mandu guard arch --watch
130
- bunx mandu guard arch --ci --format json
131
- bunx mandu guard legacy
132
- bunx mandu monitor
112
+ bunx mandu guard arch --output guard-report.md
113
+ bunx mandu check
114
+ bunx mandu routes list --verbose
115
+ bunx mandu contract create users
116
+ bunx mandu contract validate --verbose
117
+ bunx mandu contract build --output .mandu/contracts.json
118
+ bunx mandu contract diff --json
119
+ bunx mandu openapi generate --output docs/openapi.json
120
+ bunx mandu openapi serve
133
121
  bunx mandu monitor --summary --since 5m
134
- bunx mandu doctor
122
+ bunx mandu doctor --output reports/doctor.json
135
123
  bunx mandu brain setup --model codellama
136
- bunx mandu contract create users
137
- bunx mandu contract build
138
- bunx mandu contract diff
139
- bunx mandu openapi generate --output docs/api.json
140
124
  bunx mandu change begin --message "Add new route"
141
125
 
142
126
  FS Routes Workflow (권장):
@@ -173,31 +157,6 @@ function parseArgs(args: string[]): { command: string; options: Record<string, s
173
157
  return { command, options };
174
158
  }
175
159
 
176
- /**
177
- * 포트 옵션 안전하게 파싱
178
- * - 숫자가 아니면 undefined 반환 (기본값 사용)
179
- * - 유효 범위: 1-65535
180
- */
181
- function parsePort(value: string | undefined, optionName = "port"): number | undefined {
182
- if (!value || value === "true") {
183
- return undefined; // 기본값 사용
184
- }
185
-
186
- const port = Number(value);
187
-
188
- if (Number.isNaN(port)) {
189
- console.warn(`⚠️ Invalid --${optionName} value: "${value}" (using default)`);
190
- return undefined;
191
- }
192
-
193
- if (!Number.isInteger(port) || port < 1 || port > 65535) {
194
- console.warn(`⚠️ Invalid --${optionName} range: ${port} (must be 1-65535, using default)`);
195
- return undefined;
196
- }
197
-
198
- return port;
199
- }
200
-
201
160
  async function main(): Promise<void> {
202
161
  const args = process.argv.slice(2);
203
162
  const { command, options } = parseArgs(args);
@@ -229,30 +188,15 @@ async function main(): Promise<void> {
229
188
  break;
230
189
 
231
190
  case "check":
232
- success = await check({
233
- preset: options.preset as any,
234
- format: options.format as any,
235
- ci: options.ci === "true",
236
- quiet: options.quiet === "true",
237
- legacy: options.legacy === "true",
238
- });
191
+ success = await check();
239
192
  break;
240
193
 
241
194
  case "guard": {
242
195
  const subCommand = args[1];
243
196
  const hasSubCommand = subCommand && !subCommand.startsWith("--");
244
197
  const guardArchOptions = {
245
- preset: options.preset as any,
246
198
  watch: options.watch === "true",
247
- ci: options.ci === "true",
248
- format: options.format as any,
249
- quiet: options.quiet === "true",
250
- srcDir: options["src-dir"],
251
- listPresets: options["list-presets"] === "true",
252
199
  output: options.output,
253
- reportFormat: (options["report-format"] as any) || "markdown",
254
- saveStats: options["save-stats"] === "true",
255
- showTrend: options["show-trend"] === "true",
256
200
  };
257
201
  switch (subCommand) {
258
202
  case "arch":
@@ -260,9 +204,7 @@ async function main(): Promise<void> {
260
204
  break;
261
205
  case "legacy":
262
206
  case "spec":
263
- success = await guardCheck({
264
- autoCorrect: options["no-auto-correct"] !== "true",
265
- });
207
+ success = await guardCheck();
266
208
  break;
267
209
  default:
268
210
  if (hasSubCommand) {
@@ -281,20 +223,12 @@ async function main(): Promise<void> {
281
223
 
282
224
  case "build":
283
225
  success = await build({
284
- minify: options.minify === "true",
285
- sourcemap: options.sourcemap === "true",
286
226
  watch: options.watch === "true",
287
227
  });
288
228
  break;
289
229
 
290
230
  case "dev":
291
- await dev({
292
- port: parsePort(options.port),
293
- guard: options["no-guard"] === "true" ? false : options.guard !== "false",
294
- guardPreset: options["guard-preset"] as any,
295
- guardFormat: options["guard-format"] as any,
296
- legacy: options.legacy === "true",
297
- });
231
+ await dev();
298
232
  break;
299
233
 
300
234
  case "routes": {
@@ -384,9 +318,7 @@ async function main(): Promise<void> {
384
318
  });
385
319
  break;
386
320
  case "serve":
387
- success = await openAPIServe({
388
- port: parsePort(options.port),
389
- });
321
+ success = await openAPIServe();
390
322
  break;
391
323
  default:
392
324
  printCLIError(CLI_ERROR_CODES.UNKNOWN_SUBCOMMAND, {
@@ -435,7 +367,6 @@ async function main(): Promise<void> {
435
367
 
436
368
  case "doctor":
437
369
  success = await doctor({
438
- format: (options.format as "console" | "json" | "markdown") || "console",
439
370
  useLLM: options["no-llm"] !== "true",
440
371
  output: options.output,
441
372
  });
@@ -450,7 +381,6 @@ async function main(): Promise<void> {
450
381
 
451
382
  case "monitor":
452
383
  success = await monitor({
453
- format: options.format as any,
454
384
  summary: options.summary === "true",
455
385
  since: options.since,
456
386
  follow: options.follow === "false" ? false : true,