sdd-tool 0.3.0 → 0.5.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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/errors/codes.ts","../../src/errors/messages.ts","../../src/errors/base.ts","../../src/errors/index.ts","../../src/types/index.ts","../../src/utils/fs.ts","../../src/core/new/schemas.ts","../../src/core/new/spec-generator.ts","../../src/core/new/plan-generator.ts","../../src/core/new/task-generator.ts","../../src/core/new/branch.ts","../../src/core/new/checklist.ts","../../src/core/new/counter.ts","../../src/core/new/index.ts","../../src/cli/index.ts","../../src/cli/commands/init.ts","../../src/utils/logger.ts","../../src/generators/agents-md.ts","../../src/generators/claude-commands.ts","../../src/cli/commands/validate.ts","../../src/core/spec/validator.ts","../../src/core/spec/parser.ts","../../src/core/spec/schemas.ts","../../src/prompts/index.ts","../../src/cli/commands/prompt.ts","../../src/cli/commands/change.ts","../../src/core/change/schemas.ts","../../src/core/change/proposal.ts","../../src/core/change/delta.ts","../../src/core/change/archive.ts","../../src/cli/commands/impact.ts","../../src/core/impact/schemas.ts","../../src/core/impact/graph.ts","../../src/core/impact/analyzer.ts","../../src/cli/commands/new.ts","../../src/utils/index.ts","../../src/core/constitution/schemas.ts","../../src/core/constitution/parser.ts","../../src/core/constitution/changelog.ts","../../src/cli/commands/status.ts","../../src/cli/commands/list.ts","../../src/cli/commands/constitution.ts","../../src/cli/commands/start.ts","../../src/cli/commands/migrate.ts","../../src/cli/commands/cicd.ts","../../src/cli/commands/transition.ts"],"sourcesContent":["/**\r\n * 에러 코드 정의\r\n */\r\n\r\n/**\r\n * CLI 종료 코드\r\n */\r\nexport const ExitCode = {\r\n SUCCESS: 0,\r\n GENERAL_ERROR: 1,\r\n VALIDATION_FAILED: 2,\r\n CONSTITUTION_VIOLATION: 3,\r\n FILE_SYSTEM_ERROR: 4,\r\n USER_CANCELLED: 5,\r\n} as const;\r\n\r\nexport type ExitCode = (typeof ExitCode)[keyof typeof ExitCode];\r\n\r\n/**\r\n * 에러 코드\r\n */\r\nexport const ErrorCode = {\r\n // 일반 에러 (E0xx)\r\n UNKNOWN: 'E001',\r\n INVALID_ARGUMENT: 'E002',\r\n NOT_INITIALIZED: 'E003',\r\n\r\n // 파일 시스템 에러 (E1xx)\r\n FILE_NOT_FOUND: 'E101',\r\n FILE_READ_ERROR: 'E102',\r\n FILE_WRITE_ERROR: 'E103',\r\n DIRECTORY_NOT_FOUND: 'E104',\r\n DIRECTORY_EXISTS: 'E105',\r\n\r\n // 스펙 검증 에러 (E2xx)\r\n SPEC_PARSE_ERROR: 'E201',\r\n SPEC_INVALID_FORMAT: 'E202',\r\n SPEC_MISSING_REQUIRED: 'E203',\r\n RFC2119_VIOLATION: 'E204',\r\n GWT_INVALID_FORMAT: 'E205',\r\n\r\n // Constitution 에러 (E3xx)\r\n CONSTITUTION_NOT_FOUND: 'E301',\r\n CONSTITUTION_PARSE_ERROR: 'E302',\r\n CONSTITUTION_VIOLATION: 'E303',\r\n\r\n // 변경 워크플로우 에러 (E4xx)\r\n PROPOSAL_NOT_FOUND: 'E401',\r\n PROPOSAL_INVALID: 'E402',\r\n DELTA_CONFLICT: 'E403',\r\n ARCHIVE_FAILED: 'E404',\r\n\r\n // 분석 에러 (E5xx)\r\n ANALYSIS_FAILED: 'E501',\r\n INSUFFICIENT_DATA: 'E502',\r\n} as const;\r\n\r\nexport type ErrorCode = (typeof ErrorCode)[keyof typeof ErrorCode];\r\n","/**\r\n * 에러 메시지 정의\r\n */\r\nimport { ErrorCode } from './codes.js';\r\n\r\n/**\r\n * 에러 코드별 메시지 템플릿\r\n */\r\nexport const ErrorMessages: Record<ErrorCode, string> = {\r\n // 일반 에러\r\n [ErrorCode.UNKNOWN]: '알 수 없는 오류가 발생했습니다',\r\n [ErrorCode.INVALID_ARGUMENT]: '잘못된 인자입니다: {0}',\r\n [ErrorCode.NOT_INITIALIZED]: 'SDD 프로젝트가 초기화되지 않았습니다. `sdd init`을 먼저 실행하세요',\r\n\r\n // 파일 시스템 에러\r\n [ErrorCode.FILE_NOT_FOUND]: '파일을 찾을 수 없습니다: {0}',\r\n [ErrorCode.FILE_READ_ERROR]: '파일 읽기 실패: {0}',\r\n [ErrorCode.FILE_WRITE_ERROR]: '파일 쓰기 실패: {0}',\r\n [ErrorCode.DIRECTORY_NOT_FOUND]: '디렉토리를 찾을 수 없습니다: {0}',\r\n [ErrorCode.DIRECTORY_EXISTS]: '디렉토리가 이미 존재합니다: {0}',\r\n\r\n // 스펙 검증 에러\r\n [ErrorCode.SPEC_PARSE_ERROR]: '스펙 파싱 실패: {0}',\r\n [ErrorCode.SPEC_INVALID_FORMAT]: '잘못된 스펙 형식: {0}',\r\n [ErrorCode.SPEC_MISSING_REQUIRED]: '필수 필드 누락: {0}',\r\n [ErrorCode.RFC2119_VIOLATION]: 'RFC 2119 형식 위반: {0}',\r\n [ErrorCode.GWT_INVALID_FORMAT]: 'GIVEN-WHEN-THEN 형식 위반: {0}',\r\n\r\n // Constitution 에러\r\n [ErrorCode.CONSTITUTION_NOT_FOUND]: 'constitution.md를 찾을 수 없습니다',\r\n [ErrorCode.CONSTITUTION_PARSE_ERROR]: 'Constitution 파싱 실패: {0}',\r\n [ErrorCode.CONSTITUTION_VIOLATION]: 'Constitution 원칙 위반: {0}',\r\n\r\n // 변경 워크플로우 에러\r\n [ErrorCode.PROPOSAL_NOT_FOUND]: '제안서를 찾을 수 없습니다: {0}',\r\n [ErrorCode.PROPOSAL_INVALID]: '잘못된 제안서 형식: {0}',\r\n [ErrorCode.DELTA_CONFLICT]: '델타 충돌: {0}',\r\n [ErrorCode.ARCHIVE_FAILED]: '아카이브 실패: {0}',\r\n\r\n // 분석 에러\r\n [ErrorCode.ANALYSIS_FAILED]: '분석 실패: {0}',\r\n [ErrorCode.INSUFFICIENT_DATA]: '분석에 필요한 데이터 부족: {0}',\r\n};\r\n\r\n/**\r\n * 메시지 템플릿에 인자를 적용\r\n */\r\nexport function formatMessage(code: ErrorCode, ...args: string[]): string {\r\n let message = ErrorMessages[code];\r\n args.forEach((arg, index) => {\r\n message = message.replace(`{${index}}`, arg);\r\n });\r\n return message;\r\n}\r\n","/**\r\n * 에러 기본 클래스\r\n */\r\nimport { ErrorCode, ExitCode } from './codes.js';\r\nimport { formatMessage } from './messages.js';\r\n\r\n/**\r\n * SDD 도구의 기본 에러 클래스\r\n */\r\nexport class SddError extends Error {\r\n readonly code: ErrorCode;\r\n readonly exitCode: ExitCode;\r\n\r\n constructor(\r\n code: ErrorCode,\r\n message?: string,\r\n exitCode: ExitCode = ExitCode.GENERAL_ERROR\r\n ) {\r\n super(message ?? formatMessage(code));\r\n this.name = 'SddError';\r\n this.code = code;\r\n this.exitCode = exitCode;\r\n Error.captureStackTrace?.(this, this.constructor);\r\n }\r\n\r\n /**\r\n * 사용자 친화적 메시지\r\n */\r\n toUserMessage(): string {\r\n return `[${this.code}] ${this.message}`;\r\n }\r\n}\r\n\r\n/**\r\n * 파일 시스템 에러\r\n */\r\nexport class FileSystemError extends SddError {\r\n readonly path: string;\r\n\r\n constructor(code: ErrorCode, path: string) {\r\n super(code, formatMessage(code, path), ExitCode.FILE_SYSTEM_ERROR);\r\n this.name = 'FileSystemError';\r\n this.path = path;\r\n }\r\n}\r\n\r\n/**\r\n * 스펙 검증 에러\r\n */\r\nexport class ValidationError extends SddError {\r\n readonly details: string;\r\n\r\n constructor(code: ErrorCode, details: string) {\r\n super(code, formatMessage(code, details), ExitCode.VALIDATION_FAILED);\r\n this.name = 'ValidationError';\r\n this.details = details;\r\n }\r\n}\r\n\r\n/**\r\n * Constitution 위반 에러\r\n */\r\nexport class ConstitutionError extends SddError {\r\n readonly principle: string;\r\n\r\n constructor(principle: string) {\r\n super(\r\n ErrorCode.CONSTITUTION_VIOLATION,\r\n formatMessage(ErrorCode.CONSTITUTION_VIOLATION, principle),\r\n ExitCode.CONSTITUTION_VIOLATION\r\n );\r\n this.name = 'ConstitutionError';\r\n this.principle = principle;\r\n }\r\n}\r\n\r\n/**\r\n * 사용자 취소 에러\r\n */\r\nexport class UserCancelledError extends SddError {\r\n constructor(message = '사용자가 작업을 취소했습니다') {\r\n super(ErrorCode.UNKNOWN, message, ExitCode.USER_CANCELLED);\r\n this.name = 'UserCancelledError';\r\n }\r\n}\r\n\r\n/**\r\n * 변경 워크플로우 에러\r\n */\r\nexport class ChangeError extends SddError {\r\n constructor(message: string) {\r\n super(ErrorCode.UNKNOWN, message, ExitCode.GENERAL_ERROR);\r\n this.name = 'ChangeError';\r\n }\r\n}\r\n","/**\r\n * 에러 모듈 내보내기\r\n */\r\nexport * from './codes.js';\r\nexport * from './messages.js';\r\nexport * from './base.js';\r\n","/**\r\n * 공통 타입 정의\r\n */\r\n\r\n// ============================================================\r\n// 스펙 관련 타입\r\n// ============================================================\r\n\r\n/**\r\n * 스펙 문서 구조\r\n */\r\nexport interface Spec {\r\n id: string;\r\n title: string;\r\n status: SpecStatus;\r\n requirements: Requirement[];\r\n scenarios: Scenario[];\r\n dependencies: string[];\r\n metadata: SpecMetadata;\r\n}\r\n\r\nexport type SpecStatus = 'draft' | 'approved' | 'implemented';\r\n\r\nexport interface SpecMetadata {\r\n created?: string;\r\n updated?: string;\r\n author?: string;\r\n}\r\n\r\n/**\r\n * 요구사항 (RFC 2119)\r\n */\r\nexport interface Requirement {\r\n id: string;\r\n level: RequirementLevel;\r\n description: string;\r\n}\r\n\r\nexport type RequirementLevel = 'SHALL' | 'MUST' | 'SHOULD' | 'MAY';\r\n\r\n/**\r\n * 시나리오 (GIVEN-WHEN-THEN)\r\n */\r\nexport interface Scenario {\r\n name: string;\r\n given: string[];\r\n when: string;\r\n then: string[];\r\n}\r\n\r\n// ============================================================\r\n// Constitution 관련 타입\r\n// ============================================================\r\n\r\n/**\r\n * Constitution 원칙\r\n */\r\nexport interface Principle {\r\n id: string;\r\n title: string;\r\n description: string;\r\n level: PrincipleLevel;\r\n}\r\n\r\nexport type PrincipleLevel = 'core' | 'technical' | 'forbidden';\r\n\r\nexport interface Constitution {\r\n projectName: string;\r\n principles: Principle[];\r\n technicalStack?: string[];\r\n constraints?: string[];\r\n}\r\n\r\n// ============================================================\r\n// 변경 워크플로우 관련 타입\r\n// ============================================================\r\n\r\n/**\r\n * 변경 제안\r\n */\r\nexport interface Proposal {\r\n id: string;\r\n title: string;\r\n rationale: string;\r\n affectedSpecs: string[];\r\n deltas: Delta[];\r\n status: ProposalStatus;\r\n createdAt: string;\r\n}\r\n\r\nexport type ProposalStatus = 'draft' | 'review' | 'approved' | 'applied' | 'archived';\r\n\r\n/**\r\n * 델타 (변경사항)\r\n */\r\nexport interface Delta {\r\n type: DeltaType;\r\n target: string;\r\n before?: string;\r\n after?: string;\r\n}\r\n\r\nexport type DeltaType = 'ADDED' | 'MODIFIED' | 'REMOVED';\r\n\r\n// ============================================================\r\n// 검증 관련 타입\r\n// ============================================================\r\n\r\n/**\r\n * 검증 결과\r\n */\r\nexport interface ValidationResult {\r\n valid: boolean;\r\n errors: SpecValidationError[];\r\n warnings: SpecValidationWarning[];\r\n}\r\n\r\nexport interface SpecValidationError {\r\n code: string;\r\n message: string;\r\n location?: Location;\r\n}\r\n\r\nexport interface SpecValidationWarning {\r\n code: string;\r\n message: string;\r\n location?: Location;\r\n}\r\n\r\nexport interface Location {\r\n file?: string;\r\n line?: number;\r\n column?: number;\r\n}\r\n\r\n// ============================================================\r\n// 분석 관련 타입\r\n// ============================================================\r\n\r\n/**\r\n * 분석 결과\r\n */\r\nexport interface AnalysisResult {\r\n scale: Scale;\r\n recommendation: WorkflowRecommendation;\r\n confidence: number;\r\n rationale: string;\r\n alternatives: string[];\r\n}\r\n\r\nexport type Scale = 'small' | 'medium' | 'large';\r\nexport type WorkflowRecommendation = 'direct' | 'change' | 'new';\r\n\r\n// ============================================================\r\n// 유틸리티 타입\r\n// ============================================================\r\n\r\n/**\r\n * Result 타입 (에러 처리용)\r\n */\r\nexport type Result<T, E = Error> =\r\n | { success: true; data: T }\r\n | { success: false; error: E };\r\n\r\n/**\r\n * 성공 결과 생성 헬퍼\r\n */\r\nexport function success<T>(data: T): Result<T, never> {\r\n return { success: true, data };\r\n}\r\n\r\n/**\r\n * 실패 결과 생성 헬퍼\r\n */\r\nexport function failure<E>(error: E): Result<never, E> {\r\n return { success: false, error };\r\n}\r\n","/**\r\n * 파일 시스템 유틸리티\r\n */\r\nimport { promises as fs } from 'node:fs';\r\nimport path from 'node:path';\r\nimport { FileSystemError } from '../errors/index.js';\r\nimport { ErrorCode } from '../errors/codes.js';\r\nimport { Result, success, failure } from '../types/index.js';\r\n\r\n/**\r\n * 파일 존재 여부 확인\r\n */\r\nexport async function fileExists(filePath: string): Promise<boolean> {\r\n try {\r\n await fs.access(filePath);\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * 디렉토리 존재 여부 확인\r\n */\r\nexport async function directoryExists(dirPath: string): Promise<boolean> {\r\n try {\r\n const stat = await fs.stat(dirPath);\r\n return stat.isDirectory();\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * 파일 읽기\r\n */\r\nexport async function readFile(filePath: string): Promise<Result<string, FileSystemError>> {\r\n try {\r\n const content = await fs.readFile(filePath, 'utf-8');\r\n return success(content);\r\n } catch (error) {\r\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\r\n return failure(new FileSystemError(ErrorCode.FILE_NOT_FOUND, filePath));\r\n }\r\n return failure(new FileSystemError(ErrorCode.FILE_READ_ERROR, filePath));\r\n }\r\n}\r\n\r\n/**\r\n * 파일 쓰기\r\n */\r\nexport async function writeFile(\r\n filePath: string,\r\n content: string\r\n): Promise<Result<void, FileSystemError>> {\r\n try {\r\n const dir = path.dirname(filePath);\r\n await fs.mkdir(dir, { recursive: true });\r\n await fs.writeFile(filePath, content, 'utf-8');\r\n return success(undefined);\r\n } catch {\r\n return failure(new FileSystemError(ErrorCode.FILE_WRITE_ERROR, filePath));\r\n }\r\n}\r\n\r\n/**\r\n * 디렉토리 생성\r\n */\r\nexport async function ensureDir(dirPath: string): Promise<Result<void, FileSystemError>> {\r\n try {\r\n await fs.mkdir(dirPath, { recursive: true });\r\n return success(undefined);\r\n } catch {\r\n return failure(new FileSystemError(ErrorCode.FILE_WRITE_ERROR, dirPath));\r\n }\r\n}\r\n\r\n/**\r\n * 디렉토리 내 파일 목록\r\n */\r\nexport async function listFiles(\r\n dirPath: string,\r\n pattern?: RegExp\r\n): Promise<Result<string[], FileSystemError>> {\r\n try {\r\n const entries = await fs.readdir(dirPath, { withFileTypes: true });\r\n let files = entries\r\n .filter((entry) => entry.isFile())\r\n .map((entry) => path.join(dirPath, entry.name));\r\n\r\n if (pattern) {\r\n files = files.filter((file) => pattern.test(path.basename(file)));\r\n }\r\n\r\n return success(files);\r\n } catch {\r\n return failure(new FileSystemError(ErrorCode.DIRECTORY_NOT_FOUND, dirPath));\r\n }\r\n}\r\n\r\n/**\r\n * 디렉토리 내 항목 목록\r\n */\r\nexport async function readDir(dirPath: string): Promise<Result<string[], FileSystemError>> {\r\n try {\r\n const entries = await fs.readdir(dirPath);\r\n return success(entries);\r\n } catch {\r\n return failure(new FileSystemError(ErrorCode.DIRECTORY_NOT_FOUND, dirPath));\r\n }\r\n}\r\n\r\n/**\r\n * SDD 프로젝트 루트 찾기\r\n */\r\nexport async function findSddRoot(startPath: string = process.cwd()): Promise<string | null> {\r\n let currentPath = path.resolve(startPath);\r\n const root = path.parse(currentPath).root;\r\n\r\n while (currentPath !== root) {\r\n const sddPath = path.join(currentPath, '.sdd');\r\n if (await directoryExists(sddPath)) {\r\n return currentPath;\r\n }\r\n currentPath = path.dirname(currentPath);\r\n }\r\n\r\n return null;\r\n}\r\n\r\n/**\r\n * 디렉토리 복사 (재귀)\r\n */\r\nexport async function copyDir(\r\n srcPath: string,\r\n destPath: string\r\n): Promise<Result<void, FileSystemError>> {\r\n try {\r\n await fs.mkdir(destPath, { recursive: true });\r\n\r\n const entries = await fs.readdir(srcPath, { withFileTypes: true });\r\n\r\n for (const entry of entries) {\r\n const srcEntry = path.join(srcPath, entry.name);\r\n const destEntry = path.join(destPath, entry.name);\r\n\r\n if (entry.isDirectory()) {\r\n const result = await copyDir(srcEntry, destEntry);\r\n if (!result.success) {\r\n return result;\r\n }\r\n } else {\r\n await fs.copyFile(srcEntry, destEntry);\r\n }\r\n }\r\n\r\n return success(undefined);\r\n } catch {\r\n return failure(new FileSystemError(ErrorCode.FILE_WRITE_ERROR, destPath));\r\n }\r\n}\r\n\r\n/**\r\n * 디렉토리 삭제 (재귀)\r\n */\r\nexport async function removeDir(dirPath: string): Promise<Result<void, FileSystemError>> {\r\n try {\r\n await fs.rm(dirPath, { recursive: true, force: true });\r\n return success(undefined);\r\n } catch {\r\n return failure(new FileSystemError(ErrorCode.FILE_WRITE_ERROR, dirPath));\r\n }\r\n}\r\n","/**\r\n * 신규 기능 워크플로우 스키마\r\n */\r\nimport { z } from 'zod';\r\n\r\n/**\r\n * 기능 상태 스키마\r\n */\r\nexport const FeatureStatusSchema = z.enum([\r\n 'draft', // 초안 작성 중\r\n 'specified', // 명세 완료\r\n 'planned', // 계획 완료\r\n 'tasked', // 작업 분해 완료\r\n 'implementing', // 구현 중\r\n 'completed', // 완료\r\n]);\r\n\r\nexport type FeatureStatus = z.infer<typeof FeatureStatusSchema>;\r\n\r\n/**\r\n * 작업 상태 스키마\r\n */\r\nexport const TaskStatusSchema = z.enum([\r\n 'pending', // 대기 중\r\n 'in_progress', // 진행 중\r\n 'completed', // 완료\r\n 'blocked', // 차단됨\r\n]);\r\n\r\nexport type TaskStatus = z.infer<typeof TaskStatusSchema>;\r\n\r\n/**\r\n * 작업 우선순위 스키마\r\n */\r\nexport const TaskPrioritySchema = z.enum([\r\n 'high', // 높음\r\n 'medium', // 중간\r\n 'low', // 낮음\r\n]);\r\n\r\nexport type TaskPriority = z.infer<typeof TaskPrioritySchema>;\r\n\r\n/**\r\n * 기능 메타데이터 스키마\r\n */\r\nexport const FeatureMetadataSchema = z.object({\r\n id: z.string(),\r\n title: z.string(),\r\n status: FeatureStatusSchema,\r\n created: z.string(),\r\n updated: z.string().optional(),\r\n branch: z.string().optional(),\r\n depends: z.array(z.string()).nullable().default(null),\r\n});\r\n\r\nexport type FeatureMetadata = z.infer<typeof FeatureMetadataSchema>;\r\n\r\n/**\r\n * 작업 항목 스키마\r\n */\r\nexport const TaskItemSchema = z.object({\r\n id: z.string(),\r\n title: z.string(),\r\n description: z.string().optional(),\r\n status: TaskStatusSchema,\r\n priority: TaskPrioritySchema,\r\n assignee: z.string().optional(),\r\n files: z.array(z.string()).optional(),\r\n dependencies: z.array(z.string()).optional(),\r\n});\r\n\r\nexport type TaskItem = z.infer<typeof TaskItemSchema>;\r\n\r\n/**\r\n * 구현 계획 스키마\r\n */\r\nexport const PlanSchema = z.object({\r\n overview: z.string(),\r\n techDecisions: z.array(z.object({\r\n decision: z.string(),\r\n rationale: z.string(),\r\n alternatives: z.array(z.string()).optional(),\r\n })),\r\n phases: z.array(z.object({\r\n name: z.string(),\r\n description: z.string(),\r\n deliverables: z.array(z.string()),\r\n })),\r\n risks: z.array(z.object({\r\n risk: z.string(),\r\n mitigation: z.string(),\r\n impact: z.enum(['high', 'medium', 'low']),\r\n })).optional(),\r\n testingStrategy: z.string().optional(),\r\n});\r\n\r\nexport type Plan = z.infer<typeof PlanSchema>;\r\n\r\n/**\r\n * 기능 ID 생성\r\n */\r\nexport function generateFeatureId(name: string): string {\r\n return name\r\n .toLowerCase()\r\n .replace(/[^a-z0-9가-힣]+/g, '-')\r\n .replace(/^-+|-+$/g, '')\r\n .slice(0, 50);\r\n}\r\n\r\n/**\r\n * 작업 ID 생성\r\n */\r\nexport function generateTaskId(featureId: string, index: number): string {\r\n return `${featureId}-task-${String(index).padStart(3, '0')}`;\r\n}\r\n\r\n/**\r\n * 브랜치명 생성\r\n */\r\nexport function generateBranchName(featureId: string): string {\r\n return `feature/${featureId}`;\r\n}\r\n","/**\r\n * 기능 명세 생성기\r\n */\r\nimport { FeatureMetadata, FeatureStatus } from './schemas.js';\r\n\r\n/**\r\n * 명세 생성 옵션\r\n */\r\nexport interface GenerateSpecOptions {\r\n id: string;\r\n title: string;\r\n description: string;\r\n requirements?: string[];\r\n scenarios?: Array<{\r\n name: string;\r\n given: string;\r\n when: string;\r\n then: string;\r\n }>;\r\n depends?: string[];\r\n status?: FeatureStatus;\r\n constitutionVersion?: string;\r\n}\r\n\r\n/**\r\n * spec.md 파일 내용 생성\r\n */\r\nexport function generateSpec(options: GenerateSpecOptions): string {\r\n const today = new Date().toISOString().split('T')[0];\r\n const status = options.status || 'draft';\r\n const depends = options.depends?.length ? `\\n - ${options.depends.join('\\n - ')}` : 'null';\r\n const constitutionLine = options.constitutionVersion\r\n ? `\\nconstitution_version: ${options.constitutionVersion}`\r\n : '';\r\n\r\n let content = `---\r\nid: ${options.id}\r\ntitle: \"${options.title}\"\r\nstatus: ${status}\r\ncreated: ${today}\r\ndepends: ${depends}${constitutionLine}\r\n---\r\n\r\n# ${options.title}\r\n\r\n> ${options.description}\r\n\r\n---\r\n\r\n## 개요\r\n\r\n${options.description}\r\n\r\n---\r\n\r\n## 요구사항\r\n\r\n`;\r\n\r\n if (options.requirements?.length) {\r\n options.requirements.forEach((req, index) => {\r\n content += `### REQ-${String(index + 1).padStart(2, '0')}: ${req.split(':')[0] || req}\r\n\r\n${req}\r\n\r\n`;\r\n });\r\n } else {\r\n content += `### REQ-01: [요구사항 제목]\r\n\r\n[요구사항 상세 설명]\r\n- 시스템은 [기능]을 지원해야 한다(SHALL)\r\n\r\n`;\r\n }\r\n\r\n content += `---\r\n\r\n## 시나리오\r\n\r\n`;\r\n\r\n if (options.scenarios?.length) {\r\n options.scenarios.forEach((scenario, index) => {\r\n content += `### Scenario ${index + 1}: ${scenario.name}\r\n\r\n- **GIVEN** ${scenario.given}\r\n- **WHEN** ${scenario.when}\r\n- **THEN** ${scenario.then}\r\n\r\n`;\r\n });\r\n } else {\r\n content += `### Scenario 1: [시나리오명]\r\n\r\n- **GIVEN** [전제 조건]\r\n- **WHEN** [행동/트리거]\r\n- **THEN** [예상 결과]\r\n\r\n`;\r\n }\r\n\r\n content += `---\r\n\r\n## 비기능 요구사항\r\n\r\n### 성능\r\n\r\n- 응답 시간: [N]ms 이내 (SHOULD)\r\n\r\n### 보안\r\n\r\n- [보안 요구사항] (SHALL)\r\n\r\n---\r\n\r\n## 제약사항\r\n\r\n- [기술적 제약사항]\r\n- [비즈니스 제약사항]\r\n\r\n---\r\n\r\n## 용어 정의\r\n\r\n| 용어 | 정의 |\r\n|------|------|\r\n| [용어1] | [정의1] |\r\n`;\r\n\r\n return content;\r\n}\r\n\r\n/**\r\n * 명세 메타데이터 파싱\r\n */\r\nexport function parseSpecMetadata(content: string): FeatureMetadata | null {\r\n const frontmatterMatch = content.match(/^---\\n([\\s\\S]*?)\\n---/);\r\n if (!frontmatterMatch) {\r\n return null;\r\n }\r\n\r\n const frontmatter = frontmatterMatch[1];\r\n const lines = frontmatter.split('\\n');\r\n const metadata: Record<string, unknown> = {};\r\n\r\n let currentKey = '';\r\n let isArray = false;\r\n const arrayItems: string[] = [];\r\n\r\n for (const line of lines) {\r\n if (line.startsWith(' - ')) {\r\n if (isArray) {\r\n arrayItems.push(line.replace(' - ', '').trim());\r\n }\r\n } else {\r\n if (isArray && currentKey) {\r\n metadata[currentKey] = arrayItems.length > 0 ? [...arrayItems] : null;\r\n arrayItems.length = 0;\r\n isArray = false;\r\n }\r\n\r\n const colonIndex = line.indexOf(':');\r\n if (colonIndex > 0) {\r\n const key = line.slice(0, colonIndex).trim();\r\n const value = line.slice(colonIndex + 1).trim();\r\n\r\n if (value === '' || value === '|') {\r\n currentKey = key;\r\n isArray = true;\r\n } else if (value === 'null') {\r\n metadata[key] = null;\r\n } else if (value.startsWith('\"') && value.endsWith('\"')) {\r\n metadata[key] = value.slice(1, -1);\r\n } else {\r\n metadata[key] = value;\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (isArray && currentKey) {\r\n metadata[currentKey] = arrayItems.length > 0 ? arrayItems : null;\r\n }\r\n\r\n return {\r\n id: metadata.id as string,\r\n title: metadata.title as string,\r\n status: metadata.status as FeatureStatus,\r\n created: metadata.created as string,\r\n updated: metadata.updated as string | undefined,\r\n branch: metadata.branch as string | undefined,\r\n depends: metadata.depends as string[] | null,\r\n };\r\n}\r\n\r\n/**\r\n * 명세 상태 업데이트\r\n */\r\nexport function updateSpecStatus(content: string, newStatus: FeatureStatus): string {\r\n const today = new Date().toISOString().split('T')[0];\r\n\r\n let updated = content.replace(\r\n /^(---\\n[\\s\\S]*?)status:\\s*\\w+/m,\r\n `$1status: ${newStatus}`\r\n );\r\n\r\n if (updated.includes('updated:')) {\r\n updated = updated.replace(\r\n /updated:\\s*[\\d-]+/,\r\n `updated: ${today}`\r\n );\r\n } else {\r\n updated = updated.replace(\r\n /(status:\\s*\\w+)/,\r\n `$1\\nupdated: ${today}`\r\n );\r\n }\r\n\r\n return updated;\r\n}\r\n","/**\r\n * 구현 계획 생성기\r\n */\r\nimport { Plan } from './schemas.js';\r\n\r\n/**\r\n * 계획 생성 옵션\r\n */\r\nexport interface GeneratePlanOptions {\r\n featureId: string;\r\n featureTitle: string;\r\n overview: string;\r\n techDecisions?: Array<{\r\n decision: string;\r\n rationale: string;\r\n alternatives?: string[];\r\n }>;\r\n phases?: Array<{\r\n name: string;\r\n description: string;\r\n deliverables: string[];\r\n }>;\r\n risks?: Array<{\r\n risk: string;\r\n mitigation: string;\r\n impact: 'high' | 'medium' | 'low';\r\n }>;\r\n testingStrategy?: string;\r\n constitutionCompliance?: string[];\r\n}\r\n\r\n/**\r\n * plan.md 파일 내용 생성\r\n */\r\nexport function generatePlan(options: GeneratePlanOptions): string {\r\n const today = new Date().toISOString().split('T')[0];\r\n\r\n let content = `---\r\nfeature: ${options.featureId}\r\ncreated: ${today}\r\nstatus: draft\r\n---\r\n\r\n# 구현 계획: ${options.featureTitle}\r\n\r\n> ${options.overview}\r\n\r\n---\r\n\r\n## 개요\r\n\r\n${options.overview}\r\n\r\n---\r\n\r\n## 기술 결정\r\n\r\n`;\r\n\r\n if (options.techDecisions?.length) {\r\n options.techDecisions.forEach((td, index) => {\r\n content += `### 결정 ${index + 1}: ${td.decision}\r\n\r\n**근거:** ${td.rationale}\r\n\r\n`;\r\n if (td.alternatives?.length) {\r\n content += `**대안 검토:**\r\n${td.alternatives.map(alt => `- ${alt}`).join('\\n')}\r\n\r\n`;\r\n }\r\n });\r\n } else {\r\n content += `### 결정 1: [기술 결정 사항]\r\n\r\n**근거:** [결정 근거]\r\n\r\n**대안 검토:**\r\n- [대안 1]\r\n- [대안 2]\r\n\r\n`;\r\n }\r\n\r\n content += `---\r\n\r\n## 구현 단계\r\n\r\n`;\r\n\r\n if (options.phases?.length) {\r\n options.phases.forEach((phase, index) => {\r\n content += `### Phase ${index + 1}: ${phase.name}\r\n\r\n${phase.description}\r\n\r\n**산출물:**\r\n${phase.deliverables.map(d => `- [ ] ${d}`).join('\\n')}\r\n\r\n`;\r\n });\r\n } else {\r\n content += `### Phase 1: 기반 구조\r\n\r\n[기반 구조 설명]\r\n\r\n**산출물:**\r\n- [ ] [산출물 1]\r\n- [ ] [산출물 2]\r\n\r\n### Phase 2: 핵심 기능\r\n\r\n[핵심 기능 설명]\r\n\r\n**산출물:**\r\n- [ ] [산출물 1]\r\n- [ ] [산출물 2]\r\n\r\n### Phase 3: 통합 및 테스트\r\n\r\n[통합 및 테스트 설명]\r\n\r\n**산출물:**\r\n- [ ] [산출물 1]\r\n- [ ] [산출물 2]\r\n\r\n`;\r\n }\r\n\r\n content += `---\r\n\r\n## 리스크 분석\r\n\r\n`;\r\n\r\n if (options.risks?.length) {\r\n content += `| 리스크 | 영향도 | 완화 전략 |\r\n|--------|--------|----------|\r\n`;\r\n options.risks.forEach(r => {\r\n const impactIcon = r.impact === 'high' ? '🔴' : r.impact === 'medium' ? '🟡' : '🟢';\r\n content += `| ${r.risk} | ${impactIcon} ${r.impact.toUpperCase()} | ${r.mitigation} |\r\n`;\r\n });\r\n content += '\\n';\r\n } else {\r\n content += `| 리스크 | 영향도 | 완화 전략 |\r\n|--------|--------|----------|\r\n| [리스크 1] | 🟡 MEDIUM | [완화 전략] |\r\n\r\n`;\r\n }\r\n\r\n content += `---\r\n\r\n## 테스트 전략\r\n\r\n`;\r\n\r\n if (options.testingStrategy) {\r\n content += `${options.testingStrategy}\r\n\r\n`;\r\n } else {\r\n content += `### 단위 테스트\r\n\r\n- 각 모듈별 단위 테스트 작성\r\n- 커버리지 목표: 80% 이상\r\n\r\n### 통합 테스트\r\n\r\n- API 엔드포인트 통합 테스트\r\n- 시나리오 기반 테스트\r\n\r\n### E2E 테스트\r\n\r\n- 주요 사용자 시나리오 검증\r\n\r\n`;\r\n }\r\n\r\n if (options.constitutionCompliance?.length) {\r\n content += `---\r\n\r\n## 헌법 준수 사항\r\n\r\n${options.constitutionCompliance.map(c => `- ${c}`).join('\\n')}\r\n`;\r\n }\r\n\r\n content += `\r\n---\r\n\r\n## 다음 단계\r\n\r\n1. [ ] 이 계획에 대한 검토 및 승인\r\n2. [ ] \\`/sdd:tasks\\` 명령으로 작업 분해\r\n3. [ ] 구현 시작\r\n`;\r\n\r\n return content;\r\n}\r\n\r\n/**\r\n * 계획 파싱\r\n */\r\nexport function parsePlan(content: string): Plan | null {\r\n // 기본 구조 추출\r\n const overviewMatch = content.match(/## 개요\\s*\\n\\n([\\s\\S]*?)(?=\\n---|\\n##)/);\r\n const overview = overviewMatch ? overviewMatch[1].trim() : '';\r\n\r\n // 기술 결정 추출\r\n const techDecisions: Plan['techDecisions'] = [];\r\n const techMatch = content.match(/## 기술 결정\\s*\\n([\\s\\S]*?)(?=\\n---)/);\r\n if (techMatch) {\r\n const decisions = techMatch[1].match(/### 결정 \\d+: ([^\\n]+)\\s*\\n\\n\\*\\*근거:\\*\\* ([^\\n]+)/g);\r\n if (decisions) {\r\n for (const d of decisions) {\r\n const match = d.match(/### 결정 \\d+: ([^\\n]+)\\s*\\n\\n\\*\\*근거:\\*\\* ([^\\n]+)/);\r\n if (match) {\r\n techDecisions.push({\r\n decision: match[1],\r\n rationale: match[2],\r\n });\r\n }\r\n }\r\n }\r\n }\r\n\r\n // 단계 추출\r\n const phases: Plan['phases'] = [];\r\n const phaseMatches = content.matchAll(/### Phase \\d+: ([^\\n]+)\\s*\\n+([^\\n*]+)\\s*\\n+\\*\\*산출물:\\*\\*\\s*\\n([\\s\\S]*?)(?=\\n###|\\n---|$)/g);\r\n for (const match of phaseMatches) {\r\n const deliverables = match[3]\r\n .split('\\n')\r\n .filter(l => l.startsWith('- '))\r\n .map(l => l.replace(/^- \\[[ x]\\] /, '').trim());\r\n\r\n phases.push({\r\n name: match[1],\r\n description: match[2].trim(),\r\n deliverables,\r\n });\r\n }\r\n\r\n if (!overview) {\r\n return null;\r\n }\r\n\r\n return {\r\n overview,\r\n techDecisions,\r\n phases,\r\n };\r\n}\r\n\r\n/**\r\n * 계획 상태 업데이트\r\n */\r\nexport function updatePlanStatus(content: string, newStatus: string): string {\r\n return content.replace(\r\n /^(---\\n[\\s\\S]*?)status:\\s*\\w+/m,\r\n `$1status: ${newStatus}`\r\n );\r\n}\r\n","/**\r\n * 작업 분해 생성기\r\n */\r\nimport { TaskItem, TaskStatus, TaskPriority, generateTaskId } from './schemas.js';\r\n\r\n/**\r\n * 작업 생성 옵션\r\n */\r\nexport interface GenerateTasksOptions {\r\n featureId: string;\r\n featureTitle: string;\r\n tasks: Array<{\r\n title: string;\r\n description?: string;\r\n priority?: TaskPriority;\r\n files?: string[];\r\n dependencies?: string[];\r\n }>;\r\n}\r\n\r\n/**\r\n * tasks.md 파일 내용 생성\r\n */\r\nexport function generateTasks(options: GenerateTasksOptions): string {\r\n const today = new Date().toISOString().split('T')[0];\r\n\r\n let content = `---\r\nfeature: ${options.featureId}\r\ncreated: ${today}\r\ntotal: ${options.tasks.length}\r\ncompleted: 0\r\n---\r\n\r\n# 작업 목록: ${options.featureTitle}\r\n\r\n> 총 ${options.tasks.length}개 작업\r\n\r\n---\r\n\r\n## 진행 상황\r\n\r\n- 대기: ${options.tasks.length}\r\n- 진행 중: 0\r\n- 완료: 0\r\n- 차단됨: 0\r\n\r\n---\r\n\r\n## 작업 목록\r\n\r\n`;\r\n\r\n options.tasks.forEach((task, index) => {\r\n const taskId = generateTaskId(options.featureId, index + 1);\r\n const priority = task.priority || 'medium';\r\n const priorityIcon = priority === 'high' ? '🔴' : priority === 'medium' ? '🟡' : '🟢';\r\n\r\n content += `### ${taskId}: ${task.title}\r\n\r\n- **상태:** 대기\r\n- **우선순위:** ${priorityIcon} ${priority.toUpperCase()}\r\n`;\r\n\r\n if (task.description) {\r\n content += `- **설명:** ${task.description}\r\n`;\r\n }\r\n\r\n if (task.files?.length) {\r\n content += `- **관련 파일:**\r\n${task.files.map(f => ` - \\`${f}\\``).join('\\n')}\r\n`;\r\n }\r\n\r\n if (task.dependencies?.length) {\r\n content += `- **의존성:** ${task.dependencies.join(', ')}\r\n`;\r\n }\r\n\r\n content += '\\n';\r\n });\r\n\r\n content += `---\r\n\r\n## 완료 조건\r\n\r\n각 작업 완료 시:\r\n1. [ ] 코드 작성 완료\r\n2. [ ] 테스트 작성 및 통과\r\n3. [ ] 코드 리뷰 완료\r\n4. [ ] 문서 업데이트\r\n\r\n---\r\n\r\n## 다음 단계\r\n\r\n1. 첫 번째 작업부터 순차적으로 진행\r\n2. 각 작업 완료 후 상태 업데이트\r\n3. 모든 작업 완료 시 \\`/sdd:archive\\` 실행\r\n`;\r\n\r\n return content;\r\n}\r\n\r\n/**\r\n * 작업 목록 파싱\r\n */\r\nexport function parseTasks(content: string): TaskItem[] {\r\n const tasks: TaskItem[] = [];\r\n const taskMatches = content.matchAll(/### ([a-z0-9-]+): ([^\\n]+)\\s*\\n([\\s\\S]*?)(?=\\n###|\\n---|$)/gi);\r\n\r\n for (const match of taskMatches) {\r\n const id = match[1];\r\n const title = match[2];\r\n const body = match[3];\r\n\r\n // 상태 추출\r\n const statusMatch = body.match(/\\*\\*상태:\\*\\*\\s*(\\S+)/);\r\n let status: TaskStatus = 'pending';\r\n if (statusMatch) {\r\n const statusText = statusMatch[1].toLowerCase();\r\n if (statusText.includes('진행') || statusText === 'in_progress') {\r\n status = 'in_progress';\r\n } else if (statusText.includes('완료') || statusText === 'completed') {\r\n status = 'completed';\r\n } else if (statusText.includes('차단') || statusText === 'blocked') {\r\n status = 'blocked';\r\n }\r\n }\r\n\r\n // 우선순위 추출\r\n const priorityMatch = body.match(/\\*\\*우선순위:\\*\\*\\s*(?:[🔴🟡🟢]\\s*)?([A-Za-z]+)/u);\r\n let priority: TaskPriority = 'medium';\r\n if (priorityMatch) {\r\n const p = priorityMatch[1].toLowerCase();\r\n if (p === 'high' || p === '높음') priority = 'high';\r\n else if (p === 'low' || p === '낮음') priority = 'low';\r\n }\r\n\r\n // 설명 추출\r\n const descMatch = body.match(/\\*\\*설명:\\*\\*\\s*([^\\n]+)/);\r\n const description = descMatch ? descMatch[1] : undefined;\r\n\r\n // 파일 추출\r\n const filesMatch = body.match(/\\*\\*관련 파일:\\*\\*\\s*\\n([\\s\\S]*?)(?=\\n-\\s*\\*\\*|\\n\\n|$)/);\r\n const files = filesMatch\r\n ? filesMatch[1]\r\n .split('\\n')\r\n .filter(l => l.includes('`'))\r\n .map(l => l.match(/`([^`]+)`/)?.[1] || '')\r\n .filter(Boolean)\r\n : undefined;\r\n\r\n // 의존성 추출\r\n const depsMatch = body.match(/\\*\\*의존성:\\*\\*\\s*([^\\n]+)/);\r\n const dependencies = depsMatch\r\n ? depsMatch[1].split(',').map(d => d.trim()).filter(Boolean)\r\n : undefined;\r\n\r\n tasks.push({\r\n id,\r\n title,\r\n description,\r\n status,\r\n priority,\r\n files,\r\n dependencies,\r\n });\r\n }\r\n\r\n return tasks;\r\n}\r\n\r\n/**\r\n * 작업 상태 업데이트\r\n */\r\nexport function updateTaskStatus(\r\n content: string,\r\n taskId: string,\r\n newStatus: TaskStatus\r\n): string {\r\n const statusText = newStatus === 'pending' ? '대기'\r\n : newStatus === 'in_progress' ? '진행 중'\r\n : newStatus === 'completed' ? '완료'\r\n : '차단됨';\r\n\r\n // 작업 상태 업데이트\r\n const taskRegex = new RegExp(\r\n `(### ${taskId}:[^\\\\n]+\\\\s*\\\\n[\\\\s\\\\S]*?\\\\*\\\\*상태:\\\\*\\\\*)\\\\s*\\\\S+`,\r\n 'i'\r\n );\r\n\r\n let updated = content.replace(taskRegex, `$1 ${statusText}`);\r\n\r\n // 진행 상황 업데이트\r\n const tasks = parseTasks(updated);\r\n const pending = tasks.filter(t => t.status === 'pending').length;\r\n const inProgress = tasks.filter(t => t.status === 'in_progress').length;\r\n const completed = tasks.filter(t => t.status === 'completed').length;\r\n const blocked = tasks.filter(t => t.status === 'blocked').length;\r\n\r\n updated = updated.replace(\r\n /## 진행 상황\\s*\\n\\n[\\s\\S]*?(?=\\n---)/,\r\n `## 진행 상황\r\n\r\n- 대기: ${pending}\r\n- 진행 중: ${inProgress}\r\n- 완료: ${completed}\r\n- 차단됨: ${blocked}\r\n`\r\n );\r\n\r\n // frontmatter completed 업데이트\r\n updated = updated.replace(\r\n /completed:\\s*\\d+/,\r\n `completed: ${completed}`\r\n );\r\n\r\n return updated;\r\n}\r\n\r\n/**\r\n * 다음 작업 가져오기\r\n */\r\nexport function getNextTask(tasks: TaskItem[]): TaskItem | null {\r\n // 진행 중인 작업이 있으면 반환\r\n const inProgress = tasks.find(t => t.status === 'in_progress');\r\n if (inProgress) return inProgress;\r\n\r\n // 의존성이 모두 완료된 대기 중 작업 찾기 (우선순위 순)\r\n const priorityOrder: TaskPriority[] = ['high', 'medium', 'low'];\r\n const completedIds = new Set(\r\n tasks.filter(t => t.status === 'completed').map(t => t.id)\r\n );\r\n\r\n for (const priority of priorityOrder) {\r\n const candidate = tasks.find(t => {\r\n if (t.status !== 'pending' || t.priority !== priority) return false;\r\n\r\n // 의존성 확인\r\n if (t.dependencies?.length) {\r\n return t.dependencies.every(dep => completedIds.has(dep));\r\n }\r\n return true;\r\n });\r\n\r\n if (candidate) return candidate;\r\n }\r\n\r\n return null;\r\n}\r\n","/**\r\n * 브랜치 관리\r\n */\r\nimport { exec } from 'node:child_process';\r\nimport { promisify } from 'node:util';\r\nimport { Result } from '../../types/index.js';\r\nimport { SddError, ErrorCode, ExitCode } from '../../errors/index.js';\r\nimport { generateBranchName } from './schemas.js';\r\n\r\nconst execAsync = promisify(exec);\r\n\r\n/**\r\n * 브랜치 에러\r\n */\r\nexport class BranchError extends SddError {\r\n constructor(message: string) {\r\n super(ErrorCode.UNKNOWN, message, ExitCode.GENERAL_ERROR);\r\n this.name = 'BranchError';\r\n }\r\n}\r\n\r\n/**\r\n * Git 설치 확인\r\n */\r\nexport async function isGitInstalled(): Promise<boolean> {\r\n try {\r\n await execAsync('git --version');\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Git 저장소인지 확인\r\n */\r\nexport async function isGitRepository(cwd?: string): Promise<boolean> {\r\n try {\r\n await execAsync('git rev-parse --git-dir', { cwd });\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * 현재 브랜치 가져오기\r\n */\r\nexport async function getCurrentBranch(cwd?: string): Promise<Result<string, BranchError>> {\r\n try {\r\n const { stdout } = await execAsync('git branch --show-current', { cwd });\r\n return { success: true, data: stdout.trim() };\r\n } catch (error) {\r\n return {\r\n success: false,\r\n error: new BranchError(`현재 브랜치를 가져올 수 없습니다: ${error}`),\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * 브랜치 존재 확인\r\n */\r\nexport async function branchExists(\r\n branchName: string,\r\n cwd?: string\r\n): Promise<boolean> {\r\n try {\r\n await execAsync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd });\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * 브랜치 생성\r\n */\r\nexport async function createBranch(\r\n featureId: string,\r\n options?: { checkout?: boolean; baseBranch?: string; cwd?: string }\r\n): Promise<Result<string, BranchError>> {\r\n const branchName = generateBranchName(featureId);\r\n const checkout = options?.checkout ?? true;\r\n const cwd = options?.cwd;\r\n\r\n try {\r\n // Git 저장소 확인\r\n if (!(await isGitRepository(cwd))) {\r\n return {\r\n success: false,\r\n error: new BranchError('Git 저장소가 아닙니다'),\r\n };\r\n }\r\n\r\n // 브랜치 존재 확인\r\n if (await branchExists(branchName, cwd)) {\r\n return {\r\n success: false,\r\n error: new BranchError(`브랜치 '${branchName}'가 이미 존재합니다`),\r\n };\r\n }\r\n\r\n // 베이스 브랜치가 지정된 경우 먼저 체크아웃\r\n if (options?.baseBranch) {\r\n await execAsync(`git checkout ${options.baseBranch}`, { cwd });\r\n }\r\n\r\n // 브랜치 생성\r\n if (checkout) {\r\n await execAsync(`git checkout -b ${branchName}`, { cwd });\r\n } else {\r\n await execAsync(`git branch ${branchName}`, { cwd });\r\n }\r\n\r\n return { success: true, data: branchName };\r\n } catch (error) {\r\n return {\r\n success: false,\r\n error: new BranchError(`브랜치 생성 실패: ${error}`),\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * 브랜치 체크아웃\r\n */\r\nexport async function checkoutBranch(\r\n branchName: string,\r\n cwd?: string\r\n): Promise<Result<void, BranchError>> {\r\n try {\r\n await execAsync(`git checkout ${branchName}`, { cwd });\r\n return { success: true, data: undefined };\r\n } catch (error) {\r\n return {\r\n success: false,\r\n error: new BranchError(`브랜치 체크아웃 실패: ${error}`),\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * 브랜치 삭제\r\n */\r\nexport async function deleteBranch(\r\n branchName: string,\r\n options?: { force?: boolean; cwd?: string }\r\n): Promise<Result<void, BranchError>> {\r\n const force = options?.force ?? false;\r\n const cwd = options?.cwd;\r\n\r\n try {\r\n const flag = force ? '-D' : '-d';\r\n await execAsync(`git branch ${flag} ${branchName}`, { cwd });\r\n return { success: true, data: undefined };\r\n } catch (error) {\r\n return {\r\n success: false,\r\n error: new BranchError(`브랜치 삭제 실패: ${error}`),\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * 기능 브랜치 목록\r\n */\r\nexport async function listFeatureBranches(\r\n cwd?: string\r\n): Promise<Result<string[], BranchError>> {\r\n try {\r\n const { stdout } = await execAsync('git branch --list \"feature/*\"', { cwd });\r\n const branches = stdout\r\n .split('\\n')\r\n .map(b => b.trim().replace(/^\\*\\s*/, ''))\r\n .filter(Boolean);\r\n return { success: true, data: branches };\r\n } catch (error) {\r\n return {\r\n success: false,\r\n error: new BranchError(`브랜치 목록 조회 실패: ${error}`),\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * 변경사항 있는지 확인\r\n */\r\nexport async function hasUncommittedChanges(cwd?: string): Promise<boolean> {\r\n try {\r\n const { stdout } = await execAsync('git status --porcelain', { cwd });\r\n return stdout.trim().length > 0;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * 브랜치 정보\r\n */\r\nexport interface BranchInfo {\r\n name: string;\r\n featureId: string;\r\n isCurrentBranch: boolean;\r\n}\r\n\r\n/**\r\n * 브랜치에서 기능 ID 추출\r\n */\r\nexport function extractFeatureId(branchName: string): string | null {\r\n const match = branchName.match(/^feature\\/(.+)$/);\r\n return match ? match[1] : null;\r\n}\r\n\r\n/**\r\n * 기능 브랜치 상세 정보\r\n */\r\nexport async function getFeatureBranchInfo(\r\n cwd?: string\r\n): Promise<Result<BranchInfo[], BranchError>> {\r\n const branchesResult = await listFeatureBranches(cwd);\r\n if (!branchesResult.success) {\r\n return branchesResult;\r\n }\r\n\r\n const currentResult = await getCurrentBranch(cwd);\r\n const currentBranch = currentResult.success ? currentResult.data : '';\r\n\r\n const info: BranchInfo[] = branchesResult.data.map(name => ({\r\n name,\r\n featureId: extractFeatureId(name) || name,\r\n isCurrentBranch: name === currentBranch,\r\n }));\r\n\r\n return { success: true, data: info };\r\n}\r\n","/**\r\n * 체크리스트 관리\r\n */\r\n\r\n/**\r\n * 체크리스트 항목\r\n */\r\nexport interface ChecklistItem {\r\n id: string;\r\n text: string;\r\n checked: boolean;\r\n category: ChecklistCategory;\r\n}\r\n\r\n/**\r\n * 체크리스트 카테고리\r\n */\r\nexport type ChecklistCategory =\r\n | 'pre-spec' // 명세 작성 전\r\n | 'post-spec' // 명세 작성 후\r\n | 'pre-plan' // 계획 작성 전\r\n | 'post-plan' // 계획 작성 후\r\n | 'pre-impl' // 구현 전\r\n | 'post-impl' // 구현 후\r\n | 'pre-review' // 리뷰 전\r\n | 'post-review'; // 리뷰 후\r\n\r\n/**\r\n * 기본 체크리스트 템플릿\r\n */\r\nexport const DEFAULT_CHECKLISTS: Record<ChecklistCategory, string[]> = {\r\n 'pre-spec': [\r\n '기능 요구사항이 명확히 정의됨',\r\n '사용자 스토리가 작성됨',\r\n '관련 이해관계자와 논의 완료',\r\n '기존 기능과의 충돌 여부 확인',\r\n ],\r\n 'post-spec': [\r\n 'RFC 2119 키워드 사용 확인 (SHALL, MUST, SHOULD, MAY)',\r\n 'GIVEN-WHEN-THEN 시나리오 포함',\r\n '비기능 요구사항 명시',\r\n 'sdd validate 통과',\r\n ],\r\n 'pre-plan': [\r\n '명세가 승인됨',\r\n '기술 스택 결정됨',\r\n '아키텍처 검토 완료',\r\n '의존성 확인',\r\n ],\r\n 'post-plan': [\r\n '구현 단계가 명확히 정의됨',\r\n '리스크 분석 완료',\r\n '테스트 전략 수립',\r\n '헌법 준수 사항 확인',\r\n ],\r\n 'pre-impl': [\r\n '작업이 분해됨 (tasks.md)',\r\n '브랜치가 생성됨',\r\n '개발 환경 준비',\r\n '관련 테스트 환경 확인',\r\n ],\r\n 'post-impl': [\r\n '모든 작업 완료',\r\n '단위 테스트 작성 및 통과',\r\n '통합 테스트 통과',\r\n '코드 커버리지 목표 달성 (80%+)',\r\n '린트 및 타입 체크 통과',\r\n ],\r\n 'pre-review': [\r\n '셀프 코드 리뷰 완료',\r\n '문서 업데이트',\r\n 'PR 설명 작성',\r\n '테스트 결과 첨부',\r\n ],\r\n 'post-review': [\r\n '리뷰 피드백 반영',\r\n '최종 테스트 통과',\r\n '스펙 상태 업데이트',\r\n '아카이브 준비',\r\n ],\r\n};\r\n\r\n/**\r\n * 체크리스트 생성\r\n */\r\nexport function createChecklist(category: ChecklistCategory): ChecklistItem[] {\r\n const items = DEFAULT_CHECKLISTS[category];\r\n return items.map((text, index) => ({\r\n id: `${category}-${String(index + 1).padStart(2, '0')}`,\r\n text,\r\n checked: false,\r\n category,\r\n }));\r\n}\r\n\r\n/**\r\n * 체크리스트를 마크다운으로 변환\r\n */\r\nexport function checklistToMarkdown(\r\n items: ChecklistItem[],\r\n title?: string\r\n): string {\r\n let content = '';\r\n\r\n if (title) {\r\n content += `## ${title}\\n\\n`;\r\n }\r\n\r\n items.forEach(item => {\r\n const checkbox = item.checked ? '[x]' : '[ ]';\r\n content += `- ${checkbox} ${item.text}\\n`;\r\n });\r\n\r\n return content;\r\n}\r\n\r\n/**\r\n * 마크다운에서 체크리스트 파싱\r\n */\r\nexport function parseChecklistFromMarkdown(\r\n content: string,\r\n category: ChecklistCategory\r\n): ChecklistItem[] {\r\n const items: ChecklistItem[] = [];\r\n const regex = /- \\[([ x])\\] (.+)/g;\r\n let match;\r\n let index = 0;\r\n\r\n while ((match = regex.exec(content)) !== null) {\r\n items.push({\r\n id: `${category}-${String(++index).padStart(2, '0')}`,\r\n text: match[2],\r\n checked: match[1] === 'x',\r\n category,\r\n });\r\n }\r\n\r\n return items;\r\n}\r\n\r\n/**\r\n * 체크리스트 완료 여부 확인\r\n */\r\nexport function isChecklistComplete(items: ChecklistItem[]): boolean {\r\n return items.every(item => item.checked);\r\n}\r\n\r\n/**\r\n * 체크리스트 진행률 계산\r\n */\r\nexport function getChecklistProgress(items: ChecklistItem[]): {\r\n completed: number;\r\n total: number;\r\n percentage: number;\r\n} {\r\n const completed = items.filter(item => item.checked).length;\r\n const total = items.length;\r\n const percentage = total > 0 ? Math.round((completed / total) * 100) : 0;\r\n\r\n return { completed, total, percentage };\r\n}\r\n\r\n/**\r\n * 체크리스트 항목 토글\r\n */\r\nexport function toggleChecklistItem(\r\n items: ChecklistItem[],\r\n itemId: string\r\n): ChecklistItem[] {\r\n return items.map(item =>\r\n item.id === itemId ? { ...item, checked: !item.checked } : item\r\n );\r\n}\r\n\r\n/**\r\n * 워크플로우 단계별 체크리스트 생성\r\n */\r\nexport function createWorkflowChecklists(): Record<string, ChecklistItem[]> {\r\n return {\r\n '명세 작성 전': createChecklist('pre-spec'),\r\n '명세 작성 후': createChecklist('post-spec'),\r\n '계획 작성 전': createChecklist('pre-plan'),\r\n '계획 작성 후': createChecklist('post-plan'),\r\n '구현 전': createChecklist('pre-impl'),\r\n '구현 후': createChecklist('post-impl'),\r\n '리뷰 전': createChecklist('pre-review'),\r\n '리뷰 후': createChecklist('post-review'),\r\n };\r\n}\r\n\r\n/**\r\n * 전체 체크리스트 마크다운 생성\r\n */\r\nexport function generateFullChecklistMarkdown(): string {\r\n const checklists = createWorkflowChecklists();\r\n let content = `# SDD 워크플로우 체크리스트\r\n\r\n> 각 단계별로 확인해야 할 항목들입니다.\r\n\r\n---\r\n\r\n`;\r\n\r\n for (const [title, items] of Object.entries(checklists)) {\r\n content += checklistToMarkdown(items, title);\r\n content += '\\n---\\n\\n';\r\n }\r\n\r\n return content;\r\n}\r\n","/**\r\n * 기능 번호 카운터 관리\r\n *\r\n * .sdd/counter.json 파일을 사용하여 feature 번호를 자동 관리합니다.\r\n * 형식: feature/001-name, feature/002-name, ...\r\n */\r\nimport path from 'node:path';\r\nimport { promises as fs } from 'node:fs';\r\nimport { fileExists, readFile, writeFile, ensureDir } from '../../utils/fs.js';\r\nimport { Result, success, failure } from '../../types/index.js';\r\n\r\n/**\r\n * 카운터 데이터 구조\r\n */\r\nexport interface CounterData {\r\n /** 다음 기능 번호 */\r\n nextFeatureNumber: number;\r\n /** 마지막 업데이트 시간 */\r\n lastUpdated: string;\r\n /** 생성된 기능 이력 */\r\n history: FeatureHistoryEntry[];\r\n}\r\n\r\n/**\r\n * 기능 이력 항목\r\n */\r\nexport interface FeatureHistoryEntry {\r\n /** 기능 번호 */\r\n number: number;\r\n /** 기능 이름 */\r\n name: string;\r\n /** 전체 ID (예: feature/001-auth) */\r\n fullId: string;\r\n /** 생성 시간 */\r\n createdAt: string;\r\n}\r\n\r\n/**\r\n * 카운터 에러\r\n */\r\nexport class CounterError extends Error {\r\n constructor(\r\n message: string,\r\n public readonly code: string\r\n ) {\r\n super(message);\r\n this.name = 'CounterError';\r\n }\r\n}\r\n\r\n/**\r\n * 기본 카운터 데이터\r\n */\r\nfunction getDefaultCounterData(): CounterData {\r\n return {\r\n nextFeatureNumber: 1,\r\n lastUpdated: new Date().toISOString(),\r\n history: [],\r\n };\r\n}\r\n\r\n/**\r\n * 카운터 파일 경로\r\n */\r\nfunction getCounterPath(sddPath: string): string {\r\n return path.join(sddPath, 'counter.json');\r\n}\r\n\r\n/**\r\n * 카운터 데이터 읽기\r\n */\r\nexport async function readCounter(sddPath: string): Promise<Result<CounterData, CounterError>> {\r\n const counterPath = getCounterPath(sddPath);\r\n\r\n if (!(await fileExists(counterPath))) {\r\n return success(getDefaultCounterData());\r\n }\r\n\r\n const readResult = await readFile(counterPath);\r\n if (!readResult.success) {\r\n return failure(new CounterError('카운터 파일을 읽을 수 없습니다', 'READ_ERROR'));\r\n }\r\n\r\n try {\r\n const data = JSON.parse(readResult.data) as CounterData;\r\n return success(data);\r\n } catch {\r\n return failure(new CounterError('카운터 파일 형식이 올바르지 않습니다', 'PARSE_ERROR'));\r\n }\r\n}\r\n\r\n/**\r\n * 카운터 데이터 저장\r\n */\r\nexport async function saveCounter(sddPath: string, data: CounterData): Promise<Result<void, CounterError>> {\r\n const counterPath = getCounterPath(sddPath);\r\n\r\n try {\r\n await writeFile(counterPath, JSON.stringify(data, null, 2));\r\n return success(undefined);\r\n } catch {\r\n return failure(new CounterError('카운터 파일을 저장할 수 없습니다', 'WRITE_ERROR'));\r\n }\r\n}\r\n\r\n/**\r\n * 다음 기능 번호 가져오기 및 증가\r\n */\r\nexport async function getNextFeatureNumber(\r\n sddPath: string,\r\n featureName: string\r\n): Promise<Result<{ number: number; fullId: string; branchName: string }, CounterError>> {\r\n const counterResult = await readCounter(sddPath);\r\n if (!counterResult.success) {\r\n return failure(counterResult.error);\r\n }\r\n\r\n const data = counterResult.data;\r\n const currentNumber = data.nextFeatureNumber;\r\n\r\n // 번호 포맷팅 (3자리, 앞에 0 채움)\r\n const paddedNumber = String(currentNumber).padStart(3, '0');\r\n\r\n // 기능 이름 정규화\r\n const normalizedName = featureName\r\n .toLowerCase()\r\n .replace(/[^a-z0-9]+/g, '-')\r\n .replace(/^-|-$/g, '');\r\n\r\n const fullId = `${paddedNumber}-${normalizedName}`;\r\n const branchName = `feature/${fullId}`;\r\n\r\n // 카운터 업데이트\r\n data.nextFeatureNumber = currentNumber + 1;\r\n data.lastUpdated = new Date().toISOString();\r\n data.history.push({\r\n number: currentNumber,\r\n name: featureName,\r\n fullId,\r\n createdAt: new Date().toISOString(),\r\n });\r\n\r\n const saveResult = await saveCounter(sddPath, data);\r\n if (!saveResult.success) {\r\n return failure(saveResult.error);\r\n }\r\n\r\n return success({\r\n number: currentNumber,\r\n fullId,\r\n branchName,\r\n });\r\n}\r\n\r\n/**\r\n * 현재 카운터 상태 조회 (증가하지 않음)\r\n */\r\nexport async function peekNextFeatureNumber(sddPath: string): Promise<Result<number, CounterError>> {\r\n const counterResult = await readCounter(sddPath);\r\n if (!counterResult.success) {\r\n return failure(counterResult.error);\r\n }\r\n\r\n return success(counterResult.data.nextFeatureNumber);\r\n}\r\n\r\n/**\r\n * 기능 이력 조회\r\n */\r\nexport async function getFeatureHistory(sddPath: string): Promise<Result<FeatureHistoryEntry[], CounterError>> {\r\n const counterResult = await readCounter(sddPath);\r\n if (!counterResult.success) {\r\n return failure(counterResult.error);\r\n }\r\n\r\n return success(counterResult.data.history);\r\n}\r\n\r\n/**\r\n * 카운터 초기화 (주의: 모든 이력 삭제)\r\n */\r\nexport async function resetCounter(sddPath: string, startFrom: number = 1): Promise<Result<void, CounterError>> {\r\n const data: CounterData = {\r\n nextFeatureNumber: startFrom,\r\n lastUpdated: new Date().toISOString(),\r\n history: [],\r\n };\r\n\r\n return saveCounter(sddPath, data);\r\n}\r\n\r\n/**\r\n * 카운터 설정 (이력 유지)\r\n */\r\nexport async function setNextFeatureNumber(\r\n sddPath: string,\r\n nextNumber: number\r\n): Promise<Result<void, CounterError>> {\r\n const counterResult = await readCounter(sddPath);\r\n if (!counterResult.success) {\r\n return failure(counterResult.error);\r\n }\r\n\r\n const data = counterResult.data;\r\n data.nextFeatureNumber = nextNumber;\r\n data.lastUpdated = new Date().toISOString();\r\n\r\n return saveCounter(sddPath, data);\r\n}\r\n\r\n/**\r\n * 브랜치 이름에서 기능 번호 추출\r\n */\r\nexport function extractFeatureNumberFromBranch(branchName: string): number | null {\r\n // feature/001-name 또는 001-name 형식\r\n const match = branchName.match(/(?:feature\\/)?(\\d{3})-/);\r\n if (match) {\r\n return parseInt(match[1], 10);\r\n }\r\n return null;\r\n}\r\n\r\n/**\r\n * 기능 ID 형식 검증\r\n */\r\nexport function isValidFeatureId(id: string): boolean {\r\n // 001-name 형식\r\n return /^\\d{3}-[a-z0-9]+(-[a-z0-9]+)*$/.test(id);\r\n}\r\n","/**\r\n * 신규 기능 워크플로우 모듈\r\n *\r\n * 새로운 기능 개발을 위한 명세, 계획, 작업 분해 기능을 제공합니다.\r\n */\r\n\r\n// 스키마 및 타입\r\nexport {\r\n FeatureStatusSchema,\r\n TaskStatusSchema,\r\n TaskPrioritySchema,\r\n FeatureMetadataSchema,\r\n TaskItemSchema,\r\n PlanSchema,\r\n generateFeatureId,\r\n generateTaskId,\r\n generateBranchName,\r\n type FeatureStatus,\r\n type TaskStatus,\r\n type TaskPriority,\r\n type FeatureMetadata,\r\n type TaskItem,\r\n type Plan,\r\n} from './schemas.js';\r\n\r\n// 명세 생성\r\nexport {\r\n generateSpec,\r\n parseSpecMetadata,\r\n updateSpecStatus,\r\n type GenerateSpecOptions,\r\n} from './spec-generator.js';\r\n\r\n// 계획 생성\r\nexport {\r\n generatePlan,\r\n parsePlan,\r\n updatePlanStatus,\r\n type GeneratePlanOptions,\r\n} from './plan-generator.js';\r\n\r\n// 작업 분해\r\nexport {\r\n generateTasks,\r\n parseTasks,\r\n updateTaskStatus,\r\n getNextTask,\r\n type GenerateTasksOptions,\r\n} from './task-generator.js';\r\n\r\n// 브랜치 관리\r\nexport {\r\n BranchError,\r\n isGitInstalled,\r\n isGitRepository,\r\n getCurrentBranch,\r\n branchExists,\r\n createBranch,\r\n checkoutBranch,\r\n deleteBranch,\r\n listFeatureBranches,\r\n hasUncommittedChanges,\r\n extractFeatureId,\r\n getFeatureBranchInfo,\r\n type BranchInfo,\r\n} from './branch.js';\r\n\r\n// 체크리스트\r\nexport {\r\n DEFAULT_CHECKLISTS,\r\n createChecklist,\r\n checklistToMarkdown,\r\n parseChecklistFromMarkdown,\r\n isChecklistComplete,\r\n getChecklistProgress,\r\n toggleChecklistItem,\r\n createWorkflowChecklists,\r\n generateFullChecklistMarkdown,\r\n type ChecklistItem,\r\n type ChecklistCategory,\r\n} from './checklist.js';\r\n\r\n// 기능 번호 카운터\r\nexport {\r\n readCounter,\r\n saveCounter,\r\n getNextFeatureNumber,\r\n peekNextFeatureNumber,\r\n getFeatureHistory,\r\n resetCounter,\r\n setNextFeatureNumber,\r\n extractFeatureNumberFromBranch,\r\n isValidFeatureId,\r\n CounterError,\r\n type CounterData,\r\n type FeatureHistoryEntry,\r\n} from './counter.js';\r\n","/**\r\n * CLI 진입점\r\n */\r\nimport { Command } from 'commander';\r\nimport { createRequire } from 'node:module';\r\nimport { registerInitCommand } from './commands/init.js';\r\nimport { registerValidateCommand } from './commands/validate.js';\r\nimport { registerPromptCommand } from './commands/prompt.js';\r\nimport { registerChangeCommand } from './commands/change.js';\r\nimport { registerImpactCommand } from './commands/impact.js';\r\nimport { registerNewCommand } from './commands/new.js';\r\nimport { registerStatusCommand } from './commands/status.js';\r\nimport { registerListCommand } from './commands/list.js';\r\nimport { registerConstitutionCommand } from './commands/constitution.js';\r\nimport { registerStartCommand } from './commands/start.js';\r\nimport { registerMigrateCommand } from './commands/migrate.js';\r\nimport { registerCicdCommand } from './commands/cicd.js';\r\nimport { registerTransitionCommand } from './commands/transition.js';\r\n\r\nconst require = createRequire(import.meta.url);\r\nconst pkg = require('../../package.json') as { version: string; description: string };\r\n\r\nconst program = new Command();\r\n\r\nprogram\r\n .name('sdd')\r\n .description(pkg.description)\r\n .version(pkg.version);\r\n\r\n// Commands\r\nregisterInitCommand(program);\r\nregisterValidateCommand(program);\r\nregisterPromptCommand(program);\r\nregisterChangeCommand(program);\r\nregisterImpactCommand(program);\r\nregisterNewCommand(program);\r\nregisterStatusCommand(program);\r\nregisterListCommand(program);\r\nregisterConstitutionCommand(program);\r\nregisterStartCommand(program);\r\nregisterMigrateCommand(program);\r\nregisterCicdCommand(program);\r\nregisterTransitionCommand(program);\r\n\r\n/**\r\n * CLI 실행\r\n */\r\nexport function run(): void {\r\n program.parse();\r\n}\r\n\r\nexport { program };\r\n","/**\r\n * sdd init 명령어\r\n */\r\nimport { Command } from 'commander';\r\nimport path from 'node:path';\r\nimport { ensureDir, writeFile, directoryExists } from '../../utils/fs.js';\r\nimport { ExitCode } from '../../errors/index.js';\r\nimport * as logger from '../../utils/logger.js';\r\nimport { generateAgentsMd } from '../../generators/agents-md.js';\r\nimport { generateClaudeCommands } from '../../generators/claude-commands.js';\r\n\r\n/**\r\n * init 명령어 등록\r\n */\r\nexport function registerInitCommand(program: Command): void {\r\n program\r\n .command('init')\r\n .description('SDD 프로젝트를 초기화합니다')\r\n .option('-f, --force', '기존 .sdd/ 디렉토리 덮어쓰기')\r\n .action(async (options: { force?: boolean }) => {\r\n try {\r\n await runInit(options);\r\n } catch (error) {\r\n logger.error(error instanceof Error ? error.message : String(error));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n });\r\n}\r\n\r\n/**\r\n * 초기화 실행\r\n */\r\nasync function runInit(options: { force?: boolean }): Promise<void> {\r\n const cwd = process.cwd();\r\n const sddPath = path.join(cwd, '.sdd');\r\n\r\n // 기존 디렉토리 확인\r\n if (await directoryExists(sddPath)) {\r\n if (!options.force) {\r\n logger.error('.sdd/ 디렉토리가 이미 존재합니다. --force 옵션으로 덮어쓸 수 있습니다.');\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n logger.warn('기존 .sdd/ 디렉토리를 덮어씁니다.');\r\n }\r\n\r\n logger.info('SDD 프로젝트를 초기화합니다...');\r\n\r\n // 디렉토리 구조 생성\r\n const directories = [\r\n '.sdd',\r\n '.sdd/specs',\r\n '.sdd/changes',\r\n '.sdd/archive',\r\n '.sdd/templates',\r\n '.claude',\r\n '.claude/commands',\r\n ];\r\n\r\n for (const dir of directories) {\r\n const result = await ensureDir(path.join(cwd, dir));\r\n if (!result.success) {\r\n logger.error(`디렉토리 생성 실패: ${dir}`);\r\n process.exit(ExitCode.FILE_SYSTEM_ERROR);\r\n }\r\n }\r\n\r\n // 기본 파일 생성\r\n await createDefaultFiles(cwd);\r\n\r\n // 템플릿 복사\r\n await copyTemplates(cwd);\r\n\r\n // Claude 슬래시 커맨드 생성\r\n await createClaudeCommands(cwd);\r\n\r\n logger.success('SDD 프로젝트가 초기화되었습니다.');\r\n logger.newline();\r\n logger.info('생성된 구조:');\r\n logger.listItem('.sdd/');\r\n logger.listItem('AGENTS.md', 1);\r\n logger.listItem('constitution.md', 1);\r\n logger.listItem('specs/', 1);\r\n logger.listItem('changes/', 1);\r\n logger.listItem('archive/', 1);\r\n logger.listItem('templates/', 1);\r\n logger.listItem('.claude/');\r\n logger.listItem('commands/', 1);\r\n logger.newline();\r\n logger.info('Claude 슬래시 커맨드:');\r\n logger.listItem('/sdd.start - 워크플로우 시작 (통합 진입점)');\r\n logger.listItem('/sdd.constitution - 프로젝트 원칙 관리');\r\n logger.listItem('/sdd.new - 새 기능 명세 작성');\r\n logger.listItem('/sdd.plan - 구현 계획 작성');\r\n logger.listItem('/sdd.tasks - 작업 분해');\r\n logger.listItem('/sdd.implement - 구현 진행');\r\n logger.listItem('/sdd.validate - 스펙 검증');\r\n logger.listItem('/sdd.status - 상태 확인');\r\n logger.listItem('/sdd.change - 변경 제안');\r\n logger.newline();\r\n logger.info('다음 단계:');\r\n logger.listItem('constitution.md를 수정하여 프로젝트 원칙을 정의하세요');\r\n logger.listItem('/sdd.new 로 첫 번째 기능 명세를 작성하세요');\r\n}\r\n\r\n/**\r\n * 기본 파일 생성\r\n */\r\nasync function createDefaultFiles(cwd: string): Promise<void> {\r\n const projectName = path.basename(cwd);\r\n const today = new Date().toISOString().split('T')[0];\r\n\r\n // constitution.md\r\n const constitution = `---\r\nversion: 1.0.0\r\ncreated: ${today}\r\n---\r\n\r\n# Constitution: ${projectName}\r\n\r\n> 이 프로젝트의 모든 설계와 구현은 아래 원칙을 준수해야 한다(SHALL).\r\n\r\n## 핵심 원칙\r\n\r\n### 1. 품질 우선\r\n\r\n- 모든 기능은 테스트와 함께 구현해야 한다(SHALL)\r\n- 코드 리뷰 없이 머지해서는 안 된다(SHALL NOT)\r\n\r\n### 2. 명세 우선\r\n\r\n- 모든 기능은 스펙 문서가 먼저 작성되어야 한다(SHALL)\r\n- 스펙은 RFC 2119 키워드를 사용해야 한다(SHALL)\r\n- 모든 요구사항은 GIVEN-WHEN-THEN 시나리오를 포함해야 한다(SHALL)\r\n\r\n## 금지 사항\r\n\r\n- 스펙 없이 기능을 구현해서는 안 된다(SHALL NOT)\r\n- 테스트 없이 배포해서는 안 된다(SHALL NOT)\r\n\r\n## 기술 스택\r\n\r\n- (프로젝트에 맞게 수정하세요)\r\n\r\n## 품질 기준\r\n\r\n- 테스트 커버리지: 80% 이상(SHOULD)\r\n`;\r\n\r\n await writeFile(path.join(cwd, '.sdd', 'constitution.md'), constitution);\r\n\r\n // AGENTS.md - 50줄 규칙 준수를 위해 생성기 사용\r\n const agents = generateAgentsMd({ projectName });\r\n await writeFile(path.join(cwd, '.sdd', 'AGENTS.md'), agents);\r\n}\r\n\r\n/**\r\n * 템플릿 복사\r\n */\r\nasync function copyTemplates(cwd: string): Promise<void> {\r\n const today = new Date().toISOString().split('T')[0];\r\n\r\n // spec.md 템플릿\r\n const specTemplate = `---\r\nstatus: draft\r\ncreated: ${today}\r\ndepends: null\r\n---\r\n\r\n# {{FEATURE_NAME}}\r\n\r\n> 기능 설명\r\n\r\n---\r\n\r\n## Requirement: {{REQUIREMENT_TITLE}}\r\n\r\n시스템은 {{DESCRIPTION}}해야 한다(SHALL).\r\n\r\n### Scenario: {{SCENARIO_NAME}}\r\n\r\n- **GIVEN** {{GIVEN_CONDITION}}\r\n- **WHEN** {{WHEN_ACTION}}\r\n- **THEN** {{THEN_RESULT}}\r\n\r\n---\r\n\r\n## 비고\r\n\r\n추가 설명이나 제약 조건\r\n`;\r\n\r\n // proposal.md 템플릿\r\n const proposalTemplate = `---\r\nid: CHG-{{ID}}\r\nstatus: draft\r\ncreated: ${today}\r\n---\r\n\r\n# 변경 제안: {{TITLE}}\r\n\r\n> 변경 목적 및 배경 설명\r\n\r\n---\r\n\r\n## 배경\r\n\r\n왜 이 변경이 필요한가?\r\n\r\n---\r\n\r\n## 영향 범위\r\n\r\n### 영향받는 스펙\r\n\r\n- \\`specs/{{SPEC_PATH}}\\`\r\n\r\n### 변경 유형\r\n\r\n- [ ] 신규 추가 (ADDED)\r\n- [ ] 수정 (MODIFIED)\r\n- [ ] 삭제 (REMOVED)\r\n\r\n---\r\n\r\n## 변경 내용\r\n\r\n### ADDED\r\n\r\n(새로 추가되는 내용)\r\n\r\n### MODIFIED\r\n\r\n#### Before\r\n\r\n\\`\\`\\`markdown\r\n기존 내용\r\n\\`\\`\\`\r\n\r\n#### After\r\n\r\n\\`\\`\\`markdown\r\n변경된 내용\r\n\\`\\`\\`\r\n\r\n### REMOVED\r\n\r\n(삭제되는 내용)\r\n\r\n---\r\n\r\n## 리스크 평가\r\n\r\n- 영향도: 낮음/중간/높음\r\n- 복잡도: 낮음/중간/높음\r\n`;\r\n\r\n // delta.md 템플릿\r\n const deltaTemplate = `---\r\nproposal: CHG-{{ID}}\r\ncreated: ${today}\r\n---\r\n\r\n# Delta: {{TITLE}}\r\n\r\n## ADDED\r\n\r\n(추가되는 스펙 내용)\r\n\r\n## MODIFIED\r\n\r\n### {{SPEC_PATH}}\r\n\r\n#### Before\r\n\r\n\\`\\`\\`markdown\r\n기존 내용\r\n\\`\\`\\`\r\n\r\n#### After\r\n\r\n\\`\\`\\`markdown\r\n변경된 내용\r\n\\`\\`\\`\r\n\r\n## REMOVED\r\n\r\n(삭제되는 스펙 참조)\r\n`;\r\n\r\n // tasks.md 템플릿\r\n const tasksTemplate = `---\r\nspec: {{SPEC_ID}}\r\ncreated: ${today}\r\n---\r\n\r\n# Tasks: {{FEATURE_NAME}}\r\n\r\n## 개요\r\n\r\n- 총 작업 수: N개\r\n- 예상 복잡도: 낮음/중간/높음\r\n\r\n---\r\n\r\n## 작업 목록\r\n\r\n### Phase 1: 기반 구축\r\n\r\n- [ ] [P1] 작업 1 설명\r\n- [ ] [P1] 작업 2 설명\r\n\r\n### Phase 2: 핵심 구현\r\n\r\n- [ ] [P2] 작업 3 설명\r\n- [ ] [P2] 작업 4 설명\r\n\r\n### Phase 3: 마무리\r\n\r\n- [ ] [P3] 테스트 작성\r\n- [ ] [P3] 문서화\r\n\r\n---\r\n\r\n## 의존성 그래프\r\n\r\n\\`\\`\\`mermaid\r\ngraph LR\r\n A[작업 1] --> B[작업 2]\r\n B --> C[작업 3]\r\n\\`\\`\\`\r\n\r\n---\r\n\r\n## 마커 범례\r\n\r\n| 마커 | 의미 |\r\n|------|------|\r\n| [P1-3] | 우선순위 |\r\n| [→T] | 테스트 필요 |\r\n| [US] | 불확실/검토 필요 |\r\n`;\r\n\r\n await writeFile(path.join(cwd, '.sdd', 'templates', 'spec.md'), specTemplate);\r\n await writeFile(path.join(cwd, '.sdd', 'templates', 'proposal.md'), proposalTemplate);\r\n await writeFile(path.join(cwd, '.sdd', 'templates', 'delta.md'), deltaTemplate);\r\n await writeFile(path.join(cwd, '.sdd', 'templates', 'tasks.md'), tasksTemplate);\r\n}\r\n\r\n/**\r\n * Claude 슬래시 커맨드 생성\r\n */\r\nasync function createClaudeCommands(cwd: string): Promise<void> {\r\n const commands = generateClaudeCommands();\r\n\r\n for (const cmd of commands) {\r\n await writeFile(\r\n path.join(cwd, '.claude', 'commands', `${cmd.name}.md`),\r\n cmd.content\r\n );\r\n }\r\n}\r\n","/**\r\n * 로깅 유틸리티\r\n */\r\nimport chalk from 'chalk';\r\n\r\nexport type LogLevel = 'debug' | 'info' | 'warn' | 'error';\r\n\r\nconst LOG_LEVELS: Record<LogLevel, number> = {\r\n debug: 0,\r\n info: 1,\r\n warn: 2,\r\n error: 3,\r\n};\r\n\r\nlet currentLevel: LogLevel = 'info';\r\n\r\n/**\r\n * 로그 레벨 설정\r\n */\r\nexport function setLogLevel(level: LogLevel): void {\r\n currentLevel = level;\r\n}\r\n\r\n/**\r\n * 로그 레벨 확인\r\n */\r\nfunction shouldLog(level: LogLevel): boolean {\r\n return LOG_LEVELS[level] >= LOG_LEVELS[currentLevel];\r\n}\r\n\r\n/**\r\n * 디버그 로그\r\n */\r\nexport function debug(message: string, ...args: unknown[]): void {\r\n if (shouldLog('debug')) {\r\n console.log(chalk.gray(`[DEBUG] ${message}`), ...args);\r\n }\r\n}\r\n\r\n/**\r\n * 정보 로그\r\n */\r\nexport function info(message: string, ...args: unknown[]): void {\r\n if (shouldLog('info')) {\r\n console.log(chalk.blue(`ℹ ${message}`), ...args);\r\n }\r\n}\r\n\r\n/**\r\n * 성공 로그\r\n */\r\nexport function success(message: string, ...args: unknown[]): void {\r\n if (shouldLog('info')) {\r\n console.log(chalk.green(`✓ ${message}`), ...args);\r\n }\r\n}\r\n\r\n/**\r\n * 경고 로그\r\n */\r\nexport function warn(message: string, ...args: unknown[]): void {\r\n if (shouldLog('warn')) {\r\n console.log(chalk.yellow(`⚠ ${message}`), ...args);\r\n }\r\n}\r\n\r\n/**\r\n * 에러 로그\r\n */\r\nexport function error(message: string, ...args: unknown[]): void {\r\n if (shouldLog('error')) {\r\n console.error(chalk.red(`✗ ${message}`), ...args);\r\n }\r\n}\r\n\r\n/**\r\n * 제목 출력\r\n */\r\nexport function title(message: string): void {\r\n console.log();\r\n console.log(chalk.bold.cyan(message));\r\n console.log(chalk.cyan('─'.repeat(message.length)));\r\n}\r\n\r\n/**\r\n * 목록 항목 출력\r\n */\r\nexport function listItem(item: string, indent = 0): void {\r\n const prefix = ' '.repeat(indent) + '• ';\r\n console.log(prefix + item);\r\n}\r\n\r\n/**\r\n * 빈 줄 출력\r\n */\r\nexport function newline(): void {\r\n console.log();\r\n}\r\n","/**\r\n * AGENTS.md 생성기\r\n *\r\n * 상단 50줄 내에 모든 필수 형식 규칙을 배치합니다.\r\n */\r\nimport { ParsedConstitution } from '../core/constitution/schemas.js';\r\n\r\nexport interface AgentsGeneratorOptions {\r\n projectName: string;\r\n projectDescription?: string;\r\n constitution?: ParsedConstitution;\r\n}\r\n\r\n/**\r\n * AGENTS.md 생성\r\n *\r\n * 스펙 06-agents-generation 요구사항:\r\n * - 상단 50줄 내에 모든 필수 형식 규칙 포함\r\n * - RFC 2119 키워드 설명\r\n * - GIVEN-WHEN-THEN 형식 설명\r\n * - 워크플로우 지침\r\n */\r\nexport function generateAgentsMd(options: AgentsGeneratorOptions): string {\r\n const { projectName, projectDescription = '(프로젝트 설명을 추가하세요)' } = options;\r\n\r\n // 상단 50줄 내에 필수 규칙을 배치\r\n return `# SDD Workflow Guide\r\n\r\n> **${projectName}** - AI 에이전트 워크플로우 지침서\r\n\r\n---\r\n\r\n## 필수 형식 규칙 (이 섹션은 상단 50줄 내에 있어야 함)\r\n\r\n### RFC 2119 키워드\r\n\r\n| 키워드 | 의미 | 사용 예시 |\r\n|--------|------|-----------|\r\n| **SHALL** / **MUST** | 절대 필수 | \"시스템은 인증을 지원해야 한다(SHALL)\" |\r\n| **SHOULD** | 권장 (예외 가능) | \"응답 시간은 1초 이내여야 한다(SHOULD)\" |\r\n| **MAY** | 선택적 | \"다크 모드를 지원할 수 있다(MAY)\" |\r\n| **SHALL NOT** | 절대 금지 | \"평문 비밀번호를 저장해서는 안 된다(SHALL NOT)\" |\r\n\r\n### GIVEN-WHEN-THEN 형식\r\n\r\n모든 요구사항은 아래 형식의 시나리오를 포함해야 합니다:\r\n\r\n\\`\\`\\`markdown\r\n### Scenario: [시나리오명]\r\n\r\n- **GIVEN** [전제 조건]\r\n- **WHEN** [행동/트리거]\r\n- **THEN** [예상 결과]\r\n\\`\\`\\`\r\n\r\n---\r\n\r\n## 프로젝트 개요\r\n\r\n**프로젝트**: ${projectName}\r\n**설명**: ${projectDescription}\r\n\r\n---\r\n\r\n## 디렉토리 구조\r\n\r\n\\`\\`\\`\r\n.sdd/\r\n├── constitution.md # 프로젝트 헌법 (원칙, 제약)\r\n├── AGENTS.md # 이 파일 (AI 워크플로우 지침)\r\n├── specs/ # 스펙 문서\r\n│ └── <feature>/\r\n│ └── spec.md\r\n├── changes/ # 변경 제안\r\n│ └── <id>/\r\n│ ├── proposal.md\r\n│ ├── delta.md\r\n│ └── tasks.md\r\n├── archive/ # 완료된 변경\r\n└── templates/ # 템플릿 파일\r\n\\`\\`\\`\r\n\r\n---\r\n\r\n## 워크플로우\r\n\r\n### 신규 기능 워크플로우\r\n\r\n1. \\`/sdd:new <feature>\\` - 스펙 초안 작성\r\n2. \\`/sdd:plan\\` - 구현 계획 수립\r\n3. \\`/sdd:tasks\\` - 작업 분해 (마커: [P1-3], [→T], [US])\r\n4. 순차적 구현 및 테스트\r\n5. 리뷰 및 머지\r\n\r\n### 변경 워크플로우\r\n\r\n1. \\`/sdd:change <id>\\` - 제안서(proposal.md) 작성\r\n2. delta.md 작성 (ADDED/MODIFIED/REMOVED)\r\n3. tasks.md 작업 목록 생성\r\n4. 구현\r\n5. \\`/sdd:apply\\` - 델타를 스펙에 병합\r\n6. \\`/sdd:archive\\` - 완료된 변경 아카이브\r\n\r\n---\r\n\r\n## 검증\r\n\r\n스펙 변경 후 항상 검증을 실행하세요:\r\n\r\n\\`\\`\\`bash\r\nsdd validate [path] # 형식 검증\r\nsdd validate --strict # 경고도 에러로 처리\r\n\\`\\`\\`\r\n\r\n---\r\n\r\n## 슬래시 커맨드 요약\r\n\r\n| 명령어 | 설명 |\r\n|--------|------|\r\n| \\`/sdd:init\\` | 프로젝트 초기화 |\r\n| \\`/sdd:constitution\\` | Constitution 생성/수정 |\r\n| \\`/sdd:new\\` | 신규 스펙 생성 |\r\n| \\`/sdd:plan\\` | 구현 계획 수립 |\r\n| \\`/sdd:tasks\\` | 작업 분해 |\r\n| \\`/sdd:change\\` | 변경 제안 |\r\n| \\`/sdd:impact\\` | 영향도 분석 |\r\n| \\`/sdd:apply\\` | 델타 적용 |\r\n| \\`/sdd:archive\\` | 아카이브 |\r\n| \\`/sdd:validate\\` | 형식 검증 |\r\n| \\`/sdd:status\\` | 현황 조회 |\r\n\r\n---\r\n\r\n## 작업 마커\r\n\r\n| 마커 | 의미 |\r\n|------|------|\r\n| [P] | 우선순위 없음 |\r\n| [P1-3] | 우선순위 (1=높음) |\r\n| [→T] | 테스트 필요 |\r\n| [US] | 불확실/검토 필요 |\r\n\r\n---\r\n\r\n## 참조\r\n\r\n- [Constitution](./constitution.md)\r\n- [Specs](./specs/)\r\n- [Changes](./changes/)\r\n`;\r\n}\r\n\r\n/**\r\n * 상단 50줄 내에 필수 규칙이 포함되어 있는지 검증\r\n */\r\nexport function validateAgentsMdFormat(content: string): {\r\n valid: boolean;\r\n errors: string[];\r\n} {\r\n const errors: string[] = [];\r\n const lines = content.split('\\n').slice(0, 50).join('\\n');\r\n\r\n // RFC 2119 키워드 포함 확인\r\n if (!lines.includes('SHALL') || !lines.includes('MUST')) {\r\n errors.push('상단 50줄 내에 RFC 2119 키워드(SHALL, MUST)가 포함되어야 합니다');\r\n }\r\n\r\n // GIVEN-WHEN-THEN 형식 포함 확인\r\n if (!lines.includes('GIVEN') || !lines.includes('WHEN') || !lines.includes('THEN')) {\r\n errors.push('상단 50줄 내에 GIVEN-WHEN-THEN 형식이 포함되어야 합니다');\r\n }\r\n\r\n return {\r\n valid: errors.length === 0,\r\n errors,\r\n };\r\n}\r\n","/**\r\n * Claude Code 슬래시 커맨드 생성기\r\n */\r\n\r\nexport interface ClaudeCommand {\r\n name: string;\r\n content: string;\r\n}\r\n\r\n/**\r\n * SDD 워크플로우용 Claude 슬래시 커맨드 생성\r\n */\r\nexport function generateClaudeCommands(): ClaudeCommand[] {\r\n return [\r\n {\r\n name: 'sdd.start',\r\n content: `SDD 워크플로우를 시작합니다 (통합 진입점).\r\n\r\n## 개요\r\n\r\n이 커맨드는 SDD 프로젝트의 통합 진입점입니다.\r\n현재 상태를 확인하고 적절한 워크플로우를 안내합니다.\r\n\r\n## 지시사항\r\n\r\n1. \\`sdd start\\` 명령어를 실행하여 프로젝트 상태를 확인하세요\r\n2. 제시되는 워크플로우 메뉴에서 적절한 작업을 선택하세요\r\n3. 각 워크플로우의 안내에 따라 진행하세요\r\n\r\n## 사용 가능한 워크플로우\r\n\r\n- **new-feature**: 새 기능 명세 작성\r\n- **change-spec**: 기존 스펙 변경\r\n- **validate**: 명세 검증\r\n- **status**: 상태 확인\r\n- **constitution**: Constitution 관리\r\n\r\n## 명령어\r\n\r\n\\`\\`\\`bash\r\n# 프로젝트 상태 및 워크플로우 메뉴\r\nsdd start\r\n\r\n# 상태만 확인\r\nsdd start --status\r\n\r\n# 특정 워크플로우 바로 시작\r\nsdd start --workflow new-feature\r\nsdd start --workflow change-spec\r\nsdd start --workflow validate\r\n\\`\\`\\`\r\n\r\n## 프로젝트 미초기화 시\r\n\r\n프로젝트가 초기화되지 않은 경우:\r\n1. \\`sdd init\\`으로 프로젝트를 초기화하세요\r\n2. \\`/sdd.constitution\\`으로 프로젝트 원칙을 정의하세요\r\n3. \\`/sdd.new\\`로 첫 기능 명세를 작성하세요\r\n`,\r\n },\r\n {\r\n name: 'sdd.new',\r\n content: `새로운 기능 명세를 작성합니다.\r\n\r\n## 지시사항\r\n\r\n1. 사용자에게 기능명과 간단한 설명을 요청하세요\r\n2. \\`sdd new <feature-id> --all\\` 명령어를 실행하여 기본 구조를 생성하세요\r\n3. 생성된 \\`.sdd/specs/<feature-id>/spec.md\\` 파일을 열어 내용을 작성하세요\r\n\r\n## 명세 작성 규칙\r\n\r\n- RFC 2119 키워드 사용: SHALL, MUST, SHOULD, MAY, SHALL NOT\r\n- GIVEN-WHEN-THEN 형식의 시나리오 포함 필수\r\n- 각 요구사항에 고유 ID 부여 (REQ-001, REQ-002, ...)\r\n\r\n## 예시\r\n\r\n\\`\\`\\`markdown\r\n### REQ-01: 사용자 인증\r\n\r\n시스템은 이메일과 비밀번호로 사용자를 인증해야 한다(SHALL).\r\n\r\n### Scenario: 올바른 자격 증명으로 로그인\r\n\r\n- **GIVEN** 등록된 사용자가 존재할 때\r\n- **WHEN** 올바른 이메일과 비밀번호로 로그인을 시도하면\r\n- **THEN** 액세스 토큰이 발급되어야 한다\r\n\\`\\`\\`\r\n\r\n완료 후 \\`sdd validate\\`로 명세를 검증하세요.\r\n`,\r\n },\r\n {\r\n name: 'sdd.plan',\r\n content: `기능 명세에 대한 구현 계획을 작성합니다.\r\n\r\n## 지시사항\r\n\r\n1. \\`.sdd/specs/\\` 디렉토리에서 계획을 작성할 기능을 확인하세요\r\n2. 해당 기능의 \\`spec.md\\`를 읽고 요구사항을 분석하세요\r\n3. \\`sdd new plan <feature-id>\\` 명령어로 계획 템플릿을 생성하거나 기존 \\`plan.md\\`를 수정하세요\r\n\r\n## 계획 작성 규칙\r\n\r\n- 기술 결정사항과 그 근거를 명시\r\n- 구현 단계(Phase)를 나누어 정의\r\n- 각 단계별 산출물 목록 작성\r\n- 리스크 분석 및 완화 전략 포함\r\n- 테스트 전략 수립\r\n\r\n## 계획 구조\r\n\r\n\\`\\`\\`markdown\r\n## 기술 결정\r\n### 결정 1: [제목]\r\n**근거:** [왜 이 기술/방식을 선택했는지]\r\n\r\n## 구현 단계\r\n### Phase 1: 기반 구조\r\n[설명]\r\n**산출물:**\r\n- [ ] 산출물 1\r\n- [ ] 산출물 2\r\n\r\n## 리스크 분석\r\n| 리스크 | 영향도 | 완화 전략 |\r\n\\`\\`\\`\r\n\r\n완료 후 \\`/sdd.tasks\\`로 작업을 분해하세요.\r\n`,\r\n },\r\n {\r\n name: 'sdd.tasks',\r\n content: `구현 계획을 실행 가능한 작업으로 분해합니다.\r\n\r\n## 지시사항\r\n\r\n1. 해당 기능의 \\`plan.md\\`를 읽고 구현 단계를 확인하세요\r\n2. \\`sdd new tasks <feature-id>\\` 명령어로 작업 목록을 생성하세요\r\n3. 각 작업에 우선순위와 상태를 지정하세요\r\n\r\n## 작업 분해 규칙\r\n\r\n- 각 작업은 2-4시간 내 완료 가능한 크기로 분해\r\n- 작업 간 의존성을 명확히 표시\r\n- 우선순위: HIGH(🔴), MEDIUM(🟡), LOW(🟢)\r\n- 상태: 대기, 진행 중, 완료, 차단됨\r\n\r\n## 작업 구조\r\n\r\n\\`\\`\\`markdown\r\n### <feature>-task-001: [작업 제목]\r\n\r\n- **상태:** 대기\r\n- **우선순위:** 🔴 HIGH\r\n- **의존성:** 없음\r\n\r\n#### 설명\r\n[작업 상세 설명]\r\n\r\n#### 완료 조건\r\n- [ ] 조건 1\r\n- [ ] 조건 2\r\n\\`\\`\\`\r\n\r\n완료 후 \\`/sdd.implement\\`로 구현을 시작하세요.\r\n`,\r\n },\r\n {\r\n name: 'sdd.implement',\r\n content: `작업 목록을 기반으로 순차적으로 구현합니다.\r\n\r\n## 지시사항\r\n\r\n1. \\`sdd status\\`로 현재 진행 상황을 확인하세요\r\n2. 해당 기능의 \\`tasks.md\\`를 읽고 다음 작업을 확인하세요\r\n3. 작업을 구현하고 완료 시 상태를 업데이트하세요\r\n\r\n## 구현 규칙\r\n\r\n- 한 번에 하나의 작업만 진행\r\n- 각 작업 완료 후 테스트 작성 필수\r\n- 커밋 메시지에 작업 ID 포함\r\n- \\`.sdd/constitution.md\\`의 원칙 준수\r\n\r\n## 작업 흐름\r\n\r\n1. 작업 상태를 \"진행 중\"으로 변경\r\n2. 코드 구현\r\n3. 테스트 작성 및 실행\r\n4. 작업 상태를 \"완료\"로 변경\r\n5. 커밋: \\`feat(<feature>): <task-id> - <설명>\\`\r\n\r\n## 완료 조건\r\n\r\n모든 작업이 완료되면:\r\n1. \\`sdd validate\\`로 최종 검증\r\n2. PR 생성 또는 머지\r\n3. 필요시 \\`/sdd.archive\\`로 아카이브\r\n`,\r\n },\r\n {\r\n name: 'sdd.validate',\r\n content: `스펙 파일의 형식과 규칙을 검증합니다.\r\n\r\n## 지시사항\r\n\r\n\\`sdd validate\\` 명령어를 실행하여 모든 스펙을 검증하세요.\r\n\r\n## 검증 항목\r\n\r\n1. **RFC 2119 키워드**: SHALL, MUST, SHOULD, MAY 등 포함 여부\r\n2. **GIVEN-WHEN-THEN**: 시나리오 형식 준수 여부\r\n3. **메타데이터**: YAML frontmatter 필수 필드 확인\r\n4. **구조**: 필수 섹션 존재 여부\r\n\r\n## 사용법\r\n\r\n\\`\\`\\`bash\r\n# 전체 스펙 검증\r\nsdd validate\r\n\r\n# 특정 파일 검증\r\nsdd validate .sdd/specs/user-auth/spec.md\r\n\r\n# 엄격 모드 (경고도 에러로 처리)\r\nsdd validate --strict\r\n\\`\\`\\`\r\n\r\n## 오류 해결\r\n\r\n검증 실패 시 해당 파일을 열어 오류를 수정하세요.\r\n각 오류 메시지에는 해결 방법이 포함되어 있습니다.\r\n`,\r\n },\r\n {\r\n name: 'sdd.status',\r\n content: `현재 SDD 프로젝트 상태를 확인합니다.\r\n\r\n## 지시사항\r\n\r\n\\`sdd status\\` 명령어를 실행하여 프로젝트 상태를 확인하세요.\r\n\r\n## 확인 항목\r\n\r\n- 프로젝트 구조 (constitution.md, AGENTS.md 존재 여부)\r\n- 기능 목록 및 상태\r\n- 현재 Git 브랜치\r\n- 다음 단계 제안\r\n\r\n## 추가 명령어\r\n\r\n\\`\\`\\`bash\r\n# 프로젝트 요약\r\nsdd list\r\n\r\n# 기능 목록\r\nsdd list features\r\n\r\n# 스펙 파일 목록\r\nsdd list specs\r\n\r\n# JSON 형식 출력\r\nsdd status --json\r\n\\`\\`\\`\r\n`,\r\n },\r\n {\r\n name: 'sdd.change',\r\n content: `기존 스펙에 대한 변경을 제안합니다.\r\n\r\n## 지시사항\r\n\r\n1. 변경이 필요한 스펙을 확인하세요\r\n2. \\`.sdd/changes/\\` 디렉토리에 변경 제안서를 작성하세요\r\n3. 변경 유형(ADDED, MODIFIED, REMOVED)을 명시하세요\r\n\r\n## 변경 제안서 구조\r\n\r\n\\`\\`\\`markdown\r\n---\r\nid: CHG-001\r\nstatus: draft\r\ncreated: YYYY-MM-DD\r\n---\r\n\r\n# 변경 제안: [제목]\r\n\r\n## 배경\r\n왜 이 변경이 필요한가?\r\n\r\n## 영향 범위\r\n### 영향받는 스펙\r\n- \\`specs/user-auth/spec.md\\`\r\n\r\n### 변경 유형\r\n- [x] 수정 (MODIFIED)\r\n\r\n## 변경 내용\r\n\r\n### MODIFIED\r\n\r\n#### Before\r\n\\`\\`\\`markdown\r\n기존 내용\r\n\\`\\`\\`\r\n\r\n#### After\r\n\\`\\`\\`markdown\r\n변경된 내용\r\n\\`\\`\\`\r\n\\`\\`\\`\r\n\r\n검토 후 승인되면 스펙에 반영하세요.\r\n`,\r\n },\r\n {\r\n name: 'sdd.constitution',\r\n content: `프로젝트 Constitution(헌법)을 관리합니다.\r\n\r\n## 개요\r\n\r\nConstitution은 프로젝트의 핵심 원칙을 정의하는 문서입니다.\r\n모든 스펙과 구현은 Constitution의 원칙을 준수해야 합니다.\r\n\r\n## 지시사항\r\n\r\n### 새 프로젝트 설정\r\n\r\n1. 사용자에게 프로젝트의 핵심 가치와 원칙을 질문하세요\r\n2. \\`.sdd/constitution.md\\` 파일을 열어 내용을 작성하세요\r\n3. \\`sdd constitution validate\\`로 형식을 검증하세요\r\n\r\n### 기존 Constitution 수정\r\n\r\n1. \\`sdd constitution show\\`로 현재 내용을 확인하세요\r\n2. Constitution 수정 후 버전을 업데이트하세요:\r\n - \\`sdd constitution bump --patch -m \"문구 수정\"\\`\r\n - \\`sdd constitution bump --minor -m \"새 원칙 추가\"\\`\r\n - \\`sdd constitution bump --major -m \"핵심 원칙 변경\"\\`\r\n\r\n## Constitution 구조\r\n\r\n\\`\\`\\`markdown\r\n---\r\nversion: 1.0.0\r\ncreated: YYYY-MM-DD\r\nupdated: YYYY-MM-DD\r\n---\r\n\r\n# Constitution: 프로젝트명\r\n\r\n> 프로젝트 설명\r\n\r\n## 핵심 원칙\r\n\r\n### 1. 원칙명\r\n- 규칙 (SHALL/MUST/SHOULD/MAY)\r\n\r\n## 금지 사항\r\n- 금지 규칙 (SHALL NOT/MUST NOT)\r\n\r\n## 기술 스택\r\n- 기술 선택\r\n\r\n## 품질 기준\r\n- 품질 요구사항\r\n\\`\\`\\`\r\n\r\n## 버전 관리\r\n\r\n- **MAJOR**: 핵심 원칙 변경 (기존 스펙에 영향)\r\n- **MINOR**: 새 원칙 추가\r\n- **PATCH**: 문구 수정, 오타 수정\r\n\r\n## 명령어\r\n\r\n\\`\\`\\`bash\r\nsdd constitution show # 현재 Constitution 표시\r\nsdd constitution version # 버전만 표시\r\nsdd constitution validate # 형식 검증\r\nsdd constitution history # 변경 이력 조회\r\nsdd constitution bump # 버전 업데이트\r\n\\`\\`\\`\r\n`,\r\n },\r\n {\r\n name: 'sdd.research',\r\n content: `기술 리서치 문서를 작성합니다.\r\n\r\n## 개요\r\n\r\n기술적 결정이나 아키텍처 선택 전에 필요한 리서치를 문서화합니다.\r\n리서치 결과는 plan.md나 스펙의 근거로 활용됩니다.\r\n\r\n## 지시사항\r\n\r\n1. 리서치 주제와 목적을 명확히 정의하세요\r\n2. 비교할 옵션들을 나열하세요\r\n3. 각 옵션의 장단점을 분석하세요\r\n4. 권장사항을 도출하세요\r\n\r\n## 리서치 템플릿\r\n\r\n\\`\\`\\`markdown\r\n# 리서치: [주제]\r\n\r\n> 작성일: YYYY-MM-DD\r\n> 상태: 진행중/완료\r\n\r\n## 배경\r\n\r\n왜 이 리서치가 필요한가?\r\n\r\n## 비교 대상\r\n\r\n### 옵션 A: [이름]\r\n\r\n**장점:**\r\n- ...\r\n\r\n**단점:**\r\n- ...\r\n\r\n**적용 사례:**\r\n- ...\r\n\r\n### 옵션 B: [이름]\r\n\r\n...\r\n\r\n## 비교표\r\n\r\n| 기준 | 옵션 A | 옵션 B |\r\n|------|--------|--------|\r\n| 성능 | ... | ... |\r\n| 학습 곡선 | ... | ... |\r\n| 커뮤니티 | ... | ... |\r\n\r\n## 결론\r\n\r\n**권장사항:** 옵션 X\r\n\r\n**근거:**\r\n1. ...\r\n2. ...\r\n\r\n## 참고 자료\r\n\r\n- [링크1]\r\n- [링크2]\r\n\\`\\`\\`\r\n\r\n## 저장 위치\r\n\r\n리서치 문서는 \\`.sdd/research/\\` 또는 해당 기능 디렉토리에 저장하세요.\r\n`,\r\n },\r\n {\r\n name: 'sdd.data-model',\r\n content: `데이터 모델 문서를 작성합니다.\r\n\r\n## 개요\r\n\r\n시스템의 데이터 구조와 관계를 정의합니다.\r\n이 문서는 구현의 기반이 되며, 변경 시 영향도 분석에 활용됩니다.\r\n\r\n## 지시사항\r\n\r\n1. 핵심 엔티티를 정의하세요\r\n2. 각 엔티티의 속성을 나열하세요\r\n3. 엔티티 간 관계를 정의하세요\r\n4. ERD를 Mermaid로 작성하세요\r\n\r\n## 데이터 모델 템플릿\r\n\r\n\\`\\`\\`markdown\r\n# 데이터 모델: [시스템명]\r\n\r\n> 작성일: YYYY-MM-DD\r\n> 버전: 1.0.0\r\n\r\n## 엔티티 정의\r\n\r\n### User (사용자)\r\n\r\n| 필드 | 타입 | 필수 | 설명 |\r\n|------|------|------|------|\r\n| id | UUID | O | 고유 식별자 |\r\n| email | string | O | 이메일 (unique) |\r\n| name | string | O | 사용자명 |\r\n| created_at | datetime | O | 생성일시 |\r\n\r\n### Post (게시글)\r\n\r\n...\r\n\r\n## 관계도 (ERD)\r\n\r\n\\`\\`\\`mermaid\r\nerDiagram\r\n User ||--o{ Post : writes\r\n User {\r\n uuid id PK\r\n string email\r\n string name\r\n }\r\n Post {\r\n uuid id PK\r\n uuid user_id FK\r\n string title\r\n text content\r\n }\r\n\\`\\`\\`\r\n\r\n## 인덱스\r\n\r\n| 테이블 | 인덱스 | 컬럼 | 유형 |\r\n|--------|--------|------|------|\r\n| User | idx_user_email | email | UNIQUE |\r\n\r\n## 제약조건\r\n\r\n- User.email은 유일해야 한다(SHALL)\r\n- Post.user_id는 User.id를 참조해야 한다(SHALL)\r\n\\`\\`\\`\r\n\r\n## 저장 위치\r\n\r\n데이터 모델은 \\`.sdd/data-model.md\\` 또는 해당 기능 디렉토리에 저장하세요.\r\n`,\r\n },\r\n {\r\n name: 'sdd.prepare',\r\n content: `기능 구현에 필요한 환경을 준비합니다.\r\n\r\n## 개요\r\n\r\n새로운 기능을 구현하기 전에 필요한 도구, 의존성, 설정을 분석하고 준비합니다.\r\n\r\n## 지시사항\r\n\r\n1. 스펙을 분석하여 필요한 기술을 파악하세요\r\n2. 필요한 의존성을 나열하세요\r\n3. 필요한 MCP 서버가 있다면 확인하세요\r\n4. AGENTS.md에 필요한 지침을 추가하세요\r\n\r\n## 준비 체크리스트\r\n\r\n### 1. 의존성 확인\r\n\r\n\\`\\`\\`bash\r\n# 필요한 npm 패키지 확인\r\nnpm list [package-name]\r\n\r\n# 설치 필요시\r\nnpm install [package-name]\r\n\\`\\`\\`\r\n\r\n### 2. 환경 설정\r\n\r\n- [ ] 환경 변수 확인 (.env)\r\n- [ ] API 키 설정\r\n- [ ] 데이터베이스 연결\r\n\r\n### 3. MCP 서버 (필요시)\r\n\r\n필요한 MCP 서버 목록:\r\n- filesystem: 파일 시스템 접근\r\n- github: GitHub API 연동\r\n- database: 데이터베이스 접근\r\n\r\n### 4. AGENTS.md 업데이트\r\n\r\n기능 구현에 필요한 지침을 AGENTS.md에 추가:\r\n\r\n\\`\\`\\`markdown\r\n## [기능명] 구현 지침\r\n\r\n### 사용 기술\r\n- ...\r\n\r\n### 구현 규칙\r\n- ...\r\n\r\n### 참고 자료\r\n- ...\r\n\\`\\`\\`\r\n\r\n## 명령어\r\n\r\n\\`\\`\\`bash\r\n# 프로젝트 상태 확인\r\nsdd status\r\n\r\n# 스펙 검증\r\nsdd validate\r\n\\`\\`\\`\r\n`,\r\n },\r\n {\r\n name: 'sdd.analyze',\r\n content: `사용자 요청을 분석하여 적절한 워크플로우를 추천합니다.\r\n\r\n## 개요\r\n\r\n자연어 요청을 분석하여 작업 규모를 판단하고, 적절한 SDD 워크플로우를 추천합니다.\r\n\r\n## 분석 기준\r\n\r\n### 작업 규모 판단\r\n\r\n**소규모 (Small)**\r\n- 키워드: 수정, 변경, 버그, 오타, 추가(단순)\r\n- 워크플로우: change 또는 직접 수정\r\n\r\n**중규모 (Medium)**\r\n- 키워드: 기능 추가, 개선, 확장, 리팩터링\r\n- 워크플로우: new → plan → tasks\r\n\r\n**대규모 (Large)**\r\n- 키워드: 시스템, 아키텍처, 마이그레이션, 전면 개편\r\n- 워크플로우: research → new → plan → tasks → prepare\r\n\r\n### 워크플로우 선택\r\n\r\n| 규모 | 추천 워크플로우 | 필수 산출물 |\r\n|------|----------------|-------------|\r\n| Small | /sdd.change | proposal.md |\r\n| Medium | /sdd.new → /sdd.plan | spec.md, plan.md |\r\n| Large | /sdd.research → /sdd.new | research.md, spec.md, plan.md |\r\n\r\n## 사용 방법\r\n\r\n1. 사용자의 요청을 입력받습니다\r\n2. 키워드와 컨텍스트를 분석합니다\r\n3. 작업 규모를 판단합니다\r\n4. 적절한 워크플로우를 추천합니다\r\n\r\n## 예시\r\n\r\n**입력:** \"로그인 기능 추가해줘\"\r\n**분석:**\r\n- 키워드: \"기능 추가\" → 중규모\r\n- 추천: /sdd.new → /sdd.plan → /sdd.tasks → /sdd.implement\r\n\r\n**입력:** \"로그인 버튼 색상 변경\"\r\n**분석:**\r\n- 키워드: \"변경\" → 소규모\r\n- 추천: 직접 수정 또는 /sdd.change\r\n\r\n**입력:** \"마이크로서비스 아키텍처로 전환\"\r\n**분석:**\r\n- 키워드: \"아키텍처\", \"전환\" → 대규모\r\n- 추천: /sdd.research → /sdd.new → /sdd.plan\r\n`,\r\n },\r\n {\r\n name: 'sdd.chat',\r\n content: `대화형 SDD 어시스턴트를 시작합니다.\r\n\r\n## 개요\r\n\r\n자연어로 SDD 작업을 수행할 수 있는 대화형 인터페이스입니다.\r\n질문, 명세 작성, 검토, 구현 등 모든 SDD 워크플로우를 대화로 진행합니다.\r\n\r\n## 대화 모드\r\n\r\n### 1. 질문 모드 (Ask)\r\n\r\nSDD나 현재 프로젝트에 대해 질문합니다:\r\n- \"이 스펙의 의존성은 뭐야?\"\r\n- \"RFC 2119 키워드는 어떻게 사용해?\"\r\n- \"다음에 뭘 해야 해?\"\r\n\r\n### 2. 작성 모드 (Write)\r\n\r\n명세나 문서를 대화형으로 작성합니다:\r\n- \"새 기능 명세 작성해줘\"\r\n- \"이 요구사항을 시나리오로 바꿔줘\"\r\n- \"plan.md 작성 도와줘\"\r\n\r\n### 3. 검토 모드 (Review)\r\n\r\n기존 명세를 검토하고 피드백합니다:\r\n- \"spec.md 검토해줘\"\r\n- \"이 시나리오 괜찮아?\"\r\n- \"RFC 2119 키워드 사용이 맞아?\"\r\n\r\n### 4. 실행 모드 (Execute)\r\n\r\nSDD 명령어를 대신 실행합니다:\r\n- \"스펙 검증해줘\"\r\n- \"영향도 분석해줘\"\r\n- \"변경 제안 목록 보여줘\"\r\n\r\n## 컨텍스트 유지\r\n\r\n대화 중 다음 정보를 자동으로 추적합니다:\r\n- 현재 작업 중인 스펙\r\n- 최근 실행한 명령어\r\n- 발견된 문제점\r\n- 다음 단계 제안\r\n\r\n## 사용 예시\r\n\r\n**대화 시작:**\r\n> 새로운 인증 기능을 만들고 싶어\r\n\r\n**응답:**\r\n1. 기능 이름과 설명을 알려주세요\r\n2. 주요 요구사항은 무엇인가요?\r\n3. 어떤 인증 방식을 사용하나요?\r\n\r\n**대화 진행:**\r\n> 이메일/비밀번호 인증이야. 소셜 로그인은 나중에\r\n\r\n**응답:**\r\n기본 인증 스펙을 작성합니다...\r\n[spec.md 작성 시작]\r\n\r\n## 종료\r\n\r\n대화를 종료하려면:\r\n- \"끝\" 또는 \"종료\"\r\n- 다른 슬래시 커맨드 사용\r\n`,\r\n },\r\n {\r\n name: 'sdd.guide',\r\n content: `SDD 워크플로우 가이드를 표시합니다.\r\n\r\n## 개요\r\n\r\nSDD(Spec-Driven Development) 방법론의 전체 워크플로우를 안내합니다.\r\n처음 사용자나 워크플로우를 잊었을 때 참고하세요.\r\n\r\n## SDD 핵심 원칙\r\n\r\n1. **명세 우선**: 코드보다 명세를 먼저 작성\r\n2. **추적 가능성**: 모든 구현은 명세에서 추적 가능\r\n3. **점진적 구체화**: 개요 → 상세 → 구현\r\n4. **변경 관리**: 모든 변경은 제안 → 검토 → 적용\r\n\r\n## 전체 워크플로우\r\n\r\n\\`\\`\\`\r\n┌─────────────────────────────────────────────────┐\r\n│ SDD 워크플로우 │\r\n├─────────────────────────────────────────────────┤\r\n│ │\r\n│ 1. 시작 ─────> /sdd.start 또는 sdd start │\r\n│ │ │\r\n│ ▼ │\r\n│ 2. Constitution ─> /sdd.constitution │\r\n│ │ (프로젝트 원칙 정의) │\r\n│ ▼ │\r\n│ 3. 새 기능 ────> /sdd.new │\r\n│ │ (spec.md 작성) │\r\n│ ▼ │\r\n│ 4. 계획 ─────> /sdd.plan │\r\n│ │ (plan.md 작성) │\r\n│ ▼ │\r\n│ 5. 작업분해 ──> /sdd.tasks │\r\n│ │ (tasks.md 작성) │\r\n│ ▼ │\r\n│ 6. 구현 ─────> /sdd.implement │\r\n│ │ (순차적 구현) │\r\n│ ▼ │\r\n│ 7. 검증 ─────> /sdd.validate │\r\n│ │ │\r\n│ ▼ │\r\n│ 8. 완료 ─────> 머지 또는 배포 │\r\n│ │\r\n└─────────────────────────────────────────────────┘\r\n\\`\\`\\`\r\n\r\n## 변경 워크플로우\r\n\r\n기존 스펙을 수정할 때:\r\n\r\n\\`\\`\\`\r\n1. /sdd.change ──> proposal.md 작성\r\n │\r\n ▼\r\n2. sdd change validate <id> ──> 검증\r\n │\r\n ▼\r\n3. sdd change apply <id> ──> 적용\r\n │\r\n ▼\r\n4. sdd change archive <id> ──> 아카이브\r\n\\`\\`\\`\r\n\r\n## 슬래시 커맨드 요약\r\n\r\n| 커맨드 | 설명 | 사용 시점 |\r\n|--------|------|----------|\r\n| /sdd.start | 통합 진입점 | 처음 시작 시 |\r\n| /sdd.new | 새 기능 명세 | 새 기능 개발 시 |\r\n| /sdd.plan | 구현 계획 | 명세 완료 후 |\r\n| /sdd.tasks | 작업 분해 | 계획 완료 후 |\r\n| /sdd.implement | 구현 | 작업 분해 후 |\r\n| /sdd.validate | 검증 | 구현 완료 후 |\r\n| /sdd.change | 변경 제안 | 기존 스펙 수정 시 |\r\n| /sdd.constitution | 헌법 관리 | 프로젝트 설정 시 |\r\n| /sdd.chat | 대화형 모드 | 언제든지 |\r\n| /sdd.analyze | 요청 분석 | 규모 판단 시 |\r\n\r\n## CLI 명령어 요약\r\n\r\n\\`\\`\\`bash\r\nsdd init # 프로젝트 초기화\r\nsdd start # 워크플로우 시작\r\nsdd new <name> # 새 기능 생성\r\nsdd new <name> --numbered # 번호 자동 부여\r\nsdd validate # 스펙 검증\r\nsdd validate --check-links # 링크 검증 포함\r\nsdd status # 상태 확인\r\nsdd list # 스펙 목록\r\nsdd change -l # 변경 목록\r\nsdd impact <spec> # 영향도 분석\r\nsdd transition guide # 전환 가이드\r\n\\`\\`\\`\r\n\r\n## 도움말\r\n\r\n더 자세한 정보:\r\n- \\`sdd --help\\` - CLI 도움말\r\n- \\`sdd <command> --help\\` - 명령어별 도움말\r\n`,\r\n },\r\n {\r\n name: 'sdd.transition',\r\n content: `워크플로우 간 전환을 수행합니다.\r\n\r\n## 개요\r\n\r\n작업 중 워크플로우를 변경해야 할 때 사용합니다:\r\n- **new → change**: 새 기능이 기존 스펙 수정으로 변경\r\n- **change → new**: 변경 범위가 커서 새 기능으로 분리\r\n\r\n## new → change 전환\r\n\r\n### 사용 시점\r\n- 새 기능 작성 중 기존 스펙과 중복 발견\r\n- 기존 기능 확장이 더 적절한 경우\r\n- 의존성 분석 결과 기존 스펙 수정 필요\r\n\r\n### 명령어\r\n\r\n\\`\\`\\`bash\r\nsdd transition new-to-change <spec-id>\r\n -t, --title <title> # 변경 제안 제목\r\n -r, --reason <reason> # 전환 사유\r\n\\`\\`\\`\r\n\r\n### 결과\r\n- 새 변경 제안 생성 (.sdd/changes/<id>/)\r\n- proposal.md, delta.md, tasks.md 생성\r\n- 기존 스펙 참조 자동 설정\r\n\r\n## change → new 전환\r\n\r\n### 사용 시점\r\n- 변경 범위가 너무 커서 별도 기능으로 분리 필요\r\n- 기존 스펙과 독립적인 새 기능으로 발전\r\n- 영향도 분석 결과 분리가 안전\r\n\r\n### 명령어\r\n\r\n\\`\\`\\`bash\r\nsdd transition change-to-new <change-id>\r\n -n, --name <name> # 새 기능 이름\r\n -r, --reason <reason> # 전환 사유\r\n\\`\\`\\`\r\n\r\n### 결과\r\n- 새 스펙 생성 (.sdd/specs/<name>/)\r\n- spec.md, plan.md, tasks.md 생성\r\n- 원본 변경 제안은 'transitioned' 상태로 변경\r\n\r\n## 전환 판단 기준\r\n\r\n### new → change 권장\r\n- 영향받는 스펙 수 ≤ 3개\r\n- 변경이 기존 기능의 자연스러운 확장\r\n- 새 시나리오 추가보다 기존 시나리오 수정 중심\r\n\r\n### change → new 권장\r\n- 영향받는 스펙 수 > 3개\r\n- 새로운 개념/도메인 도입\r\n- 기존 스펙과 독립적으로 테스트 가능\r\n\r\n## 가이드 보기\r\n\r\n\\`\\`\\`bash\r\nsdd transition guide\r\n\\`\\`\\`\r\n`,\r\n },\r\n ];\r\n}\r\n","/**\r\n * sdd validate 명령어\r\n */\r\nimport { Command } from 'commander';\r\nimport path from 'node:path';\r\nimport chalk from 'chalk';\r\nimport { validateSpecs, type FileValidationResult } from '../../core/spec/validator.js';\r\nimport { ExitCode } from '../../errors/index.js';\r\nimport { findSddRoot } from '../../utils/fs.js';\r\nimport * as logger from '../../utils/logger.js';\r\n\r\n/**\r\n * validate 명령어 등록\r\n */\r\nexport function registerValidateCommand(program: Command): void {\r\n program\r\n .command('validate')\r\n .description('스펙 파일 형식을 검증합니다')\r\n .argument('[path]', '검증할 파일 또는 디렉토리', '')\r\n .option('-s, --strict', '경고도 에러로 처리')\r\n .option('-q, --quiet', '요약만 출력')\r\n .option('-l, --check-links', '참조 링크 유효성 검사')\r\n .action(async (targetPath: string, options: { strict?: boolean; quiet?: boolean; checkLinks?: boolean }) => {\r\n try {\r\n await runValidate(targetPath, options);\r\n } catch (error) {\r\n logger.error(error instanceof Error ? error.message : String(error));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n });\r\n}\r\n\r\n/**\r\n * 검증 실행\r\n */\r\nasync function runValidate(\r\n targetPath: string,\r\n options: { strict?: boolean; quiet?: boolean; checkLinks?: boolean }\r\n): Promise<void> {\r\n // 대상 경로 결정\r\n let resolvedPath: string;\r\n let specsRoot: string | undefined;\r\n\r\n const sddRoot = await findSddRoot();\r\n\r\n if (targetPath) {\r\n resolvedPath = path.resolve(targetPath);\r\n } else {\r\n // 기본값: .sdd/specs/\r\n if (!sddRoot) {\r\n logger.error('SDD 프로젝트를 찾을 수 없습니다. `sdd init`을 먼저 실행하세요.');\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n resolvedPath = path.join(sddRoot, '.sdd', 'specs');\r\n }\r\n\r\n // 링크 검증을 위한 스펙 루트 경로 설정\r\n if (options.checkLinks && sddRoot) {\r\n specsRoot = path.join(sddRoot, '.sdd', 'specs');\r\n }\r\n\r\n if (!options.quiet) {\r\n logger.info(`검증 중: ${resolvedPath}`);\r\n if (options.checkLinks) {\r\n logger.info('(참조 링크 검증 포함)');\r\n }\r\n logger.newline();\r\n }\r\n\r\n // 검증 실행\r\n const result = await validateSpecs(resolvedPath, {\r\n strict: options.strict,\r\n checkLinks: options.checkLinks,\r\n specsRoot,\r\n });\r\n\r\n if (!result.success) {\r\n logger.error(result.error.message);\r\n process.exit(ExitCode.FILE_SYSTEM_ERROR);\r\n }\r\n\r\n const { passed, failed, warnings, files } = result.data;\r\n\r\n // 결과 출력\r\n if (!options.quiet) {\r\n for (const file of files) {\r\n printFileResult(file, resolvedPath);\r\n }\r\n logger.newline();\r\n }\r\n\r\n // 요약\r\n const passedText = chalk.green(`${passed} passed`);\r\n const failedText = failed > 0 ? chalk.red(`${failed} failed`) : `${failed} failed`;\r\n const warningsText = warnings > 0 ? chalk.yellow(`${warnings} warnings`) : '';\r\n\r\n const summary = [passedText, failedText, warningsText].filter(Boolean).join(', ');\r\n console.log(`Result: ${summary}`);\r\n\r\n // 종료 코드\r\n if (failed > 0) {\r\n process.exit(ExitCode.VALIDATION_FAILED);\r\n }\r\n}\r\n\r\n/**\r\n * 파일 검증 결과 출력\r\n */\r\nfunction printFileResult(result: FileValidationResult, basePath: string): void {\r\n const relativePath = path.relative(basePath, result.file);\r\n\r\n if (result.valid) {\r\n console.log(chalk.green('✓') + ' ' + relativePath);\r\n } else {\r\n console.log(chalk.red('✗') + ' ' + relativePath);\r\n\r\n for (const error of result.errors) {\r\n const line = error.location?.line ? `:${error.location.line}` : '';\r\n console.log(chalk.red(` - ${error.message}${line}`));\r\n }\r\n }\r\n\r\n // 경고 출력\r\n for (const warning of result.warnings) {\r\n console.log(chalk.yellow(` ⚠ ${warning.message}`));\r\n }\r\n}\r\n","/**\r\n * 스펙 검증기\r\n */\r\nimport path from 'node:path';\r\nimport { parseSpec, validateSpecFormat } from './parser.js';\r\nimport { readFile, listFiles, directoryExists, fileExists } from '../../utils/fs.js';\r\nimport { ValidationError, ErrorCode } from '../../errors/index.js';\r\nimport { Result, success, failure, type ValidationResult, type SpecValidationError, type SpecValidationWarning } from '../../types/index.js';\r\n\r\n/**\r\n * 검증 옵션\r\n */\r\nexport interface ValidateOptions {\r\n /** 경고도 에러로 처리 */\r\n strict?: boolean;\r\n /** 참조 링크 검증 */\r\n checkLinks?: boolean;\r\n /** 스펙 루트 경로 (링크 검증 시 사용) */\r\n specsRoot?: string;\r\n}\r\n\r\n/**\r\n * 깨진 링크 정보\r\n */\r\nexport interface BrokenLink {\r\n /** 링크 텍스트 */\r\n text: string;\r\n /** 링크 대상 */\r\n target: string;\r\n /** 발견된 줄 번호 */\r\n line?: number;\r\n /** 링크 유형 */\r\n type: 'internal' | 'spec-reference' | 'dependency';\r\n}\r\n\r\n/**\r\n * 파일 검증 결과\r\n */\r\nexport interface FileValidationResult {\r\n file: string;\r\n valid: boolean;\r\n errors: SpecValidationError[];\r\n warnings: SpecValidationWarning[];\r\n /** 깨진 링크 목록 */\r\n brokenLinks?: BrokenLink[];\r\n}\r\n\r\n/**\r\n * 전체 검증 결과\r\n */\r\nexport interface ValidateResult {\r\n passed: number;\r\n failed: number;\r\n warnings: number;\r\n files: FileValidationResult[];\r\n}\r\n\r\n/**\r\n * 단일 스펙 파일 검증\r\n */\r\nexport async function validateSpecFile(\r\n filePath: string,\r\n options: ValidateOptions = {}\r\n): Promise<FileValidationResult> {\r\n const result: FileValidationResult = {\r\n file: filePath,\r\n valid: true,\r\n errors: [],\r\n warnings: [],\r\n };\r\n\r\n // 파일 읽기\r\n const readResult = await readFile(filePath);\r\n if (!readResult.success) {\r\n result.valid = false;\r\n result.errors.push({\r\n code: ErrorCode.FILE_READ_ERROR,\r\n message: `파일을 읽을 수 없습니다: ${filePath}`,\r\n location: { file: filePath },\r\n });\r\n return result;\r\n }\r\n\r\n const content = readResult.data;\r\n\r\n // 스펙 파싱 및 검증\r\n const parseResult = parseSpec(content);\r\n if (!parseResult.success) {\r\n result.valid = false;\r\n result.errors.push({\r\n code: parseResult.error.code,\r\n message: parseResult.error.message,\r\n location: { file: filePath },\r\n });\r\n return result;\r\n }\r\n\r\n const spec = parseResult.data;\r\n\r\n // RFC 2119 키워드 검증\r\n if (spec.requirements.length === 0) {\r\n result.valid = false;\r\n result.errors.push({\r\n code: ErrorCode.RFC2119_VIOLATION,\r\n message: 'Requirement에 RFC 2119 키워드(SHALL, MUST, SHOULD, MAY)가 없습니다',\r\n location: { file: filePath },\r\n });\r\n }\r\n\r\n // GIVEN-WHEN-THEN 형식 검증\r\n if (spec.scenarios.length === 0) {\r\n result.valid = false;\r\n result.errors.push({\r\n code: ErrorCode.GWT_INVALID_FORMAT,\r\n message: 'Scenario에 GIVEN-WHEN-THEN 형식이 없습니다',\r\n location: { file: filePath },\r\n });\r\n }\r\n\r\n // Frontmatter 경고\r\n if (!spec.metadata.created) {\r\n result.warnings.push({\r\n code: 'W001',\r\n message: 'YAML frontmatter에 created 날짜가 없습니다',\r\n location: { file: filePath },\r\n });\r\n }\r\n\r\n // 참조 링크 검증\r\n if (options.checkLinks && options.specsRoot) {\r\n const brokenLinks = await validateLinks(content, filePath, options.specsRoot);\r\n if (brokenLinks.length > 0) {\r\n result.brokenLinks = brokenLinks;\r\n for (const link of brokenLinks) {\r\n result.warnings.push({\r\n code: 'W002',\r\n message: `깨진 ${link.type} 링크: ${link.target}`,\r\n location: { file: filePath, line: link.line },\r\n });\r\n }\r\n }\r\n }\r\n\r\n // strict 모드: 경고도 에러로 처리\r\n if (options.strict && result.warnings.length > 0) {\r\n result.valid = false;\r\n result.errors.push(...result.warnings.map((w) => ({\r\n code: w.code,\r\n message: `[STRICT] ${w.message}`,\r\n location: w.location,\r\n })));\r\n }\r\n\r\n return result;\r\n}\r\n\r\n/**\r\n * 스펙 파일 내 링크 검증\r\n */\r\nasync function validateLinks(\r\n content: string,\r\n filePath: string,\r\n specsRoot: string\r\n): Promise<BrokenLink[]> {\r\n const brokenLinks: BrokenLink[] = [];\r\n const lines = content.split('\\n');\r\n const fileDir = path.dirname(filePath);\r\n\r\n // 마크다운 링크 패턴: [text](url)\r\n const linkPattern = /\\[([^\\]]+)\\]\\(([^)]+)\\)/g;\r\n\r\n // 스펙 참조 패턴: `spec-id` 또는 [[spec-id]]\r\n const specRefPattern = /(?:`([a-z0-9-]+)`|\\[\\[([a-z0-9-]+)\\]\\])/g;\r\n\r\n for (let lineNum = 0; lineNum < lines.length; lineNum++) {\r\n const line = lines[lineNum];\r\n\r\n // 마크다운 링크 검증\r\n let match;\r\n while ((match = linkPattern.exec(line)) !== null) {\r\n const [, text, target] = match;\r\n\r\n // 외부 링크 (http/https) 또는 앵커 링크 (#) 무시\r\n if (target.startsWith('http://') || target.startsWith('https://') || target.startsWith('#')) {\r\n continue;\r\n }\r\n\r\n // 내부 파일 링크 검증\r\n const targetPath = path.resolve(fileDir, target);\r\n if (!(await fileExists(targetPath))) {\r\n brokenLinks.push({\r\n text,\r\n target,\r\n line: lineNum + 1,\r\n type: 'internal',\r\n });\r\n }\r\n }\r\n\r\n // 스펙 참조 검증 (backtick 또는 wiki-style 링크)\r\n while ((match = specRefPattern.exec(line)) !== null) {\r\n const specId = match[1] || match[2];\r\n\r\n // 일반적인 코드 키워드 제외\r\n const codeKeywords = ['true', 'false', 'null', 'undefined', 'string', 'number', 'boolean', 'object', 'array'];\r\n if (codeKeywords.includes(specId)) {\r\n continue;\r\n }\r\n\r\n // 스펙 ID 형식인지 확인 (하이픈 포함, 영소문자+숫자)\r\n if (!/^[a-z][a-z0-9]*(-[a-z0-9]+)+$/.test(specId)) {\r\n continue;\r\n }\r\n\r\n // 스펙 디렉토리 확인\r\n const specPath = path.join(specsRoot, specId);\r\n const specFilePath = path.join(specPath, 'spec.md');\r\n if (!(await directoryExists(specPath)) && !(await fileExists(specFilePath))) {\r\n brokenLinks.push({\r\n text: specId,\r\n target: specId,\r\n line: lineNum + 1,\r\n type: 'spec-reference',\r\n });\r\n }\r\n }\r\n }\r\n\r\n return brokenLinks;\r\n}\r\n\r\n/**\r\n * 스펙의 의존성 검증\r\n */\r\nexport async function validateDependencies(\r\n filePath: string,\r\n specsRoot: string\r\n): Promise<BrokenLink[]> {\r\n const brokenLinks: BrokenLink[] = [];\r\n\r\n const readResult = await readFile(filePath);\r\n if (!readResult.success) {\r\n return brokenLinks;\r\n }\r\n\r\n const parseResult = parseSpec(readResult.data);\r\n if (!parseResult.success) {\r\n return brokenLinks;\r\n }\r\n\r\n const spec = parseResult.data;\r\n\r\n // dependencies 필드 검증\r\n if (spec.metadata.dependencies && Array.isArray(spec.metadata.dependencies)) {\r\n for (const dep of spec.metadata.dependencies) {\r\n const depPath = path.join(specsRoot, dep);\r\n const depFilePath = path.join(depPath, 'spec.md');\r\n if (!(await directoryExists(depPath)) && !(await fileExists(depFilePath))) {\r\n brokenLinks.push({\r\n text: dep,\r\n target: dep,\r\n type: 'dependency',\r\n });\r\n }\r\n }\r\n }\r\n\r\n return brokenLinks;\r\n}\r\n\r\n/**\r\n * 디렉토리 내 모든 스펙 파일 검증\r\n */\r\nexport async function validateSpecs(\r\n targetPath: string,\r\n options: ValidateOptions = {}\r\n): Promise<Result<ValidateResult, ValidationError>> {\r\n const results: FileValidationResult[] = [];\r\n let passed = 0;\r\n let failed = 0;\r\n let warnings = 0;\r\n\r\n // 디렉토리인지 파일인지 확인\r\n if (await directoryExists(targetPath)) {\r\n // 디렉토리 내 모든 .md 파일 찾기\r\n const filesResult = await findSpecFiles(targetPath);\r\n if (!filesResult.success) {\r\n return failure(new ValidationError(ErrorCode.DIRECTORY_NOT_FOUND, targetPath));\r\n }\r\n\r\n for (const file of filesResult.data) {\r\n const result = await validateSpecFile(file, options);\r\n results.push(result);\r\n\r\n if (result.valid) {\r\n passed++;\r\n } else {\r\n failed++;\r\n }\r\n warnings += result.warnings.length;\r\n }\r\n } else {\r\n // 단일 파일 검증\r\n const result = await validateSpecFile(targetPath, options);\r\n results.push(result);\r\n\r\n if (result.valid) {\r\n passed++;\r\n } else {\r\n failed++;\r\n }\r\n warnings += result.warnings.length;\r\n }\r\n\r\n return success({\r\n passed,\r\n failed,\r\n warnings,\r\n files: results,\r\n });\r\n}\r\n\r\n/**\r\n * 디렉토리 내 스펙 파일 재귀 검색\r\n */\r\nasync function findSpecFiles(dirPath: string): Promise<Result<string[], ValidationError>> {\r\n const files: string[] = [];\r\n\r\n async function scanDir(dir: string): Promise<void> {\r\n const { promises: fs } = await import('node:fs');\r\n\r\n try {\r\n const entries = await fs.readdir(dir, { withFileTypes: true });\r\n\r\n for (const entry of entries) {\r\n const fullPath = path.join(dir, entry.name);\r\n\r\n if (entry.isDirectory()) {\r\n await scanDir(fullPath);\r\n } else if (entry.isFile() && entry.name.endsWith('.md')) {\r\n // 보조 파일 및 시스템 파일 제외 (spec.md만 검증)\r\n const excludeFiles = [\r\n 'index.md',\r\n 'readme.md',\r\n 'plan.md',\r\n 'tasks.md',\r\n 'checklist.md',\r\n ];\r\n if (!excludeFiles.includes(entry.name.toLowerCase())) {\r\n files.push(fullPath);\r\n }\r\n }\r\n }\r\n } catch {\r\n // 디렉토리 읽기 실패 시 무시\r\n }\r\n }\r\n\r\n await scanDir(dirPath);\r\n return success(files);\r\n}\r\n","/**\r\n * 스펙 마크다운 파서\r\n */\r\nimport matter from 'gray-matter';\r\nimport {\r\n ParsedSpec,\r\n SpecMetadataSchema,\r\n Requirement,\r\n Scenario,\r\n extractRfc2119Keywords,\r\n type SpecMetadata,\r\n} from './schemas.js';\r\nimport { Result, success, failure } from '../../types/index.js';\r\nimport { ValidationError, ErrorCode } from '../../errors/index.js';\r\n\r\n/**\r\n * 마크다운 스펙 파일 파싱\r\n */\r\nexport function parseSpec(content: string): Result<ParsedSpec, ValidationError> {\r\n try {\r\n // 1. Frontmatter 파싱\r\n const { data: rawMeta, content: body } = matter(content);\r\n\r\n // 2. 메타데이터 검증\r\n const metaResult = SpecMetadataSchema.safeParse(rawMeta);\r\n if (!metaResult.success) {\r\n const errors = metaResult.error.errors.map((e) => e.message).join(', ');\r\n return failure(new ValidationError(ErrorCode.SPEC_INVALID_FORMAT, `메타데이터 오류: ${errors}`));\r\n }\r\n const metadata: SpecMetadata = metaResult.data;\r\n\r\n // 3. 제목 추출\r\n const titleMatch = body.match(/^#\\s+(.+)$/m);\r\n if (!titleMatch) {\r\n return failure(new ValidationError(ErrorCode.SPEC_MISSING_REQUIRED, '제목(# Title)이 필요합니다'));\r\n }\r\n const title = titleMatch[1].trim();\r\n\r\n // 4. 설명 추출 (제목 다음 줄의 blockquote)\r\n const descMatch = body.match(/^#\\s+.+\\n+>\\s*(.+)$/m);\r\n const description = descMatch?.[1]?.trim();\r\n\r\n // 5. 요구사항 추출\r\n const requirements = parseRequirements(body);\r\n\r\n // 6. 시나리오 추출\r\n const scenarios = parseScenarios(body);\r\n\r\n return success({\r\n title,\r\n description,\r\n metadata,\r\n requirements,\r\n scenarios,\r\n rawContent: content,\r\n });\r\n } catch (error) {\r\n const message = error instanceof Error ? error.message : String(error);\r\n return failure(new ValidationError(ErrorCode.SPEC_PARSE_ERROR, message));\r\n }\r\n}\r\n\r\n/**\r\n * 요구사항 파싱\r\n */\r\nfunction parseRequirements(content: string): Requirement[] {\r\n const requirements: Requirement[] = [];\r\n\r\n // 요구사항 섹션 찾기 (## 요구사항 또는 ## Requirements)\r\n const reqSectionMatch = content.match(/##\\s+(?:요구사항|Requirements?)\\s*\\n([\\s\\S]*?)(?=\\n##\\s+[^#]|\\n---|\\n$)/i);\r\n if (!reqSectionMatch) {\r\n // 전체 문서에서 RFC 2119 키워드 찾기\r\n return parseRequirementsFromContent(content);\r\n }\r\n\r\n return parseRequirementsFromContent(reqSectionMatch[1]);\r\n}\r\n\r\n/**\r\n * 컨텐츠에서 요구사항 추출\r\n */\r\nfunction parseRequirementsFromContent(content: string): Requirement[] {\r\n const requirements: Requirement[] = [];\r\n const lines = content.split('\\n');\r\n let reqId = 1;\r\n\r\n for (const line of lines) {\r\n const keywords = extractRfc2119Keywords(line);\r\n if (keywords.length > 0) {\r\n // 가장 강한 키워드 사용 (SHALL/MUST > SHOULD > MAY)\r\n const level = keywords.includes('SHALL') || keywords.includes('MUST')\r\n ? (keywords.includes('SHALL') ? 'SHALL' : 'MUST')\r\n : keywords.includes('SHOULD')\r\n ? 'SHOULD'\r\n : 'MAY';\r\n\r\n requirements.push({\r\n id: `REQ-${String(reqId++).padStart(3, '0')}`,\r\n level,\r\n description: line.trim(),\r\n raw: line,\r\n });\r\n }\r\n }\r\n\r\n return requirements;\r\n}\r\n\r\n/**\r\n * 시나리오 파싱 (GIVEN-WHEN-THEN)\r\n */\r\nfunction parseScenarios(content: string): Scenario[] {\r\n const scenarios: Scenario[] = [];\r\n\r\n // ### Scenario 섹션 찾기 (Scenario:, Scenario 1:, Scenario 1. 등 다양한 형식 지원)\r\n const scenarioRegex = /###\\s+Scenario[:\\s]+(.+?)(?=\\n###|\\n##|\\n---|\\n$)/gis;\r\n let match: RegExpExecArray | null;\r\n\r\n while ((match = scenarioRegex.exec(content)) !== null) {\r\n const sectionContent = match[0];\r\n const nameMatch = sectionContent.match(/###\\s+Scenario[:\\s]+(.+)/i);\r\n const name = nameMatch?.[1]?.trim() ?? 'Unnamed';\r\n\r\n const given: string[] = [];\r\n const then: string[] = [];\r\n let when = '';\r\n\r\n const lines = sectionContent.split('\\n');\r\n\r\n for (const line of lines) {\r\n const trimmed = line.trim();\r\n\r\n // GIVEN 파싱\r\n const givenMatch = trimmed.match(/[-*]\\s*\\*?\\*?GIVEN\\*?\\*?\\s+(.+)/i);\r\n if (givenMatch) {\r\n given.push(givenMatch[1].trim());\r\n continue;\r\n }\r\n\r\n // WHEN 파싱\r\n const whenMatch = trimmed.match(/[-*]\\s*\\*?\\*?WHEN\\*?\\*?\\s+(.+)/i);\r\n if (whenMatch) {\r\n when = whenMatch[1].trim();\r\n continue;\r\n }\r\n\r\n // THEN 파싱\r\n const thenMatch = trimmed.match(/[-*]\\s*\\*?\\*?THEN\\*?\\*?\\s+(.+)/i);\r\n if (thenMatch) {\r\n then.push(thenMatch[1].trim());\r\n }\r\n }\r\n\r\n if (given.length > 0 && when && then.length > 0) {\r\n scenarios.push({ name, given, when, then });\r\n }\r\n }\r\n\r\n return scenarios;\r\n}\r\n\r\n/**\r\n * 스펙 파일 검증만 수행 (파싱 + 검증)\r\n */\r\nexport function validateSpecFormat(content: string): Result<true, ValidationError> {\r\n const result = parseSpec(content);\r\n if (!result.success) {\r\n return result as Result<true, ValidationError>;\r\n }\r\n\r\n const spec = result.data;\r\n\r\n // 요구사항 필수 검증\r\n if (spec.requirements.length === 0) {\r\n return failure(\r\n new ValidationError(\r\n ErrorCode.RFC2119_VIOLATION,\r\n 'RFC 2119 키워드(SHALL, MUST, SHOULD, MAY)가 포함된 요구사항이 없습니다'\r\n )\r\n );\r\n }\r\n\r\n // 시나리오 필수 검증\r\n if (spec.scenarios.length === 0) {\r\n return failure(\r\n new ValidationError(\r\n ErrorCode.GWT_INVALID_FORMAT,\r\n 'GIVEN-WHEN-THEN 형식의 시나리오가 없습니다'\r\n )\r\n );\r\n }\r\n\r\n return success(true);\r\n}\r\n","/**\r\n * 스펙 관련 Zod 스키마 정의\r\n */\r\nimport { z } from 'zod';\r\n\r\n/**\r\n * RFC 2119 키워드\r\n */\r\nexport const RFC2119_KEYWORDS = ['SHALL', 'MUST', 'SHOULD', 'MAY', 'SHALL NOT', 'MUST NOT'] as const;\r\nexport type Rfc2119Keyword = (typeof RFC2119_KEYWORDS)[number];\r\n\r\n/**\r\n * 스펙 상태\r\n */\r\nexport const SpecStatusSchema = z.enum(['draft', 'review', 'approved', 'implemented']);\r\nexport type SpecStatus = z.infer<typeof SpecStatusSchema>;\r\n\r\n/**\r\n * 날짜 스키마 (Date 객체 또는 문자열 허용, 문자열로 변환)\r\n */\r\nconst DateStringSchema = z.preprocess(\r\n (val) => {\r\n if (val instanceof Date) {\r\n return val.toISOString().split('T')[0];\r\n }\r\n return val;\r\n },\r\n z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/, '날짜 형식: YYYY-MM-DD').optional()\r\n);\r\n\r\n/**\r\n * 스펙 메타데이터 (YAML frontmatter)\r\n */\r\nexport const SpecMetadataSchema = z.object({\r\n status: SpecStatusSchema.default('draft'),\r\n created: DateStringSchema,\r\n depends: z.string().nullable().optional(),\r\n command: z.string().optional(),\r\n author: z.string().optional(),\r\n});\r\nexport type SpecMetadata = z.infer<typeof SpecMetadataSchema>;\r\n\r\n/**\r\n * 요구사항 레벨\r\n */\r\nexport const RequirementLevelSchema = z.enum(['SHALL', 'MUST', 'SHOULD', 'MAY']);\r\nexport type RequirementLevel = z.infer<typeof RequirementLevelSchema>;\r\n\r\n/**\r\n * 요구사항\r\n */\r\nexport const RequirementSchema = z.object({\r\n id: z.string(),\r\n level: RequirementLevelSchema,\r\n description: z.string(),\r\n raw: z.string(),\r\n});\r\nexport type Requirement = z.infer<typeof RequirementSchema>;\r\n\r\n/**\r\n * 시나리오 (GIVEN-WHEN-THEN)\r\n */\r\nexport const ScenarioSchema = z.object({\r\n name: z.string(),\r\n given: z.array(z.string()).min(1, 'GIVEN 조건이 최소 1개 필요합니다'),\r\n when: z.string().min(1, 'WHEN 조건이 필요합니다'),\r\n then: z.array(z.string()).min(1, 'THEN 결과가 최소 1개 필요합니다'),\r\n});\r\nexport type Scenario = z.infer<typeof ScenarioSchema>;\r\n\r\n/**\r\n * 파싱된 스펙 문서\r\n */\r\nexport const ParsedSpecSchema = z.object({\r\n title: z.string(),\r\n description: z.string().optional(),\r\n metadata: SpecMetadataSchema,\r\n requirements: z.array(RequirementSchema),\r\n scenarios: z.array(ScenarioSchema),\r\n rawContent: z.string(),\r\n});\r\nexport type ParsedSpec = z.infer<typeof ParsedSpecSchema>;\r\n\r\n/**\r\n * 키워드가 RFC 2119 키워드인지 확인\r\n */\r\nexport function isRfc2119Keyword(keyword: string): keyword is Rfc2119Keyword {\r\n return RFC2119_KEYWORDS.includes(keyword as Rfc2119Keyword);\r\n}\r\n\r\n/**\r\n * 문자열에서 RFC 2119 키워드 추출\r\n */\r\nexport function extractRfc2119Keywords(text: string): Rfc2119Keyword[] {\r\n const keywords: Rfc2119Keyword[] = [];\r\n\r\n // SHALL NOT, MUST NOT를 먼저 체크 (더 긴 패턴)\r\n if (/SHALL\\s+NOT/i.test(text)) keywords.push('SHALL NOT');\r\n if (/MUST\\s+NOT/i.test(text)) keywords.push('MUST NOT');\r\n\r\n // 단일 키워드 체크 (NOT이 붙지 않은 경우만)\r\n if (/(?<!NOT\\s)SHALL(?!\\s+NOT)/i.test(text)) keywords.push('SHALL');\r\n if (/(?<!NOT\\s)MUST(?!\\s+NOT)/i.test(text)) keywords.push('MUST');\r\n if (/SHOULD/i.test(text)) keywords.push('SHOULD');\r\n if (/MAY/i.test(text)) keywords.push('MAY');\r\n\r\n return [...new Set(keywords)];\r\n}\r\n","/**\r\n * 슬래시 커맨드 프롬프트 템플릿\r\n *\r\n * AI 코딩 도구용 명령어 프롬프트를 제공합니다.\r\n */\r\n\r\n/**\r\n * 형식 규칙 가이드 (공통)\r\n */\r\nexport const FORMAT_GUIDE = `## 형식 규칙 (필수)\r\n\r\n### RFC 2119 키워드\r\n\r\n| 키워드 | 의미 | 사용 예시 |\r\n|--------|------|-----------|\r\n| **SHALL** / **MUST** | 절대 필수 | \"시스템은 인증을 지원해야 한다(SHALL)\" |\r\n| **SHOULD** | 권장 (예외 가능) | \"응답 시간은 1초 이내여야 한다(SHOULD)\" |\r\n| **MAY** | 선택적 | \"다크 모드를 지원할 수 있다(MAY)\" |\r\n| **SHALL NOT** | 절대 금지 | \"평문 비밀번호를 저장해서는 안 된다(SHALL NOT)\" |\r\n\r\n### GIVEN-WHEN-THEN 형식\r\n\r\n모든 요구사항은 아래 형식의 시나리오를 포함해야 합니다:\r\n\r\n\\`\\`\\`markdown\r\n### Scenario: [시나리오명]\r\n\r\n- **GIVEN** [전제 조건]\r\n- **WHEN** [행동/트리거]\r\n- **THEN** [예상 결과]\r\n\\`\\`\\`\r\n`;\r\n\r\n/**\r\n * /sdd:change 프롬프트\r\n */\r\nexport const CHANGE_PROMPT = `# /sdd:change - 변경 제안\r\n\r\n> 기존 스펙에 대한 변경을 제안합니다.\r\n\r\n${FORMAT_GUIDE}\r\n\r\n---\r\n\r\n## 생성 전 체크리스트\r\n\r\n- [ ] 변경 대상 스펙 확인됨\r\n- [ ] 변경 사유가 명확함\r\n- [ ] 영향 범위가 파악됨\r\n\r\n---\r\n\r\n## 생성할 파일\r\n\r\n### 1. proposal.md\r\n\r\n\\`\\`\\`markdown\r\n---\r\nid: CHG-{ID}\r\nstatus: draft\r\ncreated: {TODAY}\r\n---\r\n\r\n# 변경 제안: {TITLE}\r\n\r\n> 변경 목적 및 배경 설명\r\n\r\n---\r\n\r\n## 배경\r\n\r\n왜 이 변경이 필요한가?\r\n\r\n---\r\n\r\n## 영향 범위\r\n\r\n### 영향받는 스펙\r\n\r\n- \\`specs/{SPEC_PATH}\\`\r\n\r\n### 변경 유형\r\n\r\n- [ ] 신규 추가 (ADDED)\r\n- [ ] 수정 (MODIFIED)\r\n- [ ] 삭제 (REMOVED)\r\n\r\n---\r\n\r\n## 변경 내용\r\n\r\n(ADDED/MODIFIED/REMOVED 섹션별 상세 내용)\r\n\r\n---\r\n\r\n## 리스크 평가\r\n\r\n- 영향도: 낮음/중간/높음\r\n- 복잡도: 낮음/중간/높음\r\n\\`\\`\\`\r\n\r\n---\r\n\r\n## 생성 후 확인\r\n\r\n- [ ] \\`sdd validate .sdd/changes/{ID}/proposal.md\\` 실행\r\n- [ ] 델타 형식 확인 (ADDED/MODIFIED/REMOVED)\r\n- [ ] 영향받는 스펙 목록 확인\r\n`;\r\n\r\n/**\r\n * /sdd:apply 프롬프트\r\n */\r\nexport const APPLY_PROMPT = `# /sdd:apply - 변경 적용\r\n\r\n> 승인된 변경 제안을 스펙에 적용합니다.\r\n\r\n---\r\n\r\n## 적용 전 체크리스트\r\n\r\n- [ ] proposal.md 상태가 approved인지 확인\r\n- [ ] delta.md가 존재하는지 확인\r\n- [ ] 영향받는 모든 스펙 파일 확인\r\n\r\n---\r\n\r\n## 적용 프로세스\r\n\r\n1. delta.md에서 변경 내용 추출\r\n2. 영향받는 스펙 파일 수정\r\n - ADDED: 새 섹션 추가\r\n - MODIFIED: 기존 섹션 수정\r\n - REMOVED: 해당 섹션 삭제\r\n3. 스펙 파일 검증\r\n\r\n---\r\n\r\n## 적용 후 확인\r\n\r\n- [ ] \\`sdd validate\\` 실행하여 모든 스펙 검증\r\n- [ ] 변경된 스펙 파일 목록 확인\r\n- [ ] 다음 단계: \\`/sdd:archive\\` 실행\r\n`;\r\n\r\n/**\r\n * /sdd:archive 프롬프트\r\n */\r\nexport const ARCHIVE_PROMPT = `# /sdd:archive - 변경 아카이브\r\n\r\n> 완료된 변경 제안을 아카이브합니다.\r\n\r\n---\r\n\r\n## 아카이브 전 체크리스트\r\n\r\n- [ ] 변경이 스펙에 적용되었는지 확인\r\n- [ ] 모든 테스트가 통과하는지 확인\r\n- [ ] 스펙 검증 통과 확인\r\n\r\n---\r\n\r\n## 아카이브 프로세스\r\n\r\n1. .sdd/changes/{ID}/ 디렉토리를 .sdd/archive/로 이동\r\n2. 아카이브 날짜를 파일명에 추가: {YYYY-MM-DD}-{ID}/\r\n3. proposal.md 상태를 archived로 변경\r\n\r\n---\r\n\r\n## 아카이브 후 확인\r\n\r\n- [ ] .sdd/changes/{ID}/ 디렉토리가 삭제됨\r\n- [ ] .sdd/archive/{DATE}-{ID}/ 디렉토리가 생성됨\r\n- [ ] 아카이브된 proposal.md 상태 확인\r\n`;\r\n\r\n/**\r\n * /sdd:impact 프롬프트\r\n */\r\nexport const IMPACT_PROMPT = `# /sdd:impact - 영향도 분석\r\n\r\n> 스펙 변경 시 관련 스펙 및 코드에 미치는 영향을 분석합니다.\r\n\r\n---\r\n\r\n## 분석 전 체크리스트\r\n\r\n- [ ] 변경할 스펙 식별됨\r\n- [ ] 변경 범위 파악됨\r\n\r\n---\r\n\r\n## 분석 프로세스\r\n\r\n1. 대상 스펙의 의존성 그래프 구축\r\n2. 이 스펙에 의존하는 다른 스펙 식별\r\n3. 영향도 수준 평가 (높음/중간/낮음)\r\n4. 리스크 점수 산출 (1-10)\r\n\r\n---\r\n\r\n## CLI 사용법\r\n\r\n\\`\\`\\`bash\r\n# 특정 기능 영향도 분석\r\nsdd impact <feature-name>\r\n\r\n# 의존성 그래프 출력 (Mermaid)\r\nsdd impact --graph\r\n\r\n# JSON 형식 출력\r\nsdd impact <feature-name> --json\r\n\\`\\`\\`\r\n\r\n---\r\n\r\n## 영향 수준 기준\r\n\r\n| 수준 | 기준 | 표시 |\r\n|------|------|------|\r\n| 높음 | 직접 의존, API 변경 | 🔴 HIGH |\r\n| 중간 | 간접 의존, 데이터 공유 | 🟡 MEDIUM |\r\n| 낮음 | UI 컴포넌트 공유 | 🟢 LOW |\r\n\r\n---\r\n\r\n## 리스크 점수 해석\r\n\r\n- 1-3: 낮은 리스크 - 바로 진행 가능\r\n- 4-6: 중간 리스크 - 검토 권장\r\n- 7-10: 높은 리스크 - 신중한 검토 필요\r\n\r\n---\r\n\r\n## 분석 후 조치\r\n\r\n- 높은 리스크: 관련 팀과 공유, 단계적 마이그레이션 검토\r\n- 중간 리스크: 영향 스펙 테스트 확인\r\n- 낮은 리스크: 표준 프로세스 진행\r\n`;\r\n\r\n/**\r\n * /sdd:new 프롬프트\r\n */\r\nexport const NEW_PROMPT = `# /sdd:new - 신규 기능 명세\r\n\r\n> 새로운 기능의 명세를 작성합니다.\r\n\r\n${FORMAT_GUIDE}\r\n\r\n---\r\n\r\n## 생성 전 체크리스트\r\n\r\n- [ ] 기능 요구사항이 명확히 정의됨\r\n- [ ] 사용자 스토리가 작성됨\r\n- [ ] 관련 이해관계자와 논의 완료\r\n- [ ] 기존 기능과의 충돌 여부 확인\r\n\r\n---\r\n\r\n## 생성할 파일\r\n\r\n### 1. spec.md\r\n\r\n\\`\\`\\`markdown\r\n---\r\nid: {FEATURE_ID}\r\ntitle: \"{TITLE}\"\r\nstatus: draft\r\ncreated: {TODAY}\r\ndepends: null\r\n---\r\n\r\n# {TITLE}\r\n\r\n> {DESCRIPTION}\r\n\r\n---\r\n\r\n## 개요\r\n\r\n{DESCRIPTION}\r\n\r\n---\r\n\r\n## 요구사항\r\n\r\n### REQ-01: [요구사항 제목]\r\n\r\n[요구사항 상세 설명]\r\n- 시스템은 [기능]을 지원해야 한다(SHALL)\r\n\r\n---\r\n\r\n## 시나리오\r\n\r\n### Scenario 1: [시나리오명]\r\n\r\n- **GIVEN** [전제 조건]\r\n- **WHEN** [행동/트리거]\r\n- **THEN** [예상 결과]\r\n\r\n---\r\n\r\n## 비기능 요구사항\r\n\r\n### 성능\r\n- 응답 시간: [N]ms 이내 (SHOULD)\r\n\r\n### 보안\r\n- [보안 요구사항] (SHALL)\r\n\\`\\`\\`\r\n\r\n---\r\n\r\n## CLI 사용법\r\n\r\n\\`\\`\\`bash\r\n# 기본 사용\r\nsdd new <feature-name>\r\n\r\n# 옵션 지정\r\nsdd new <feature-name> --title \"제목\" --description \"설명\"\r\n\r\n# 계획 및 작업도 함께 생성\r\nsdd new <feature-name> --all\r\n\r\n# 브랜치 생성 안 함\r\nsdd new <feature-name> --no-branch\r\n\\`\\`\\`\r\n\r\n---\r\n\r\n## 생성 후 확인\r\n\r\n- [ ] \\`sdd validate .sdd/specs/{FEATURE_ID}/spec.md\\` 실행\r\n- [ ] RFC 2119 키워드 사용 확인\r\n- [ ] GIVEN-WHEN-THEN 시나리오 포함 확인\r\n- [ ] 다음 단계: \\`/sdd:plan\\` 실행\r\n`;\r\n\r\n/**\r\n * /sdd:plan 프롬프트\r\n */\r\nexport const PLAN_PROMPT = `# /sdd:plan - 구현 계획\r\n\r\n> 기능 명세에 대한 구현 계획을 작성합니다.\r\n\r\n---\r\n\r\n## 생성 전 체크리스트\r\n\r\n- [ ] 명세(spec.md)가 검토 완료됨\r\n- [ ] 기술 스택 결정됨\r\n- [ ] 아키텍처 검토 완료\r\n- [ ] 의존성 확인\r\n\r\n---\r\n\r\n## 생성할 파일\r\n\r\n### 1. plan.md\r\n\r\n\\`\\`\\`markdown\r\n---\r\nfeature: {FEATURE_ID}\r\ncreated: {TODAY}\r\nstatus: draft\r\n---\r\n\r\n# 구현 계획: {TITLE}\r\n\r\n> {OVERVIEW}\r\n\r\n---\r\n\r\n## 기술 결정\r\n\r\n### 결정 1: [기술 결정 사항]\r\n\r\n**근거:** [결정 근거]\r\n\r\n**대안 검토:**\r\n- [대안 1]\r\n- [대안 2]\r\n\r\n---\r\n\r\n## 구현 단계\r\n\r\n### Phase 1: 기반 구조\r\n\r\n[기반 구조 설명]\r\n\r\n**산출물:**\r\n- [ ] [산출물 1]\r\n- [ ] [산출물 2]\r\n\r\n### Phase 2: 핵심 기능\r\n\r\n[핵심 기능 설명]\r\n\r\n**산출물:**\r\n- [ ] [산출물 1]\r\n\r\n---\r\n\r\n## 리스크 분석\r\n\r\n| 리스크 | 영향도 | 완화 전략 |\r\n|--------|--------|----------|\r\n| [리스크] | 🟡 MEDIUM | [전략] |\r\n\r\n---\r\n\r\n## 테스트 전략\r\n\r\n- 단위 테스트: 커버리지 80% 이상\r\n- 통합 테스트: API 엔드포인트\r\n- E2E 테스트: 주요 시나리오\r\n\\`\\`\\`\r\n\r\n---\r\n\r\n## CLI 사용법\r\n\r\n\\`\\`\\`bash\r\n# 계획 생성\r\nsdd new plan <feature-id>\r\n\r\n# 제목 지정\r\nsdd new plan <feature-id> --title \"구현 계획\"\r\n\\`\\`\\`\r\n\r\n---\r\n\r\n## 생성 후 확인\r\n\r\n- [ ] 기술 결정 근거 확인\r\n- [ ] 구현 단계 정의\r\n- [ ] 리스크 분석 완료\r\n- [ ] 다음 단계: \\`/sdd:tasks\\` 실행\r\n`;\r\n\r\n/**\r\n * /sdd:tasks 프롬프트\r\n */\r\nexport const TASKS_PROMPT = `# /sdd:tasks - 작업 분해\r\n\r\n> 구현 계획을 실행 가능한 작업으로 분해합니다.\r\n\r\n---\r\n\r\n## 생성 전 체크리스트\r\n\r\n- [ ] 계획(plan.md)이 승인됨\r\n- [ ] 작업 규모가 파악됨\r\n- [ ] 의존성 관계 정의됨\r\n\r\n---\r\n\r\n## 생성할 파일\r\n\r\n### 1. tasks.md\r\n\r\n\\`\\`\\`markdown\r\n---\r\nfeature: {FEATURE_ID}\r\ncreated: {TODAY}\r\ntotal: {N}\r\ncompleted: 0\r\n---\r\n\r\n# 작업 목록: {TITLE}\r\n\r\n> 총 {N}개 작업\r\n\r\n---\r\n\r\n## 진행 상황\r\n\r\n- 대기: {N}\r\n- 진행 중: 0\r\n- 완료: 0\r\n- 차단됨: 0\r\n\r\n---\r\n\r\n## 작업 목록\r\n\r\n### {FEATURE_ID}-task-001: [작업 제목]\r\n\r\n- **상태:** 대기\r\n- **우선순위:** 🔴 HIGH\r\n- **설명:** [작업 설명]\r\n- **관련 파일:**\r\n - \\`src/path/to/file.ts\\`\r\n- **의존성:** 없음\r\n\r\n### {FEATURE_ID}-task-002: [작업 제목]\r\n\r\n- **상태:** 대기\r\n- **우선순위:** 🟡 MEDIUM\r\n- **의존성:** {FEATURE_ID}-task-001\r\n\\`\\`\\`\r\n\r\n---\r\n\r\n## CLI 사용법\r\n\r\n\\`\\`\\`bash\r\n# 작업 분해 생성\r\nsdd new tasks <feature-id>\r\n\\`\\`\\`\r\n\r\n---\r\n\r\n## 작업 완료 조건\r\n\r\n각 작업 완료 시:\r\n1. [ ] 코드 작성 완료\r\n2. [ ] 테스트 작성 및 통과\r\n3. [ ] 코드 리뷰 완료\r\n4. [ ] 문서 업데이트\r\n\r\n---\r\n\r\n## 다음 단계\r\n\r\n1. 첫 번째 작업부터 순차적으로 진행\r\n2. 각 작업 완료 후 상태 업데이트\r\n3. 모든 작업 완료 시 \\`/sdd:archive\\` 실행\r\n`;\r\n\r\n/**\r\n * /sdd:validate 프롬프트\r\n */\r\nexport const VALIDATE_PROMPT = `# /sdd:validate - 스펙 검증\r\n\r\n> 스펙 파일의 형식과 내용을 검증합니다.\r\n\r\n---\r\n\r\n## 검증 대상\r\n\r\n- .sdd/specs/ 디렉토리의 모든 스펙 파일\r\n- .sdd/changes/ 디렉토리의 모든 변경 제안\r\n\r\n---\r\n\r\n## 검증 항목\r\n\r\n### 필수 형식\r\n\r\n1. YAML frontmatter 존재\r\n - status: draft | active | deprecated\r\n - created: YYYY-MM-DD\r\n - depends: null | [spec-id, ...]\r\n\r\n2. RFC 2119 키워드 사용\r\n - SHALL, MUST, SHOULD, MAY, SHALL NOT\r\n\r\n3. GIVEN-WHEN-THEN 시나리오\r\n - 모든 Requirement에 최소 1개 Scenario\r\n\r\n---\r\n\r\n## CLI 사용법\r\n\r\n\\`\\`\\`bash\r\n# 전체 검증\r\nsdd validate\r\n\r\n# 특정 경로 검증\r\nsdd validate .sdd/specs/feature/spec.md\r\n\r\n# 엄격 모드 (경고도 에러로 처리)\r\nsdd validate --strict\r\n\r\n# 조용한 모드\r\nsdd validate --quiet\r\n\\`\\`\\`\r\n\r\n---\r\n\r\n## 검증 결과\r\n\r\n- ✅ PASS: 모든 검증 통과\r\n- ⚠️ WARN: 경고 (--strict에서 실패)\r\n- ❌ FAIL: 필수 항목 누락\r\n`;\r\n\r\n/**\r\n * 모든 프롬프트 맵\r\n */\r\nexport const PROMPTS: Record<string, string> = {\r\n change: CHANGE_PROMPT,\r\n apply: APPLY_PROMPT,\r\n archive: ARCHIVE_PROMPT,\r\n impact: IMPACT_PROMPT,\r\n validate: VALIDATE_PROMPT,\r\n new: NEW_PROMPT,\r\n plan: PLAN_PROMPT,\r\n tasks: TASKS_PROMPT,\r\n};\r\n\r\n/**\r\n * 프롬프트 가져오기\r\n */\r\nexport function getPrompt(command: string): string | undefined {\r\n return PROMPTS[command];\r\n}\r\n\r\n/**\r\n * 사용 가능한 명령어 목록\r\n */\r\nexport function getAvailableCommands(): string[] {\r\n return Object.keys(PROMPTS);\r\n}\r\n","/**\r\n * sdd prompt 명령어\r\n *\r\n * AI 코딩 도구용 슬래시 커맨드 프롬프트를 출력합니다.\r\n */\r\nimport { Command } from 'commander';\r\nimport { getPrompt, getAvailableCommands } from '../../prompts/index.js';\r\nimport * as logger from '../../utils/logger.js';\r\nimport { ExitCode } from '../../errors/index.js';\r\n\r\n/**\r\n * prompt 명령어 등록\r\n */\r\nexport function registerPromptCommand(program: Command): void {\r\n program\r\n .command('prompt [command]')\r\n .description('슬래시 커맨드 프롬프트를 출력합니다')\r\n .option('-l, --list', '사용 가능한 명령어 목록')\r\n .action(async (command: string | undefined, options: { list?: boolean }) => {\r\n try {\r\n await runPrompt(command, options);\r\n } catch (error) {\r\n logger.error(error instanceof Error ? error.message : String(error));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n });\r\n}\r\n\r\n/**\r\n * 프롬프트 실행\r\n */\r\nasync function runPrompt(\r\n command: string | undefined,\r\n options: { list?: boolean }\r\n): Promise<void> {\r\n // 목록 출력\r\n if (options.list || !command) {\r\n const commands = getAvailableCommands();\r\n logger.info('사용 가능한 슬래시 커맨드:');\r\n logger.newline();\r\n for (const cmd of commands) {\r\n logger.listItem(`/sdd:${cmd}`);\r\n }\r\n logger.newline();\r\n logger.info('사용법: sdd prompt <command>');\r\n logger.info('예시: sdd prompt change');\r\n return;\r\n }\r\n\r\n // 프롬프트 출력\r\n const prompt = getPrompt(command);\r\n if (!prompt) {\r\n logger.error(`알 수 없는 명령어: ${command}`);\r\n logger.info('사용 가능한 명령어: ' + getAvailableCommands().join(', '));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n // 프롬프트 출력 (마크다운)\r\n console.log(prompt);\r\n}\r\n","/**\r\n * sdd change 명령어\r\n *\r\n * 변경 제안 워크플로우를 관리합니다.\r\n */\r\nimport { Command } from 'commander';\r\nimport path from 'node:path';\r\nimport { promises as fs } from 'node:fs';\r\nimport {\r\n generateProposal,\r\n generateDelta,\r\n parseProposal,\r\n parseDelta,\r\n validateDelta,\r\n updateProposalStatus,\r\n listPendingChanges,\r\n archiveChange,\r\n generateChangeId,\r\n} from '../../core/change/index.js';\r\nimport { findSddRoot, directoryExists, ensureDir, writeFile, readFile, fileExists } from '../../utils/fs.js';\r\nimport * as logger from '../../utils/logger.js';\r\nimport { ExitCode } from '../../errors/index.js';\r\n\r\n/**\r\n * change 명령어 등록\r\n */\r\nexport function registerChangeCommand(program: Command): void {\r\n const change = program\r\n .command('change [id]')\r\n .description('변경 제안을 생성하거나 관리합니다')\r\n .option('-l, --list', '진행 중인 변경 목록')\r\n .option('-t, --title <title>', '변경 제안 제목')\r\n .option('-s, --spec <spec>', '대상 스펙 경로')\r\n .action(async (id: string | undefined, options: {\r\n list?: boolean;\r\n title?: string;\r\n spec?: string;\r\n }) => {\r\n try {\r\n await runChange(id, options);\r\n } catch (error) {\r\n logger.error(error instanceof Error ? error.message : String(error));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n });\r\n\r\n // apply 서브커맨드\r\n change\r\n .command('apply <id>')\r\n .description('변경 제안을 스펙에 적용합니다')\r\n .action(async (id: string) => {\r\n try {\r\n await runApply(id);\r\n } catch (error) {\r\n logger.error(error instanceof Error ? error.message : String(error));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n });\r\n\r\n // archive 서브커맨드\r\n change\r\n .command('archive <id>')\r\n .description('완료된 변경을 아카이브합니다')\r\n .action(async (id: string) => {\r\n try {\r\n await runArchive(id);\r\n } catch (error) {\r\n logger.error(error instanceof Error ? error.message : String(error));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n });\r\n\r\n // diff 서브커맨드\r\n change\r\n .command('diff <id>')\r\n .description('변경 제안의 diff를 표시합니다')\r\n .action(async (id: string) => {\r\n try {\r\n await runDiff(id);\r\n } catch (error) {\r\n logger.error(error instanceof Error ? error.message : String(error));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n });\r\n\r\n // validate 서브커맨드\r\n change\r\n .command('validate <id>')\r\n .description('변경 제안의 유효성을 검증합니다')\r\n .action(async (id: string) => {\r\n try {\r\n await runValidateChange(id);\r\n } catch (error) {\r\n logger.error(error instanceof Error ? error.message : String(error));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n });\r\n}\r\n\r\n/**\r\n * 변경 제안 생성/조회\r\n */\r\nasync function runChange(\r\n id: string | undefined,\r\n options: { list?: boolean; title?: string; spec?: string }\r\n): Promise<void> {\r\n const projectRoot = await findSddRoot();\r\n if (!projectRoot) {\r\n logger.error('SDD 프로젝트를 찾을 수 없습니다. `sdd init`을 먼저 실행하세요.');\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n const sddPath = path.join(projectRoot, '.sdd');\r\n\r\n // 목록 출력\r\n if (options.list) {\r\n const result = await listPendingChanges(sddPath);\r\n if (!result.success) {\r\n logger.error(result.error.message);\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n if (result.data.length === 0) {\r\n logger.info('진행 중인 변경이 없습니다.');\r\n return;\r\n }\r\n\r\n logger.info('진행 중인 변경:');\r\n logger.newline();\r\n for (const change of result.data) {\r\n const statusIcon = change.status === 'approved' ? '✓' : '○';\r\n logger.listItem(`${statusIcon} ${change.id}: ${change.title || '(제목 없음)'} [${change.status}]`);\r\n }\r\n return;\r\n }\r\n\r\n // 기존 변경 조회\r\n if (id) {\r\n const changePath = path.join(sddPath, 'changes', id);\r\n if (!(await directoryExists(changePath))) {\r\n logger.error(`변경을 찾을 수 없습니다: ${id}`);\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n const proposalPath = path.join(changePath, 'proposal.md');\r\n try {\r\n const content = await fs.readFile(proposalPath, 'utf-8');\r\n const parseResult = parseProposal(content);\r\n if (parseResult.success) {\r\n logger.info(`변경 제안: ${parseResult.data.title}`);\r\n logger.info(`상태: ${parseResult.data.metadata.status}`);\r\n logger.info(`생성: ${parseResult.data.metadata.created}`);\r\n if (parseResult.data.affectedSpecs.length > 0) {\r\n logger.info('영향 스펙:');\r\n parseResult.data.affectedSpecs.forEach((spec) => logger.listItem(spec, 1));\r\n }\r\n }\r\n } catch {\r\n logger.error('proposal.md를 읽을 수 없습니다.');\r\n }\r\n return;\r\n }\r\n\r\n // 새 변경 생성\r\n const changesPath = path.join(sddPath, 'changes');\r\n await ensureDir(changesPath);\r\n\r\n // 기존 ID 수집\r\n const existingIds: string[] = [];\r\n try {\r\n const dirs = await fs.readdir(changesPath);\r\n existingIds.push(...dirs.filter((d) => d.startsWith('CHG-')));\r\n } catch {\r\n // 디렉토리가 없을 수 있음\r\n }\r\n\r\n const newId = generateChangeId(existingIds);\r\n const title = options.title || '새 변경 제안';\r\n const affectedSpecs = options.spec ? [options.spec] : [];\r\n\r\n const changePath = path.join(changesPath, newId);\r\n await ensureDir(changePath);\r\n\r\n // proposal.md 생성\r\n const proposal = generateProposal({\r\n id: newId,\r\n title,\r\n affectedSpecs,\r\n });\r\n await writeFile(path.join(changePath, 'proposal.md'), proposal);\r\n\r\n // delta.md 생성\r\n const delta = generateDelta({\r\n proposalId: newId,\r\n title,\r\n });\r\n await writeFile(path.join(changePath, 'delta.md'), delta);\r\n\r\n logger.success(`변경 제안이 생성되었습니다: ${newId}`);\r\n logger.newline();\r\n logger.info('생성된 파일:');\r\n logger.listItem(`.sdd/changes/${newId}/proposal.md`);\r\n logger.listItem(`.sdd/changes/${newId}/delta.md`);\r\n logger.newline();\r\n logger.info('다음 단계:');\r\n logger.listItem('proposal.md를 수정하여 변경 내용을 작성하세요');\r\n logger.listItem('delta.md에 ADDED/MODIFIED/REMOVED를 작성하세요');\r\n logger.listItem(`\\`sdd change apply ${newId}\\`로 적용하세요`);\r\n}\r\n\r\n/**\r\n * 변경 적용\r\n */\r\nasync function runApply(id: string): Promise<void> {\r\n const projectRoot = await findSddRoot();\r\n if (!projectRoot) {\r\n logger.error('SDD 프로젝트를 찾을 수 없습니다.');\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n const sddPath = path.join(projectRoot, '.sdd');\r\n const changePath = path.join(sddPath, 'changes', id);\r\n\r\n if (!(await directoryExists(changePath))) {\r\n logger.error(`변경을 찾을 수 없습니다: ${id}`);\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n // proposal.md 상태 업데이트\r\n const proposalPath = path.join(changePath, 'proposal.md');\r\n try {\r\n const content = await fs.readFile(proposalPath, 'utf-8');\r\n const updateResult = updateProposalStatus(content, 'applied');\r\n if (updateResult.success) {\r\n await fs.writeFile(proposalPath, updateResult.data);\r\n }\r\n } catch {\r\n logger.error('proposal.md를 업데이트할 수 없습니다.');\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n logger.success(`변경이 적용 상태로 변경되었습니다: ${id}`);\r\n logger.newline();\r\n logger.info('다음 단계:');\r\n logger.listItem('delta.md를 참조하여 스펙을 수정하세요');\r\n logger.listItem('구현이 완료되면 `sdd change archive ${id}`를 실행하세요');\r\n}\r\n\r\n/**\r\n * 변경 아카이브\r\n */\r\nasync function runArchive(id: string): Promise<void> {\r\n const projectRoot = await findSddRoot();\r\n if (!projectRoot) {\r\n logger.error('SDD 프로젝트를 찾을 수 없습니다.');\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n const sddPath = path.join(projectRoot, '.sdd');\r\n const result = await archiveChange(sddPath, id);\r\n\r\n if (!result.success) {\r\n logger.error(result.error.message);\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n logger.success(`변경이 아카이브되었습니다: ${id}`);\r\n logger.info(`위치: ${result.data.archiveDir}`);\r\n}\r\n\r\n/**\r\n * 변경 diff 표시\r\n */\r\nasync function runDiff(id: string): Promise<void> {\r\n const projectRoot = await findSddRoot();\r\n if (!projectRoot) {\r\n logger.error('SDD 프로젝트를 찾을 수 없습니다.');\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n const sddPath = path.join(projectRoot, '.sdd');\r\n const changePath = path.join(sddPath, 'changes', id);\r\n\r\n if (!(await directoryExists(changePath))) {\r\n logger.error(`변경을 찾을 수 없습니다: ${id}`);\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n const deltaPath = path.join(changePath, 'delta.md');\r\n if (!(await fileExists(deltaPath))) {\r\n logger.error('delta.md를 찾을 수 없습니다.');\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n const deltaResult = await readFile(deltaPath);\r\n if (!deltaResult.success) {\r\n logger.error('delta.md를 읽을 수 없습니다.');\r\n process.exit(ExitCode.FILE_SYSTEM_ERROR);\r\n }\r\n\r\n const parseResult = parseDelta(deltaResult.data);\r\n if (!parseResult.success) {\r\n logger.error(`Delta 파싱 실패: ${parseResult.error.message}`);\r\n process.exit(ExitCode.VALIDATION_ERROR);\r\n }\r\n\r\n const delta = parseResult.data;\r\n\r\n logger.info(`변경 Diff: ${id}`);\r\n logger.newline();\r\n\r\n // ADDED\r\n if (delta.added.length > 0 && delta.added[0].content !== '(추가되는 스펙 내용)') {\r\n logger.info('📗 ADDED:');\r\n for (const item of delta.added) {\r\n console.log(` + ${item.content.split('\\n')[0]}...`);\r\n }\r\n logger.newline();\r\n }\r\n\r\n // MODIFIED\r\n if (delta.modified.length > 0) {\r\n logger.info('📘 MODIFIED:');\r\n for (const item of delta.modified) {\r\n if (item.before && item.after) {\r\n logger.info(' Before:');\r\n for (const line of item.before.split('\\n').slice(0, 3)) {\r\n console.log(` - ${line}`);\r\n }\r\n logger.info(' After:');\r\n for (const line of item.after.split('\\n').slice(0, 3)) {\r\n console.log(` + ${line}`);\r\n }\r\n } else {\r\n console.log(` ~ ${item.content.split('\\n')[0]}...`);\r\n }\r\n }\r\n logger.newline();\r\n }\r\n\r\n // REMOVED\r\n if (delta.removed.length > 0 && delta.removed[0].content !== '(삭제되는 스펙 참조)') {\r\n logger.info('📕 REMOVED:');\r\n for (const item of delta.removed) {\r\n console.log(` - ${item.content.split('\\n')[0]}...`);\r\n }\r\n logger.newline();\r\n }\r\n}\r\n\r\n/**\r\n * 변경 제안 유효성 검증\r\n */\r\nasync function runValidateChange(id: string): Promise<void> {\r\n const projectRoot = await findSddRoot();\r\n if (!projectRoot) {\r\n logger.error('SDD 프로젝트를 찾을 수 없습니다.');\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n const sddPath = path.join(projectRoot, '.sdd');\r\n const changePath = path.join(sddPath, 'changes', id);\r\n\r\n if (!(await directoryExists(changePath))) {\r\n logger.error(`변경을 찾을 수 없습니다: ${id}`);\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n let hasErrors = false;\r\n\r\n // Proposal 검증\r\n const proposalPath = path.join(changePath, 'proposal.md');\r\n if (await fileExists(proposalPath)) {\r\n const proposalResult = await readFile(proposalPath);\r\n if (proposalResult.success) {\r\n const parsed = parseProposal(proposalResult.data);\r\n if (parsed.success) {\r\n logger.success(`✓ proposal.md 유효 (${parsed.data.title})`);\r\n } else {\r\n logger.error(`✗ proposal.md 오류: ${parsed.error.message}`);\r\n hasErrors = true;\r\n }\r\n }\r\n } else {\r\n logger.error('✗ proposal.md가 없습니다.');\r\n hasErrors = true;\r\n }\r\n\r\n // Delta 검증\r\n const deltaPath = path.join(changePath, 'delta.md');\r\n if (await fileExists(deltaPath)) {\r\n const deltaResult = await readFile(deltaPath);\r\n if (deltaResult.success) {\r\n const validation = validateDelta(deltaResult.data);\r\n if (validation.valid) {\r\n const types = [];\r\n if (validation.hasAdded) types.push('ADDED');\r\n if (validation.hasModified) types.push('MODIFIED');\r\n if (validation.hasRemoved) types.push('REMOVED');\r\n logger.success(`✓ delta.md 유효 (${types.join(', ')})`);\r\n\r\n for (const warning of validation.warnings) {\r\n logger.warn(` ⚠ ${warning}`);\r\n }\r\n } else {\r\n logger.error(`✗ delta.md 오류:`);\r\n for (const error of validation.errors) {\r\n logger.error(` - ${error}`);\r\n }\r\n hasErrors = true;\r\n }\r\n }\r\n } else {\r\n logger.warn('⚠ delta.md가 없습니다.');\r\n }\r\n\r\n logger.newline();\r\n if (hasErrors) {\r\n logger.error(`검증 실패: ${id}`);\r\n process.exit(ExitCode.VALIDATION_ERROR);\r\n } else {\r\n logger.success(`검증 통과: ${id}`);\r\n }\r\n}\r\n","/**\r\n * 변경 제안 스키마\r\n */\r\nimport { z } from 'zod';\r\n\r\n/**\r\n * 변경 상태\r\n */\r\nexport const ChangeStatusSchema = z.enum([\r\n 'draft',\r\n 'proposed',\r\n 'approved',\r\n 'applied',\r\n 'archived',\r\n 'rejected',\r\n]);\r\n\r\nexport type ChangeStatus = z.infer<typeof ChangeStatusSchema>;\r\n\r\n/**\r\n * 변경 유형\r\n */\r\nexport const DeltaTypeSchema = z.enum(['ADDED', 'MODIFIED', 'REMOVED']);\r\n\r\nexport type DeltaType = z.infer<typeof DeltaTypeSchema>;\r\n\r\n/**\r\n * 영향도 수준\r\n */\r\nexport const ImpactLevelSchema = z.enum(['low', 'medium', 'high']);\r\n\r\nexport type ImpactLevel = z.infer<typeof ImpactLevelSchema>;\r\n\r\n/**\r\n * Proposal 메타데이터 스키마\r\n */\r\nexport const ProposalMetadataSchema = z.object({\r\n id: z.string().regex(/^CHG-\\d{3,}$/, 'ID 형식: CHG-XXX'),\r\n status: ChangeStatusSchema,\r\n created: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/, '날짜 형식: YYYY-MM-DD'),\r\n updated: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/).optional(),\r\n target: z.string().optional(),\r\n});\r\n\r\nexport type ProposalMetadata = z.infer<typeof ProposalMetadataSchema>;\r\n\r\n/**\r\n * 델타 항목 스키마\r\n */\r\nexport const DeltaItemSchema = z.object({\r\n type: DeltaTypeSchema,\r\n target: z.string(),\r\n before: z.string().optional(),\r\n after: z.string().optional(),\r\n description: z.string().optional(),\r\n});\r\n\r\nexport type DeltaItem = z.infer<typeof DeltaItemSchema>;\r\n\r\n/**\r\n * 델타 메타데이터 스키마\r\n */\r\nexport const DeltaMetadataSchema = z.object({\r\n proposal: z.string(),\r\n created: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/),\r\n});\r\n\r\nexport type DeltaMetadata = z.infer<typeof DeltaMetadataSchema>;\r\n\r\n/**\r\n * 변경 제안 전체 스키마\r\n */\r\nexport const ProposalSchema = z.object({\r\n metadata: ProposalMetadataSchema,\r\n title: z.string(),\r\n rationale: z.string().optional(),\r\n affectedSpecs: z.array(z.string()),\r\n changeType: z.array(DeltaTypeSchema),\r\n summary: z.string().optional(),\r\n riskLevel: ImpactLevelSchema.optional(),\r\n complexity: ImpactLevelSchema.optional(),\r\n});\r\n\r\nexport type Proposal = z.infer<typeof ProposalSchema>;\r\n\r\n/**\r\n * 델타 전체 스키마\r\n */\r\nexport const DeltaSchema = z.object({\r\n metadata: DeltaMetadataSchema,\r\n title: z.string(),\r\n added: z.array(z.string()).optional(),\r\n modified: z.array(\r\n z.object({\r\n target: z.string(),\r\n before: z.string(),\r\n after: z.string(),\r\n })\r\n ).optional(),\r\n removed: z.array(z.string()).optional(),\r\n});\r\n\r\nexport type Delta = z.infer<typeof DeltaSchema>;\r\n\r\n/**\r\n * 다음 변경 ID 생성\r\n */\r\nexport function generateChangeId(existingIds: string[]): string {\r\n const maxId = existingIds\r\n .map((id) => {\r\n const match = id.match(/^CHG-(\\d+)$/);\r\n return match ? parseInt(match[1], 10) : 0;\r\n })\r\n .reduce((max, curr) => Math.max(max, curr), 0);\r\n\r\n return `CHG-${String(maxId + 1).padStart(3, '0')}`;\r\n}\r\n","/**\r\n * Proposal 파서 및 생성기\r\n */\r\nimport matter from 'gray-matter';\r\nimport { z } from 'zod';\r\nimport {\r\n ProposalMetadataSchema,\r\n Proposal,\r\n ChangeStatus,\r\n DeltaType,\r\n ImpactLevel,\r\n generateChangeId,\r\n} from './schemas.js';\r\nimport { success, failure, Result } from '../../types/index.js';\r\nimport { ChangeError } from '../../errors/index.js';\r\n\r\n/**\r\n * Proposal 파싱 결과\r\n */\r\nexport interface ParsedProposal {\r\n metadata: {\r\n id: string;\r\n status: ChangeStatus;\r\n created: string;\r\n updated?: string;\r\n target?: string;\r\n };\r\n title: string;\r\n rationale: string;\r\n affectedSpecs: string[];\r\n changeType: DeltaType[];\r\n summary: string;\r\n riskLevel: ImpactLevel;\r\n complexity: ImpactLevel;\r\n rawContent: string;\r\n}\r\n\r\n/**\r\n * Proposal 메타데이터 전처리\r\n */\r\nconst PreprocessedProposalMetadataSchema = z.object({\r\n id: z.string().regex(/^CHG-\\d{3,}$/, 'ID 형식: CHG-XXX'),\r\n status: z.preprocess(\r\n (val) => (typeof val === 'string' ? val : 'draft'),\r\n z.enum(['draft', 'proposed', 'approved', 'applied', 'archived', 'rejected'])\r\n ),\r\n created: z.preprocess(\r\n (val) => {\r\n if (val instanceof Date) {\r\n return val.toISOString().split('T')[0];\r\n }\r\n return val;\r\n },\r\n z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/, '날짜 형식: YYYY-MM-DD')\r\n ),\r\n updated: z.preprocess(\r\n (val) => {\r\n if (val instanceof Date) {\r\n return val.toISOString().split('T')[0];\r\n }\r\n return val;\r\n },\r\n z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/).optional()\r\n ),\r\n target: z.string().optional(),\r\n});\r\n\r\n/**\r\n * Proposal 파싱\r\n */\r\nexport function parseProposal(content: string): Result<ParsedProposal, ChangeError> {\r\n try {\r\n const { data: frontmatter, content: body } = matter(content);\r\n\r\n // 메타데이터 검증\r\n const metadataResult = PreprocessedProposalMetadataSchema.safeParse(frontmatter);\r\n if (!metadataResult.success) {\r\n return failure(\r\n new ChangeError(`Proposal 메타데이터 오류: ${metadataResult.error.message}`)\r\n );\r\n }\r\n\r\n // 제목 추출 (첫 번째 # 헤더)\r\n const titleMatch = body.match(/^#\\s+(?:변경\\s+제안:\\s*)?(.+)$/m);\r\n const title = titleMatch?.[1]?.trim() || '';\r\n\r\n // 배경/이유 추출\r\n const rationaleMatch = body.match(/##\\s*배경\\s*([\\s\\S]*?)(?=\\n##|$)/i);\r\n const rationale = rationaleMatch?.[1]?.trim() || '';\r\n\r\n // 영향받는 스펙 추출\r\n const specsMatch = body.match(/##\\s*영향\\s*범위[\\s\\S]*?영향받는\\s*스펙\\s*([\\s\\S]*?)(?=\\n###|\\n##|$)/i);\r\n const affectedSpecs: string[] = [];\r\n if (specsMatch) {\r\n const specLines = specsMatch[1].match(/`([^`]+)`/g);\r\n if (specLines) {\r\n specLines.forEach((line) => {\r\n affectedSpecs.push(line.replace(/`/g, ''));\r\n });\r\n }\r\n }\r\n\r\n // 변경 유형 추출\r\n const changeType: DeltaType[] = [];\r\n if (body.includes('[x] 신규 추가') || body.includes('[X] 신규 추가')) {\r\n changeType.push('ADDED');\r\n }\r\n if (body.includes('[x] 수정') || body.includes('[X] 수정')) {\r\n changeType.push('MODIFIED');\r\n }\r\n if (body.includes('[x] 삭제') || body.includes('[X] 삭제')) {\r\n changeType.push('REMOVED');\r\n }\r\n\r\n // 변경 내용 요약 추출\r\n const summaryMatch = body.match(/##\\s*변경\\s*내용\\s*([\\s\\S]*?)(?=\\n##|$)/i);\r\n const summary = summaryMatch?.[1]?.trim() || '';\r\n\r\n // 리스크 평가 추출\r\n const riskMatch = body.match(/영향도:\\s*(낮음|중간|높음)/i);\r\n const riskLevel: ImpactLevel = riskMatch\r\n ? (riskMatch[1] === '낮음' ? 'low' : riskMatch[1] === '높음' ? 'high' : 'medium')\r\n : 'medium';\r\n\r\n const complexityMatch = body.match(/복잡도:\\s*(낮음|중간|높음)/i);\r\n const complexity: ImpactLevel = complexityMatch\r\n ? (complexityMatch[1] === '낮음' ? 'low' : complexityMatch[1] === '높음' ? 'high' : 'medium')\r\n : 'medium';\r\n\r\n return success({\r\n metadata: metadataResult.data,\r\n title,\r\n rationale,\r\n affectedSpecs,\r\n changeType,\r\n summary,\r\n riskLevel,\r\n complexity,\r\n rawContent: body,\r\n });\r\n } catch (error) {\r\n return failure(\r\n new ChangeError(\r\n `Proposal 파싱 실패: ${error instanceof Error ? error.message : String(error)}`\r\n )\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Proposal 생성 옵션\r\n */\r\nexport interface GenerateProposalOptions {\r\n id: string;\r\n title: string;\r\n rationale?: string;\r\n affectedSpecs?: string[];\r\n changeType?: DeltaType[];\r\n}\r\n\r\n/**\r\n * Proposal 템플릿 생성\r\n */\r\nexport function generateProposal(options: GenerateProposalOptions): string {\r\n const today = new Date().toISOString().split('T')[0];\r\n const specs = options.affectedSpecs || [];\r\n const types = options.changeType || ['MODIFIED'];\r\n\r\n return `---\r\nid: ${options.id}\r\nstatus: draft\r\ncreated: ${today}\r\n---\r\n\r\n# 변경 제안: ${options.title}\r\n\r\n> ${options.rationale || '변경 목적 및 배경 설명'}\r\n\r\n---\r\n\r\n## 배경\r\n\r\n${options.rationale || '왜 이 변경이 필요한가?'}\r\n\r\n---\r\n\r\n## 영향 범위\r\n\r\n### 영향받는 스펙\r\n\r\n${specs.length > 0 ? specs.map((s) => `- \\`${s}\\``).join('\\n') : '- `specs/{{SPEC_PATH}}`'}\r\n\r\n### 변경 유형\r\n\r\n- [${types.includes('ADDED') ? 'x' : ' '}] 신규 추가 (ADDED)\r\n- [${types.includes('MODIFIED') ? 'x' : ' '}] 수정 (MODIFIED)\r\n- [${types.includes('REMOVED') ? 'x' : ' '}] 삭제 (REMOVED)\r\n\r\n---\r\n\r\n## 변경 내용\r\n\r\n### ADDED\r\n\r\n(새로 추가되는 내용)\r\n\r\n### MODIFIED\r\n\r\n#### Before\r\n\r\n\\`\\`\\`markdown\r\n기존 내용\r\n\\`\\`\\`\r\n\r\n#### After\r\n\r\n\\`\\`\\`markdown\r\n변경된 내용\r\n\\`\\`\\`\r\n\r\n### REMOVED\r\n\r\n(삭제되는 내용)\r\n\r\n---\r\n\r\n## 리스크 평가\r\n\r\n- 영향도: 중간\r\n- 복잡도: 중간\r\n`;\r\n}\r\n\r\n/**\r\n * Proposal 상태 업데이트\r\n */\r\nexport function updateProposalStatus(\r\n content: string,\r\n newStatus: ChangeStatus\r\n): Result<string, ChangeError> {\r\n try {\r\n const { data: frontmatter, content: body } = matter(content);\r\n const today = new Date().toISOString().split('T')[0];\r\n\r\n const updatedFrontmatter = {\r\n ...frontmatter,\r\n status: newStatus,\r\n updated: today,\r\n };\r\n\r\n return success(matter.stringify(body, updatedFrontmatter));\r\n } catch (error) {\r\n return failure(\r\n new ChangeError(\r\n `상태 업데이트 실패: ${error instanceof Error ? error.message : String(error)}`\r\n )\r\n );\r\n }\r\n}\r\n","/**\r\n * Delta 파서 및 생성기\r\n */\r\nimport matter from 'gray-matter';\r\nimport { z } from 'zod';\r\nimport { DeltaType, DeltaMetadataSchema } from './schemas.js';\r\nimport { success, failure, Result } from '../../types/index.js';\r\nimport { ChangeError } from '../../errors/index.js';\r\n\r\n/**\r\n * 델타 항목\r\n */\r\nexport interface DeltaItem {\r\n type: DeltaType;\r\n content: string;\r\n target?: string;\r\n before?: string;\r\n after?: string;\r\n}\r\n\r\n/**\r\n * 파싱된 델타\r\n */\r\nexport interface ParsedDelta {\r\n metadata: {\r\n proposal: string;\r\n created: string;\r\n };\r\n title: string;\r\n added: DeltaItem[];\r\n modified: DeltaItem[];\r\n removed: DeltaItem[];\r\n rawContent: string;\r\n}\r\n\r\n/**\r\n * 델타 메타데이터 전처리 스키마\r\n */\r\nconst PreprocessedDeltaMetadataSchema = z.object({\r\n proposal: z.string(),\r\n created: z.preprocess(\r\n (val) => {\r\n if (val instanceof Date) {\r\n return val.toISOString().split('T')[0];\r\n }\r\n return val;\r\n },\r\n z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/, '날짜 형식: YYYY-MM-DD')\r\n ),\r\n});\r\n\r\n/**\r\n * Delta 파싱\r\n */\r\nexport function parseDelta(content: string): Result<ParsedDelta, ChangeError> {\r\n try {\r\n const { data: frontmatter, content: body } = matter(content);\r\n\r\n // 메타데이터 검증\r\n const metadataResult = PreprocessedDeltaMetadataSchema.safeParse(frontmatter);\r\n if (!metadataResult.success) {\r\n return failure(\r\n new ChangeError(`Delta 메타데이터 오류: ${metadataResult.error.message}`)\r\n );\r\n }\r\n\r\n // 제목 추출\r\n const titleMatch = body.match(/^#\\s+(?:Delta:\\s*)?(.+)$/m);\r\n const title = titleMatch?.[1]?.trim() || '';\r\n\r\n // ADDED 섹션 추출\r\n const addedMatch = body.match(/##\\s*ADDED\\s*([\\s\\S]*?)(?=\\n##|$)/i);\r\n const added: DeltaItem[] = [];\r\n if (addedMatch && addedMatch[1].trim()) {\r\n added.push({\r\n type: 'ADDED',\r\n content: addedMatch[1].trim(),\r\n });\r\n }\r\n\r\n // MODIFIED 섹션 추출\r\n const modifiedMatch = body.match(/##\\s*MODIFIED\\s*([\\s\\S]*?)(?=\\n##\\s+(?:REMOVED|ADDED)|$)/i);\r\n const modified: DeltaItem[] = [];\r\n if (modifiedMatch) {\r\n const contentTrimmed = modifiedMatch[1].trim();\r\n\r\n // 빈 섹션이나 템플릿만 있는 경우 스킵\r\n if (contentTrimmed.length > 0 &&\r\n !contentTrimmed.includes('{{SPEC_PATH}}') &&\r\n contentTrimmed !== '기존 내용') {\r\n // Before/After 블록 추출 - 더 유연한 패턴\r\n const beforeMatch = contentTrimmed.match(/####?\\s*Before\\s*\\n+```(?:markdown)?\\n([\\s\\S]*?)\\n```/i);\r\n const afterMatch = contentTrimmed.match(/####?\\s*After\\s*\\n+```(?:markdown)?\\n([\\s\\S]*?)\\n```/i);\r\n\r\n modified.push({\r\n type: 'MODIFIED',\r\n content: contentTrimmed,\r\n before: beforeMatch?.[1]?.trim(),\r\n after: afterMatch?.[1]?.trim(),\r\n });\r\n }\r\n }\r\n\r\n // REMOVED 섹션 추출\r\n const removedMatch = body.match(/##\\s*REMOVED\\s*([\\s\\S]*?)(?=\\n##|$)/i);\r\n const removed: DeltaItem[] = [];\r\n if (removedMatch && removedMatch[1].trim()) {\r\n removed.push({\r\n type: 'REMOVED',\r\n content: removedMatch[1].trim(),\r\n });\r\n }\r\n\r\n return success({\r\n metadata: metadataResult.data,\r\n title,\r\n added,\r\n modified,\r\n removed,\r\n rawContent: body,\r\n });\r\n } catch (error) {\r\n return failure(\r\n new ChangeError(\r\n `Delta 파싱 실패: ${error instanceof Error ? error.message : String(error)}`\r\n )\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Delta 생성 옵션\r\n */\r\nexport interface GenerateDeltaOptions {\r\n proposalId: string;\r\n title: string;\r\n added?: string[];\r\n modified?: Array<{ target: string; before: string; after: string }>;\r\n removed?: string[];\r\n}\r\n\r\n/**\r\n * Delta 템플릿 생성\r\n */\r\nexport function generateDelta(options: GenerateDeltaOptions): string {\r\n const today = new Date().toISOString().split('T')[0];\r\n\r\n let content = `---\r\nproposal: ${options.proposalId}\r\ncreated: ${today}\r\n---\r\n\r\n# Delta: ${options.title}\r\n\r\n## ADDED\r\n\r\n`;\r\n\r\n if (options.added && options.added.length > 0) {\r\n content += options.added.join('\\n\\n');\r\n } else {\r\n content += '(추가되는 스펙 내용)';\r\n }\r\n\r\n content += '\\n\\n## MODIFIED\\n\\n';\r\n\r\n if (options.modified && options.modified.length > 0) {\r\n options.modified.forEach((mod) => {\r\n content += `### ${mod.target}\\n\\n`;\r\n content += `#### Before\\n\\n\\`\\`\\`markdown\\n${mod.before}\\n\\`\\`\\`\\n\\n`;\r\n content += `#### After\\n\\n\\`\\`\\`markdown\\n${mod.after}\\n\\`\\`\\`\\n\\n`;\r\n });\r\n } else {\r\n content += `### {{SPEC_PATH}}\r\n\r\n#### Before\r\n\r\n\\`\\`\\`markdown\r\n기존 내용\r\n\\`\\`\\`\r\n\r\n#### After\r\n\r\n\\`\\`\\`markdown\r\n변경된 내용\r\n\\`\\`\\`\r\n\r\n`;\r\n }\r\n\r\n content += '## REMOVED\\n\\n';\r\n\r\n if (options.removed && options.removed.length > 0) {\r\n content += options.removed.join('\\n\\n');\r\n } else {\r\n content += '(삭제되는 스펙 참조)';\r\n }\r\n\r\n return content;\r\n}\r\n\r\n/**\r\n * Delta 유효성 검증\r\n */\r\nexport interface DeltaValidationResult {\r\n valid: boolean;\r\n hasAdded: boolean;\r\n hasModified: boolean;\r\n hasRemoved: boolean;\r\n errors: string[];\r\n warnings: string[];\r\n}\r\n\r\nexport function validateDelta(content: string): DeltaValidationResult {\r\n const result: DeltaValidationResult = {\r\n valid: true,\r\n hasAdded: false,\r\n hasModified: false,\r\n hasRemoved: false,\r\n errors: [],\r\n warnings: [],\r\n };\r\n\r\n const parseResult = parseDelta(content);\r\n if (!parseResult.success) {\r\n result.valid = false;\r\n result.errors.push(parseResult.error.message);\r\n return result;\r\n }\r\n\r\n const delta = parseResult.data;\r\n\r\n // 변경 내용 확인\r\n result.hasAdded = delta.added.length > 0 && delta.added[0].content !== '(추가되는 스펙 내용)';\r\n result.hasModified = delta.modified.length > 0 && delta.modified[0].content !== '';\r\n result.hasRemoved = delta.removed.length > 0 && delta.removed[0].content !== '(삭제되는 스펙 참조)';\r\n\r\n // 최소 하나의 변경이 있어야 함\r\n if (!result.hasAdded && !result.hasModified && !result.hasRemoved) {\r\n result.valid = false;\r\n result.errors.push('델타에 변경 내용이 없습니다. ADDED, MODIFIED, REMOVED 중 하나 이상이 필요합니다.');\r\n }\r\n\r\n // MODIFIED에 Before/After가 있는지 확인\r\n if (result.hasModified) {\r\n const mod = delta.modified[0];\r\n if (!mod.before || !mod.after) {\r\n result.warnings.push('MODIFIED 섹션에 Before/After 블록이 없습니다.');\r\n }\r\n }\r\n\r\n return result;\r\n}\r\n","/**\r\n * 변경 아카이브 기능\r\n */\r\nimport path from 'node:path';\r\nimport { promises as fs } from 'node:fs';\r\nimport { success, failure, Result } from '../../types/index.js';\r\nimport { ChangeError } from '../../errors/index.js';\r\nimport { directoryExists, ensureDir, copyDir, removeDir } from '../../utils/fs.js';\r\nimport { parseProposal, updateProposalStatus } from './proposal.js';\r\n\r\n/**\r\n * 아카이브 결과\r\n */\r\nexport interface ArchiveResult {\r\n sourceDir: string;\r\n archiveDir: string;\r\n archivedAt: string;\r\n changeId: string;\r\n}\r\n\r\n/**\r\n * 변경 아카이브\r\n */\r\nexport async function archiveChange(\r\n sddPath: string,\r\n changeId: string\r\n): Promise<Result<ArchiveResult, ChangeError>> {\r\n try {\r\n const changesPath = path.join(sddPath, 'changes');\r\n const archivePath = path.join(sddPath, 'archive');\r\n\r\n // 변경 디렉토리 확인\r\n const sourceDir = path.join(changesPath, changeId);\r\n if (!(await directoryExists(sourceDir))) {\r\n return failure(new ChangeError(`변경 디렉토리를 찾을 수 없습니다: ${changeId}`));\r\n }\r\n\r\n // 아카이브 디렉토리 생성\r\n const today = new Date();\r\n const yearMonth = `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, '0')}`;\r\n const archiveMonthDir = path.join(archivePath, yearMonth);\r\n await ensureDir(archiveMonthDir);\r\n\r\n // 날짜 프리픽스로 아카이브\r\n const datePrefix = today.toISOString().split('T')[0];\r\n const archiveDir = path.join(archiveMonthDir, `${datePrefix}-${changeId}`);\r\n\r\n // 디렉토리 복사\r\n const copyResult = await copyDir(sourceDir, archiveDir);\r\n if (!copyResult.success) {\r\n return failure(new ChangeError(`아카이브 복사 실패: ${copyResult.error?.message}`));\r\n }\r\n\r\n // proposal.md 상태 업데이트\r\n const proposalPath = path.join(archiveDir, 'proposal.md');\r\n try {\r\n const proposalContent = await fs.readFile(proposalPath, 'utf-8');\r\n const updateResult = updateProposalStatus(proposalContent, 'archived');\r\n if (updateResult.success) {\r\n await fs.writeFile(proposalPath, updateResult.data);\r\n }\r\n } catch {\r\n // proposal.md가 없을 수 있음\r\n }\r\n\r\n // 원본 디렉토리 삭제\r\n const removeResult = await removeDir(sourceDir);\r\n if (!removeResult.success) {\r\n return failure(new ChangeError(`원본 디렉토리 삭제 실패: ${removeResult.error?.message}`));\r\n }\r\n\r\n return success({\r\n sourceDir,\r\n archiveDir,\r\n archivedAt: today.toISOString(),\r\n changeId,\r\n });\r\n } catch (error) {\r\n return failure(\r\n new ChangeError(\r\n `아카이브 실패: ${error instanceof Error ? error.message : String(error)}`\r\n )\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * 아카이브 목록 조회\r\n */\r\nexport interface ArchivedChange {\r\n id: string;\r\n path: string;\r\n archivedAt: string;\r\n title?: string;\r\n}\r\n\r\nexport async function listArchives(\r\n sddPath: string\r\n): Promise<Result<ArchivedChange[], ChangeError>> {\r\n try {\r\n const archivePath = path.join(sddPath, 'archive');\r\n\r\n if (!(await directoryExists(archivePath))) {\r\n return success([]);\r\n }\r\n\r\n const archives: ArchivedChange[] = [];\r\n\r\n // 월별 디렉토리 순회\r\n const months = await fs.readdir(archivePath);\r\n for (const month of months) {\r\n const monthPath = path.join(archivePath, month);\r\n const stat = await fs.stat(monthPath);\r\n if (!stat.isDirectory()) continue;\r\n\r\n // 변경 디렉토리 순회\r\n const changes = await fs.readdir(monthPath);\r\n for (const change of changes) {\r\n const changePath = path.join(monthPath, change);\r\n const changeStat = await fs.stat(changePath);\r\n if (!changeStat.isDirectory()) continue;\r\n\r\n // ID 추출 (YYYY-MM-DD-CHG-XXX 형식)\r\n const idMatch = change.match(/\\d{4}-\\d{2}-\\d{2}-(CHG-\\d+)/);\r\n const id = idMatch ? idMatch[1] : change;\r\n\r\n // 날짜 추출\r\n const dateMatch = change.match(/^(\\d{4}-\\d{2}-\\d{2})/);\r\n const archivedAt = dateMatch ? dateMatch[1] : month;\r\n\r\n // 제목 추출 (proposal.md에서)\r\n let title: string | undefined;\r\n try {\r\n const proposalPath = path.join(changePath, 'proposal.md');\r\n const proposalContent = await fs.readFile(proposalPath, 'utf-8');\r\n const parseResult = parseProposal(proposalContent);\r\n if (parseResult.success) {\r\n title = parseResult.data.title;\r\n }\r\n } catch {\r\n // proposal.md가 없을 수 있음\r\n }\r\n\r\n archives.push({\r\n id,\r\n path: changePath,\r\n archivedAt,\r\n title,\r\n });\r\n }\r\n }\r\n\r\n // 날짜 역순 정렬\r\n archives.sort((a, b) => b.archivedAt.localeCompare(a.archivedAt));\r\n\r\n return success(archives);\r\n } catch (error) {\r\n return failure(\r\n new ChangeError(\r\n `아카이브 목록 조회 실패: ${error instanceof Error ? error.message : String(error)}`\r\n )\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * 진행 중인 변경 목록 조회\r\n */\r\nexport interface PendingChange {\r\n id: string;\r\n path: string;\r\n status: string;\r\n title?: string;\r\n createdAt?: string;\r\n}\r\n\r\nexport async function listPendingChanges(\r\n sddPath: string\r\n): Promise<Result<PendingChange[], ChangeError>> {\r\n try {\r\n const changesPath = path.join(sddPath, 'changes');\r\n\r\n if (!(await directoryExists(changesPath))) {\r\n return success([]);\r\n }\r\n\r\n const changes: PendingChange[] = [];\r\n\r\n const dirs = await fs.readdir(changesPath);\r\n for (const dir of dirs) {\r\n const changePath = path.join(changesPath, dir);\r\n const stat = await fs.stat(changePath);\r\n if (!stat.isDirectory()) continue;\r\n\r\n // proposal.md에서 정보 추출\r\n let status = 'draft';\r\n let title: string | undefined;\r\n let createdAt: string | undefined;\r\n\r\n try {\r\n const proposalPath = path.join(changePath, 'proposal.md');\r\n const proposalContent = await fs.readFile(proposalPath, 'utf-8');\r\n const parseResult = parseProposal(proposalContent);\r\n if (parseResult.success) {\r\n status = parseResult.data.metadata.status;\r\n title = parseResult.data.title;\r\n createdAt = parseResult.data.metadata.created;\r\n }\r\n } catch {\r\n // proposal.md가 없을 수 있음\r\n }\r\n\r\n changes.push({\r\n id: dir,\r\n path: changePath,\r\n status,\r\n title,\r\n createdAt,\r\n });\r\n }\r\n\r\n // 생성일 역순 정렬\r\n changes.sort((a, b) => (b.createdAt || '').localeCompare(a.createdAt || ''));\r\n\r\n return success(changes);\r\n } catch (error) {\r\n return failure(\r\n new ChangeError(\r\n `변경 목록 조회 실패: ${error instanceof Error ? error.message : String(error)}`\r\n )\r\n );\r\n }\r\n}\r\n","/**\r\n * sdd impact 명령어\r\n *\r\n * 스펙 간 영향도를 분석합니다.\r\n */\r\nimport { Command } from 'commander';\r\nimport path from 'node:path';\r\nimport {\r\n analyzeImpact,\r\n formatImpactResult,\r\n buildDependencyGraph,\r\n generateMermaidGraph,\r\n generateImpactReport,\r\n formatImpactReport,\r\n analyzeChangeImpact,\r\n} from '../../core/impact/index.js';\r\nimport { findSddRoot } from '../../utils/fs.js';\r\nimport * as logger from '../../utils/logger.js';\r\nimport { ExitCode } from '../../errors/index.js';\r\n\r\n/**\r\n * impact 명령어 등록\r\n */\r\nexport function registerImpactCommand(program: Command): void {\r\n const impact = program\r\n .command('impact [feature]')\r\n .description('스펙 변경의 영향도를 분석합니다')\r\n .option('-g, --graph', '의존성 그래프 출력 (Mermaid)')\r\n .option('-r, --reverse', '역방향 영향도 분석')\r\n .option('--json', 'JSON 형식 출력')\r\n .action(async (feature: string | undefined, options: {\r\n graph?: boolean;\r\n reverse?: boolean;\r\n json?: boolean;\r\n }) => {\r\n try {\r\n await runImpact(feature, options);\r\n } catch (error) {\r\n logger.error(error instanceof Error ? error.message : String(error));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n });\r\n\r\n // report 서브커맨드\r\n impact\r\n .command('report')\r\n .description('전체 프로젝트 의존성 리포트 생성')\r\n .option('--json', 'JSON 형식 출력')\r\n .action(async (options: { json?: boolean }) => {\r\n try {\r\n await runImpactReport(options);\r\n } catch (error) {\r\n logger.error(error instanceof Error ? error.message : String(error));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n });\r\n\r\n // change 서브커맨드\r\n impact\r\n .command('change <id>')\r\n .description('변경 제안의 영향도를 분석합니다')\r\n .option('--json', 'JSON 형식 출력')\r\n .action(async (id: string, options: { json?: boolean }) => {\r\n try {\r\n await runChangeImpact(id, options);\r\n } catch (error) {\r\n logger.error(error instanceof Error ? error.message : String(error));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n });\r\n}\r\n\r\n/**\r\n * 영향도 분석 실행\r\n */\r\nasync function runImpact(\r\n feature: string | undefined,\r\n options: { graph?: boolean; reverse?: boolean; json?: boolean }\r\n): Promise<void> {\r\n const projectRoot = await findSddRoot();\r\n if (!projectRoot) {\r\n logger.error('SDD 프로젝트를 찾을 수 없습니다. `sdd init`을 먼저 실행하세요.');\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n const sddPath = path.join(projectRoot, '.sdd');\r\n\r\n // 그래프 모드\r\n if (options.graph) {\r\n const graphResult = await buildDependencyGraph(path.join(sddPath, 'specs'));\r\n if (!graphResult.success) {\r\n logger.error(graphResult.error.message);\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n const mermaid = generateMermaidGraph(graphResult.data, feature);\r\n\r\n if (options.json) {\r\n console.log(JSON.stringify({\r\n format: 'mermaid',\r\n content: mermaid,\r\n nodes: Array.from(graphResult.data.nodes.values()),\r\n edges: graphResult.data.edges,\r\n }, null, 2));\r\n } else {\r\n logger.info('의존성 그래프 (Mermaid):');\r\n logger.newline();\r\n console.log('```mermaid');\r\n console.log(mermaid);\r\n console.log('```');\r\n }\r\n return;\r\n }\r\n\r\n // 특정 기능 영향도 분석\r\n if (!feature) {\r\n logger.error('분석할 기능을 지정하세요.');\r\n logger.info('사용법: sdd impact <feature>');\r\n logger.info('예시: sdd impact auth');\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n const result = await analyzeImpact(sddPath, feature);\r\n if (!result.success) {\r\n logger.error(result.error.message);\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n if (options.json) {\r\n console.log(JSON.stringify(result.data, null, 2));\r\n } else {\r\n console.log(formatImpactResult(result.data));\r\n }\r\n}\r\n\r\n/**\r\n * 영향도 리포트 생성\r\n */\r\nasync function runImpactReport(options: { json?: boolean }): Promise<void> {\r\n const projectRoot = await findSddRoot();\r\n if (!projectRoot) {\r\n logger.error('SDD 프로젝트를 찾을 수 없습니다. `sdd init`을 먼저 실행하세요.');\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n const sddPath = path.join(projectRoot, '.sdd');\r\n const result = await generateImpactReport(sddPath);\r\n\r\n if (!result.success) {\r\n logger.error(result.error.message);\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n if (options.json) {\r\n console.log(JSON.stringify(result.data, null, 2));\r\n } else {\r\n console.log(formatImpactReport(result.data));\r\n }\r\n}\r\n\r\n/**\r\n * 변경 제안 영향 분석\r\n */\r\nasync function runChangeImpact(changeId: string, options: { json?: boolean }): Promise<void> {\r\n const projectRoot = await findSddRoot();\r\n if (!projectRoot) {\r\n logger.error('SDD 프로젝트를 찾을 수 없습니다. `sdd init`을 먼저 실행하세요.');\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n const sddPath = path.join(projectRoot, '.sdd');\r\n const result = await analyzeChangeImpact(sddPath, changeId);\r\n\r\n if (!result.success) {\r\n logger.error(result.error.message);\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n if (options.json) {\r\n console.log(JSON.stringify(result.data, null, 2));\r\n } else {\r\n const data = result.data;\r\n logger.info(`📊 변경 영향 분석: ${data.changeId}`);\r\n if (data.title) {\r\n logger.info(`제목: ${data.title}`);\r\n }\r\n logger.info(`상태: ${data.status}`);\r\n logger.newline();\r\n\r\n if (data.affectedSpecs.length > 0) {\r\n logger.info('⚠️ 직접 영향 받는 스펙:');\r\n for (const spec of data.affectedSpecs) {\r\n logger.listItem(`${spec.id} - ${spec.reason}`, 1);\r\n }\r\n logger.newline();\r\n }\r\n\r\n if (data.transitiveAffected.length > 0) {\r\n logger.info('🔄 간접 영향 받는 스펙:');\r\n for (const spec of data.transitiveAffected) {\r\n logger.listItem(`${spec.id} (${spec.reason})`, 1);\r\n }\r\n logger.newline();\r\n }\r\n\r\n const riskIcon = data.riskLevel === 'high' ? '🔴' : data.riskLevel === 'medium' ? '🟡' : '🟢';\r\n logger.info(`총 영향 범위: ${data.totalImpact}개 스펙 ${riskIcon}`);\r\n logger.newline();\r\n\r\n if (data.recommendations.length > 0) {\r\n logger.info('💡 권장사항:');\r\n for (const rec of data.recommendations) {\r\n logger.listItem(rec, 1);\r\n }\r\n }\r\n }\r\n}\r\n","/**\r\n * 영향도 분석 스키마\r\n */\r\nimport { z } from 'zod';\r\n\r\n/**\r\n * 의존성 유형\r\n */\r\nexport const DependencyTypeSchema = z.enum([\r\n 'explicit', // frontmatter depends 필드\r\n 'reference', // 문서 내 참조\r\n 'data', // 데이터 모델 공유\r\n 'api', // API 의존\r\n 'component', // 컴포넌트 공유\r\n]);\r\n\r\nexport type DependencyType = z.infer<typeof DependencyTypeSchema>;\r\n\r\n/**\r\n * 영향도 수준\r\n */\r\nexport const ImpactLevelSchema = z.enum(['low', 'medium', 'high']);\r\n\r\nexport type ImpactLevel = z.infer<typeof ImpactLevelSchema>;\r\n\r\n/**\r\n * 의존성 엣지\r\n */\r\nexport interface DependencyEdge {\r\n from: string; // 의존하는 스펙\r\n to: string; // 의존되는 스펙\r\n type: DependencyType;\r\n description?: string;\r\n}\r\n\r\n/**\r\n * 의존성 그래프 노드\r\n */\r\nexport interface DependencyNode {\r\n id: string;\r\n path: string;\r\n title?: string;\r\n dependsOn: string[]; // 이 스펙이 의존하는 것\r\n dependedBy: string[]; // 이 스펙에 의존하는 것\r\n}\r\n\r\n/**\r\n * 의존성 그래프\r\n */\r\nexport interface DependencyGraph {\r\n nodes: Map<string, DependencyNode>;\r\n edges: DependencyEdge[];\r\n}\r\n\r\n/**\r\n * 영향 받는 스펙 정보\r\n */\r\nexport interface AffectedSpec {\r\n id: string;\r\n path: string;\r\n title?: string;\r\n level: ImpactLevel;\r\n type: DependencyType;\r\n reason: string;\r\n}\r\n\r\n/**\r\n * 영향도 분석 결과\r\n */\r\nexport interface ImpactAnalysisResult {\r\n targetSpec: string;\r\n dependsOn: AffectedSpec[];\r\n affectedBy: AffectedSpec[];\r\n transitiveAffected: AffectedSpec[]; // 간접 영향 받는 스펙\r\n riskScore: number; // 1-10\r\n riskLevel: ImpactLevel;\r\n summary: string;\r\n recommendations: string[];\r\n}\r\n\r\n/**\r\n * 영향도 리포트\r\n */\r\nexport interface ImpactReport {\r\n generatedAt: string;\r\n projectPath: string;\r\n totalSpecs: number;\r\n totalEdges: number;\r\n mostConnectedSpecs: Array<{\r\n id: string;\r\n title?: string;\r\n inbound: number;\r\n outbound: number;\r\n total: number;\r\n }>;\r\n orphanSpecs: string[]; // 의존성 없는 스펙\r\n circularDependencies: Array<{\r\n cycle: string[];\r\n description: string;\r\n }>;\r\n healthScore: number; // 1-100\r\n summary: string;\r\n}\r\n\r\n/**\r\n * 변경 제안 영향 분석\r\n */\r\nexport interface ChangeImpactAnalysis {\r\n changeId: string;\r\n title?: string;\r\n status: string;\r\n affectedSpecs: AffectedSpec[];\r\n transitiveAffected: AffectedSpec[];\r\n totalImpact: number;\r\n riskLevel: ImpactLevel;\r\n recommendations: string[];\r\n}\r\n\r\n/**\r\n * 리스크 점수 계산 가중치\r\n */\r\nexport const RISK_WEIGHTS = {\r\n directDependency: 2, // 직접 의존\r\n indirectDependency: 1, // 간접 의존\r\n apiChange: 3, // API 변경\r\n dataModelChange: 2, // 데이터 모델 변경\r\n corePrinciple: 2, // 핵심 원칙 관련\r\n} as const;\r\n\r\n/**\r\n * 영향도 수준 판단 기준\r\n */\r\nexport function getImpactLevel(score: number): ImpactLevel {\r\n if (score <= 3) return 'low';\r\n if (score <= 6) return 'medium';\r\n return 'high';\r\n}\r\n","/**\r\n * 의존성 그래프 분석\r\n */\r\nimport { promises as fs } from 'node:fs';\r\nimport path from 'node:path';\r\nimport matter from 'gray-matter';\r\nimport {\r\n DependencyGraph,\r\n DependencyNode,\r\n DependencyEdge,\r\n DependencyType,\r\n} from './schemas.js';\r\nimport { success, failure, Result } from '../../types/index.js';\r\nimport { ChangeError } from '../../errors/index.js';\r\nimport { directoryExists } from '../../utils/fs.js';\r\n\r\n/**\r\n * 스펙 디렉토리에서 의존성 그래프 구축\r\n */\r\nexport async function buildDependencyGraph(\r\n specsPath: string\r\n): Promise<Result<DependencyGraph, ChangeError>> {\r\n try {\r\n const graph: DependencyGraph = {\r\n nodes: new Map(),\r\n edges: [],\r\n };\r\n\r\n if (!(await directoryExists(specsPath))) {\r\n return success(graph);\r\n }\r\n\r\n // 스펙 파일 수집\r\n const specFiles = await collectSpecFiles(specsPath);\r\n\r\n // 각 스펙 파일 분석\r\n for (const filePath of specFiles) {\r\n const content = await fs.readFile(filePath, 'utf-8');\r\n const relativePath = path.relative(specsPath, filePath);\r\n const specId = getSpecId(relativePath);\r\n\r\n // 노드 생성\r\n const node: DependencyNode = {\r\n id: specId,\r\n path: relativePath,\r\n title: extractTitle(content),\r\n dependsOn: [],\r\n dependedBy: [],\r\n };\r\n\r\n // frontmatter에서 명시적 의존성 추출\r\n const { data: frontmatter } = matter(content);\r\n if (frontmatter.depends) {\r\n const explicitDeps = Array.isArray(frontmatter.depends)\r\n ? frontmatter.depends\r\n : [frontmatter.depends];\r\n\r\n for (const dep of explicitDeps) {\r\n if (dep && dep !== 'null') {\r\n node.dependsOn.push(dep);\r\n graph.edges.push({\r\n from: specId,\r\n to: dep,\r\n type: 'explicit',\r\n description: 'frontmatter depends 필드',\r\n });\r\n }\r\n }\r\n }\r\n\r\n // 내용에서 참조 추출\r\n const references = extractReferences(content, specFiles.map((f) => getSpecId(path.relative(specsPath, f))));\r\n for (const ref of references) {\r\n if (ref !== specId && !node.dependsOn.includes(ref)) {\r\n node.dependsOn.push(ref);\r\n graph.edges.push({\r\n from: specId,\r\n to: ref,\r\n type: 'reference',\r\n description: '문서 내 참조',\r\n });\r\n }\r\n }\r\n\r\n graph.nodes.set(specId, node);\r\n }\r\n\r\n // 역방향 의존성 계산\r\n for (const edge of graph.edges) {\r\n const targetNode = graph.nodes.get(edge.to);\r\n if (targetNode && !targetNode.dependedBy.includes(edge.from)) {\r\n targetNode.dependedBy.push(edge.from);\r\n }\r\n }\r\n\r\n return success(graph);\r\n } catch (error) {\r\n return failure(\r\n new ChangeError(\r\n `의존성 그래프 구축 실패: ${error instanceof Error ? error.message : String(error)}`\r\n )\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * 스펙 파일 수집 (재귀)\r\n */\r\nasync function collectSpecFiles(dirPath: string): Promise<string[]> {\r\n const files: string[] = [];\r\n\r\n const entries = await fs.readdir(dirPath, { withFileTypes: true });\r\n\r\n for (const entry of entries) {\r\n const fullPath = path.join(dirPath, entry.name);\r\n\r\n if (entry.isDirectory()) {\r\n files.push(...(await collectSpecFiles(fullPath)));\r\n } else if (entry.name.endsWith('.md') && entry.name !== 'AGENTS.md') {\r\n files.push(fullPath);\r\n }\r\n }\r\n\r\n return files;\r\n}\r\n\r\n/**\r\n * 파일 경로에서 스펙 ID 추출\r\n */\r\nfunction getSpecId(relativePath: string): string {\r\n return relativePath\r\n .replace(/\\\\/g, '/')\r\n .replace(/\\.md$/, '')\r\n .replace(/\\/spec$/, '');\r\n}\r\n\r\n/**\r\n * 마크다운에서 제목 추출\r\n */\r\nfunction extractTitle(content: string): string | undefined {\r\n const { content: body } = matter(content);\r\n const titleMatch = body.match(/^#\\s+(.+)$/m);\r\n return titleMatch?.[1]?.trim();\r\n}\r\n\r\n/**\r\n * 내용에서 다른 스펙 참조 추출\r\n */\r\nfunction extractReferences(content: string, allSpecIds: string[]): string[] {\r\n const references: string[] = [];\r\n\r\n for (const specId of allSpecIds) {\r\n // 스펙 ID나 경로가 문서에서 언급되는지 확인\r\n const patterns = [\r\n new RegExp(`\\\\[.*?\\\\]\\\\(.*?${escapeRegex(specId)}.*?\\\\)`, 'gi'), // 마크다운 링크\r\n new RegExp(`specs/${escapeRegex(specId)}`, 'gi'), // specs/ 경로\r\n new RegExp(`\\`${escapeRegex(specId)}\\``, 'gi'), // 백틱 내 참조\r\n ];\r\n\r\n for (const pattern of patterns) {\r\n if (pattern.test(content) && !references.includes(specId)) {\r\n references.push(specId);\r\n break;\r\n }\r\n }\r\n }\r\n\r\n return references;\r\n}\r\n\r\n/**\r\n * 정규식 특수문자 이스케이프\r\n */\r\nfunction escapeRegex(str: string): string {\r\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\r\n}\r\n\r\n/**\r\n * Mermaid 그래프 생성\r\n */\r\nexport function generateMermaidGraph(\r\n graph: DependencyGraph,\r\n targetSpec?: string\r\n): string {\r\n let mermaid = 'graph LR\\n';\r\n\r\n // 노드 정의\r\n for (const [id, node] of graph.nodes) {\r\n const label = node.title || id;\r\n const style = targetSpec === id ? 'fill:#ff9' : '';\r\n mermaid += ` ${sanitizeId(id)}[\"${label}\"]\\n`;\r\n if (style) {\r\n mermaid += ` style ${sanitizeId(id)} ${style}\\n`;\r\n }\r\n }\r\n\r\n // 엣지 정의\r\n for (const edge of graph.edges) {\r\n const arrowStyle = edge.type === 'explicit' ? '-->' : '-..->';\r\n mermaid += ` ${sanitizeId(edge.from)} ${arrowStyle} ${sanitizeId(edge.to)}\\n`;\r\n }\r\n\r\n return mermaid;\r\n}\r\n\r\n/**\r\n * Mermaid ID 정리\r\n */\r\nfunction sanitizeId(id: string): string {\r\n return id.replace(/[^a-zA-Z0-9]/g, '_');\r\n}\r\n","/**\r\n * 영향도 분석기\r\n */\r\nimport path from 'node:path';\r\nimport { promises as fs } from 'node:fs';\r\nimport {\r\n DependencyGraph,\r\n ImpactAnalysisResult,\r\n AffectedSpec,\r\n ImpactLevel,\r\n RISK_WEIGHTS,\r\n getImpactLevel,\r\n ImpactReport,\r\n ChangeImpactAnalysis,\r\n} from './schemas.js';\r\nimport { buildDependencyGraph, generateMermaidGraph } from './graph.js';\r\nimport { success, failure, Result } from '../../types/index.js';\r\nimport { ChangeError } from '../../errors/index.js';\r\nimport { directoryExists, fileExists, readFile } from '../../utils/fs.js';\r\nimport { parseProposal } from '../change/index.js';\r\n\r\n/**\r\n * 영향도 분석 실행\r\n */\r\nexport async function analyzeImpact(\r\n sddPath: string,\r\n targetSpec: string\r\n): Promise<Result<ImpactAnalysisResult, ChangeError>> {\r\n try {\r\n const specsPath = path.join(sddPath, 'specs');\r\n\r\n if (!(await directoryExists(specsPath))) {\r\n return failure(new ChangeError('스펙 디렉토리를 찾을 수 없습니다.'));\r\n }\r\n\r\n // 의존성 그래프 구축\r\n const graphResult = await buildDependencyGraph(specsPath);\r\n if (!graphResult.success) {\r\n return failure(graphResult.error);\r\n }\r\n\r\n const graph = graphResult.data;\r\n const targetNode = graph.nodes.get(targetSpec);\r\n\r\n if (!targetNode) {\r\n return failure(new ChangeError(`스펙을 찾을 수 없습니다: ${targetSpec}`));\r\n }\r\n\r\n // 의존하는 스펙 (이 스펙이 사용하는)\r\n const dependsOn: AffectedSpec[] = targetNode.dependsOn.map((depId) => {\r\n const depNode = graph.nodes.get(depId);\r\n const edge = graph.edges.find((e) => e.from === targetSpec && e.to === depId);\r\n return {\r\n id: depId,\r\n path: depNode?.path || depId,\r\n title: depNode?.title,\r\n level: 'low' as ImpactLevel,\r\n type: edge?.type || 'reference',\r\n reason: edge?.description || '의존',\r\n };\r\n });\r\n\r\n // 영향 받는 스펙 (이 스펙을 사용하는)\r\n const affectedBy: AffectedSpec[] = targetNode.dependedBy.map((depId) => {\r\n const depNode = graph.nodes.get(depId);\r\n const edge = graph.edges.find((e) => e.from === depId && e.to === targetSpec);\r\n const level = determineImpactLevel(edge?.type);\r\n return {\r\n id: depId,\r\n path: depNode?.path || depId,\r\n title: depNode?.title,\r\n level,\r\n type: edge?.type || 'reference',\r\n reason: edge?.description || '이 스펙에 의존함',\r\n };\r\n });\r\n\r\n // 간접 영향 분석 (transitive)\r\n const transitiveAffected = getTransitiveAffected(graph, targetSpec, new Set([targetSpec]));\r\n\r\n // 리스크 점수 계산\r\n const riskScore = calculateRiskScore(dependsOn, affectedBy, transitiveAffected);\r\n const riskLevel = getImpactLevel(riskScore);\r\n\r\n // 요약 및 권장사항 생성\r\n const summary = generateSummary(targetSpec, dependsOn, affectedBy, transitiveAffected, riskScore);\r\n const recommendations = generateRecommendations(affectedBy, transitiveAffected, riskLevel);\r\n\r\n return success({\r\n targetSpec,\r\n dependsOn,\r\n affectedBy,\r\n transitiveAffected,\r\n riskScore,\r\n riskLevel,\r\n summary,\r\n recommendations,\r\n });\r\n } catch (error) {\r\n return failure(\r\n new ChangeError(\r\n `영향도 분석 실패: ${error instanceof Error ? error.message : String(error)}`\r\n )\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * 의존성 유형에 따른 영향도 수준 결정\r\n */\r\nfunction determineImpactLevel(type?: string): ImpactLevel {\r\n switch (type) {\r\n case 'explicit':\r\n case 'api':\r\n return 'high';\r\n case 'data':\r\n return 'medium';\r\n default:\r\n return 'low';\r\n }\r\n}\r\n\r\n/**\r\n * 간접 영향 받는 스펙 조회 (재귀)\r\n */\r\nfunction getTransitiveAffected(\r\n graph: DependencyGraph,\r\n specId: string,\r\n visited: Set<string>,\r\n depth: number = 0\r\n): AffectedSpec[] {\r\n const result: AffectedSpec[] = [];\r\n const node = graph.nodes.get(specId);\r\n\r\n if (!node || depth > 5) return result; // 최대 5단계까지\r\n\r\n for (const depId of node.dependedBy) {\r\n if (visited.has(depId)) continue;\r\n visited.add(depId);\r\n\r\n // 직접 의존이 아닌 경우만 추가 (depth > 0)\r\n if (depth > 0) {\r\n const depNode = graph.nodes.get(depId);\r\n const edge = graph.edges.find((e) => e.from === depId && e.to === specId);\r\n result.push({\r\n id: depId,\r\n path: depNode?.path || depId,\r\n title: depNode?.title,\r\n level: depth === 1 ? 'medium' : 'low',\r\n type: edge?.type || 'reference',\r\n reason: `${depth}단계 간접 의존`,\r\n });\r\n }\r\n\r\n // 재귀 탐색\r\n result.push(...getTransitiveAffected(graph, depId, visited, depth + 1));\r\n }\r\n\r\n return result;\r\n}\r\n\r\n/**\r\n * 리스크 점수 계산\r\n */\r\nfunction calculateRiskScore(\r\n dependsOn: AffectedSpec[],\r\n affectedBy: AffectedSpec[],\r\n transitiveAffected: AffectedSpec[] = []\r\n): number {\r\n let score = 0;\r\n\r\n // 직접 영향 받는 스펙 수\r\n const highImpactCount = affectedBy.filter((s) => s.level === 'high').length;\r\n const mediumImpactCount = affectedBy.filter((s) => s.level === 'medium').length;\r\n const lowImpactCount = affectedBy.filter((s) => s.level === 'low').length;\r\n\r\n score += highImpactCount * RISK_WEIGHTS.directDependency;\r\n score += mediumImpactCount * RISK_WEIGHTS.indirectDependency;\r\n score += lowImpactCount * 0.5;\r\n\r\n // 간접 영향 추가\r\n score += transitiveAffected.length * 0.3;\r\n\r\n // API 변경 포함 시\r\n if (affectedBy.some((s) => s.type === 'api')) {\r\n score += RISK_WEIGHTS.apiChange;\r\n }\r\n\r\n // 데이터 모델 변경 포함 시\r\n if (affectedBy.some((s) => s.type === 'data')) {\r\n score += RISK_WEIGHTS.dataModelChange;\r\n }\r\n\r\n // 1-10 범위로 정규화\r\n return Math.min(10, Math.max(1, Math.round(score)));\r\n}\r\n\r\n/**\r\n * 요약 생성\r\n */\r\nfunction generateSummary(\r\n targetSpec: string,\r\n dependsOn: AffectedSpec[],\r\n affectedBy: AffectedSpec[],\r\n transitiveAffected: AffectedSpec[],\r\n riskScore: number\r\n): string {\r\n const parts: string[] = [];\r\n\r\n parts.push(`'${targetSpec}' 스펙 변경 시:`);\r\n\r\n if (dependsOn.length > 0) {\r\n parts.push(`- ${dependsOn.length}개 스펙에 의존함`);\r\n }\r\n\r\n if (affectedBy.length > 0) {\r\n parts.push(`- ${affectedBy.length}개 스펙에 직접 영향을 줌`);\r\n\r\n const highCount = affectedBy.filter((s) => s.level === 'high').length;\r\n if (highCount > 0) {\r\n parts.push(` - 높은 영향: ${highCount}개`);\r\n }\r\n }\r\n\r\n if (transitiveAffected.length > 0) {\r\n parts.push(`- ${transitiveAffected.length}개 스펙에 간접 영향을 줌`);\r\n }\r\n\r\n parts.push(`- 총 영향 범위: ${affectedBy.length + transitiveAffected.length}개 스펙`);\r\n parts.push(`- 리스크 점수: ${riskScore}/10`);\r\n\r\n return parts.join('\\n');\r\n}\r\n\r\n/**\r\n * 권장사항 생성\r\n */\r\nfunction generateRecommendations(\r\n affectedBy: AffectedSpec[],\r\n transitiveAffected: AffectedSpec[],\r\n riskLevel: ImpactLevel\r\n): string[] {\r\n const recommendations: string[] = [];\r\n\r\n if (riskLevel === 'high') {\r\n recommendations.push('변경 전 영향 받는 모든 스펙을 검토하세요.');\r\n recommendations.push('관련 팀과 변경 사항을 공유하세요.');\r\n recommendations.push('단계적 마이그레이션을 고려하세요.');\r\n } else if (riskLevel === 'medium') {\r\n recommendations.push('영향 받는 스펙의 테스트를 확인하세요.');\r\n recommendations.push('변경 후 영향 스펙 검증을 수행하세요.');\r\n } else {\r\n recommendations.push('표준 변경 프로세스를 따르세요.');\r\n }\r\n\r\n // 특정 유형에 대한 권장사항\r\n const hasApiDep = affectedBy.some((s) => s.type === 'api');\r\n if (hasApiDep) {\r\n recommendations.push('API 변경 시 버전 관리를 고려하세요.');\r\n }\r\n\r\n const hasDataDep = affectedBy.some((s) => s.type === 'data');\r\n if (hasDataDep) {\r\n recommendations.push('데이터 마이그레이션 계획을 수립하세요.');\r\n }\r\n\r\n // 간접 영향 관련 권장사항\r\n if (transitiveAffected.length > 3) {\r\n recommendations.push('영향 범위가 넓습니다. 변경 제안서(CHG)를 작성하세요.');\r\n }\r\n\r\n return recommendations;\r\n}\r\n\r\n/**\r\n * 영향도 분석 결과 포맷팅\r\n */\r\nexport function formatImpactResult(result: ImpactAnalysisResult): string {\r\n const lines: string[] = [];\r\n\r\n lines.push(`📊 영향도 분석: ${result.targetSpec}`);\r\n lines.push('');\r\n\r\n if (result.dependsOn.length > 0) {\r\n lines.push('🔗 의존하는 스펙 (이 기능이 사용하는):');\r\n for (const dep of result.dependsOn) {\r\n lines.push(` └─ ${dep.id} (${dep.type})`);\r\n }\r\n lines.push('');\r\n }\r\n\r\n if (result.affectedBy.length > 0) {\r\n lines.push('⚠️ 직접 영향 받는 스펙 (이 기능을 사용하는):');\r\n for (const affected of result.affectedBy) {\r\n const icon = affected.level === 'high' ? '🔴' : affected.level === 'medium' ? '🟡' : '🟢';\r\n lines.push(` ├─ ${icon} ${affected.id} (${affected.type})`);\r\n }\r\n lines.push('');\r\n }\r\n\r\n if (result.transitiveAffected.length > 0) {\r\n lines.push('🔄 간접 영향 받는 스펙:');\r\n for (const affected of result.transitiveAffected) {\r\n lines.push(` └─ ${affected.id} (${affected.reason})`);\r\n }\r\n lines.push('');\r\n }\r\n\r\n const riskIcon = result.riskLevel === 'high' ? '🔴' : result.riskLevel === 'medium' ? '🟡' : '🟢';\r\n lines.push(`📈 리스크 점수: ${result.riskScore}/10 ${riskIcon}`);\r\n lines.push('');\r\n\r\n if (result.recommendations.length > 0) {\r\n lines.push('💡 권장사항:');\r\n for (const rec of result.recommendations) {\r\n lines.push(` - ${rec}`);\r\n }\r\n }\r\n\r\n return lines.join('\\n');\r\n}\r\n\r\n/**\r\n * 전체 프로젝트 영향도 리포트 생성\r\n */\r\nexport async function generateImpactReport(\r\n sddPath: string\r\n): Promise<Result<ImpactReport, ChangeError>> {\r\n try {\r\n const specsPath = path.join(sddPath, 'specs');\r\n\r\n if (!(await directoryExists(specsPath))) {\r\n return failure(new ChangeError('스펙 디렉토리를 찾을 수 없습니다.'));\r\n }\r\n\r\n // 의존성 그래프 구축\r\n const graphResult = await buildDependencyGraph(specsPath);\r\n if (!graphResult.success) {\r\n return failure(graphResult.error);\r\n }\r\n\r\n const graph = graphResult.data;\r\n const nodes = Array.from(graph.nodes.values());\r\n\r\n // 연결성 통계\r\n const mostConnected = nodes\r\n .map((node) => ({\r\n id: node.id,\r\n title: node.title,\r\n inbound: node.dependedBy.length,\r\n outbound: node.dependsOn.length,\r\n total: node.dependedBy.length + node.dependsOn.length,\r\n }))\r\n .sort((a, b) => b.total - a.total)\r\n .slice(0, 5);\r\n\r\n // 고립된 스펙\r\n const orphanSpecs = nodes\r\n .filter((n) => n.dependsOn.length === 0 && n.dependedBy.length === 0)\r\n .map((n) => n.id);\r\n\r\n // 순환 의존성 탐지\r\n const circularDeps = detectCircularDependencies(graph);\r\n\r\n // 건강도 점수 계산\r\n const healthScore = calculateHealthScore(nodes.length, graph.edges.length, orphanSpecs.length, circularDeps.length);\r\n\r\n // 요약\r\n const summary = generateReportSummary(nodes.length, graph.edges.length, orphanSpecs.length, circularDeps.length, healthScore);\r\n\r\n return success({\r\n generatedAt: new Date().toISOString(),\r\n projectPath: sddPath,\r\n totalSpecs: nodes.length,\r\n totalEdges: graph.edges.length,\r\n mostConnectedSpecs: mostConnected,\r\n orphanSpecs,\r\n circularDependencies: circularDeps,\r\n healthScore,\r\n summary,\r\n });\r\n } catch (error) {\r\n return failure(\r\n new ChangeError(\r\n `영향도 리포트 생성 실패: ${error instanceof Error ? error.message : String(error)}`\r\n )\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * 순환 의존성 탐지\r\n */\r\nfunction detectCircularDependencies(\r\n graph: DependencyGraph\r\n): Array<{ cycle: string[]; description: string }> {\r\n const cycles: Array<{ cycle: string[]; description: string }> = [];\r\n const visited = new Set<string>();\r\n const recStack = new Set<string>();\r\n\r\n function dfs(nodeId: string, path: string[]): boolean {\r\n visited.add(nodeId);\r\n recStack.add(nodeId);\r\n\r\n const node = graph.nodes.get(nodeId);\r\n if (!node) return false;\r\n\r\n for (const depId of node.dependsOn) {\r\n if (!visited.has(depId)) {\r\n if (dfs(depId, [...path, nodeId])) {\r\n return true;\r\n }\r\n } else if (recStack.has(depId)) {\r\n // 순환 발견\r\n const cycleStart = path.indexOf(depId);\r\n const cycle = cycleStart >= 0 ? [...path.slice(cycleStart), nodeId, depId] : [nodeId, depId];\r\n cycles.push({\r\n cycle,\r\n description: `순환 의존성: ${cycle.join(' → ')}`,\r\n });\r\n return true;\r\n }\r\n }\r\n\r\n recStack.delete(nodeId);\r\n return false;\r\n }\r\n\r\n for (const nodeId of graph.nodes.keys()) {\r\n if (!visited.has(nodeId)) {\r\n dfs(nodeId, []);\r\n }\r\n }\r\n\r\n return cycles;\r\n}\r\n\r\n/**\r\n * 건강도 점수 계산\r\n */\r\nfunction calculateHealthScore(\r\n totalSpecs: number,\r\n totalEdges: number,\r\n orphanCount: number,\r\n circularCount: number\r\n): number {\r\n if (totalSpecs === 0) return 100;\r\n\r\n let score = 100;\r\n\r\n // 고립된 스펙이 많으면 감점\r\n const orphanRatio = orphanCount / totalSpecs;\r\n score -= orphanRatio * 20;\r\n\r\n // 순환 의존성이 있으면 감점\r\n score -= circularCount * 10;\r\n\r\n // 연결성이 너무 낮으면 감점\r\n const avgConnections = (totalEdges * 2) / totalSpecs;\r\n if (avgConnections < 0.5 && totalSpecs > 2) {\r\n score -= 10;\r\n }\r\n\r\n return Math.max(0, Math.min(100, Math.round(score)));\r\n}\r\n\r\n/**\r\n * 리포트 요약 생성\r\n */\r\nfunction generateReportSummary(\r\n totalSpecs: number,\r\n totalEdges: number,\r\n orphanCount: number,\r\n circularCount: number,\r\n healthScore: number\r\n): string {\r\n const parts: string[] = [];\r\n\r\n parts.push(`프로젝트 의존성 분석 결과:`);\r\n parts.push(`- 총 ${totalSpecs}개 스펙, ${totalEdges}개 의존 관계`);\r\n\r\n if (orphanCount > 0) {\r\n parts.push(`- ${orphanCount}개 스펙이 다른 스펙과 연결되지 않음`);\r\n }\r\n\r\n if (circularCount > 0) {\r\n parts.push(`- ${circularCount}개 순환 의존성 발견 (해결 필요)`);\r\n }\r\n\r\n const healthLevel = healthScore >= 80 ? '양호' : healthScore >= 50 ? '주의 필요' : '문제 있음';\r\n parts.push(`- 건강도 점수: ${healthScore}/100 (${healthLevel})`);\r\n\r\n return parts.join('\\n');\r\n}\r\n\r\n/**\r\n * 변경 제안 영향 분석\r\n */\r\nexport async function analyzeChangeImpact(\r\n sddPath: string,\r\n changeId: string\r\n): Promise<Result<ChangeImpactAnalysis, ChangeError>> {\r\n try {\r\n const changePath = path.join(sddPath, 'changes', changeId);\r\n const proposalPath = path.join(changePath, 'proposal.md');\r\n\r\n if (!(await fileExists(proposalPath))) {\r\n return failure(new ChangeError(`변경 제안을 찾을 수 없습니다: ${changeId}`));\r\n }\r\n\r\n const contentResult = await readFile(proposalPath);\r\n if (!contentResult.success) {\r\n return failure(new ChangeError('proposal.md를 읽을 수 없습니다.'));\r\n }\r\n\r\n const parseResult = parseProposal(contentResult.data);\r\n if (!parseResult.success) {\r\n return failure(new ChangeError(`제안서 파싱 실패: ${parseResult.error.message}`));\r\n }\r\n\r\n const proposal = parseResult.data;\r\n const specsPath = path.join(sddPath, 'specs');\r\n\r\n // 의존성 그래프 구축\r\n const graphResult = await buildDependencyGraph(specsPath);\r\n if (!graphResult.success) {\r\n return failure(graphResult.error);\r\n }\r\n\r\n const graph = graphResult.data;\r\n const allAffected: AffectedSpec[] = [];\r\n const allTransitive: AffectedSpec[] = [];\r\n\r\n // 각 영향 받는 스펙에 대해 분석\r\n for (const specPath of proposal.affectedSpecs) {\r\n const specId = specPath.replace(/^specs\\//, '').replace(/\\/spec\\.md$/, '');\r\n const node = graph.nodes.get(specId);\r\n\r\n if (node) {\r\n // 직접 영향 받는 스펙\r\n for (const depId of node.dependedBy) {\r\n const depNode = graph.nodes.get(depId);\r\n if (!allAffected.some((a) => a.id === depId)) {\r\n allAffected.push({\r\n id: depId,\r\n path: depNode?.path || depId,\r\n title: depNode?.title,\r\n level: 'high',\r\n type: 'explicit',\r\n reason: `${specId} 변경으로 인한 영향`,\r\n });\r\n }\r\n }\r\n\r\n // 간접 영향\r\n const transitive = getTransitiveAffected(graph, specId, new Set([specId]));\r\n for (const t of transitive) {\r\n if (!allTransitive.some((a) => a.id === t.id)) {\r\n allTransitive.push(t);\r\n }\r\n }\r\n }\r\n }\r\n\r\n const totalImpact = allAffected.length + allTransitive.length;\r\n const riskLevel = getImpactLevel(Math.min(10, totalImpact * 2));\r\n\r\n const recommendations: string[] = [];\r\n if (totalImpact > 5) {\r\n recommendations.push('영향 범위가 넓습니다. 단계적 적용을 고려하세요.');\r\n }\r\n if (allAffected.length > 0) {\r\n recommendations.push(`${allAffected.length}개 스펙의 업데이트가 필요합니다.`);\r\n }\r\n recommendations.push('변경 후 sdd validate를 실행하세요.');\r\n\r\n return success({\r\n changeId,\r\n title: proposal.title,\r\n status: proposal.metadata.status,\r\n affectedSpecs: allAffected,\r\n transitiveAffected: allTransitive,\r\n totalImpact,\r\n riskLevel,\r\n recommendations,\r\n });\r\n } catch (error) {\r\n return failure(\r\n new ChangeError(\r\n `변경 영향 분석 실패: ${error instanceof Error ? error.message : String(error)}`\r\n )\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * 영향도 리포트 포맷팅\r\n */\r\nexport function formatImpactReport(report: ImpactReport): string {\r\n const lines: string[] = [];\r\n\r\n lines.push('📊 프로젝트 의존성 리포트');\r\n lines.push(`생성: ${report.generatedAt}`);\r\n lines.push('');\r\n\r\n lines.push(`📈 통계`);\r\n lines.push(` - 총 스펙 수: ${report.totalSpecs}`);\r\n lines.push(` - 총 의존 관계: ${report.totalEdges}`);\r\n const healthIcon = report.healthScore >= 80 ? '🟢' : report.healthScore >= 50 ? '🟡' : '🔴';\r\n lines.push(` - 건강도 점수: ${report.healthScore}/100 ${healthIcon}`);\r\n lines.push('');\r\n\r\n if (report.mostConnectedSpecs.length > 0) {\r\n lines.push('🔗 핵심 스펙 (연결 수 기준):');\r\n for (const spec of report.mostConnectedSpecs) {\r\n lines.push(` - ${spec.id}: 입력 ${spec.inbound}, 출력 ${spec.outbound}`);\r\n }\r\n lines.push('');\r\n }\r\n\r\n if (report.orphanSpecs.length > 0) {\r\n lines.push('⚠️ 고립된 스펙 (연결 없음):');\r\n for (const spec of report.orphanSpecs) {\r\n lines.push(` - ${spec}`);\r\n }\r\n lines.push('');\r\n }\r\n\r\n if (report.circularDependencies.length > 0) {\r\n lines.push('🔴 순환 의존성:');\r\n for (const cycle of report.circularDependencies) {\r\n lines.push(` - ${cycle.description}`);\r\n }\r\n lines.push('');\r\n }\r\n\r\n lines.push('📝 요약');\r\n lines.push(report.summary);\r\n\r\n return lines.join('\\n');\r\n}\r\n\r\nexport { generateMermaidGraph };\r\n","/**\r\n * sdd new 명령어 - 신규 기능 생성\r\n */\r\nimport { Command } from 'commander';\r\nimport path from 'node:path';\r\nimport { promises as fs } from 'node:fs';\r\nimport {\r\n generateFeatureId,\r\n generateSpec,\r\n generatePlan,\r\n generateTasks,\r\n createBranch,\r\n isGitRepository,\r\n generateFullChecklistMarkdown,\r\n getNextFeatureNumber,\r\n peekNextFeatureNumber,\r\n getFeatureHistory,\r\n} from '../../core/new/index.js';\r\nimport { logger } from '../../utils/index.js';\r\nimport { ensureDir, fileExists, readFile } from '../../utils/fs.js';\r\nimport { parseConstitution } from '../../core/constitution/index.js';\r\n\r\n/**\r\n * new 명령어 등록\r\n */\r\nexport function registerNewCommand(program: Command): void {\r\n const newCmd = program\r\n .command('new')\r\n .description('새로운 기능 생성')\r\n .argument('[name]', '기능 이름')\r\n .option('--title <title>', '기능 제목')\r\n .option('--description <desc>', '기능 설명')\r\n .option('--no-branch', '브랜치 생성 안 함')\r\n .option('--numbered', '자동 번호 부여 (feature/001-name 형식)')\r\n .option('--plan', '계획 파일도 함께 생성')\r\n .option('--tasks', '작업 분해 파일도 함께 생성')\r\n .option('--all', '모든 파일 생성 (spec, plan, tasks)')\r\n .option('--checklist', '체크리스트 파일 생성')\r\n .action(async (name, options) => {\r\n await handleNew(name, options);\r\n });\r\n\r\n // plan 서브커맨드\r\n newCmd\r\n .command('plan')\r\n .description('기능 구현 계획 생성')\r\n .argument('<feature>', '기능 ID')\r\n .option('--title <title>', '계획 제목')\r\n .action(async (feature, opts) => {\r\n await handlePlan(feature, opts);\r\n });\r\n\r\n // tasks 서브커맨드\r\n newCmd\r\n .command('tasks')\r\n .description('작업 분해 생성')\r\n .argument('<feature>', '기능 ID')\r\n .action(async (feature) => {\r\n await handleTasks(feature);\r\n });\r\n\r\n // checklist 서브커맨드\r\n newCmd\r\n .command('checklist')\r\n .description('워크플로우 체크리스트 생성')\r\n .action(async () => {\r\n await handleChecklist();\r\n });\r\n\r\n // counter 서브커맨드\r\n newCmd\r\n .command('counter')\r\n .description('기능 번호 카운터 관리')\r\n .option('--peek', '다음 번호 확인 (증가하지 않음)')\r\n .option('--history', '생성 이력 조회')\r\n .option('--set <number>', '다음 번호 설정')\r\n .action(async (opts) => {\r\n await handleCounter(opts);\r\n });\r\n}\r\n\r\n/**\r\n * new 명령어 핸들러\r\n */\r\nasync function handleNew(\r\n name: string | undefined,\r\n options: {\r\n title?: string;\r\n description?: string;\r\n branch?: boolean;\r\n numbered?: boolean;\r\n plan?: boolean;\r\n tasks?: boolean;\r\n all?: boolean;\r\n checklist?: boolean;\r\n }\r\n): Promise<void> {\r\n if (!name) {\r\n logger.error('기능 이름을 입력해주세요: sdd new <name>');\r\n process.exit(1);\r\n }\r\n\r\n const cwd = process.cwd();\r\n const sddPath = path.join(cwd, '.sdd');\r\n\r\n // 기능 ID 생성 (번호 부여 옵션에 따라)\r\n let featureId: string;\r\n let branchName: string | undefined;\r\n\r\n if (options.numbered) {\r\n const numberResult = await getNextFeatureNumber(sddPath, name);\r\n if (!numberResult.success) {\r\n logger.error(`번호 생성 실패: ${numberResult.error.message}`);\r\n process.exit(1);\r\n }\r\n featureId = numberResult.data.fullId;\r\n branchName = numberResult.data.branchName;\r\n logger.info(`자동 번호 부여: #${numberResult.data.number.toString().padStart(3, '0')}`);\r\n } else {\r\n featureId = generateFeatureId(name);\r\n }\r\n\r\n const title = options.title || name;\r\n const description = options.description || `${title} 기능 명세`;\r\n const featurePath = path.join(sddPath, 'specs', featureId);\r\n\r\n try {\r\n // .sdd 디렉토리 확인\r\n if (!(await fileExists(sddPath))) {\r\n logger.error('.sdd 디렉토리가 없습니다. 먼저 sdd init을 실행해주세요.');\r\n process.exit(1);\r\n }\r\n\r\n // 기능 디렉토리 생성\r\n await ensureDir(featurePath);\r\n\r\n // Constitution 버전 읽기\r\n let constitutionVersion: string | undefined;\r\n const constitutionPath = path.join(sddPath, 'constitution.md');\r\n if (await fileExists(constitutionPath)) {\r\n const constResult = await readFile(constitutionPath);\r\n if (constResult.success) {\r\n const parseResult = parseConstitution(constResult.data);\r\n if (parseResult.success) {\r\n constitutionVersion = parseResult.data.metadata.version;\r\n }\r\n }\r\n }\r\n\r\n // spec.md 생성\r\n const specContent = generateSpec({\r\n id: featureId,\r\n title,\r\n description,\r\n constitutionVersion,\r\n });\r\n await fs.writeFile(path.join(featurePath, 'spec.md'), specContent, 'utf-8');\r\n logger.info(`✅ 명세 생성: ${featurePath}/spec.md`);\r\n\r\n // 브랜치 생성\r\n if (options.branch !== false) {\r\n if (await isGitRepository(cwd)) {\r\n // 번호 부여 모드에서는 전체 브랜치 이름 사용, 아니면 기존 방식\r\n const branchToCreate = branchName || featureId;\r\n const result = await createBranch(branchToCreate, { checkout: true, cwd });\r\n if (result.success) {\r\n logger.info(`✅ 브랜치 생성: ${result.data}`);\r\n } else {\r\n logger.warn(`⚠️ 브랜치 생성 실패: ${result.error.message}`);\r\n }\r\n } else {\r\n logger.warn('⚠️ Git 저장소가 아닙니다. 브랜치 생성을 건너뜁니다.');\r\n }\r\n }\r\n\r\n // plan.md 생성\r\n if (options.plan || options.all) {\r\n const planContent = generatePlan({\r\n featureId,\r\n featureTitle: title,\r\n overview: description,\r\n });\r\n await fs.writeFile(path.join(featurePath, 'plan.md'), planContent, 'utf-8');\r\n logger.info(`✅ 계획 생성: ${featurePath}/plan.md`);\r\n }\r\n\r\n // tasks.md 생성\r\n if (options.tasks || options.all) {\r\n const tasksContent = generateTasks({\r\n featureId,\r\n featureTitle: title,\r\n tasks: [\r\n { title: '기반 구조 설정', priority: 'high' },\r\n { title: '핵심 기능 구현', priority: 'high' },\r\n { title: '테스트 작성', priority: 'medium' },\r\n { title: '문서 업데이트', priority: 'low' },\r\n ],\r\n });\r\n await fs.writeFile(path.join(featurePath, 'tasks.md'), tasksContent, 'utf-8');\r\n logger.info(`✅ 작업 분해 생성: ${featurePath}/tasks.md`);\r\n }\r\n\r\n // 체크리스트 생성\r\n if (options.checklist || options.all) {\r\n const checklistContent = generateFullChecklistMarkdown();\r\n await fs.writeFile(path.join(featurePath, 'checklist.md'), checklistContent, 'utf-8');\r\n logger.info(`✅ 체크리스트 생성: ${featurePath}/checklist.md`);\r\n }\r\n\r\n logger.info('');\r\n logger.info(`🎉 기능 '${featureId}' 생성 완료!`);\r\n logger.info('');\r\n logger.info('다음 단계:');\r\n logger.info(` 1. ${featurePath}/spec.md 편집`);\r\n if (!(options.plan || options.all)) {\r\n logger.info(' 2. sdd new plan ' + featureId + ' - 계획 작성');\r\n }\r\n if (!(options.tasks || options.all)) {\r\n logger.info(' 3. sdd new tasks ' + featureId + ' - 작업 분해');\r\n }\r\n logger.info(' 4. sdd validate - 명세 검증');\r\n } catch (error) {\r\n logger.error(`기능 생성 실패: ${error}`);\r\n process.exit(1);\r\n }\r\n}\r\n\r\n/**\r\n * plan 서브커맨드 핸들러\r\n */\r\nasync function handlePlan(\r\n feature: string,\r\n options: { title?: string }\r\n): Promise<void> {\r\n const cwd = process.cwd();\r\n const featurePath = path.join(cwd, '.sdd', 'specs', feature);\r\n\r\n try {\r\n // 기능 디렉토리 확인\r\n if (!(await fileExists(featurePath))) {\r\n logger.error(`기능 '${feature}'을 찾을 수 없습니다.`);\r\n process.exit(1);\r\n }\r\n\r\n // spec.md에서 제목 추출 시도\r\n let title = options.title || feature;\r\n const specPath = path.join(featurePath, 'spec.md');\r\n if (await fileExists(specPath)) {\r\n const specContent = await fs.readFile(specPath, 'utf-8');\r\n const titleMatch = specContent.match(/title:\\s*\"?([^\"\\n]+)\"?/);\r\n if (titleMatch) {\r\n title = titleMatch[1];\r\n }\r\n }\r\n\r\n // plan.md 생성\r\n const planContent = generatePlan({\r\n featureId: feature,\r\n featureTitle: title,\r\n overview: `${title} 구현 계획`,\r\n });\r\n\r\n await fs.writeFile(path.join(featurePath, 'plan.md'), planContent, 'utf-8');\r\n logger.info(`✅ 계획 생성: ${featurePath}/plan.md`);\r\n logger.info('');\r\n logger.info('다음 단계:');\r\n logger.info(` 1. ${featurePath}/plan.md 편집`);\r\n logger.info(' 2. sdd new tasks ' + feature + ' - 작업 분해');\r\n } catch (error) {\r\n logger.error(`계획 생성 실패: ${error}`);\r\n process.exit(1);\r\n }\r\n}\r\n\r\n/**\r\n * tasks 서브커맨드 핸들러\r\n */\r\nasync function handleTasks(feature: string): Promise<void> {\r\n const cwd = process.cwd();\r\n const featurePath = path.join(cwd, '.sdd', 'specs', feature);\r\n\r\n try {\r\n // 기능 디렉토리 확인\r\n if (!(await fileExists(featurePath))) {\r\n logger.error(`기능 '${feature}'을 찾을 수 없습니다.`);\r\n process.exit(1);\r\n }\r\n\r\n // spec.md에서 제목 추출 시도\r\n let title = feature;\r\n const specPath = path.join(featurePath, 'spec.md');\r\n if (await fileExists(specPath)) {\r\n const specContent = await fs.readFile(specPath, 'utf-8');\r\n const titleMatch = specContent.match(/title:\\s*\"?([^\"\\n]+)\"?/);\r\n if (titleMatch) {\r\n title = titleMatch[1];\r\n }\r\n }\r\n\r\n // tasks.md 생성\r\n const tasksContent = generateTasks({\r\n featureId: feature,\r\n featureTitle: title,\r\n tasks: [\r\n { title: '기반 구조 설정', priority: 'high' },\r\n { title: '핵심 기능 구현', priority: 'high' },\r\n { title: '테스트 작성', priority: 'medium' },\r\n { title: '문서 업데이트', priority: 'low' },\r\n ],\r\n });\r\n\r\n await fs.writeFile(path.join(featurePath, 'tasks.md'), tasksContent, 'utf-8');\r\n logger.info(`✅ 작업 분해 생성: ${featurePath}/tasks.md`);\r\n logger.info('');\r\n logger.info('다음 단계:');\r\n logger.info(` 1. ${featurePath}/tasks.md 편집`);\r\n logger.info(' 2. 각 작업 순차적으로 구현');\r\n } catch (error) {\r\n logger.error(`작업 분해 생성 실패: ${error}`);\r\n process.exit(1);\r\n }\r\n}\r\n\r\n/**\r\n * checklist 서브커맨드 핸들러\r\n */\r\nasync function handleChecklist(): Promise<void> {\r\n const cwd = process.cwd();\r\n const sddPath = path.join(cwd, '.sdd');\r\n\r\n try {\r\n if (!(await fileExists(sddPath))) {\r\n logger.error('.sdd 디렉토리가 없습니다. 먼저 sdd init을 실행해주세요.');\r\n process.exit(1);\r\n }\r\n\r\n const checklistContent = generateFullChecklistMarkdown();\r\n const outputPath = path.join(sddPath, 'checklist.md');\r\n await fs.writeFile(outputPath, checklistContent, 'utf-8');\r\n logger.info(`✅ 체크리스트 생성: ${outputPath}`);\r\n } catch (error) {\r\n logger.error(`체크리스트 생성 실패: ${error}`);\r\n process.exit(1);\r\n }\r\n}\r\n\r\n/**\r\n * counter 서브커맨드 핸들러\r\n */\r\nasync function handleCounter(options: {\r\n peek?: boolean;\r\n history?: boolean;\r\n set?: string;\r\n}): Promise<void> {\r\n const cwd = process.cwd();\r\n const sddPath = path.join(cwd, '.sdd');\r\n\r\n if (!(await fileExists(sddPath))) {\r\n logger.error('.sdd 디렉토리가 없습니다. 먼저 sdd init을 실행해주세요.');\r\n process.exit(1);\r\n }\r\n\r\n // 다음 번호 확인\r\n if (options.peek) {\r\n const result = await peekNextFeatureNumber(sddPath);\r\n if (result.success) {\r\n const paddedNumber = String(result.data).padStart(3, '0');\r\n logger.info(`다음 기능 번호: #${paddedNumber}`);\r\n logger.info(`브랜치 형식: feature/${paddedNumber}-<name>`);\r\n } else {\r\n logger.error(`카운터 조회 실패: ${result.error.message}`);\r\n process.exit(1);\r\n }\r\n return;\r\n }\r\n\r\n // 이력 조회\r\n if (options.history) {\r\n const result = await getFeatureHistory(sddPath);\r\n if (result.success) {\r\n if (result.data.length === 0) {\r\n logger.info('생성된 기능 이력이 없습니다.');\r\n } else {\r\n logger.info('=== 기능 생성 이력 ===');\r\n logger.info('');\r\n for (const entry of result.data) {\r\n const date = new Date(entry.createdAt).toLocaleDateString('ko-KR');\r\n logger.info(`#${String(entry.number).padStart(3, '0')} ${entry.name}`);\r\n logger.info(` ID: ${entry.fullId}`);\r\n logger.info(` 생성일: ${date}`);\r\n logger.info('');\r\n }\r\n }\r\n } else {\r\n logger.error(`이력 조회 실패: ${result.error.message}`);\r\n process.exit(1);\r\n }\r\n return;\r\n }\r\n\r\n // 번호 설정\r\n if (options.set) {\r\n const nextNumber = parseInt(options.set, 10);\r\n if (isNaN(nextNumber) || nextNumber < 1) {\r\n logger.error('유효한 번호를 입력해주세요 (1 이상의 정수)');\r\n process.exit(1);\r\n }\r\n\r\n const { setNextFeatureNumber } = await import('../../core/new/index.js');\r\n const result = await setNextFeatureNumber(sddPath, nextNumber);\r\n if (result.success) {\r\n logger.info(`다음 기능 번호가 #${String(nextNumber).padStart(3, '0')}로 설정되었습니다.`);\r\n } else {\r\n logger.error(`번호 설정 실패: ${result.error.message}`);\r\n process.exit(1);\r\n }\r\n return;\r\n }\r\n\r\n // 기본: 현재 상태 표시\r\n const peekResult = await peekNextFeatureNumber(sddPath);\r\n const historyResult = await getFeatureHistory(sddPath);\r\n\r\n if (peekResult.success && historyResult.success) {\r\n logger.info('=== 기능 번호 카운터 상태 ===');\r\n logger.info('');\r\n logger.info(`다음 번호: #${String(peekResult.data).padStart(3, '0')}`);\r\n logger.info(`생성된 기능 수: ${historyResult.data.length}개`);\r\n logger.info('');\r\n logger.info('옵션:');\r\n logger.info(' --peek 다음 번호 확인');\r\n logger.info(' --history 생성 이력 조회');\r\n logger.info(' --set <n> 다음 번호 설정');\r\n } else {\r\n logger.error('카운터 상태 조회 실패');\r\n process.exit(1);\r\n }\r\n}\r\n","/**\r\n * 유틸리티 모듈 내보내기\r\n */\r\nexport * from './fs.js';\r\nexport * as logger from './logger.js';\r\n","/**\r\n * Constitution 관련 Zod 스키마 정의\r\n */\r\nimport { z } from 'zod';\r\n\r\n/**\r\n * 시맨틱 버전 스키마\r\n */\r\nexport const SemanticVersionSchema = z.string().regex(\r\n /^\\d+\\.\\d+\\.\\d+$/,\r\n '버전 형식: MAJOR.MINOR.PATCH (예: 1.2.3)'\r\n);\r\nexport type SemanticVersion = z.infer<typeof SemanticVersionSchema>;\r\n\r\n/**\r\n * 버전 범프 유형\r\n */\r\nexport const VersionBumpType = ['major', 'minor', 'patch'] as const;\r\nexport type VersionBumpType = (typeof VersionBumpType)[number];\r\n\r\n/**\r\n * Constitution 메타데이터\r\n */\r\nexport const ConstitutionMetadataSchema = z.object({\r\n version: SemanticVersionSchema,\r\n created: z.string(),\r\n updated: z.string().optional(),\r\n});\r\nexport type ConstitutionMetadata = z.infer<typeof ConstitutionMetadataSchema>;\r\n\r\n/**\r\n * 원칙 레벨\r\n */\r\nexport const PrincipleLevelSchema = z.enum(['core', 'technical', 'forbidden']);\r\nexport type PrincipleLevel = z.infer<typeof PrincipleLevelSchema>;\r\n\r\n/**\r\n * 원칙\r\n */\r\nexport const PrincipleSchema = z.object({\r\n id: z.string(),\r\n title: z.string(),\r\n description: z.string(),\r\n level: PrincipleLevelSchema,\r\n rules: z.array(z.string()),\r\n});\r\nexport type Principle = z.infer<typeof PrincipleSchema>;\r\n\r\n/**\r\n * 파싱된 Constitution\r\n */\r\nexport const ParsedConstitutionSchema = z.object({\r\n projectName: z.string(),\r\n metadata: ConstitutionMetadataSchema,\r\n description: z.string().optional(),\r\n principles: z.array(PrincipleSchema),\r\n forbidden: z.array(z.string()),\r\n techStack: z.array(z.string()),\r\n qualityStandards: z.array(z.string()),\r\n rawContent: z.string(),\r\n});\r\nexport type ParsedConstitution = z.infer<typeof ParsedConstitutionSchema>;\r\n\r\n/**\r\n * CHANGELOG 항목 유형\r\n */\r\nexport const ChangeTypeSchema = z.enum(['added', 'changed', 'deprecated', 'removed', 'fixed']);\r\nexport type ChangeType = z.infer<typeof ChangeTypeSchema>;\r\n\r\n/**\r\n * CHANGELOG 항목\r\n */\r\nexport const ChangelogEntrySchema = z.object({\r\n version: SemanticVersionSchema,\r\n date: z.string(),\r\n changes: z.array(z.object({\r\n type: ChangeTypeSchema,\r\n description: z.string(),\r\n })),\r\n reason: z.string().optional(),\r\n});\r\nexport type ChangelogEntry = z.infer<typeof ChangelogEntrySchema>;\r\n\r\n/**\r\n * 버전 파싱\r\n */\r\nexport function parseVersion(version: string): { major: number; minor: number; patch: number } | null {\r\n const match = version.match(/^(\\d+)\\.(\\d+)\\.(\\d+)$/);\r\n if (!match) return null;\r\n return {\r\n major: parseInt(match[1], 10),\r\n minor: parseInt(match[2], 10),\r\n patch: parseInt(match[3], 10),\r\n };\r\n}\r\n\r\n/**\r\n * 버전 범프\r\n */\r\nexport function bumpVersion(version: string, type: VersionBumpType): string {\r\n const parsed = parseVersion(version);\r\n if (!parsed) return '1.0.0';\r\n\r\n switch (type) {\r\n case 'major':\r\n return `${parsed.major + 1}.0.0`;\r\n case 'minor':\r\n return `${parsed.major}.${parsed.minor + 1}.0`;\r\n case 'patch':\r\n return `${parsed.major}.${parsed.minor}.${parsed.patch + 1}`;\r\n }\r\n}\r\n\r\n/**\r\n * 버전 비교 (a > b: 1, a < b: -1, a === b: 0)\r\n */\r\nexport function compareVersions(a: string, b: string): number {\r\n const pa = parseVersion(a);\r\n const pb = parseVersion(b);\r\n\r\n if (!pa || !pb) return 0;\r\n\r\n if (pa.major !== pb.major) return pa.major > pb.major ? 1 : -1;\r\n if (pa.minor !== pb.minor) return pa.minor > pb.minor ? 1 : -1;\r\n if (pa.patch !== pb.patch) return pa.patch > pb.patch ? 1 : -1;\r\n return 0;\r\n}\r\n","/**\r\n * Constitution 파서\r\n */\r\nimport matter from 'gray-matter';\r\nimport {\r\n ParsedConstitution,\r\n ConstitutionMetadataSchema,\r\n Principle,\r\n type ConstitutionMetadata,\r\n} from './schemas.js';\r\nimport { Result, success, failure } from '../../types/index.js';\r\nimport { ValidationError, ErrorCode } from '../../errors/index.js';\r\nimport { extractRfc2119Keywords } from '../spec/schemas.js';\r\n\r\n/**\r\n * Constitution 마크다운 파싱\r\n */\r\nexport function parseConstitution(content: string): Result<ParsedConstitution, ValidationError> {\r\n try {\r\n // 1. Frontmatter 파싱\r\n const { data: rawMeta, content: body } = matter(content);\r\n\r\n // 2. 메타데이터 검증\r\n const metaResult = ConstitutionMetadataSchema.safeParse({\r\n version: rawMeta.version ?? '1.0.0',\r\n created: rawMeta.created ? formatDate(rawMeta.created) : formatDate(new Date()),\r\n updated: rawMeta.updated ? formatDate(rawMeta.updated) : undefined,\r\n });\r\n\r\n if (!metaResult.success) {\r\n const errors = metaResult.error.errors.map((e) => e.message).join(', ');\r\n return failure(new ValidationError(ErrorCode.CONSTITUTION_PARSE_ERROR, `메타데이터 오류: ${errors}`));\r\n }\r\n const metadata: ConstitutionMetadata = metaResult.data;\r\n\r\n // 3. 프로젝트명 추출\r\n const projectMatch = body.match(/^#\\s+Constitution:\\s*(.+)$/m);\r\n if (!projectMatch) {\r\n return failure(new ValidationError(\r\n ErrorCode.CONSTITUTION_PARSE_ERROR,\r\n '프로젝트명을 찾을 수 없습니다 (# Constitution: 프로젝트명)'\r\n ));\r\n }\r\n const projectName = projectMatch[1].trim();\r\n\r\n // 4. 설명 추출\r\n const descMatch = body.match(/^#\\s+Constitution:.+\\n+>\\s*(.+)$/m);\r\n const description = descMatch?.[1]?.trim();\r\n\r\n // 5. 원칙 추출\r\n const principles = parsePrinciples(body);\r\n\r\n // 6. 금지 사항 추출\r\n const forbidden = parseForbidden(body);\r\n\r\n // 7. 기술 스택 추출\r\n const techStack = parseTechStack(body);\r\n\r\n // 8. 품질 기준 추출\r\n const qualityStandards = parseQualityStandards(body);\r\n\r\n return success({\r\n projectName,\r\n metadata,\r\n description,\r\n principles,\r\n forbidden,\r\n techStack,\r\n qualityStandards,\r\n rawContent: content,\r\n });\r\n } catch (error) {\r\n const message = error instanceof Error ? error.message : String(error);\r\n return failure(new ValidationError(ErrorCode.CONSTITUTION_PARSE_ERROR, message));\r\n }\r\n}\r\n\r\n/**\r\n * 날짜 포맷팅\r\n */\r\nfunction formatDate(date: Date | string): string {\r\n if (typeof date === 'string') return date;\r\n return date.toISOString().split('T')[0];\r\n}\r\n\r\n/**\r\n * 원칙 파싱\r\n */\r\nfunction parsePrinciples(content: string): Principle[] {\r\n const principles: Principle[] = [];\r\n\r\n // ## 핵심 원칙 또는 ## 원칙 섹션 찾기\r\n const principlesSectionMatch = content.match(/##\\s+(?:핵심\\s*)?원칙([\\s\\S]*?)(?=\\n##\\s+[^#]|\\n---|\\n$)/i);\r\n if (!principlesSectionMatch) return principles;\r\n\r\n const section = principlesSectionMatch[1];\r\n\r\n // ### N. 원칙명 형태의 섹션을 분리\r\n const sectionParts = section.split(/(?=###\\s+\\d+\\.)/);\r\n\r\n for (const part of sectionParts) {\r\n const headerMatch = part.match(/###\\s+(\\d+)\\.\\s*(.+)/);\r\n if (!headerMatch) continue;\r\n\r\n const id = headerMatch[1];\r\n const title = headerMatch[2].trim();\r\n\r\n // 규칙 추출 (- 로 시작하는 라인)\r\n const rules: string[] = [];\r\n const ruleRegex = /-\\s+(.+)/g;\r\n let ruleMatch: RegExpExecArray | null;\r\n\r\n while ((ruleMatch = ruleRegex.exec(part)) !== null) {\r\n rules.push(ruleMatch[1].trim());\r\n }\r\n\r\n // 레벨 결정\r\n let level: 'core' | 'technical' | 'forbidden' = 'core';\r\n if (title.toLowerCase().includes('기술') || title.toLowerCase().includes('technical')) {\r\n level = 'technical';\r\n }\r\n\r\n principles.push({\r\n id: `P${id}`,\r\n title,\r\n description: title,\r\n level,\r\n rules,\r\n });\r\n }\r\n\r\n return principles;\r\n}\r\n\r\n/**\r\n * 금지 사항 파싱\r\n */\r\nfunction parseForbidden(content: string): string[] {\r\n const forbidden: string[] = [];\r\n\r\n // ## 금지 사항 또는 ## 금지 섹션 찾기\r\n const forbiddenSectionMatch = content.match(/##\\s+금지\\s*(?:사항)?([\\s\\S]*?)(?=\\n##|\\n---|\\n$)/i);\r\n if (!forbiddenSectionMatch) return forbidden;\r\n\r\n const section = forbiddenSectionMatch[1];\r\n\r\n // - 로 시작하는 라인 추출\r\n const ruleRegex = /-\\s+(.+?)(?:\\n|$)/g;\r\n let match: RegExpExecArray | null;\r\n\r\n while ((match = ruleRegex.exec(section)) !== null) {\r\n const rule = match[1].trim();\r\n // SHALL NOT 또는 MUST NOT이 포함된 규칙만\r\n if (/SHALL\\s+NOT|MUST\\s+NOT/i.test(rule)) {\r\n forbidden.push(rule);\r\n }\r\n }\r\n\r\n return forbidden;\r\n}\r\n\r\n/**\r\n * 기술 스택 파싱\r\n */\r\nfunction parseTechStack(content: string): string[] {\r\n const techStack: string[] = [];\r\n\r\n // ## 기술 스택 섹션 찾기\r\n const techSectionMatch = content.match(/##\\s+기술\\s*스택([\\s\\S]*?)(?=\\n##|\\n---|\\n$)/i);\r\n if (!techSectionMatch) return techStack;\r\n\r\n const section = techSectionMatch[1];\r\n\r\n // - Category: Value 형태 추출\r\n const techRegex = /-\\s+(.+?)(?:\\n|$)/g;\r\n let match: RegExpExecArray | null;\r\n\r\n while ((match = techRegex.exec(section)) !== null) {\r\n techStack.push(match[1].trim());\r\n }\r\n\r\n return techStack;\r\n}\r\n\r\n/**\r\n * 품질 기준 파싱\r\n */\r\nfunction parseQualityStandards(content: string): string[] {\r\n const standards: string[] = [];\r\n\r\n // ## 품질 기준 섹션 찾기\r\n const qualitySectionMatch = content.match(/##\\s+품질\\s*기준([\\s\\S]*?)(?=\\n##|\\n---|\\n$)/i);\r\n if (!qualitySectionMatch) return standards;\r\n\r\n const section = qualitySectionMatch[1];\r\n\r\n // - 로 시작하는 라인 추출\r\n const ruleRegex = /-\\s+(.+?)(?:\\n|$)/g;\r\n let match: RegExpExecArray | null;\r\n\r\n while ((match = ruleRegex.exec(section)) !== null) {\r\n standards.push(match[1].trim());\r\n }\r\n\r\n return standards;\r\n}\r\n\r\n/**\r\n * Constitution 검증\r\n */\r\nexport function validateConstitution(constitution: ParsedConstitution): Result<true, ValidationError> {\r\n // 최소 요구사항 검증\r\n if (!constitution.projectName) {\r\n return failure(new ValidationError(\r\n ErrorCode.CONSTITUTION_PARSE_ERROR,\r\n '프로젝트명이 없습니다'\r\n ));\r\n }\r\n\r\n // 원칙이 하나 이상 있어야 함\r\n if (constitution.principles.length === 0 && constitution.forbidden.length === 0) {\r\n return failure(new ValidationError(\r\n ErrorCode.CONSTITUTION_PARSE_ERROR,\r\n '원칙이나 금지 사항이 최소 하나 이상 필요합니다'\r\n ));\r\n }\r\n\r\n return success(true);\r\n}\r\n","/**\r\n * CHANGELOG 관리\r\n */\r\nimport { ChangelogEntry, ChangeType, bumpVersion, type VersionBumpType } from './schemas.js';\r\nimport { Result, success, failure } from '../../types/index.js';\r\nimport { ValidationError, ErrorCode } from '../../errors/index.js';\r\n\r\n/**\r\n * CHANGELOG 헤더\r\n */\r\nconst CHANGELOG_HEADER = `# Constitution Changelog\r\n\r\nAll notable changes to the Constitution will be documented in this file.\r\n\r\n`;\r\n\r\n/**\r\n * CHANGELOG 생성\r\n */\r\nexport function generateChangelog(entries: ChangelogEntry[]): string {\r\n let content = CHANGELOG_HEADER;\r\n\r\n for (const entry of entries) {\r\n content += formatChangelogEntry(entry);\r\n content += '\\n---\\n\\n';\r\n }\r\n\r\n return content;\r\n}\r\n\r\n/**\r\n * CHANGELOG 항목 포맷팅\r\n */\r\nexport function formatChangelogEntry(entry: ChangelogEntry): string {\r\n let content = `## [${entry.version}] - ${entry.date}\\n\\n`;\r\n\r\n // 변경 유형별 그룹화\r\n const grouped: Record<ChangeType, string[]> = {\r\n added: [],\r\n changed: [],\r\n deprecated: [],\r\n removed: [],\r\n fixed: [],\r\n };\r\n\r\n for (const change of entry.changes) {\r\n grouped[change.type].push(change.description);\r\n }\r\n\r\n // 그룹별 출력\r\n const typeLabels: Record<ChangeType, string> = {\r\n added: 'Added',\r\n changed: 'Changed',\r\n deprecated: 'Deprecated',\r\n removed: 'Removed',\r\n fixed: 'Fixed',\r\n };\r\n\r\n for (const [type, items] of Object.entries(grouped)) {\r\n if (items.length > 0) {\r\n content += `### ${typeLabels[type as ChangeType]}\\n`;\r\n for (const item of items) {\r\n content += `- ${item}\\n`;\r\n }\r\n content += '\\n';\r\n }\r\n }\r\n\r\n // 변경 사유\r\n if (entry.reason) {\r\n content += `### Reason\\n- ${entry.reason}\\n\\n`;\r\n }\r\n\r\n return content;\r\n}\r\n\r\n/**\r\n * CHANGELOG 파싱\r\n */\r\nexport function parseChangelog(content: string): Result<ChangelogEntry[], ValidationError> {\r\n const entries: ChangelogEntry[] = [];\r\n\r\n // ## [version] - date 형태 찾기\r\n const entryRegex = /##\\s+\\[(\\d+\\.\\d+\\.\\d+)\\]\\s+-\\s+(\\d{4}-\\d{2}-\\d{2})([\\s\\S]*?)(?=\\n##\\s+\\[|\\n---|\\n$)/g;\r\n let match: RegExpExecArray | null;\r\n\r\n while ((match = entryRegex.exec(content)) !== null) {\r\n const version = match[1];\r\n const date = match[2];\r\n const entryContent = match[3];\r\n\r\n const changes: { type: ChangeType; description: string }[] = [];\r\n let reason: string | undefined;\r\n\r\n // 변경 유형별 파싱\r\n const typeRegex = /###\\s+(Added|Changed|Deprecated|Removed|Fixed|Reason)\\n([\\s\\S]*?)(?=\\n###|\\n##|\\n---|\\n$)/gi;\r\n let typeMatch: RegExpExecArray | null;\r\n\r\n while ((typeMatch = typeRegex.exec(entryContent)) !== null) {\r\n const typeLabel = typeMatch[1].toLowerCase();\r\n const typeContent = typeMatch[2];\r\n\r\n if (typeLabel === 'reason') {\r\n const reasonMatch = typeContent.match(/-\\s+(.+)/);\r\n if (reasonMatch) {\r\n reason = reasonMatch[1].trim();\r\n }\r\n } else {\r\n // 항목 추출\r\n const itemRegex = /-\\s+(.+?)(?:\\n|$)/g;\r\n let itemMatch: RegExpExecArray | null;\r\n\r\n while ((itemMatch = itemRegex.exec(typeContent)) !== null) {\r\n changes.push({\r\n type: typeLabel as ChangeType,\r\n description: itemMatch[1].trim(),\r\n });\r\n }\r\n }\r\n }\r\n\r\n entries.push({ version, date, changes, reason });\r\n }\r\n\r\n return success(entries);\r\n}\r\n\r\n/**\r\n * 새 CHANGELOG 항목 생성\r\n */\r\nexport function createChangelogEntry(\r\n currentVersion: string,\r\n bumpType: VersionBumpType,\r\n changes: { type: ChangeType; description: string }[],\r\n reason?: string\r\n): ChangelogEntry {\r\n const newVersion = bumpVersion(currentVersion, bumpType);\r\n const today = new Date().toISOString().split('T')[0];\r\n\r\n return {\r\n version: newVersion,\r\n date: today,\r\n changes,\r\n reason,\r\n };\r\n}\r\n\r\n/**\r\n * 버전 범프 유형 추천\r\n */\r\nexport function suggestBumpType(changes: { type: ChangeType; description: string }[]): VersionBumpType {\r\n // removed나 breaking change가 있으면 MAJOR\r\n for (const change of changes) {\r\n if (change.type === 'removed') return 'major';\r\n if (change.description.toLowerCase().includes('breaking')) return 'major';\r\n // 기존 규칙 변경도 MAJOR\r\n if (change.type === 'changed' &&\r\n (change.description.includes('→') || change.description.includes('->'))) {\r\n return 'major';\r\n }\r\n }\r\n\r\n // added가 있으면 MINOR\r\n if (changes.some((c) => c.type === 'added')) return 'minor';\r\n\r\n // 그 외 PATCH\r\n return 'patch';\r\n}\r\n","/**\r\n * sdd status 명령어 - 프로젝트 상태 조회\r\n */\r\nimport { Command } from 'commander';\r\nimport path from 'node:path';\r\nimport { promises as fs } from 'node:fs';\r\nimport { logger } from '../../utils/index.js';\r\nimport { fileExists, readDir } from '../../utils/fs.js';\r\nimport { parseSpecMetadata } from '../../core/new/spec-generator.js';\r\nimport { parseTasks, getNextTask } from '../../core/new/task-generator.js';\r\nimport { listPendingChanges, listArchives } from '../../core/change/archive.js';\r\nimport { getCurrentBranch, listFeatureBranches } from '../../core/new/branch.js';\r\n\r\n/**\r\n * status 명령어 등록\r\n */\r\nexport function registerStatusCommand(program: Command): void {\r\n program\r\n .command('status')\r\n .description('SDD 프로젝트 상태 조회')\r\n .option('--json', 'JSON 형식으로 출력')\r\n .option('--verbose', '상세 정보 출력')\r\n .action(async (options) => {\r\n await handleStatus(options);\r\n });\r\n}\r\n\r\ninterface FeatureInfo {\r\n id: string;\r\n title: string;\r\n status: string;\r\n hasSpec: boolean;\r\n hasPlan: boolean;\r\n hasTasks: boolean;\r\n taskProgress?: {\r\n completed: number;\r\n total: number;\r\n };\r\n}\r\n\r\ninterface ProjectStatus {\r\n initialized: boolean;\r\n hasConstitution: boolean;\r\n hasAgents: boolean;\r\n features: FeatureInfo[];\r\n pendingChanges: string[];\r\n archivedChanges: number;\r\n currentBranch?: string;\r\n featureBranches: string[];\r\n}\r\n\r\n/**\r\n * status 명령어 핸들러\r\n */\r\nasync function handleStatus(options: { json?: boolean; verbose?: boolean }): Promise<void> {\r\n const cwd = process.cwd();\r\n const sddPath = path.join(cwd, '.sdd');\r\n\r\n const status: ProjectStatus = {\r\n initialized: false,\r\n hasConstitution: false,\r\n hasAgents: false,\r\n features: [],\r\n pendingChanges: [],\r\n archivedChanges: 0,\r\n featureBranches: [],\r\n };\r\n\r\n // .sdd 디렉토리 확인\r\n status.initialized = await fileExists(sddPath);\r\n\r\n if (!status.initialized) {\r\n if (options.json) {\r\n console.log(JSON.stringify(status, null, 2));\r\n } else {\r\n logger.warn('SDD 프로젝트가 초기화되지 않았습니다.');\r\n logger.info('sdd init 명령어로 초기화하세요.');\r\n }\r\n return;\r\n }\r\n\r\n // 헌법 확인\r\n status.hasConstitution = await fileExists(path.join(sddPath, 'constitution.md'));\r\n\r\n // AGENTS.md 확인\r\n status.hasAgents = await fileExists(path.join(sddPath, 'AGENTS.md'));\r\n\r\n // 기능 스펙 조회\r\n const specsPath = path.join(sddPath, 'specs');\r\n if (await fileExists(specsPath)) {\r\n const specsResult = await readDir(specsPath);\r\n if (specsResult.success) {\r\n for (const entry of specsResult.data) {\r\n const featurePath = path.join(specsPath, entry);\r\n const stat = await fs.stat(featurePath);\r\n\r\n if (stat.isDirectory()) {\r\n const featureInfo = await getFeatureInfo(entry, featurePath);\r\n status.features.push(featureInfo);\r\n }\r\n }\r\n }\r\n }\r\n\r\n // 대기 중인 변경 조회\r\n const pendingResult = await listPendingChanges(sddPath);\r\n if (pendingResult.success) {\r\n status.pendingChanges = pendingResult.data;\r\n }\r\n\r\n // 아카이브된 변경 수 조회\r\n const archiveResult = await listArchives(sddPath);\r\n if (archiveResult.success) {\r\n status.archivedChanges = archiveResult.data.length;\r\n }\r\n\r\n // Git 브랜치 정보\r\n const currentBranchResult = await getCurrentBranch(cwd);\r\n if (currentBranchResult.success) {\r\n status.currentBranch = currentBranchResult.data;\r\n }\r\n\r\n const featureBranchesResult = await listFeatureBranches(cwd);\r\n if (featureBranchesResult.success) {\r\n status.featureBranches = featureBranchesResult.data;\r\n }\r\n\r\n // 출력\r\n if (options.json) {\r\n console.log(JSON.stringify(status, null, 2));\r\n } else {\r\n printStatus(status, options.verbose);\r\n }\r\n}\r\n\r\n/**\r\n * 기능 정보 조회\r\n */\r\nasync function getFeatureInfo(id: string, featurePath: string): Promise<FeatureInfo> {\r\n const info: FeatureInfo = {\r\n id,\r\n title: id,\r\n status: 'unknown',\r\n hasSpec: false,\r\n hasPlan: false,\r\n hasTasks: false,\r\n };\r\n\r\n // spec.md 확인\r\n const specPath = path.join(featurePath, 'spec.md');\r\n if (await fileExists(specPath)) {\r\n info.hasSpec = true;\r\n const content = await fs.readFile(specPath, 'utf-8');\r\n const metadata = parseSpecMetadata(content);\r\n if (metadata) {\r\n info.title = metadata.title;\r\n info.status = metadata.status;\r\n }\r\n }\r\n\r\n // plan.md 확인\r\n info.hasPlan = await fileExists(path.join(featurePath, 'plan.md'));\r\n\r\n // tasks.md 확인\r\n const tasksPath = path.join(featurePath, 'tasks.md');\r\n if (await fileExists(tasksPath)) {\r\n info.hasTasks = true;\r\n const content = await fs.readFile(tasksPath, 'utf-8');\r\n const tasks = parseTasks(content);\r\n const completed = tasks.filter(t => t.status === 'completed').length;\r\n info.taskProgress = {\r\n completed,\r\n total: tasks.length,\r\n };\r\n }\r\n\r\n return info;\r\n}\r\n\r\n/**\r\n * 상태 출력\r\n */\r\nfunction printStatus(status: ProjectStatus, verbose?: boolean): void {\r\n console.log('');\r\n console.log('📊 SDD 프로젝트 상태');\r\n console.log('═'.repeat(40));\r\n console.log('');\r\n\r\n // 기본 정보\r\n console.log('📁 프로젝트 구조:');\r\n console.log(` ${status.hasConstitution ? '✅' : '❌'} constitution.md`);\r\n console.log(` ${status.hasAgents ? '✅' : '❌'} AGENTS.md`);\r\n console.log('');\r\n\r\n // 기능 목록\r\n if (status.features.length > 0) {\r\n console.log('📋 기능 목록:');\r\n for (const feature of status.features) {\r\n const statusIcon = getStatusIcon(feature.status);\r\n const files = [\r\n feature.hasSpec ? 'spec' : '',\r\n feature.hasPlan ? 'plan' : '',\r\n feature.hasTasks ? 'tasks' : '',\r\n ].filter(Boolean).join(', ');\r\n\r\n let progressStr = '';\r\n if (feature.taskProgress) {\r\n const { completed, total } = feature.taskProgress;\r\n const percent = total > 0 ? Math.round((completed / total) * 100) : 0;\r\n progressStr = ` [${completed}/${total} = ${percent}%]`;\r\n }\r\n\r\n console.log(` ${statusIcon} ${feature.title} (${feature.id})`);\r\n if (verbose) {\r\n console.log(` 상태: ${feature.status}, 파일: ${files}${progressStr}`);\r\n }\r\n }\r\n console.log('');\r\n } else {\r\n console.log('📋 기능: 없음');\r\n console.log(' sdd new <name> 명령어로 새 기능을 생성하세요.');\r\n console.log('');\r\n }\r\n\r\n // 변경 정보\r\n if (status.pendingChanges.length > 0) {\r\n console.log('📝 대기 중인 변경:');\r\n for (const change of status.pendingChanges) {\r\n console.log(` - ${change}`);\r\n }\r\n console.log('');\r\n }\r\n\r\n if (status.archivedChanges > 0 && verbose) {\r\n console.log(`📦 아카이브된 변경: ${status.archivedChanges}개`);\r\n console.log('');\r\n }\r\n\r\n // Git 정보\r\n if (status.currentBranch) {\r\n console.log(`🔀 현재 브랜치: ${status.currentBranch}`);\r\n if (status.featureBranches.length > 0 && verbose) {\r\n console.log(' 기능 브랜치:');\r\n for (const branch of status.featureBranches) {\r\n const isCurrent = branch === status.currentBranch;\r\n console.log(` ${isCurrent ? '→' : ' '} ${branch}`);\r\n }\r\n }\r\n console.log('');\r\n }\r\n\r\n // 다음 단계 안내\r\n console.log('💡 다음 단계:');\r\n if (status.features.length === 0) {\r\n console.log(' sdd new <name> - 새 기능 생성');\r\n } else {\r\n const inProgress = status.features.find(f => f.status === 'implementing');\r\n if (inProgress) {\r\n console.log(` ${inProgress.id} 기능 구현 중...`);\r\n if (inProgress.taskProgress) {\r\n const { completed, total } = inProgress.taskProgress;\r\n if (completed < total) {\r\n console.log(` sdd validate - 스펙 검증`);\r\n }\r\n }\r\n } else {\r\n const draft = status.features.find(f => f.status === 'draft');\r\n if (draft) {\r\n console.log(` ${draft.id} 기능 명세 작성 완료 후 /sdd:plan 실행`);\r\n }\r\n }\r\n }\r\n console.log('');\r\n}\r\n\r\n/**\r\n * 상태 아이콘\r\n */\r\nfunction getStatusIcon(status: string): string {\r\n switch (status) {\r\n case 'draft':\r\n return '📝';\r\n case 'specified':\r\n return '📄';\r\n case 'planned':\r\n return '📋';\r\n case 'tasked':\r\n return '✏️';\r\n case 'implementing':\r\n return '🔨';\r\n case 'completed':\r\n return '✅';\r\n default:\r\n return '❓';\r\n }\r\n}\r\n","/**\r\n * sdd list 명령어 - 항목 목록 조회\r\n */\r\nimport { Command } from 'commander';\r\nimport path from 'node:path';\r\nimport { promises as fs } from 'node:fs';\r\nimport { logger } from '../../utils/index.js';\r\nimport { fileExists, readDir } from '../../utils/fs.js';\r\nimport { parseSpecMetadata } from '../../core/new/spec-generator.js';\r\nimport { listPendingChanges, listArchives } from '../../core/change/archive.js';\r\n\r\n/**\r\n * list 명령어 등록\r\n */\r\nexport function registerListCommand(program: Command): void {\r\n const listCmd = program\r\n .command('list')\r\n .alias('ls')\r\n .description('항목 목록 조회');\r\n\r\n // features 서브커맨드\r\n listCmd\r\n .command('features')\r\n .alias('f')\r\n .description('기능 목록 조회')\r\n .option('--status <status>', '상태별 필터 (draft, specified, planned, etc.)')\r\n .action(async (options) => {\r\n await listFeatures(options);\r\n });\r\n\r\n // changes 서브커맨드\r\n listCmd\r\n .command('changes')\r\n .alias('c')\r\n .description('변경 제안 목록 조회')\r\n .option('--pending', '대기 중인 변경만 표시')\r\n .option('--archived', '아카이브된 변경만 표시')\r\n .action(async (options) => {\r\n await listChanges(options);\r\n });\r\n\r\n // specs 서브커맨드\r\n listCmd\r\n .command('specs')\r\n .alias('s')\r\n .description('스펙 파일 목록 조회')\r\n .action(async () => {\r\n await listSpecs();\r\n });\r\n\r\n // templates 서브커맨드\r\n listCmd\r\n .command('templates')\r\n .alias('t')\r\n .description('템플릿 목록 조회')\r\n .action(async () => {\r\n await listTemplates();\r\n });\r\n\r\n // 기본 동작 (전체 요약)\r\n listCmd.action(async () => {\r\n await listSummary();\r\n });\r\n}\r\n\r\n/**\r\n * 기능 목록 조회\r\n */\r\nasync function listFeatures(options: { status?: string }): Promise<void> {\r\n const cwd = process.cwd();\r\n const specsPath = path.join(cwd, '.sdd', 'specs');\r\n\r\n if (!(await fileExists(specsPath))) {\r\n logger.warn('스펙 디렉토리가 없습니다. sdd init을 먼저 실행하세요.');\r\n return;\r\n }\r\n\r\n const result = await readDir(specsPath);\r\n if (!result.success) {\r\n logger.error('스펙 디렉토리를 읽을 수 없습니다.');\r\n return;\r\n }\r\n\r\n const features: Array<{ id: string; title: string; status: string }> = [];\r\n\r\n for (const entry of result.data) {\r\n const featurePath = path.join(specsPath, entry);\r\n const stat = await fs.stat(featurePath);\r\n\r\n if (stat.isDirectory()) {\r\n const specPath = path.join(featurePath, 'spec.md');\r\n if (await fileExists(specPath)) {\r\n const content = await fs.readFile(specPath, 'utf-8');\r\n const metadata = parseSpecMetadata(content);\r\n if (metadata) {\r\n if (!options.status || metadata.status === options.status) {\r\n features.push({\r\n id: entry,\r\n title: metadata.title,\r\n status: metadata.status,\r\n });\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (features.length === 0) {\r\n logger.info('기능이 없습니다.');\r\n return;\r\n }\r\n\r\n console.log('');\r\n console.log('📋 기능 목록');\r\n console.log('─'.repeat(50));\r\n for (const f of features) {\r\n const statusIcon = getStatusIcon(f.status);\r\n console.log(`${statusIcon} ${f.title} (${f.id}) - ${f.status}`);\r\n }\r\n console.log('');\r\n}\r\n\r\n/**\r\n * 변경 목록 조회\r\n */\r\nasync function listChanges(options: { pending?: boolean; archived?: boolean }): Promise<void> {\r\n const cwd = process.cwd();\r\n const sddPath = path.join(cwd, '.sdd');\r\n\r\n if (!(await fileExists(sddPath))) {\r\n logger.warn('.sdd 디렉토리가 없습니다. sdd init을 먼저 실행하세요.');\r\n return;\r\n }\r\n\r\n console.log('');\r\n\r\n if (!options.archived) {\r\n const pendingResult = await listPendingChanges(sddPath);\r\n if (pendingResult.success && pendingResult.data.length > 0) {\r\n console.log('📝 대기 중인 변경');\r\n console.log('─'.repeat(30));\r\n for (const change of pendingResult.data) {\r\n console.log(` - ${change}`);\r\n }\r\n console.log('');\r\n } else if (!options.pending) {\r\n console.log('대기 중인 변경이 없습니다.');\r\n }\r\n }\r\n\r\n if (!options.pending) {\r\n const archiveResult = await listArchives(sddPath);\r\n if (archiveResult.success && archiveResult.data.length > 0) {\r\n console.log('📦 아카이브된 변경');\r\n console.log('─'.repeat(30));\r\n for (const archive of archiveResult.data) {\r\n console.log(` - ${archive}`);\r\n }\r\n console.log('');\r\n } else if (!options.archived) {\r\n console.log('아카이브된 변경이 없습니다.');\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * 스펙 파일 목록\r\n */\r\nasync function listSpecs(): Promise<void> {\r\n const cwd = process.cwd();\r\n const specsPath = path.join(cwd, '.sdd', 'specs');\r\n\r\n if (!(await fileExists(specsPath))) {\r\n logger.warn('스펙 디렉토리가 없습니다.');\r\n return;\r\n }\r\n\r\n console.log('');\r\n console.log('📄 스펙 파일 목록');\r\n console.log('─'.repeat(50));\r\n\r\n await walkSpecs(specsPath, '');\r\n console.log('');\r\n}\r\n\r\n/**\r\n * 스펙 디렉토리 순회\r\n */\r\nasync function walkSpecs(basePath: string, prefix: string): Promise<void> {\r\n const result = await readDir(basePath);\r\n if (!result.success) return;\r\n\r\n for (const entry of result.data) {\r\n const fullPath = path.join(basePath, entry);\r\n const stat = await fs.stat(fullPath);\r\n\r\n if (stat.isDirectory()) {\r\n console.log(`${prefix}📁 ${entry}/`);\r\n await walkSpecs(fullPath, prefix + ' ');\r\n } else if (entry.endsWith('.md')) {\r\n console.log(`${prefix}📄 ${entry}`);\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * 템플릿 목록\r\n */\r\nasync function listTemplates(): Promise<void> {\r\n const cwd = process.cwd();\r\n const templatesPath = path.join(cwd, '.sdd', 'templates');\r\n\r\n if (!(await fileExists(templatesPath))) {\r\n logger.warn('템플릿 디렉토리가 없습니다.');\r\n return;\r\n }\r\n\r\n const result = await readDir(templatesPath);\r\n if (!result.success) {\r\n logger.error('템플릿 디렉토리를 읽을 수 없습니다.');\r\n return;\r\n }\r\n\r\n console.log('');\r\n console.log('📑 템플릿 목록');\r\n console.log('─'.repeat(30));\r\n for (const template of result.data.filter(f => f.endsWith('.md'))) {\r\n console.log(` - ${template}`);\r\n }\r\n console.log('');\r\n}\r\n\r\n/**\r\n * 전체 요약\r\n */\r\nasync function listSummary(): Promise<void> {\r\n const cwd = process.cwd();\r\n const sddPath = path.join(cwd, '.sdd');\r\n\r\n if (!(await fileExists(sddPath))) {\r\n logger.warn('.sdd 디렉토리가 없습니다. sdd init을 먼저 실행하세요.');\r\n return;\r\n }\r\n\r\n console.log('');\r\n console.log('📊 SDD 프로젝트 요약');\r\n console.log('═'.repeat(40));\r\n\r\n // 기능 수\r\n const specsPath = path.join(sddPath, 'specs');\r\n let featureCount = 0;\r\n if (await fileExists(specsPath)) {\r\n const result = await readDir(specsPath);\r\n if (result.success) {\r\n for (const entry of result.data) {\r\n const stat = await fs.stat(path.join(specsPath, entry));\r\n if (stat.isDirectory()) featureCount++;\r\n }\r\n }\r\n }\r\n console.log(`📋 기능: ${featureCount}개`);\r\n\r\n // 변경 수\r\n const pendingResult = await listPendingChanges(sddPath);\r\n const pendingCount = pendingResult.success ? pendingResult.data.length : 0;\r\n console.log(`📝 대기 중인 변경: ${pendingCount}개`);\r\n\r\n const archiveResult = await listArchives(sddPath);\r\n const archiveCount = archiveResult.success ? archiveResult.data.length : 0;\r\n console.log(`📦 아카이브된 변경: ${archiveCount}개`);\r\n\r\n console.log('');\r\n console.log('상세 정보:');\r\n console.log(' sdd list features - 기능 목록');\r\n console.log(' sdd list changes - 변경 목록');\r\n console.log(' sdd list specs - 스펙 파일 목록');\r\n console.log(' sdd status - 프로젝트 상태');\r\n console.log('');\r\n}\r\n\r\n/**\r\n * 상태 아이콘\r\n */\r\nfunction getStatusIcon(status: string): string {\r\n switch (status) {\r\n case 'draft':\r\n return '📝';\r\n case 'specified':\r\n return '📄';\r\n case 'planned':\r\n return '📋';\r\n case 'tasked':\r\n return '✏️';\r\n case 'implementing':\r\n return '🔨';\r\n case 'completed':\r\n return '✅';\r\n default:\r\n return '❓';\r\n }\r\n}\r\n","/**\r\n * sdd constitution 명령어\r\n */\r\nimport { Command } from 'commander';\r\nimport path from 'node:path';\r\nimport { readFile, writeFile, fileExists } from '../../utils/fs.js';\r\nimport { ExitCode } from '../../errors/index.js';\r\nimport * as logger from '../../utils/logger.js';\r\nimport {\r\n parseConstitution,\r\n validateConstitution,\r\n bumpVersion,\r\n parseVersion,\r\n generateChangelog,\r\n parseChangelog,\r\n createChangelogEntry,\r\n suggestBumpType,\r\n type VersionBumpType,\r\n type ChangeType,\r\n type ChangelogEntry,\r\n} from '../../core/constitution/index.js';\r\n\r\n/**\r\n * constitution 명령어 등록\r\n */\r\nexport function registerConstitutionCommand(program: Command): void {\r\n const constitution = program\r\n .command('constitution')\r\n .description('Constitution(프로젝트 원칙) 관리');\r\n\r\n // show 서브커맨드\r\n constitution\r\n .command('show')\r\n .description('현재 Constitution 내용 표시')\r\n .option('--json', 'JSON 형식으로 출력')\r\n .action(async (options: { json?: boolean }) => {\r\n try {\r\n await runShow(options);\r\n } catch (error) {\r\n logger.error(error instanceof Error ? error.message : String(error));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n });\r\n\r\n // version 서브커맨드\r\n constitution\r\n .command('version')\r\n .description('현재 Constitution 버전 표시')\r\n .action(async () => {\r\n try {\r\n await runVersion();\r\n } catch (error) {\r\n logger.error(error instanceof Error ? error.message : String(error));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n });\r\n\r\n // bump 서브커맨드\r\n constitution\r\n .command('bump')\r\n .description('Constitution 버전 업데이트')\r\n .option('--major', 'MAJOR 버전 업데이트 (핵심 원칙 변경)')\r\n .option('--minor', 'MINOR 버전 업데이트 (새 원칙 추가)')\r\n .option('--patch', 'PATCH 버전 업데이트 (문구 수정)')\r\n .option('-m, --message <message>', '변경 사유')\r\n .action(async (options: { major?: boolean; minor?: boolean; patch?: boolean; message?: string }) => {\r\n try {\r\n await runBump(options);\r\n } catch (error) {\r\n logger.error(error instanceof Error ? error.message : String(error));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n });\r\n\r\n // history 서브커맨드\r\n constitution\r\n .command('history')\r\n .description('Constitution 변경 이력 조회')\r\n .option('-n, --count <count>', '표시할 항목 수', '10')\r\n .action(async (options: { count: string }) => {\r\n try {\r\n await runHistory(options);\r\n } catch (error) {\r\n logger.error(error instanceof Error ? error.message : String(error));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n });\r\n\r\n // validate 서브커맨드\r\n constitution\r\n .command('validate')\r\n .description('Constitution 형식 검증')\r\n .action(async () => {\r\n try {\r\n await runValidate();\r\n } catch (error) {\r\n logger.error(error instanceof Error ? error.message : String(error));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n });\r\n\r\n // 기본 동작 (서브커맨드 없이 실행 시)\r\n constitution.action(async () => {\r\n await runShow({});\r\n });\r\n}\r\n\r\n/**\r\n * Constitution 표시\r\n */\r\nasync function runShow(options: { json?: boolean }): Promise<void> {\r\n const cwd = process.cwd();\r\n const constitutionPath = path.join(cwd, '.sdd', 'constitution.md');\r\n\r\n if (!(await fileExists(constitutionPath))) {\r\n logger.error('Constitution이 없습니다. `sdd init`으로 프로젝트를 초기화하세요.');\r\n process.exit(ExitCode.FILE_NOT_FOUND);\r\n }\r\n\r\n const contentResult = await readFile(constitutionPath);\r\n if (!contentResult.success) {\r\n logger.error('Constitution 파일을 읽을 수 없습니다.');\r\n process.exit(ExitCode.FILE_SYSTEM_ERROR);\r\n }\r\n\r\n const parseResult = parseConstitution(contentResult.data);\r\n if (!parseResult.success) {\r\n logger.error(`Constitution 파싱 실패: ${parseResult.error.message}`);\r\n process.exit(ExitCode.VALIDATION_ERROR);\r\n }\r\n\r\n const constitution = parseResult.data;\r\n\r\n if (options.json) {\r\n console.log(JSON.stringify({\r\n projectName: constitution.projectName,\r\n version: constitution.metadata.version,\r\n created: constitution.metadata.created,\r\n updated: constitution.metadata.updated,\r\n principles: constitution.principles,\r\n forbidden: constitution.forbidden,\r\n techStack: constitution.techStack,\r\n qualityStandards: constitution.qualityStandards,\r\n }, null, 2));\r\n return;\r\n }\r\n\r\n // 콘솔 출력\r\n logger.info(`Constitution: ${constitution.projectName}`);\r\n logger.info(`버전: ${constitution.metadata.version}`);\r\n if (constitution.description) {\r\n logger.info(`설명: ${constitution.description}`);\r\n }\r\n logger.newline();\r\n\r\n if (constitution.principles.length > 0) {\r\n logger.info('핵심 원칙:');\r\n for (const principle of constitution.principles) {\r\n logger.listItem(`${principle.id}. ${principle.title}`);\r\n for (const rule of principle.rules) {\r\n logger.listItem(rule, 1);\r\n }\r\n }\r\n logger.newline();\r\n }\r\n\r\n if (constitution.forbidden.length > 0) {\r\n logger.info('금지 사항:');\r\n for (const item of constitution.forbidden) {\r\n logger.listItem(item);\r\n }\r\n logger.newline();\r\n }\r\n\r\n if (constitution.techStack.length > 0) {\r\n logger.info('기술 스택:');\r\n for (const tech of constitution.techStack) {\r\n logger.listItem(tech);\r\n }\r\n logger.newline();\r\n }\r\n\r\n if (constitution.qualityStandards.length > 0) {\r\n logger.info('품질 기준:');\r\n for (const standard of constitution.qualityStandards) {\r\n logger.listItem(standard);\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * 버전 표시\r\n */\r\nasync function runVersion(): Promise<void> {\r\n const cwd = process.cwd();\r\n const constitutionPath = path.join(cwd, '.sdd', 'constitution.md');\r\n\r\n if (!(await fileExists(constitutionPath))) {\r\n logger.error('Constitution이 없습니다.');\r\n process.exit(ExitCode.FILE_NOT_FOUND);\r\n }\r\n\r\n const contentResult = await readFile(constitutionPath);\r\n if (!contentResult.success) {\r\n logger.error('Constitution 파일을 읽을 수 없습니다.');\r\n process.exit(ExitCode.FILE_SYSTEM_ERROR);\r\n }\r\n\r\n const parseResult = parseConstitution(contentResult.data);\r\n if (!parseResult.success) {\r\n logger.error(`Constitution 파싱 실패: ${parseResult.error.message}`);\r\n process.exit(ExitCode.VALIDATION_ERROR);\r\n }\r\n\r\n console.log(parseResult.data.metadata.version);\r\n}\r\n\r\n/**\r\n * 버전 범프\r\n */\r\nasync function runBump(options: { major?: boolean; minor?: boolean; patch?: boolean; message?: string }): Promise<void> {\r\n const cwd = process.cwd();\r\n const constitutionPath = path.join(cwd, '.sdd', 'constitution.md');\r\n const changelogPath = path.join(cwd, '.sdd', 'CHANGELOG.md');\r\n\r\n if (!(await fileExists(constitutionPath))) {\r\n logger.error('Constitution이 없습니다.');\r\n process.exit(ExitCode.FILE_NOT_FOUND);\r\n }\r\n\r\n // 버전 범프 유형 결정\r\n let bumpType: VersionBumpType;\r\n if (options.major) {\r\n bumpType = 'major';\r\n } else if (options.minor) {\r\n bumpType = 'minor';\r\n } else if (options.patch) {\r\n bumpType = 'patch';\r\n } else {\r\n logger.error('버전 유형을 지정하세요: --major, --minor, 또는 --patch');\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n // Constitution 읽기\r\n const contentResult = await readFile(constitutionPath);\r\n if (!contentResult.success) {\r\n logger.error('Constitution 파일을 읽을 수 없습니다.');\r\n process.exit(ExitCode.FILE_SYSTEM_ERROR);\r\n }\r\n\r\n const parseResult = parseConstitution(contentResult.data);\r\n if (!parseResult.success) {\r\n logger.error(`Constitution 파싱 실패: ${parseResult.error.message}`);\r\n process.exit(ExitCode.VALIDATION_ERROR);\r\n }\r\n\r\n const currentVersion = parseResult.data.metadata.version;\r\n const newVersion = bumpVersion(currentVersion, bumpType);\r\n const today = new Date().toISOString().split('T')[0];\r\n\r\n // Constitution 업데이트\r\n let updatedContent = contentResult.data;\r\n\r\n // version 업데이트\r\n updatedContent = updatedContent.replace(\r\n /^version:\\s*.+$/m,\r\n `version: ${newVersion}`\r\n );\r\n\r\n // updated 필드 추가/업데이트\r\n if (/^updated:/m.test(updatedContent)) {\r\n updatedContent = updatedContent.replace(\r\n /^updated:\\s*.+$/m,\r\n `updated: ${today}`\r\n );\r\n } else {\r\n updatedContent = updatedContent.replace(\r\n /^(version:\\s*.+)$/m,\r\n `$1\\nupdated: ${today}`\r\n );\r\n }\r\n\r\n await writeFile(constitutionPath, updatedContent);\r\n\r\n // CHANGELOG 업데이트\r\n const changeType: ChangeType = bumpType === 'major' ? 'changed' : bumpType === 'minor' ? 'added' : 'fixed';\r\n const changeDescription = options.message || `Constitution ${bumpType} 업데이트`;\r\n\r\n const newEntry = createChangelogEntry(\r\n currentVersion,\r\n bumpType,\r\n [{ type: changeType, description: changeDescription }],\r\n options.message\r\n );\r\n\r\n let existingEntries: ChangelogEntry[] = [];\r\n if (await fileExists(changelogPath)) {\r\n const changelogContent = await readFile(changelogPath);\r\n if (changelogContent.success) {\r\n const parsed = parseChangelog(changelogContent.data);\r\n if (parsed.success) {\r\n existingEntries = parsed.data;\r\n }\r\n }\r\n }\r\n\r\n const allEntries = [newEntry, ...existingEntries];\r\n const newChangelog = generateChangelog(allEntries);\r\n await writeFile(changelogPath, newChangelog);\r\n\r\n logger.success(`Constitution 버전 업데이트: ${currentVersion} → ${newVersion}`);\r\n logger.info(`CHANGELOG 업데이트: ${changelogPath}`);\r\n}\r\n\r\n/**\r\n * 변경 이력 조회\r\n */\r\nasync function runHistory(options: { count: string }): Promise<void> {\r\n const cwd = process.cwd();\r\n const changelogPath = path.join(cwd, '.sdd', 'CHANGELOG.md');\r\n\r\n if (!(await fileExists(changelogPath))) {\r\n logger.warn('CHANGELOG가 없습니다. `sdd constitution bump`로 버전을 업데이트하면 생성됩니다.');\r\n return;\r\n }\r\n\r\n const contentResult = await readFile(changelogPath);\r\n if (!contentResult.success) {\r\n logger.error('CHANGELOG 파일을 읽을 수 없습니다.');\r\n process.exit(ExitCode.FILE_SYSTEM_ERROR);\r\n }\r\n\r\n const parseResult = parseChangelog(contentResult.data);\r\n if (!parseResult.success) {\r\n logger.error(`CHANGELOG 파싱 실패: ${parseResult.error.message}`);\r\n process.exit(ExitCode.VALIDATION_ERROR);\r\n }\r\n\r\n const count = parseInt(options.count, 10) || 10;\r\n const entries = parseResult.data.slice(0, count);\r\n\r\n if (entries.length === 0) {\r\n logger.info('변경 이력이 없습니다.');\r\n return;\r\n }\r\n\r\n logger.info('Constitution 변경 이력:');\r\n logger.newline();\r\n\r\n for (const entry of entries) {\r\n logger.info(`[${entry.version}] - ${entry.date}`);\r\n for (const change of entry.changes) {\r\n logger.listItem(`[${change.type.toUpperCase()}] ${change.description}`);\r\n }\r\n if (entry.reason) {\r\n logger.listItem(`사유: ${entry.reason}`, 1);\r\n }\r\n logger.newline();\r\n }\r\n}\r\n\r\n/**\r\n * Constitution 검증\r\n */\r\nasync function runValidate(): Promise<void> {\r\n const cwd = process.cwd();\r\n const constitutionPath = path.join(cwd, '.sdd', 'constitution.md');\r\n\r\n if (!(await fileExists(constitutionPath))) {\r\n logger.error('Constitution이 없습니다.');\r\n process.exit(ExitCode.FILE_NOT_FOUND);\r\n }\r\n\r\n const contentResult = await readFile(constitutionPath);\r\n if (!contentResult.success) {\r\n logger.error('Constitution 파일을 읽을 수 없습니다.');\r\n process.exit(ExitCode.FILE_SYSTEM_ERROR);\r\n }\r\n\r\n const parseResult = parseConstitution(contentResult.data);\r\n if (!parseResult.success) {\r\n logger.error(`Constitution 파싱 실패: ${parseResult.error.message}`);\r\n process.exit(ExitCode.VALIDATION_ERROR);\r\n }\r\n\r\n const validationResult = validateConstitution(parseResult.data);\r\n if (!validationResult.success) {\r\n logger.error(`Constitution 검증 실패: ${validationResult.error.message}`);\r\n process.exit(ExitCode.VALIDATION_ERROR);\r\n }\r\n\r\n logger.success('Constitution 검증 통과');\r\n logger.info(`프로젝트: ${parseResult.data.projectName}`);\r\n logger.info(`버전: ${parseResult.data.metadata.version}`);\r\n logger.info(`원칙 수: ${parseResult.data.principles.length}`);\r\n logger.info(`금지 사항 수: ${parseResult.data.forbidden.length}`);\r\n}\r\n","/**\r\n * sdd start 명령어 - 통합 진입점\r\n *\r\n * 워크플로우 선택 메뉴를 제공하여 사용자가 쉽게 작업을 시작할 수 있도록 합니다.\r\n */\r\nimport { Command } from 'commander';\r\nimport path from 'node:path';\r\nimport { promises as fs } from 'node:fs';\r\nimport * as logger from '../../utils/logger.js';\r\nimport { ExitCode } from '../../errors/index.js';\r\nimport { findSddRoot, fileExists, readFile, directoryExists } from '../../utils/fs.js';\r\nimport { parseConstitution } from '../../core/constitution/index.js';\r\nimport { listPendingChanges } from '../../core/change/index.js';\r\n\r\n/**\r\n * 워크플로우 타입 정의\r\n */\r\nexport type WorkflowType =\r\n | 'new-feature'\r\n | 'change-spec'\r\n | 'validate'\r\n | 'status'\r\n | 'constitution';\r\n\r\n/**\r\n * 워크플로우 정보\r\n */\r\nexport interface WorkflowInfo {\r\n type: WorkflowType;\r\n name: string;\r\n description: string;\r\n command: string;\r\n available: boolean;\r\n reason?: string;\r\n}\r\n\r\n/**\r\n * 프로젝트 상태 정보\r\n */\r\nexport interface ProjectStatus {\r\n initialized: boolean;\r\n hasConstitution: boolean;\r\n constitutionVersion?: string;\r\n specCount: number;\r\n pendingChanges: number;\r\n specs: string[];\r\n}\r\n\r\n/**\r\n * start 명령어 등록\r\n */\r\nexport function registerStartCommand(program: Command): void {\r\n program\r\n .command('start')\r\n .description('SDD 워크플로우를 시작합니다 (통합 진입점)')\r\n .option('-w, --workflow <type>', '워크플로우 유형 (new-feature, change-spec, validate, status, constitution)')\r\n .option('--status', '프로젝트 상태만 표시')\r\n .action(async (options: { workflow?: WorkflowType; status?: boolean }) => {\r\n try {\r\n await runStart(options);\r\n } catch (error) {\r\n logger.error(error instanceof Error ? error.message : String(error));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n });\r\n}\r\n\r\n/**\r\n * start 명령어 실행\r\n */\r\nasync function runStart(options: { workflow?: WorkflowType; status?: boolean }): Promise<void> {\r\n // 프로젝트 상태 확인\r\n const projectStatus = await getProjectStatus();\r\n\r\n // 프로젝트가 초기화되지 않은 경우\r\n if (!projectStatus.initialized) {\r\n logger.info('SDD 프로젝트가 초기화되지 않았습니다.');\r\n logger.newline();\r\n logger.info('프로젝트를 시작하려면:');\r\n logger.listItem('sdd init');\r\n logger.newline();\r\n logger.info('또는 다음 슬래시 커맨드를 사용하세요:');\r\n logger.listItem('/sdd.new - 새 프로젝트와 함께 기능 생성');\r\n return;\r\n }\r\n\r\n // 상태만 표시\r\n if (options.status) {\r\n displayProjectStatus(projectStatus);\r\n return;\r\n }\r\n\r\n // 워크플로우가 지정된 경우 해당 워크플로우 안내\r\n if (options.workflow) {\r\n const workflow = getWorkflowInfo(options.workflow, projectStatus);\r\n displayWorkflowGuide(workflow);\r\n return;\r\n }\r\n\r\n // 기본: 전체 상태 + 워크플로우 메뉴\r\n displayProjectStatus(projectStatus);\r\n logger.newline();\r\n displayWorkflowMenu(projectStatus);\r\n}\r\n\r\n/**\r\n * 프로젝트 상태 조회\r\n */\r\nasync function getProjectStatus(): Promise<ProjectStatus> {\r\n const projectRoot = await findSddRoot();\r\n\r\n if (!projectRoot) {\r\n return {\r\n initialized: false,\r\n hasConstitution: false,\r\n specCount: 0,\r\n pendingChanges: 0,\r\n specs: [],\r\n };\r\n }\r\n\r\n const sddPath = path.join(projectRoot, '.sdd');\r\n const specsPath = path.join(sddPath, 'specs');\r\n\r\n // Constitution 확인\r\n let hasConstitution = false;\r\n let constitutionVersion: string | undefined;\r\n const constitutionPath = path.join(sddPath, 'constitution.md');\r\n\r\n if (await fileExists(constitutionPath)) {\r\n hasConstitution = true;\r\n const content = await readFile(constitutionPath);\r\n if (content.success) {\r\n const parsed = parseConstitution(content.data);\r\n if (parsed.success) {\r\n constitutionVersion = parsed.data.metadata.version;\r\n }\r\n }\r\n }\r\n\r\n // Spec 목록 조회\r\n const specs: string[] = [];\r\n if (await directoryExists(specsPath)) {\r\n try {\r\n const dirs = await fs.readdir(specsPath);\r\n for (const dir of dirs) {\r\n const specPath = path.join(specsPath, dir, 'spec.md');\r\n if (await fileExists(specPath)) {\r\n specs.push(dir);\r\n }\r\n }\r\n } catch {\r\n // ignore\r\n }\r\n }\r\n\r\n // 진행 중인 변경 조회\r\n let pendingChanges = 0;\r\n const changesResult = await listPendingChanges(sddPath);\r\n if (changesResult.success) {\r\n pendingChanges = changesResult.data.length;\r\n }\r\n\r\n return {\r\n initialized: true,\r\n hasConstitution,\r\n constitutionVersion,\r\n specCount: specs.length,\r\n pendingChanges,\r\n specs,\r\n };\r\n}\r\n\r\n/**\r\n * 프로젝트 상태 표시\r\n */\r\nfunction displayProjectStatus(status: ProjectStatus): void {\r\n logger.info('=== SDD 프로젝트 상태 ===');\r\n logger.newline();\r\n\r\n if (status.hasConstitution) {\r\n logger.info(`Constitution: v${status.constitutionVersion || '?.?.?'}`);\r\n } else {\r\n logger.warn('Constitution: 없음 (권장: sdd constitution 생성)');\r\n }\r\n\r\n logger.info(`명세 수: ${status.specCount}개`);\r\n if (status.specs.length > 0 && status.specs.length <= 5) {\r\n for (const spec of status.specs) {\r\n logger.listItem(spec, 1);\r\n }\r\n } else if (status.specs.length > 5) {\r\n for (const spec of status.specs.slice(0, 5)) {\r\n logger.listItem(spec, 1);\r\n }\r\n logger.listItem(`... 외 ${status.specs.length - 5}개`, 1);\r\n }\r\n\r\n if (status.pendingChanges > 0) {\r\n logger.warn(`진행 중인 변경: ${status.pendingChanges}개`);\r\n } else {\r\n logger.info('진행 중인 변경: 없음');\r\n }\r\n}\r\n\r\n/**\r\n * 워크플로우 메뉴 표시\r\n */\r\nfunction displayWorkflowMenu(status: ProjectStatus): void {\r\n logger.info('=== 사용 가능한 워크플로우 ===');\r\n logger.newline();\r\n\r\n const workflows: WorkflowInfo[] = [\r\n getWorkflowInfo('new-feature', status),\r\n getWorkflowInfo('change-spec', status),\r\n getWorkflowInfo('validate', status),\r\n getWorkflowInfo('status', status),\r\n getWorkflowInfo('constitution', status),\r\n ];\r\n\r\n for (const workflow of workflows) {\r\n if (workflow.available) {\r\n logger.info(`[${workflow.type}] ${workflow.name}`);\r\n logger.listItem(workflow.description, 1);\r\n logger.listItem(`명령어: ${workflow.command}`, 1);\r\n } else {\r\n logger.warn(`[${workflow.type}] ${workflow.name} (사용 불가)`);\r\n logger.listItem(workflow.reason || '조건 미충족', 1);\r\n }\r\n logger.newline();\r\n }\r\n\r\n logger.info('특정 워크플로우를 바로 시작하려면:');\r\n logger.listItem('sdd start --workflow <type>');\r\n logger.newline();\r\n logger.info('또는 Claude Code 슬래시 커맨드를 사용하세요:');\r\n logger.listItem('/sdd.new - 새 기능 명세');\r\n logger.listItem('/sdd.change - 기존 스펙 변경');\r\n logger.listItem('/sdd.validate - 명세 검증');\r\n}\r\n\r\n/**\r\n * 워크플로우 정보 조회\r\n */\r\nfunction getWorkflowInfo(type: WorkflowType, status: ProjectStatus): WorkflowInfo {\r\n switch (type) {\r\n case 'new-feature':\r\n return {\r\n type,\r\n name: '새 기능 명세',\r\n description: '새로운 기능의 명세를 작성합니다 (spec.md, plan.md, tasks.md)',\r\n command: 'sdd new <name>',\r\n available: true,\r\n };\r\n\r\n case 'change-spec':\r\n return {\r\n type,\r\n name: '기존 스펙 변경',\r\n description: '기존 명세에 대한 변경을 제안하고 관리합니다',\r\n command: 'sdd change',\r\n available: status.specCount > 0,\r\n reason: status.specCount === 0 ? '변경할 스펙이 없습니다' : undefined,\r\n };\r\n\r\n case 'validate':\r\n return {\r\n type,\r\n name: '명세 검증',\r\n description: '모든 명세 파일의 형식과 무결성을 검증합니다',\r\n command: 'sdd validate',\r\n available: status.specCount > 0 || status.hasConstitution,\r\n reason: status.specCount === 0 && !status.hasConstitution\r\n ? '검증할 명세가 없습니다'\r\n : undefined,\r\n };\r\n\r\n case 'status':\r\n return {\r\n type,\r\n name: '상태 확인',\r\n description: '전체 프로젝트 및 개별 스펙의 상태를 확인합니다',\r\n command: 'sdd status',\r\n available: true,\r\n };\r\n\r\n case 'constitution':\r\n return {\r\n type,\r\n name: 'Constitution 관리',\r\n description: '프로젝트 원칙(헌법)을 조회하고 관리합니다',\r\n command: 'sdd constitution',\r\n available: true,\r\n };\r\n\r\n default:\r\n return {\r\n type,\r\n name: '알 수 없는 워크플로우',\r\n description: '',\r\n command: '',\r\n available: false,\r\n reason: '알 수 없는 워크플로우 유형입니다',\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * 워크플로우 가이드 표시\r\n */\r\nfunction displayWorkflowGuide(workflow: WorkflowInfo): void {\r\n logger.info(`=== ${workflow.name} ===`);\r\n logger.newline();\r\n\r\n if (!workflow.available) {\r\n logger.error(`이 워크플로우는 현재 사용할 수 없습니다: ${workflow.reason}`);\r\n return;\r\n }\r\n\r\n logger.info(workflow.description);\r\n logger.newline();\r\n\r\n switch (workflow.type) {\r\n case 'new-feature':\r\n displayNewFeatureGuide();\r\n break;\r\n case 'change-spec':\r\n displayChangeSpecGuide();\r\n break;\r\n case 'validate':\r\n displayValidateGuide();\r\n break;\r\n case 'status':\r\n displayStatusGuide();\r\n break;\r\n case 'constitution':\r\n displayConstitutionGuide();\r\n break;\r\n }\r\n}\r\n\r\n/**\r\n * 새 기능 워크플로우 가이드\r\n */\r\nfunction displayNewFeatureGuide(): void {\r\n logger.info('단계:');\r\n logger.listItem('1. sdd new <name> - 명세 파일 생성');\r\n logger.listItem('2. spec.md 편집 - 요구사항 및 시나리오 작성');\r\n logger.listItem('3. sdd new plan <id> - 구현 계획 작성');\r\n logger.listItem('4. sdd new tasks <id> - 작업 분해');\r\n logger.listItem('5. 구현 진행');\r\n logger.newline();\r\n logger.info('Claude Code 슬래시 커맨드:');\r\n logger.listItem('/sdd.new - 대화형 명세 작성');\r\n logger.listItem('/sdd.plan - 구현 계획 수립');\r\n logger.listItem('/sdd.tasks - 작업 분해');\r\n logger.listItem('/sdd.implement - 구현 진행');\r\n logger.newline();\r\n logger.info('옵션:');\r\n logger.listItem('--all : spec, plan, tasks 모두 생성');\r\n logger.listItem('--no-branch : Git 브랜치 생성 안 함');\r\n}\r\n\r\n/**\r\n * 변경 워크플로우 가이드\r\n */\r\nfunction displayChangeSpecGuide(): void {\r\n logger.info('단계:');\r\n logger.listItem('1. sdd change -t \"변경 제목\" - 변경 제안 생성');\r\n logger.listItem('2. proposal.md 편집 - 변경 배경 및 내용 작성');\r\n logger.listItem('3. delta.md 편집 - ADDED/MODIFIED/REMOVED 작성');\r\n logger.listItem('4. sdd change validate <id> - 제안 검증');\r\n logger.listItem('5. sdd change apply <id> - 변경 적용');\r\n logger.listItem('6. sdd change archive <id> - 완료 후 아카이브');\r\n logger.newline();\r\n logger.info('Claude Code 슬래시 커맨드:');\r\n logger.listItem('/sdd.change - 변경 제안 작성');\r\n logger.newline();\r\n logger.info('명령어:');\r\n logger.listItem('sdd change -l : 진행 중인 변경 목록');\r\n logger.listItem('sdd change <id> : 특정 변경 조회');\r\n logger.listItem('sdd change diff <id> : 변경 내용 diff');\r\n}\r\n\r\n/**\r\n * 검증 워크플로우 가이드\r\n */\r\nfunction displayValidateGuide(): void {\r\n logger.info('사용법:');\r\n logger.listItem('sdd validate : 전체 검증');\r\n logger.listItem('sdd validate <id> : 특정 스펙 검증');\r\n logger.listItem('sdd validate --strict : 엄격 모드');\r\n logger.newline();\r\n logger.info('검증 항목:');\r\n logger.listItem('- frontmatter 형식');\r\n logger.listItem('- RFC 2119 키워드 사용');\r\n logger.listItem('- GIVEN-WHEN-THEN 시나리오');\r\n logger.listItem('- 의존성 참조');\r\n logger.newline();\r\n logger.info('Claude Code 슬래시 커맨드:');\r\n logger.listItem('/sdd.validate - 검증 및 피드백');\r\n}\r\n\r\n/**\r\n * 상태 확인 워크플로우 가이드\r\n */\r\nfunction displayStatusGuide(): void {\r\n logger.info('사용법:');\r\n logger.listItem('sdd status : 프로젝트 전체 상태');\r\n logger.listItem('sdd status <id> : 특정 스펙 상태');\r\n logger.newline();\r\n logger.info('Claude Code 슬래시 커맨드:');\r\n logger.listItem('/sdd.status - 상태 리포트');\r\n}\r\n\r\n/**\r\n * Constitution 워크플로우 가이드\r\n */\r\nfunction displayConstitutionGuide(): void {\r\n logger.info('사용법:');\r\n logger.listItem('sdd constitution : Constitution 표시');\r\n logger.listItem('sdd constitution version : 버전 확인');\r\n logger.listItem('sdd constitution bump : 버전 업데이트');\r\n logger.listItem('sdd constitution history : 변경 이력');\r\n logger.listItem('sdd constitution validate : 형식 검증');\r\n logger.newline();\r\n logger.info('버전 업데이트:');\r\n logger.listItem('--major : 주요 변경 (원칙 삭제 등)');\r\n logger.listItem('--minor : 기능 추가');\r\n logger.listItem('--patch : 오타/명확화');\r\n logger.newline();\r\n logger.info('Claude Code 슬래시 커맨드:');\r\n logger.listItem('/sdd.constitution - Constitution 관리');\r\n}\r\n","/**\r\n * sdd migrate 명령어\r\n *\r\n * 기존 문서나 코드를 SDD 형식으로 마이그레이션합니다.\r\n */\r\nimport { Command } from 'commander';\r\nimport path from 'node:path';\r\nimport { promises as fs } from 'node:fs';\r\nimport * as logger from '../../utils/logger.js';\r\nimport { ExitCode } from '../../errors/index.js';\r\nimport { findSddRoot, fileExists, ensureDir, writeFile, directoryExists } from '../../utils/fs.js';\r\nimport { generateSpec } from '../../core/new/index.js';\r\nimport { generateFeatureId } from '../../core/new/schemas.js';\r\n\r\n/**\r\n * 마이그레이션 결과\r\n */\r\ninterface MigrationResult {\r\n source: string;\r\n target: string;\r\n success: boolean;\r\n error?: string;\r\n}\r\n\r\n/**\r\n * 마이그레이션 요약\r\n */\r\ninterface MigrationSummary {\r\n total: number;\r\n succeeded: number;\r\n failed: number;\r\n results: MigrationResult[];\r\n}\r\n\r\n/**\r\n * 문서 분석 결과\r\n */\r\ninterface DocumentAnalysis {\r\n title: string;\r\n description: string;\r\n requirements: string[];\r\n scenarios: Array<{\r\n name: string;\r\n given: string;\r\n when: string;\r\n then: string;\r\n }>;\r\n hasRfc2119: boolean;\r\n hasScenarios: boolean;\r\n}\r\n\r\n/**\r\n * migrate 명령어 등록\r\n */\r\nexport function registerMigrateCommand(program: Command): void {\r\n const migrate = program\r\n .command('migrate')\r\n .description('기존 문서를 SDD 형식으로 마이그레이션합니다');\r\n\r\n // docs 서브커맨드 - 문서 마이그레이션\r\n migrate\r\n .command('docs <source>')\r\n .description('마크다운 문서를 spec.md 형식으로 변환합니다')\r\n .option('-o, --output <dir>', '출력 디렉토리')\r\n .option('--dry-run', '실제 파일 생성 없이 미리보기')\r\n .action(async (source: string, options: { output?: string; dryRun?: boolean }) => {\r\n try {\r\n await runMigrateDocs(source, options);\r\n } catch (error) {\r\n logger.error(error instanceof Error ? error.message : String(error));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n });\r\n\r\n // analyze 서브커맨드 - 문서 분석\r\n migrate\r\n .command('analyze <file>')\r\n .description('문서를 분석하여 SDD 호환성을 확인합니다')\r\n .action(async (file: string) => {\r\n try {\r\n await runAnalyze(file);\r\n } catch (error) {\r\n logger.error(error instanceof Error ? error.message : String(error));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n });\r\n\r\n // scan 서브커맨드 - 디렉토리 스캔\r\n migrate\r\n .command('scan [dir]')\r\n .description('디렉토리에서 마이그레이션 가능한 문서를 스캔합니다')\r\n .option('--ext <extensions>', '파일 확장자 (기본: .md)')\r\n .action(async (dir: string | undefined, options: { ext?: string }) => {\r\n try {\r\n await runScan(dir || '.', options);\r\n } catch (error) {\r\n logger.error(error instanceof Error ? error.message : String(error));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n });\r\n}\r\n\r\n/**\r\n * 문서 마이그레이션 실행\r\n */\r\nasync function runMigrateDocs(\r\n source: string,\r\n options: { output?: string; dryRun?: boolean }\r\n): Promise<void> {\r\n const projectRoot = await findSddRoot();\r\n if (!projectRoot && !options.output) {\r\n logger.error('SDD 프로젝트를 찾을 수 없습니다. --output 옵션을 사용하거나 sdd init을 먼저 실행하세요.');\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n const sourcePath = path.resolve(source);\r\n\r\n // 파일 또는 디렉토리 확인\r\n let files: string[] = [];\r\n try {\r\n const stat = await fs.stat(sourcePath);\r\n if (stat.isDirectory()) {\r\n files = await collectMarkdownFiles(sourcePath);\r\n } else if (stat.isFile()) {\r\n files = [sourcePath];\r\n }\r\n } catch {\r\n logger.error(`소스를 찾을 수 없습니다: ${source}`);\r\n process.exit(ExitCode.FILE_SYSTEM_ERROR);\r\n }\r\n\r\n if (files.length === 0) {\r\n logger.info('마이그레이션할 마크다운 파일이 없습니다.');\r\n return;\r\n }\r\n\r\n logger.info(`${files.length}개 파일 발견`);\r\n logger.newline();\r\n\r\n const outputDir = options.output\r\n ? path.resolve(options.output)\r\n : path.join(projectRoot!, '.sdd', 'specs');\r\n\r\n const summary: MigrationSummary = {\r\n total: files.length,\r\n succeeded: 0,\r\n failed: 0,\r\n results: [],\r\n };\r\n\r\n for (const file of files) {\r\n const result = await migrateDocument(file, outputDir, options.dryRun || false);\r\n summary.results.push(result);\r\n if (result.success) {\r\n summary.succeeded++;\r\n logger.info(`✅ ${path.basename(file)} → ${result.target}`);\r\n } else {\r\n summary.failed++;\r\n logger.error(`❌ ${path.basename(file)}: ${result.error}`);\r\n }\r\n }\r\n\r\n logger.newline();\r\n logger.info('=== 마이그레이션 완료 ===');\r\n logger.info(`총: ${summary.total}개, 성공: ${summary.succeeded}개, 실패: ${summary.failed}개`);\r\n\r\n if (options.dryRun) {\r\n logger.warn('(dry-run 모드: 실제 파일이 생성되지 않았습니다)');\r\n }\r\n}\r\n\r\n/**\r\n * 단일 문서 마이그레이션\r\n */\r\nasync function migrateDocument(\r\n filePath: string,\r\n outputDir: string,\r\n dryRun: boolean\r\n): Promise<MigrationResult> {\r\n try {\r\n const content = await fs.readFile(filePath, 'utf-8');\r\n const analysis = analyzeDocument(content);\r\n\r\n // spec.md 생성\r\n const featureId = generateFeatureId(analysis.title || path.basename(filePath, '.md'));\r\n const specContent = generateSpec({\r\n id: featureId,\r\n title: analysis.title || path.basename(filePath, '.md'),\r\n description: analysis.description || '',\r\n requirements: analysis.requirements,\r\n scenarios: analysis.scenarios,\r\n });\r\n\r\n const targetDir = path.join(outputDir, featureId);\r\n const targetPath = path.join(targetDir, 'spec.md');\r\n\r\n if (!dryRun) {\r\n await ensureDir(targetDir);\r\n await writeFile(targetPath, specContent);\r\n }\r\n\r\n return {\r\n source: filePath,\r\n target: path.relative(process.cwd(), targetPath),\r\n success: true,\r\n };\r\n } catch (error) {\r\n return {\r\n source: filePath,\r\n target: '',\r\n success: false,\r\n error: error instanceof Error ? error.message : String(error),\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * 문서 분석\r\n */\r\nfunction analyzeDocument(content: string): DocumentAnalysis {\r\n // 제목 추출\r\n const titleMatch = content.match(/^#\\s+(.+)$/m);\r\n const title = titleMatch ? titleMatch[1].trim() : '';\r\n\r\n // 설명 추출 (첫 번째 단락)\r\n const descMatch = content.match(/^#[^\\n]+\\n\\n([^#]+)/m);\r\n const description = descMatch ? descMatch[1].trim().split('\\n')[0] : '';\r\n\r\n // 요구사항 추출\r\n const requirements: string[] = [];\r\n const reqMatches = content.matchAll(/(?:SHALL|MUST|SHOULD|MAY|SHALL NOT|MUST NOT)[^.]+\\./gi);\r\n for (const match of reqMatches) {\r\n requirements.push(match[0].trim());\r\n }\r\n\r\n // 시나리오 추출\r\n const scenarios: DocumentAnalysis['scenarios'] = [];\r\n const givenWhenThen = content.matchAll(\r\n /(?:GIVEN|Given|given)[:\\s]+([^\\n]+)\\n.*?(?:WHEN|When|when)[:\\s]+([^\\n]+)\\n.*?(?:THEN|Then|then)[:\\s]+([^\\n]+)/gi\r\n );\r\n for (const match of givenWhenThen) {\r\n scenarios.push({\r\n name: `Scenario ${scenarios.length + 1}`,\r\n given: match[1].trim(),\r\n when: match[2].trim(),\r\n then: match[3].trim(),\r\n });\r\n }\r\n\r\n // RFC 2119 키워드 확인\r\n const hasRfc2119 = /\\b(SHALL|MUST|SHOULD|MAY|SHALL NOT|MUST NOT)\\b/.test(content);\r\n\r\n return {\r\n title,\r\n description,\r\n requirements,\r\n scenarios,\r\n hasRfc2119,\r\n hasScenarios: scenarios.length > 0,\r\n };\r\n}\r\n\r\n/**\r\n * 문서 분석 실행\r\n */\r\nasync function runAnalyze(file: string): Promise<void> {\r\n const filePath = path.resolve(file);\r\n\r\n if (!(await fileExists(filePath))) {\r\n logger.error(`파일을 찾을 수 없습니다: ${file}`);\r\n process.exit(ExitCode.FILE_SYSTEM_ERROR);\r\n }\r\n\r\n const content = await fs.readFile(filePath, 'utf-8');\r\n const analysis = analyzeDocument(content);\r\n\r\n logger.info(`📊 문서 분석: ${path.basename(file)}`);\r\n logger.newline();\r\n\r\n logger.info(`제목: ${analysis.title || '(없음)'}`);\r\n logger.info(`설명: ${analysis.description || '(없음)'}`);\r\n logger.newline();\r\n\r\n logger.info('SDD 호환성:');\r\n const rfc2119Icon = analysis.hasRfc2119 ? '✅' : '❌';\r\n logger.listItem(`${rfc2119Icon} RFC 2119 키워드: ${analysis.requirements.length}개`);\r\n\r\n const scenarioIcon = analysis.hasScenarios ? '✅' : '❌';\r\n logger.listItem(`${scenarioIcon} GIVEN-WHEN-THEN 시나리오: ${analysis.scenarios.length}개`);\r\n logger.newline();\r\n\r\n if (analysis.requirements.length > 0) {\r\n logger.info('발견된 요구사항:');\r\n for (const req of analysis.requirements.slice(0, 5)) {\r\n logger.listItem(req.substring(0, 80) + (req.length > 80 ? '...' : ''), 1);\r\n }\r\n if (analysis.requirements.length > 5) {\r\n logger.info(` ... 외 ${analysis.requirements.length - 5}개`);\r\n }\r\n logger.newline();\r\n }\r\n\r\n if (analysis.scenarios.length > 0) {\r\n logger.info('발견된 시나리오:');\r\n for (const scenario of analysis.scenarios) {\r\n logger.listItem(`GIVEN ${scenario.given}`, 1);\r\n logger.listItem(`WHEN ${scenario.when}`, 1);\r\n logger.listItem(`THEN ${scenario.then}`, 1);\r\n }\r\n logger.newline();\r\n }\r\n\r\n // 마이그레이션 권장사항\r\n logger.info('💡 권장사항:');\r\n if (!analysis.hasRfc2119) {\r\n logger.listItem('RFC 2119 키워드(SHALL, MUST, SHOULD 등)를 추가하세요.', 1);\r\n }\r\n if (!analysis.hasScenarios) {\r\n logger.listItem('GIVEN-WHEN-THEN 형식의 시나리오를 추가하세요.', 1);\r\n }\r\n if (analysis.hasRfc2119 && analysis.hasScenarios) {\r\n logger.listItem('이 문서는 SDD 형식으로 마이그레이션하기에 적합합니다!', 1);\r\n logger.listItem('`sdd migrate docs ' + file + '`로 마이그레이션하세요.', 1);\r\n }\r\n}\r\n\r\n/**\r\n * 디렉토리 스캔 실행\r\n */\r\nasync function runScan(dir: string, options: { ext?: string }): Promise<void> {\r\n const dirPath = path.resolve(dir);\r\n\r\n if (!(await directoryExists(dirPath))) {\r\n logger.error(`디렉토리를 찾을 수 없습니다: ${dir}`);\r\n process.exit(ExitCode.FILE_SYSTEM_ERROR);\r\n }\r\n\r\n const extensions = (options.ext || '.md').split(',').map((e) => e.trim());\r\n const files = await collectFilesWithExtensions(dirPath, extensions);\r\n\r\n if (files.length === 0) {\r\n logger.info(`마이그레이션 가능한 파일이 없습니다 (확장자: ${extensions.join(', ')})`);\r\n return;\r\n }\r\n\r\n logger.info(`📂 스캔 결과: ${dir}`);\r\n logger.newline();\r\n\r\n const results: Array<{ file: string; analysis: DocumentAnalysis }> = [];\r\n\r\n for (const file of files) {\r\n try {\r\n const content = await fs.readFile(file, 'utf-8');\r\n const analysis = analyzeDocument(content);\r\n results.push({ file, analysis });\r\n } catch {\r\n // 읽기 실패 무시\r\n }\r\n }\r\n\r\n // 적합도 순으로 정렬\r\n results.sort((a, b) => {\r\n const scoreA = (a.analysis.hasRfc2119 ? 2 : 0) + (a.analysis.hasScenarios ? 2 : 0) + a.analysis.requirements.length;\r\n const scoreB = (b.analysis.hasRfc2119 ? 2 : 0) + (b.analysis.hasScenarios ? 2 : 0) + b.analysis.requirements.length;\r\n return scoreB - scoreA;\r\n });\r\n\r\n // 결과 표시\r\n const ready: string[] = [];\r\n const partial: string[] = [];\r\n const notReady: string[] = [];\r\n\r\n for (const { file, analysis } of results) {\r\n const relativePath = path.relative(process.cwd(), file);\r\n if (analysis.hasRfc2119 && analysis.hasScenarios) {\r\n ready.push(relativePath);\r\n } else if (analysis.hasRfc2119 || analysis.hasScenarios || analysis.requirements.length > 0) {\r\n partial.push(relativePath);\r\n } else {\r\n notReady.push(relativePath);\r\n }\r\n }\r\n\r\n if (ready.length > 0) {\r\n logger.info('🟢 마이그레이션 준비됨:');\r\n for (const file of ready) {\r\n logger.listItem(file, 1);\r\n }\r\n logger.newline();\r\n }\r\n\r\n if (partial.length > 0) {\r\n logger.info('🟡 일부 수정 필요:');\r\n for (const file of partial) {\r\n logger.listItem(file, 1);\r\n }\r\n logger.newline();\r\n }\r\n\r\n if (notReady.length > 0) {\r\n logger.info('🔴 추가 작업 필요:');\r\n for (const file of notReady.slice(0, 10)) {\r\n logger.listItem(file, 1);\r\n }\r\n if (notReady.length > 10) {\r\n logger.info(` ... 외 ${notReady.length - 10}개`);\r\n }\r\n logger.newline();\r\n }\r\n\r\n logger.info('=== 요약 ===');\r\n logger.info(`총: ${results.length}개, 준비됨: ${ready.length}개, 일부: ${partial.length}개, 미준비: ${notReady.length}개`);\r\n logger.newline();\r\n\r\n if (ready.length > 0) {\r\n logger.info('다음 명령어로 마이그레이션을 시작하세요:');\r\n logger.listItem(`sdd migrate docs ${ready[0]}`);\r\n }\r\n}\r\n\r\n/**\r\n * 마크다운 파일 수집\r\n */\r\nasync function collectMarkdownFiles(dirPath: string): Promise<string[]> {\r\n return collectFilesWithExtensions(dirPath, ['.md']);\r\n}\r\n\r\n/**\r\n * 특정 확장자 파일 수집\r\n */\r\nasync function collectFilesWithExtensions(dirPath: string, extensions: string[]): Promise<string[]> {\r\n const files: string[] = [];\r\n\r\n async function scan(dir: string): Promise<void> {\r\n const entries = await fs.readdir(dir, { withFileTypes: true });\r\n\r\n for (const entry of entries) {\r\n const fullPath = path.join(dir, entry.name);\r\n\r\n // 무시할 디렉토리\r\n if (entry.isDirectory()) {\r\n if (!['node_modules', '.git', '.sdd', 'dist', 'build'].includes(entry.name)) {\r\n await scan(fullPath);\r\n }\r\n } else if (entry.isFile()) {\r\n const ext = path.extname(entry.name).toLowerCase();\r\n if (extensions.some((e) => e.toLowerCase() === ext)) {\r\n // AGENTS.md, README.md 등은 제외\r\n if (!['agents.md', 'readme.md', 'changelog.md', 'license.md'].includes(entry.name.toLowerCase())) {\r\n files.push(fullPath);\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n await scan(dirPath);\r\n return files;\r\n}\r\n","/**\r\n * sdd cicd 명령어\r\n *\r\n * CI/CD 파이프라인 통합을 설정합니다.\r\n */\r\nimport { Command } from 'commander';\r\nimport path from 'node:path';\r\nimport * as logger from '../../utils/logger.js';\r\nimport { ExitCode } from '../../errors/index.js';\r\nimport { findSddRoot, ensureDir, writeFile, fileExists, directoryExists } from '../../utils/fs.js';\r\n\r\n/**\r\n * CI 플랫폼 유형\r\n */\r\ntype CIPlatform = 'github' | 'gitlab' | 'all';\r\n\r\n/**\r\n * 훅 유형\r\n */\r\ntype HookType = 'pre-commit' | 'pre-push' | 'commit-msg';\r\n\r\n/**\r\n * cicd 명령어 등록\r\n */\r\nexport function registerCicdCommand(program: Command): void {\r\n const cicd = program\r\n .command('cicd')\r\n .description('CI/CD 파이프라인 통합 설정');\r\n\r\n // setup 서브커맨드 - CI 설정\r\n cicd\r\n .command('setup [platform]')\r\n .description('CI 워크플로우 파일을 생성합니다')\r\n .option('--strict', '엄격 모드 (경고도 에러로 처리)')\r\n .action(async (platform: CIPlatform | undefined, options: { strict?: boolean }) => {\r\n try {\r\n await runSetup(platform || 'github', options);\r\n } catch (error) {\r\n logger.error(error instanceof Error ? error.message : String(error));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n });\r\n\r\n // hooks 서브커맨드 - Git hooks 설정\r\n cicd\r\n .command('hooks [type]')\r\n .description('Git hooks를 설정합니다')\r\n .option('--install', 'husky 설치 포함')\r\n .action(async (type: HookType | undefined, options: { install?: boolean }) => {\r\n try {\r\n await runHooksSetup(type, options);\r\n } catch (error) {\r\n logger.error(error instanceof Error ? error.message : String(error));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n });\r\n\r\n // check 서브커맨드 - CI에서 사용할 검증\r\n cicd\r\n .command('check')\r\n .description('CI 환경에서 스펙 검증을 수행합니다')\r\n .option('--strict', '엄격 모드')\r\n .option('--fail-on-warning', '경고 시 실패')\r\n .action(async (options: { strict?: boolean; failOnWarning?: boolean }) => {\r\n try {\r\n await runCiCheck(options);\r\n } catch (error) {\r\n logger.error(error instanceof Error ? error.message : String(error));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n });\r\n}\r\n\r\n/**\r\n * CI 설정 실행\r\n */\r\nasync function runSetup(platform: CIPlatform, options: { strict?: boolean }): Promise<void> {\r\n const projectRoot = await findSddRoot();\r\n if (!projectRoot) {\r\n logger.error('SDD 프로젝트를 찾을 수 없습니다. `sdd init`을 먼저 실행하세요.');\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n logger.info(`CI/CD 설정: ${platform}`);\r\n logger.newline();\r\n\r\n if (platform === 'github' || platform === 'all') {\r\n await setupGitHubActions(projectRoot, options.strict || false);\r\n }\r\n\r\n if (platform === 'gitlab' || platform === 'all') {\r\n await setupGitLabCI(projectRoot, options.strict || false);\r\n }\r\n\r\n logger.newline();\r\n logger.success('CI/CD 설정이 완료되었습니다!');\r\n logger.newline();\r\n logger.info('다음 단계:');\r\n logger.listItem('변경사항을 커밋하세요');\r\n logger.listItem('PR/MR 생성 시 자동으로 스펙 검증이 실행됩니다');\r\n}\r\n\r\n/**\r\n * GitHub Actions 설정\r\n */\r\nasync function setupGitHubActions(projectRoot: string, strict: boolean): Promise<void> {\r\n const workflowDir = path.join(projectRoot, '.github', 'workflows');\r\n await ensureDir(workflowDir);\r\n\r\n const workflowContent = generateGitHubWorkflow(strict);\r\n const workflowPath = path.join(workflowDir, 'sdd-validate.yml');\r\n\r\n await writeFile(workflowPath, workflowContent);\r\n logger.info(`✅ GitHub Actions 워크플로우 생성: .github/workflows/sdd-validate.yml`);\r\n}\r\n\r\n/**\r\n * GitLab CI 설정\r\n */\r\nasync function setupGitLabCI(projectRoot: string, strict: boolean): Promise<void> {\r\n const ciContent = generateGitLabCI(strict);\r\n const ciPath = path.join(projectRoot, '.gitlab-ci-sdd.yml');\r\n\r\n await writeFile(ciPath, ciContent);\r\n logger.info(`✅ GitLab CI 구성 생성: .gitlab-ci-sdd.yml`);\r\n logger.info(' (기존 .gitlab-ci.yml에 include하거나 병합하세요)');\r\n}\r\n\r\n/**\r\n * GitHub Actions 워크플로우 생성\r\n */\r\nfunction generateGitHubWorkflow(strict: boolean): string {\r\n const strictFlag = strict ? ' --strict' : '';\r\n\r\n return `# SDD 스펙 검증 워크플로우\r\n# 이 파일은 sdd cicd setup으로 생성되었습니다.\r\n\r\nname: SDD Validation\r\n\r\non:\r\n push:\r\n branches: [main, master, develop]\r\n paths:\r\n - '.sdd/**'\r\n pull_request:\r\n branches: [main, master, develop]\r\n paths:\r\n - '.sdd/**'\r\n\r\njobs:\r\n validate:\r\n name: Validate Specs\r\n runs-on: ubuntu-latest\r\n\r\n steps:\r\n - name: Checkout repository\r\n uses: actions/checkout@v4\r\n\r\n - name: Setup Node.js\r\n uses: actions/setup-node@v4\r\n with:\r\n node-version: '20'\r\n cache: 'npm'\r\n\r\n - name: Install dependencies\r\n run: npm ci\r\n\r\n - name: Install SDD Tool\r\n run: npm install -g sdd-tool\r\n\r\n - name: Validate specifications\r\n run: sdd validate${strictFlag}\r\n\r\n - name: Check constitution\r\n run: sdd constitution validate\r\n\r\n - name: Generate impact report\r\n run: sdd impact report --json > impact-report.json\r\n\r\n - name: Upload impact report\r\n uses: actions/upload-artifact@v4\r\n with:\r\n name: impact-report\r\n path: impact-report.json\r\n`;\r\n}\r\n\r\n/**\r\n * GitLab CI 구성 생성\r\n */\r\nfunction generateGitLabCI(strict: boolean): string {\r\n const strictFlag = strict ? ' --strict' : '';\r\n\r\n return `# SDD 스펙 검증 파이프라인\r\n# 이 파일은 sdd cicd setup으로 생성되었습니다.\r\n# 기존 .gitlab-ci.yml에 include하거나 내용을 병합하세요.\r\n\r\nsdd:validate:\r\n stage: test\r\n image: node:20\r\n rules:\r\n - if: $CI_PIPELINE_SOURCE == \"merge_request_event\"\r\n changes:\r\n - .sdd/**/*\r\n - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH\r\n changes:\r\n - .sdd/**/*\r\n before_script:\r\n - npm ci\r\n - npm install -g sdd-tool\r\n script:\r\n - sdd validate${strictFlag}\r\n - sdd constitution validate\r\n - sdd impact report --json > impact-report.json\r\n artifacts:\r\n reports:\r\n dotenv: impact-report.json\r\n paths:\r\n - impact-report.json\r\n expire_in: 1 week\r\n`;\r\n}\r\n\r\n/**\r\n * Git hooks 설정 실행\r\n */\r\nasync function runHooksSetup(type: HookType | undefined, options: { install?: boolean }): Promise<void> {\r\n const projectRoot = await findSddRoot();\r\n if (!projectRoot) {\r\n logger.error('SDD 프로젝트를 찾을 수 없습니다. `sdd init`을 먼저 실행하세요.');\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n const hooksDir = path.join(projectRoot, '.husky');\r\n\r\n if (options.install) {\r\n logger.info('husky 설치 방법:');\r\n logger.newline();\r\n logger.listItem('npm install -D husky');\r\n logger.listItem('npx husky init');\r\n logger.newline();\r\n }\r\n\r\n // hooks 디렉토리가 없으면 생성\r\n if (!(await directoryExists(hooksDir))) {\r\n await ensureDir(hooksDir);\r\n }\r\n\r\n const hooks: HookType[] = type ? [type] : ['pre-commit', 'pre-push'];\r\n\r\n for (const hook of hooks) {\r\n const hookContent = generateHookScript(hook);\r\n const hookPath = path.join(hooksDir, hook);\r\n await writeFile(hookPath, hookContent);\r\n logger.info(`✅ ${hook} 훅 생성: .husky/${hook}`);\r\n }\r\n\r\n logger.newline();\r\n logger.info('훅이 설정되었습니다.');\r\n logger.newline();\r\n logger.info('husky가 설치되어 있다면 훅이 자동으로 실행됩니다.');\r\n logger.info('그렇지 않으면 다음 명령어로 설치하세요:');\r\n logger.listItem('npm install -D husky && npx husky init');\r\n}\r\n\r\n/**\r\n * Git hook 스크립트 생성\r\n */\r\nfunction generateHookScript(hook: HookType): string {\r\n switch (hook) {\r\n case 'pre-commit':\r\n return `#!/bin/sh\r\n. \"$(dirname \"$0\")/_/husky.sh\"\r\n\r\n# SDD 스펙 검증\r\necho \"🔍 Validating SDD specs...\"\r\nnpx sdd validate\r\n\r\nif [ $? -ne 0 ]; then\r\n echo \"❌ SDD validation failed. Please fix the issues before committing.\"\r\n exit 1\r\nfi\r\n\r\necho \"✅ SDD validation passed.\"\r\n`;\r\n\r\n case 'pre-push':\r\n return `#!/bin/sh\r\n. \"$(dirname \"$0\")/_/husky.sh\"\r\n\r\n# SDD 스펙 검증 (strict mode)\r\necho \"🔍 Validating SDD specs (strict mode)...\"\r\nnpx sdd validate --strict\r\n\r\nif [ $? -ne 0 ]; then\r\n echo \"❌ SDD validation failed. Please fix all issues before pushing.\"\r\n exit 1\r\nfi\r\n\r\n# Constitution 검증\r\necho \"📜 Validating constitution...\"\r\nnpx sdd constitution validate\r\n\r\nif [ $? -ne 0 ]; then\r\n echo \"❌ Constitution validation failed.\"\r\n exit 1\r\nfi\r\n\r\necho \"✅ All validations passed.\"\r\n`;\r\n\r\n case 'commit-msg':\r\n return `#!/bin/sh\r\n. \"$(dirname \"$0\")/_/husky.sh\"\r\n\r\n# 커밋 메시지에서 스펙 참조 확인 (선택적)\r\nCOMMIT_MSG=$(cat \"$1\")\r\n\r\n# spec: 또는 feat(spec-id): 형식 확인\r\nif echo \"$COMMIT_MSG\" | grep -qE \"^(feat|fix|docs|chore)\\\\([a-z-]+\\\\):\"; then\r\n echo \"✅ Commit message format is valid.\"\r\nelse\r\n echo \"⚠️ Commit message doesn't reference a spec.\"\r\n echo \" Consider using: feat(<spec-id>): <message>\"\r\nfi\r\n`;\r\n\r\n default:\r\n return '#!/bin/sh\\nexit 0\\n';\r\n }\r\n}\r\n\r\n/**\r\n * CI 체크 실행\r\n */\r\nasync function runCiCheck(options: { strict?: boolean; failOnWarning?: boolean }): Promise<void> {\r\n const projectRoot = await findSddRoot();\r\n if (!projectRoot) {\r\n logger.error('SDD 프로젝트를 찾을 수 없습니다.');\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n logger.info('🔍 CI 검증 시작...');\r\n logger.newline();\r\n\r\n let hasErrors = false;\r\n let hasWarnings = false;\r\n\r\n // 1. Constitution 검증\r\n logger.info('1. Constitution 검증...');\r\n const constitutionPath = path.join(projectRoot, '.sdd', 'constitution.md');\r\n if (await fileExists(constitutionPath)) {\r\n logger.info(' ✅ constitution.md 존재');\r\n } else {\r\n logger.warn(' ⚠️ constitution.md 없음');\r\n hasWarnings = true;\r\n }\r\n\r\n // 2. 스펙 디렉토리 확인\r\n logger.info('2. 스펙 디렉토리 확인...');\r\n const specsPath = path.join(projectRoot, '.sdd', 'specs');\r\n if (await directoryExists(specsPath)) {\r\n logger.info(' ✅ specs/ 디렉토리 존재');\r\n } else {\r\n logger.warn(' ⚠️ specs/ 디렉토리 없음');\r\n hasWarnings = true;\r\n }\r\n\r\n // 3. 기본 구조 확인\r\n logger.info('3. 기본 구조 확인...');\r\n const requiredDirs = ['changes', 'archive', 'templates'];\r\n for (const dir of requiredDirs) {\r\n const dirPath = path.join(projectRoot, '.sdd', dir);\r\n if (await directoryExists(dirPath)) {\r\n logger.info(` ✅ ${dir}/ 존재`);\r\n } else {\r\n if (options.strict) {\r\n logger.error(` ❌ ${dir}/ 없음`);\r\n hasErrors = true;\r\n } else {\r\n logger.warn(` ⚠️ ${dir}/ 없음`);\r\n hasWarnings = true;\r\n }\r\n }\r\n }\r\n\r\n logger.newline();\r\n\r\n // 결과 출력\r\n if (hasErrors) {\r\n logger.error('❌ CI 검증 실패');\r\n process.exit(ExitCode.VALIDATION_ERROR);\r\n } else if (hasWarnings && options.failOnWarning) {\r\n logger.warn('⚠️ 경고가 있습니다 (--fail-on-warning)');\r\n process.exit(ExitCode.VALIDATION_ERROR);\r\n } else if (hasWarnings) {\r\n logger.warn('⚠️ 경고가 있지만 검증은 통과했습니다');\r\n } else {\r\n logger.success('✅ CI 검증 통과');\r\n }\r\n}\r\n","/**\r\n * sdd transition 명령어 - 워크플로우 간 전환\r\n *\r\n * new ↔ change 워크플로우 간 전환을 지원합니다.\r\n */\r\nimport { Command } from 'commander';\r\nimport path from 'node:path';\r\nimport { promises as fs } from 'node:fs';\r\nimport * as logger from '../../utils/logger.js';\r\nimport { ExitCode } from '../../errors/index.js';\r\nimport { findSddRoot, fileExists, readFile, ensureDir, writeFile, directoryExists } from '../../utils/fs.js';\r\nimport { generateChangeId } from '../../core/change/index.js';\r\n\r\n/**\r\n * 전환 방향\r\n */\r\ntype TransitionDirection = 'new-to-change' | 'change-to-new';\r\n\r\n/**\r\n * transition 명령어 등록\r\n */\r\nexport function registerTransitionCommand(program: Command): void {\r\n const transition = program\r\n .command('transition')\r\n .description('워크플로우 간 전환을 수행합니다');\r\n\r\n // new → change 전환\r\n transition\r\n .command('new-to-change <spec-id>')\r\n .description('새 기능 작업을 기존 스펙 변경으로 전환합니다')\r\n .option('-t, --title <title>', '변경 제안 제목')\r\n .option('-r, --reason <reason>', '전환 사유')\r\n .action(async (specId: string, options: { title?: string; reason?: string }) => {\r\n try {\r\n await runNewToChange(specId, options);\r\n } catch (error) {\r\n logger.error(error instanceof Error ? error.message : String(error));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n });\r\n\r\n // change → new 전환\r\n transition\r\n .command('change-to-new <change-id>')\r\n .description('기존 스펙 변경 작업을 새 기능으로 전환합니다')\r\n .option('-n, --name <name>', '새 기능 이름')\r\n .option('-r, --reason <reason>', '전환 사유')\r\n .action(async (changeId: string, options: { name?: string; reason?: string }) => {\r\n try {\r\n await runChangeToNew(changeId, options);\r\n } catch (error) {\r\n logger.error(error instanceof Error ? error.message : String(error));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n });\r\n\r\n // 전환 가이드\r\n transition\r\n .command('guide')\r\n .description('워크플로우 전환 가이드를 표시합니다')\r\n .action(() => {\r\n displayTransitionGuide();\r\n });\r\n}\r\n\r\n/**\r\n * new → change 전환 실행\r\n *\r\n * 새 기능 작성 중 기존 스펙과 중복/관련됨을 발견했을 때\r\n * 변경 제안 워크플로우로 전환합니다.\r\n */\r\nasync function runNewToChange(\r\n specId: string,\r\n options: { title?: string; reason?: string }\r\n): Promise<void> {\r\n const projectRoot = await findSddRoot();\r\n if (!projectRoot) {\r\n logger.error('SDD 프로젝트를 찾을 수 없습니다. `sdd init`을 먼저 실행하세요.');\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n const sddPath = path.join(projectRoot, '.sdd');\r\n const specsPath = path.join(sddPath, 'specs');\r\n\r\n // 대상 스펙 확인\r\n const specPath = path.join(specsPath, specId, 'spec.md');\r\n if (!(await fileExists(specPath))) {\r\n logger.error(`스펙을 찾을 수 없습니다: ${specId}`);\r\n logger.info('사용 가능한 스펙 목록은 `sdd list`로 확인하세요.');\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n logger.info('=== 워크플로우 전환: new → change ===');\r\n logger.newline();\r\n logger.info(`대상 스펙: ${specId}`);\r\n\r\n // 변경 ID 생성\r\n const changeId = generateChangeId();\r\n const changePath = path.join(sddPath, 'changes', changeId);\r\n await ensureDir(changePath);\r\n\r\n // 기존 스펙 내용 읽기\r\n const specContent = await readFile(specPath);\r\n if (!specContent.success) {\r\n logger.error('스펙 파일을 읽을 수 없습니다.');\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n // proposal.md 생성\r\n const title = options.title || `${specId} 기능 확장`;\r\n const reason = options.reason || 'new 워크플로우에서 전환됨';\r\n const proposalContent = generateTransitionProposal(specId, title, reason, 'new-to-change');\r\n await writeFile(path.join(changePath, 'proposal.md'), proposalContent);\r\n\r\n // delta.md 생성 (템플릿)\r\n const deltaContent = generateDeltaTemplate(specId);\r\n await writeFile(path.join(changePath, 'delta.md'), deltaContent);\r\n\r\n // tasks.md 생성 (템플릿)\r\n const tasksContent = generateTasksTemplate();\r\n await writeFile(path.join(changePath, 'tasks.md'), tasksContent);\r\n\r\n logger.newline();\r\n logger.success(`전환 완료! 변경 제안이 생성되었습니다.`);\r\n logger.newline();\r\n logger.info(`변경 ID: ${changeId}`);\r\n logger.info(`위치: .sdd/changes/${changeId}/`);\r\n logger.newline();\r\n logger.info('다음 단계:');\r\n logger.listItem(`1. .sdd/changes/${changeId}/proposal.md 편집`);\r\n logger.listItem(`2. .sdd/changes/${changeId}/delta.md 작성`);\r\n logger.listItem(`3. sdd change validate ${changeId}`);\r\n logger.listItem(`4. sdd change apply ${changeId}`);\r\n logger.newline();\r\n logger.info('또는 슬래시 커맨드 사용:');\r\n logger.listItem('/sdd.change - 변경 내용 작성 도움');\r\n}\r\n\r\n/**\r\n * change → new 전환 실행\r\n *\r\n * 변경 작업 중 범위가 너무 커서 새 기능으로 분리해야 할 때\r\n * 새 기능 워크플로우로 전환합니다.\r\n */\r\nasync function runChangeToNew(\r\n changeId: string,\r\n options: { name?: string; reason?: string }\r\n): Promise<void> {\r\n const projectRoot = await findSddRoot();\r\n if (!projectRoot) {\r\n logger.error('SDD 프로젝트를 찾을 수 없습니다. `sdd init`을 먼저 실행하세요.');\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n const sddPath = path.join(projectRoot, '.sdd');\r\n const changePath = path.join(sddPath, 'changes', changeId);\r\n\r\n // 변경 제안 확인\r\n if (!(await directoryExists(changePath))) {\r\n logger.error(`변경 제안을 찾을 수 없습니다: ${changeId}`);\r\n logger.info('진행 중인 변경 목록은 `sdd change -l`로 확인하세요.');\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n logger.info('=== 워크플로우 전환: change → new ===');\r\n logger.newline();\r\n logger.info(`원본 변경: ${changeId}`);\r\n\r\n // proposal.md에서 제목 추출\r\n const proposalPath = path.join(changePath, 'proposal.md');\r\n let extractedTitle = '';\r\n if (await fileExists(proposalPath)) {\r\n const proposalContent = await readFile(proposalPath);\r\n if (proposalContent.success) {\r\n const titleMatch = proposalContent.data.match(/^#\\s+(.+)$/m);\r\n if (titleMatch) {\r\n extractedTitle = titleMatch[1];\r\n }\r\n }\r\n }\r\n\r\n // 새 기능 이름 결정\r\n const featureName = options.name || extractedTitle.toLowerCase().replace(/\\s+/g, '-') || `feature-from-${changeId}`;\r\n const specsPath = path.join(sddPath, 'specs');\r\n const newSpecPath = path.join(specsPath, featureName);\r\n\r\n // 이미 존재하는지 확인\r\n if (await directoryExists(newSpecPath)) {\r\n logger.error(`스펙이 이미 존재합니다: ${featureName}`);\r\n logger.info('다른 이름을 지정하세요: --name <name>');\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n await ensureDir(newSpecPath);\r\n\r\n // spec.md 생성\r\n const reason = options.reason || 'change 워크플로우에서 전환됨';\r\n const specContent = generateTransitionSpec(featureName, extractedTitle || featureName, reason, changeId);\r\n await writeFile(path.join(newSpecPath, 'spec.md'), specContent);\r\n\r\n // plan.md 템플릿 생성\r\n const planContent = generatePlanTemplate(featureName);\r\n await writeFile(path.join(newSpecPath, 'plan.md'), planContent);\r\n\r\n // tasks.md 템플릿 생성\r\n const tasksContent = generateTasksTemplate();\r\n await writeFile(path.join(newSpecPath, 'tasks.md'), tasksContent);\r\n\r\n // 원본 변경 제안 상태 업데이트\r\n const statusPath = path.join(changePath, '.status');\r\n await writeFile(statusPath, JSON.stringify({\r\n status: 'transitioned',\r\n transitionedTo: featureName,\r\n transitionedAt: new Date().toISOString(),\r\n reason,\r\n }, null, 2));\r\n\r\n logger.newline();\r\n logger.success(`전환 완료! 새 기능 스펙이 생성되었습니다.`);\r\n logger.newline();\r\n logger.info(`기능 이름: ${featureName}`);\r\n logger.info(`위치: .sdd/specs/${featureName}/`);\r\n logger.info(`원본 변경 ${changeId}은 'transitioned' 상태로 변경되었습니다.`);\r\n logger.newline();\r\n logger.info('다음 단계:');\r\n logger.listItem(`1. .sdd/specs/${featureName}/spec.md 편집`);\r\n logger.listItem(`2. sdd new plan ${featureName}`);\r\n logger.listItem(`3. sdd new tasks ${featureName}`);\r\n logger.listItem(`4. 구현 진행`);\r\n logger.newline();\r\n logger.info('또는 슬래시 커맨드 사용:');\r\n logger.listItem('/sdd.new - 명세 작성 도움');\r\n}\r\n\r\n/**\r\n * 전환 가이드 표시\r\n */\r\nfunction displayTransitionGuide(): void {\r\n logger.info('=== 워크플로우 전환 가이드 ===');\r\n logger.newline();\r\n\r\n logger.info('## new → change 전환');\r\n logger.newline();\r\n logger.info('사용 시점:');\r\n logger.listItem('새 기능 작성 중 기존 스펙과 중복 발견');\r\n logger.listItem('기존 기능 확장이 더 적절한 경우');\r\n logger.listItem('의존성 분석 결과 기존 스펙 수정 필요');\r\n logger.newline();\r\n logger.info('명령어:');\r\n logger.listItem('sdd transition new-to-change <spec-id>');\r\n logger.listItem(' -t, --title <title> : 변경 제안 제목');\r\n logger.listItem(' -r, --reason <reason>: 전환 사유');\r\n logger.newline();\r\n\r\n logger.info('## change → new 전환');\r\n logger.newline();\r\n logger.info('사용 시점:');\r\n logger.listItem('변경 범위가 너무 커서 별도 기능으로 분리 필요');\r\n logger.listItem('기존 스펙과 독립적인 새 기능으로 발전');\r\n logger.listItem('영향도 분석 결과 분리가 안전');\r\n logger.newline();\r\n logger.info('명령어:');\r\n logger.listItem('sdd transition change-to-new <change-id>');\r\n logger.listItem(' -n, --name <name> : 새 기능 이름');\r\n logger.listItem(' -r, --reason <reason>: 전환 사유');\r\n logger.newline();\r\n\r\n logger.info('## 전환 판단 기준');\r\n logger.newline();\r\n logger.info('new → change:');\r\n logger.listItem('영향받는 스펙 수 ≤ 3개');\r\n logger.listItem('변경이 기존 기능의 자연스러운 확장');\r\n logger.listItem('새 시나리오 추가보다 기존 시나리오 수정 중심');\r\n logger.newline();\r\n logger.info('change → new:');\r\n logger.listItem('영향받는 스펙 수 > 3개');\r\n logger.listItem('새로운 개념/도메인 도입');\r\n logger.listItem('기존 스펙과 독립적으로 테스트 가능');\r\n}\r\n\r\n/**\r\n * 전환용 proposal.md 생성\r\n */\r\nfunction generateTransitionProposal(\r\n specId: string,\r\n title: string,\r\n reason: string,\r\n direction: TransitionDirection\r\n): string {\r\n const now = new Date().toISOString().split('T')[0];\r\n return `---\r\nid: ${specId}-change\r\ntitle: \"${title}\"\r\ntarget_spec: ${specId}\r\nstatus: draft\r\ncreated_at: ${now}\r\ntransition_from: ${direction === 'new-to-change' ? 'new' : 'change'}\r\ntransition_reason: \"${reason}\"\r\n---\r\n\r\n# ${title}\r\n\r\n## 배경\r\n\r\n> 이 변경 제안은 \\`${direction}\\` 워크플로우 전환으로 생성되었습니다.\r\n> 전환 사유: ${reason}\r\n\r\n<!-- 변경이 필요한 배경을 설명하세요 -->\r\n\r\n## 변경 목적\r\n\r\n<!-- 이 변경으로 달성하려는 목표를 설명하세요 -->\r\n\r\n## 영향 범위\r\n\r\n- 대상 스펙: \\`${specId}\\`\r\n\r\n<!-- 관련된 다른 스펙이 있다면 나열하세요 -->\r\n\r\n## 제약 사항\r\n\r\n<!-- 이 변경의 제약 조건을 설명하세요 -->\r\n\r\n## 참고 사항\r\n\r\n<!-- 추가 참고 정보가 있다면 작성하세요 -->\r\n`;\r\n}\r\n\r\n/**\r\n * delta.md 템플릿 생성\r\n */\r\nfunction generateDeltaTemplate(specId: string): string {\r\n return `---\r\ntarget: ${specId}\r\n---\r\n\r\n# Delta: ${specId}\r\n\r\n## ADDED\r\n\r\n<!-- 추가되는 요구사항/시나리오 -->\r\n\r\n## MODIFIED\r\n\r\n<!-- 변경되는 내용 (Before/After) -->\r\n\r\n### 요구사항 변경\r\n\r\n**Before:**\r\n\\`\\`\\`\r\n<!-- 기존 내용 -->\r\n\\`\\`\\`\r\n\r\n**After:**\r\n\\`\\`\\`\r\n<!-- 변경된 내용 -->\r\n\\`\\`\\`\r\n\r\n## REMOVED\r\n\r\n<!-- 제거되는 내용 (있는 경우) -->\r\n`;\r\n}\r\n\r\n/**\r\n * 전환용 spec.md 생성\r\n */\r\nfunction generateTransitionSpec(\r\n featureName: string,\r\n title: string,\r\n reason: string,\r\n fromChangeId: string\r\n): string {\r\n const now = new Date().toISOString().split('T')[0];\r\n return `---\r\nid: ${featureName}\r\ntitle: \"${title}\"\r\nstatus: draft\r\ncreated_at: ${now}\r\ntransition_from: change\r\ntransition_change_id: ${fromChangeId}\r\ntransition_reason: \"${reason}\"\r\n---\r\n\r\n# ${title}\r\n\r\n> 이 명세는 변경 제안 \\`${fromChangeId}\\`에서 분리되어 생성되었습니다.\r\n> 전환 사유: ${reason}\r\n\r\n## 개요\r\n\r\n<!-- 기능 개요를 작성하세요 -->\r\n\r\n## 요구사항\r\n\r\n### 기능 요구사항\r\n\r\n<!-- RFC 2119 키워드(MUST, SHOULD, MAY)를 사용하세요 -->\r\n\r\n### 비기능 요구사항\r\n\r\n<!-- 성능, 보안 등 비기능 요구사항 -->\r\n\r\n## 시나리오\r\n\r\n### 기본 시나리오\r\n\r\n\\`\\`\\`gherkin\r\nGIVEN 초기 상태\r\nWHEN 사용자가 동작을 수행하면\r\nTHEN 기대 결과가 발생한다\r\n\\`\\`\\`\r\n\r\n## 의존성\r\n\r\n<!-- 관련 스펙 참조 -->\r\n\r\n## 비고\r\n\r\n<!-- 추가 참고 사항 -->\r\n`;\r\n}\r\n\r\n/**\r\n * plan.md 템플릿 생성\r\n */\r\nfunction generatePlanTemplate(featureName: string): string {\r\n return `---\r\nspec: ${featureName}\r\nstatus: draft\r\n---\r\n\r\n# 구현 계획: ${featureName}\r\n\r\n## 기술 결정\r\n\r\n<!-- 구현에 필요한 기술 결정 사항 -->\r\n\r\n## 구현 전략\r\n\r\n<!-- 단계별 구현 전략 -->\r\n\r\n## 영향 분석\r\n\r\n<!-- 이 구현이 다른 부분에 미치는 영향 -->\r\n\r\n## 테스트 전략\r\n\r\n<!-- 테스트 방법 및 범위 -->\r\n\r\n## 위험 요소\r\n\r\n<!-- 구현 시 고려할 위험 요소 -->\r\n`;\r\n}\r\n\r\n/**\r\n * tasks.md 템플릿 생성\r\n */\r\nfunction generateTasksTemplate(): string {\r\n return `---\r\nstatus: pending\r\n---\r\n\r\n# Tasks\r\n\r\n## 작업 목록\r\n\r\n- [ ] 작업 1\r\n- [ ] 작업 2\r\n- [ ] 작업 3\r\n\r\n## 완료 조건\r\n\r\n- [ ] 모든 시나리오 테스트 통과\r\n- [ ] 코드 리뷰 완료\r\n- [ ] 문서 업데이트\r\n`;\r\n}\r\n"],"mappings":"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AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAmEX;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAqEX;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAuEX;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAiEX;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAsDX;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAoEX;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA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","names":["path","error","error","z","title","error","info","title","path","path","success","program","error","path","success","path","chalk","path","title","error","path","fs","path","program","error","path","chalk","program","error","path","fs","z","matter","z","title","error","matter","z","title","error","path","fs","path","fs","error","title","program","error","path","changePath","fs","title","success","path","z","ImpactLevelSchema","fs","path","matter","error","path","path","error","program","error","path","path","fs","z","z","matter","matter","error","title","program","path","title","fs","error","setNextFeatureNumber","path","fs","program","path","fs","info","path","fs","program","path","fs","getStatusIcon","path","program","error","runValidate","path","success","path","fs","program","error","path","fs","path","fs","program","error","path","fs","title","path","program","error","success","path","path","program","error","path","title","success","require"]}
1
+ {"version":3,"sources":["../../src/errors/codes.ts","../../src/errors/messages.ts","../../src/errors/base.ts","../../src/errors/index.ts","../../src/types/index.ts","../../src/utils/fs.ts","../../src/core/new/schemas.ts","../../src/core/new/spec-generator.ts","../../src/core/new/plan-generator.ts","../../src/core/new/task-generator.ts","../../src/core/new/branch.ts","../../src/core/new/checklist.ts","../../src/core/new/counter.ts","../../src/core/new/index.ts","../../src/cli/index.ts","../../src/cli/commands/init.ts","../../src/utils/logger.ts","../../src/generators/agents-md.ts","../../src/generators/claude-commands.ts","../../src/cli/commands/validate.ts","../../src/core/spec/validator.ts","../../src/core/spec/parser.ts","../../src/core/spec/schemas.ts","../../src/core/constitution/schemas.ts","../../src/core/constitution/parser.ts","../../src/core/constitution/changelog.ts","../../src/core/constitution/violation-checker.ts","../../src/prompts/index.ts","../../src/cli/commands/prompt.ts","../../src/cli/commands/change.ts","../../src/core/change/schemas.ts","../../src/core/change/proposal.ts","../../src/core/change/delta.ts","../../src/core/change/archive.ts","../../src/cli/commands/impact.ts","../../src/core/impact/schemas.ts","../../src/core/impact/graph.ts","../../src/core/impact/analyzer.ts","../../src/core/impact/simulator.ts","../../src/core/impact/code-analyzer.ts","../../src/cli/commands/new.ts","../../src/utils/index.ts","../../src/cli/commands/status.ts","../../src/cli/commands/list.ts","../../src/cli/commands/constitution.ts","../../src/cli/commands/start.ts","../../src/cli/commands/migrate.ts","../../src/core/migrate/detector.ts","../../src/cli/commands/cicd.ts","../../src/cli/commands/transition.ts","../../src/cli/commands/watch.ts","../../src/core/watch/watcher.ts","../../src/cli/commands/quality.ts","../../src/core/quality/analyzer.ts","../../src/cli/commands/report.ts","../../src/core/report/reporter.ts"],"sourcesContent":["/**\r\n * 에러 코드 정의\r\n */\r\n\r\n/**\r\n * CLI 종료 코드\r\n */\r\nexport const ExitCode = {\r\n SUCCESS: 0,\r\n GENERAL_ERROR: 1,\r\n VALIDATION_FAILED: 2,\r\n CONSTITUTION_VIOLATION: 3,\r\n FILE_SYSTEM_ERROR: 4,\r\n USER_CANCELLED: 5,\r\n} as const;\r\n\r\nexport type ExitCode = (typeof ExitCode)[keyof typeof ExitCode];\r\n\r\n/**\r\n * 에러 코드\r\n */\r\nexport const ErrorCode = {\r\n // 일반 에러 (E0xx)\r\n UNKNOWN: 'E001',\r\n INVALID_ARGUMENT: 'E002',\r\n NOT_INITIALIZED: 'E003',\r\n\r\n // 파일 시스템 에러 (E1xx)\r\n FILE_NOT_FOUND: 'E101',\r\n FILE_READ_ERROR: 'E102',\r\n FILE_WRITE_ERROR: 'E103',\r\n DIRECTORY_NOT_FOUND: 'E104',\r\n DIRECTORY_EXISTS: 'E105',\r\n\r\n // 스펙 검증 에러 (E2xx)\r\n SPEC_PARSE_ERROR: 'E201',\r\n SPEC_INVALID_FORMAT: 'E202',\r\n SPEC_MISSING_REQUIRED: 'E203',\r\n RFC2119_VIOLATION: 'E204',\r\n GWT_INVALID_FORMAT: 'E205',\r\n\r\n // Constitution 에러 (E3xx)\r\n CONSTITUTION_NOT_FOUND: 'E301',\r\n CONSTITUTION_PARSE_ERROR: 'E302',\r\n CONSTITUTION_VIOLATION: 'E303',\r\n CONSTITUTION_VERSION_MISMATCH: 'E304',\r\n\r\n // 변경 워크플로우 에러 (E4xx)\r\n PROPOSAL_NOT_FOUND: 'E401',\r\n PROPOSAL_INVALID: 'E402',\r\n DELTA_CONFLICT: 'E403',\r\n ARCHIVE_FAILED: 'E404',\r\n\r\n // 분석 에러 (E5xx)\r\n ANALYSIS_FAILED: 'E501',\r\n INSUFFICIENT_DATA: 'E502',\r\n} as const;\r\n\r\nexport type ErrorCode = (typeof ErrorCode)[keyof typeof ErrorCode];\r\n","/**\r\n * 에러 메시지 정의\r\n */\r\nimport { ErrorCode } from './codes.js';\r\n\r\n/**\r\n * 에러 코드별 메시지 템플릿\r\n */\r\nexport const ErrorMessages: Record<ErrorCode, string> = {\r\n // 일반 에러\r\n [ErrorCode.UNKNOWN]: '알 수 없는 오류가 발생했습니다',\r\n [ErrorCode.INVALID_ARGUMENT]: '잘못된 인자입니다: {0}',\r\n [ErrorCode.NOT_INITIALIZED]: 'SDD 프로젝트가 초기화되지 않았습니다. `sdd init`을 먼저 실행하세요',\r\n\r\n // 파일 시스템 에러\r\n [ErrorCode.FILE_NOT_FOUND]: '파일을 찾을 수 없습니다: {0}',\r\n [ErrorCode.FILE_READ_ERROR]: '파일 읽기 실패: {0}',\r\n [ErrorCode.FILE_WRITE_ERROR]: '파일 쓰기 실패: {0}',\r\n [ErrorCode.DIRECTORY_NOT_FOUND]: '디렉토리를 찾을 수 없습니다: {0}',\r\n [ErrorCode.DIRECTORY_EXISTS]: '디렉토리가 이미 존재합니다: {0}',\r\n\r\n // 스펙 검증 에러\r\n [ErrorCode.SPEC_PARSE_ERROR]: '스펙 파싱 실패: {0}',\r\n [ErrorCode.SPEC_INVALID_FORMAT]: '잘못된 스펙 형식: {0}',\r\n [ErrorCode.SPEC_MISSING_REQUIRED]: '필수 필드 누락: {0}',\r\n [ErrorCode.RFC2119_VIOLATION]: 'RFC 2119 형식 위반: {0}',\r\n [ErrorCode.GWT_INVALID_FORMAT]: 'GIVEN-WHEN-THEN 형식 위반: {0}',\r\n\r\n // Constitution 에러\r\n [ErrorCode.CONSTITUTION_NOT_FOUND]: 'constitution.md를 찾을 수 없습니다',\r\n [ErrorCode.CONSTITUTION_PARSE_ERROR]: 'Constitution 파싱 실패: {0}',\r\n [ErrorCode.CONSTITUTION_VIOLATION]: 'Constitution 원칙 위반: {0}',\r\n [ErrorCode.CONSTITUTION_VERSION_MISMATCH]: 'Constitution 버전 불일치: {0}',\r\n\r\n // 변경 워크플로우 에러\r\n [ErrorCode.PROPOSAL_NOT_FOUND]: '제안서를 찾을 수 없습니다: {0}',\r\n [ErrorCode.PROPOSAL_INVALID]: '잘못된 제안서 형식: {0}',\r\n [ErrorCode.DELTA_CONFLICT]: '델타 충돌: {0}',\r\n [ErrorCode.ARCHIVE_FAILED]: '아카이브 실패: {0}',\r\n\r\n // 분석 에러\r\n [ErrorCode.ANALYSIS_FAILED]: '분석 실패: {0}',\r\n [ErrorCode.INSUFFICIENT_DATA]: '분석에 필요한 데이터 부족: {0}',\r\n};\r\n\r\n/**\r\n * 메시지 템플릿에 인자를 적용\r\n */\r\nexport function formatMessage(code: ErrorCode, ...args: string[]): string {\r\n let message = ErrorMessages[code];\r\n args.forEach((arg, index) => {\r\n message = message.replace(`{${index}}`, arg);\r\n });\r\n return message;\r\n}\r\n","/**\r\n * 에러 기본 클래스\r\n */\r\nimport { ErrorCode, ExitCode } from './codes.js';\r\nimport { formatMessage } from './messages.js';\r\n\r\n/**\r\n * SDD 도구의 기본 에러 클래스\r\n */\r\nexport class SddError extends Error {\r\n readonly code: ErrorCode;\r\n readonly exitCode: ExitCode;\r\n\r\n constructor(\r\n code: ErrorCode,\r\n message?: string,\r\n exitCode: ExitCode = ExitCode.GENERAL_ERROR\r\n ) {\r\n super(message ?? formatMessage(code));\r\n this.name = 'SddError';\r\n this.code = code;\r\n this.exitCode = exitCode;\r\n Error.captureStackTrace?.(this, this.constructor);\r\n }\r\n\r\n /**\r\n * 사용자 친화적 메시지\r\n */\r\n toUserMessage(): string {\r\n return `[${this.code}] ${this.message}`;\r\n }\r\n}\r\n\r\n/**\r\n * 파일 시스템 에러\r\n */\r\nexport class FileSystemError extends SddError {\r\n readonly path: string;\r\n\r\n constructor(code: ErrorCode, path: string) {\r\n super(code, formatMessage(code, path), ExitCode.FILE_SYSTEM_ERROR);\r\n this.name = 'FileSystemError';\r\n this.path = path;\r\n }\r\n}\r\n\r\n/**\r\n * 스펙 검증 에러\r\n */\r\nexport class ValidationError extends SddError {\r\n readonly details: string;\r\n\r\n constructor(code: ErrorCode, details: string) {\r\n super(code, formatMessage(code, details), ExitCode.VALIDATION_FAILED);\r\n this.name = 'ValidationError';\r\n this.details = details;\r\n }\r\n}\r\n\r\n/**\r\n * Constitution 위반 에러\r\n */\r\nexport class ConstitutionError extends SddError {\r\n readonly principle: string;\r\n\r\n constructor(principle: string) {\r\n super(\r\n ErrorCode.CONSTITUTION_VIOLATION,\r\n formatMessage(ErrorCode.CONSTITUTION_VIOLATION, principle),\r\n ExitCode.CONSTITUTION_VIOLATION\r\n );\r\n this.name = 'ConstitutionError';\r\n this.principle = principle;\r\n }\r\n}\r\n\r\n/**\r\n * 사용자 취소 에러\r\n */\r\nexport class UserCancelledError extends SddError {\r\n constructor(message = '사용자가 작업을 취소했습니다') {\r\n super(ErrorCode.UNKNOWN, message, ExitCode.USER_CANCELLED);\r\n this.name = 'UserCancelledError';\r\n }\r\n}\r\n\r\n/**\r\n * 변경 워크플로우 에러\r\n */\r\nexport class ChangeError extends SddError {\r\n constructor(message: string) {\r\n super(ErrorCode.UNKNOWN, message, ExitCode.GENERAL_ERROR);\r\n this.name = 'ChangeError';\r\n }\r\n}\r\n","/**\r\n * 에러 모듈 내보내기\r\n */\r\nexport * from './codes.js';\r\nexport * from './messages.js';\r\nexport * from './base.js';\r\n","/**\r\n * 공통 타입 정의\r\n */\r\n\r\n// ============================================================\r\n// 스펙 관련 타입\r\n// ============================================================\r\n\r\n/**\r\n * 스펙 문서 구조\r\n */\r\nexport interface Spec {\r\n id: string;\r\n title: string;\r\n status: SpecStatus;\r\n requirements: Requirement[];\r\n scenarios: Scenario[];\r\n dependencies: string[];\r\n metadata: SpecMetadata;\r\n}\r\n\r\nexport type SpecStatus = 'draft' | 'approved' | 'implemented';\r\n\r\nexport interface SpecMetadata {\r\n created?: string;\r\n updated?: string;\r\n author?: string;\r\n}\r\n\r\n/**\r\n * 요구사항 (RFC 2119)\r\n */\r\nexport interface Requirement {\r\n id: string;\r\n level: RequirementLevel;\r\n description: string;\r\n}\r\n\r\nexport type RequirementLevel = 'SHALL' | 'MUST' | 'SHOULD' | 'MAY';\r\n\r\n/**\r\n * 시나리오 (GIVEN-WHEN-THEN)\r\n */\r\nexport interface Scenario {\r\n name: string;\r\n given: string[];\r\n when: string;\r\n then: string[];\r\n}\r\n\r\n// ============================================================\r\n// Constitution 관련 타입\r\n// ============================================================\r\n\r\n/**\r\n * Constitution 원칙\r\n */\r\nexport interface Principle {\r\n id: string;\r\n title: string;\r\n description: string;\r\n level: PrincipleLevel;\r\n}\r\n\r\nexport type PrincipleLevel = 'core' | 'technical' | 'forbidden';\r\n\r\nexport interface Constitution {\r\n projectName: string;\r\n principles: Principle[];\r\n technicalStack?: string[];\r\n constraints?: string[];\r\n}\r\n\r\n// ============================================================\r\n// 변경 워크플로우 관련 타입\r\n// ============================================================\r\n\r\n/**\r\n * 변경 제안\r\n */\r\nexport interface Proposal {\r\n id: string;\r\n title: string;\r\n rationale: string;\r\n affectedSpecs: string[];\r\n deltas: Delta[];\r\n status: ProposalStatus;\r\n createdAt: string;\r\n}\r\n\r\nexport type ProposalStatus = 'draft' | 'review' | 'approved' | 'applied' | 'archived';\r\n\r\n/**\r\n * 델타 (변경사항)\r\n */\r\nexport interface Delta {\r\n type: DeltaType;\r\n target: string;\r\n before?: string;\r\n after?: string;\r\n}\r\n\r\nexport type DeltaType = 'ADDED' | 'MODIFIED' | 'REMOVED';\r\n\r\n// ============================================================\r\n// 검증 관련 타입\r\n// ============================================================\r\n\r\n/**\r\n * 검증 결과\r\n */\r\nexport interface ValidationResult {\r\n valid: boolean;\r\n errors: SpecValidationError[];\r\n warnings: SpecValidationWarning[];\r\n}\r\n\r\nexport interface SpecValidationError {\r\n code: string;\r\n message: string;\r\n location?: Location;\r\n}\r\n\r\nexport interface SpecValidationWarning {\r\n code: string;\r\n message: string;\r\n location?: Location;\r\n}\r\n\r\nexport interface Location {\r\n file?: string;\r\n line?: number;\r\n column?: number;\r\n}\r\n\r\n// ============================================================\r\n// 분석 관련 타입\r\n// ============================================================\r\n\r\n/**\r\n * 분석 결과\r\n */\r\nexport interface AnalysisResult {\r\n scale: Scale;\r\n recommendation: WorkflowRecommendation;\r\n confidence: number;\r\n rationale: string;\r\n alternatives: string[];\r\n}\r\n\r\nexport type Scale = 'small' | 'medium' | 'large';\r\nexport type WorkflowRecommendation = 'direct' | 'change' | 'new';\r\n\r\n// ============================================================\r\n// 유틸리티 타입\r\n// ============================================================\r\n\r\n/**\r\n * Result 타입 (에러 처리용)\r\n */\r\nexport type Result<T, E = Error> =\r\n | { success: true; data: T }\r\n | { success: false; error: E };\r\n\r\n/**\r\n * 성공 결과 생성 헬퍼\r\n */\r\nexport function success<T>(data: T): Result<T, never> {\r\n return { success: true, data };\r\n}\r\n\r\n/**\r\n * 실패 결과 생성 헬퍼\r\n */\r\nexport function failure<E>(error: E): Result<never, E> {\r\n return { success: false, error };\r\n}\r\n","/**\r\n * 파일 시스템 유틸리티\r\n */\r\nimport { promises as fs } from 'node:fs';\r\nimport path from 'node:path';\r\nimport { FileSystemError } from '../errors/index.js';\r\nimport { ErrorCode } from '../errors/codes.js';\r\nimport { Result, success, failure } from '../types/index.js';\r\n\r\n/**\r\n * 파일 존재 여부 확인\r\n */\r\nexport async function fileExists(filePath: string): Promise<boolean> {\r\n try {\r\n await fs.access(filePath);\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * 디렉토리 존재 여부 확인\r\n */\r\nexport async function directoryExists(dirPath: string): Promise<boolean> {\r\n try {\r\n const stat = await fs.stat(dirPath);\r\n return stat.isDirectory();\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * 파일 읽기\r\n */\r\nexport async function readFile(filePath: string): Promise<Result<string, FileSystemError>> {\r\n try {\r\n const content = await fs.readFile(filePath, 'utf-8');\r\n return success(content);\r\n } catch (error) {\r\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\r\n return failure(new FileSystemError(ErrorCode.FILE_NOT_FOUND, filePath));\r\n }\r\n return failure(new FileSystemError(ErrorCode.FILE_READ_ERROR, filePath));\r\n }\r\n}\r\n\r\n/**\r\n * 파일 쓰기\r\n */\r\nexport async function writeFile(\r\n filePath: string,\r\n content: string\r\n): Promise<Result<void, FileSystemError>> {\r\n try {\r\n const dir = path.dirname(filePath);\r\n await fs.mkdir(dir, { recursive: true });\r\n await fs.writeFile(filePath, content, 'utf-8');\r\n return success(undefined);\r\n } catch {\r\n return failure(new FileSystemError(ErrorCode.FILE_WRITE_ERROR, filePath));\r\n }\r\n}\r\n\r\n/**\r\n * 디렉토리 생성\r\n */\r\nexport async function ensureDir(dirPath: string): Promise<Result<void, FileSystemError>> {\r\n try {\r\n await fs.mkdir(dirPath, { recursive: true });\r\n return success(undefined);\r\n } catch {\r\n return failure(new FileSystemError(ErrorCode.FILE_WRITE_ERROR, dirPath));\r\n }\r\n}\r\n\r\n/**\r\n * 디렉토리 내 파일 목록\r\n */\r\nexport async function listFiles(\r\n dirPath: string,\r\n pattern?: RegExp\r\n): Promise<Result<string[], FileSystemError>> {\r\n try {\r\n const entries = await fs.readdir(dirPath, { withFileTypes: true });\r\n let files = entries\r\n .filter((entry) => entry.isFile())\r\n .map((entry) => path.join(dirPath, entry.name));\r\n\r\n if (pattern) {\r\n files = files.filter((file) => pattern.test(path.basename(file)));\r\n }\r\n\r\n return success(files);\r\n } catch {\r\n return failure(new FileSystemError(ErrorCode.DIRECTORY_NOT_FOUND, dirPath));\r\n }\r\n}\r\n\r\n/**\r\n * 디렉토리 내 항목 목록\r\n */\r\nexport async function readDir(dirPath: string): Promise<Result<string[], FileSystemError>> {\r\n try {\r\n const entries = await fs.readdir(dirPath);\r\n return success(entries);\r\n } catch {\r\n return failure(new FileSystemError(ErrorCode.DIRECTORY_NOT_FOUND, dirPath));\r\n }\r\n}\r\n\r\n/**\r\n * SDD 프로젝트 루트 찾기\r\n */\r\nexport async function findSddRoot(startPath: string = process.cwd()): Promise<string | null> {\r\n let currentPath = path.resolve(startPath);\r\n const root = path.parse(currentPath).root;\r\n\r\n while (currentPath !== root) {\r\n const sddPath = path.join(currentPath, '.sdd');\r\n if (await directoryExists(sddPath)) {\r\n return currentPath;\r\n }\r\n currentPath = path.dirname(currentPath);\r\n }\r\n\r\n return null;\r\n}\r\n\r\n/**\r\n * 디렉토리 복사 (재귀)\r\n */\r\nexport async function copyDir(\r\n srcPath: string,\r\n destPath: string\r\n): Promise<Result<void, FileSystemError>> {\r\n try {\r\n await fs.mkdir(destPath, { recursive: true });\r\n\r\n const entries = await fs.readdir(srcPath, { withFileTypes: true });\r\n\r\n for (const entry of entries) {\r\n const srcEntry = path.join(srcPath, entry.name);\r\n const destEntry = path.join(destPath, entry.name);\r\n\r\n if (entry.isDirectory()) {\r\n const result = await copyDir(srcEntry, destEntry);\r\n if (!result.success) {\r\n return result;\r\n }\r\n } else {\r\n await fs.copyFile(srcEntry, destEntry);\r\n }\r\n }\r\n\r\n return success(undefined);\r\n } catch {\r\n return failure(new FileSystemError(ErrorCode.FILE_WRITE_ERROR, destPath));\r\n }\r\n}\r\n\r\n/**\r\n * 디렉토리 삭제 (재귀)\r\n */\r\nexport async function removeDir(dirPath: string): Promise<Result<void, FileSystemError>> {\r\n try {\r\n await fs.rm(dirPath, { recursive: true, force: true });\r\n return success(undefined);\r\n } catch {\r\n return failure(new FileSystemError(ErrorCode.FILE_WRITE_ERROR, dirPath));\r\n }\r\n}\r\n","/**\r\n * 신규 기능 워크플로우 스키마\r\n */\r\nimport { z } from 'zod';\r\n\r\n/**\r\n * 기능 상태 스키마\r\n */\r\nexport const FeatureStatusSchema = z.enum([\r\n 'draft', // 초안 작성 중\r\n 'specified', // 명세 완료\r\n 'planned', // 계획 완료\r\n 'tasked', // 작업 분해 완료\r\n 'implementing', // 구현 중\r\n 'completed', // 완료\r\n]);\r\n\r\nexport type FeatureStatus = z.infer<typeof FeatureStatusSchema>;\r\n\r\n/**\r\n * 작업 상태 스키마\r\n */\r\nexport const TaskStatusSchema = z.enum([\r\n 'pending', // 대기 중\r\n 'in_progress', // 진행 중\r\n 'completed', // 완료\r\n 'blocked', // 차단됨\r\n]);\r\n\r\nexport type TaskStatus = z.infer<typeof TaskStatusSchema>;\r\n\r\n/**\r\n * 작업 우선순위 스키마\r\n */\r\nexport const TaskPrioritySchema = z.enum([\r\n 'high', // 높음\r\n 'medium', // 중간\r\n 'low', // 낮음\r\n]);\r\n\r\nexport type TaskPriority = z.infer<typeof TaskPrioritySchema>;\r\n\r\n/**\r\n * 기능 메타데이터 스키마\r\n */\r\nexport const FeatureMetadataSchema = z.object({\r\n id: z.string(),\r\n title: z.string(),\r\n status: FeatureStatusSchema,\r\n created: z.string(),\r\n updated: z.string().optional(),\r\n branch: z.string().optional(),\r\n depends: z.array(z.string()).nullable().default(null),\r\n});\r\n\r\nexport type FeatureMetadata = z.infer<typeof FeatureMetadataSchema>;\r\n\r\n/**\r\n * 작업 항목 스키마\r\n */\r\nexport const TaskItemSchema = z.object({\r\n id: z.string(),\r\n title: z.string(),\r\n description: z.string().optional(),\r\n status: TaskStatusSchema,\r\n priority: TaskPrioritySchema,\r\n assignee: z.string().optional(),\r\n files: z.array(z.string()).optional(),\r\n dependencies: z.array(z.string()).optional(),\r\n});\r\n\r\nexport type TaskItem = z.infer<typeof TaskItemSchema>;\r\n\r\n/**\r\n * 구현 계획 스키마\r\n */\r\nexport const PlanSchema = z.object({\r\n overview: z.string(),\r\n techDecisions: z.array(z.object({\r\n decision: z.string(),\r\n rationale: z.string(),\r\n alternatives: z.array(z.string()).optional(),\r\n })),\r\n phases: z.array(z.object({\r\n name: z.string(),\r\n description: z.string(),\r\n deliverables: z.array(z.string()),\r\n })),\r\n risks: z.array(z.object({\r\n risk: z.string(),\r\n mitigation: z.string(),\r\n impact: z.enum(['high', 'medium', 'low']),\r\n })).optional(),\r\n testingStrategy: z.string().optional(),\r\n});\r\n\r\nexport type Plan = z.infer<typeof PlanSchema>;\r\n\r\n/**\r\n * 기능 ID 생성\r\n */\r\nexport function generateFeatureId(name: string): string {\r\n return name\r\n .toLowerCase()\r\n .replace(/[^a-z0-9가-힣]+/g, '-')\r\n .replace(/^-+|-+$/g, '')\r\n .slice(0, 50);\r\n}\r\n\r\n/**\r\n * 작업 ID 생성\r\n */\r\nexport function generateTaskId(featureId: string, index: number): string {\r\n return `${featureId}-task-${String(index).padStart(3, '0')}`;\r\n}\r\n\r\n/**\r\n * 브랜치명 생성\r\n */\r\nexport function generateBranchName(featureId: string): string {\r\n return `feature/${featureId}`;\r\n}\r\n","/**\r\n * 기능 명세 생성기\r\n */\r\nimport { FeatureMetadata, FeatureStatus } from './schemas.js';\r\n\r\n/**\r\n * 명세 생성 옵션\r\n */\r\nexport interface GenerateSpecOptions {\r\n id: string;\r\n title: string;\r\n description: string;\r\n requirements?: string[];\r\n scenarios?: Array<{\r\n name: string;\r\n given: string;\r\n when: string;\r\n then: string;\r\n }>;\r\n depends?: string[];\r\n status?: FeatureStatus;\r\n constitutionVersion?: string;\r\n}\r\n\r\n/**\r\n * spec.md 파일 내용 생성\r\n */\r\nexport function generateSpec(options: GenerateSpecOptions): string {\r\n const today = new Date().toISOString().split('T')[0];\r\n const status = options.status || 'draft';\r\n const depends = options.depends?.length ? `\\n - ${options.depends.join('\\n - ')}` : 'null';\r\n const constitutionLine = options.constitutionVersion\r\n ? `\\nconstitution_version: ${options.constitutionVersion}`\r\n : '';\r\n\r\n let content = `---\r\nid: ${options.id}\r\ntitle: \"${options.title}\"\r\nstatus: ${status}\r\ncreated: ${today}\r\ndepends: ${depends}${constitutionLine}\r\n---\r\n\r\n# ${options.title}\r\n\r\n> ${options.description}\r\n\r\n---\r\n\r\n## 개요\r\n\r\n${options.description}\r\n\r\n---\r\n\r\n## 요구사항\r\n\r\n`;\r\n\r\n if (options.requirements?.length) {\r\n options.requirements.forEach((req, index) => {\r\n content += `### REQ-${String(index + 1).padStart(2, '0')}: ${req.split(':')[0] || req}\r\n\r\n${req}\r\n\r\n`;\r\n });\r\n } else {\r\n content += `### REQ-01: [요구사항 제목]\r\n\r\n[요구사항 상세 설명]\r\n- 시스템은 [기능]을 지원해야 한다(SHALL)\r\n\r\n`;\r\n }\r\n\r\n content += `---\r\n\r\n## 시나리오\r\n\r\n`;\r\n\r\n if (options.scenarios?.length) {\r\n options.scenarios.forEach((scenario, index) => {\r\n content += `### Scenario ${index + 1}: ${scenario.name}\r\n\r\n- **GIVEN** ${scenario.given}\r\n- **WHEN** ${scenario.when}\r\n- **THEN** ${scenario.then}\r\n\r\n`;\r\n });\r\n } else {\r\n content += `### Scenario 1: [시나리오명]\r\n\r\n- **GIVEN** [전제 조건]\r\n- **WHEN** [행동/트리거]\r\n- **THEN** [예상 결과]\r\n\r\n`;\r\n }\r\n\r\n content += `---\r\n\r\n## 비기능 요구사항\r\n\r\n### 성능\r\n\r\n- 응답 시간: [N]ms 이내 (SHOULD)\r\n\r\n### 보안\r\n\r\n- [보안 요구사항] (SHALL)\r\n\r\n---\r\n\r\n## 제약사항\r\n\r\n- [기술적 제약사항]\r\n- [비즈니스 제약사항]\r\n\r\n---\r\n\r\n## 용어 정의\r\n\r\n| 용어 | 정의 |\r\n|------|------|\r\n| [용어1] | [정의1] |\r\n`;\r\n\r\n return content;\r\n}\r\n\r\n/**\r\n * 명세 메타데이터 파싱\r\n */\r\nexport function parseSpecMetadata(content: string): FeatureMetadata | null {\r\n const frontmatterMatch = content.match(/^---\\n([\\s\\S]*?)\\n---/);\r\n if (!frontmatterMatch) {\r\n return null;\r\n }\r\n\r\n const frontmatter = frontmatterMatch[1];\r\n const lines = frontmatter.split('\\n');\r\n const metadata: Record<string, unknown> = {};\r\n\r\n let currentKey = '';\r\n let isArray = false;\r\n const arrayItems: string[] = [];\r\n\r\n for (const line of lines) {\r\n if (line.startsWith(' - ')) {\r\n if (isArray) {\r\n arrayItems.push(line.replace(' - ', '').trim());\r\n }\r\n } else {\r\n if (isArray && currentKey) {\r\n metadata[currentKey] = arrayItems.length > 0 ? [...arrayItems] : null;\r\n arrayItems.length = 0;\r\n isArray = false;\r\n }\r\n\r\n const colonIndex = line.indexOf(':');\r\n if (colonIndex > 0) {\r\n const key = line.slice(0, colonIndex).trim();\r\n const value = line.slice(colonIndex + 1).trim();\r\n\r\n if (value === '' || value === '|') {\r\n currentKey = key;\r\n isArray = true;\r\n } else if (value === 'null') {\r\n metadata[key] = null;\r\n } else if (value.startsWith('\"') && value.endsWith('\"')) {\r\n metadata[key] = value.slice(1, -1);\r\n } else {\r\n metadata[key] = value;\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (isArray && currentKey) {\r\n metadata[currentKey] = arrayItems.length > 0 ? arrayItems : null;\r\n }\r\n\r\n return {\r\n id: metadata.id as string,\r\n title: metadata.title as string,\r\n status: metadata.status as FeatureStatus,\r\n created: metadata.created as string,\r\n updated: metadata.updated as string | undefined,\r\n branch: metadata.branch as string | undefined,\r\n depends: metadata.depends as string[] | null,\r\n };\r\n}\r\n\r\n/**\r\n * 명세 상태 업데이트\r\n */\r\nexport function updateSpecStatus(content: string, newStatus: FeatureStatus): string {\r\n const today = new Date().toISOString().split('T')[0];\r\n\r\n let updated = content.replace(\r\n /^(---\\n[\\s\\S]*?)status:\\s*\\w+/m,\r\n `$1status: ${newStatus}`\r\n );\r\n\r\n if (updated.includes('updated:')) {\r\n updated = updated.replace(\r\n /updated:\\s*[\\d-]+/,\r\n `updated: ${today}`\r\n );\r\n } else {\r\n updated = updated.replace(\r\n /(status:\\s*\\w+)/,\r\n `$1\\nupdated: ${today}`\r\n );\r\n }\r\n\r\n return updated;\r\n}\r\n","/**\r\n * 구현 계획 생성기\r\n */\r\nimport { Plan } from './schemas.js';\r\n\r\n/**\r\n * 계획 생성 옵션\r\n */\r\nexport interface GeneratePlanOptions {\r\n featureId: string;\r\n featureTitle: string;\r\n overview: string;\r\n techDecisions?: Array<{\r\n decision: string;\r\n rationale: string;\r\n alternatives?: string[];\r\n }>;\r\n phases?: Array<{\r\n name: string;\r\n description: string;\r\n deliverables: string[];\r\n }>;\r\n risks?: Array<{\r\n risk: string;\r\n mitigation: string;\r\n impact: 'high' | 'medium' | 'low';\r\n }>;\r\n testingStrategy?: string;\r\n constitutionCompliance?: string[];\r\n}\r\n\r\n/**\r\n * plan.md 파일 내용 생성\r\n */\r\nexport function generatePlan(options: GeneratePlanOptions): string {\r\n const today = new Date().toISOString().split('T')[0];\r\n\r\n let content = `---\r\nfeature: ${options.featureId}\r\ncreated: ${today}\r\nstatus: draft\r\n---\r\n\r\n# 구현 계획: ${options.featureTitle}\r\n\r\n> ${options.overview}\r\n\r\n---\r\n\r\n## 개요\r\n\r\n${options.overview}\r\n\r\n---\r\n\r\n## 기술 결정\r\n\r\n`;\r\n\r\n if (options.techDecisions?.length) {\r\n options.techDecisions.forEach((td, index) => {\r\n content += `### 결정 ${index + 1}: ${td.decision}\r\n\r\n**근거:** ${td.rationale}\r\n\r\n`;\r\n if (td.alternatives?.length) {\r\n content += `**대안 검토:**\r\n${td.alternatives.map(alt => `- ${alt}`).join('\\n')}\r\n\r\n`;\r\n }\r\n });\r\n } else {\r\n content += `### 결정 1: [기술 결정 사항]\r\n\r\n**근거:** [결정 근거]\r\n\r\n**대안 검토:**\r\n- [대안 1]\r\n- [대안 2]\r\n\r\n`;\r\n }\r\n\r\n content += `---\r\n\r\n## 구현 단계\r\n\r\n`;\r\n\r\n if (options.phases?.length) {\r\n options.phases.forEach((phase, index) => {\r\n content += `### Phase ${index + 1}: ${phase.name}\r\n\r\n${phase.description}\r\n\r\n**산출물:**\r\n${phase.deliverables.map(d => `- [ ] ${d}`).join('\\n')}\r\n\r\n`;\r\n });\r\n } else {\r\n content += `### Phase 1: 기반 구조\r\n\r\n[기반 구조 설명]\r\n\r\n**산출물:**\r\n- [ ] [산출물 1]\r\n- [ ] [산출물 2]\r\n\r\n### Phase 2: 핵심 기능\r\n\r\n[핵심 기능 설명]\r\n\r\n**산출물:**\r\n- [ ] [산출물 1]\r\n- [ ] [산출물 2]\r\n\r\n### Phase 3: 통합 및 테스트\r\n\r\n[통합 및 테스트 설명]\r\n\r\n**산출물:**\r\n- [ ] [산출물 1]\r\n- [ ] [산출물 2]\r\n\r\n`;\r\n }\r\n\r\n content += `---\r\n\r\n## 리스크 분석\r\n\r\n`;\r\n\r\n if (options.risks?.length) {\r\n content += `| 리스크 | 영향도 | 완화 전략 |\r\n|--------|--------|----------|\r\n`;\r\n options.risks.forEach(r => {\r\n const impactIcon = r.impact === 'high' ? '🔴' : r.impact === 'medium' ? '🟡' : '🟢';\r\n content += `| ${r.risk} | ${impactIcon} ${r.impact.toUpperCase()} | ${r.mitigation} |\r\n`;\r\n });\r\n content += '\\n';\r\n } else {\r\n content += `| 리스크 | 영향도 | 완화 전략 |\r\n|--------|--------|----------|\r\n| [리스크 1] | 🟡 MEDIUM | [완화 전략] |\r\n\r\n`;\r\n }\r\n\r\n content += `---\r\n\r\n## 테스트 전략\r\n\r\n`;\r\n\r\n if (options.testingStrategy) {\r\n content += `${options.testingStrategy}\r\n\r\n`;\r\n } else {\r\n content += `### 단위 테스트\r\n\r\n- 각 모듈별 단위 테스트 작성\r\n- 커버리지 목표: 80% 이상\r\n\r\n### 통합 테스트\r\n\r\n- API 엔드포인트 통합 테스트\r\n- 시나리오 기반 테스트\r\n\r\n### E2E 테스트\r\n\r\n- 주요 사용자 시나리오 검증\r\n\r\n`;\r\n }\r\n\r\n if (options.constitutionCompliance?.length) {\r\n content += `---\r\n\r\n## 헌법 준수 사항\r\n\r\n${options.constitutionCompliance.map(c => `- ${c}`).join('\\n')}\r\n`;\r\n }\r\n\r\n content += `\r\n---\r\n\r\n## 다음 단계\r\n\r\n1. [ ] 이 계획에 대한 검토 및 승인\r\n2. [ ] \\`/sdd:tasks\\` 명령으로 작업 분해\r\n3. [ ] 구현 시작\r\n`;\r\n\r\n return content;\r\n}\r\n\r\n/**\r\n * 계획 파싱\r\n */\r\nexport function parsePlan(content: string): Plan | null {\r\n // 기본 구조 추출\r\n const overviewMatch = content.match(/## 개요\\s*\\n\\n([\\s\\S]*?)(?=\\n---|\\n##)/);\r\n const overview = overviewMatch ? overviewMatch[1].trim() : '';\r\n\r\n // 기술 결정 추출\r\n const techDecisions: Plan['techDecisions'] = [];\r\n const techMatch = content.match(/## 기술 결정\\s*\\n([\\s\\S]*?)(?=\\n---)/);\r\n if (techMatch) {\r\n const decisions = techMatch[1].match(/### 결정 \\d+: ([^\\n]+)\\s*\\n\\n\\*\\*근거:\\*\\* ([^\\n]+)/g);\r\n if (decisions) {\r\n for (const d of decisions) {\r\n const match = d.match(/### 결정 \\d+: ([^\\n]+)\\s*\\n\\n\\*\\*근거:\\*\\* ([^\\n]+)/);\r\n if (match) {\r\n techDecisions.push({\r\n decision: match[1],\r\n rationale: match[2],\r\n });\r\n }\r\n }\r\n }\r\n }\r\n\r\n // 단계 추출\r\n const phases: Plan['phases'] = [];\r\n const phaseMatches = content.matchAll(/### Phase \\d+: ([^\\n]+)\\s*\\n+([^\\n*]+)\\s*\\n+\\*\\*산출물:\\*\\*\\s*\\n([\\s\\S]*?)(?=\\n###|\\n---|$)/g);\r\n for (const match of phaseMatches) {\r\n const deliverables = match[3]\r\n .split('\\n')\r\n .filter(l => l.startsWith('- '))\r\n .map(l => l.replace(/^- \\[[ x]\\] /, '').trim());\r\n\r\n phases.push({\r\n name: match[1],\r\n description: match[2].trim(),\r\n deliverables,\r\n });\r\n }\r\n\r\n if (!overview) {\r\n return null;\r\n }\r\n\r\n return {\r\n overview,\r\n techDecisions,\r\n phases,\r\n };\r\n}\r\n\r\n/**\r\n * 계획 상태 업데이트\r\n */\r\nexport function updatePlanStatus(content: string, newStatus: string): string {\r\n return content.replace(\r\n /^(---\\n[\\s\\S]*?)status:\\s*\\w+/m,\r\n `$1status: ${newStatus}`\r\n );\r\n}\r\n","/**\r\n * 작업 분해 생성기\r\n */\r\nimport { TaskItem, TaskStatus, TaskPriority, generateTaskId } from './schemas.js';\r\n\r\n/**\r\n * 작업 생성 옵션\r\n */\r\nexport interface GenerateTasksOptions {\r\n featureId: string;\r\n featureTitle: string;\r\n tasks: Array<{\r\n title: string;\r\n description?: string;\r\n priority?: TaskPriority;\r\n files?: string[];\r\n dependencies?: string[];\r\n }>;\r\n}\r\n\r\n/**\r\n * tasks.md 파일 내용 생성\r\n */\r\nexport function generateTasks(options: GenerateTasksOptions): string {\r\n const today = new Date().toISOString().split('T')[0];\r\n\r\n let content = `---\r\nfeature: ${options.featureId}\r\ncreated: ${today}\r\ntotal: ${options.tasks.length}\r\ncompleted: 0\r\n---\r\n\r\n# 작업 목록: ${options.featureTitle}\r\n\r\n> 총 ${options.tasks.length}개 작업\r\n\r\n---\r\n\r\n## 진행 상황\r\n\r\n- 대기: ${options.tasks.length}\r\n- 진행 중: 0\r\n- 완료: 0\r\n- 차단됨: 0\r\n\r\n---\r\n\r\n## 작업 목록\r\n\r\n`;\r\n\r\n options.tasks.forEach((task, index) => {\r\n const taskId = generateTaskId(options.featureId, index + 1);\r\n const priority = task.priority || 'medium';\r\n const priorityIcon = priority === 'high' ? '🔴' : priority === 'medium' ? '🟡' : '🟢';\r\n\r\n content += `### ${taskId}: ${task.title}\r\n\r\n- **상태:** 대기\r\n- **우선순위:** ${priorityIcon} ${priority.toUpperCase()}\r\n`;\r\n\r\n if (task.description) {\r\n content += `- **설명:** ${task.description}\r\n`;\r\n }\r\n\r\n if (task.files?.length) {\r\n content += `- **관련 파일:**\r\n${task.files.map(f => ` - \\`${f}\\``).join('\\n')}\r\n`;\r\n }\r\n\r\n if (task.dependencies?.length) {\r\n content += `- **의존성:** ${task.dependencies.join(', ')}\r\n`;\r\n }\r\n\r\n content += '\\n';\r\n });\r\n\r\n content += `---\r\n\r\n## 완료 조건\r\n\r\n각 작업 완료 시:\r\n1. [ ] 코드 작성 완료\r\n2. [ ] 테스트 작성 및 통과\r\n3. [ ] 코드 리뷰 완료\r\n4. [ ] 문서 업데이트\r\n\r\n---\r\n\r\n## 다음 단계\r\n\r\n1. 첫 번째 작업부터 순차적으로 진행\r\n2. 각 작업 완료 후 상태 업데이트\r\n3. 모든 작업 완료 시 \\`/sdd:archive\\` 실행\r\n`;\r\n\r\n return content;\r\n}\r\n\r\n/**\r\n * 작업 목록 파싱\r\n */\r\nexport function parseTasks(content: string): TaskItem[] {\r\n const tasks: TaskItem[] = [];\r\n const taskMatches = content.matchAll(/### ([a-z0-9-]+): ([^\\n]+)\\s*\\n([\\s\\S]*?)(?=\\n###|\\n---|$)/gi);\r\n\r\n for (const match of taskMatches) {\r\n const id = match[1];\r\n const title = match[2];\r\n const body = match[3];\r\n\r\n // 상태 추출\r\n const statusMatch = body.match(/\\*\\*상태:\\*\\*\\s*(\\S+)/);\r\n let status: TaskStatus = 'pending';\r\n if (statusMatch) {\r\n const statusText = statusMatch[1].toLowerCase();\r\n if (statusText.includes('진행') || statusText === 'in_progress') {\r\n status = 'in_progress';\r\n } else if (statusText.includes('완료') || statusText === 'completed') {\r\n status = 'completed';\r\n } else if (statusText.includes('차단') || statusText === 'blocked') {\r\n status = 'blocked';\r\n }\r\n }\r\n\r\n // 우선순위 추출\r\n const priorityMatch = body.match(/\\*\\*우선순위:\\*\\*\\s*(?:[🔴🟡🟢]\\s*)?([A-Za-z]+)/u);\r\n let priority: TaskPriority = 'medium';\r\n if (priorityMatch) {\r\n const p = priorityMatch[1].toLowerCase();\r\n if (p === 'high' || p === '높음') priority = 'high';\r\n else if (p === 'low' || p === '낮음') priority = 'low';\r\n }\r\n\r\n // 설명 추출\r\n const descMatch = body.match(/\\*\\*설명:\\*\\*\\s*([^\\n]+)/);\r\n const description = descMatch ? descMatch[1] : undefined;\r\n\r\n // 파일 추출\r\n const filesMatch = body.match(/\\*\\*관련 파일:\\*\\*\\s*\\n([\\s\\S]*?)(?=\\n-\\s*\\*\\*|\\n\\n|$)/);\r\n const files = filesMatch\r\n ? filesMatch[1]\r\n .split('\\n')\r\n .filter(l => l.includes('`'))\r\n .map(l => l.match(/`([^`]+)`/)?.[1] || '')\r\n .filter(Boolean)\r\n : undefined;\r\n\r\n // 의존성 추출\r\n const depsMatch = body.match(/\\*\\*의존성:\\*\\*\\s*([^\\n]+)/);\r\n const dependencies = depsMatch\r\n ? depsMatch[1].split(',').map(d => d.trim()).filter(Boolean)\r\n : undefined;\r\n\r\n tasks.push({\r\n id,\r\n title,\r\n description,\r\n status,\r\n priority,\r\n files,\r\n dependencies,\r\n });\r\n }\r\n\r\n return tasks;\r\n}\r\n\r\n/**\r\n * 작업 상태 업데이트\r\n */\r\nexport function updateTaskStatus(\r\n content: string,\r\n taskId: string,\r\n newStatus: TaskStatus\r\n): string {\r\n const statusText = newStatus === 'pending' ? '대기'\r\n : newStatus === 'in_progress' ? '진행 중'\r\n : newStatus === 'completed' ? '완료'\r\n : '차단됨';\r\n\r\n // 작업 상태 업데이트\r\n const taskRegex = new RegExp(\r\n `(### ${taskId}:[^\\\\n]+\\\\s*\\\\n[\\\\s\\\\S]*?\\\\*\\\\*상태:\\\\*\\\\*)\\\\s*\\\\S+`,\r\n 'i'\r\n );\r\n\r\n let updated = content.replace(taskRegex, `$1 ${statusText}`);\r\n\r\n // 진행 상황 업데이트\r\n const tasks = parseTasks(updated);\r\n const pending = tasks.filter(t => t.status === 'pending').length;\r\n const inProgress = tasks.filter(t => t.status === 'in_progress').length;\r\n const completed = tasks.filter(t => t.status === 'completed').length;\r\n const blocked = tasks.filter(t => t.status === 'blocked').length;\r\n\r\n updated = updated.replace(\r\n /## 진행 상황\\s*\\n\\n[\\s\\S]*?(?=\\n---)/,\r\n `## 진행 상황\r\n\r\n- 대기: ${pending}\r\n- 진행 중: ${inProgress}\r\n- 완료: ${completed}\r\n- 차단됨: ${blocked}\r\n`\r\n );\r\n\r\n // frontmatter completed 업데이트\r\n updated = updated.replace(\r\n /completed:\\s*\\d+/,\r\n `completed: ${completed}`\r\n );\r\n\r\n return updated;\r\n}\r\n\r\n/**\r\n * 다음 작업 가져오기\r\n */\r\nexport function getNextTask(tasks: TaskItem[]): TaskItem | null {\r\n // 진행 중인 작업이 있으면 반환\r\n const inProgress = tasks.find(t => t.status === 'in_progress');\r\n if (inProgress) return inProgress;\r\n\r\n // 의존성이 모두 완료된 대기 중 작업 찾기 (우선순위 순)\r\n const priorityOrder: TaskPriority[] = ['high', 'medium', 'low'];\r\n const completedIds = new Set(\r\n tasks.filter(t => t.status === 'completed').map(t => t.id)\r\n );\r\n\r\n for (const priority of priorityOrder) {\r\n const candidate = tasks.find(t => {\r\n if (t.status !== 'pending' || t.priority !== priority) return false;\r\n\r\n // 의존성 확인\r\n if (t.dependencies?.length) {\r\n return t.dependencies.every(dep => completedIds.has(dep));\r\n }\r\n return true;\r\n });\r\n\r\n if (candidate) return candidate;\r\n }\r\n\r\n return null;\r\n}\r\n","/**\r\n * 브랜치 관리\r\n */\r\nimport { exec } from 'node:child_process';\r\nimport { promisify } from 'node:util';\r\nimport { Result } from '../../types/index.js';\r\nimport { SddError, ErrorCode, ExitCode } from '../../errors/index.js';\r\nimport { generateBranchName } from './schemas.js';\r\n\r\nconst execAsync = promisify(exec);\r\n\r\n/**\r\n * 브랜치 에러\r\n */\r\nexport class BranchError extends SddError {\r\n constructor(message: string) {\r\n super(ErrorCode.UNKNOWN, message, ExitCode.GENERAL_ERROR);\r\n this.name = 'BranchError';\r\n }\r\n}\r\n\r\n/**\r\n * Git 설치 확인\r\n */\r\nexport async function isGitInstalled(): Promise<boolean> {\r\n try {\r\n await execAsync('git --version');\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Git 저장소인지 확인\r\n */\r\nexport async function isGitRepository(cwd?: string): Promise<boolean> {\r\n try {\r\n await execAsync('git rev-parse --git-dir', { cwd });\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * 현재 브랜치 가져오기\r\n */\r\nexport async function getCurrentBranch(cwd?: string): Promise<Result<string, BranchError>> {\r\n try {\r\n const { stdout } = await execAsync('git branch --show-current', { cwd });\r\n return { success: true, data: stdout.trim() };\r\n } catch (error) {\r\n return {\r\n success: false,\r\n error: new BranchError(`현재 브랜치를 가져올 수 없습니다: ${error}`),\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * 브랜치 존재 확인\r\n */\r\nexport async function branchExists(\r\n branchName: string,\r\n cwd?: string\r\n): Promise<boolean> {\r\n try {\r\n await execAsync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd });\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * 브랜치 생성\r\n */\r\nexport async function createBranch(\r\n featureId: string,\r\n options?: { checkout?: boolean; baseBranch?: string; cwd?: string }\r\n): Promise<Result<string, BranchError>> {\r\n const branchName = generateBranchName(featureId);\r\n const checkout = options?.checkout ?? true;\r\n const cwd = options?.cwd;\r\n\r\n try {\r\n // Git 저장소 확인\r\n if (!(await isGitRepository(cwd))) {\r\n return {\r\n success: false,\r\n error: new BranchError('Git 저장소가 아닙니다'),\r\n };\r\n }\r\n\r\n // 브랜치 존재 확인\r\n if (await branchExists(branchName, cwd)) {\r\n return {\r\n success: false,\r\n error: new BranchError(`브랜치 '${branchName}'가 이미 존재합니다`),\r\n };\r\n }\r\n\r\n // 베이스 브랜치가 지정된 경우 먼저 체크아웃\r\n if (options?.baseBranch) {\r\n await execAsync(`git checkout ${options.baseBranch}`, { cwd });\r\n }\r\n\r\n // 브랜치 생성\r\n if (checkout) {\r\n await execAsync(`git checkout -b ${branchName}`, { cwd });\r\n } else {\r\n await execAsync(`git branch ${branchName}`, { cwd });\r\n }\r\n\r\n return { success: true, data: branchName };\r\n } catch (error) {\r\n return {\r\n success: false,\r\n error: new BranchError(`브랜치 생성 실패: ${error}`),\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * 브랜치 체크아웃\r\n */\r\nexport async function checkoutBranch(\r\n branchName: string,\r\n cwd?: string\r\n): Promise<Result<void, BranchError>> {\r\n try {\r\n await execAsync(`git checkout ${branchName}`, { cwd });\r\n return { success: true, data: undefined };\r\n } catch (error) {\r\n return {\r\n success: false,\r\n error: new BranchError(`브랜치 체크아웃 실패: ${error}`),\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * 브랜치 삭제\r\n */\r\nexport async function deleteBranch(\r\n branchName: string,\r\n options?: { force?: boolean; cwd?: string }\r\n): Promise<Result<void, BranchError>> {\r\n const force = options?.force ?? false;\r\n const cwd = options?.cwd;\r\n\r\n try {\r\n const flag = force ? '-D' : '-d';\r\n await execAsync(`git branch ${flag} ${branchName}`, { cwd });\r\n return { success: true, data: undefined };\r\n } catch (error) {\r\n return {\r\n success: false,\r\n error: new BranchError(`브랜치 삭제 실패: ${error}`),\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * 기능 브랜치 목록\r\n */\r\nexport async function listFeatureBranches(\r\n cwd?: string\r\n): Promise<Result<string[], BranchError>> {\r\n try {\r\n const { stdout } = await execAsync('git branch --list \"feature/*\"', { cwd });\r\n const branches = stdout\r\n .split('\\n')\r\n .map(b => b.trim().replace(/^\\*\\s*/, ''))\r\n .filter(Boolean);\r\n return { success: true, data: branches };\r\n } catch (error) {\r\n return {\r\n success: false,\r\n error: new BranchError(`브랜치 목록 조회 실패: ${error}`),\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * 변경사항 있는지 확인\r\n */\r\nexport async function hasUncommittedChanges(cwd?: string): Promise<boolean> {\r\n try {\r\n const { stdout } = await execAsync('git status --porcelain', { cwd });\r\n return stdout.trim().length > 0;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * 브랜치 정보\r\n */\r\nexport interface BranchInfo {\r\n name: string;\r\n featureId: string;\r\n isCurrentBranch: boolean;\r\n}\r\n\r\n/**\r\n * 브랜치에서 기능 ID 추출\r\n */\r\nexport function extractFeatureId(branchName: string): string | null {\r\n const match = branchName.match(/^feature\\/(.+)$/);\r\n return match ? match[1] : null;\r\n}\r\n\r\n/**\r\n * 기능 브랜치 상세 정보\r\n */\r\nexport async function getFeatureBranchInfo(\r\n cwd?: string\r\n): Promise<Result<BranchInfo[], BranchError>> {\r\n const branchesResult = await listFeatureBranches(cwd);\r\n if (!branchesResult.success) {\r\n return branchesResult;\r\n }\r\n\r\n const currentResult = await getCurrentBranch(cwd);\r\n const currentBranch = currentResult.success ? currentResult.data : '';\r\n\r\n const info: BranchInfo[] = branchesResult.data.map(name => ({\r\n name,\r\n featureId: extractFeatureId(name) || name,\r\n isCurrentBranch: name === currentBranch,\r\n }));\r\n\r\n return { success: true, data: info };\r\n}\r\n","/**\r\n * 체크리스트 관리\r\n */\r\n\r\n/**\r\n * 체크리스트 항목\r\n */\r\nexport interface ChecklistItem {\r\n id: string;\r\n text: string;\r\n checked: boolean;\r\n category: ChecklistCategory;\r\n}\r\n\r\n/**\r\n * 체크리스트 카테고리\r\n */\r\nexport type ChecklistCategory =\r\n | 'pre-spec' // 명세 작성 전\r\n | 'post-spec' // 명세 작성 후\r\n | 'pre-plan' // 계획 작성 전\r\n | 'post-plan' // 계획 작성 후\r\n | 'pre-impl' // 구현 전\r\n | 'post-impl' // 구현 후\r\n | 'pre-review' // 리뷰 전\r\n | 'post-review'; // 리뷰 후\r\n\r\n/**\r\n * 기본 체크리스트 템플릿\r\n */\r\nexport const DEFAULT_CHECKLISTS: Record<ChecklistCategory, string[]> = {\r\n 'pre-spec': [\r\n '기능 요구사항이 명확히 정의됨',\r\n '사용자 스토리가 작성됨',\r\n '관련 이해관계자와 논의 완료',\r\n '기존 기능과의 충돌 여부 확인',\r\n ],\r\n 'post-spec': [\r\n 'RFC 2119 키워드 사용 확인 (SHALL, MUST, SHOULD, MAY)',\r\n 'GIVEN-WHEN-THEN 시나리오 포함',\r\n '비기능 요구사항 명시',\r\n 'sdd validate 통과',\r\n ],\r\n 'pre-plan': [\r\n '명세가 승인됨',\r\n '기술 스택 결정됨',\r\n '아키텍처 검토 완료',\r\n '의존성 확인',\r\n ],\r\n 'post-plan': [\r\n '구현 단계가 명확히 정의됨',\r\n '리스크 분석 완료',\r\n '테스트 전략 수립',\r\n '헌법 준수 사항 확인',\r\n ],\r\n 'pre-impl': [\r\n '작업이 분해됨 (tasks.md)',\r\n '브랜치가 생성됨',\r\n '개발 환경 준비',\r\n '관련 테스트 환경 확인',\r\n ],\r\n 'post-impl': [\r\n '모든 작업 완료',\r\n '단위 테스트 작성 및 통과',\r\n '통합 테스트 통과',\r\n '코드 커버리지 목표 달성 (80%+)',\r\n '린트 및 타입 체크 통과',\r\n ],\r\n 'pre-review': [\r\n '셀프 코드 리뷰 완료',\r\n '문서 업데이트',\r\n 'PR 설명 작성',\r\n '테스트 결과 첨부',\r\n ],\r\n 'post-review': [\r\n '리뷰 피드백 반영',\r\n '최종 테스트 통과',\r\n '스펙 상태 업데이트',\r\n '아카이브 준비',\r\n ],\r\n};\r\n\r\n/**\r\n * 체크리스트 생성\r\n */\r\nexport function createChecklist(category: ChecklistCategory): ChecklistItem[] {\r\n const items = DEFAULT_CHECKLISTS[category];\r\n return items.map((text, index) => ({\r\n id: `${category}-${String(index + 1).padStart(2, '0')}`,\r\n text,\r\n checked: false,\r\n category,\r\n }));\r\n}\r\n\r\n/**\r\n * 체크리스트를 마크다운으로 변환\r\n */\r\nexport function checklistToMarkdown(\r\n items: ChecklistItem[],\r\n title?: string\r\n): string {\r\n let content = '';\r\n\r\n if (title) {\r\n content += `## ${title}\\n\\n`;\r\n }\r\n\r\n items.forEach(item => {\r\n const checkbox = item.checked ? '[x]' : '[ ]';\r\n content += `- ${checkbox} ${item.text}\\n`;\r\n });\r\n\r\n return content;\r\n}\r\n\r\n/**\r\n * 마크다운에서 체크리스트 파싱\r\n */\r\nexport function parseChecklistFromMarkdown(\r\n content: string,\r\n category: ChecklistCategory\r\n): ChecklistItem[] {\r\n const items: ChecklistItem[] = [];\r\n const regex = /- \\[([ x])\\] (.+)/g;\r\n let match;\r\n let index = 0;\r\n\r\n while ((match = regex.exec(content)) !== null) {\r\n items.push({\r\n id: `${category}-${String(++index).padStart(2, '0')}`,\r\n text: match[2],\r\n checked: match[1] === 'x',\r\n category,\r\n });\r\n }\r\n\r\n return items;\r\n}\r\n\r\n/**\r\n * 체크리스트 완료 여부 확인\r\n */\r\nexport function isChecklistComplete(items: ChecklistItem[]): boolean {\r\n return items.every(item => item.checked);\r\n}\r\n\r\n/**\r\n * 체크리스트 진행률 계산\r\n */\r\nexport function getChecklistProgress(items: ChecklistItem[]): {\r\n completed: number;\r\n total: number;\r\n percentage: number;\r\n} {\r\n const completed = items.filter(item => item.checked).length;\r\n const total = items.length;\r\n const percentage = total > 0 ? Math.round((completed / total) * 100) : 0;\r\n\r\n return { completed, total, percentage };\r\n}\r\n\r\n/**\r\n * 체크리스트 항목 토글\r\n */\r\nexport function toggleChecklistItem(\r\n items: ChecklistItem[],\r\n itemId: string\r\n): ChecklistItem[] {\r\n return items.map(item =>\r\n item.id === itemId ? { ...item, checked: !item.checked } : item\r\n );\r\n}\r\n\r\n/**\r\n * 워크플로우 단계별 체크리스트 생성\r\n */\r\nexport function createWorkflowChecklists(): Record<string, ChecklistItem[]> {\r\n return {\r\n '명세 작성 전': createChecklist('pre-spec'),\r\n '명세 작성 후': createChecklist('post-spec'),\r\n '계획 작성 전': createChecklist('pre-plan'),\r\n '계획 작성 후': createChecklist('post-plan'),\r\n '구현 전': createChecklist('pre-impl'),\r\n '구현 후': createChecklist('post-impl'),\r\n '리뷰 전': createChecklist('pre-review'),\r\n '리뷰 후': createChecklist('post-review'),\r\n };\r\n}\r\n\r\n/**\r\n * 전체 체크리스트 마크다운 생성\r\n */\r\nexport function generateFullChecklistMarkdown(): string {\r\n const checklists = createWorkflowChecklists();\r\n let content = `# SDD 워크플로우 체크리스트\r\n\r\n> 각 단계별로 확인해야 할 항목들입니다.\r\n\r\n---\r\n\r\n`;\r\n\r\n for (const [title, items] of Object.entries(checklists)) {\r\n content += checklistToMarkdown(items, title);\r\n content += '\\n---\\n\\n';\r\n }\r\n\r\n return content;\r\n}\r\n","/**\r\n * 기능 번호 카운터 관리\r\n *\r\n * .sdd/counter.json 파일을 사용하여 feature 번호를 자동 관리합니다.\r\n * 형식: feature/001-name, feature/002-name, ...\r\n */\r\nimport path from 'node:path';\r\nimport { promises as fs } from 'node:fs';\r\nimport { fileExists, readFile, writeFile, ensureDir } from '../../utils/fs.js';\r\nimport { Result, success, failure } from '../../types/index.js';\r\n\r\n/**\r\n * 카운터 데이터 구조\r\n */\r\nexport interface CounterData {\r\n /** 다음 기능 번호 */\r\n nextFeatureNumber: number;\r\n /** 마지막 업데이트 시간 */\r\n lastUpdated: string;\r\n /** 생성된 기능 이력 */\r\n history: FeatureHistoryEntry[];\r\n}\r\n\r\n/**\r\n * 기능 이력 항목\r\n */\r\nexport interface FeatureHistoryEntry {\r\n /** 기능 번호 */\r\n number: number;\r\n /** 기능 이름 */\r\n name: string;\r\n /** 전체 ID (예: feature/001-auth) */\r\n fullId: string;\r\n /** 생성 시간 */\r\n createdAt: string;\r\n}\r\n\r\n/**\r\n * 카운터 에러\r\n */\r\nexport class CounterError extends Error {\r\n constructor(\r\n message: string,\r\n public readonly code: string\r\n ) {\r\n super(message);\r\n this.name = 'CounterError';\r\n }\r\n}\r\n\r\n/**\r\n * 기본 카운터 데이터\r\n */\r\nfunction getDefaultCounterData(): CounterData {\r\n return {\r\n nextFeatureNumber: 1,\r\n lastUpdated: new Date().toISOString(),\r\n history: [],\r\n };\r\n}\r\n\r\n/**\r\n * 카운터 파일 경로\r\n */\r\nfunction getCounterPath(sddPath: string): string {\r\n return path.join(sddPath, 'counter.json');\r\n}\r\n\r\n/**\r\n * 카운터 데이터 읽기\r\n */\r\nexport async function readCounter(sddPath: string): Promise<Result<CounterData, CounterError>> {\r\n const counterPath = getCounterPath(sddPath);\r\n\r\n if (!(await fileExists(counterPath))) {\r\n return success(getDefaultCounterData());\r\n }\r\n\r\n const readResult = await readFile(counterPath);\r\n if (!readResult.success) {\r\n return failure(new CounterError('카운터 파일을 읽을 수 없습니다', 'READ_ERROR'));\r\n }\r\n\r\n try {\r\n const data = JSON.parse(readResult.data) as CounterData;\r\n return success(data);\r\n } catch {\r\n return failure(new CounterError('카운터 파일 형식이 올바르지 않습니다', 'PARSE_ERROR'));\r\n }\r\n}\r\n\r\n/**\r\n * 카운터 데이터 저장\r\n */\r\nexport async function saveCounter(sddPath: string, data: CounterData): Promise<Result<void, CounterError>> {\r\n const counterPath = getCounterPath(sddPath);\r\n\r\n try {\r\n await writeFile(counterPath, JSON.stringify(data, null, 2));\r\n return success(undefined);\r\n } catch {\r\n return failure(new CounterError('카운터 파일을 저장할 수 없습니다', 'WRITE_ERROR'));\r\n }\r\n}\r\n\r\n/**\r\n * 다음 기능 번호 가져오기 및 증가\r\n */\r\nexport async function getNextFeatureNumber(\r\n sddPath: string,\r\n featureName: string\r\n): Promise<Result<{ number: number; fullId: string; branchName: string }, CounterError>> {\r\n const counterResult = await readCounter(sddPath);\r\n if (!counterResult.success) {\r\n return failure(counterResult.error);\r\n }\r\n\r\n const data = counterResult.data;\r\n const currentNumber = data.nextFeatureNumber;\r\n\r\n // 번호 포맷팅 (3자리, 앞에 0 채움)\r\n const paddedNumber = String(currentNumber).padStart(3, '0');\r\n\r\n // 기능 이름 정규화\r\n const normalizedName = featureName\r\n .toLowerCase()\r\n .replace(/[^a-z0-9]+/g, '-')\r\n .replace(/^-|-$/g, '');\r\n\r\n const fullId = `${paddedNumber}-${normalizedName}`;\r\n const branchName = `feature/${fullId}`;\r\n\r\n // 카운터 업데이트\r\n data.nextFeatureNumber = currentNumber + 1;\r\n data.lastUpdated = new Date().toISOString();\r\n data.history.push({\r\n number: currentNumber,\r\n name: featureName,\r\n fullId,\r\n createdAt: new Date().toISOString(),\r\n });\r\n\r\n const saveResult = await saveCounter(sddPath, data);\r\n if (!saveResult.success) {\r\n return failure(saveResult.error);\r\n }\r\n\r\n return success({\r\n number: currentNumber,\r\n fullId,\r\n branchName,\r\n });\r\n}\r\n\r\n/**\r\n * 현재 카운터 상태 조회 (증가하지 않음)\r\n */\r\nexport async function peekNextFeatureNumber(sddPath: string): Promise<Result<number, CounterError>> {\r\n const counterResult = await readCounter(sddPath);\r\n if (!counterResult.success) {\r\n return failure(counterResult.error);\r\n }\r\n\r\n return success(counterResult.data.nextFeatureNumber);\r\n}\r\n\r\n/**\r\n * 기능 이력 조회\r\n */\r\nexport async function getFeatureHistory(sddPath: string): Promise<Result<FeatureHistoryEntry[], CounterError>> {\r\n const counterResult = await readCounter(sddPath);\r\n if (!counterResult.success) {\r\n return failure(counterResult.error);\r\n }\r\n\r\n return success(counterResult.data.history);\r\n}\r\n\r\n/**\r\n * 카운터 초기화 (주의: 모든 이력 삭제)\r\n */\r\nexport async function resetCounter(sddPath: string, startFrom: number = 1): Promise<Result<void, CounterError>> {\r\n const data: CounterData = {\r\n nextFeatureNumber: startFrom,\r\n lastUpdated: new Date().toISOString(),\r\n history: [],\r\n };\r\n\r\n return saveCounter(sddPath, data);\r\n}\r\n\r\n/**\r\n * 카운터 설정 (이력 유지)\r\n */\r\nexport async function setNextFeatureNumber(\r\n sddPath: string,\r\n nextNumber: number\r\n): Promise<Result<void, CounterError>> {\r\n const counterResult = await readCounter(sddPath);\r\n if (!counterResult.success) {\r\n return failure(counterResult.error);\r\n }\r\n\r\n const data = counterResult.data;\r\n data.nextFeatureNumber = nextNumber;\r\n data.lastUpdated = new Date().toISOString();\r\n\r\n return saveCounter(sddPath, data);\r\n}\r\n\r\n/**\r\n * 브랜치 이름에서 기능 번호 추출\r\n */\r\nexport function extractFeatureNumberFromBranch(branchName: string): number | null {\r\n // feature/001-name 또는 001-name 형식\r\n const match = branchName.match(/(?:feature\\/)?(\\d{3})-/);\r\n if (match) {\r\n return parseInt(match[1], 10);\r\n }\r\n return null;\r\n}\r\n\r\n/**\r\n * 기능 ID 형식 검증\r\n */\r\nexport function isValidFeatureId(id: string): boolean {\r\n // 001-name 형식\r\n return /^\\d{3}-[a-z0-9]+(-[a-z0-9]+)*$/.test(id);\r\n}\r\n","/**\r\n * 신규 기능 워크플로우 모듈\r\n *\r\n * 새로운 기능 개발을 위한 명세, 계획, 작업 분해 기능을 제공합니다.\r\n */\r\n\r\n// 스키마 및 타입\r\nexport {\r\n FeatureStatusSchema,\r\n TaskStatusSchema,\r\n TaskPrioritySchema,\r\n FeatureMetadataSchema,\r\n TaskItemSchema,\r\n PlanSchema,\r\n generateFeatureId,\r\n generateTaskId,\r\n generateBranchName,\r\n type FeatureStatus,\r\n type TaskStatus,\r\n type TaskPriority,\r\n type FeatureMetadata,\r\n type TaskItem,\r\n type Plan,\r\n} from './schemas.js';\r\n\r\n// 명세 생성\r\nexport {\r\n generateSpec,\r\n parseSpecMetadata,\r\n updateSpecStatus,\r\n type GenerateSpecOptions,\r\n} from './spec-generator.js';\r\n\r\n// 계획 생성\r\nexport {\r\n generatePlan,\r\n parsePlan,\r\n updatePlanStatus,\r\n type GeneratePlanOptions,\r\n} from './plan-generator.js';\r\n\r\n// 작업 분해\r\nexport {\r\n generateTasks,\r\n parseTasks,\r\n updateTaskStatus,\r\n getNextTask,\r\n type GenerateTasksOptions,\r\n} from './task-generator.js';\r\n\r\n// 브랜치 관리\r\nexport {\r\n BranchError,\r\n isGitInstalled,\r\n isGitRepository,\r\n getCurrentBranch,\r\n branchExists,\r\n createBranch,\r\n checkoutBranch,\r\n deleteBranch,\r\n listFeatureBranches,\r\n hasUncommittedChanges,\r\n extractFeatureId,\r\n getFeatureBranchInfo,\r\n type BranchInfo,\r\n} from './branch.js';\r\n\r\n// 체크리스트\r\nexport {\r\n DEFAULT_CHECKLISTS,\r\n createChecklist,\r\n checklistToMarkdown,\r\n parseChecklistFromMarkdown,\r\n isChecklistComplete,\r\n getChecklistProgress,\r\n toggleChecklistItem,\r\n createWorkflowChecklists,\r\n generateFullChecklistMarkdown,\r\n type ChecklistItem,\r\n type ChecklistCategory,\r\n} from './checklist.js';\r\n\r\n// 기능 번호 카운터\r\nexport {\r\n readCounter,\r\n saveCounter,\r\n getNextFeatureNumber,\r\n peekNextFeatureNumber,\r\n getFeatureHistory,\r\n resetCounter,\r\n setNextFeatureNumber,\r\n extractFeatureNumberFromBranch,\r\n isValidFeatureId,\r\n CounterError,\r\n type CounterData,\r\n type FeatureHistoryEntry,\r\n} from './counter.js';\r\n","/**\r\n * CLI 진입점\r\n */\r\nimport { Command } from 'commander';\r\nimport { createRequire } from 'node:module';\r\nimport { registerInitCommand } from './commands/init.js';\r\nimport { registerValidateCommand } from './commands/validate.js';\r\nimport { registerPromptCommand } from './commands/prompt.js';\r\nimport { registerChangeCommand } from './commands/change.js';\r\nimport { registerImpactCommand } from './commands/impact.js';\r\nimport { registerNewCommand } from './commands/new.js';\r\nimport { registerStatusCommand } from './commands/status.js';\r\nimport { registerListCommand } from './commands/list.js';\r\nimport { registerConstitutionCommand } from './commands/constitution.js';\r\nimport { registerStartCommand } from './commands/start.js';\r\nimport { registerMigrateCommand } from './commands/migrate.js';\r\nimport { registerCicdCommand } from './commands/cicd.js';\r\nimport { registerTransitionCommand } from './commands/transition.js';\r\nimport { registerWatchCommand } from './commands/watch.js';\r\nimport { registerQualityCommand } from './commands/quality.js';\r\nimport { registerReportCommand } from './commands/report.js';\r\n\r\nconst require = createRequire(import.meta.url);\r\nconst pkg = require('../../package.json') as { version: string; description: string };\r\n\r\nconst program = new Command();\r\n\r\nprogram\r\n .name('sdd')\r\n .description(pkg.description)\r\n .version(pkg.version);\r\n\r\n// Commands\r\nregisterInitCommand(program);\r\nregisterValidateCommand(program);\r\nregisterPromptCommand(program);\r\nregisterChangeCommand(program);\r\nregisterImpactCommand(program);\r\nregisterNewCommand(program);\r\nregisterStatusCommand(program);\r\nregisterListCommand(program);\r\nregisterConstitutionCommand(program);\r\nregisterStartCommand(program);\r\nregisterMigrateCommand(program);\r\nregisterCicdCommand(program);\r\nregisterTransitionCommand(program);\r\nregisterWatchCommand(program);\r\nregisterQualityCommand(program);\r\nregisterReportCommand(program);\r\n\r\n/**\r\n * CLI 실행\r\n */\r\nexport function run(): void {\r\n program.parse();\r\n}\r\n\r\nexport { program };\r\n","/**\r\n * sdd init 명령어\r\n */\r\nimport { Command } from 'commander';\r\nimport path from 'node:path';\r\nimport { ensureDir, writeFile, directoryExists } from '../../utils/fs.js';\r\nimport { ExitCode } from '../../errors/index.js';\r\nimport * as logger from '../../utils/logger.js';\r\nimport { generateAgentsMd } from '../../generators/agents-md.js';\r\nimport { generateClaudeCommands } from '../../generators/claude-commands.js';\r\n\r\n/**\r\n * init 명령어 등록\r\n */\r\nexport function registerInitCommand(program: Command): void {\r\n program\r\n .command('init')\r\n .description('SDD 프로젝트를 초기화합니다')\r\n .option('-f, --force', '기존 .sdd/ 디렉토리 덮어쓰기')\r\n .action(async (options: { force?: boolean }) => {\r\n try {\r\n await runInit(options);\r\n } catch (error) {\r\n logger.error(error instanceof Error ? error.message : String(error));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n });\r\n}\r\n\r\n/**\r\n * 초기화 실행\r\n */\r\nasync function runInit(options: { force?: boolean }): Promise<void> {\r\n const cwd = process.cwd();\r\n const sddPath = path.join(cwd, '.sdd');\r\n\r\n // 기존 디렉토리 확인\r\n if (await directoryExists(sddPath)) {\r\n if (!options.force) {\r\n logger.error('.sdd/ 디렉토리가 이미 존재합니다. --force 옵션으로 덮어쓸 수 있습니다.');\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n logger.warn('기존 .sdd/ 디렉토리를 덮어씁니다.');\r\n }\r\n\r\n logger.info('SDD 프로젝트를 초기화합니다...');\r\n\r\n // 디렉토리 구조 생성\r\n const directories = [\r\n '.sdd',\r\n '.sdd/specs',\r\n '.sdd/changes',\r\n '.sdd/archive',\r\n '.sdd/templates',\r\n '.claude',\r\n '.claude/commands',\r\n ];\r\n\r\n for (const dir of directories) {\r\n const result = await ensureDir(path.join(cwd, dir));\r\n if (!result.success) {\r\n logger.error(`디렉토리 생성 실패: ${dir}`);\r\n process.exit(ExitCode.FILE_SYSTEM_ERROR);\r\n }\r\n }\r\n\r\n // 기본 파일 생성\r\n await createDefaultFiles(cwd);\r\n\r\n // 템플릿 복사\r\n await copyTemplates(cwd);\r\n\r\n // Claude 슬래시 커맨드 생성\r\n await createClaudeCommands(cwd);\r\n\r\n logger.success('SDD 프로젝트가 초기화되었습니다.');\r\n logger.newline();\r\n logger.info('생성된 구조:');\r\n logger.listItem('.sdd/');\r\n logger.listItem('AGENTS.md', 1);\r\n logger.listItem('constitution.md', 1);\r\n logger.listItem('specs/', 1);\r\n logger.listItem('changes/', 1);\r\n logger.listItem('archive/', 1);\r\n logger.listItem('templates/', 1);\r\n logger.listItem('.claude/');\r\n logger.listItem('commands/', 1);\r\n logger.newline();\r\n logger.info('Claude 슬래시 커맨드:');\r\n logger.listItem('/sdd.start - 워크플로우 시작 (통합 진입점)');\r\n logger.listItem('/sdd.constitution - 프로젝트 원칙 관리');\r\n logger.listItem('/sdd.new - 새 기능 명세 작성');\r\n logger.listItem('/sdd.plan - 구현 계획 작성');\r\n logger.listItem('/sdd.tasks - 작업 분해');\r\n logger.listItem('/sdd.implement - 구현 진행');\r\n logger.listItem('/sdd.validate - 스펙 검증');\r\n logger.listItem('/sdd.status - 상태 확인');\r\n logger.listItem('/sdd.change - 변경 제안');\r\n logger.newline();\r\n logger.info('다음 단계:');\r\n logger.listItem('constitution.md를 수정하여 프로젝트 원칙을 정의하세요');\r\n logger.listItem('/sdd.new 로 첫 번째 기능 명세를 작성하세요');\r\n}\r\n\r\n/**\r\n * 기본 파일 생성\r\n */\r\nasync function createDefaultFiles(cwd: string): Promise<void> {\r\n const projectName = path.basename(cwd);\r\n const today = new Date().toISOString().split('T')[0];\r\n\r\n // constitution.md\r\n const constitution = `---\r\nversion: 1.0.0\r\ncreated: ${today}\r\n---\r\n\r\n# Constitution: ${projectName}\r\n\r\n> 이 프로젝트의 모든 설계와 구현은 아래 원칙을 준수해야 한다(SHALL).\r\n\r\n## 핵심 원칙\r\n\r\n### 1. 품질 우선\r\n\r\n- 모든 기능은 테스트와 함께 구현해야 한다(SHALL)\r\n- 코드 리뷰 없이 머지해서는 안 된다(SHALL NOT)\r\n\r\n### 2. 명세 우선\r\n\r\n- 모든 기능은 스펙 문서가 먼저 작성되어야 한다(SHALL)\r\n- 스펙은 RFC 2119 키워드를 사용해야 한다(SHALL)\r\n- 모든 요구사항은 GIVEN-WHEN-THEN 시나리오를 포함해야 한다(SHALL)\r\n\r\n## 금지 사항\r\n\r\n- 스펙 없이 기능을 구현해서는 안 된다(SHALL NOT)\r\n- 테스트 없이 배포해서는 안 된다(SHALL NOT)\r\n\r\n## 기술 스택\r\n\r\n- (프로젝트에 맞게 수정하세요)\r\n\r\n## 품질 기준\r\n\r\n- 테스트 커버리지: 80% 이상(SHOULD)\r\n`;\r\n\r\n await writeFile(path.join(cwd, '.sdd', 'constitution.md'), constitution);\r\n\r\n // AGENTS.md - 50줄 규칙 준수를 위해 생성기 사용\r\n const agents = generateAgentsMd({ projectName });\r\n await writeFile(path.join(cwd, '.sdd', 'AGENTS.md'), agents);\r\n}\r\n\r\n/**\r\n * 템플릿 복사\r\n */\r\nasync function copyTemplates(cwd: string): Promise<void> {\r\n const today = new Date().toISOString().split('T')[0];\r\n\r\n // spec.md 템플릿\r\n const specTemplate = `---\r\nstatus: draft\r\ncreated: ${today}\r\ndepends: null\r\n---\r\n\r\n# {{FEATURE_NAME}}\r\n\r\n> 기능 설명\r\n\r\n---\r\n\r\n## Requirement: {{REQUIREMENT_TITLE}}\r\n\r\n시스템은 {{DESCRIPTION}}해야 한다(SHALL).\r\n\r\n### Scenario: {{SCENARIO_NAME}}\r\n\r\n- **GIVEN** {{GIVEN_CONDITION}}\r\n- **WHEN** {{WHEN_ACTION}}\r\n- **THEN** {{THEN_RESULT}}\r\n\r\n---\r\n\r\n## 비고\r\n\r\n추가 설명이나 제약 조건\r\n`;\r\n\r\n // proposal.md 템플릿\r\n const proposalTemplate = `---\r\nid: CHG-{{ID}}\r\nstatus: draft\r\ncreated: ${today}\r\n---\r\n\r\n# 변경 제안: {{TITLE}}\r\n\r\n> 변경 목적 및 배경 설명\r\n\r\n---\r\n\r\n## 배경\r\n\r\n왜 이 변경이 필요한가?\r\n\r\n---\r\n\r\n## 영향 범위\r\n\r\n### 영향받는 스펙\r\n\r\n- \\`specs/{{SPEC_PATH}}\\`\r\n\r\n### 변경 유형\r\n\r\n- [ ] 신규 추가 (ADDED)\r\n- [ ] 수정 (MODIFIED)\r\n- [ ] 삭제 (REMOVED)\r\n\r\n---\r\n\r\n## 변경 내용\r\n\r\n### ADDED\r\n\r\n(새로 추가되는 내용)\r\n\r\n### MODIFIED\r\n\r\n#### Before\r\n\r\n\\`\\`\\`markdown\r\n기존 내용\r\n\\`\\`\\`\r\n\r\n#### After\r\n\r\n\\`\\`\\`markdown\r\n변경된 내용\r\n\\`\\`\\`\r\n\r\n### REMOVED\r\n\r\n(삭제되는 내용)\r\n\r\n---\r\n\r\n## 리스크 평가\r\n\r\n- 영향도: 낮음/중간/높음\r\n- 복잡도: 낮음/중간/높음\r\n`;\r\n\r\n // delta.md 템플릿\r\n const deltaTemplate = `---\r\nproposal: CHG-{{ID}}\r\ncreated: ${today}\r\n---\r\n\r\n# Delta: {{TITLE}}\r\n\r\n## ADDED\r\n\r\n(추가되는 스펙 내용)\r\n\r\n## MODIFIED\r\n\r\n### {{SPEC_PATH}}\r\n\r\n#### Before\r\n\r\n\\`\\`\\`markdown\r\n기존 내용\r\n\\`\\`\\`\r\n\r\n#### After\r\n\r\n\\`\\`\\`markdown\r\n변경된 내용\r\n\\`\\`\\`\r\n\r\n## REMOVED\r\n\r\n(삭제되는 스펙 참조)\r\n`;\r\n\r\n // tasks.md 템플릿\r\n const tasksTemplate = `---\r\nspec: {{SPEC_ID}}\r\ncreated: ${today}\r\n---\r\n\r\n# Tasks: {{FEATURE_NAME}}\r\n\r\n## 개요\r\n\r\n- 총 작업 수: N개\r\n- 예상 복잡도: 낮음/중간/높음\r\n\r\n---\r\n\r\n## 작업 목록\r\n\r\n### Phase 1: 기반 구축\r\n\r\n- [ ] [P1] 작업 1 설명\r\n- [ ] [P1] 작업 2 설명\r\n\r\n### Phase 2: 핵심 구현\r\n\r\n- [ ] [P2] 작업 3 설명\r\n- [ ] [P2] 작업 4 설명\r\n\r\n### Phase 3: 마무리\r\n\r\n- [ ] [P3] 테스트 작성\r\n- [ ] [P3] 문서화\r\n\r\n---\r\n\r\n## 의존성 그래프\r\n\r\n\\`\\`\\`mermaid\r\ngraph LR\r\n A[작업 1] --> B[작업 2]\r\n B --> C[작업 3]\r\n\\`\\`\\`\r\n\r\n---\r\n\r\n## 마커 범례\r\n\r\n| 마커 | 의미 |\r\n|------|------|\r\n| [P1-3] | 우선순위 |\r\n| [→T] | 테스트 필요 |\r\n| [US] | 불확실/검토 필요 |\r\n`;\r\n\r\n await writeFile(path.join(cwd, '.sdd', 'templates', 'spec.md'), specTemplate);\r\n await writeFile(path.join(cwd, '.sdd', 'templates', 'proposal.md'), proposalTemplate);\r\n await writeFile(path.join(cwd, '.sdd', 'templates', 'delta.md'), deltaTemplate);\r\n await writeFile(path.join(cwd, '.sdd', 'templates', 'tasks.md'), tasksTemplate);\r\n}\r\n\r\n/**\r\n * Claude 슬래시 커맨드 생성\r\n */\r\nasync function createClaudeCommands(cwd: string): Promise<void> {\r\n const commands = generateClaudeCommands();\r\n\r\n for (const cmd of commands) {\r\n await writeFile(\r\n path.join(cwd, '.claude', 'commands', `${cmd.name}.md`),\r\n cmd.content\r\n );\r\n }\r\n}\r\n","/**\r\n * 로깅 유틸리티\r\n */\r\nimport chalk from 'chalk';\r\n\r\nexport type LogLevel = 'debug' | 'info' | 'warn' | 'error';\r\n\r\nconst LOG_LEVELS: Record<LogLevel, number> = {\r\n debug: 0,\r\n info: 1,\r\n warn: 2,\r\n error: 3,\r\n};\r\n\r\nlet currentLevel: LogLevel = 'info';\r\n\r\n/**\r\n * 로그 레벨 설정\r\n */\r\nexport function setLogLevel(level: LogLevel): void {\r\n currentLevel = level;\r\n}\r\n\r\n/**\r\n * 로그 레벨 확인\r\n */\r\nfunction shouldLog(level: LogLevel): boolean {\r\n return LOG_LEVELS[level] >= LOG_LEVELS[currentLevel];\r\n}\r\n\r\n/**\r\n * 디버그 로그\r\n */\r\nexport function debug(message: string, ...args: unknown[]): void {\r\n if (shouldLog('debug')) {\r\n console.log(chalk.gray(`[DEBUG] ${message}`), ...args);\r\n }\r\n}\r\n\r\n/**\r\n * 정보 로그\r\n */\r\nexport function info(message: string, ...args: unknown[]): void {\r\n if (shouldLog('info')) {\r\n console.log(chalk.blue(`ℹ ${message}`), ...args);\r\n }\r\n}\r\n\r\n/**\r\n * 성공 로그\r\n */\r\nexport function success(message: string, ...args: unknown[]): void {\r\n if (shouldLog('info')) {\r\n console.log(chalk.green(`✓ ${message}`), ...args);\r\n }\r\n}\r\n\r\n/**\r\n * 경고 로그\r\n */\r\nexport function warn(message: string, ...args: unknown[]): void {\r\n if (shouldLog('warn')) {\r\n console.log(chalk.yellow(`⚠ ${message}`), ...args);\r\n }\r\n}\r\n\r\n/**\r\n * 에러 로그\r\n */\r\nexport function error(message: string, ...args: unknown[]): void {\r\n if (shouldLog('error')) {\r\n console.error(chalk.red(`✗ ${message}`), ...args);\r\n }\r\n}\r\n\r\n/**\r\n * 제목 출력\r\n */\r\nexport function title(message: string): void {\r\n console.log();\r\n console.log(chalk.bold.cyan(message));\r\n console.log(chalk.cyan('─'.repeat(message.length)));\r\n}\r\n\r\n/**\r\n * 목록 항목 출력\r\n */\r\nexport function listItem(item: string, indent = 0): void {\r\n const prefix = ' '.repeat(indent) + '• ';\r\n console.log(prefix + item);\r\n}\r\n\r\n/**\r\n * 빈 줄 출력\r\n */\r\nexport function newline(): void {\r\n console.log();\r\n}\r\n","/**\r\n * AGENTS.md 생성기\r\n *\r\n * 상단 50줄 내에 모든 필수 형식 규칙을 배치합니다.\r\n */\r\nimport { ParsedConstitution } from '../core/constitution/schemas.js';\r\n\r\nexport interface AgentsGeneratorOptions {\r\n projectName: string;\r\n projectDescription?: string;\r\n constitution?: ParsedConstitution;\r\n}\r\n\r\n/**\r\n * AGENTS.md 생성\r\n *\r\n * 스펙 06-agents-generation 요구사항:\r\n * - 상단 50줄 내에 모든 필수 형식 규칙 포함\r\n * - RFC 2119 키워드 설명\r\n * - GIVEN-WHEN-THEN 형식 설명\r\n * - 워크플로우 지침\r\n */\r\nexport function generateAgentsMd(options: AgentsGeneratorOptions): string {\r\n const { projectName, projectDescription = '(프로젝트 설명을 추가하세요)' } = options;\r\n\r\n // 상단 50줄 내에 필수 규칙을 배치\r\n return `# SDD Workflow Guide\r\n\r\n> **${projectName}** - AI 에이전트 워크플로우 지침서\r\n\r\n---\r\n\r\n## 필수 형식 규칙 (이 섹션은 상단 50줄 내에 있어야 함)\r\n\r\n### RFC 2119 키워드\r\n\r\n| 키워드 | 의미 | 사용 예시 |\r\n|--------|------|-----------|\r\n| **SHALL** / **MUST** | 절대 필수 | \"시스템은 인증을 지원해야 한다(SHALL)\" |\r\n| **SHOULD** | 권장 (예외 가능) | \"응답 시간은 1초 이내여야 한다(SHOULD)\" |\r\n| **MAY** | 선택적 | \"다크 모드를 지원할 수 있다(MAY)\" |\r\n| **SHALL NOT** | 절대 금지 | \"평문 비밀번호를 저장해서는 안 된다(SHALL NOT)\" |\r\n\r\n### GIVEN-WHEN-THEN 형식\r\n\r\n모든 요구사항은 아래 형식의 시나리오를 포함해야 합니다:\r\n\r\n\\`\\`\\`markdown\r\n### Scenario: [시나리오명]\r\n\r\n- **GIVEN** [전제 조건]\r\n- **WHEN** [행동/트리거]\r\n- **THEN** [예상 결과]\r\n\\`\\`\\`\r\n\r\n---\r\n\r\n## 프로젝트 개요\r\n\r\n**프로젝트**: ${projectName}\r\n**설명**: ${projectDescription}\r\n\r\n---\r\n\r\n## 디렉토리 구조\r\n\r\n\\`\\`\\`\r\n.sdd/\r\n├── constitution.md # 프로젝트 헌법 (원칙, 제약)\r\n├── AGENTS.md # 이 파일 (AI 워크플로우 지침)\r\n├── specs/ # 스펙 문서\r\n│ └── <feature>/\r\n│ └── spec.md\r\n├── changes/ # 변경 제안\r\n│ └── <id>/\r\n│ ├── proposal.md\r\n│ ├── delta.md\r\n│ └── tasks.md\r\n├── archive/ # 완료된 변경\r\n└── templates/ # 템플릿 파일\r\n\\`\\`\\`\r\n\r\n---\r\n\r\n## 워크플로우\r\n\r\n### 신규 기능 워크플로우\r\n\r\n1. \\`/sdd:new <feature>\\` - 스펙 초안 작성\r\n2. \\`/sdd:plan\\` - 구현 계획 수립\r\n3. \\`/sdd:tasks\\` - 작업 분해 (마커: [P1-3], [→T], [US])\r\n4. 순차적 구현 및 테스트\r\n5. 리뷰 및 머지\r\n\r\n### 변경 워크플로우\r\n\r\n1. \\`/sdd:change <id>\\` - 제안서(proposal.md) 작성\r\n2. delta.md 작성 (ADDED/MODIFIED/REMOVED)\r\n3. tasks.md 작업 목록 생성\r\n4. 구현\r\n5. \\`/sdd:apply\\` - 델타를 스펙에 병합\r\n6. \\`/sdd:archive\\` - 완료된 변경 아카이브\r\n\r\n---\r\n\r\n## 검증\r\n\r\n스펙 변경 후 항상 검증을 실행하세요:\r\n\r\n\\`\\`\\`bash\r\nsdd validate [path] # 형식 검증\r\nsdd validate --strict # 경고도 에러로 처리\r\n\\`\\`\\`\r\n\r\n---\r\n\r\n## 슬래시 커맨드 요약\r\n\r\n| 명령어 | 설명 |\r\n|--------|------|\r\n| \\`/sdd:init\\` | 프로젝트 초기화 |\r\n| \\`/sdd:constitution\\` | Constitution 생성/수정 |\r\n| \\`/sdd:new\\` | 신규 스펙 생성 |\r\n| \\`/sdd:plan\\` | 구현 계획 수립 |\r\n| \\`/sdd:tasks\\` | 작업 분해 |\r\n| \\`/sdd:change\\` | 변경 제안 |\r\n| \\`/sdd:impact\\` | 영향도 분석 |\r\n| \\`/sdd:apply\\` | 델타 적용 |\r\n| \\`/sdd:archive\\` | 아카이브 |\r\n| \\`/sdd:validate\\` | 형식 검증 |\r\n| \\`/sdd:status\\` | 현황 조회 |\r\n\r\n---\r\n\r\n## 작업 마커\r\n\r\n| 마커 | 의미 |\r\n|------|------|\r\n| [P] | 우선순위 없음 |\r\n| [P1-3] | 우선순위 (1=높음) |\r\n| [→T] | 테스트 필요 |\r\n| [US] | 불확실/검토 필요 |\r\n\r\n---\r\n\r\n## 참조\r\n\r\n- [Constitution](./constitution.md)\r\n- [Specs](./specs/)\r\n- [Changes](./changes/)\r\n`;\r\n}\r\n\r\n/**\r\n * 상단 50줄 내에 필수 규칙이 포함되어 있는지 검증\r\n */\r\nexport function validateAgentsMdFormat(content: string): {\r\n valid: boolean;\r\n errors: string[];\r\n} {\r\n const errors: string[] = [];\r\n const lines = content.split('\\n').slice(0, 50).join('\\n');\r\n\r\n // RFC 2119 키워드 포함 확인\r\n if (!lines.includes('SHALL') || !lines.includes('MUST')) {\r\n errors.push('상단 50줄 내에 RFC 2119 키워드(SHALL, MUST)가 포함되어야 합니다');\r\n }\r\n\r\n // GIVEN-WHEN-THEN 형식 포함 확인\r\n if (!lines.includes('GIVEN') || !lines.includes('WHEN') || !lines.includes('THEN')) {\r\n errors.push('상단 50줄 내에 GIVEN-WHEN-THEN 형식이 포함되어야 합니다');\r\n }\r\n\r\n return {\r\n valid: errors.length === 0,\r\n errors,\r\n };\r\n}\r\n","/**\r\n * Claude Code 슬래시 커맨드 생성기\r\n */\r\n\r\nexport interface ClaudeCommand {\r\n name: string;\r\n content: string;\r\n}\r\n\r\n/**\r\n * SDD 워크플로우용 Claude 슬래시 커맨드 생성\r\n */\r\nexport function generateClaudeCommands(): ClaudeCommand[] {\r\n return [\r\n {\r\n name: 'sdd.start',\r\n content: `SDD 워크플로우를 시작합니다 (통합 진입점).\r\n\r\n## 개요\r\n\r\n이 커맨드는 SDD 프로젝트의 통합 진입점입니다.\r\n현재 상태를 확인하고 적절한 워크플로우를 안내합니다.\r\n\r\n## 지시사항\r\n\r\n1. \\`sdd start\\` 명령어를 실행하여 프로젝트 상태를 확인하세요\r\n2. 제시되는 워크플로우 메뉴에서 적절한 작업을 선택하세요\r\n3. 각 워크플로우의 안내에 따라 진행하세요\r\n\r\n## 사용 가능한 워크플로우\r\n\r\n- **new-feature**: 새 기능 명세 작성\r\n- **change-spec**: 기존 스펙 변경\r\n- **validate**: 명세 검증\r\n- **status**: 상태 확인\r\n- **constitution**: Constitution 관리\r\n\r\n## 명령어\r\n\r\n\\`\\`\\`bash\r\n# 프로젝트 상태 및 워크플로우 메뉴\r\nsdd start\r\n\r\n# 상태만 확인\r\nsdd start --status\r\n\r\n# 특정 워크플로우 바로 시작\r\nsdd start --workflow new-feature\r\nsdd start --workflow change-spec\r\nsdd start --workflow validate\r\n\\`\\`\\`\r\n\r\n## 프로젝트 미초기화 시\r\n\r\n프로젝트가 초기화되지 않은 경우:\r\n1. \\`sdd init\\`으로 프로젝트를 초기화하세요\r\n2. \\`/sdd.constitution\\`으로 프로젝트 원칙을 정의하세요\r\n3. \\`/sdd.new\\`로 첫 기능 명세를 작성하세요\r\n`,\r\n },\r\n {\r\n name: 'sdd.new',\r\n content: `새로운 기능 명세를 작성합니다.\r\n\r\n## 지시사항\r\n\r\n1. 사용자에게 기능명과 간단한 설명을 요청하세요\r\n2. \\`sdd new <feature-id> --all\\` 명령어를 실행하여 기본 구조를 생성하세요\r\n3. 생성된 \\`.sdd/specs/<feature-id>/spec.md\\` 파일을 열어 내용을 작성하세요\r\n\r\n## 명세 작성 규칙\r\n\r\n- RFC 2119 키워드 사용: SHALL, MUST, SHOULD, MAY, SHALL NOT\r\n- GIVEN-WHEN-THEN 형식의 시나리오 포함 필수\r\n- 각 요구사항에 고유 ID 부여 (REQ-001, REQ-002, ...)\r\n\r\n## 예시\r\n\r\n\\`\\`\\`markdown\r\n### REQ-01: 사용자 인증\r\n\r\n시스템은 이메일과 비밀번호로 사용자를 인증해야 한다(SHALL).\r\n\r\n### Scenario: 올바른 자격 증명으로 로그인\r\n\r\n- **GIVEN** 등록된 사용자가 존재할 때\r\n- **WHEN** 올바른 이메일과 비밀번호로 로그인을 시도하면\r\n- **THEN** 액세스 토큰이 발급되어야 한다\r\n\\`\\`\\`\r\n\r\n완료 후 \\`sdd validate\\`로 명세를 검증하세요.\r\n`,\r\n },\r\n {\r\n name: 'sdd.plan',\r\n content: `기능 명세에 대한 구현 계획을 작성합니다.\r\n\r\n## 지시사항\r\n\r\n1. \\`.sdd/specs/\\` 디렉토리에서 계획을 작성할 기능을 확인하세요\r\n2. 해당 기능의 \\`spec.md\\`를 읽고 요구사항을 분석하세요\r\n3. \\`sdd new plan <feature-id>\\` 명령어로 계획 템플릿을 생성하거나 기존 \\`plan.md\\`를 수정하세요\r\n\r\n## 계획 작성 규칙\r\n\r\n- 기술 결정사항과 그 근거를 명시\r\n- 구현 단계(Phase)를 나누어 정의\r\n- 각 단계별 산출물 목록 작성\r\n- 리스크 분석 및 완화 전략 포함\r\n- 테스트 전략 수립\r\n\r\n## 계획 구조\r\n\r\n\\`\\`\\`markdown\r\n## 기술 결정\r\n### 결정 1: [제목]\r\n**근거:** [왜 이 기술/방식을 선택했는지]\r\n\r\n## 구현 단계\r\n### Phase 1: 기반 구조\r\n[설명]\r\n**산출물:**\r\n- [ ] 산출물 1\r\n- [ ] 산출물 2\r\n\r\n## 리스크 분석\r\n| 리스크 | 영향도 | 완화 전략 |\r\n\\`\\`\\`\r\n\r\n완료 후 \\`/sdd.tasks\\`로 작업을 분해하세요.\r\n`,\r\n },\r\n {\r\n name: 'sdd.tasks',\r\n content: `구현 계획을 실행 가능한 작업으로 분해합니다.\r\n\r\n## 지시사항\r\n\r\n1. 해당 기능의 \\`plan.md\\`를 읽고 구현 단계를 확인하세요\r\n2. \\`sdd new tasks <feature-id>\\` 명령어로 작업 목록을 생성하세요\r\n3. 각 작업에 우선순위와 상태를 지정하세요\r\n\r\n## 작업 분해 규칙\r\n\r\n- 각 작업은 2-4시간 내 완료 가능한 크기로 분해\r\n- 작업 간 의존성을 명확히 표시\r\n- 우선순위: HIGH(🔴), MEDIUM(🟡), LOW(🟢)\r\n- 상태: 대기, 진행 중, 완료, 차단됨\r\n\r\n## 작업 구조\r\n\r\n\\`\\`\\`markdown\r\n### <feature>-task-001: [작업 제목]\r\n\r\n- **상태:** 대기\r\n- **우선순위:** 🔴 HIGH\r\n- **의존성:** 없음\r\n\r\n#### 설명\r\n[작업 상세 설명]\r\n\r\n#### 완료 조건\r\n- [ ] 조건 1\r\n- [ ] 조건 2\r\n\\`\\`\\`\r\n\r\n완료 후 \\`/sdd.implement\\`로 구현을 시작하세요.\r\n`,\r\n },\r\n {\r\n name: 'sdd.implement',\r\n content: `작업 목록을 기반으로 순차적으로 구현합니다.\r\n\r\n## 지시사항\r\n\r\n1. \\`sdd status\\`로 현재 진행 상황을 확인하세요\r\n2. 해당 기능의 \\`tasks.md\\`를 읽고 다음 작업을 확인하세요\r\n3. 작업을 구현하고 완료 시 상태를 업데이트하세요\r\n\r\n## 구현 규칙\r\n\r\n- 한 번에 하나의 작업만 진행\r\n- 각 작업 완료 후 테스트 작성 필수\r\n- 커밋 메시지에 작업 ID 포함\r\n- \\`.sdd/constitution.md\\`의 원칙 준수\r\n\r\n## 작업 흐름\r\n\r\n1. 작업 상태를 \"진행 중\"으로 변경\r\n2. 코드 구현\r\n3. 테스트 작성 및 실행\r\n4. 작업 상태를 \"완료\"로 변경\r\n5. 커밋: \\`feat(<feature>): <task-id> - <설명>\\`\r\n\r\n## 완료 조건\r\n\r\n모든 작업이 완료되면:\r\n1. \\`sdd validate\\`로 최종 검증\r\n2. PR 생성 또는 머지\r\n3. 필요시 \\`/sdd.archive\\`로 아카이브\r\n`,\r\n },\r\n {\r\n name: 'sdd.validate',\r\n content: `스펙 파일의 형식과 규칙을 검증합니다.\r\n\r\n## 지시사항\r\n\r\n\\`sdd validate\\` 명령어를 실행하여 모든 스펙을 검증하세요.\r\n\r\n## 검증 항목\r\n\r\n1. **RFC 2119 키워드**: SHALL, MUST, SHOULD, MAY 등 포함 여부\r\n2. **GIVEN-WHEN-THEN**: 시나리오 형식 준수 여부\r\n3. **메타데이터**: YAML frontmatter 필수 필드 확인\r\n4. **구조**: 필수 섹션 존재 여부\r\n\r\n## 사용법\r\n\r\n\\`\\`\\`bash\r\n# 전체 스펙 검증\r\nsdd validate\r\n\r\n# 특정 파일 검증\r\nsdd validate .sdd/specs/user-auth/spec.md\r\n\r\n# 엄격 모드 (경고도 에러로 처리)\r\nsdd validate --strict\r\n\\`\\`\\`\r\n\r\n## 오류 해결\r\n\r\n검증 실패 시 해당 파일을 열어 오류를 수정하세요.\r\n각 오류 메시지에는 해결 방법이 포함되어 있습니다.\r\n`,\r\n },\r\n {\r\n name: 'sdd.status',\r\n content: `현재 SDD 프로젝트 상태를 확인합니다.\r\n\r\n## 지시사항\r\n\r\n\\`sdd status\\` 명령어를 실행하여 프로젝트 상태를 확인하세요.\r\n\r\n## 확인 항목\r\n\r\n- 프로젝트 구조 (constitution.md, AGENTS.md 존재 여부)\r\n- 기능 목록 및 상태\r\n- 현재 Git 브랜치\r\n- 다음 단계 제안\r\n\r\n## 추가 명령어\r\n\r\n\\`\\`\\`bash\r\n# 프로젝트 요약\r\nsdd list\r\n\r\n# 기능 목록\r\nsdd list features\r\n\r\n# 스펙 파일 목록\r\nsdd list specs\r\n\r\n# JSON 형식 출력\r\nsdd status --json\r\n\\`\\`\\`\r\n`,\r\n },\r\n {\r\n name: 'sdd.change',\r\n content: `기존 스펙에 대한 변경을 제안합니다.\r\n\r\n## 지시사항\r\n\r\n1. 변경이 필요한 스펙을 확인하세요\r\n2. \\`.sdd/changes/\\` 디렉토리에 변경 제안서를 작성하세요\r\n3. 변경 유형(ADDED, MODIFIED, REMOVED)을 명시하세요\r\n\r\n## 변경 제안서 구조\r\n\r\n\\`\\`\\`markdown\r\n---\r\nid: CHG-001\r\nstatus: draft\r\ncreated: YYYY-MM-DD\r\n---\r\n\r\n# 변경 제안: [제목]\r\n\r\n## 배경\r\n왜 이 변경이 필요한가?\r\n\r\n## 영향 범위\r\n### 영향받는 스펙\r\n- \\`specs/user-auth/spec.md\\`\r\n\r\n### 변경 유형\r\n- [x] 수정 (MODIFIED)\r\n\r\n## 변경 내용\r\n\r\n### MODIFIED\r\n\r\n#### Before\r\n\\`\\`\\`markdown\r\n기존 내용\r\n\\`\\`\\`\r\n\r\n#### After\r\n\\`\\`\\`markdown\r\n변경된 내용\r\n\\`\\`\\`\r\n\\`\\`\\`\r\n\r\n검토 후 승인되면 스펙에 반영하세요.\r\n`,\r\n },\r\n {\r\n name: 'sdd.constitution',\r\n content: `프로젝트 Constitution(헌법)을 관리합니다.\r\n\r\n## 개요\r\n\r\nConstitution은 프로젝트의 핵심 원칙을 정의하는 문서입니다.\r\n모든 스펙과 구현은 Constitution의 원칙을 준수해야 합니다.\r\n\r\n## 지시사항\r\n\r\n### 새 프로젝트 설정\r\n\r\n1. 사용자에게 프로젝트의 핵심 가치와 원칙을 질문하세요\r\n2. \\`.sdd/constitution.md\\` 파일을 열어 내용을 작성하세요\r\n3. \\`sdd constitution validate\\`로 형식을 검증하세요\r\n\r\n### 기존 Constitution 수정\r\n\r\n1. \\`sdd constitution show\\`로 현재 내용을 확인하세요\r\n2. Constitution 수정 후 버전을 업데이트하세요:\r\n - \\`sdd constitution bump --patch -m \"문구 수정\"\\`\r\n - \\`sdd constitution bump --minor -m \"새 원칙 추가\"\\`\r\n - \\`sdd constitution bump --major -m \"핵심 원칙 변경\"\\`\r\n\r\n## Constitution 구조\r\n\r\n\\`\\`\\`markdown\r\n---\r\nversion: 1.0.0\r\ncreated: YYYY-MM-DD\r\nupdated: YYYY-MM-DD\r\n---\r\n\r\n# Constitution: 프로젝트명\r\n\r\n> 프로젝트 설명\r\n\r\n## 핵심 원칙\r\n\r\n### 1. 원칙명\r\n- 규칙 (SHALL/MUST/SHOULD/MAY)\r\n\r\n## 금지 사항\r\n- 금지 규칙 (SHALL NOT/MUST NOT)\r\n\r\n## 기술 스택\r\n- 기술 선택\r\n\r\n## 품질 기준\r\n- 품질 요구사항\r\n\\`\\`\\`\r\n\r\n## 버전 관리\r\n\r\n- **MAJOR**: 핵심 원칙 변경 (기존 스펙에 영향)\r\n- **MINOR**: 새 원칙 추가\r\n- **PATCH**: 문구 수정, 오타 수정\r\n\r\n## 명령어\r\n\r\n\\`\\`\\`bash\r\nsdd constitution show # 현재 Constitution 표시\r\nsdd constitution version # 버전만 표시\r\nsdd constitution validate # 형식 검증\r\nsdd constitution history # 변경 이력 조회\r\nsdd constitution bump # 버전 업데이트\r\n\\`\\`\\`\r\n`,\r\n },\r\n {\r\n name: 'sdd.research',\r\n content: `기술 리서치 문서를 작성합니다.\r\n\r\n## 개요\r\n\r\n기술적 결정이나 아키텍처 선택 전에 필요한 리서치를 문서화합니다.\r\n리서치 결과는 plan.md나 스펙의 근거로 활용됩니다.\r\n\r\n## 지시사항\r\n\r\n1. 리서치 주제와 목적을 명확히 정의하세요\r\n2. 비교할 옵션들을 나열하세요\r\n3. 각 옵션의 장단점을 분석하세요\r\n4. 권장사항을 도출하세요\r\n\r\n## 리서치 템플릿\r\n\r\n\\`\\`\\`markdown\r\n# 리서치: [주제]\r\n\r\n> 작성일: YYYY-MM-DD\r\n> 상태: 진행중/완료\r\n\r\n## 배경\r\n\r\n왜 이 리서치가 필요한가?\r\n\r\n## 비교 대상\r\n\r\n### 옵션 A: [이름]\r\n\r\n**장점:**\r\n- ...\r\n\r\n**단점:**\r\n- ...\r\n\r\n**적용 사례:**\r\n- ...\r\n\r\n### 옵션 B: [이름]\r\n\r\n...\r\n\r\n## 비교표\r\n\r\n| 기준 | 옵션 A | 옵션 B |\r\n|------|--------|--------|\r\n| 성능 | ... | ... |\r\n| 학습 곡선 | ... | ... |\r\n| 커뮤니티 | ... | ... |\r\n\r\n## 결론\r\n\r\n**권장사항:** 옵션 X\r\n\r\n**근거:**\r\n1. ...\r\n2. ...\r\n\r\n## 참고 자료\r\n\r\n- [링크1]\r\n- [링크2]\r\n\\`\\`\\`\r\n\r\n## 저장 위치\r\n\r\n리서치 문서는 \\`.sdd/research/\\` 또는 해당 기능 디렉토리에 저장하세요.\r\n`,\r\n },\r\n {\r\n name: 'sdd.data-model',\r\n content: `데이터 모델 문서를 작성합니다.\r\n\r\n## 개요\r\n\r\n시스템의 데이터 구조와 관계를 정의합니다.\r\n이 문서는 구현의 기반이 되며, 변경 시 영향도 분석에 활용됩니다.\r\n\r\n## 지시사항\r\n\r\n1. 핵심 엔티티를 정의하세요\r\n2. 각 엔티티의 속성을 나열하세요\r\n3. 엔티티 간 관계를 정의하세요\r\n4. ERD를 Mermaid로 작성하세요\r\n\r\n## 데이터 모델 템플릿\r\n\r\n\\`\\`\\`markdown\r\n# 데이터 모델: [시스템명]\r\n\r\n> 작성일: YYYY-MM-DD\r\n> 버전: 1.0.0\r\n\r\n## 엔티티 정의\r\n\r\n### User (사용자)\r\n\r\n| 필드 | 타입 | 필수 | 설명 |\r\n|------|------|------|------|\r\n| id | UUID | O | 고유 식별자 |\r\n| email | string | O | 이메일 (unique) |\r\n| name | string | O | 사용자명 |\r\n| created_at | datetime | O | 생성일시 |\r\n\r\n### Post (게시글)\r\n\r\n...\r\n\r\n## 관계도 (ERD)\r\n\r\n\\`\\`\\`mermaid\r\nerDiagram\r\n User ||--o{ Post : writes\r\n User {\r\n uuid id PK\r\n string email\r\n string name\r\n }\r\n Post {\r\n uuid id PK\r\n uuid user_id FK\r\n string title\r\n text content\r\n }\r\n\\`\\`\\`\r\n\r\n## 인덱스\r\n\r\n| 테이블 | 인덱스 | 컬럼 | 유형 |\r\n|--------|--------|------|------|\r\n| User | idx_user_email | email | UNIQUE |\r\n\r\n## 제약조건\r\n\r\n- User.email은 유일해야 한다(SHALL)\r\n- Post.user_id는 User.id를 참조해야 한다(SHALL)\r\n\\`\\`\\`\r\n\r\n## 저장 위치\r\n\r\n데이터 모델은 \\`.sdd/data-model.md\\` 또는 해당 기능 디렉토리에 저장하세요.\r\n`,\r\n },\r\n {\r\n name: 'sdd.prepare',\r\n content: `기능 구현에 필요한 환경을 준비합니다.\r\n\r\n## 개요\r\n\r\n새로운 기능을 구현하기 전에 필요한 도구, 의존성, 설정을 분석하고 준비합니다.\r\n\r\n## 지시사항\r\n\r\n1. 스펙을 분석하여 필요한 기술을 파악하세요\r\n2. 필요한 의존성을 나열하세요\r\n3. 필요한 MCP 서버가 있다면 확인하세요\r\n4. AGENTS.md에 필요한 지침을 추가하세요\r\n\r\n## 준비 체크리스트\r\n\r\n### 1. 의존성 확인\r\n\r\n\\`\\`\\`bash\r\n# 필요한 npm 패키지 확인\r\nnpm list [package-name]\r\n\r\n# 설치 필요시\r\nnpm install [package-name]\r\n\\`\\`\\`\r\n\r\n### 2. 환경 설정\r\n\r\n- [ ] 환경 변수 확인 (.env)\r\n- [ ] API 키 설정\r\n- [ ] 데이터베이스 연결\r\n\r\n### 3. MCP 서버 (필요시)\r\n\r\n필요한 MCP 서버 목록:\r\n- filesystem: 파일 시스템 접근\r\n- github: GitHub API 연동\r\n- database: 데이터베이스 접근\r\n\r\n### 4. AGENTS.md 업데이트\r\n\r\n기능 구현에 필요한 지침을 AGENTS.md에 추가:\r\n\r\n\\`\\`\\`markdown\r\n## [기능명] 구현 지침\r\n\r\n### 사용 기술\r\n- ...\r\n\r\n### 구현 규칙\r\n- ...\r\n\r\n### 참고 자료\r\n- ...\r\n\\`\\`\\`\r\n\r\n## 명령어\r\n\r\n\\`\\`\\`bash\r\n# 프로젝트 상태 확인\r\nsdd status\r\n\r\n# 스펙 검증\r\nsdd validate\r\n\\`\\`\\`\r\n`,\r\n },\r\n {\r\n name: 'sdd.analyze',\r\n content: `사용자 요청을 분석하여 적절한 워크플로우를 추천합니다.\r\n\r\n## 개요\r\n\r\n자연어 요청을 분석하여 작업 규모를 판단하고, 적절한 SDD 워크플로우를 추천합니다.\r\n\r\n## 분석 기준\r\n\r\n### 작업 규모 판단\r\n\r\n**소규모 (Small)**\r\n- 키워드: 수정, 변경, 버그, 오타, 추가(단순)\r\n- 워크플로우: change 또는 직접 수정\r\n\r\n**중규모 (Medium)**\r\n- 키워드: 기능 추가, 개선, 확장, 리팩터링\r\n- 워크플로우: new → plan → tasks\r\n\r\n**대규모 (Large)**\r\n- 키워드: 시스템, 아키텍처, 마이그레이션, 전면 개편\r\n- 워크플로우: research → new → plan → tasks → prepare\r\n\r\n### 워크플로우 선택\r\n\r\n| 규모 | 추천 워크플로우 | 필수 산출물 |\r\n|------|----------------|-------------|\r\n| Small | /sdd.change | proposal.md |\r\n| Medium | /sdd.new → /sdd.plan | spec.md, plan.md |\r\n| Large | /sdd.research → /sdd.new | research.md, spec.md, plan.md |\r\n\r\n## 사용 방법\r\n\r\n1. 사용자의 요청을 입력받습니다\r\n2. 키워드와 컨텍스트를 분석합니다\r\n3. 작업 규모를 판단합니다\r\n4. 적절한 워크플로우를 추천합니다\r\n\r\n## 예시\r\n\r\n**입력:** \"로그인 기능 추가해줘\"\r\n**분석:**\r\n- 키워드: \"기능 추가\" → 중규모\r\n- 추천: /sdd.new → /sdd.plan → /sdd.tasks → /sdd.implement\r\n\r\n**입력:** \"로그인 버튼 색상 변경\"\r\n**분석:**\r\n- 키워드: \"변경\" → 소규모\r\n- 추천: 직접 수정 또는 /sdd.change\r\n\r\n**입력:** \"마이크로서비스 아키텍처로 전환\"\r\n**분석:**\r\n- 키워드: \"아키텍처\", \"전환\" → 대규모\r\n- 추천: /sdd.research → /sdd.new → /sdd.plan\r\n`,\r\n },\r\n {\r\n name: 'sdd.chat',\r\n content: `대화형 SDD 어시스턴트를 시작합니다.\r\n\r\n## 개요\r\n\r\n자연어로 SDD 작업을 수행할 수 있는 대화형 인터페이스입니다.\r\n질문, 명세 작성, 검토, 구현 등 모든 SDD 워크플로우를 대화로 진행합니다.\r\n\r\n## 대화 모드\r\n\r\n### 1. 질문 모드 (Ask)\r\n\r\nSDD나 현재 프로젝트에 대해 질문합니다:\r\n- \"이 스펙의 의존성은 뭐야?\"\r\n- \"RFC 2119 키워드는 어떻게 사용해?\"\r\n- \"다음에 뭘 해야 해?\"\r\n\r\n### 2. 작성 모드 (Write)\r\n\r\n명세나 문서를 대화형으로 작성합니다:\r\n- \"새 기능 명세 작성해줘\"\r\n- \"이 요구사항을 시나리오로 바꿔줘\"\r\n- \"plan.md 작성 도와줘\"\r\n\r\n### 3. 검토 모드 (Review)\r\n\r\n기존 명세를 검토하고 피드백합니다:\r\n- \"spec.md 검토해줘\"\r\n- \"이 시나리오 괜찮아?\"\r\n- \"RFC 2119 키워드 사용이 맞아?\"\r\n\r\n### 4. 실행 모드 (Execute)\r\n\r\nSDD 명령어를 대신 실행합니다:\r\n- \"스펙 검증해줘\"\r\n- \"영향도 분석해줘\"\r\n- \"변경 제안 목록 보여줘\"\r\n\r\n## 컨텍스트 유지\r\n\r\n대화 중 다음 정보를 자동으로 추적합니다:\r\n- 현재 작업 중인 스펙\r\n- 최근 실행한 명령어\r\n- 발견된 문제점\r\n- 다음 단계 제안\r\n\r\n## 사용 예시\r\n\r\n**대화 시작:**\r\n> 새로운 인증 기능을 만들고 싶어\r\n\r\n**응답:**\r\n1. 기능 이름과 설명을 알려주세요\r\n2. 주요 요구사항은 무엇인가요?\r\n3. 어떤 인증 방식을 사용하나요?\r\n\r\n**대화 진행:**\r\n> 이메일/비밀번호 인증이야. 소셜 로그인은 나중에\r\n\r\n**응답:**\r\n기본 인증 스펙을 작성합니다...\r\n[spec.md 작성 시작]\r\n\r\n## 종료\r\n\r\n대화를 종료하려면:\r\n- \"끝\" 또는 \"종료\"\r\n- 다른 슬래시 커맨드 사용\r\n`,\r\n },\r\n {\r\n name: 'sdd.guide',\r\n content: `SDD 워크플로우 가이드를 표시합니다.\r\n\r\n## 개요\r\n\r\nSDD(Spec-Driven Development) 방법론의 전체 워크플로우를 안내합니다.\r\n처음 사용자나 워크플로우를 잊었을 때 참고하세요.\r\n\r\n## SDD 핵심 원칙\r\n\r\n1. **명세 우선**: 코드보다 명세를 먼저 작성\r\n2. **추적 가능성**: 모든 구현은 명세에서 추적 가능\r\n3. **점진적 구체화**: 개요 → 상세 → 구현\r\n4. **변경 관리**: 모든 변경은 제안 → 검토 → 적용\r\n\r\n## 전체 워크플로우\r\n\r\n\\`\\`\\`\r\n┌─────────────────────────────────────────────────┐\r\n│ SDD 워크플로우 │\r\n├─────────────────────────────────────────────────┤\r\n│ │\r\n│ 1. 시작 ─────> /sdd.start 또는 sdd start │\r\n│ │ │\r\n│ ▼ │\r\n│ 2. Constitution ─> /sdd.constitution │\r\n│ │ (프로젝트 원칙 정의) │\r\n│ ▼ │\r\n│ 3. 새 기능 ────> /sdd.new │\r\n│ │ (spec.md 작성) │\r\n│ ▼ │\r\n│ 4. 계획 ─────> /sdd.plan │\r\n│ │ (plan.md 작성) │\r\n│ ▼ │\r\n│ 5. 작업분해 ──> /sdd.tasks │\r\n│ │ (tasks.md 작성) │\r\n│ ▼ │\r\n│ 6. 구현 ─────> /sdd.implement │\r\n│ │ (순차적 구현) │\r\n│ ▼ │\r\n│ 7. 검증 ─────> /sdd.validate │\r\n│ │ │\r\n│ ▼ │\r\n│ 8. 완료 ─────> 머지 또는 배포 │\r\n│ │\r\n└─────────────────────────────────────────────────┘\r\n\\`\\`\\`\r\n\r\n## 변경 워크플로우\r\n\r\n기존 스펙을 수정할 때:\r\n\r\n\\`\\`\\`\r\n1. /sdd.change ──> proposal.md 작성\r\n │\r\n ▼\r\n2. sdd change validate <id> ──> 검증\r\n │\r\n ▼\r\n3. sdd change apply <id> ──> 적용\r\n │\r\n ▼\r\n4. sdd change archive <id> ──> 아카이브\r\n\\`\\`\\`\r\n\r\n## 슬래시 커맨드 요약\r\n\r\n| 커맨드 | 설명 | 사용 시점 |\r\n|--------|------|----------|\r\n| /sdd.start | 통합 진입점 | 처음 시작 시 |\r\n| /sdd.new | 새 기능 명세 | 새 기능 개발 시 |\r\n| /sdd.plan | 구현 계획 | 명세 완료 후 |\r\n| /sdd.tasks | 작업 분해 | 계획 완료 후 |\r\n| /sdd.implement | 구현 | 작업 분해 후 |\r\n| /sdd.validate | 검증 | 구현 완료 후 |\r\n| /sdd.change | 변경 제안 | 기존 스펙 수정 시 |\r\n| /sdd.constitution | 헌법 관리 | 프로젝트 설정 시 |\r\n| /sdd.chat | 대화형 모드 | 언제든지 |\r\n| /sdd.analyze | 요청 분석 | 규모 판단 시 |\r\n\r\n## CLI 명령어 요약\r\n\r\n\\`\\`\\`bash\r\nsdd init # 프로젝트 초기화\r\nsdd start # 워크플로우 시작\r\nsdd new <name> # 새 기능 생성\r\nsdd new <name> --numbered # 번호 자동 부여\r\nsdd validate # 스펙 검증\r\nsdd validate --check-links # 링크 검증 포함\r\nsdd status # 상태 확인\r\nsdd list # 스펙 목록\r\nsdd change -l # 변경 목록\r\nsdd impact <spec> # 영향도 분석\r\nsdd transition guide # 전환 가이드\r\n\\`\\`\\`\r\n\r\n## 도움말\r\n\r\n더 자세한 정보:\r\n- \\`sdd --help\\` - CLI 도움말\r\n- \\`sdd <command> --help\\` - 명령어별 도움말\r\n`,\r\n },\r\n {\r\n name: 'sdd.transition',\r\n content: `워크플로우 간 전환을 수행합니다.\r\n\r\n## 개요\r\n\r\n작업 중 워크플로우를 변경해야 할 때 사용합니다:\r\n- **new → change**: 새 기능이 기존 스펙 수정으로 변경\r\n- **change → new**: 변경 범위가 커서 새 기능으로 분리\r\n\r\n## new → change 전환\r\n\r\n### 사용 시점\r\n- 새 기능 작성 중 기존 스펙과 중복 발견\r\n- 기존 기능 확장이 더 적절한 경우\r\n- 의존성 분석 결과 기존 스펙 수정 필요\r\n\r\n### 명령어\r\n\r\n\\`\\`\\`bash\r\nsdd transition new-to-change <spec-id>\r\n -t, --title <title> # 변경 제안 제목\r\n -r, --reason <reason> # 전환 사유\r\n\\`\\`\\`\r\n\r\n### 결과\r\n- 새 변경 제안 생성 (.sdd/changes/<id>/)\r\n- proposal.md, delta.md, tasks.md 생성\r\n- 기존 스펙 참조 자동 설정\r\n\r\n## change → new 전환\r\n\r\n### 사용 시점\r\n- 변경 범위가 너무 커서 별도 기능으로 분리 필요\r\n- 기존 스펙과 독립적인 새 기능으로 발전\r\n- 영향도 분석 결과 분리가 안전\r\n\r\n### 명령어\r\n\r\n\\`\\`\\`bash\r\nsdd transition change-to-new <change-id>\r\n -n, --name <name> # 새 기능 이름\r\n -r, --reason <reason> # 전환 사유\r\n\\`\\`\\`\r\n\r\n### 결과\r\n- 새 스펙 생성 (.sdd/specs/<name>/)\r\n- spec.md, plan.md, tasks.md 생성\r\n- 원본 변경 제안은 'transitioned' 상태로 변경\r\n\r\n## 전환 판단 기준\r\n\r\n### new → change 권장\r\n- 영향받는 스펙 수 ≤ 3개\r\n- 변경이 기존 기능의 자연스러운 확장\r\n- 새 시나리오 추가보다 기존 시나리오 수정 중심\r\n\r\n### change → new 권장\r\n- 영향받는 스펙 수 > 3개\r\n- 새로운 개념/도메인 도입\r\n- 기존 스펙과 독립적으로 테스트 가능\r\n\r\n## 가이드 보기\r\n\r\n\\`\\`\\`bash\r\nsdd transition guide\r\n\\`\\`\\`\r\n`,\r\n },\r\n ];\r\n}\r\n","/**\r\n * sdd validate 명령어\r\n */\r\nimport { Command } from 'commander';\r\nimport path from 'node:path';\r\nimport chalk from 'chalk';\r\nimport { validateSpecs, type FileValidationResult } from '../../core/spec/validator.js';\r\nimport { ExitCode } from '../../errors/index.js';\r\nimport { findSddRoot, fileExists } from '../../utils/fs.js';\r\nimport * as logger from '../../utils/logger.js';\r\nimport { formatViolationReport } from '../../core/constitution/index.js';\r\n\r\n/**\r\n * validate 명령어 등록\r\n */\r\nexport function registerValidateCommand(program: Command): void {\r\n program\r\n .command('validate')\r\n .description('스펙 파일 형식을 검증합니다')\r\n .argument('[path]', '검증할 파일 또는 디렉토리', '')\r\n .option('-s, --strict', '경고도 에러로 처리')\r\n .option('-q, --quiet', '요약만 출력')\r\n .option('-l, --check-links', '참조 링크 유효성 검사')\r\n .option('-c, --constitution', 'Constitution 위반 검사 (기본값)')\r\n .option('--no-constitution', 'Constitution 검사 건너뛰기')\r\n .action(async (targetPath: string, options: ValidateOptions) => {\r\n try {\r\n await runValidate(targetPath, options);\r\n } catch (error) {\r\n logger.error(error instanceof Error ? error.message : String(error));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n });\r\n}\r\n\r\n/**\r\n * CLI 옵션\r\n */\r\ninterface ValidateOptions {\r\n strict?: boolean;\r\n quiet?: boolean;\r\n checkLinks?: boolean;\r\n constitution?: boolean;\r\n}\r\n\r\n/**\r\n * 검증 실행\r\n */\r\nasync function runValidate(\r\n targetPath: string,\r\n options: ValidateOptions\r\n): Promise<void> {\r\n // 대상 경로 결정\r\n let resolvedPath: string;\r\n let specsRoot: string | undefined;\r\n\r\n const sddRoot = await findSddRoot();\r\n\r\n if (targetPath) {\r\n resolvedPath = path.resolve(targetPath);\r\n } else {\r\n // 기본값: .sdd/specs/\r\n if (!sddRoot) {\r\n logger.error('SDD 프로젝트를 찾을 수 없습니다. `sdd init`을 먼저 실행하세요.');\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n resolvedPath = path.join(sddRoot, '.sdd', 'specs');\r\n }\r\n\r\n // 링크 검증을 위한 스펙 루트 경로 설정\r\n if (options.checkLinks && sddRoot) {\r\n specsRoot = path.join(sddRoot, '.sdd', 'specs');\r\n }\r\n\r\n // Constitution 검증 여부 결정 (기본값: true, --no-constitution 시 false)\r\n const checkConstitution = options.constitution !== false;\r\n let hasConstitution = false;\r\n\r\n if (checkConstitution && sddRoot) {\r\n const constitutionPath = path.join(sddRoot, '.sdd', 'constitution.md');\r\n hasConstitution = await fileExists(constitutionPath);\r\n }\r\n\r\n if (!options.quiet) {\r\n logger.info(`검증 중: ${resolvedPath}`);\r\n if (options.checkLinks) {\r\n logger.info('(참조 링크 검증 포함)');\r\n }\r\n if (checkConstitution && hasConstitution) {\r\n logger.info('(Constitution 위반 검사 포함)');\r\n }\r\n logger.newline();\r\n }\r\n\r\n // 검증 실행\r\n const result = await validateSpecs(resolvedPath, {\r\n strict: options.strict,\r\n checkLinks: options.checkLinks,\r\n specsRoot,\r\n checkConstitution: checkConstitution && hasConstitution,\r\n sddRoot: sddRoot || undefined,\r\n });\r\n\r\n if (!result.success) {\r\n logger.error(result.error.message);\r\n process.exit(ExitCode.FILE_SYSTEM_ERROR);\r\n }\r\n\r\n const { passed, failed, warnings, files } = result.data;\r\n\r\n // 결과 출력\r\n if (!options.quiet) {\r\n for (const file of files) {\r\n printFileResult(file, resolvedPath);\r\n }\r\n logger.newline();\r\n }\r\n\r\n // 요약\r\n const passedText = chalk.green(`${passed} passed`);\r\n const failedText = failed > 0 ? chalk.red(`${failed} failed`) : `${failed} failed`;\r\n const warningsText = warnings > 0 ? chalk.yellow(`${warnings} warnings`) : '';\r\n\r\n const summary = [passedText, failedText, warningsText].filter(Boolean).join(', ');\r\n console.log(`Result: ${summary}`);\r\n\r\n // 종료 코드\r\n if (failed > 0) {\r\n process.exit(ExitCode.VALIDATION_FAILED);\r\n }\r\n}\r\n\r\n/**\r\n * 파일 검증 결과 출력\r\n */\r\nfunction printFileResult(result: FileValidationResult, basePath: string): void {\r\n const relativePath = path.relative(basePath, result.file);\r\n\r\n if (result.valid) {\r\n console.log(chalk.green('✓') + ' ' + relativePath);\r\n } else {\r\n console.log(chalk.red('✗') + ' ' + relativePath);\r\n\r\n for (const error of result.errors) {\r\n const line = error.location?.line ? `:${error.location.line}` : '';\r\n console.log(chalk.red(` - ${error.message}${line}`));\r\n }\r\n }\r\n\r\n // 경고 출력\r\n for (const warning of result.warnings) {\r\n console.log(chalk.yellow(` ⚠ ${warning.message}`));\r\n }\r\n\r\n // Constitution 검사 결과 요약\r\n if (result.constitutionCheck) {\r\n const cc = result.constitutionCheck;\r\n if (cc.passed) {\r\n console.log(chalk.green(` ✓ Constitution 검사 통과 (${cc.rulesChecked}개 규칙)`));\r\n } else {\r\n console.log(chalk.red(` ✗ Constitution 위반 발견 (${cc.violations.length}건)`));\r\n }\r\n }\r\n}\r\n","/**\r\n * 스펙 검증기\r\n */\r\nimport path from 'node:path';\r\nimport { parseSpec, validateSpecFormat } from './parser.js';\r\nimport { readFile, listFiles, directoryExists, fileExists } from '../../utils/fs.js';\r\nimport { ValidationError, ErrorCode } from '../../errors/index.js';\r\nimport { Result, success, failure, type ValidationResult, type SpecValidationError, type SpecValidationWarning } from '../../types/index.js';\r\nimport {\r\n parseConstitution,\r\n checkConstitutionViolations,\r\n type ConstitutionCheckResult,\r\n type Violation,\r\n} from '../constitution/index.js';\r\n\r\n/**\r\n * 검증 옵션\r\n */\r\nexport interface ValidateOptions {\r\n /** 경고도 에러로 처리 */\r\n strict?: boolean;\r\n /** 참조 링크 검증 */\r\n checkLinks?: boolean;\r\n /** 스펙 루트 경로 (링크 검증 시 사용) */\r\n specsRoot?: string;\r\n /** Constitution 위반 검증 */\r\n checkConstitution?: boolean;\r\n /** SDD 루트 경로 (Constitution 검증 시 사용) */\r\n sddRoot?: string;\r\n}\r\n\r\n/**\r\n * 깨진 링크 정보\r\n */\r\nexport interface BrokenLink {\r\n /** 링크 텍스트 */\r\n text: string;\r\n /** 링크 대상 */\r\n target: string;\r\n /** 발견된 줄 번호 */\r\n line?: number;\r\n /** 링크 유형 */\r\n type: 'internal' | 'spec-reference' | 'dependency';\r\n}\r\n\r\n/**\r\n * 파일 검증 결과\r\n */\r\nexport interface FileValidationResult {\r\n file: string;\r\n valid: boolean;\r\n errors: SpecValidationError[];\r\n warnings: SpecValidationWarning[];\r\n /** 깨진 링크 목록 */\r\n brokenLinks?: BrokenLink[];\r\n /** Constitution 위반 검사 결과 */\r\n constitutionCheck?: ConstitutionCheckResult;\r\n}\r\n\r\n/**\r\n * 전체 검증 결과\r\n */\r\nexport interface ValidateResult {\r\n passed: number;\r\n failed: number;\r\n warnings: number;\r\n files: FileValidationResult[];\r\n}\r\n\r\n/**\r\n * 단일 스펙 파일 검증\r\n */\r\nexport async function validateSpecFile(\r\n filePath: string,\r\n options: ValidateOptions = {}\r\n): Promise<FileValidationResult> {\r\n const result: FileValidationResult = {\r\n file: filePath,\r\n valid: true,\r\n errors: [],\r\n warnings: [],\r\n };\r\n\r\n // 파일 읽기\r\n const readResult = await readFile(filePath);\r\n if (!readResult.success) {\r\n result.valid = false;\r\n result.errors.push({\r\n code: ErrorCode.FILE_READ_ERROR,\r\n message: `파일을 읽을 수 없습니다: ${filePath}`,\r\n location: { file: filePath },\r\n });\r\n return result;\r\n }\r\n\r\n const content = readResult.data;\r\n\r\n // 스펙 파싱 및 검증\r\n const parseResult = parseSpec(content);\r\n if (!parseResult.success) {\r\n result.valid = false;\r\n result.errors.push({\r\n code: parseResult.error.code,\r\n message: parseResult.error.message,\r\n location: { file: filePath },\r\n });\r\n return result;\r\n }\r\n\r\n const spec = parseResult.data;\r\n\r\n // RFC 2119 키워드 검증\r\n if (spec.requirements.length === 0) {\r\n result.valid = false;\r\n result.errors.push({\r\n code: ErrorCode.RFC2119_VIOLATION,\r\n message: 'Requirement에 RFC 2119 키워드(SHALL, MUST, SHOULD, MAY)가 없습니다',\r\n location: { file: filePath },\r\n });\r\n }\r\n\r\n // GIVEN-WHEN-THEN 형식 검증\r\n if (spec.scenarios.length === 0) {\r\n result.valid = false;\r\n result.errors.push({\r\n code: ErrorCode.GWT_INVALID_FORMAT,\r\n message: 'Scenario에 GIVEN-WHEN-THEN 형식이 없습니다',\r\n location: { file: filePath },\r\n });\r\n }\r\n\r\n // Frontmatter 경고\r\n if (!spec.metadata.created) {\r\n result.warnings.push({\r\n code: 'W001',\r\n message: 'YAML frontmatter에 created 날짜가 없습니다',\r\n location: { file: filePath },\r\n });\r\n }\r\n\r\n // 참조 링크 검증\r\n if (options.checkLinks && options.specsRoot) {\r\n const brokenLinks = await validateLinks(content, filePath, options.specsRoot);\r\n if (brokenLinks.length > 0) {\r\n result.brokenLinks = brokenLinks;\r\n for (const link of brokenLinks) {\r\n result.warnings.push({\r\n code: 'W002',\r\n message: `깨진 ${link.type} 링크: ${link.target}`,\r\n location: { file: filePath, line: link.line },\r\n });\r\n }\r\n }\r\n }\r\n\r\n // Constitution 위반 검증\r\n if (options.checkConstitution && options.sddRoot) {\r\n const constitutionPath = path.join(options.sddRoot, '.sdd', 'constitution.md');\r\n const constReadResult = await readFile(constitutionPath);\r\n\r\n if (constReadResult.success) {\r\n const constParseResult = parseConstitution(constReadResult.data);\r\n\r\n if (constParseResult.success) {\r\n const constitution = constParseResult.data;\r\n const specConstitutionVersion = spec.metadata.constitution_version as string | undefined;\r\n\r\n const checkResult = checkConstitutionViolations(\r\n content,\r\n specConstitutionVersion,\r\n constitution\r\n );\r\n\r\n result.constitutionCheck = checkResult;\r\n\r\n // 위반 사항을 에러/경고로 변환\r\n for (const violation of checkResult.violations) {\r\n if (violation.severity === 'critical') {\r\n result.valid = false;\r\n result.errors.push({\r\n code: ErrorCode.CONSTITUTION_VIOLATION,\r\n message: `[${violation.ruleId}] ${violation.message}`,\r\n location: { file: filePath, line: violation.line },\r\n });\r\n } else {\r\n result.warnings.push({\r\n code: 'W003',\r\n message: `[Constitution] ${violation.message}`,\r\n location: { file: filePath, line: violation.line },\r\n });\r\n }\r\n }\r\n\r\n // 버전 불일치 경고/에러\r\n if (checkResult.versionMismatch) {\r\n const vm = checkResult.versionMismatch;\r\n if (vm.severity === 'critical') {\r\n result.valid = false;\r\n result.errors.push({\r\n code: ErrorCode.CONSTITUTION_VERSION_MISMATCH,\r\n message: vm.message,\r\n location: { file: filePath },\r\n });\r\n } else {\r\n result.warnings.push({\r\n code: 'W004',\r\n message: vm.message,\r\n location: { file: filePath },\r\n });\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n // strict 모드: 경고도 에러로 처리\r\n if (options.strict && result.warnings.length > 0) {\r\n result.valid = false;\r\n result.errors.push(...result.warnings.map((w) => ({\r\n code: w.code,\r\n message: `[STRICT] ${w.message}`,\r\n location: w.location,\r\n })));\r\n }\r\n\r\n return result;\r\n}\r\n\r\n/**\r\n * 스펙 파일 내 링크 검증\r\n */\r\nasync function validateLinks(\r\n content: string,\r\n filePath: string,\r\n specsRoot: string\r\n): Promise<BrokenLink[]> {\r\n const brokenLinks: BrokenLink[] = [];\r\n const lines = content.split('\\n');\r\n const fileDir = path.dirname(filePath);\r\n\r\n // 마크다운 링크 패턴: [text](url)\r\n const linkPattern = /\\[([^\\]]+)\\]\\(([^)]+)\\)/g;\r\n\r\n // 스펙 참조 패턴: `spec-id` 또는 [[spec-id]]\r\n const specRefPattern = /(?:`([a-z0-9-]+)`|\\[\\[([a-z0-9-]+)\\]\\])/g;\r\n\r\n for (let lineNum = 0; lineNum < lines.length; lineNum++) {\r\n const line = lines[lineNum];\r\n\r\n // 마크다운 링크 검증\r\n let match;\r\n while ((match = linkPattern.exec(line)) !== null) {\r\n const [, text, target] = match;\r\n\r\n // 외부 링크 (http/https) 또는 앵커 링크 (#) 무시\r\n if (target.startsWith('http://') || target.startsWith('https://') || target.startsWith('#')) {\r\n continue;\r\n }\r\n\r\n // 내부 파일 링크 검증\r\n const targetPath = path.resolve(fileDir, target);\r\n if (!(await fileExists(targetPath))) {\r\n brokenLinks.push({\r\n text,\r\n target,\r\n line: lineNum + 1,\r\n type: 'internal',\r\n });\r\n }\r\n }\r\n\r\n // 스펙 참조 검증 (backtick 또는 wiki-style 링크)\r\n while ((match = specRefPattern.exec(line)) !== null) {\r\n const specId = match[1] || match[2];\r\n\r\n // 일반적인 코드 키워드 제외\r\n const codeKeywords = ['true', 'false', 'null', 'undefined', 'string', 'number', 'boolean', 'object', 'array'];\r\n if (codeKeywords.includes(specId)) {\r\n continue;\r\n }\r\n\r\n // 스펙 ID 형식인지 확인 (하이픈 포함, 영소문자+숫자)\r\n if (!/^[a-z][a-z0-9]*(-[a-z0-9]+)+$/.test(specId)) {\r\n continue;\r\n }\r\n\r\n // 스펙 디렉토리 확인\r\n const specPath = path.join(specsRoot, specId);\r\n const specFilePath = path.join(specPath, 'spec.md');\r\n if (!(await directoryExists(specPath)) && !(await fileExists(specFilePath))) {\r\n brokenLinks.push({\r\n text: specId,\r\n target: specId,\r\n line: lineNum + 1,\r\n type: 'spec-reference',\r\n });\r\n }\r\n }\r\n }\r\n\r\n return brokenLinks;\r\n}\r\n\r\n/**\r\n * 스펙의 의존성 검증\r\n */\r\nexport async function validateDependencies(\r\n filePath: string,\r\n specsRoot: string\r\n): Promise<BrokenLink[]> {\r\n const brokenLinks: BrokenLink[] = [];\r\n\r\n const readResult = await readFile(filePath);\r\n if (!readResult.success) {\r\n return brokenLinks;\r\n }\r\n\r\n const parseResult = parseSpec(readResult.data);\r\n if (!parseResult.success) {\r\n return brokenLinks;\r\n }\r\n\r\n const spec = parseResult.data;\r\n\r\n // dependencies 필드 검증\r\n if (spec.metadata.dependencies && Array.isArray(spec.metadata.dependencies)) {\r\n for (const dep of spec.metadata.dependencies) {\r\n const depPath = path.join(specsRoot, dep);\r\n const depFilePath = path.join(depPath, 'spec.md');\r\n if (!(await directoryExists(depPath)) && !(await fileExists(depFilePath))) {\r\n brokenLinks.push({\r\n text: dep,\r\n target: dep,\r\n type: 'dependency',\r\n });\r\n }\r\n }\r\n }\r\n\r\n return brokenLinks;\r\n}\r\n\r\n/**\r\n * 디렉토리 내 모든 스펙 파일 검증\r\n */\r\nexport async function validateSpecs(\r\n targetPath: string,\r\n options: ValidateOptions = {}\r\n): Promise<Result<ValidateResult, ValidationError>> {\r\n const results: FileValidationResult[] = [];\r\n let passed = 0;\r\n let failed = 0;\r\n let warnings = 0;\r\n\r\n // 디렉토리인지 파일인지 확인\r\n if (await directoryExists(targetPath)) {\r\n // 디렉토리 내 모든 .md 파일 찾기\r\n const filesResult = await findSpecFiles(targetPath);\r\n if (!filesResult.success) {\r\n return failure(new ValidationError(ErrorCode.DIRECTORY_NOT_FOUND, targetPath));\r\n }\r\n\r\n for (const file of filesResult.data) {\r\n const result = await validateSpecFile(file, options);\r\n results.push(result);\r\n\r\n if (result.valid) {\r\n passed++;\r\n } else {\r\n failed++;\r\n }\r\n warnings += result.warnings.length;\r\n }\r\n } else {\r\n // 단일 파일 검증\r\n const result = await validateSpecFile(targetPath, options);\r\n results.push(result);\r\n\r\n if (result.valid) {\r\n passed++;\r\n } else {\r\n failed++;\r\n }\r\n warnings += result.warnings.length;\r\n }\r\n\r\n return success({\r\n passed,\r\n failed,\r\n warnings,\r\n files: results,\r\n });\r\n}\r\n\r\n/**\r\n * 디렉토리 내 스펙 파일 재귀 검색\r\n */\r\nasync function findSpecFiles(dirPath: string): Promise<Result<string[], ValidationError>> {\r\n const files: string[] = [];\r\n\r\n async function scanDir(dir: string): Promise<void> {\r\n const { promises: fs } = await import('node:fs');\r\n\r\n try {\r\n const entries = await fs.readdir(dir, { withFileTypes: true });\r\n\r\n for (const entry of entries) {\r\n const fullPath = path.join(dir, entry.name);\r\n\r\n if (entry.isDirectory()) {\r\n await scanDir(fullPath);\r\n } else if (entry.isFile() && entry.name.endsWith('.md')) {\r\n // 보조 파일 및 시스템 파일 제외 (spec.md만 검증)\r\n const excludeFiles = [\r\n 'index.md',\r\n 'readme.md',\r\n 'plan.md',\r\n 'tasks.md',\r\n 'checklist.md',\r\n ];\r\n if (!excludeFiles.includes(entry.name.toLowerCase())) {\r\n files.push(fullPath);\r\n }\r\n }\r\n }\r\n } catch {\r\n // 디렉토리 읽기 실패 시 무시\r\n }\r\n }\r\n\r\n await scanDir(dirPath);\r\n return success(files);\r\n}\r\n","/**\r\n * 스펙 마크다운 파서\r\n */\r\nimport matter from 'gray-matter';\r\nimport {\r\n ParsedSpec,\r\n SpecMetadataSchema,\r\n Requirement,\r\n Scenario,\r\n extractRfc2119Keywords,\r\n type SpecMetadata,\r\n} from './schemas.js';\r\nimport { Result, success, failure } from '../../types/index.js';\r\nimport { ValidationError, ErrorCode } from '../../errors/index.js';\r\n\r\n/**\r\n * 마크다운 스펙 파일 파싱\r\n */\r\nexport function parseSpec(content: string): Result<ParsedSpec, ValidationError> {\r\n try {\r\n // 1. Frontmatter 파싱\r\n const { data: rawMeta, content: body } = matter(content);\r\n\r\n // 2. 메타데이터 검증\r\n const metaResult = SpecMetadataSchema.safeParse(rawMeta);\r\n if (!metaResult.success) {\r\n const errors = metaResult.error.errors.map((e) => e.message).join(', ');\r\n return failure(new ValidationError(ErrorCode.SPEC_INVALID_FORMAT, `메타데이터 오류: ${errors}`));\r\n }\r\n const metadata: SpecMetadata = metaResult.data;\r\n\r\n // 3. 제목 추출\r\n const titleMatch = body.match(/^#\\s+(.+)$/m);\r\n if (!titleMatch) {\r\n return failure(new ValidationError(ErrorCode.SPEC_MISSING_REQUIRED, '제목(# Title)이 필요합니다'));\r\n }\r\n const title = titleMatch[1].trim();\r\n\r\n // 4. 설명 추출 (제목 다음 줄의 blockquote)\r\n const descMatch = body.match(/^#\\s+.+\\n+>\\s*(.+)$/m);\r\n const description = descMatch?.[1]?.trim();\r\n\r\n // 5. 요구사항 추출\r\n const requirements = parseRequirements(body);\r\n\r\n // 6. 시나리오 추출\r\n const scenarios = parseScenarios(body);\r\n\r\n return success({\r\n title,\r\n description,\r\n metadata,\r\n requirements,\r\n scenarios,\r\n rawContent: content,\r\n });\r\n } catch (error) {\r\n const message = error instanceof Error ? error.message : String(error);\r\n return failure(new ValidationError(ErrorCode.SPEC_PARSE_ERROR, message));\r\n }\r\n}\r\n\r\n/**\r\n * 요구사항 파싱\r\n */\r\nfunction parseRequirements(content: string): Requirement[] {\r\n const requirements: Requirement[] = [];\r\n\r\n // 요구사항 섹션 찾기 (## 요구사항 또는 ## Requirements)\r\n const reqSectionMatch = content.match(/##\\s+(?:요구사항|Requirements?)\\s*\\n([\\s\\S]*?)(?=\\n##\\s+[^#]|\\n---|\\n$)/i);\r\n if (!reqSectionMatch) {\r\n // 전체 문서에서 RFC 2119 키워드 찾기\r\n return parseRequirementsFromContent(content);\r\n }\r\n\r\n return parseRequirementsFromContent(reqSectionMatch[1]);\r\n}\r\n\r\n/**\r\n * 컨텐츠에서 요구사항 추출\r\n */\r\nfunction parseRequirementsFromContent(content: string): Requirement[] {\r\n const requirements: Requirement[] = [];\r\n const lines = content.split('\\n');\r\n let reqId = 1;\r\n\r\n for (const line of lines) {\r\n const keywords = extractRfc2119Keywords(line);\r\n if (keywords.length > 0) {\r\n // 가장 강한 키워드 사용 (SHALL/MUST > SHOULD > MAY)\r\n const level = keywords.includes('SHALL') || keywords.includes('MUST')\r\n ? (keywords.includes('SHALL') ? 'SHALL' : 'MUST')\r\n : keywords.includes('SHOULD')\r\n ? 'SHOULD'\r\n : 'MAY';\r\n\r\n requirements.push({\r\n id: `REQ-${String(reqId++).padStart(3, '0')}`,\r\n level,\r\n description: line.trim(),\r\n raw: line,\r\n });\r\n }\r\n }\r\n\r\n return requirements;\r\n}\r\n\r\n/**\r\n * 시나리오 파싱 (GIVEN-WHEN-THEN)\r\n */\r\nfunction parseScenarios(content: string): Scenario[] {\r\n const scenarios: Scenario[] = [];\r\n\r\n // ### Scenario 섹션 찾기 (Scenario:, Scenario 1:, Scenario 1. 등 다양한 형식 지원)\r\n const scenarioRegex = /###\\s+Scenario[:\\s]+(.+?)(?=\\n###|\\n##|\\n---|\\n$)/gis;\r\n let match: RegExpExecArray | null;\r\n\r\n while ((match = scenarioRegex.exec(content)) !== null) {\r\n const sectionContent = match[0];\r\n const nameMatch = sectionContent.match(/###\\s+Scenario[:\\s]+(.+)/i);\r\n const name = nameMatch?.[1]?.trim() ?? 'Unnamed';\r\n\r\n const given: string[] = [];\r\n const then: string[] = [];\r\n let when = '';\r\n\r\n const lines = sectionContent.split('\\n');\r\n\r\n for (const line of lines) {\r\n const trimmed = line.trim();\r\n\r\n // GIVEN 파싱\r\n const givenMatch = trimmed.match(/[-*]\\s*\\*?\\*?GIVEN\\*?\\*?\\s+(.+)/i);\r\n if (givenMatch) {\r\n given.push(givenMatch[1].trim());\r\n continue;\r\n }\r\n\r\n // WHEN 파싱\r\n const whenMatch = trimmed.match(/[-*]\\s*\\*?\\*?WHEN\\*?\\*?\\s+(.+)/i);\r\n if (whenMatch) {\r\n when = whenMatch[1].trim();\r\n continue;\r\n }\r\n\r\n // THEN 파싱\r\n const thenMatch = trimmed.match(/[-*]\\s*\\*?\\*?THEN\\*?\\*?\\s+(.+)/i);\r\n if (thenMatch) {\r\n then.push(thenMatch[1].trim());\r\n }\r\n }\r\n\r\n if (given.length > 0 && when && then.length > 0) {\r\n scenarios.push({ name, given, when, then });\r\n }\r\n }\r\n\r\n return scenarios;\r\n}\r\n\r\n/**\r\n * 스펙 파일 검증만 수행 (파싱 + 검증)\r\n */\r\nexport function validateSpecFormat(content: string): Result<true, ValidationError> {\r\n const result = parseSpec(content);\r\n if (!result.success) {\r\n return result as Result<true, ValidationError>;\r\n }\r\n\r\n const spec = result.data;\r\n\r\n // 요구사항 필수 검증\r\n if (spec.requirements.length === 0) {\r\n return failure(\r\n new ValidationError(\r\n ErrorCode.RFC2119_VIOLATION,\r\n 'RFC 2119 키워드(SHALL, MUST, SHOULD, MAY)가 포함된 요구사항이 없습니다'\r\n )\r\n );\r\n }\r\n\r\n // 시나리오 필수 검증\r\n if (spec.scenarios.length === 0) {\r\n return failure(\r\n new ValidationError(\r\n ErrorCode.GWT_INVALID_FORMAT,\r\n 'GIVEN-WHEN-THEN 형식의 시나리오가 없습니다'\r\n )\r\n );\r\n }\r\n\r\n return success(true);\r\n}\r\n","/**\r\n * 스펙 관련 Zod 스키마 정의\r\n */\r\nimport { z } from 'zod';\r\n\r\n/**\r\n * RFC 2119 키워드\r\n */\r\nexport const RFC2119_KEYWORDS = ['SHALL', 'MUST', 'SHOULD', 'MAY', 'SHALL NOT', 'MUST NOT'] as const;\r\nexport type Rfc2119Keyword = (typeof RFC2119_KEYWORDS)[number];\r\n\r\n/**\r\n * 스펙 상태\r\n */\r\nexport const SpecStatusSchema = z.enum(['draft', 'review', 'approved', 'implemented']);\r\nexport type SpecStatus = z.infer<typeof SpecStatusSchema>;\r\n\r\n/**\r\n * 날짜 스키마 (Date 객체 또는 문자열 허용, 문자열로 변환)\r\n */\r\nconst DateStringSchema = z.preprocess(\r\n (val) => {\r\n if (val instanceof Date) {\r\n return val.toISOString().split('T')[0];\r\n }\r\n return val;\r\n },\r\n z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/, '날짜 형식: YYYY-MM-DD').optional()\r\n);\r\n\r\n/**\r\n * 스펙 메타데이터 (YAML frontmatter)\r\n */\r\nexport const SpecMetadataSchema = z.object({\r\n status: SpecStatusSchema.default('draft'),\r\n created: DateStringSchema,\r\n depends: z.string().nullable().optional(),\r\n command: z.string().optional(),\r\n author: z.string().optional(),\r\n});\r\nexport type SpecMetadata = z.infer<typeof SpecMetadataSchema>;\r\n\r\n/**\r\n * 요구사항 레벨\r\n */\r\nexport const RequirementLevelSchema = z.enum(['SHALL', 'MUST', 'SHOULD', 'MAY']);\r\nexport type RequirementLevel = z.infer<typeof RequirementLevelSchema>;\r\n\r\n/**\r\n * 요구사항\r\n */\r\nexport const RequirementSchema = z.object({\r\n id: z.string(),\r\n level: RequirementLevelSchema,\r\n description: z.string(),\r\n raw: z.string(),\r\n});\r\nexport type Requirement = z.infer<typeof RequirementSchema>;\r\n\r\n/**\r\n * 시나리오 (GIVEN-WHEN-THEN)\r\n */\r\nexport const ScenarioSchema = z.object({\r\n name: z.string(),\r\n given: z.array(z.string()).min(1, 'GIVEN 조건이 최소 1개 필요합니다'),\r\n when: z.string().min(1, 'WHEN 조건이 필요합니다'),\r\n then: z.array(z.string()).min(1, 'THEN 결과가 최소 1개 필요합니다'),\r\n});\r\nexport type Scenario = z.infer<typeof ScenarioSchema>;\r\n\r\n/**\r\n * 파싱된 스펙 문서\r\n */\r\nexport const ParsedSpecSchema = z.object({\r\n title: z.string(),\r\n description: z.string().optional(),\r\n metadata: SpecMetadataSchema,\r\n requirements: z.array(RequirementSchema),\r\n scenarios: z.array(ScenarioSchema),\r\n rawContent: z.string(),\r\n});\r\nexport type ParsedSpec = z.infer<typeof ParsedSpecSchema>;\r\n\r\n/**\r\n * 키워드가 RFC 2119 키워드인지 확인\r\n */\r\nexport function isRfc2119Keyword(keyword: string): keyword is Rfc2119Keyword {\r\n return RFC2119_KEYWORDS.includes(keyword as Rfc2119Keyword);\r\n}\r\n\r\n/**\r\n * 문자열에서 RFC 2119 키워드 추출\r\n */\r\nexport function extractRfc2119Keywords(text: string): Rfc2119Keyword[] {\r\n const keywords: Rfc2119Keyword[] = [];\r\n\r\n // SHALL NOT, MUST NOT를 먼저 체크 (더 긴 패턴)\r\n if (/SHALL\\s+NOT/i.test(text)) keywords.push('SHALL NOT');\r\n if (/MUST\\s+NOT/i.test(text)) keywords.push('MUST NOT');\r\n\r\n // 단일 키워드 체크 (NOT이 붙지 않은 경우만)\r\n if (/(?<!NOT\\s)SHALL(?!\\s+NOT)/i.test(text)) keywords.push('SHALL');\r\n if (/(?<!NOT\\s)MUST(?!\\s+NOT)/i.test(text)) keywords.push('MUST');\r\n if (/SHOULD/i.test(text)) keywords.push('SHOULD');\r\n if (/MAY/i.test(text)) keywords.push('MAY');\r\n\r\n return [...new Set(keywords)];\r\n}\r\n","/**\r\n * Constitution 관련 Zod 스키마 정의\r\n */\r\nimport { z } from 'zod';\r\n\r\n/**\r\n * 시맨틱 버전 스키마\r\n */\r\nexport const SemanticVersionSchema = z.string().regex(\r\n /^\\d+\\.\\d+\\.\\d+$/,\r\n '버전 형식: MAJOR.MINOR.PATCH (예: 1.2.3)'\r\n);\r\nexport type SemanticVersion = z.infer<typeof SemanticVersionSchema>;\r\n\r\n/**\r\n * 버전 범프 유형\r\n */\r\nexport const VersionBumpType = ['major', 'minor', 'patch'] as const;\r\nexport type VersionBumpType = (typeof VersionBumpType)[number];\r\n\r\n/**\r\n * Constitution 메타데이터\r\n */\r\nexport const ConstitutionMetadataSchema = z.object({\r\n version: SemanticVersionSchema,\r\n created: z.string(),\r\n updated: z.string().optional(),\r\n});\r\nexport type ConstitutionMetadata = z.infer<typeof ConstitutionMetadataSchema>;\r\n\r\n/**\r\n * 원칙 레벨\r\n */\r\nexport const PrincipleLevelSchema = z.enum(['core', 'technical', 'forbidden']);\r\nexport type PrincipleLevel = z.infer<typeof PrincipleLevelSchema>;\r\n\r\n/**\r\n * 원칙\r\n */\r\nexport const PrincipleSchema = z.object({\r\n id: z.string(),\r\n title: z.string(),\r\n description: z.string(),\r\n level: PrincipleLevelSchema,\r\n rules: z.array(z.string()),\r\n});\r\nexport type Principle = z.infer<typeof PrincipleSchema>;\r\n\r\n/**\r\n * 파싱된 Constitution\r\n */\r\nexport const ParsedConstitutionSchema = z.object({\r\n projectName: z.string(),\r\n metadata: ConstitutionMetadataSchema,\r\n description: z.string().optional(),\r\n principles: z.array(PrincipleSchema),\r\n forbidden: z.array(z.string()),\r\n techStack: z.array(z.string()),\r\n qualityStandards: z.array(z.string()),\r\n rawContent: z.string(),\r\n});\r\nexport type ParsedConstitution = z.infer<typeof ParsedConstitutionSchema>;\r\n\r\n/**\r\n * CHANGELOG 항목 유형\r\n */\r\nexport const ChangeTypeSchema = z.enum(['added', 'changed', 'deprecated', 'removed', 'fixed']);\r\nexport type ChangeType = z.infer<typeof ChangeTypeSchema>;\r\n\r\n/**\r\n * CHANGELOG 항목\r\n */\r\nexport const ChangelogEntrySchema = z.object({\r\n version: SemanticVersionSchema,\r\n date: z.string(),\r\n changes: z.array(z.object({\r\n type: ChangeTypeSchema,\r\n description: z.string(),\r\n })),\r\n reason: z.string().optional(),\r\n});\r\nexport type ChangelogEntry = z.infer<typeof ChangelogEntrySchema>;\r\n\r\n/**\r\n * 버전 파싱\r\n */\r\nexport function parseVersion(version: string): { major: number; minor: number; patch: number } | null {\r\n const match = version.match(/^(\\d+)\\.(\\d+)\\.(\\d+)$/);\r\n if (!match) return null;\r\n return {\r\n major: parseInt(match[1], 10),\r\n minor: parseInt(match[2], 10),\r\n patch: parseInt(match[3], 10),\r\n };\r\n}\r\n\r\n/**\r\n * 버전 범프\r\n */\r\nexport function bumpVersion(version: string, type: VersionBumpType): string {\r\n const parsed = parseVersion(version);\r\n if (!parsed) return '1.0.0';\r\n\r\n switch (type) {\r\n case 'major':\r\n return `${parsed.major + 1}.0.0`;\r\n case 'minor':\r\n return `${parsed.major}.${parsed.minor + 1}.0`;\r\n case 'patch':\r\n return `${parsed.major}.${parsed.minor}.${parsed.patch + 1}`;\r\n }\r\n}\r\n\r\n/**\r\n * 버전 비교 (a > b: 1, a < b: -1, a === b: 0)\r\n */\r\nexport function compareVersions(a: string, b: string): number {\r\n const pa = parseVersion(a);\r\n const pb = parseVersion(b);\r\n\r\n if (!pa || !pb) return 0;\r\n\r\n if (pa.major !== pb.major) return pa.major > pb.major ? 1 : -1;\r\n if (pa.minor !== pb.minor) return pa.minor > pb.minor ? 1 : -1;\r\n if (pa.patch !== pb.patch) return pa.patch > pb.patch ? 1 : -1;\r\n return 0;\r\n}\r\n","/**\r\n * Constitution 파서\r\n */\r\nimport matter from 'gray-matter';\r\nimport {\r\n ParsedConstitution,\r\n ConstitutionMetadataSchema,\r\n Principle,\r\n type ConstitutionMetadata,\r\n} from './schemas.js';\r\nimport { Result, success, failure } from '../../types/index.js';\r\nimport { ValidationError, ErrorCode } from '../../errors/index.js';\r\nimport { extractRfc2119Keywords } from '../spec/schemas.js';\r\n\r\n/**\r\n * Constitution 마크다운 파싱\r\n */\r\nexport function parseConstitution(content: string): Result<ParsedConstitution, ValidationError> {\r\n try {\r\n // 1. Frontmatter 파싱\r\n const { data: rawMeta, content: body } = matter(content);\r\n\r\n // 2. 메타데이터 검증\r\n const metaResult = ConstitutionMetadataSchema.safeParse({\r\n version: rawMeta.version ?? '1.0.0',\r\n created: rawMeta.created ? formatDate(rawMeta.created) : formatDate(new Date()),\r\n updated: rawMeta.updated ? formatDate(rawMeta.updated) : undefined,\r\n });\r\n\r\n if (!metaResult.success) {\r\n const errors = metaResult.error.errors.map((e) => e.message).join(', ');\r\n return failure(new ValidationError(ErrorCode.CONSTITUTION_PARSE_ERROR, `메타데이터 오류: ${errors}`));\r\n }\r\n const metadata: ConstitutionMetadata = metaResult.data;\r\n\r\n // 3. 프로젝트명 추출\r\n const projectMatch = body.match(/^#\\s+Constitution:\\s*(.+)$/m);\r\n if (!projectMatch) {\r\n return failure(new ValidationError(\r\n ErrorCode.CONSTITUTION_PARSE_ERROR,\r\n '프로젝트명을 찾을 수 없습니다 (# Constitution: 프로젝트명)'\r\n ));\r\n }\r\n const projectName = projectMatch[1].trim();\r\n\r\n // 4. 설명 추출\r\n const descMatch = body.match(/^#\\s+Constitution:.+\\n+>\\s*(.+)$/m);\r\n const description = descMatch?.[1]?.trim();\r\n\r\n // 5. 원칙 추출\r\n const principles = parsePrinciples(body);\r\n\r\n // 6. 금지 사항 추출\r\n const forbidden = parseForbidden(body);\r\n\r\n // 7. 기술 스택 추출\r\n const techStack = parseTechStack(body);\r\n\r\n // 8. 품질 기준 추출\r\n const qualityStandards = parseQualityStandards(body);\r\n\r\n return success({\r\n projectName,\r\n metadata,\r\n description,\r\n principles,\r\n forbidden,\r\n techStack,\r\n qualityStandards,\r\n rawContent: content,\r\n });\r\n } catch (error) {\r\n const message = error instanceof Error ? error.message : String(error);\r\n return failure(new ValidationError(ErrorCode.CONSTITUTION_PARSE_ERROR, message));\r\n }\r\n}\r\n\r\n/**\r\n * 날짜 포맷팅\r\n */\r\nfunction formatDate(date: Date | string): string {\r\n if (typeof date === 'string') return date;\r\n return date.toISOString().split('T')[0];\r\n}\r\n\r\n/**\r\n * 원칙 파싱\r\n */\r\nfunction parsePrinciples(content: string): Principle[] {\r\n const principles: Principle[] = [];\r\n\r\n // ## 핵심 원칙 또는 ## 원칙 섹션 찾기\r\n const principlesSectionMatch = content.match(/##\\s+(?:핵심\\s*)?원칙([\\s\\S]*?)(?=\\n##\\s+[^#]|\\n---|\\n$)/i);\r\n if (!principlesSectionMatch) return principles;\r\n\r\n const section = principlesSectionMatch[1];\r\n\r\n // ### N. 원칙명 형태의 섹션을 분리\r\n const sectionParts = section.split(/(?=###\\s+\\d+\\.)/);\r\n\r\n for (const part of sectionParts) {\r\n const headerMatch = part.match(/###\\s+(\\d+)\\.\\s*(.+)/);\r\n if (!headerMatch) continue;\r\n\r\n const id = headerMatch[1];\r\n const title = headerMatch[2].trim();\r\n\r\n // 규칙 추출 (- 로 시작하는 라인)\r\n const rules: string[] = [];\r\n const ruleRegex = /-\\s+(.+)/g;\r\n let ruleMatch: RegExpExecArray | null;\r\n\r\n while ((ruleMatch = ruleRegex.exec(part)) !== null) {\r\n rules.push(ruleMatch[1].trim());\r\n }\r\n\r\n // 레벨 결정\r\n let level: 'core' | 'technical' | 'forbidden' = 'core';\r\n if (title.toLowerCase().includes('기술') || title.toLowerCase().includes('technical')) {\r\n level = 'technical';\r\n }\r\n\r\n principles.push({\r\n id: `P${id}`,\r\n title,\r\n description: title,\r\n level,\r\n rules,\r\n });\r\n }\r\n\r\n return principles;\r\n}\r\n\r\n/**\r\n * 금지 사항 파싱\r\n */\r\nfunction parseForbidden(content: string): string[] {\r\n const forbidden: string[] = [];\r\n\r\n // ## 금지 사항 또는 ## 금지 섹션 찾기\r\n const forbiddenSectionMatch = content.match(/##\\s+금지\\s*(?:사항)?([\\s\\S]*?)(?=\\n##|\\n---|\\n$)/i);\r\n if (!forbiddenSectionMatch) return forbidden;\r\n\r\n const section = forbiddenSectionMatch[1];\r\n\r\n // - 로 시작하는 라인 추출\r\n const ruleRegex = /-\\s+(.+?)(?:\\n|$)/g;\r\n let match: RegExpExecArray | null;\r\n\r\n while ((match = ruleRegex.exec(section)) !== null) {\r\n const rule = match[1].trim();\r\n // SHALL NOT 또는 MUST NOT이 포함된 규칙만\r\n if (/SHALL\\s+NOT|MUST\\s+NOT/i.test(rule)) {\r\n forbidden.push(rule);\r\n }\r\n }\r\n\r\n return forbidden;\r\n}\r\n\r\n/**\r\n * 기술 스택 파싱\r\n */\r\nfunction parseTechStack(content: string): string[] {\r\n const techStack: string[] = [];\r\n\r\n // ## 기술 스택 섹션 찾기\r\n const techSectionMatch = content.match(/##\\s+기술\\s*스택([\\s\\S]*?)(?=\\n##|\\n---|\\n$)/i);\r\n if (!techSectionMatch) return techStack;\r\n\r\n const section = techSectionMatch[1];\r\n\r\n // - Category: Value 형태 추출\r\n const techRegex = /-\\s+(.+?)(?:\\n|$)/g;\r\n let match: RegExpExecArray | null;\r\n\r\n while ((match = techRegex.exec(section)) !== null) {\r\n techStack.push(match[1].trim());\r\n }\r\n\r\n return techStack;\r\n}\r\n\r\n/**\r\n * 품질 기준 파싱\r\n */\r\nfunction parseQualityStandards(content: string): string[] {\r\n const standards: string[] = [];\r\n\r\n // ## 품질 기준 섹션 찾기\r\n const qualitySectionMatch = content.match(/##\\s+품질\\s*기준([\\s\\S]*?)(?=\\n##|\\n---|\\n$)/i);\r\n if (!qualitySectionMatch) return standards;\r\n\r\n const section = qualitySectionMatch[1];\r\n\r\n // - 로 시작하는 라인 추출\r\n const ruleRegex = /-\\s+(.+?)(?:\\n|$)/g;\r\n let match: RegExpExecArray | null;\r\n\r\n while ((match = ruleRegex.exec(section)) !== null) {\r\n standards.push(match[1].trim());\r\n }\r\n\r\n return standards;\r\n}\r\n\r\n/**\r\n * Constitution 검증\r\n */\r\nexport function validateConstitution(constitution: ParsedConstitution): Result<true, ValidationError> {\r\n // 최소 요구사항 검증\r\n if (!constitution.projectName) {\r\n return failure(new ValidationError(\r\n ErrorCode.CONSTITUTION_PARSE_ERROR,\r\n '프로젝트명이 없습니다'\r\n ));\r\n }\r\n\r\n // 원칙이 하나 이상 있어야 함\r\n if (constitution.principles.length === 0 && constitution.forbidden.length === 0) {\r\n return failure(new ValidationError(\r\n ErrorCode.CONSTITUTION_PARSE_ERROR,\r\n '원칙이나 금지 사항이 최소 하나 이상 필요합니다'\r\n ));\r\n }\r\n\r\n return success(true);\r\n}\r\n","/**\r\n * CHANGELOG 관리\r\n */\r\nimport { ChangelogEntry, ChangeType, bumpVersion, type VersionBumpType } from './schemas.js';\r\nimport { Result, success, failure } from '../../types/index.js';\r\nimport { ValidationError, ErrorCode } from '../../errors/index.js';\r\n\r\n/**\r\n * CHANGELOG 헤더\r\n */\r\nconst CHANGELOG_HEADER = `# Constitution Changelog\r\n\r\nAll notable changes to the Constitution will be documented in this file.\r\n\r\n`;\r\n\r\n/**\r\n * CHANGELOG 생성\r\n */\r\nexport function generateChangelog(entries: ChangelogEntry[]): string {\r\n let content = CHANGELOG_HEADER;\r\n\r\n for (const entry of entries) {\r\n content += formatChangelogEntry(entry);\r\n content += '\\n---\\n\\n';\r\n }\r\n\r\n return content;\r\n}\r\n\r\n/**\r\n * CHANGELOG 항목 포맷팅\r\n */\r\nexport function formatChangelogEntry(entry: ChangelogEntry): string {\r\n let content = `## [${entry.version}] - ${entry.date}\\n\\n`;\r\n\r\n // 변경 유형별 그룹화\r\n const grouped: Record<ChangeType, string[]> = {\r\n added: [],\r\n changed: [],\r\n deprecated: [],\r\n removed: [],\r\n fixed: [],\r\n };\r\n\r\n for (const change of entry.changes) {\r\n grouped[change.type].push(change.description);\r\n }\r\n\r\n // 그룹별 출력\r\n const typeLabels: Record<ChangeType, string> = {\r\n added: 'Added',\r\n changed: 'Changed',\r\n deprecated: 'Deprecated',\r\n removed: 'Removed',\r\n fixed: 'Fixed',\r\n };\r\n\r\n for (const [type, items] of Object.entries(grouped)) {\r\n if (items.length > 0) {\r\n content += `### ${typeLabels[type as ChangeType]}\\n`;\r\n for (const item of items) {\r\n content += `- ${item}\\n`;\r\n }\r\n content += '\\n';\r\n }\r\n }\r\n\r\n // 변경 사유\r\n if (entry.reason) {\r\n content += `### Reason\\n- ${entry.reason}\\n\\n`;\r\n }\r\n\r\n return content;\r\n}\r\n\r\n/**\r\n * CHANGELOG 파싱\r\n */\r\nexport function parseChangelog(content: string): Result<ChangelogEntry[], ValidationError> {\r\n const entries: ChangelogEntry[] = [];\r\n\r\n // ## [version] - date 형태 찾기\r\n const entryRegex = /##\\s+\\[(\\d+\\.\\d+\\.\\d+)\\]\\s+-\\s+(\\d{4}-\\d{2}-\\d{2})([\\s\\S]*?)(?=\\n##\\s+\\[|\\n---|\\n$)/g;\r\n let match: RegExpExecArray | null;\r\n\r\n while ((match = entryRegex.exec(content)) !== null) {\r\n const version = match[1];\r\n const date = match[2];\r\n const entryContent = match[3];\r\n\r\n const changes: { type: ChangeType; description: string }[] = [];\r\n let reason: string | undefined;\r\n\r\n // 변경 유형별 파싱\r\n const typeRegex = /###\\s+(Added|Changed|Deprecated|Removed|Fixed|Reason)\\n([\\s\\S]*?)(?=\\n###|\\n##|\\n---|\\n$)/gi;\r\n let typeMatch: RegExpExecArray | null;\r\n\r\n while ((typeMatch = typeRegex.exec(entryContent)) !== null) {\r\n const typeLabel = typeMatch[1].toLowerCase();\r\n const typeContent = typeMatch[2];\r\n\r\n if (typeLabel === 'reason') {\r\n const reasonMatch = typeContent.match(/-\\s+(.+)/);\r\n if (reasonMatch) {\r\n reason = reasonMatch[1].trim();\r\n }\r\n } else {\r\n // 항목 추출\r\n const itemRegex = /-\\s+(.+?)(?:\\n|$)/g;\r\n let itemMatch: RegExpExecArray | null;\r\n\r\n while ((itemMatch = itemRegex.exec(typeContent)) !== null) {\r\n changes.push({\r\n type: typeLabel as ChangeType,\r\n description: itemMatch[1].trim(),\r\n });\r\n }\r\n }\r\n }\r\n\r\n entries.push({ version, date, changes, reason });\r\n }\r\n\r\n return success(entries);\r\n}\r\n\r\n/**\r\n * 새 CHANGELOG 항목 생성\r\n */\r\nexport function createChangelogEntry(\r\n currentVersion: string,\r\n bumpType: VersionBumpType,\r\n changes: { type: ChangeType; description: string }[],\r\n reason?: string\r\n): ChangelogEntry {\r\n const newVersion = bumpVersion(currentVersion, bumpType);\r\n const today = new Date().toISOString().split('T')[0];\r\n\r\n return {\r\n version: newVersion,\r\n date: today,\r\n changes,\r\n reason,\r\n };\r\n}\r\n\r\n/**\r\n * 버전 범프 유형 추천\r\n */\r\nexport function suggestBumpType(changes: { type: ChangeType; description: string }[]): VersionBumpType {\r\n // removed나 breaking change가 있으면 MAJOR\r\n for (const change of changes) {\r\n if (change.type === 'removed') return 'major';\r\n if (change.description.toLowerCase().includes('breaking')) return 'major';\r\n // 기존 규칙 변경도 MAJOR\r\n if (change.type === 'changed' &&\r\n (change.description.includes('→') || change.description.includes('->'))) {\r\n return 'major';\r\n }\r\n }\r\n\r\n // added가 있으면 MINOR\r\n if (changes.some((c) => c.type === 'added')) return 'minor';\r\n\r\n // 그 외 PATCH\r\n return 'patch';\r\n}\r\n","/**\r\n * Constitution 위반 검사 모듈\r\n *\r\n * 스펙 내용이 Constitution 원칙을 위반하는지 검사합니다.\r\n */\r\nimport { ParsedConstitution, Principle, compareVersions } from './schemas.js';\r\nimport { Result, success, failure } from '../../types/index.js';\r\nimport { ValidationError, ErrorCode } from '../../errors/index.js';\r\n\r\n/**\r\n * 위반 심각도\r\n */\r\nexport type ViolationSeverity = 'critical' | 'warning' | 'info';\r\n\r\n/**\r\n * 위반 항목\r\n */\r\nexport interface Violation {\r\n /** 위반 규칙 ID (예: P1, FORBIDDEN-1) */\r\n ruleId: string;\r\n /** 위반 규칙 설명 */\r\n rule: string;\r\n /** 스펙에서 위반한 내용 */\r\n matchedContent: string;\r\n /** 위반된 라인 번호 (1-indexed) */\r\n line?: number;\r\n /** 심각도 */\r\n severity: ViolationSeverity;\r\n /** 설명 */\r\n message: string;\r\n}\r\n\r\n/**\r\n * 버전 불일치 정보\r\n */\r\nexport interface VersionMismatch {\r\n specVersion: string;\r\n constitutionVersion: string;\r\n severity: ViolationSeverity;\r\n message: string;\r\n}\r\n\r\n/**\r\n * Constitution 검증 결과\r\n */\r\nexport interface ConstitutionCheckResult {\r\n /** 검증 통과 여부 */\r\n passed: boolean;\r\n /** 위반 항목 목록 */\r\n violations: Violation[];\r\n /** 버전 불일치 (있는 경우) */\r\n versionMismatch?: VersionMismatch;\r\n /** 검사한 규칙 수 */\r\n rulesChecked: number;\r\n}\r\n\r\n/**\r\n * 금지 키워드 패턴\r\n * Constitution의 금지 사항에서 추출한 키워드를 스펙에서 검색\r\n */\r\ninterface ForbiddenPattern {\r\n /** 원본 금지 규칙 */\r\n rule: string;\r\n /** 검색할 키워드 패턴 */\r\n patterns: string[];\r\n /** 부정적 표현 (이것이 있으면 위반 아님) */\r\n negativePatterns: string[];\r\n}\r\n\r\n/**\r\n * Constitution 위반 검사\r\n */\r\nexport function checkConstitutionViolations(\r\n specContent: string,\r\n specConstitutionVersion: string | undefined,\r\n constitution: ParsedConstitution\r\n): ConstitutionCheckResult {\r\n const violations: Violation[] = [];\r\n let rulesChecked = 0;\r\n\r\n // 1. 버전 불일치 검사\r\n const versionMismatch = checkVersionMismatch(specConstitutionVersion, constitution.metadata.version);\r\n\r\n // 2. 금지 사항 위반 검사\r\n for (let i = 0; i < constitution.forbidden.length; i++) {\r\n const forbiddenRule = constitution.forbidden[i];\r\n rulesChecked++;\r\n\r\n const pattern = extractForbiddenPattern(forbiddenRule);\r\n const violation = checkForbiddenViolation(specContent, pattern, `FORBIDDEN-${i + 1}`);\r\n\r\n if (violation) {\r\n violations.push(violation);\r\n }\r\n }\r\n\r\n // 3. 원칙 위반 검사 (SHALL NOT, MUST NOT 규칙)\r\n for (const principle of constitution.principles) {\r\n for (let i = 0; i < principle.rules.length; i++) {\r\n const rule = principle.rules[i];\r\n rulesChecked++;\r\n\r\n // SHALL NOT 또는 MUST NOT 규칙만 위반 검사\r\n if (/SHALL\\s+NOT|MUST\\s+NOT/i.test(rule)) {\r\n const pattern = extractForbiddenPattern(rule);\r\n const violation = checkForbiddenViolation(\r\n specContent,\r\n pattern,\r\n `${principle.id}-R${i + 1}`\r\n );\r\n\r\n if (violation) {\r\n violations.push(violation);\r\n }\r\n }\r\n }\r\n }\r\n\r\n // 4. 결과 반환\r\n const hasCritical = violations.some((v) => v.severity === 'critical');\r\n const hasVersionIssue = versionMismatch && versionMismatch.severity === 'critical';\r\n\r\n return {\r\n passed: !hasCritical && !hasVersionIssue,\r\n violations,\r\n versionMismatch,\r\n rulesChecked,\r\n };\r\n}\r\n\r\n/**\r\n * 버전 불일치 검사\r\n */\r\nfunction checkVersionMismatch(\r\n specVersion: string | undefined,\r\n constitutionVersion: string\r\n): VersionMismatch | undefined {\r\n // 스펙에 버전이 없으면 경고\r\n if (!specVersion) {\r\n return {\r\n specVersion: '(없음)',\r\n constitutionVersion,\r\n severity: 'warning',\r\n message: `스펙에 constitution_version이 지정되지 않았습니다. 현재 Constitution 버전: ${constitutionVersion}`,\r\n };\r\n }\r\n\r\n // 버전 비교\r\n const comparison = compareVersions(specVersion, constitutionVersion);\r\n\r\n if (comparison < 0) {\r\n // 스펙 버전이 더 낮음 (Constitution이 업데이트됨)\r\n const parsed1 = specVersion.split('.').map(Number);\r\n const parsed2 = constitutionVersion.split('.').map(Number);\r\n\r\n // Major 버전이 다르면 critical\r\n if (parsed1[0] !== parsed2[0]) {\r\n return {\r\n specVersion,\r\n constitutionVersion,\r\n severity: 'critical',\r\n message: `Constitution Major 버전이 변경되었습니다 (${specVersion} → ${constitutionVersion}). 스펙 검토가 필요합니다.`,\r\n };\r\n }\r\n\r\n // Minor 버전이 다르면 warning\r\n if (parsed1[1] !== parsed2[1]) {\r\n return {\r\n specVersion,\r\n constitutionVersion,\r\n severity: 'warning',\r\n message: `Constitution Minor 버전이 변경되었습니다 (${specVersion} → ${constitutionVersion}). 새 원칙을 확인하세요.`,\r\n };\r\n }\r\n\r\n // Patch 버전만 다르면 info\r\n return {\r\n specVersion,\r\n constitutionVersion,\r\n severity: 'info',\r\n message: `Constitution Patch 버전이 변경되었습니다 (${specVersion} → ${constitutionVersion}).`,\r\n };\r\n }\r\n\r\n return undefined;\r\n}\r\n\r\n/**\r\n * 금지 규칙에서 키워드 패턴 추출\r\n */\r\nfunction extractForbiddenPattern(rule: string): ForbiddenPattern {\r\n const patterns: string[] = [];\r\n const negativePatterns: string[] = [];\r\n\r\n // SHALL NOT / MUST NOT 앞뒤의 내용 모두 추출\r\n const forbiddenMatch = rule.match(/(.+?)(?:SHALL\\s+NOT|MUST\\s+NOT)\\s*(.+?)(?:\\(|$)/i);\r\n\r\n if (forbiddenMatch) {\r\n const beforeKeyword = forbiddenMatch[1].trim();\r\n const afterKeyword = forbiddenMatch[2].trim();\r\n\r\n // 앞뒤 모두에서 핵심 키워드 추출\r\n const keywords = [\r\n ...extractKeywords(beforeKeyword),\r\n ...extractKeywords(afterKeyword),\r\n ];\r\n patterns.push(...keywords);\r\n } else {\r\n // 전체 규칙에서 키워드 추출 (폴백)\r\n patterns.push(...extractKeywords(rule));\r\n }\r\n\r\n // 부정적 패턴 (예: \"암호화된\", \"해시된\" 등은 위반이 아님)\r\n const safePatterns = [\r\n '암호화',\r\n '해시',\r\n 'encrypt',\r\n 'hash',\r\n 'bcrypt',\r\n 'argon2',\r\n '보안',\r\n 'secure',\r\n ];\r\n negativePatterns.push(...safePatterns);\r\n\r\n return {\r\n rule,\r\n patterns,\r\n negativePatterns,\r\n };\r\n}\r\n\r\n/**\r\n * 텍스트에서 핵심 키워드 추출\r\n */\r\nfunction extractKeywords(text: string): string[] {\r\n const keywords: string[] = [];\r\n\r\n // 한글 키워드\r\n const koreanKeywords = text.match(/[가-힣]+/g) || [];\r\n keywords.push(...koreanKeywords.filter((k) => k.length >= 2));\r\n\r\n // 영문 키워드\r\n const englishKeywords = text.match(/[a-zA-Z]+/g) || [];\r\n keywords.push(...englishKeywords.filter((k) => k.length >= 3));\r\n\r\n // 불용어 제거\r\n const stopwords = ['을', '를', '이', '가', '는', '은', '에', '의', 'the', 'a', 'an', 'and', 'or', 'not'];\r\n return keywords.filter((k) => !stopwords.includes(k.toLowerCase()));\r\n}\r\n\r\n/**\r\n * 금지 규칙 위반 검사\r\n */\r\nfunction checkForbiddenViolation(\r\n content: string,\r\n pattern: ForbiddenPattern,\r\n ruleId: string\r\n): Violation | null {\r\n const lines = content.split('\\n');\r\n\r\n for (let i = 0; i < lines.length; i++) {\r\n const line = lines[i];\r\n const lineLower = line.toLowerCase();\r\n\r\n // 패턴 매칭\r\n for (const keyword of pattern.patterns) {\r\n const keywordLower = keyword.toLowerCase();\r\n\r\n if (lineLower.includes(keywordLower)) {\r\n // 부정적 패턴 확인 (안전한 표현이 있으면 위반 아님)\r\n const hasSafePattern = pattern.negativePatterns.some((safe) =>\r\n lineLower.includes(safe.toLowerCase())\r\n );\r\n\r\n if (!hasSafePattern) {\r\n return {\r\n ruleId,\r\n rule: pattern.rule,\r\n matchedContent: line.trim(),\r\n line: i + 1,\r\n severity: 'critical',\r\n message: `금지된 내용 발견: \"${keyword}\" - 규칙: ${pattern.rule}`,\r\n };\r\n }\r\n }\r\n }\r\n }\r\n\r\n return null;\r\n}\r\n\r\n/**\r\n * 위반 결과를 보기 좋은 형식으로 변환\r\n */\r\nexport function formatViolationReport(result: ConstitutionCheckResult): string {\r\n const lines: string[] = [];\r\n\r\n lines.push('=== Constitution 위반 검사 결과 ===');\r\n lines.push('');\r\n\r\n if (result.passed) {\r\n lines.push('✅ 검사 통과: 위반 사항 없음');\r\n } else {\r\n lines.push('❌ 검사 실패: 위반 사항 발견');\r\n }\r\n\r\n lines.push(`검사한 규칙 수: ${result.rulesChecked}`);\r\n lines.push('');\r\n\r\n // 버전 불일치\r\n if (result.versionMismatch) {\r\n const vm = result.versionMismatch;\r\n const icon = vm.severity === 'critical' ? '🔴' : vm.severity === 'warning' ? '🟡' : '🔵';\r\n lines.push(`${icon} 버전 불일치`);\r\n lines.push(` 스펙: ${vm.specVersion} → Constitution: ${vm.constitutionVersion}`);\r\n lines.push(` ${vm.message}`);\r\n lines.push('');\r\n }\r\n\r\n // 위반 항목\r\n if (result.violations.length > 0) {\r\n lines.push('--- 위반 항목 ---');\r\n lines.push('');\r\n\r\n for (const v of result.violations) {\r\n const icon = v.severity === 'critical' ? '🔴' : v.severity === 'warning' ? '🟡' : '🔵';\r\n lines.push(`${icon} [${v.ruleId}] ${v.message}`);\r\n if (v.line) {\r\n lines.push(` 라인 ${v.line}: ${v.matchedContent}`);\r\n }\r\n lines.push('');\r\n }\r\n }\r\n\r\n return lines.join('\\n');\r\n}\r\n","/**\r\n * 슬래시 커맨드 프롬프트 템플릿\r\n *\r\n * AI 코딩 도구용 명령어 프롬프트를 제공합니다.\r\n */\r\n\r\n/**\r\n * 형식 규칙 가이드 (공통)\r\n */\r\nexport const FORMAT_GUIDE = `## 형식 규칙 (필수)\r\n\r\n### RFC 2119 키워드\r\n\r\n| 키워드 | 의미 | 사용 예시 |\r\n|--------|------|-----------|\r\n| **SHALL** / **MUST** | 절대 필수 | \"시스템은 인증을 지원해야 한다(SHALL)\" |\r\n| **SHOULD** | 권장 (예외 가능) | \"응답 시간은 1초 이내여야 한다(SHOULD)\" |\r\n| **MAY** | 선택적 | \"다크 모드를 지원할 수 있다(MAY)\" |\r\n| **SHALL NOT** | 절대 금지 | \"평문 비밀번호를 저장해서는 안 된다(SHALL NOT)\" |\r\n\r\n### GIVEN-WHEN-THEN 형식\r\n\r\n모든 요구사항은 아래 형식의 시나리오를 포함해야 합니다:\r\n\r\n\\`\\`\\`markdown\r\n### Scenario: [시나리오명]\r\n\r\n- **GIVEN** [전제 조건]\r\n- **WHEN** [행동/트리거]\r\n- **THEN** [예상 결과]\r\n\\`\\`\\`\r\n`;\r\n\r\n/**\r\n * /sdd:change 프롬프트\r\n */\r\nexport const CHANGE_PROMPT = `# /sdd:change - 변경 제안\r\n\r\n> 기존 스펙에 대한 변경을 제안합니다.\r\n\r\n${FORMAT_GUIDE}\r\n\r\n---\r\n\r\n## 생성 전 체크리스트\r\n\r\n- [ ] 변경 대상 스펙 확인됨\r\n- [ ] 변경 사유가 명확함\r\n- [ ] 영향 범위가 파악됨\r\n\r\n---\r\n\r\n## 생성할 파일\r\n\r\n### 1. proposal.md\r\n\r\n\\`\\`\\`markdown\r\n---\r\nid: CHG-{ID}\r\nstatus: draft\r\ncreated: {TODAY}\r\n---\r\n\r\n# 변경 제안: {TITLE}\r\n\r\n> 변경 목적 및 배경 설명\r\n\r\n---\r\n\r\n## 배경\r\n\r\n왜 이 변경이 필요한가?\r\n\r\n---\r\n\r\n## 영향 범위\r\n\r\n### 영향받는 스펙\r\n\r\n- \\`specs/{SPEC_PATH}\\`\r\n\r\n### 변경 유형\r\n\r\n- [ ] 신규 추가 (ADDED)\r\n- [ ] 수정 (MODIFIED)\r\n- [ ] 삭제 (REMOVED)\r\n\r\n---\r\n\r\n## 변경 내용\r\n\r\n(ADDED/MODIFIED/REMOVED 섹션별 상세 내용)\r\n\r\n---\r\n\r\n## 리스크 평가\r\n\r\n- 영향도: 낮음/중간/높음\r\n- 복잡도: 낮음/중간/높음\r\n\\`\\`\\`\r\n\r\n---\r\n\r\n## 생성 후 확인\r\n\r\n- [ ] \\`sdd validate .sdd/changes/{ID}/proposal.md\\` 실행\r\n- [ ] 델타 형식 확인 (ADDED/MODIFIED/REMOVED)\r\n- [ ] 영향받는 스펙 목록 확인\r\n`;\r\n\r\n/**\r\n * /sdd:apply 프롬프트\r\n */\r\nexport const APPLY_PROMPT = `# /sdd:apply - 변경 적용\r\n\r\n> 승인된 변경 제안을 스펙에 적용합니다.\r\n\r\n---\r\n\r\n## 적용 전 체크리스트\r\n\r\n- [ ] proposal.md 상태가 approved인지 확인\r\n- [ ] delta.md가 존재하는지 확인\r\n- [ ] 영향받는 모든 스펙 파일 확인\r\n\r\n---\r\n\r\n## 적용 프로세스\r\n\r\n1. delta.md에서 변경 내용 추출\r\n2. 영향받는 스펙 파일 수정\r\n - ADDED: 새 섹션 추가\r\n - MODIFIED: 기존 섹션 수정\r\n - REMOVED: 해당 섹션 삭제\r\n3. 스펙 파일 검증\r\n\r\n---\r\n\r\n## 적용 후 확인\r\n\r\n- [ ] \\`sdd validate\\` 실행하여 모든 스펙 검증\r\n- [ ] 변경된 스펙 파일 목록 확인\r\n- [ ] 다음 단계: \\`/sdd:archive\\` 실행\r\n`;\r\n\r\n/**\r\n * /sdd:archive 프롬프트\r\n */\r\nexport const ARCHIVE_PROMPT = `# /sdd:archive - 변경 아카이브\r\n\r\n> 완료된 변경 제안을 아카이브합니다.\r\n\r\n---\r\n\r\n## 아카이브 전 체크리스트\r\n\r\n- [ ] 변경이 스펙에 적용되었는지 확인\r\n- [ ] 모든 테스트가 통과하는지 확인\r\n- [ ] 스펙 검증 통과 확인\r\n\r\n---\r\n\r\n## 아카이브 프로세스\r\n\r\n1. .sdd/changes/{ID}/ 디렉토리를 .sdd/archive/로 이동\r\n2. 아카이브 날짜를 파일명에 추가: {YYYY-MM-DD}-{ID}/\r\n3. proposal.md 상태를 archived로 변경\r\n\r\n---\r\n\r\n## 아카이브 후 확인\r\n\r\n- [ ] .sdd/changes/{ID}/ 디렉토리가 삭제됨\r\n- [ ] .sdd/archive/{DATE}-{ID}/ 디렉토리가 생성됨\r\n- [ ] 아카이브된 proposal.md 상태 확인\r\n`;\r\n\r\n/**\r\n * /sdd:impact 프롬프트\r\n */\r\nexport const IMPACT_PROMPT = `# /sdd:impact - 영향도 분석\r\n\r\n> 스펙 변경 시 관련 스펙 및 코드에 미치는 영향을 분석합니다.\r\n\r\n---\r\n\r\n## 분석 전 체크리스트\r\n\r\n- [ ] 변경할 스펙 식별됨\r\n- [ ] 변경 범위 파악됨\r\n\r\n---\r\n\r\n## 분석 프로세스\r\n\r\n1. 대상 스펙의 의존성 그래프 구축\r\n2. 이 스펙에 의존하는 다른 스펙 식별\r\n3. 영향도 수준 평가 (높음/중간/낮음)\r\n4. 리스크 점수 산출 (1-10)\r\n\r\n---\r\n\r\n## CLI 사용법\r\n\r\n\\`\\`\\`bash\r\n# 특정 기능 영향도 분석\r\nsdd impact <feature-name>\r\n\r\n# 의존성 그래프 출력 (Mermaid)\r\nsdd impact --graph\r\n\r\n# JSON 형식 출력\r\nsdd impact <feature-name> --json\r\n\\`\\`\\`\r\n\r\n---\r\n\r\n## 영향 수준 기준\r\n\r\n| 수준 | 기준 | 표시 |\r\n|------|------|------|\r\n| 높음 | 직접 의존, API 변경 | 🔴 HIGH |\r\n| 중간 | 간접 의존, 데이터 공유 | 🟡 MEDIUM |\r\n| 낮음 | UI 컴포넌트 공유 | 🟢 LOW |\r\n\r\n---\r\n\r\n## 리스크 점수 해석\r\n\r\n- 1-3: 낮은 리스크 - 바로 진행 가능\r\n- 4-6: 중간 리스크 - 검토 권장\r\n- 7-10: 높은 리스크 - 신중한 검토 필요\r\n\r\n---\r\n\r\n## 분석 후 조치\r\n\r\n- 높은 리스크: 관련 팀과 공유, 단계적 마이그레이션 검토\r\n- 중간 리스크: 영향 스펙 테스트 확인\r\n- 낮은 리스크: 표준 프로세스 진행\r\n`;\r\n\r\n/**\r\n * /sdd:new 프롬프트\r\n */\r\nexport const NEW_PROMPT = `# /sdd:new - 신규 기능 명세\r\n\r\n> 새로운 기능의 명세를 작성합니다.\r\n\r\n${FORMAT_GUIDE}\r\n\r\n---\r\n\r\n## 생성 전 체크리스트\r\n\r\n- [ ] 기능 요구사항이 명확히 정의됨\r\n- [ ] 사용자 스토리가 작성됨\r\n- [ ] 관련 이해관계자와 논의 완료\r\n- [ ] 기존 기능과의 충돌 여부 확인\r\n\r\n---\r\n\r\n## 생성할 파일\r\n\r\n### 1. spec.md\r\n\r\n\\`\\`\\`markdown\r\n---\r\nid: {FEATURE_ID}\r\ntitle: \"{TITLE}\"\r\nstatus: draft\r\ncreated: {TODAY}\r\ndepends: null\r\n---\r\n\r\n# {TITLE}\r\n\r\n> {DESCRIPTION}\r\n\r\n---\r\n\r\n## 개요\r\n\r\n{DESCRIPTION}\r\n\r\n---\r\n\r\n## 요구사항\r\n\r\n### REQ-01: [요구사항 제목]\r\n\r\n[요구사항 상세 설명]\r\n- 시스템은 [기능]을 지원해야 한다(SHALL)\r\n\r\n---\r\n\r\n## 시나리오\r\n\r\n### Scenario 1: [시나리오명]\r\n\r\n- **GIVEN** [전제 조건]\r\n- **WHEN** [행동/트리거]\r\n- **THEN** [예상 결과]\r\n\r\n---\r\n\r\n## 비기능 요구사항\r\n\r\n### 성능\r\n- 응답 시간: [N]ms 이내 (SHOULD)\r\n\r\n### 보안\r\n- [보안 요구사항] (SHALL)\r\n\\`\\`\\`\r\n\r\n---\r\n\r\n## CLI 사용법\r\n\r\n\\`\\`\\`bash\r\n# 기본 사용\r\nsdd new <feature-name>\r\n\r\n# 옵션 지정\r\nsdd new <feature-name> --title \"제목\" --description \"설명\"\r\n\r\n# 계획 및 작업도 함께 생성\r\nsdd new <feature-name> --all\r\n\r\n# 브랜치 생성 안 함\r\nsdd new <feature-name> --no-branch\r\n\\`\\`\\`\r\n\r\n---\r\n\r\n## 생성 후 확인\r\n\r\n- [ ] \\`sdd validate .sdd/specs/{FEATURE_ID}/spec.md\\` 실행\r\n- [ ] RFC 2119 키워드 사용 확인\r\n- [ ] GIVEN-WHEN-THEN 시나리오 포함 확인\r\n- [ ] 다음 단계: \\`/sdd:plan\\` 실행\r\n`;\r\n\r\n/**\r\n * /sdd:plan 프롬프트\r\n */\r\nexport const PLAN_PROMPT = `# /sdd:plan - 구현 계획\r\n\r\n> 기능 명세에 대한 구현 계획을 작성합니다.\r\n\r\n---\r\n\r\n## 생성 전 체크리스트\r\n\r\n- [ ] 명세(spec.md)가 검토 완료됨\r\n- [ ] 기술 스택 결정됨\r\n- [ ] 아키텍처 검토 완료\r\n- [ ] 의존성 확인\r\n\r\n---\r\n\r\n## 생성할 파일\r\n\r\n### 1. plan.md\r\n\r\n\\`\\`\\`markdown\r\n---\r\nfeature: {FEATURE_ID}\r\ncreated: {TODAY}\r\nstatus: draft\r\n---\r\n\r\n# 구현 계획: {TITLE}\r\n\r\n> {OVERVIEW}\r\n\r\n---\r\n\r\n## 기술 결정\r\n\r\n### 결정 1: [기술 결정 사항]\r\n\r\n**근거:** [결정 근거]\r\n\r\n**대안 검토:**\r\n- [대안 1]\r\n- [대안 2]\r\n\r\n---\r\n\r\n## 구현 단계\r\n\r\n### Phase 1: 기반 구조\r\n\r\n[기반 구조 설명]\r\n\r\n**산출물:**\r\n- [ ] [산출물 1]\r\n- [ ] [산출물 2]\r\n\r\n### Phase 2: 핵심 기능\r\n\r\n[핵심 기능 설명]\r\n\r\n**산출물:**\r\n- [ ] [산출물 1]\r\n\r\n---\r\n\r\n## 리스크 분석\r\n\r\n| 리스크 | 영향도 | 완화 전략 |\r\n|--------|--------|----------|\r\n| [리스크] | 🟡 MEDIUM | [전략] |\r\n\r\n---\r\n\r\n## 테스트 전략\r\n\r\n- 단위 테스트: 커버리지 80% 이상\r\n- 통합 테스트: API 엔드포인트\r\n- E2E 테스트: 주요 시나리오\r\n\\`\\`\\`\r\n\r\n---\r\n\r\n## CLI 사용법\r\n\r\n\\`\\`\\`bash\r\n# 계획 생성\r\nsdd new plan <feature-id>\r\n\r\n# 제목 지정\r\nsdd new plan <feature-id> --title \"구현 계획\"\r\n\\`\\`\\`\r\n\r\n---\r\n\r\n## 생성 후 확인\r\n\r\n- [ ] 기술 결정 근거 확인\r\n- [ ] 구현 단계 정의\r\n- [ ] 리스크 분석 완료\r\n- [ ] 다음 단계: \\`/sdd:tasks\\` 실행\r\n`;\r\n\r\n/**\r\n * /sdd:tasks 프롬프트\r\n */\r\nexport const TASKS_PROMPT = `# /sdd:tasks - 작업 분해\r\n\r\n> 구현 계획을 실행 가능한 작업으로 분해합니다.\r\n\r\n---\r\n\r\n## 생성 전 체크리스트\r\n\r\n- [ ] 계획(plan.md)이 승인됨\r\n- [ ] 작업 규모가 파악됨\r\n- [ ] 의존성 관계 정의됨\r\n\r\n---\r\n\r\n## 생성할 파일\r\n\r\n### 1. tasks.md\r\n\r\n\\`\\`\\`markdown\r\n---\r\nfeature: {FEATURE_ID}\r\ncreated: {TODAY}\r\ntotal: {N}\r\ncompleted: 0\r\n---\r\n\r\n# 작업 목록: {TITLE}\r\n\r\n> 총 {N}개 작업\r\n\r\n---\r\n\r\n## 진행 상황\r\n\r\n- 대기: {N}\r\n- 진행 중: 0\r\n- 완료: 0\r\n- 차단됨: 0\r\n\r\n---\r\n\r\n## 작업 목록\r\n\r\n### {FEATURE_ID}-task-001: [작업 제목]\r\n\r\n- **상태:** 대기\r\n- **우선순위:** 🔴 HIGH\r\n- **설명:** [작업 설명]\r\n- **관련 파일:**\r\n - \\`src/path/to/file.ts\\`\r\n- **의존성:** 없음\r\n\r\n### {FEATURE_ID}-task-002: [작업 제목]\r\n\r\n- **상태:** 대기\r\n- **우선순위:** 🟡 MEDIUM\r\n- **의존성:** {FEATURE_ID}-task-001\r\n\\`\\`\\`\r\n\r\n---\r\n\r\n## CLI 사용법\r\n\r\n\\`\\`\\`bash\r\n# 작업 분해 생성\r\nsdd new tasks <feature-id>\r\n\\`\\`\\`\r\n\r\n---\r\n\r\n## 작업 완료 조건\r\n\r\n각 작업 완료 시:\r\n1. [ ] 코드 작성 완료\r\n2. [ ] 테스트 작성 및 통과\r\n3. [ ] 코드 리뷰 완료\r\n4. [ ] 문서 업데이트\r\n\r\n---\r\n\r\n## 다음 단계\r\n\r\n1. 첫 번째 작업부터 순차적으로 진행\r\n2. 각 작업 완료 후 상태 업데이트\r\n3. 모든 작업 완료 시 \\`/sdd:archive\\` 실행\r\n`;\r\n\r\n/**\r\n * /sdd:validate 프롬프트\r\n */\r\nexport const VALIDATE_PROMPT = `# /sdd:validate - 스펙 검증\r\n\r\n> 스펙 파일의 형식과 내용을 검증합니다.\r\n\r\n---\r\n\r\n## 검증 대상\r\n\r\n- .sdd/specs/ 디렉토리의 모든 스펙 파일\r\n- .sdd/changes/ 디렉토리의 모든 변경 제안\r\n\r\n---\r\n\r\n## 검증 항목\r\n\r\n### 필수 형식\r\n\r\n1. YAML frontmatter 존재\r\n - status: draft | active | deprecated\r\n - created: YYYY-MM-DD\r\n - depends: null | [spec-id, ...]\r\n\r\n2. RFC 2119 키워드 사용\r\n - SHALL, MUST, SHOULD, MAY, SHALL NOT\r\n\r\n3. GIVEN-WHEN-THEN 시나리오\r\n - 모든 Requirement에 최소 1개 Scenario\r\n\r\n---\r\n\r\n## CLI 사용법\r\n\r\n\\`\\`\\`bash\r\n# 전체 검증\r\nsdd validate\r\n\r\n# 특정 경로 검증\r\nsdd validate .sdd/specs/feature/spec.md\r\n\r\n# 엄격 모드 (경고도 에러로 처리)\r\nsdd validate --strict\r\n\r\n# 조용한 모드\r\nsdd validate --quiet\r\n\\`\\`\\`\r\n\r\n---\r\n\r\n## 검증 결과\r\n\r\n- ✅ PASS: 모든 검증 통과\r\n- ⚠️ WARN: 경고 (--strict에서 실패)\r\n- ❌ FAIL: 필수 항목 누락\r\n`;\r\n\r\n/**\r\n * 모든 프롬프트 맵\r\n */\r\nexport const PROMPTS: Record<string, string> = {\r\n change: CHANGE_PROMPT,\r\n apply: APPLY_PROMPT,\r\n archive: ARCHIVE_PROMPT,\r\n impact: IMPACT_PROMPT,\r\n validate: VALIDATE_PROMPT,\r\n new: NEW_PROMPT,\r\n plan: PLAN_PROMPT,\r\n tasks: TASKS_PROMPT,\r\n};\r\n\r\n/**\r\n * 프롬프트 가져오기\r\n */\r\nexport function getPrompt(command: string): string | undefined {\r\n return PROMPTS[command];\r\n}\r\n\r\n/**\r\n * 사용 가능한 명령어 목록\r\n */\r\nexport function getAvailableCommands(): string[] {\r\n return Object.keys(PROMPTS);\r\n}\r\n","/**\r\n * sdd prompt 명령어\r\n *\r\n * AI 코딩 도구용 슬래시 커맨드 프롬프트를 출력합니다.\r\n */\r\nimport { Command } from 'commander';\r\nimport { getPrompt, getAvailableCommands } from '../../prompts/index.js';\r\nimport * as logger from '../../utils/logger.js';\r\nimport { ExitCode } from '../../errors/index.js';\r\n\r\n/**\r\n * prompt 명령어 등록\r\n */\r\nexport function registerPromptCommand(program: Command): void {\r\n program\r\n .command('prompt [command]')\r\n .description('슬래시 커맨드 프롬프트를 출력합니다')\r\n .option('-l, --list', '사용 가능한 명령어 목록')\r\n .action(async (command: string | undefined, options: { list?: boolean }) => {\r\n try {\r\n await runPrompt(command, options);\r\n } catch (error) {\r\n logger.error(error instanceof Error ? error.message : String(error));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n });\r\n}\r\n\r\n/**\r\n * 프롬프트 실행\r\n */\r\nasync function runPrompt(\r\n command: string | undefined,\r\n options: { list?: boolean }\r\n): Promise<void> {\r\n // 목록 출력\r\n if (options.list || !command) {\r\n const commands = getAvailableCommands();\r\n logger.info('사용 가능한 슬래시 커맨드:');\r\n logger.newline();\r\n for (const cmd of commands) {\r\n logger.listItem(`/sdd:${cmd}`);\r\n }\r\n logger.newline();\r\n logger.info('사용법: sdd prompt <command>');\r\n logger.info('예시: sdd prompt change');\r\n return;\r\n }\r\n\r\n // 프롬프트 출력\r\n const prompt = getPrompt(command);\r\n if (!prompt) {\r\n logger.error(`알 수 없는 명령어: ${command}`);\r\n logger.info('사용 가능한 명령어: ' + getAvailableCommands().join(', '));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n // 프롬프트 출력 (마크다운)\r\n console.log(prompt);\r\n}\r\n","/**\r\n * sdd change 명령어\r\n *\r\n * 변경 제안 워크플로우를 관리합니다.\r\n */\r\nimport { Command } from 'commander';\r\nimport path from 'node:path';\r\nimport { promises as fs } from 'node:fs';\r\nimport {\r\n generateProposal,\r\n generateDelta,\r\n parseProposal,\r\n parseDelta,\r\n validateDelta,\r\n updateProposalStatus,\r\n listPendingChanges,\r\n archiveChange,\r\n generateChangeId,\r\n} from '../../core/change/index.js';\r\nimport { findSddRoot, directoryExists, ensureDir, writeFile, readFile, fileExists } from '../../utils/fs.js';\r\nimport * as logger from '../../utils/logger.js';\r\nimport { ExitCode } from '../../errors/index.js';\r\n\r\n/**\r\n * change 명령어 등록\r\n */\r\nexport function registerChangeCommand(program: Command): void {\r\n const change = program\r\n .command('change [id]')\r\n .description('변경 제안을 생성하거나 관리합니다')\r\n .option('-l, --list', '진행 중인 변경 목록')\r\n .option('-t, --title <title>', '변경 제안 제목')\r\n .option('-s, --spec <spec>', '대상 스펙 경로')\r\n .action(async (id: string | undefined, options: {\r\n list?: boolean;\r\n title?: string;\r\n spec?: string;\r\n }) => {\r\n try {\r\n await runChange(id, options);\r\n } catch (error) {\r\n logger.error(error instanceof Error ? error.message : String(error));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n });\r\n\r\n // apply 서브커맨드\r\n change\r\n .command('apply <id>')\r\n .description('변경 제안을 스펙에 적용합니다')\r\n .action(async (id: string) => {\r\n try {\r\n await runApply(id);\r\n } catch (error) {\r\n logger.error(error instanceof Error ? error.message : String(error));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n });\r\n\r\n // archive 서브커맨드\r\n change\r\n .command('archive <id>')\r\n .description('완료된 변경을 아카이브합니다')\r\n .action(async (id: string) => {\r\n try {\r\n await runArchive(id);\r\n } catch (error) {\r\n logger.error(error instanceof Error ? error.message : String(error));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n });\r\n\r\n // diff 서브커맨드\r\n change\r\n .command('diff <id>')\r\n .description('변경 제안의 diff를 표시합니다')\r\n .action(async (id: string) => {\r\n try {\r\n await runDiff(id);\r\n } catch (error) {\r\n logger.error(error instanceof Error ? error.message : String(error));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n });\r\n\r\n // validate 서브커맨드\r\n change\r\n .command('validate <id>')\r\n .description('변경 제안의 유효성을 검증합니다')\r\n .action(async (id: string) => {\r\n try {\r\n await runValidateChange(id);\r\n } catch (error) {\r\n logger.error(error instanceof Error ? error.message : String(error));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n });\r\n}\r\n\r\n/**\r\n * 변경 제안 생성/조회\r\n */\r\nasync function runChange(\r\n id: string | undefined,\r\n options: { list?: boolean; title?: string; spec?: string }\r\n): Promise<void> {\r\n const projectRoot = await findSddRoot();\r\n if (!projectRoot) {\r\n logger.error('SDD 프로젝트를 찾을 수 없습니다. `sdd init`을 먼저 실행하세요.');\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n const sddPath = path.join(projectRoot, '.sdd');\r\n\r\n // 목록 출력\r\n if (options.list) {\r\n const result = await listPendingChanges(sddPath);\r\n if (!result.success) {\r\n logger.error(result.error.message);\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n if (result.data.length === 0) {\r\n logger.info('진행 중인 변경이 없습니다.');\r\n return;\r\n }\r\n\r\n logger.info('진행 중인 변경:');\r\n logger.newline();\r\n for (const change of result.data) {\r\n const statusIcon = change.status === 'approved' ? '✓' : '○';\r\n logger.listItem(`${statusIcon} ${change.id}: ${change.title || '(제목 없음)'} [${change.status}]`);\r\n }\r\n return;\r\n }\r\n\r\n // 기존 변경 조회\r\n if (id) {\r\n const changePath = path.join(sddPath, 'changes', id);\r\n if (!(await directoryExists(changePath))) {\r\n logger.error(`변경을 찾을 수 없습니다: ${id}`);\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n const proposalPath = path.join(changePath, 'proposal.md');\r\n try {\r\n const content = await fs.readFile(proposalPath, 'utf-8');\r\n const parseResult = parseProposal(content);\r\n if (parseResult.success) {\r\n logger.info(`변경 제안: ${parseResult.data.title}`);\r\n logger.info(`상태: ${parseResult.data.metadata.status}`);\r\n logger.info(`생성: ${parseResult.data.metadata.created}`);\r\n if (parseResult.data.affectedSpecs.length > 0) {\r\n logger.info('영향 스펙:');\r\n parseResult.data.affectedSpecs.forEach((spec) => logger.listItem(spec, 1));\r\n }\r\n }\r\n } catch {\r\n logger.error('proposal.md를 읽을 수 없습니다.');\r\n }\r\n return;\r\n }\r\n\r\n // 새 변경 생성\r\n const changesPath = path.join(sddPath, 'changes');\r\n await ensureDir(changesPath);\r\n\r\n // 기존 ID 수집\r\n const existingIds: string[] = [];\r\n try {\r\n const dirs = await fs.readdir(changesPath);\r\n existingIds.push(...dirs.filter((d) => d.startsWith('CHG-')));\r\n } catch {\r\n // 디렉토리가 없을 수 있음\r\n }\r\n\r\n const newId = generateChangeId(existingIds);\r\n const title = options.title || '새 변경 제안';\r\n const affectedSpecs = options.spec ? [options.spec] : [];\r\n\r\n const changePath = path.join(changesPath, newId);\r\n await ensureDir(changePath);\r\n\r\n // proposal.md 생성\r\n const proposal = generateProposal({\r\n id: newId,\r\n title,\r\n affectedSpecs,\r\n });\r\n await writeFile(path.join(changePath, 'proposal.md'), proposal);\r\n\r\n // delta.md 생성\r\n const delta = generateDelta({\r\n proposalId: newId,\r\n title,\r\n });\r\n await writeFile(path.join(changePath, 'delta.md'), delta);\r\n\r\n logger.success(`변경 제안이 생성되었습니다: ${newId}`);\r\n logger.newline();\r\n logger.info('생성된 파일:');\r\n logger.listItem(`.sdd/changes/${newId}/proposal.md`);\r\n logger.listItem(`.sdd/changes/${newId}/delta.md`);\r\n logger.newline();\r\n logger.info('다음 단계:');\r\n logger.listItem('proposal.md를 수정하여 변경 내용을 작성하세요');\r\n logger.listItem('delta.md에 ADDED/MODIFIED/REMOVED를 작성하세요');\r\n logger.listItem(`\\`sdd change apply ${newId}\\`로 적용하세요`);\r\n}\r\n\r\n/**\r\n * 변경 적용\r\n */\r\nasync function runApply(id: string): Promise<void> {\r\n const projectRoot = await findSddRoot();\r\n if (!projectRoot) {\r\n logger.error('SDD 프로젝트를 찾을 수 없습니다.');\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n const sddPath = path.join(projectRoot, '.sdd');\r\n const changePath = path.join(sddPath, 'changes', id);\r\n\r\n if (!(await directoryExists(changePath))) {\r\n logger.error(`변경을 찾을 수 없습니다: ${id}`);\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n // proposal.md 상태 업데이트\r\n const proposalPath = path.join(changePath, 'proposal.md');\r\n try {\r\n const content = await fs.readFile(proposalPath, 'utf-8');\r\n const updateResult = updateProposalStatus(content, 'applied');\r\n if (updateResult.success) {\r\n await fs.writeFile(proposalPath, updateResult.data);\r\n }\r\n } catch {\r\n logger.error('proposal.md를 업데이트할 수 없습니다.');\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n logger.success(`변경이 적용 상태로 변경되었습니다: ${id}`);\r\n logger.newline();\r\n logger.info('다음 단계:');\r\n logger.listItem('delta.md를 참조하여 스펙을 수정하세요');\r\n logger.listItem('구현이 완료되면 `sdd change archive ${id}`를 실행하세요');\r\n}\r\n\r\n/**\r\n * 변경 아카이브\r\n */\r\nasync function runArchive(id: string): Promise<void> {\r\n const projectRoot = await findSddRoot();\r\n if (!projectRoot) {\r\n logger.error('SDD 프로젝트를 찾을 수 없습니다.');\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n const sddPath = path.join(projectRoot, '.sdd');\r\n const result = await archiveChange(sddPath, id);\r\n\r\n if (!result.success) {\r\n logger.error(result.error.message);\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n logger.success(`변경이 아카이브되었습니다: ${id}`);\r\n logger.info(`위치: ${result.data.archiveDir}`);\r\n}\r\n\r\n/**\r\n * 변경 diff 표시\r\n */\r\nasync function runDiff(id: string): Promise<void> {\r\n const projectRoot = await findSddRoot();\r\n if (!projectRoot) {\r\n logger.error('SDD 프로젝트를 찾을 수 없습니다.');\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n const sddPath = path.join(projectRoot, '.sdd');\r\n const changePath = path.join(sddPath, 'changes', id);\r\n\r\n if (!(await directoryExists(changePath))) {\r\n logger.error(`변경을 찾을 수 없습니다: ${id}`);\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n const deltaPath = path.join(changePath, 'delta.md');\r\n if (!(await fileExists(deltaPath))) {\r\n logger.error('delta.md를 찾을 수 없습니다.');\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n const deltaResult = await readFile(deltaPath);\r\n if (!deltaResult.success) {\r\n logger.error('delta.md를 읽을 수 없습니다.');\r\n process.exit(ExitCode.FILE_SYSTEM_ERROR);\r\n }\r\n\r\n const parseResult = parseDelta(deltaResult.data);\r\n if (!parseResult.success) {\r\n logger.error(`Delta 파싱 실패: ${parseResult.error.message}`);\r\n process.exit(ExitCode.VALIDATION_ERROR);\r\n }\r\n\r\n const delta = parseResult.data;\r\n\r\n logger.info(`변경 Diff: ${id}`);\r\n logger.newline();\r\n\r\n // ADDED\r\n if (delta.added.length > 0 && delta.added[0].content !== '(추가되는 스펙 내용)') {\r\n logger.info('📗 ADDED:');\r\n for (const item of delta.added) {\r\n console.log(` + ${item.content.split('\\n')[0]}...`);\r\n }\r\n logger.newline();\r\n }\r\n\r\n // MODIFIED\r\n if (delta.modified.length > 0) {\r\n logger.info('📘 MODIFIED:');\r\n for (const item of delta.modified) {\r\n if (item.before && item.after) {\r\n logger.info(' Before:');\r\n for (const line of item.before.split('\\n').slice(0, 3)) {\r\n console.log(` - ${line}`);\r\n }\r\n logger.info(' After:');\r\n for (const line of item.after.split('\\n').slice(0, 3)) {\r\n console.log(` + ${line}`);\r\n }\r\n } else {\r\n console.log(` ~ ${item.content.split('\\n')[0]}...`);\r\n }\r\n }\r\n logger.newline();\r\n }\r\n\r\n // REMOVED\r\n if (delta.removed.length > 0 && delta.removed[0].content !== '(삭제되는 스펙 참조)') {\r\n logger.info('📕 REMOVED:');\r\n for (const item of delta.removed) {\r\n console.log(` - ${item.content.split('\\n')[0]}...`);\r\n }\r\n logger.newline();\r\n }\r\n}\r\n\r\n/**\r\n * 변경 제안 유효성 검증\r\n */\r\nasync function runValidateChange(id: string): Promise<void> {\r\n const projectRoot = await findSddRoot();\r\n if (!projectRoot) {\r\n logger.error('SDD 프로젝트를 찾을 수 없습니다.');\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n const sddPath = path.join(projectRoot, '.sdd');\r\n const changePath = path.join(sddPath, 'changes', id);\r\n\r\n if (!(await directoryExists(changePath))) {\r\n logger.error(`변경을 찾을 수 없습니다: ${id}`);\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n let hasErrors = false;\r\n\r\n // Proposal 검증\r\n const proposalPath = path.join(changePath, 'proposal.md');\r\n if (await fileExists(proposalPath)) {\r\n const proposalResult = await readFile(proposalPath);\r\n if (proposalResult.success) {\r\n const parsed = parseProposal(proposalResult.data);\r\n if (parsed.success) {\r\n logger.success(`✓ proposal.md 유효 (${parsed.data.title})`);\r\n } else {\r\n logger.error(`✗ proposal.md 오류: ${parsed.error.message}`);\r\n hasErrors = true;\r\n }\r\n }\r\n } else {\r\n logger.error('✗ proposal.md가 없습니다.');\r\n hasErrors = true;\r\n }\r\n\r\n // Delta 검증\r\n const deltaPath = path.join(changePath, 'delta.md');\r\n if (await fileExists(deltaPath)) {\r\n const deltaResult = await readFile(deltaPath);\r\n if (deltaResult.success) {\r\n const validation = validateDelta(deltaResult.data);\r\n if (validation.valid) {\r\n const types = [];\r\n if (validation.hasAdded) types.push('ADDED');\r\n if (validation.hasModified) types.push('MODIFIED');\r\n if (validation.hasRemoved) types.push('REMOVED');\r\n logger.success(`✓ delta.md 유효 (${types.join(', ')})`);\r\n\r\n for (const warning of validation.warnings) {\r\n logger.warn(` ⚠ ${warning}`);\r\n }\r\n } else {\r\n logger.error(`✗ delta.md 오류:`);\r\n for (const error of validation.errors) {\r\n logger.error(` - ${error}`);\r\n }\r\n hasErrors = true;\r\n }\r\n }\r\n } else {\r\n logger.warn('⚠ delta.md가 없습니다.');\r\n }\r\n\r\n logger.newline();\r\n if (hasErrors) {\r\n logger.error(`검증 실패: ${id}`);\r\n process.exit(ExitCode.VALIDATION_ERROR);\r\n } else {\r\n logger.success(`검증 통과: ${id}`);\r\n }\r\n}\r\n","/**\r\n * 변경 제안 스키마\r\n */\r\nimport { z } from 'zod';\r\n\r\n/**\r\n * 변경 상태\r\n */\r\nexport const ChangeStatusSchema = z.enum([\r\n 'draft',\r\n 'proposed',\r\n 'approved',\r\n 'applied',\r\n 'archived',\r\n 'rejected',\r\n]);\r\n\r\nexport type ChangeStatus = z.infer<typeof ChangeStatusSchema>;\r\n\r\n/**\r\n * 변경 유형\r\n */\r\nexport const DeltaTypeSchema = z.enum(['ADDED', 'MODIFIED', 'REMOVED']);\r\n\r\nexport type DeltaType = z.infer<typeof DeltaTypeSchema>;\r\n\r\n/**\r\n * 영향도 수준\r\n */\r\nexport const ImpactLevelSchema = z.enum(['low', 'medium', 'high']);\r\n\r\nexport type ImpactLevel = z.infer<typeof ImpactLevelSchema>;\r\n\r\n/**\r\n * Proposal 메타데이터 스키마\r\n */\r\nexport const ProposalMetadataSchema = z.object({\r\n id: z.string().regex(/^CHG-\\d{3,}$/, 'ID 형식: CHG-XXX'),\r\n status: ChangeStatusSchema,\r\n created: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/, '날짜 형식: YYYY-MM-DD'),\r\n updated: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/).optional(),\r\n target: z.string().optional(),\r\n});\r\n\r\nexport type ProposalMetadata = z.infer<typeof ProposalMetadataSchema>;\r\n\r\n/**\r\n * 델타 항목 스키마\r\n */\r\nexport const DeltaItemSchema = z.object({\r\n type: DeltaTypeSchema,\r\n target: z.string(),\r\n before: z.string().optional(),\r\n after: z.string().optional(),\r\n description: z.string().optional(),\r\n});\r\n\r\nexport type DeltaItem = z.infer<typeof DeltaItemSchema>;\r\n\r\n/**\r\n * 델타 메타데이터 스키마\r\n */\r\nexport const DeltaMetadataSchema = z.object({\r\n proposal: z.string(),\r\n created: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/),\r\n});\r\n\r\nexport type DeltaMetadata = z.infer<typeof DeltaMetadataSchema>;\r\n\r\n/**\r\n * 변경 제안 전체 스키마\r\n */\r\nexport const ProposalSchema = z.object({\r\n metadata: ProposalMetadataSchema,\r\n title: z.string(),\r\n rationale: z.string().optional(),\r\n affectedSpecs: z.array(z.string()),\r\n changeType: z.array(DeltaTypeSchema),\r\n summary: z.string().optional(),\r\n riskLevel: ImpactLevelSchema.optional(),\r\n complexity: ImpactLevelSchema.optional(),\r\n});\r\n\r\nexport type Proposal = z.infer<typeof ProposalSchema>;\r\n\r\n/**\r\n * 델타 전체 스키마\r\n */\r\nexport const DeltaSchema = z.object({\r\n metadata: DeltaMetadataSchema,\r\n title: z.string(),\r\n added: z.array(z.string()).optional(),\r\n modified: z.array(\r\n z.object({\r\n target: z.string(),\r\n before: z.string(),\r\n after: z.string(),\r\n })\r\n ).optional(),\r\n removed: z.array(z.string()).optional(),\r\n});\r\n\r\nexport type Delta = z.infer<typeof DeltaSchema>;\r\n\r\n/**\r\n * 다음 변경 ID 생성\r\n */\r\nexport function generateChangeId(existingIds: string[]): string {\r\n const maxId = existingIds\r\n .map((id) => {\r\n const match = id.match(/^CHG-(\\d+)$/);\r\n return match ? parseInt(match[1], 10) : 0;\r\n })\r\n .reduce((max, curr) => Math.max(max, curr), 0);\r\n\r\n return `CHG-${String(maxId + 1).padStart(3, '0')}`;\r\n}\r\n","/**\r\n * Proposal 파서 및 생성기\r\n */\r\nimport matter from 'gray-matter';\r\nimport { z } from 'zod';\r\nimport {\r\n ProposalMetadataSchema,\r\n Proposal,\r\n ChangeStatus,\r\n DeltaType,\r\n ImpactLevel,\r\n generateChangeId,\r\n} from './schemas.js';\r\nimport { success, failure, Result } from '../../types/index.js';\r\nimport { ChangeError } from '../../errors/index.js';\r\n\r\n/**\r\n * Proposal 파싱 결과\r\n */\r\nexport interface ParsedProposal {\r\n metadata: {\r\n id: string;\r\n status: ChangeStatus;\r\n created: string;\r\n updated?: string;\r\n target?: string;\r\n };\r\n title: string;\r\n rationale: string;\r\n affectedSpecs: string[];\r\n changeType: DeltaType[];\r\n summary: string;\r\n riskLevel: ImpactLevel;\r\n complexity: ImpactLevel;\r\n rawContent: string;\r\n}\r\n\r\n/**\r\n * Proposal 메타데이터 전처리\r\n */\r\nconst PreprocessedProposalMetadataSchema = z.object({\r\n id: z.string().regex(/^CHG-\\d{3,}$/, 'ID 형식: CHG-XXX'),\r\n status: z.preprocess(\r\n (val) => (typeof val === 'string' ? val : 'draft'),\r\n z.enum(['draft', 'proposed', 'approved', 'applied', 'archived', 'rejected'])\r\n ),\r\n created: z.preprocess(\r\n (val) => {\r\n if (val instanceof Date) {\r\n return val.toISOString().split('T')[0];\r\n }\r\n return val;\r\n },\r\n z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/, '날짜 형식: YYYY-MM-DD')\r\n ),\r\n updated: z.preprocess(\r\n (val) => {\r\n if (val instanceof Date) {\r\n return val.toISOString().split('T')[0];\r\n }\r\n return val;\r\n },\r\n z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/).optional()\r\n ),\r\n target: z.string().optional(),\r\n});\r\n\r\n/**\r\n * Proposal 파싱\r\n */\r\nexport function parseProposal(content: string): Result<ParsedProposal, ChangeError> {\r\n try {\r\n const { data: frontmatter, content: body } = matter(content);\r\n\r\n // 메타데이터 검증\r\n const metadataResult = PreprocessedProposalMetadataSchema.safeParse(frontmatter);\r\n if (!metadataResult.success) {\r\n return failure(\r\n new ChangeError(`Proposal 메타데이터 오류: ${metadataResult.error.message}`)\r\n );\r\n }\r\n\r\n // 제목 추출 (첫 번째 # 헤더)\r\n const titleMatch = body.match(/^#\\s+(?:변경\\s+제안:\\s*)?(.+)$/m);\r\n const title = titleMatch?.[1]?.trim() || '';\r\n\r\n // 배경/이유 추출\r\n const rationaleMatch = body.match(/##\\s*배경\\s*([\\s\\S]*?)(?=\\n##|$)/i);\r\n const rationale = rationaleMatch?.[1]?.trim() || '';\r\n\r\n // 영향받는 스펙 추출\r\n const specsMatch = body.match(/##\\s*영향\\s*범위[\\s\\S]*?영향받는\\s*스펙\\s*([\\s\\S]*?)(?=\\n###|\\n##|$)/i);\r\n const affectedSpecs: string[] = [];\r\n if (specsMatch) {\r\n const specLines = specsMatch[1].match(/`([^`]+)`/g);\r\n if (specLines) {\r\n specLines.forEach((line) => {\r\n affectedSpecs.push(line.replace(/`/g, ''));\r\n });\r\n }\r\n }\r\n\r\n // 변경 유형 추출\r\n const changeType: DeltaType[] = [];\r\n if (body.includes('[x] 신규 추가') || body.includes('[X] 신규 추가')) {\r\n changeType.push('ADDED');\r\n }\r\n if (body.includes('[x] 수정') || body.includes('[X] 수정')) {\r\n changeType.push('MODIFIED');\r\n }\r\n if (body.includes('[x] 삭제') || body.includes('[X] 삭제')) {\r\n changeType.push('REMOVED');\r\n }\r\n\r\n // 변경 내용 요약 추출\r\n const summaryMatch = body.match(/##\\s*변경\\s*내용\\s*([\\s\\S]*?)(?=\\n##|$)/i);\r\n const summary = summaryMatch?.[1]?.trim() || '';\r\n\r\n // 리스크 평가 추출\r\n const riskMatch = body.match(/영향도:\\s*(낮음|중간|높음)/i);\r\n const riskLevel: ImpactLevel = riskMatch\r\n ? (riskMatch[1] === '낮음' ? 'low' : riskMatch[1] === '높음' ? 'high' : 'medium')\r\n : 'medium';\r\n\r\n const complexityMatch = body.match(/복잡도:\\s*(낮음|중간|높음)/i);\r\n const complexity: ImpactLevel = complexityMatch\r\n ? (complexityMatch[1] === '낮음' ? 'low' : complexityMatch[1] === '높음' ? 'high' : 'medium')\r\n : 'medium';\r\n\r\n return success({\r\n metadata: metadataResult.data,\r\n title,\r\n rationale,\r\n affectedSpecs,\r\n changeType,\r\n summary,\r\n riskLevel,\r\n complexity,\r\n rawContent: body,\r\n });\r\n } catch (error) {\r\n return failure(\r\n new ChangeError(\r\n `Proposal 파싱 실패: ${error instanceof Error ? error.message : String(error)}`\r\n )\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Proposal 생성 옵션\r\n */\r\nexport interface GenerateProposalOptions {\r\n id: string;\r\n title: string;\r\n rationale?: string;\r\n affectedSpecs?: string[];\r\n changeType?: DeltaType[];\r\n}\r\n\r\n/**\r\n * Proposal 템플릿 생성\r\n */\r\nexport function generateProposal(options: GenerateProposalOptions): string {\r\n const today = new Date().toISOString().split('T')[0];\r\n const specs = options.affectedSpecs || [];\r\n const types = options.changeType || ['MODIFIED'];\r\n\r\n return `---\r\nid: ${options.id}\r\nstatus: draft\r\ncreated: ${today}\r\n---\r\n\r\n# 변경 제안: ${options.title}\r\n\r\n> ${options.rationale || '변경 목적 및 배경 설명'}\r\n\r\n---\r\n\r\n## 배경\r\n\r\n${options.rationale || '왜 이 변경이 필요한가?'}\r\n\r\n---\r\n\r\n## 영향 범위\r\n\r\n### 영향받는 스펙\r\n\r\n${specs.length > 0 ? specs.map((s) => `- \\`${s}\\``).join('\\n') : '- `specs/{{SPEC_PATH}}`'}\r\n\r\n### 변경 유형\r\n\r\n- [${types.includes('ADDED') ? 'x' : ' '}] 신규 추가 (ADDED)\r\n- [${types.includes('MODIFIED') ? 'x' : ' '}] 수정 (MODIFIED)\r\n- [${types.includes('REMOVED') ? 'x' : ' '}] 삭제 (REMOVED)\r\n\r\n---\r\n\r\n## 변경 내용\r\n\r\n### ADDED\r\n\r\n(새로 추가되는 내용)\r\n\r\n### MODIFIED\r\n\r\n#### Before\r\n\r\n\\`\\`\\`markdown\r\n기존 내용\r\n\\`\\`\\`\r\n\r\n#### After\r\n\r\n\\`\\`\\`markdown\r\n변경된 내용\r\n\\`\\`\\`\r\n\r\n### REMOVED\r\n\r\n(삭제되는 내용)\r\n\r\n---\r\n\r\n## 리스크 평가\r\n\r\n- 영향도: 중간\r\n- 복잡도: 중간\r\n`;\r\n}\r\n\r\n/**\r\n * Proposal 상태 업데이트\r\n */\r\nexport function updateProposalStatus(\r\n content: string,\r\n newStatus: ChangeStatus\r\n): Result<string, ChangeError> {\r\n try {\r\n const { data: frontmatter, content: body } = matter(content);\r\n const today = new Date().toISOString().split('T')[0];\r\n\r\n const updatedFrontmatter = {\r\n ...frontmatter,\r\n status: newStatus,\r\n updated: today,\r\n };\r\n\r\n return success(matter.stringify(body, updatedFrontmatter));\r\n } catch (error) {\r\n return failure(\r\n new ChangeError(\r\n `상태 업데이트 실패: ${error instanceof Error ? error.message : String(error)}`\r\n )\r\n );\r\n }\r\n}\r\n","/**\r\n * Delta 파서 및 생성기\r\n */\r\nimport matter from 'gray-matter';\r\nimport { z } from 'zod';\r\nimport { DeltaType, DeltaMetadataSchema } from './schemas.js';\r\nimport { success, failure, Result } from '../../types/index.js';\r\nimport { ChangeError } from '../../errors/index.js';\r\n\r\n/**\r\n * 델타 항목\r\n */\r\nexport interface DeltaItem {\r\n type: DeltaType;\r\n content: string;\r\n target?: string;\r\n before?: string;\r\n after?: string;\r\n}\r\n\r\n/**\r\n * 파싱된 델타\r\n */\r\nexport interface ParsedDelta {\r\n metadata: {\r\n proposal: string;\r\n created: string;\r\n };\r\n title: string;\r\n added: DeltaItem[];\r\n modified: DeltaItem[];\r\n removed: DeltaItem[];\r\n rawContent: string;\r\n}\r\n\r\n/**\r\n * 델타 메타데이터 전처리 스키마\r\n */\r\nconst PreprocessedDeltaMetadataSchema = z.object({\r\n proposal: z.string(),\r\n created: z.preprocess(\r\n (val) => {\r\n if (val instanceof Date) {\r\n return val.toISOString().split('T')[0];\r\n }\r\n return val;\r\n },\r\n z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/, '날짜 형식: YYYY-MM-DD')\r\n ),\r\n});\r\n\r\n/**\r\n * Delta 파싱\r\n */\r\nexport function parseDelta(content: string): Result<ParsedDelta, ChangeError> {\r\n try {\r\n const { data: frontmatter, content: body } = matter(content);\r\n\r\n // 메타데이터 검증\r\n const metadataResult = PreprocessedDeltaMetadataSchema.safeParse(frontmatter);\r\n if (!metadataResult.success) {\r\n return failure(\r\n new ChangeError(`Delta 메타데이터 오류: ${metadataResult.error.message}`)\r\n );\r\n }\r\n\r\n // 제목 추출\r\n const titleMatch = body.match(/^#\\s+(?:Delta:\\s*)?(.+)$/m);\r\n const title = titleMatch?.[1]?.trim() || '';\r\n\r\n // ADDED 섹션 추출\r\n const addedMatch = body.match(/##\\s*ADDED\\s*([\\s\\S]*?)(?=\\n##|$)/i);\r\n const added: DeltaItem[] = [];\r\n if (addedMatch && addedMatch[1].trim()) {\r\n added.push({\r\n type: 'ADDED',\r\n content: addedMatch[1].trim(),\r\n });\r\n }\r\n\r\n // MODIFIED 섹션 추출\r\n const modifiedMatch = body.match(/##\\s*MODIFIED\\s*([\\s\\S]*?)(?=\\n##\\s+(?:REMOVED|ADDED)|$)/i);\r\n const modified: DeltaItem[] = [];\r\n if (modifiedMatch) {\r\n const contentTrimmed = modifiedMatch[1].trim();\r\n\r\n // 빈 섹션이나 템플릿만 있는 경우 스킵\r\n if (contentTrimmed.length > 0 &&\r\n !contentTrimmed.includes('{{SPEC_PATH}}') &&\r\n contentTrimmed !== '기존 내용') {\r\n // Before/After 블록 추출 - 더 유연한 패턴\r\n const beforeMatch = contentTrimmed.match(/####?\\s*Before\\s*\\n+```(?:markdown)?\\n([\\s\\S]*?)\\n```/i);\r\n const afterMatch = contentTrimmed.match(/####?\\s*After\\s*\\n+```(?:markdown)?\\n([\\s\\S]*?)\\n```/i);\r\n\r\n modified.push({\r\n type: 'MODIFIED',\r\n content: contentTrimmed,\r\n before: beforeMatch?.[1]?.trim(),\r\n after: afterMatch?.[1]?.trim(),\r\n });\r\n }\r\n }\r\n\r\n // REMOVED 섹션 추출\r\n const removedMatch = body.match(/##\\s*REMOVED\\s*([\\s\\S]*?)(?=\\n##|$)/i);\r\n const removed: DeltaItem[] = [];\r\n if (removedMatch && removedMatch[1].trim()) {\r\n removed.push({\r\n type: 'REMOVED',\r\n content: removedMatch[1].trim(),\r\n });\r\n }\r\n\r\n return success({\r\n metadata: metadataResult.data,\r\n title,\r\n added,\r\n modified,\r\n removed,\r\n rawContent: body,\r\n });\r\n } catch (error) {\r\n return failure(\r\n new ChangeError(\r\n `Delta 파싱 실패: ${error instanceof Error ? error.message : String(error)}`\r\n )\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Delta 생성 옵션\r\n */\r\nexport interface GenerateDeltaOptions {\r\n proposalId: string;\r\n title: string;\r\n added?: string[];\r\n modified?: Array<{ target: string; before: string; after: string }>;\r\n removed?: string[];\r\n}\r\n\r\n/**\r\n * Delta 템플릿 생성\r\n */\r\nexport function generateDelta(options: GenerateDeltaOptions): string {\r\n const today = new Date().toISOString().split('T')[0];\r\n\r\n let content = `---\r\nproposal: ${options.proposalId}\r\ncreated: ${today}\r\n---\r\n\r\n# Delta: ${options.title}\r\n\r\n## ADDED\r\n\r\n`;\r\n\r\n if (options.added && options.added.length > 0) {\r\n content += options.added.join('\\n\\n');\r\n } else {\r\n content += '(추가되는 스펙 내용)';\r\n }\r\n\r\n content += '\\n\\n## MODIFIED\\n\\n';\r\n\r\n if (options.modified && options.modified.length > 0) {\r\n options.modified.forEach((mod) => {\r\n content += `### ${mod.target}\\n\\n`;\r\n content += `#### Before\\n\\n\\`\\`\\`markdown\\n${mod.before}\\n\\`\\`\\`\\n\\n`;\r\n content += `#### After\\n\\n\\`\\`\\`markdown\\n${mod.after}\\n\\`\\`\\`\\n\\n`;\r\n });\r\n } else {\r\n content += `### {{SPEC_PATH}}\r\n\r\n#### Before\r\n\r\n\\`\\`\\`markdown\r\n기존 내용\r\n\\`\\`\\`\r\n\r\n#### After\r\n\r\n\\`\\`\\`markdown\r\n변경된 내용\r\n\\`\\`\\`\r\n\r\n`;\r\n }\r\n\r\n content += '## REMOVED\\n\\n';\r\n\r\n if (options.removed && options.removed.length > 0) {\r\n content += options.removed.join('\\n\\n');\r\n } else {\r\n content += '(삭제되는 스펙 참조)';\r\n }\r\n\r\n return content;\r\n}\r\n\r\n/**\r\n * Delta 유효성 검증\r\n */\r\nexport interface DeltaValidationResult {\r\n valid: boolean;\r\n hasAdded: boolean;\r\n hasModified: boolean;\r\n hasRemoved: boolean;\r\n errors: string[];\r\n warnings: string[];\r\n}\r\n\r\nexport function validateDelta(content: string): DeltaValidationResult {\r\n const result: DeltaValidationResult = {\r\n valid: true,\r\n hasAdded: false,\r\n hasModified: false,\r\n hasRemoved: false,\r\n errors: [],\r\n warnings: [],\r\n };\r\n\r\n const parseResult = parseDelta(content);\r\n if (!parseResult.success) {\r\n result.valid = false;\r\n result.errors.push(parseResult.error.message);\r\n return result;\r\n }\r\n\r\n const delta = parseResult.data;\r\n\r\n // 변경 내용 확인\r\n result.hasAdded = delta.added.length > 0 && delta.added[0].content !== '(추가되는 스펙 내용)';\r\n result.hasModified = delta.modified.length > 0 && delta.modified[0].content !== '';\r\n result.hasRemoved = delta.removed.length > 0 && delta.removed[0].content !== '(삭제되는 스펙 참조)';\r\n\r\n // 최소 하나의 변경이 있어야 함\r\n if (!result.hasAdded && !result.hasModified && !result.hasRemoved) {\r\n result.valid = false;\r\n result.errors.push('델타에 변경 내용이 없습니다. ADDED, MODIFIED, REMOVED 중 하나 이상이 필요합니다.');\r\n }\r\n\r\n // MODIFIED에 Before/After가 있는지 확인\r\n if (result.hasModified) {\r\n const mod = delta.modified[0];\r\n if (!mod.before || !mod.after) {\r\n result.warnings.push('MODIFIED 섹션에 Before/After 블록이 없습니다.');\r\n }\r\n }\r\n\r\n return result;\r\n}\r\n","/**\r\n * 변경 아카이브 기능\r\n */\r\nimport path from 'node:path';\r\nimport { promises as fs } from 'node:fs';\r\nimport { success, failure, Result } from '../../types/index.js';\r\nimport { ChangeError } from '../../errors/index.js';\r\nimport { directoryExists, ensureDir, copyDir, removeDir } from '../../utils/fs.js';\r\nimport { parseProposal, updateProposalStatus } from './proposal.js';\r\n\r\n/**\r\n * 아카이브 결과\r\n */\r\nexport interface ArchiveResult {\r\n sourceDir: string;\r\n archiveDir: string;\r\n archivedAt: string;\r\n changeId: string;\r\n}\r\n\r\n/**\r\n * 변경 아카이브\r\n */\r\nexport async function archiveChange(\r\n sddPath: string,\r\n changeId: string\r\n): Promise<Result<ArchiveResult, ChangeError>> {\r\n try {\r\n const changesPath = path.join(sddPath, 'changes');\r\n const archivePath = path.join(sddPath, 'archive');\r\n\r\n // 변경 디렉토리 확인\r\n const sourceDir = path.join(changesPath, changeId);\r\n if (!(await directoryExists(sourceDir))) {\r\n return failure(new ChangeError(`변경 디렉토리를 찾을 수 없습니다: ${changeId}`));\r\n }\r\n\r\n // 아카이브 디렉토리 생성\r\n const today = new Date();\r\n const yearMonth = `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, '0')}`;\r\n const archiveMonthDir = path.join(archivePath, yearMonth);\r\n await ensureDir(archiveMonthDir);\r\n\r\n // 날짜 프리픽스로 아카이브\r\n const datePrefix = today.toISOString().split('T')[0];\r\n const archiveDir = path.join(archiveMonthDir, `${datePrefix}-${changeId}`);\r\n\r\n // 디렉토리 복사\r\n const copyResult = await copyDir(sourceDir, archiveDir);\r\n if (!copyResult.success) {\r\n return failure(new ChangeError(`아카이브 복사 실패: ${copyResult.error?.message}`));\r\n }\r\n\r\n // proposal.md 상태 업데이트\r\n const proposalPath = path.join(archiveDir, 'proposal.md');\r\n try {\r\n const proposalContent = await fs.readFile(proposalPath, 'utf-8');\r\n const updateResult = updateProposalStatus(proposalContent, 'archived');\r\n if (updateResult.success) {\r\n await fs.writeFile(proposalPath, updateResult.data);\r\n }\r\n } catch {\r\n // proposal.md가 없을 수 있음\r\n }\r\n\r\n // 원본 디렉토리 삭제\r\n const removeResult = await removeDir(sourceDir);\r\n if (!removeResult.success) {\r\n return failure(new ChangeError(`원본 디렉토리 삭제 실패: ${removeResult.error?.message}`));\r\n }\r\n\r\n return success({\r\n sourceDir,\r\n archiveDir,\r\n archivedAt: today.toISOString(),\r\n changeId,\r\n });\r\n } catch (error) {\r\n return failure(\r\n new ChangeError(\r\n `아카이브 실패: ${error instanceof Error ? error.message : String(error)}`\r\n )\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * 아카이브 목록 조회\r\n */\r\nexport interface ArchivedChange {\r\n id: string;\r\n path: string;\r\n archivedAt: string;\r\n title?: string;\r\n}\r\n\r\nexport async function listArchives(\r\n sddPath: string\r\n): Promise<Result<ArchivedChange[], ChangeError>> {\r\n try {\r\n const archivePath = path.join(sddPath, 'archive');\r\n\r\n if (!(await directoryExists(archivePath))) {\r\n return success([]);\r\n }\r\n\r\n const archives: ArchivedChange[] = [];\r\n\r\n // 월별 디렉토리 순회\r\n const months = await fs.readdir(archivePath);\r\n for (const month of months) {\r\n const monthPath = path.join(archivePath, month);\r\n const stat = await fs.stat(monthPath);\r\n if (!stat.isDirectory()) continue;\r\n\r\n // 변경 디렉토리 순회\r\n const changes = await fs.readdir(monthPath);\r\n for (const change of changes) {\r\n const changePath = path.join(monthPath, change);\r\n const changeStat = await fs.stat(changePath);\r\n if (!changeStat.isDirectory()) continue;\r\n\r\n // ID 추출 (YYYY-MM-DD-CHG-XXX 형식)\r\n const idMatch = change.match(/\\d{4}-\\d{2}-\\d{2}-(CHG-\\d+)/);\r\n const id = idMatch ? idMatch[1] : change;\r\n\r\n // 날짜 추출\r\n const dateMatch = change.match(/^(\\d{4}-\\d{2}-\\d{2})/);\r\n const archivedAt = dateMatch ? dateMatch[1] : month;\r\n\r\n // 제목 추출 (proposal.md에서)\r\n let title: string | undefined;\r\n try {\r\n const proposalPath = path.join(changePath, 'proposal.md');\r\n const proposalContent = await fs.readFile(proposalPath, 'utf-8');\r\n const parseResult = parseProposal(proposalContent);\r\n if (parseResult.success) {\r\n title = parseResult.data.title;\r\n }\r\n } catch {\r\n // proposal.md가 없을 수 있음\r\n }\r\n\r\n archives.push({\r\n id,\r\n path: changePath,\r\n archivedAt,\r\n title,\r\n });\r\n }\r\n }\r\n\r\n // 날짜 역순 정렬\r\n archives.sort((a, b) => b.archivedAt.localeCompare(a.archivedAt));\r\n\r\n return success(archives);\r\n } catch (error) {\r\n return failure(\r\n new ChangeError(\r\n `아카이브 목록 조회 실패: ${error instanceof Error ? error.message : String(error)}`\r\n )\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * 진행 중인 변경 목록 조회\r\n */\r\nexport interface PendingChange {\r\n id: string;\r\n path: string;\r\n status: string;\r\n title?: string;\r\n createdAt?: string;\r\n}\r\n\r\nexport async function listPendingChanges(\r\n sddPath: string\r\n): Promise<Result<PendingChange[], ChangeError>> {\r\n try {\r\n const changesPath = path.join(sddPath, 'changes');\r\n\r\n if (!(await directoryExists(changesPath))) {\r\n return success([]);\r\n }\r\n\r\n const changes: PendingChange[] = [];\r\n\r\n const dirs = await fs.readdir(changesPath);\r\n for (const dir of dirs) {\r\n const changePath = path.join(changesPath, dir);\r\n const stat = await fs.stat(changePath);\r\n if (!stat.isDirectory()) continue;\r\n\r\n // proposal.md에서 정보 추출\r\n let status = 'draft';\r\n let title: string | undefined;\r\n let createdAt: string | undefined;\r\n\r\n try {\r\n const proposalPath = path.join(changePath, 'proposal.md');\r\n const proposalContent = await fs.readFile(proposalPath, 'utf-8');\r\n const parseResult = parseProposal(proposalContent);\r\n if (parseResult.success) {\r\n status = parseResult.data.metadata.status;\r\n title = parseResult.data.title;\r\n createdAt = parseResult.data.metadata.created;\r\n }\r\n } catch {\r\n // proposal.md가 없을 수 있음\r\n }\r\n\r\n changes.push({\r\n id: dir,\r\n path: changePath,\r\n status,\r\n title,\r\n createdAt,\r\n });\r\n }\r\n\r\n // 생성일 역순 정렬\r\n changes.sort((a, b) => (b.createdAt || '').localeCompare(a.createdAt || ''));\r\n\r\n return success(changes);\r\n } catch (error) {\r\n return failure(\r\n new ChangeError(\r\n `변경 목록 조회 실패: ${error instanceof Error ? error.message : String(error)}`\r\n )\r\n );\r\n }\r\n}\r\n","/**\r\n * sdd impact 명령어\r\n *\r\n * 스펙 간 영향도를 분석합니다.\r\n */\r\nimport { Command } from 'commander';\r\nimport path from 'node:path';\r\nimport {\r\n analyzeImpact,\r\n formatImpactResult,\r\n buildDependencyGraph,\r\n generateMermaidGraph,\r\n generateImpactReport,\r\n formatImpactReport,\r\n analyzeChangeImpact,\r\n parseDeltaFromProposal,\r\n runSimulation,\r\n formatSimulationResult,\r\n analyzeCodeImpact,\r\n formatCodeImpactResult,\r\n} from '../../core/impact/index.js';\r\nimport { findSddRoot } from '../../utils/fs.js';\r\nimport * as logger from '../../utils/logger.js';\r\nimport { ExitCode } from '../../errors/index.js';\r\n\r\n/**\r\n * impact 명령어 등록\r\n */\r\nexport function registerImpactCommand(program: Command): void {\r\n const impact = program\r\n .command('impact [feature]')\r\n .description('스펙 변경의 영향도를 분석합니다')\r\n .option('-g, --graph', '의존성 그래프 출력 (Mermaid)')\r\n .option('-r, --reverse', '역방향 영향도 분석')\r\n .option('-c, --code', '코드 영향도 분석')\r\n .option('--json', 'JSON 형식 출력')\r\n .action(async (feature: string | undefined, options: {\r\n graph?: boolean;\r\n reverse?: boolean;\r\n code?: boolean;\r\n json?: boolean;\r\n }) => {\r\n try {\r\n await runImpact(feature, options);\r\n } catch (error) {\r\n logger.error(error instanceof Error ? error.message : String(error));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n });\r\n\r\n // report 서브커맨드\r\n impact\r\n .command('report')\r\n .description('전체 프로젝트 의존성 리포트 생성')\r\n .option('--json', 'JSON 형식 출력')\r\n .action(async (options: { json?: boolean }) => {\r\n try {\r\n await runImpactReport(options);\r\n } catch (error) {\r\n logger.error(error instanceof Error ? error.message : String(error));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n });\r\n\r\n // change 서브커맨드\r\n impact\r\n .command('change <id>')\r\n .description('변경 제안의 영향도를 분석합니다')\r\n .option('--json', 'JSON 형식 출력')\r\n .action(async (id: string, options: { json?: boolean }) => {\r\n try {\r\n await runChangeImpact(id, options);\r\n } catch (error) {\r\n logger.error(error instanceof Error ? error.message : String(error));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n });\r\n\r\n // simulate 서브커맨드\r\n impact\r\n .command('simulate <feature> <proposal>')\r\n .description('변경 제안을 시뮬레이션하여 영향도를 예측합니다')\r\n .option('--json', 'JSON 형식 출력')\r\n .action(async (feature: string, proposal: string, options: { json?: boolean }) => {\r\n try {\r\n await runSimulate(feature, proposal, options);\r\n } catch (error) {\r\n logger.error(error instanceof Error ? error.message : String(error));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n });\r\n}\r\n\r\n/**\r\n * 영향도 분석 실행\r\n */\r\nasync function runImpact(\r\n feature: string | undefined,\r\n options: { graph?: boolean; reverse?: boolean; code?: boolean; json?: boolean }\r\n): Promise<void> {\r\n const projectRoot = await findSddRoot();\r\n if (!projectRoot) {\r\n logger.error('SDD 프로젝트를 찾을 수 없습니다. `sdd init`을 먼저 실행하세요.');\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n const sddPath = path.join(projectRoot, '.sdd');\r\n\r\n // 그래프 모드\r\n if (options.graph) {\r\n const graphResult = await buildDependencyGraph(path.join(sddPath, 'specs'));\r\n if (!graphResult.success) {\r\n logger.error(graphResult.error.message);\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n const mermaid = generateMermaidGraph(graphResult.data, feature);\r\n\r\n if (options.json) {\r\n console.log(JSON.stringify({\r\n format: 'mermaid',\r\n content: mermaid,\r\n nodes: Array.from(graphResult.data.nodes.values()),\r\n edges: graphResult.data.edges,\r\n }, null, 2));\r\n } else {\r\n logger.info('의존성 그래프 (Mermaid):');\r\n logger.newline();\r\n console.log('```mermaid');\r\n console.log(mermaid);\r\n console.log('```');\r\n }\r\n return;\r\n }\r\n\r\n // 코드 영향도 분석 모드\r\n if (options.code) {\r\n if (!feature) {\r\n logger.error('분석할 기능을 지정하세요.');\r\n logger.info('사용법: sdd impact <feature> --code');\r\n logger.info('예시: sdd impact auth --code');\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n logger.info(`💻 코드 영향도 분석: ${feature}`);\r\n logger.newline();\r\n\r\n const codeResult = await analyzeCodeImpact(projectRoot, sddPath, feature);\r\n if (!codeResult.success) {\r\n logger.error(codeResult.error.message);\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n if (options.json) {\r\n console.log(JSON.stringify(codeResult.data, null, 2));\r\n } else {\r\n console.log(formatCodeImpactResult(codeResult.data));\r\n }\r\n return;\r\n }\r\n\r\n // 특정 기능 영향도 분석\r\n if (!feature) {\r\n logger.error('분석할 기능을 지정하세요.');\r\n logger.info('사용법: sdd impact <feature>');\r\n logger.info('예시: sdd impact auth');\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n const result = await analyzeImpact(sddPath, feature);\r\n if (!result.success) {\r\n logger.error(result.error.message);\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n if (options.json) {\r\n console.log(JSON.stringify(result.data, null, 2));\r\n } else {\r\n console.log(formatImpactResult(result.data));\r\n }\r\n}\r\n\r\n/**\r\n * 영향도 리포트 생성\r\n */\r\nasync function runImpactReport(options: { json?: boolean }): Promise<void> {\r\n const projectRoot = await findSddRoot();\r\n if (!projectRoot) {\r\n logger.error('SDD 프로젝트를 찾을 수 없습니다. `sdd init`을 먼저 실행하세요.');\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n const sddPath = path.join(projectRoot, '.sdd');\r\n const result = await generateImpactReport(sddPath);\r\n\r\n if (!result.success) {\r\n logger.error(result.error.message);\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n if (options.json) {\r\n console.log(JSON.stringify(result.data, null, 2));\r\n } else {\r\n console.log(formatImpactReport(result.data));\r\n }\r\n}\r\n\r\n/**\r\n * 변경 제안 영향 분석\r\n */\r\nasync function runChangeImpact(changeId: string, options: { json?: boolean }): Promise<void> {\r\n const projectRoot = await findSddRoot();\r\n if (!projectRoot) {\r\n logger.error('SDD 프로젝트를 찾을 수 없습니다. `sdd init`을 먼저 실행하세요.');\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n const sddPath = path.join(projectRoot, '.sdd');\r\n const result = await analyzeChangeImpact(sddPath, changeId);\r\n\r\n if (!result.success) {\r\n logger.error(result.error.message);\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n if (options.json) {\r\n console.log(JSON.stringify(result.data, null, 2));\r\n } else {\r\n const data = result.data;\r\n logger.info(`📊 변경 영향 분석: ${data.changeId}`);\r\n if (data.title) {\r\n logger.info(`제목: ${data.title}`);\r\n }\r\n logger.info(`상태: ${data.status}`);\r\n logger.newline();\r\n\r\n if (data.affectedSpecs.length > 0) {\r\n logger.info('⚠️ 직접 영향 받는 스펙:');\r\n for (const spec of data.affectedSpecs) {\r\n logger.listItem(`${spec.id} - ${spec.reason}`, 1);\r\n }\r\n logger.newline();\r\n }\r\n\r\n if (data.transitiveAffected.length > 0) {\r\n logger.info('🔄 간접 영향 받는 스펙:');\r\n for (const spec of data.transitiveAffected) {\r\n logger.listItem(`${spec.id} (${spec.reason})`, 1);\r\n }\r\n logger.newline();\r\n }\r\n\r\n const riskIcon = data.riskLevel === 'high' ? '🔴' : data.riskLevel === 'medium' ? '🟡' : '🟢';\r\n logger.info(`총 영향 범위: ${data.totalImpact}개 스펙 ${riskIcon}`);\r\n logger.newline();\r\n\r\n if (data.recommendations.length > 0) {\r\n logger.info('💡 권장사항:');\r\n for (const rec of data.recommendations) {\r\n logger.listItem(rec, 1);\r\n }\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * What-if 시뮬레이션 실행\r\n */\r\nasync function runSimulate(\r\n feature: string,\r\n proposalPath: string,\r\n options: { json?: boolean }\r\n): Promise<void> {\r\n const projectRoot = await findSddRoot();\r\n if (!projectRoot) {\r\n logger.error('SDD 프로젝트를 찾을 수 없습니다. `sdd init`을 먼저 실행하세요.');\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n const sddPath = path.join(projectRoot, '.sdd');\r\n const specsPath = path.join(sddPath, 'specs');\r\n\r\n // 제안서 경로 해석\r\n let fullProposalPath = proposalPath;\r\n if (!path.isAbsolute(proposalPath)) {\r\n // 상대 경로인 경우 changes/ 디렉토리에서 찾기\r\n const changesPath = path.join(sddPath, 'changes', proposalPath);\r\n if (proposalPath.endsWith('.md')) {\r\n fullProposalPath = changesPath;\r\n } else {\r\n fullProposalPath = path.join(changesPath, 'proposal.md');\r\n }\r\n }\r\n\r\n logger.info(`📊 What-if 시뮬레이션`);\r\n logger.info(`대상 스펙: ${feature}`);\r\n logger.info(`변경 제안: ${fullProposalPath}`);\r\n logger.newline();\r\n\r\n // 델타 파싱\r\n const deltaResult = await parseDeltaFromProposal(fullProposalPath);\r\n if (!deltaResult.success) {\r\n logger.error(deltaResult.error.message);\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n const deltas = deltaResult.data;\r\n if (deltas.length === 0) {\r\n logger.warn('변경 제안에서 델타를 찾을 수 없습니다.');\r\n logger.info('ADDED, MODIFIED, REMOVED 섹션을 확인하세요.');\r\n return;\r\n }\r\n\r\n logger.info(`감지된 변경: ${deltas.length}건`);\r\n for (const delta of deltas) {\r\n const icon = delta.type === 'ADDED' ? '➕' : delta.type === 'REMOVED' ? '➖' : '✏️';\r\n logger.listItem(`${icon} ${delta.type}: ${delta.specId}`, 1);\r\n }\r\n logger.newline();\r\n\r\n // 시뮬레이션 실행\r\n const simResult = await runSimulation(specsPath, feature, deltas);\r\n if (!simResult.success) {\r\n logger.error(simResult.error.message);\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n if (options.json) {\r\n console.log(JSON.stringify(simResult.data, null, 2));\r\n } else {\r\n console.log(formatSimulationResult(simResult.data, feature));\r\n }\r\n}\r\n","/**\r\n * 영향도 분석 스키마\r\n */\r\nimport { z } from 'zod';\r\n\r\n/**\r\n * 의존성 유형\r\n */\r\nexport const DependencyTypeSchema = z.enum([\r\n 'explicit', // frontmatter depends 필드\r\n 'reference', // 문서 내 참조\r\n 'data', // 데이터 모델 공유\r\n 'api', // API 의존\r\n 'component', // 컴포넌트 공유\r\n]);\r\n\r\nexport type DependencyType = z.infer<typeof DependencyTypeSchema>;\r\n\r\n/**\r\n * 영향도 수준\r\n */\r\nexport const ImpactLevelSchema = z.enum(['low', 'medium', 'high']);\r\n\r\nexport type ImpactLevel = z.infer<typeof ImpactLevelSchema>;\r\n\r\n/**\r\n * 의존성 엣지\r\n */\r\nexport interface DependencyEdge {\r\n from: string; // 의존하는 스펙\r\n to: string; // 의존되는 스펙\r\n type: DependencyType;\r\n description?: string;\r\n}\r\n\r\n/**\r\n * 의존성 그래프 노드\r\n */\r\nexport interface DependencyNode {\r\n id: string;\r\n path: string;\r\n title?: string;\r\n dependsOn: string[]; // 이 스펙이 의존하는 것\r\n dependedBy: string[]; // 이 스펙에 의존하는 것\r\n}\r\n\r\n/**\r\n * 의존성 그래프\r\n */\r\nexport interface DependencyGraph {\r\n nodes: Map<string, DependencyNode>;\r\n edges: DependencyEdge[];\r\n}\r\n\r\n/**\r\n * 영향 받는 스펙 정보\r\n */\r\nexport interface AffectedSpec {\r\n id: string;\r\n path: string;\r\n title?: string;\r\n level: ImpactLevel;\r\n type: DependencyType;\r\n reason: string;\r\n}\r\n\r\n/**\r\n * 영향도 분석 결과\r\n */\r\nexport interface ImpactAnalysisResult {\r\n targetSpec: string;\r\n dependsOn: AffectedSpec[];\r\n affectedBy: AffectedSpec[];\r\n transitiveAffected: AffectedSpec[]; // 간접 영향 받는 스펙\r\n riskScore: number; // 1-10\r\n riskLevel: ImpactLevel;\r\n summary: string;\r\n recommendations: string[];\r\n}\r\n\r\n/**\r\n * 영향도 리포트\r\n */\r\nexport interface ImpactReport {\r\n generatedAt: string;\r\n projectPath: string;\r\n totalSpecs: number;\r\n totalEdges: number;\r\n mostConnectedSpecs: Array<{\r\n id: string;\r\n title?: string;\r\n inbound: number;\r\n outbound: number;\r\n total: number;\r\n }>;\r\n orphanSpecs: string[]; // 의존성 없는 스펙\r\n circularDependencies: Array<{\r\n cycle: string[];\r\n description: string;\r\n }>;\r\n healthScore: number; // 1-100\r\n summary: string;\r\n}\r\n\r\n/**\r\n * 변경 제안 영향 분석\r\n */\r\nexport interface ChangeImpactAnalysis {\r\n changeId: string;\r\n title?: string;\r\n status: string;\r\n affectedSpecs: AffectedSpec[];\r\n transitiveAffected: AffectedSpec[];\r\n totalImpact: number;\r\n riskLevel: ImpactLevel;\r\n recommendations: string[];\r\n}\r\n\r\n/**\r\n * 리스크 점수 계산 가중치\r\n */\r\nexport const RISK_WEIGHTS = {\r\n directDependency: 2, // 직접 의존\r\n indirectDependency: 1, // 간접 의존\r\n apiChange: 3, // API 변경\r\n dataModelChange: 2, // 데이터 모델 변경\r\n corePrinciple: 2, // 핵심 원칙 관련\r\n} as const;\r\n\r\n/**\r\n * 영향도 수준 판단 기준\r\n */\r\nexport function getImpactLevel(score: number): ImpactLevel {\r\n if (score <= 3) return 'low';\r\n if (score <= 6) return 'medium';\r\n return 'high';\r\n}\r\n","/**\r\n * 의존성 그래프 분석\r\n */\r\nimport { promises as fs } from 'node:fs';\r\nimport path from 'node:path';\r\nimport matter from 'gray-matter';\r\nimport {\r\n DependencyGraph,\r\n DependencyNode,\r\n DependencyEdge,\r\n DependencyType,\r\n} from './schemas.js';\r\nimport { success, failure, Result } from '../../types/index.js';\r\nimport { ChangeError } from '../../errors/index.js';\r\nimport { directoryExists } from '../../utils/fs.js';\r\n\r\n/**\r\n * 스펙 디렉토리에서 의존성 그래프 구축\r\n */\r\nexport async function buildDependencyGraph(\r\n specsPath: string\r\n): Promise<Result<DependencyGraph, ChangeError>> {\r\n try {\r\n const graph: DependencyGraph = {\r\n nodes: new Map(),\r\n edges: [],\r\n };\r\n\r\n if (!(await directoryExists(specsPath))) {\r\n return success(graph);\r\n }\r\n\r\n // 스펙 파일 수집\r\n const specFiles = await collectSpecFiles(specsPath);\r\n\r\n // 각 스펙 파일 분석\r\n for (const filePath of specFiles) {\r\n const content = await fs.readFile(filePath, 'utf-8');\r\n const relativePath = path.relative(specsPath, filePath);\r\n const specId = getSpecId(relativePath);\r\n\r\n // 노드 생성\r\n const node: DependencyNode = {\r\n id: specId,\r\n path: relativePath,\r\n title: extractTitle(content),\r\n dependsOn: [],\r\n dependedBy: [],\r\n };\r\n\r\n // frontmatter에서 명시적 의존성 추출\r\n const { data: frontmatter } = matter(content);\r\n if (frontmatter.depends) {\r\n const explicitDeps = Array.isArray(frontmatter.depends)\r\n ? frontmatter.depends\r\n : [frontmatter.depends];\r\n\r\n for (const dep of explicitDeps) {\r\n if (dep && dep !== 'null') {\r\n node.dependsOn.push(dep);\r\n graph.edges.push({\r\n from: specId,\r\n to: dep,\r\n type: 'explicit',\r\n description: 'frontmatter depends 필드',\r\n });\r\n }\r\n }\r\n }\r\n\r\n // 내용에서 참조 추출\r\n const references = extractReferences(content, specFiles.map((f) => getSpecId(path.relative(specsPath, f))));\r\n for (const ref of references) {\r\n if (ref !== specId && !node.dependsOn.includes(ref)) {\r\n node.dependsOn.push(ref);\r\n graph.edges.push({\r\n from: specId,\r\n to: ref,\r\n type: 'reference',\r\n description: '문서 내 참조',\r\n });\r\n }\r\n }\r\n\r\n graph.nodes.set(specId, node);\r\n }\r\n\r\n // 역방향 의존성 계산\r\n for (const edge of graph.edges) {\r\n const targetNode = graph.nodes.get(edge.to);\r\n if (targetNode && !targetNode.dependedBy.includes(edge.from)) {\r\n targetNode.dependedBy.push(edge.from);\r\n }\r\n }\r\n\r\n return success(graph);\r\n } catch (error) {\r\n return failure(\r\n new ChangeError(\r\n `의존성 그래프 구축 실패: ${error instanceof Error ? error.message : String(error)}`\r\n )\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * 스펙 파일 수집 (재귀)\r\n */\r\nasync function collectSpecFiles(dirPath: string): Promise<string[]> {\r\n const files: string[] = [];\r\n\r\n const entries = await fs.readdir(dirPath, { withFileTypes: true });\r\n\r\n for (const entry of entries) {\r\n const fullPath = path.join(dirPath, entry.name);\r\n\r\n if (entry.isDirectory()) {\r\n files.push(...(await collectSpecFiles(fullPath)));\r\n } else if (entry.name.endsWith('.md') && entry.name !== 'AGENTS.md') {\r\n files.push(fullPath);\r\n }\r\n }\r\n\r\n return files;\r\n}\r\n\r\n/**\r\n * 파일 경로에서 스펙 ID 추출\r\n */\r\nfunction getSpecId(relativePath: string): string {\r\n return relativePath\r\n .replace(/\\\\/g, '/')\r\n .replace(/\\.md$/, '')\r\n .replace(/\\/spec$/, '');\r\n}\r\n\r\n/**\r\n * 마크다운에서 제목 추출\r\n */\r\nfunction extractTitle(content: string): string | undefined {\r\n const { content: body } = matter(content);\r\n const titleMatch = body.match(/^#\\s+(.+)$/m);\r\n return titleMatch?.[1]?.trim();\r\n}\r\n\r\n/**\r\n * 내용에서 다른 스펙 참조 추출\r\n */\r\nfunction extractReferences(content: string, allSpecIds: string[]): string[] {\r\n const references: string[] = [];\r\n\r\n for (const specId of allSpecIds) {\r\n // 스펙 ID나 경로가 문서에서 언급되는지 확인\r\n const patterns = [\r\n new RegExp(`\\\\[.*?\\\\]\\\\(.*?${escapeRegex(specId)}.*?\\\\)`, 'gi'), // 마크다운 링크\r\n new RegExp(`specs/${escapeRegex(specId)}`, 'gi'), // specs/ 경로\r\n new RegExp(`\\`${escapeRegex(specId)}\\``, 'gi'), // 백틱 내 참조\r\n ];\r\n\r\n for (const pattern of patterns) {\r\n if (pattern.test(content) && !references.includes(specId)) {\r\n references.push(specId);\r\n break;\r\n }\r\n }\r\n }\r\n\r\n return references;\r\n}\r\n\r\n/**\r\n * 정규식 특수문자 이스케이프\r\n */\r\nfunction escapeRegex(str: string): string {\r\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\r\n}\r\n\r\n/**\r\n * Mermaid 그래프 생성\r\n */\r\nexport function generateMermaidGraph(\r\n graph: DependencyGraph,\r\n targetSpec?: string\r\n): string {\r\n let mermaid = 'graph LR\\n';\r\n\r\n // 노드 정의\r\n for (const [id, node] of graph.nodes) {\r\n const label = node.title || id;\r\n const style = targetSpec === id ? 'fill:#ff9' : '';\r\n mermaid += ` ${sanitizeId(id)}[\"${label}\"]\\n`;\r\n if (style) {\r\n mermaid += ` style ${sanitizeId(id)} ${style}\\n`;\r\n }\r\n }\r\n\r\n // 엣지 정의\r\n for (const edge of graph.edges) {\r\n const arrowStyle = edge.type === 'explicit' ? '-->' : '-..->';\r\n mermaid += ` ${sanitizeId(edge.from)} ${arrowStyle} ${sanitizeId(edge.to)}\\n`;\r\n }\r\n\r\n return mermaid;\r\n}\r\n\r\n/**\r\n * Mermaid ID 정리\r\n */\r\nfunction sanitizeId(id: string): string {\r\n return id.replace(/[^a-zA-Z0-9]/g, '_');\r\n}\r\n","/**\r\n * 영향도 분석기\r\n */\r\nimport path from 'node:path';\r\nimport { promises as fs } from 'node:fs';\r\nimport {\r\n DependencyGraph,\r\n ImpactAnalysisResult,\r\n AffectedSpec,\r\n ImpactLevel,\r\n RISK_WEIGHTS,\r\n getImpactLevel,\r\n ImpactReport,\r\n ChangeImpactAnalysis,\r\n} from './schemas.js';\r\nimport { buildDependencyGraph, generateMermaidGraph } from './graph.js';\r\nimport { success, failure, Result } from '../../types/index.js';\r\nimport { ChangeError } from '../../errors/index.js';\r\nimport { directoryExists, fileExists, readFile } from '../../utils/fs.js';\r\nimport { parseProposal } from '../change/index.js';\r\n\r\n/**\r\n * 영향도 분석 실행\r\n */\r\nexport async function analyzeImpact(\r\n sddPath: string,\r\n targetSpec: string\r\n): Promise<Result<ImpactAnalysisResult, ChangeError>> {\r\n try {\r\n const specsPath = path.join(sddPath, 'specs');\r\n\r\n if (!(await directoryExists(specsPath))) {\r\n return failure(new ChangeError('스펙 디렉토리를 찾을 수 없습니다.'));\r\n }\r\n\r\n // 의존성 그래프 구축\r\n const graphResult = await buildDependencyGraph(specsPath);\r\n if (!graphResult.success) {\r\n return failure(graphResult.error);\r\n }\r\n\r\n const graph = graphResult.data;\r\n const targetNode = graph.nodes.get(targetSpec);\r\n\r\n if (!targetNode) {\r\n return failure(new ChangeError(`스펙을 찾을 수 없습니다: ${targetSpec}`));\r\n }\r\n\r\n // 의존하는 스펙 (이 스펙이 사용하는)\r\n const dependsOn: AffectedSpec[] = targetNode.dependsOn.map((depId) => {\r\n const depNode = graph.nodes.get(depId);\r\n const edge = graph.edges.find((e) => e.from === targetSpec && e.to === depId);\r\n return {\r\n id: depId,\r\n path: depNode?.path || depId,\r\n title: depNode?.title,\r\n level: 'low' as ImpactLevel,\r\n type: edge?.type || 'reference',\r\n reason: edge?.description || '의존',\r\n };\r\n });\r\n\r\n // 영향 받는 스펙 (이 스펙을 사용하는)\r\n const affectedBy: AffectedSpec[] = targetNode.dependedBy.map((depId) => {\r\n const depNode = graph.nodes.get(depId);\r\n const edge = graph.edges.find((e) => e.from === depId && e.to === targetSpec);\r\n const level = determineImpactLevel(edge?.type);\r\n return {\r\n id: depId,\r\n path: depNode?.path || depId,\r\n title: depNode?.title,\r\n level,\r\n type: edge?.type || 'reference',\r\n reason: edge?.description || '이 스펙에 의존함',\r\n };\r\n });\r\n\r\n // 간접 영향 분석 (transitive)\r\n const transitiveAffected = getTransitiveAffected(graph, targetSpec, new Set([targetSpec]));\r\n\r\n // 리스크 점수 계산\r\n const riskScore = calculateRiskScore(dependsOn, affectedBy, transitiveAffected);\r\n const riskLevel = getImpactLevel(riskScore);\r\n\r\n // 요약 및 권장사항 생성\r\n const summary = generateSummary(targetSpec, dependsOn, affectedBy, transitiveAffected, riskScore);\r\n const recommendations = generateRecommendations(affectedBy, transitiveAffected, riskLevel);\r\n\r\n return success({\r\n targetSpec,\r\n dependsOn,\r\n affectedBy,\r\n transitiveAffected,\r\n riskScore,\r\n riskLevel,\r\n summary,\r\n recommendations,\r\n });\r\n } catch (error) {\r\n return failure(\r\n new ChangeError(\r\n `영향도 분석 실패: ${error instanceof Error ? error.message : String(error)}`\r\n )\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * 의존성 유형에 따른 영향도 수준 결정\r\n */\r\nfunction determineImpactLevel(type?: string): ImpactLevel {\r\n switch (type) {\r\n case 'explicit':\r\n case 'api':\r\n return 'high';\r\n case 'data':\r\n return 'medium';\r\n default:\r\n return 'low';\r\n }\r\n}\r\n\r\n/**\r\n * 간접 영향 받는 스펙 조회 (재귀)\r\n */\r\nfunction getTransitiveAffected(\r\n graph: DependencyGraph,\r\n specId: string,\r\n visited: Set<string>,\r\n depth: number = 0\r\n): AffectedSpec[] {\r\n const result: AffectedSpec[] = [];\r\n const node = graph.nodes.get(specId);\r\n\r\n if (!node || depth > 5) return result; // 최대 5단계까지\r\n\r\n for (const depId of node.dependedBy) {\r\n if (visited.has(depId)) continue;\r\n visited.add(depId);\r\n\r\n // 직접 의존이 아닌 경우만 추가 (depth > 0)\r\n if (depth > 0) {\r\n const depNode = graph.nodes.get(depId);\r\n const edge = graph.edges.find((e) => e.from === depId && e.to === specId);\r\n result.push({\r\n id: depId,\r\n path: depNode?.path || depId,\r\n title: depNode?.title,\r\n level: depth === 1 ? 'medium' : 'low',\r\n type: edge?.type || 'reference',\r\n reason: `${depth}단계 간접 의존`,\r\n });\r\n }\r\n\r\n // 재귀 탐색\r\n result.push(...getTransitiveAffected(graph, depId, visited, depth + 1));\r\n }\r\n\r\n return result;\r\n}\r\n\r\n/**\r\n * 리스크 점수 계산\r\n */\r\nfunction calculateRiskScore(\r\n dependsOn: AffectedSpec[],\r\n affectedBy: AffectedSpec[],\r\n transitiveAffected: AffectedSpec[] = []\r\n): number {\r\n let score = 0;\r\n\r\n // 직접 영향 받는 스펙 수\r\n const highImpactCount = affectedBy.filter((s) => s.level === 'high').length;\r\n const mediumImpactCount = affectedBy.filter((s) => s.level === 'medium').length;\r\n const lowImpactCount = affectedBy.filter((s) => s.level === 'low').length;\r\n\r\n score += highImpactCount * RISK_WEIGHTS.directDependency;\r\n score += mediumImpactCount * RISK_WEIGHTS.indirectDependency;\r\n score += lowImpactCount * 0.5;\r\n\r\n // 간접 영향 추가\r\n score += transitiveAffected.length * 0.3;\r\n\r\n // API 변경 포함 시\r\n if (affectedBy.some((s) => s.type === 'api')) {\r\n score += RISK_WEIGHTS.apiChange;\r\n }\r\n\r\n // 데이터 모델 변경 포함 시\r\n if (affectedBy.some((s) => s.type === 'data')) {\r\n score += RISK_WEIGHTS.dataModelChange;\r\n }\r\n\r\n // 1-10 범위로 정규화\r\n return Math.min(10, Math.max(1, Math.round(score)));\r\n}\r\n\r\n/**\r\n * 요약 생성\r\n */\r\nfunction generateSummary(\r\n targetSpec: string,\r\n dependsOn: AffectedSpec[],\r\n affectedBy: AffectedSpec[],\r\n transitiveAffected: AffectedSpec[],\r\n riskScore: number\r\n): string {\r\n const parts: string[] = [];\r\n\r\n parts.push(`'${targetSpec}' 스펙 변경 시:`);\r\n\r\n if (dependsOn.length > 0) {\r\n parts.push(`- ${dependsOn.length}개 스펙에 의존함`);\r\n }\r\n\r\n if (affectedBy.length > 0) {\r\n parts.push(`- ${affectedBy.length}개 스펙에 직접 영향을 줌`);\r\n\r\n const highCount = affectedBy.filter((s) => s.level === 'high').length;\r\n if (highCount > 0) {\r\n parts.push(` - 높은 영향: ${highCount}개`);\r\n }\r\n }\r\n\r\n if (transitiveAffected.length > 0) {\r\n parts.push(`- ${transitiveAffected.length}개 스펙에 간접 영향을 줌`);\r\n }\r\n\r\n parts.push(`- 총 영향 범위: ${affectedBy.length + transitiveAffected.length}개 스펙`);\r\n parts.push(`- 리스크 점수: ${riskScore}/10`);\r\n\r\n return parts.join('\\n');\r\n}\r\n\r\n/**\r\n * 권장사항 생성\r\n */\r\nfunction generateRecommendations(\r\n affectedBy: AffectedSpec[],\r\n transitiveAffected: AffectedSpec[],\r\n riskLevel: ImpactLevel\r\n): string[] {\r\n const recommendations: string[] = [];\r\n\r\n if (riskLevel === 'high') {\r\n recommendations.push('변경 전 영향 받는 모든 스펙을 검토하세요.');\r\n recommendations.push('관련 팀과 변경 사항을 공유하세요.');\r\n recommendations.push('단계적 마이그레이션을 고려하세요.');\r\n } else if (riskLevel === 'medium') {\r\n recommendations.push('영향 받는 스펙의 테스트를 확인하세요.');\r\n recommendations.push('변경 후 영향 스펙 검증을 수행하세요.');\r\n } else {\r\n recommendations.push('표준 변경 프로세스를 따르세요.');\r\n }\r\n\r\n // 특정 유형에 대한 권장사항\r\n const hasApiDep = affectedBy.some((s) => s.type === 'api');\r\n if (hasApiDep) {\r\n recommendations.push('API 변경 시 버전 관리를 고려하세요.');\r\n }\r\n\r\n const hasDataDep = affectedBy.some((s) => s.type === 'data');\r\n if (hasDataDep) {\r\n recommendations.push('데이터 마이그레이션 계획을 수립하세요.');\r\n }\r\n\r\n // 간접 영향 관련 권장사항\r\n if (transitiveAffected.length > 3) {\r\n recommendations.push('영향 범위가 넓습니다. 변경 제안서(CHG)를 작성하세요.');\r\n }\r\n\r\n return recommendations;\r\n}\r\n\r\n/**\r\n * 영향도 분석 결과 포맷팅\r\n */\r\nexport function formatImpactResult(result: ImpactAnalysisResult): string {\r\n const lines: string[] = [];\r\n\r\n lines.push(`📊 영향도 분석: ${result.targetSpec}`);\r\n lines.push('');\r\n\r\n if (result.dependsOn.length > 0) {\r\n lines.push('🔗 의존하는 스펙 (이 기능이 사용하는):');\r\n for (const dep of result.dependsOn) {\r\n lines.push(` └─ ${dep.id} (${dep.type})`);\r\n }\r\n lines.push('');\r\n }\r\n\r\n if (result.affectedBy.length > 0) {\r\n lines.push('⚠️ 직접 영향 받는 스펙 (이 기능을 사용하는):');\r\n for (const affected of result.affectedBy) {\r\n const icon = affected.level === 'high' ? '🔴' : affected.level === 'medium' ? '🟡' : '🟢';\r\n lines.push(` ├─ ${icon} ${affected.id} (${affected.type})`);\r\n }\r\n lines.push('');\r\n }\r\n\r\n if (result.transitiveAffected.length > 0) {\r\n lines.push('🔄 간접 영향 받는 스펙:');\r\n for (const affected of result.transitiveAffected) {\r\n lines.push(` └─ ${affected.id} (${affected.reason})`);\r\n }\r\n lines.push('');\r\n }\r\n\r\n const riskIcon = result.riskLevel === 'high' ? '🔴' : result.riskLevel === 'medium' ? '🟡' : '🟢';\r\n lines.push(`📈 리스크 점수: ${result.riskScore}/10 ${riskIcon}`);\r\n lines.push('');\r\n\r\n if (result.recommendations.length > 0) {\r\n lines.push('💡 권장사항:');\r\n for (const rec of result.recommendations) {\r\n lines.push(` - ${rec}`);\r\n }\r\n }\r\n\r\n return lines.join('\\n');\r\n}\r\n\r\n/**\r\n * 전체 프로젝트 영향도 리포트 생성\r\n */\r\nexport async function generateImpactReport(\r\n sddPath: string\r\n): Promise<Result<ImpactReport, ChangeError>> {\r\n try {\r\n const specsPath = path.join(sddPath, 'specs');\r\n\r\n if (!(await directoryExists(specsPath))) {\r\n return failure(new ChangeError('스펙 디렉토리를 찾을 수 없습니다.'));\r\n }\r\n\r\n // 의존성 그래프 구축\r\n const graphResult = await buildDependencyGraph(specsPath);\r\n if (!graphResult.success) {\r\n return failure(graphResult.error);\r\n }\r\n\r\n const graph = graphResult.data;\r\n const nodes = Array.from(graph.nodes.values());\r\n\r\n // 연결성 통계\r\n const mostConnected = nodes\r\n .map((node) => ({\r\n id: node.id,\r\n title: node.title,\r\n inbound: node.dependedBy.length,\r\n outbound: node.dependsOn.length,\r\n total: node.dependedBy.length + node.dependsOn.length,\r\n }))\r\n .sort((a, b) => b.total - a.total)\r\n .slice(0, 5);\r\n\r\n // 고립된 스펙\r\n const orphanSpecs = nodes\r\n .filter((n) => n.dependsOn.length === 0 && n.dependedBy.length === 0)\r\n .map((n) => n.id);\r\n\r\n // 순환 의존성 탐지\r\n const circularDeps = detectCircularDependencies(graph);\r\n\r\n // 건강도 점수 계산\r\n const healthScore = calculateHealthScore(nodes.length, graph.edges.length, orphanSpecs.length, circularDeps.length);\r\n\r\n // 요약\r\n const summary = generateReportSummary(nodes.length, graph.edges.length, orphanSpecs.length, circularDeps.length, healthScore);\r\n\r\n return success({\r\n generatedAt: new Date().toISOString(),\r\n projectPath: sddPath,\r\n totalSpecs: nodes.length,\r\n totalEdges: graph.edges.length,\r\n mostConnectedSpecs: mostConnected,\r\n orphanSpecs,\r\n circularDependencies: circularDeps,\r\n healthScore,\r\n summary,\r\n });\r\n } catch (error) {\r\n return failure(\r\n new ChangeError(\r\n `영향도 리포트 생성 실패: ${error instanceof Error ? error.message : String(error)}`\r\n )\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * 순환 의존성 탐지\r\n */\r\nfunction detectCircularDependencies(\r\n graph: DependencyGraph\r\n): Array<{ cycle: string[]; description: string }> {\r\n const cycles: Array<{ cycle: string[]; description: string }> = [];\r\n const visited = new Set<string>();\r\n const recStack = new Set<string>();\r\n\r\n function dfs(nodeId: string, path: string[]): boolean {\r\n visited.add(nodeId);\r\n recStack.add(nodeId);\r\n\r\n const node = graph.nodes.get(nodeId);\r\n if (!node) return false;\r\n\r\n for (const depId of node.dependsOn) {\r\n if (!visited.has(depId)) {\r\n if (dfs(depId, [...path, nodeId])) {\r\n return true;\r\n }\r\n } else if (recStack.has(depId)) {\r\n // 순환 발견\r\n const cycleStart = path.indexOf(depId);\r\n const cycle = cycleStart >= 0 ? [...path.slice(cycleStart), nodeId, depId] : [nodeId, depId];\r\n cycles.push({\r\n cycle,\r\n description: `순환 의존성: ${cycle.join(' → ')}`,\r\n });\r\n return true;\r\n }\r\n }\r\n\r\n recStack.delete(nodeId);\r\n return false;\r\n }\r\n\r\n for (const nodeId of graph.nodes.keys()) {\r\n if (!visited.has(nodeId)) {\r\n dfs(nodeId, []);\r\n }\r\n }\r\n\r\n return cycles;\r\n}\r\n\r\n/**\r\n * 건강도 점수 계산\r\n */\r\nfunction calculateHealthScore(\r\n totalSpecs: number,\r\n totalEdges: number,\r\n orphanCount: number,\r\n circularCount: number\r\n): number {\r\n if (totalSpecs === 0) return 100;\r\n\r\n let score = 100;\r\n\r\n // 고립된 스펙이 많으면 감점\r\n const orphanRatio = orphanCount / totalSpecs;\r\n score -= orphanRatio * 20;\r\n\r\n // 순환 의존성이 있으면 감점\r\n score -= circularCount * 10;\r\n\r\n // 연결성이 너무 낮으면 감점\r\n const avgConnections = (totalEdges * 2) / totalSpecs;\r\n if (avgConnections < 0.5 && totalSpecs > 2) {\r\n score -= 10;\r\n }\r\n\r\n return Math.max(0, Math.min(100, Math.round(score)));\r\n}\r\n\r\n/**\r\n * 리포트 요약 생성\r\n */\r\nfunction generateReportSummary(\r\n totalSpecs: number,\r\n totalEdges: number,\r\n orphanCount: number,\r\n circularCount: number,\r\n healthScore: number\r\n): string {\r\n const parts: string[] = [];\r\n\r\n parts.push(`프로젝트 의존성 분석 결과:`);\r\n parts.push(`- 총 ${totalSpecs}개 스펙, ${totalEdges}개 의존 관계`);\r\n\r\n if (orphanCount > 0) {\r\n parts.push(`- ${orphanCount}개 스펙이 다른 스펙과 연결되지 않음`);\r\n }\r\n\r\n if (circularCount > 0) {\r\n parts.push(`- ${circularCount}개 순환 의존성 발견 (해결 필요)`);\r\n }\r\n\r\n const healthLevel = healthScore >= 80 ? '양호' : healthScore >= 50 ? '주의 필요' : '문제 있음';\r\n parts.push(`- 건강도 점수: ${healthScore}/100 (${healthLevel})`);\r\n\r\n return parts.join('\\n');\r\n}\r\n\r\n/**\r\n * 변경 제안 영향 분석\r\n */\r\nexport async function analyzeChangeImpact(\r\n sddPath: string,\r\n changeId: string\r\n): Promise<Result<ChangeImpactAnalysis, ChangeError>> {\r\n try {\r\n const changePath = path.join(sddPath, 'changes', changeId);\r\n const proposalPath = path.join(changePath, 'proposal.md');\r\n\r\n if (!(await fileExists(proposalPath))) {\r\n return failure(new ChangeError(`변경 제안을 찾을 수 없습니다: ${changeId}`));\r\n }\r\n\r\n const contentResult = await readFile(proposalPath);\r\n if (!contentResult.success) {\r\n return failure(new ChangeError('proposal.md를 읽을 수 없습니다.'));\r\n }\r\n\r\n const parseResult = parseProposal(contentResult.data);\r\n if (!parseResult.success) {\r\n return failure(new ChangeError(`제안서 파싱 실패: ${parseResult.error.message}`));\r\n }\r\n\r\n const proposal = parseResult.data;\r\n const specsPath = path.join(sddPath, 'specs');\r\n\r\n // 의존성 그래프 구축\r\n const graphResult = await buildDependencyGraph(specsPath);\r\n if (!graphResult.success) {\r\n return failure(graphResult.error);\r\n }\r\n\r\n const graph = graphResult.data;\r\n const allAffected: AffectedSpec[] = [];\r\n const allTransitive: AffectedSpec[] = [];\r\n\r\n // 각 영향 받는 스펙에 대해 분석\r\n for (const specPath of proposal.affectedSpecs) {\r\n const specId = specPath.replace(/^specs\\//, '').replace(/\\/spec\\.md$/, '');\r\n const node = graph.nodes.get(specId);\r\n\r\n if (node) {\r\n // 직접 영향 받는 스펙\r\n for (const depId of node.dependedBy) {\r\n const depNode = graph.nodes.get(depId);\r\n if (!allAffected.some((a) => a.id === depId)) {\r\n allAffected.push({\r\n id: depId,\r\n path: depNode?.path || depId,\r\n title: depNode?.title,\r\n level: 'high',\r\n type: 'explicit',\r\n reason: `${specId} 변경으로 인한 영향`,\r\n });\r\n }\r\n }\r\n\r\n // 간접 영향\r\n const transitive = getTransitiveAffected(graph, specId, new Set([specId]));\r\n for (const t of transitive) {\r\n if (!allTransitive.some((a) => a.id === t.id)) {\r\n allTransitive.push(t);\r\n }\r\n }\r\n }\r\n }\r\n\r\n const totalImpact = allAffected.length + allTransitive.length;\r\n const riskLevel = getImpactLevel(Math.min(10, totalImpact * 2));\r\n\r\n const recommendations: string[] = [];\r\n if (totalImpact > 5) {\r\n recommendations.push('영향 범위가 넓습니다. 단계적 적용을 고려하세요.');\r\n }\r\n if (allAffected.length > 0) {\r\n recommendations.push(`${allAffected.length}개 스펙의 업데이트가 필요합니다.`);\r\n }\r\n recommendations.push('변경 후 sdd validate를 실행하세요.');\r\n\r\n return success({\r\n changeId,\r\n title: proposal.title,\r\n status: proposal.metadata.status,\r\n affectedSpecs: allAffected,\r\n transitiveAffected: allTransitive,\r\n totalImpact,\r\n riskLevel,\r\n recommendations,\r\n });\r\n } catch (error) {\r\n return failure(\r\n new ChangeError(\r\n `변경 영향 분석 실패: ${error instanceof Error ? error.message : String(error)}`\r\n )\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * 영향도 리포트 포맷팅\r\n */\r\nexport function formatImpactReport(report: ImpactReport): string {\r\n const lines: string[] = [];\r\n\r\n lines.push('📊 프로젝트 의존성 리포트');\r\n lines.push(`생성: ${report.generatedAt}`);\r\n lines.push('');\r\n\r\n lines.push(`📈 통계`);\r\n lines.push(` - 총 스펙 수: ${report.totalSpecs}`);\r\n lines.push(` - 총 의존 관계: ${report.totalEdges}`);\r\n const healthIcon = report.healthScore >= 80 ? '🟢' : report.healthScore >= 50 ? '🟡' : '🔴';\r\n lines.push(` - 건강도 점수: ${report.healthScore}/100 ${healthIcon}`);\r\n lines.push('');\r\n\r\n if (report.mostConnectedSpecs.length > 0) {\r\n lines.push('🔗 핵심 스펙 (연결 수 기준):');\r\n for (const spec of report.mostConnectedSpecs) {\r\n lines.push(` - ${spec.id}: 입력 ${spec.inbound}, 출력 ${spec.outbound}`);\r\n }\r\n lines.push('');\r\n }\r\n\r\n if (report.orphanSpecs.length > 0) {\r\n lines.push('⚠️ 고립된 스펙 (연결 없음):');\r\n for (const spec of report.orphanSpecs) {\r\n lines.push(` - ${spec}`);\r\n }\r\n lines.push('');\r\n }\r\n\r\n if (report.circularDependencies.length > 0) {\r\n lines.push('🔴 순환 의존성:');\r\n for (const cycle of report.circularDependencies) {\r\n lines.push(` - ${cycle.description}`);\r\n }\r\n lines.push('');\r\n }\r\n\r\n lines.push('📝 요약');\r\n lines.push(report.summary);\r\n\r\n return lines.join('\\n');\r\n}\r\n\r\nexport { generateMermaidGraph };\r\n","/**\r\n * What-if 시뮬레이션 모듈\r\n *\r\n * 변경 제안을 실제로 적용하지 않고 영향도를 미리 분석합니다.\r\n */\r\nimport { promises as fs } from 'node:fs';\r\nimport path from 'node:path';\r\nimport matter from 'gray-matter';\r\nimport {\r\n DependencyGraph,\r\n DependencyNode,\r\n DependencyEdge,\r\n ImpactLevel,\r\n AffectedSpec,\r\n getImpactLevel,\r\n RISK_WEIGHTS,\r\n} from './schemas.js';\r\nimport { buildDependencyGraph } from './graph.js';\r\nimport { Result, success, failure } from '../../types/index.js';\r\nimport { ChangeError } from '../../errors/index.js';\r\nimport { fileExists } from '../../utils/fs.js';\r\n\r\n/**\r\n * 델타 변경 유형\r\n */\r\nexport type DeltaType = 'ADDED' | 'MODIFIED' | 'REMOVED';\r\n\r\n/**\r\n * 델타 변경 항목\r\n */\r\nexport interface DeltaItem {\r\n type: DeltaType;\r\n specId: string;\r\n description?: string;\r\n before?: string;\r\n after?: string;\r\n newDependencies?: string[];\r\n removedDependencies?: string[];\r\n}\r\n\r\n/**\r\n * 시뮬레이션 결과\r\n */\r\nexport interface SimulationResult {\r\n /** 현재 상태 */\r\n current: {\r\n totalSpecs: number;\r\n totalEdges: number;\r\n targetRiskScore: number;\r\n targetRiskLevel: ImpactLevel;\r\n };\r\n /** 변경 후 상태 */\r\n projected: {\r\n totalSpecs: number;\r\n totalEdges: number;\r\n targetRiskScore: number;\r\n targetRiskLevel: ImpactLevel;\r\n };\r\n /** 변경 사항 */\r\n changes: {\r\n addedSpecs: string[];\r\n removedSpecs: string[];\r\n modifiedSpecs: string[];\r\n addedEdges: number;\r\n removedEdges: number;\r\n };\r\n /** 새로 영향받는 스펙 */\r\n newlyAffected: AffectedSpec[];\r\n /** 더 이상 영향받지 않는 스펙 */\r\n noLongerAffected: string[];\r\n /** 리스크 변화 */\r\n riskDelta: number;\r\n /** 경고 메시지 */\r\n warnings: string[];\r\n /** 권장 사항 */\r\n recommendations: string[];\r\n}\r\n\r\n/**\r\n * 변경 제안 파일에서 델타 파싱\r\n */\r\nexport async function parseDeltaFromProposal(\r\n proposalPath: string\r\n): Promise<Result<DeltaItem[], ChangeError>> {\r\n try {\r\n if (!(await fileExists(proposalPath))) {\r\n return failure(new ChangeError(`제안서 파일을 찾을 수 없습니다: ${proposalPath}`));\r\n }\r\n\r\n const content = await fs.readFile(proposalPath, 'utf-8');\r\n const deltas: DeltaItem[] = [];\r\n\r\n // ADDED 섹션 파싱\r\n const addedSection = content.match(/##\\s*ADDED([\\s\\S]*?)(?=##\\s*(?:MODIFIED|REMOVED)|---|\\n$)/i);\r\n if (addedSection) {\r\n const items = parseListItems(addedSection[1]);\r\n for (const item of items) {\r\n deltas.push({\r\n type: 'ADDED',\r\n specId: extractSpecIdFromText(item),\r\n description: item,\r\n });\r\n }\r\n }\r\n\r\n // MODIFIED 섹션 파싱\r\n const modifiedSection = content.match(/##\\s*MODIFIED([\\s\\S]*?)(?=##\\s*(?:ADDED|REMOVED)|---|\\n$)/i);\r\n if (modifiedSection) {\r\n const items = parseModifiedItems(modifiedSection[1]);\r\n deltas.push(...items);\r\n }\r\n\r\n // REMOVED 섹션 파싱\r\n const removedSection = content.match(/##\\s*REMOVED([\\s\\S]*?)(?=##\\s*(?:ADDED|MODIFIED)|---|\\n$)/i);\r\n if (removedSection) {\r\n const items = parseListItems(removedSection[1]);\r\n for (const item of items) {\r\n deltas.push({\r\n type: 'REMOVED',\r\n specId: extractSpecIdFromText(item),\r\n description: item,\r\n });\r\n }\r\n }\r\n\r\n // depends 변경 추출\r\n extractDependencyChanges(content, deltas);\r\n\r\n return success(deltas);\r\n } catch (error) {\r\n return failure(\r\n new ChangeError(`델타 파싱 실패: ${error instanceof Error ? error.message : String(error)}`)\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * 리스트 아이템 파싱\r\n */\r\nfunction parseListItems(section: string): string[] {\r\n const items: string[] = [];\r\n const lines = section.split('\\n');\r\n\r\n for (const line of lines) {\r\n const match = line.match(/^\\s*-\\s+(.+)/);\r\n if (match) {\r\n items.push(match[1].trim());\r\n }\r\n }\r\n\r\n return items;\r\n}\r\n\r\n/**\r\n * MODIFIED 섹션 파싱 (Before/After 포함)\r\n */\r\nfunction parseModifiedItems(section: string): DeltaItem[] {\r\n const items: DeltaItem[] = [];\r\n\r\n // ### 형식의 수정 항목 찾기\r\n const itemBlocks = section.split(/###\\s+/);\r\n\r\n for (const block of itemBlocks) {\r\n if (!block.trim()) continue;\r\n\r\n const titleMatch = block.match(/^(.+?)(?:\\n|$)/);\r\n if (!titleMatch) continue;\r\n\r\n const specId = extractSpecIdFromText(titleMatch[1]);\r\n const beforeMatch = block.match(/\\*\\*Before\\*\\*:?\\s*(.+?)(?=\\*\\*After\\*\\*|$)/is);\r\n const afterMatch = block.match(/\\*\\*After\\*\\*:?\\s*(.+?)(?=###|$)/is);\r\n\r\n items.push({\r\n type: 'MODIFIED',\r\n specId,\r\n description: titleMatch[1].trim(),\r\n before: beforeMatch?.[1]?.trim(),\r\n after: afterMatch?.[1]?.trim(),\r\n });\r\n }\r\n\r\n // 리스트 형식도 지원\r\n if (items.length === 0) {\r\n const listItems = parseListItems(section);\r\n for (const item of listItems) {\r\n items.push({\r\n type: 'MODIFIED',\r\n specId: extractSpecIdFromText(item),\r\n description: item,\r\n });\r\n }\r\n }\r\n\r\n return items;\r\n}\r\n\r\n/**\r\n * 텍스트에서 스펙 ID 추출\r\n */\r\nfunction extractSpecIdFromText(text: string): string {\r\n // `spec-id` 형식\r\n const backtickMatch = text.match(/`([a-z0-9-]+)`/i);\r\n if (backtickMatch) return backtickMatch[1];\r\n\r\n // 첫 번째 단어 사용 (폴백)\r\n const wordMatch = text.match(/^([a-z0-9-]+)/i);\r\n return wordMatch ? wordMatch[1] : text.slice(0, 20).replace(/\\s/g, '-').toLowerCase();\r\n}\r\n\r\n/**\r\n * 의존성 변경 추출\r\n */\r\nfunction extractDependencyChanges(content: string, deltas: DeltaItem[]): void {\r\n // depends 추가 패턴\r\n const addDepsPattern = /depends?\\s*(?:에|를|:)?\\s*(?:추가|add)/gi;\r\n const removeDepsPattern = /depends?\\s*(?:에서|를|:)?\\s*(?:제거|remove)/gi;\r\n\r\n for (const delta of deltas) {\r\n // 관련 텍스트에서 의존성 변경 찾기\r\n if (delta.after) {\r\n const depsMatch = delta.after.match(/depends?:\\s*\\[?([^\\]\\n]+)\\]?/i);\r\n if (depsMatch) {\r\n delta.newDependencies = depsMatch[1]\r\n .split(',')\r\n .map((d) => d.trim().replace(/[\"`']/g, ''))\r\n .filter(Boolean);\r\n }\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * What-if 시뮬레이션 실행\r\n */\r\nexport async function runSimulation(\r\n specsPath: string,\r\n targetSpec: string,\r\n deltas: DeltaItem[]\r\n): Promise<Result<SimulationResult, ChangeError>> {\r\n try {\r\n // 1. 현재 그래프 구축\r\n const currentGraphResult = await buildDependencyGraph(specsPath);\r\n if (!currentGraphResult.success) {\r\n return failure(currentGraphResult.error);\r\n }\r\n const currentGraph = currentGraphResult.data;\r\n\r\n // 2. 가상 그래프 생성 (딥 복사)\r\n const projectedGraph = cloneGraph(currentGraph);\r\n\r\n // 3. 델타 적용\r\n applyDeltas(projectedGraph, deltas);\r\n\r\n // 4. 영향도 계산\r\n const currentRisk = calculateRiskScore(currentGraph, targetSpec);\r\n const projectedRisk = calculateRiskScore(projectedGraph, targetSpec);\r\n\r\n // 5. 새로 영향받는 스펙 계산\r\n const currentAffected = getAffectedSpecs(currentGraph, targetSpec);\r\n const projectedAffected = getAffectedSpecs(projectedGraph, targetSpec);\r\n\r\n const newlyAffected = projectedAffected.filter(\r\n (spec) => !currentAffected.some((s) => s.id === spec.id)\r\n );\r\n const noLongerAffected = currentAffected\r\n .filter((spec) => !projectedAffected.some((s) => s.id === spec.id))\r\n .map((s) => s.id);\r\n\r\n // 6. 변경 사항 요약\r\n const addedSpecs = deltas.filter((d) => d.type === 'ADDED').map((d) => d.specId);\r\n const removedSpecs = deltas.filter((d) => d.type === 'REMOVED').map((d) => d.specId);\r\n const modifiedSpecs = deltas.filter((d) => d.type === 'MODIFIED').map((d) => d.specId);\r\n\r\n // 7. 경고 및 권장사항 생성\r\n const warnings: string[] = [];\r\n const recommendations: string[] = [];\r\n\r\n const riskDelta = projectedRisk.score - currentRisk.score;\r\n\r\n if (riskDelta > 2) {\r\n warnings.push(`리스크 점수가 ${riskDelta}점 증가합니다 (${currentRisk.score} → ${projectedRisk.score})`);\r\n }\r\n\r\n if (newlyAffected.length > 3) {\r\n warnings.push(`${newlyAffected.length}개의 스펙이 새로 영향받게 됩니다`);\r\n recommendations.push('변경 범위를 줄이거나 단계적 적용을 고려하세요');\r\n }\r\n\r\n if (projectedRisk.level === 'high' && currentRisk.level !== 'high') {\r\n warnings.push('변경 후 리스크 수준이 \"high\"로 상승합니다');\r\n recommendations.push('영향받는 스펙들의 테스트 계획을 먼저 수립하세요');\r\n }\r\n\r\n if (removedSpecs.length > 0) {\r\n const affectedByRemoved = removedSpecs.filter((specId) => {\r\n const node = currentGraph.nodes.get(specId);\r\n return node && node.dependedBy.length > 0;\r\n });\r\n if (affectedByRemoved.length > 0) {\r\n warnings.push(`제거될 스펙 중 다른 스펙에서 참조하는 것이 있습니다: ${affectedByRemoved.join(', ')}`);\r\n }\r\n }\r\n\r\n return success({\r\n current: {\r\n totalSpecs: currentGraph.nodes.size,\r\n totalEdges: currentGraph.edges.length,\r\n targetRiskScore: currentRisk.score,\r\n targetRiskLevel: currentRisk.level,\r\n },\r\n projected: {\r\n totalSpecs: projectedGraph.nodes.size,\r\n totalEdges: projectedGraph.edges.length,\r\n targetRiskScore: projectedRisk.score,\r\n targetRiskLevel: projectedRisk.level,\r\n },\r\n changes: {\r\n addedSpecs,\r\n removedSpecs,\r\n modifiedSpecs,\r\n addedEdges: projectedGraph.edges.length - currentGraph.edges.length,\r\n removedEdges: 0, // 간략화\r\n },\r\n newlyAffected,\r\n noLongerAffected,\r\n riskDelta,\r\n warnings,\r\n recommendations,\r\n });\r\n } catch (error) {\r\n return failure(\r\n new ChangeError(`시뮬레이션 실패: ${error instanceof Error ? error.message : String(error)}`)\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * 그래프 딥 복사\r\n */\r\nfunction cloneGraph(graph: DependencyGraph): DependencyGraph {\r\n const cloned: DependencyGraph = {\r\n nodes: new Map(),\r\n edges: [...graph.edges.map((e) => ({ ...e }))],\r\n };\r\n\r\n for (const [id, node] of graph.nodes) {\r\n cloned.nodes.set(id, {\r\n ...node,\r\n dependsOn: [...node.dependsOn],\r\n dependedBy: [...node.dependedBy],\r\n });\r\n }\r\n\r\n return cloned;\r\n}\r\n\r\n/**\r\n * 델타를 가상 그래프에 적용\r\n */\r\nfunction applyDeltas(graph: DependencyGraph, deltas: DeltaItem[]): void {\r\n for (const delta of deltas) {\r\n switch (delta.type) {\r\n case 'ADDED':\r\n // 새 노드 추가\r\n if (!graph.nodes.has(delta.specId)) {\r\n graph.nodes.set(delta.specId, {\r\n id: delta.specId,\r\n path: `${delta.specId}/spec.md`,\r\n title: delta.description,\r\n dependsOn: delta.newDependencies || [],\r\n dependedBy: [],\r\n });\r\n\r\n // 의존성 엣지 추가\r\n for (const dep of delta.newDependencies || []) {\r\n graph.edges.push({\r\n from: delta.specId,\r\n to: dep,\r\n type: 'explicit',\r\n });\r\n\r\n // 역방향 업데이트\r\n const targetNode = graph.nodes.get(dep);\r\n if (targetNode) {\r\n targetNode.dependedBy.push(delta.specId);\r\n }\r\n }\r\n }\r\n break;\r\n\r\n case 'REMOVED':\r\n // 노드 및 관련 엣지 제거\r\n if (graph.nodes.has(delta.specId)) {\r\n const node = graph.nodes.get(delta.specId)!;\r\n\r\n // 관련 엣지 제거\r\n graph.edges = graph.edges.filter(\r\n (e) => e.from !== delta.specId && e.to !== delta.specId\r\n );\r\n\r\n // 다른 노드에서 참조 제거\r\n for (const depId of node.dependsOn) {\r\n const depNode = graph.nodes.get(depId);\r\n if (depNode) {\r\n depNode.dependedBy = depNode.dependedBy.filter((id) => id !== delta.specId);\r\n }\r\n }\r\n\r\n for (const byId of node.dependedBy) {\r\n const byNode = graph.nodes.get(byId);\r\n if (byNode) {\r\n byNode.dependsOn = byNode.dependsOn.filter((id) => id !== delta.specId);\r\n }\r\n }\r\n\r\n graph.nodes.delete(delta.specId);\r\n }\r\n break;\r\n\r\n case 'MODIFIED':\r\n // 의존성 변경 적용\r\n if (graph.nodes.has(delta.specId) && delta.newDependencies) {\r\n const node = graph.nodes.get(delta.specId)!;\r\n const oldDeps = new Set(node.dependsOn);\r\n\r\n for (const newDep of delta.newDependencies) {\r\n if (!oldDeps.has(newDep)) {\r\n node.dependsOn.push(newDep);\r\n graph.edges.push({\r\n from: delta.specId,\r\n to: newDep,\r\n type: 'explicit',\r\n });\r\n\r\n const targetNode = graph.nodes.get(newDep);\r\n if (targetNode) {\r\n targetNode.dependedBy.push(delta.specId);\r\n }\r\n }\r\n }\r\n }\r\n break;\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * 리스크 점수 계산\r\n */\r\nfunction calculateRiskScore(\r\n graph: DependencyGraph,\r\n targetSpec: string\r\n): { score: number; level: ImpactLevel } {\r\n const node = graph.nodes.get(targetSpec);\r\n if (!node) {\r\n return { score: 0, level: 'low' };\r\n }\r\n\r\n let score = 0;\r\n\r\n // 직접 의존하는 것들\r\n score += node.dependsOn.length * RISK_WEIGHTS.directDependency;\r\n\r\n // 이 스펙에 의존하는 것들\r\n score += node.dependedBy.length * RISK_WEIGHTS.directDependency;\r\n\r\n // 간접 의존성 (2단계까지)\r\n const indirectDeps = new Set<string>();\r\n for (const depId of node.dependedBy) {\r\n const depNode = graph.nodes.get(depId);\r\n if (depNode) {\r\n for (const indirectId of depNode.dependedBy) {\r\n if (indirectId !== targetSpec) {\r\n indirectDeps.add(indirectId);\r\n }\r\n }\r\n }\r\n }\r\n score += indirectDeps.size * RISK_WEIGHTS.indirectDependency;\r\n\r\n // 정규화 (1-10)\r\n score = Math.min(10, Math.max(1, Math.round(score)));\r\n\r\n return {\r\n score,\r\n level: getImpactLevel(score),\r\n };\r\n}\r\n\r\n/**\r\n * 영향받는 스펙 목록 가져오기\r\n */\r\nfunction getAffectedSpecs(graph: DependencyGraph, targetSpec: string): AffectedSpec[] {\r\n const affected: AffectedSpec[] = [];\r\n const node = graph.nodes.get(targetSpec);\r\n\r\n if (!node) return affected;\r\n\r\n // 직접 영향받는 스펙 (이 스펙에 의존하는 것들)\r\n for (const depId of node.dependedBy) {\r\n const depNode = graph.nodes.get(depId);\r\n if (depNode) {\r\n affected.push({\r\n id: depId,\r\n path: depNode.path,\r\n title: depNode.title,\r\n level: 'high',\r\n type: 'explicit',\r\n reason: `${targetSpec}에 직접 의존`,\r\n });\r\n }\r\n }\r\n\r\n // 간접 영향받는 스펙\r\n const visited = new Set<string>([targetSpec, ...node.dependedBy]);\r\n const queue = [...node.dependedBy];\r\n\r\n while (queue.length > 0) {\r\n const current = queue.shift()!;\r\n const currentNode = graph.nodes.get(current);\r\n\r\n if (!currentNode) continue;\r\n\r\n for (const byId of currentNode.dependedBy) {\r\n if (!visited.has(byId)) {\r\n visited.add(byId);\r\n const byNode = graph.nodes.get(byId);\r\n if (byNode) {\r\n affected.push({\r\n id: byId,\r\n path: byNode.path,\r\n title: byNode.title,\r\n level: 'medium',\r\n type: 'reference',\r\n reason: `${current}를 통해 간접 영향`,\r\n });\r\n queue.push(byId);\r\n }\r\n }\r\n }\r\n }\r\n\r\n return affected;\r\n}\r\n\r\n/**\r\n * 시뮬레이션 결과를 텍스트로 포맷\r\n */\r\nexport function formatSimulationResult(result: SimulationResult, targetSpec: string): string {\r\n const lines: string[] = [];\r\n\r\n lines.push('=== What-if 시뮬레이션 결과 ===');\r\n lines.push(`대상 스펙: ${targetSpec}`);\r\n lines.push('');\r\n\r\n // 상태 비교\r\n lines.push('--- 상태 비교 ---');\r\n lines.push('');\r\n lines.push('| 항목 | 현재 | 변경 후 | 차이 |');\r\n lines.push('|------|------|---------|------|');\r\n lines.push(\r\n `| 스펙 수 | ${result.current.totalSpecs} | ${result.projected.totalSpecs} | ${result.projected.totalSpecs - result.current.totalSpecs >= 0 ? '+' : ''}${result.projected.totalSpecs - result.current.totalSpecs} |`\r\n );\r\n lines.push(\r\n `| 엣지 수 | ${result.current.totalEdges} | ${result.projected.totalEdges} | ${result.projected.totalEdges - result.current.totalEdges >= 0 ? '+' : ''}${result.projected.totalEdges - result.current.totalEdges} |`\r\n );\r\n lines.push(\r\n `| 리스크 점수 | ${result.current.targetRiskScore} | ${result.projected.targetRiskScore} | ${result.riskDelta >= 0 ? '+' : ''}${result.riskDelta} |`\r\n );\r\n lines.push(\r\n `| 리스크 수준 | ${result.current.targetRiskLevel} | ${result.projected.targetRiskLevel} | - |`\r\n );\r\n lines.push('');\r\n\r\n // 변경 사항\r\n if (result.changes.addedSpecs.length > 0 ||\r\n result.changes.removedSpecs.length > 0 ||\r\n result.changes.modifiedSpecs.length > 0) {\r\n lines.push('--- 변경 사항 ---');\r\n lines.push('');\r\n if (result.changes.addedSpecs.length > 0) {\r\n lines.push(`추가: ${result.changes.addedSpecs.join(', ')}`);\r\n }\r\n if (result.changes.removedSpecs.length > 0) {\r\n lines.push(`제거: ${result.changes.removedSpecs.join(', ')}`);\r\n }\r\n if (result.changes.modifiedSpecs.length > 0) {\r\n lines.push(`수정: ${result.changes.modifiedSpecs.join(', ')}`);\r\n }\r\n lines.push('');\r\n }\r\n\r\n // 새로 영향받는 스펙\r\n if (result.newlyAffected.length > 0) {\r\n lines.push('--- 새로 영향받는 스펙 ---');\r\n lines.push('');\r\n for (const spec of result.newlyAffected) {\r\n lines.push(`- ${spec.id} (${spec.level}): ${spec.reason}`);\r\n }\r\n lines.push('');\r\n }\r\n\r\n // 더 이상 영향받지 않는 스펙\r\n if (result.noLongerAffected.length > 0) {\r\n lines.push('--- 더 이상 영향받지 않는 스펙 ---');\r\n lines.push('');\r\n lines.push(result.noLongerAffected.join(', '));\r\n lines.push('');\r\n }\r\n\r\n // 경고\r\n if (result.warnings.length > 0) {\r\n lines.push('--- 경고 ---');\r\n lines.push('');\r\n for (const warning of result.warnings) {\r\n lines.push(`⚠️ ${warning}`);\r\n }\r\n lines.push('');\r\n }\r\n\r\n // 권장사항\r\n if (result.recommendations.length > 0) {\r\n lines.push('--- 권장사항 ---');\r\n lines.push('');\r\n for (const rec of result.recommendations) {\r\n lines.push(`💡 ${rec}`);\r\n }\r\n lines.push('');\r\n }\r\n\r\n return lines.join('\\n');\r\n}\r\n","/**\r\n * 코드 영향도 분석기\r\n *\r\n * 스펙 변경이 소스 코드 파일에 미치는 영향을 분석합니다.\r\n */\r\nimport path from 'node:path';\r\nimport { promises as fs } from 'node:fs';\r\nimport { success, failure, Result } from '../../types/index.js';\r\nimport { ChangeError } from '../../errors/index.js';\r\nimport { directoryExists, fileExists, readFile } from '../../utils/fs.js';\r\nimport { ImpactLevel, getImpactLevel } from './schemas.js';\r\n\r\n/**\r\n * 코드 파일 정보\r\n */\r\nexport interface CodeFile {\r\n path: string;\r\n relativePath: string;\r\n type: 'typescript' | 'javascript' | 'other';\r\n specReferences: string[];\r\n imports: string[];\r\n exports: string[];\r\n}\r\n\r\n/**\r\n * 스펙-코드 연결\r\n */\r\nexport interface CodeLink {\r\n specId: string;\r\n filePath: string;\r\n linkType: 'comment' | 'filename' | 'directory' | 'config';\r\n confidence: 'high' | 'medium' | 'low';\r\n}\r\n\r\n/**\r\n * 코드 매핑 설정\r\n */\r\nexport interface CodeMappingConfig {\r\n version: string;\r\n mappings: Array<{\r\n specId: string;\r\n files: string[];\r\n directories?: string[];\r\n }>;\r\n patterns?: {\r\n include?: string[];\r\n exclude?: string[];\r\n };\r\n}\r\n\r\n/**\r\n * 영향받는 코드 파일\r\n */\r\nexport interface AffectedCodeFile {\r\n path: string;\r\n relativePath: string;\r\n impactLevel: ImpactLevel;\r\n impactType: 'direct' | 'indirect';\r\n reason: string;\r\n linkedSpec?: string;\r\n}\r\n\r\n/**\r\n * 코드 영향도 분석 결과\r\n */\r\nexport interface CodeImpactResult {\r\n targetSpec: string;\r\n directFiles: AffectedCodeFile[];\r\n indirectFiles: AffectedCodeFile[];\r\n totalFiles: number;\r\n riskScore: number;\r\n riskLevel: ImpactLevel;\r\n summary: string;\r\n recommendations: string[];\r\n}\r\n\r\n/**\r\n * 스펙 참조 패턴\r\n */\r\nconst SPEC_REFERENCE_PATTERNS = [\r\n /\\/\\/\\s*spec:\\s*([\\w-]+)/gi, // // spec: feature-id\r\n /\\/\\*\\s*spec:\\s*([\\w-]+)\\s*\\*\\//gi, // /* spec: feature-id */\r\n /\\/\\*\\*[\\s\\S]*?@spec\\s+([\\w-]+)[\\s\\S]*?\\*\\//gi, // /** @spec feature-id */\r\n /#\\s*spec:\\s*([\\w-]+)/gi, // # spec: feature-id (for Python, etc.)\r\n];\r\n\r\n/**\r\n * 코드 영향도 분석 실행\r\n */\r\nexport async function analyzeCodeImpact(\r\n projectRoot: string,\r\n sddPath: string,\r\n targetSpec: string\r\n): Promise<Result<CodeImpactResult, ChangeError>> {\r\n try {\r\n // 매핑 설정 로드 (있는 경우)\r\n const mappingConfig = await loadCodeMappingConfig(sddPath);\r\n\r\n // 소스 코드 파일 스캔\r\n const codeFiles = await scanCodeFiles(projectRoot);\r\n\r\n // 스펙-코드 연결 찾기\r\n const links = await findSpecLinks(\r\n targetSpec,\r\n codeFiles,\r\n mappingConfig\r\n );\r\n\r\n // 직접 영향받는 파일\r\n const directFiles: AffectedCodeFile[] = links.map((link) => ({\r\n path: link.filePath,\r\n relativePath: path.relative(projectRoot, link.filePath),\r\n impactLevel: getLinkImpactLevel(link.confidence),\r\n impactType: 'direct' as const,\r\n reason: getLinkReason(link.linkType),\r\n linkedSpec: link.specId,\r\n }));\r\n\r\n // 간접 영향받는 파일 (import 추적)\r\n const indirectFiles = await findIndirectImpact(\r\n projectRoot,\r\n directFiles.map((f) => f.path),\r\n codeFiles\r\n );\r\n\r\n // 리스크 점수 계산\r\n const totalFiles = directFiles.length + indirectFiles.length;\r\n const riskScore = calculateCodeRiskScore(directFiles, indirectFiles);\r\n const riskLevel = getImpactLevel(riskScore);\r\n\r\n // 요약 및 권장사항\r\n const summary = generateCodeSummary(targetSpec, directFiles, indirectFiles);\r\n const recommendations = generateCodeRecommendations(\r\n directFiles,\r\n indirectFiles,\r\n riskLevel\r\n );\r\n\r\n return success({\r\n targetSpec,\r\n directFiles,\r\n indirectFiles,\r\n totalFiles,\r\n riskScore,\r\n riskLevel,\r\n summary,\r\n recommendations,\r\n });\r\n } catch (error) {\r\n return failure(\r\n new ChangeError(\r\n `코드 영향도 분석 실패: ${error instanceof Error ? error.message : String(error)}`\r\n )\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * 코드 매핑 설정 로드\r\n */\r\nasync function loadCodeMappingConfig(\r\n sddPath: string\r\n): Promise<CodeMappingConfig | null> {\r\n const configPath = path.join(sddPath, 'code-mapping.json');\r\n\r\n if (!(await fileExists(configPath))) {\r\n return null;\r\n }\r\n\r\n const contentResult = await readFile(configPath);\r\n if (!contentResult.success) {\r\n return null;\r\n }\r\n\r\n try {\r\n return JSON.parse(contentResult.data) as CodeMappingConfig;\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * 소스 코드 파일 스캔\r\n */\r\nasync function scanCodeFiles(\r\n projectRoot: string,\r\n maxDepth: number = 10\r\n): Promise<CodeFile[]> {\r\n const codeFiles: CodeFile[] = [];\r\n const excludeDirs = new Set([\r\n 'node_modules',\r\n '.git',\r\n 'dist',\r\n 'build',\r\n 'coverage',\r\n '.sdd',\r\n '.next',\r\n '.nuxt',\r\n 'vendor',\r\n '__pycache__',\r\n ]);\r\n\r\n async function scan(dir: string, depth: number): Promise<void> {\r\n if (depth > maxDepth) return;\r\n\r\n try {\r\n const entries = await fs.readdir(dir, { withFileTypes: true });\r\n\r\n for (const entry of entries) {\r\n const fullPath = path.join(dir, entry.name);\r\n\r\n if (entry.isDirectory()) {\r\n if (!excludeDirs.has(entry.name) && !entry.name.startsWith('.')) {\r\n await scan(fullPath, depth + 1);\r\n }\r\n } else if (entry.isFile()) {\r\n const ext = path.extname(entry.name).toLowerCase();\r\n if (isCodeFile(ext)) {\r\n const codeFile = await analyzeCodeFile(fullPath, projectRoot);\r\n if (codeFile) {\r\n codeFiles.push(codeFile);\r\n }\r\n }\r\n }\r\n }\r\n } catch {\r\n // 디렉토리 접근 오류 무시\r\n }\r\n }\r\n\r\n await scan(projectRoot, 0);\r\n return codeFiles;\r\n}\r\n\r\n/**\r\n * 코드 파일 여부 확인\r\n */\r\nfunction isCodeFile(ext: string): boolean {\r\n const codeExtensions = new Set([\r\n '.ts',\r\n '.tsx',\r\n '.js',\r\n '.jsx',\r\n '.mjs',\r\n '.cjs',\r\n '.vue',\r\n '.svelte',\r\n ]);\r\n return codeExtensions.has(ext);\r\n}\r\n\r\n/**\r\n * 코드 파일 분석\r\n */\r\nasync function analyzeCodeFile(\r\n filePath: string,\r\n projectRoot: string\r\n): Promise<CodeFile | null> {\r\n try {\r\n const content = await fs.readFile(filePath, 'utf-8');\r\n const ext = path.extname(filePath).toLowerCase();\r\n\r\n // 스펙 참조 추출\r\n const specReferences = extractSpecReferences(content);\r\n\r\n // import 추출\r\n const imports = extractImports(content);\r\n\r\n // export 추출\r\n const exports = extractExports(content);\r\n\r\n return {\r\n path: filePath,\r\n relativePath: path.relative(projectRoot, filePath),\r\n type: ext === '.ts' || ext === '.tsx' ? 'typescript' : ext === '.js' || ext === '.jsx' ? 'javascript' : 'other',\r\n specReferences,\r\n imports,\r\n exports,\r\n };\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * 스펙 참조 추출\r\n */\r\nfunction extractSpecReferences(content: string): string[] {\r\n const refs = new Set<string>();\r\n\r\n for (const pattern of SPEC_REFERENCE_PATTERNS) {\r\n // 패턴을 복사하여 lastIndex 초기화\r\n const regex = new RegExp(pattern.source, pattern.flags);\r\n let match: RegExpExecArray | null;\r\n\r\n while ((match = regex.exec(content)) !== null) {\r\n if (match[1]) {\r\n refs.add(match[1].toLowerCase());\r\n }\r\n }\r\n }\r\n\r\n return Array.from(refs);\r\n}\r\n\r\n/**\r\n * import 문 추출\r\n */\r\nfunction extractImports(content: string): string[] {\r\n const imports: string[] = [];\r\n\r\n // ES6 import\r\n const es6Pattern = /import\\s+(?:(?:\\{[^}]*\\}|\\*\\s+as\\s+\\w+|\\w+)\\s+from\\s+)?['\"]([^'\"]+)['\"]/g;\r\n let match: RegExpExecArray | null;\r\n\r\n while ((match = es6Pattern.exec(content)) !== null) {\r\n if (match[1] && !match[1].startsWith('.')) {\r\n continue; // 외부 패키지 제외\r\n }\r\n if (match[1]) {\r\n imports.push(match[1]);\r\n }\r\n }\r\n\r\n // CommonJS require\r\n const cjsPattern = /require\\s*\\(\\s*['\"]([^'\"]+)['\"]\\s*\\)/g;\r\n\r\n while ((match = cjsPattern.exec(content)) !== null) {\r\n if (match[1] && !match[1].startsWith('.')) {\r\n continue; // 외부 패키지 제외\r\n }\r\n if (match[1]) {\r\n imports.push(match[1]);\r\n }\r\n }\r\n\r\n return imports;\r\n}\r\n\r\n/**\r\n * export 문 추출\r\n */\r\nfunction extractExports(content: string): string[] {\r\n const exports: string[] = [];\r\n\r\n // Named exports\r\n const namedPattern = /export\\s+(?:const|let|var|function|class|interface|type|enum)\\s+(\\w+)/g;\r\n let match: RegExpExecArray | null;\r\n\r\n while ((match = namedPattern.exec(content)) !== null) {\r\n if (match[1]) {\r\n exports.push(match[1]);\r\n }\r\n }\r\n\r\n // Default export\r\n if (/export\\s+default/.test(content)) {\r\n exports.push('default');\r\n }\r\n\r\n return exports;\r\n}\r\n\r\n/**\r\n * 스펙-코드 연결 찾기\r\n */\r\nasync function findSpecLinks(\r\n targetSpec: string,\r\n codeFiles: CodeFile[],\r\n mappingConfig: CodeMappingConfig | null\r\n): Promise<CodeLink[]> {\r\n const links: CodeLink[] = [];\r\n const normalizedSpec = targetSpec.toLowerCase();\r\n\r\n // 1. 설정 파일에서 매핑 확인\r\n if (mappingConfig) {\r\n const mapping = mappingConfig.mappings.find(\r\n (m) => m.specId.toLowerCase() === normalizedSpec\r\n );\r\n\r\n if (mapping) {\r\n for (const file of mapping.files) {\r\n // 경로 정규화 (슬래시 통일)\r\n const normalizedFile = file.replace(/\\\\/g, '/');\r\n const codeFile = codeFiles.find(\r\n (cf) => {\r\n const normalizedRelPath = cf.relativePath.replace(/\\\\/g, '/');\r\n return normalizedRelPath === normalizedFile ||\r\n cf.path.replace(/\\\\/g, '/').endsWith(normalizedFile);\r\n }\r\n );\r\n if (codeFile) {\r\n links.push({\r\n specId: targetSpec,\r\n filePath: codeFile.path,\r\n linkType: 'config',\r\n confidence: 'high',\r\n });\r\n }\r\n }\r\n }\r\n }\r\n\r\n // 2. 주석에서 스펙 참조 확인\r\n for (const file of codeFiles) {\r\n if (file.specReferences.includes(normalizedSpec)) {\r\n // 이미 추가된 파일인지 확인\r\n if (!links.some((l) => l.filePath === file.path)) {\r\n links.push({\r\n specId: targetSpec,\r\n filePath: file.path,\r\n linkType: 'comment',\r\n confidence: 'high',\r\n });\r\n }\r\n }\r\n }\r\n\r\n // 3. 파일명/디렉토리명 매칭\r\n for (const file of codeFiles) {\r\n const fileName = path.basename(file.path, path.extname(file.path)).toLowerCase();\r\n const dirName = path.basename(path.dirname(file.path)).toLowerCase();\r\n\r\n // 파일명 매칭 (예: auth.ts ↔ auth 스펙)\r\n if (fileName === normalizedSpec || fileName === normalizedSpec.replace(/-/g, '')) {\r\n if (!links.some((l) => l.filePath === file.path)) {\r\n links.push({\r\n specId: targetSpec,\r\n filePath: file.path,\r\n linkType: 'filename',\r\n confidence: 'medium',\r\n });\r\n }\r\n }\r\n\r\n // 디렉토리명 매칭 (예: auth/ 디렉토리 ↔ auth 스펙)\r\n if (dirName === normalizedSpec || dirName === normalizedSpec.replace(/-/g, '')) {\r\n if (!links.some((l) => l.filePath === file.path)) {\r\n links.push({\r\n specId: targetSpec,\r\n filePath: file.path,\r\n linkType: 'directory',\r\n confidence: 'low',\r\n });\r\n }\r\n }\r\n }\r\n\r\n return links;\r\n}\r\n\r\n/**\r\n * 간접 영향받는 파일 찾기\r\n */\r\nasync function findIndirectImpact(\r\n projectRoot: string,\r\n directFilePaths: string[],\r\n allFiles: CodeFile[]\r\n): Promise<AffectedCodeFile[]> {\r\n const indirectFiles: AffectedCodeFile[] = [];\r\n const directSet = new Set(directFilePaths);\r\n const visited = new Set<string>(directFilePaths);\r\n\r\n // 직접 영향받는 파일을 import하는 파일 찾기\r\n for (const file of allFiles) {\r\n if (directSet.has(file.path)) continue;\r\n\r\n for (const imp of file.imports) {\r\n const resolvedImport = resolveImport(file.path, imp);\r\n\r\n // 직접 영향받는 파일을 import하는지 확인\r\n for (const directPath of directFilePaths) {\r\n if (isImportMatch(resolvedImport, directPath)) {\r\n if (!visited.has(file.path)) {\r\n visited.add(file.path);\r\n indirectFiles.push({\r\n path: file.path,\r\n relativePath: path.relative(projectRoot, file.path),\r\n impactLevel: 'medium',\r\n impactType: 'indirect',\r\n reason: `${path.basename(directPath)}를 import함`,\r\n });\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n return indirectFiles;\r\n}\r\n\r\n/**\r\n * import 경로 해석\r\n */\r\nfunction resolveImport(fromFile: string, importPath: string): string {\r\n if (!importPath.startsWith('.')) {\r\n return importPath;\r\n }\r\n\r\n const dir = path.dirname(fromFile);\r\n return path.resolve(dir, importPath);\r\n}\r\n\r\n/**\r\n * import가 대상 파일과 일치하는지 확인\r\n */\r\nfunction isImportMatch(resolvedImport: string, targetFile: string): boolean {\r\n // 확장자 없이 비교\r\n const importWithoutExt = resolvedImport.replace(/\\.(ts|tsx|js|jsx|mjs|cjs)$/, '');\r\n const targetWithoutExt = targetFile.replace(/\\.(ts|tsx|js|jsx|mjs|cjs)$/, '');\r\n\r\n // 정확한 일치\r\n if (importWithoutExt === targetWithoutExt) return true;\r\n\r\n // index 파일 처리\r\n if (targetWithoutExt.endsWith('/index')) {\r\n const dirPath = targetWithoutExt.slice(0, -6);\r\n if (importWithoutExt === dirPath) return true;\r\n }\r\n\r\n return false;\r\n}\r\n\r\n/**\r\n * 링크 신뢰도에 따른 영향도 수준\r\n */\r\nfunction getLinkImpactLevel(confidence: 'high' | 'medium' | 'low'): ImpactLevel {\r\n switch (confidence) {\r\n case 'high':\r\n return 'high';\r\n case 'medium':\r\n return 'medium';\r\n case 'low':\r\n return 'low';\r\n }\r\n}\r\n\r\n/**\r\n * 링크 유형에 따른 이유 설명\r\n */\r\nfunction getLinkReason(linkType: CodeLink['linkType']): string {\r\n switch (linkType) {\r\n case 'comment':\r\n return '스펙 ID 주석 참조';\r\n case 'filename':\r\n return '파일명 일치';\r\n case 'directory':\r\n return '디렉토리명 일치';\r\n case 'config':\r\n return '매핑 설정에 정의됨';\r\n }\r\n}\r\n\r\n/**\r\n * 코드 리스크 점수 계산\r\n */\r\nfunction calculateCodeRiskScore(\r\n directFiles: AffectedCodeFile[],\r\n indirectFiles: AffectedCodeFile[]\r\n): number {\r\n let score = 0;\r\n\r\n // 직접 영향 파일\r\n const highCount = directFiles.filter((f) => f.impactLevel === 'high').length;\r\n const mediumCount = directFiles.filter((f) => f.impactLevel === 'medium').length;\r\n const lowCount = directFiles.filter((f) => f.impactLevel === 'low').length;\r\n\r\n score += highCount * 2;\r\n score += mediumCount * 1;\r\n score += lowCount * 0.5;\r\n\r\n // 간접 영향 파일\r\n score += indirectFiles.length * 0.3;\r\n\r\n // 1-10 범위로 정규화\r\n return Math.min(10, Math.max(1, Math.round(score)));\r\n}\r\n\r\n/**\r\n * 코드 요약 생성\r\n */\r\nfunction generateCodeSummary(\r\n targetSpec: string,\r\n directFiles: AffectedCodeFile[],\r\n indirectFiles: AffectedCodeFile[]\r\n): string {\r\n const parts: string[] = [];\r\n\r\n parts.push(`'${targetSpec}' 스펙 변경 시 코드 영향:`);\r\n\r\n if (directFiles.length > 0) {\r\n parts.push(`- ${directFiles.length}개 파일에 직접 영향`);\r\n\r\n // 링크 유형별 분류\r\n const byComment = directFiles.filter((f) => f.reason === '스펙 ID 주석 참조').length;\r\n const byFilename = directFiles.filter((f) => f.reason === '파일명 일치').length;\r\n const byDir = directFiles.filter((f) => f.reason === '디렉토리명 일치').length;\r\n const byConfig = directFiles.filter((f) => f.reason === '매핑 설정에 정의됨').length;\r\n\r\n if (byComment > 0) parts.push(` - 주석 참조: ${byComment}개`);\r\n if (byFilename > 0) parts.push(` - 파일명 매칭: ${byFilename}개`);\r\n if (byDir > 0) parts.push(` - 디렉토리 매칭: ${byDir}개`);\r\n if (byConfig > 0) parts.push(` - 설정 매핑: ${byConfig}개`);\r\n } else {\r\n parts.push('- 직접 연결된 코드 파일 없음');\r\n }\r\n\r\n if (indirectFiles.length > 0) {\r\n parts.push(`- ${indirectFiles.length}개 파일에 간접 영향 (import 관계)`);\r\n }\r\n\r\n parts.push(`- 총 영향 범위: ${directFiles.length + indirectFiles.length}개 파일`);\r\n\r\n return parts.join('\\n');\r\n}\r\n\r\n/**\r\n * 코드 권장사항 생성\r\n */\r\nfunction generateCodeRecommendations(\r\n directFiles: AffectedCodeFile[],\r\n indirectFiles: AffectedCodeFile[],\r\n riskLevel: ImpactLevel\r\n): string[] {\r\n const recommendations: string[] = [];\r\n\r\n if (riskLevel === 'high') {\r\n recommendations.push('영향받는 모든 코드 파일을 검토하세요.');\r\n recommendations.push('관련 테스트 케이스를 실행하세요.');\r\n recommendations.push('변경 전 코드 리뷰를 권장합니다.');\r\n } else if (riskLevel === 'medium') {\r\n recommendations.push('직접 영향받는 파일을 검토하세요.');\r\n recommendations.push('관련 테스트를 실행하세요.');\r\n } else {\r\n recommendations.push('표준 변경 프로세스를 따르세요.');\r\n }\r\n\r\n // 직접 연결 없는 경우\r\n if (directFiles.length === 0) {\r\n recommendations.push('코드에 스펙 참조 주석을 추가하면 추적이 용이합니다.');\r\n recommendations.push('예: // spec: ' + 'feature-id');\r\n }\r\n\r\n // 간접 영향이 많은 경우\r\n if (indirectFiles.length > 5) {\r\n recommendations.push('영향 범위가 넓습니다. 단계적 변경을 고려하세요.');\r\n }\r\n\r\n return recommendations;\r\n}\r\n\r\n/**\r\n * 코드 영향도 결과 포맷팅\r\n */\r\nexport function formatCodeImpactResult(result: CodeImpactResult): string {\r\n const lines: string[] = [];\r\n\r\n lines.push(`💻 코드 영향도 분석: ${result.targetSpec}`);\r\n lines.push('');\r\n\r\n if (result.directFiles.length > 0) {\r\n lines.push('📂 직접 영향받는 파일:');\r\n for (const file of result.directFiles) {\r\n const icon =\r\n file.impactLevel === 'high' ? '🔴' : file.impactLevel === 'medium' ? '🟡' : '🟢';\r\n lines.push(` ${icon} ${file.relativePath}`);\r\n lines.push(` └─ ${file.reason}`);\r\n }\r\n lines.push('');\r\n } else {\r\n lines.push('📂 직접 연결된 코드 파일 없음');\r\n lines.push(' (코드에 `// spec: feature-id` 주석을 추가하여 연결할 수 있습니다)');\r\n lines.push('');\r\n }\r\n\r\n if (result.indirectFiles.length > 0) {\r\n lines.push('🔗 간접 영향받는 파일 (import 관계):');\r\n for (const file of result.indirectFiles) {\r\n lines.push(` └─ ${file.relativePath}`);\r\n lines.push(` └─ ${file.reason}`);\r\n }\r\n lines.push('');\r\n }\r\n\r\n const riskIcon =\r\n result.riskLevel === 'high' ? '🔴' : result.riskLevel === 'medium' ? '🟡' : '🟢';\r\n lines.push(`📈 리스크 점수: ${result.riskScore}/10 ${riskIcon}`);\r\n lines.push(`📊 총 영향 파일: ${result.totalFiles}개`);\r\n lines.push('');\r\n\r\n if (result.recommendations.length > 0) {\r\n lines.push('💡 권장사항:');\r\n for (const rec of result.recommendations) {\r\n lines.push(` - ${rec}`);\r\n }\r\n }\r\n\r\n return lines.join('\\n');\r\n}\r\n","/**\r\n * sdd new 명령어 - 신규 기능 생성\r\n */\r\nimport { Command } from 'commander';\r\nimport path from 'node:path';\r\nimport { promises as fs } from 'node:fs';\r\nimport {\r\n generateFeatureId,\r\n generateSpec,\r\n generatePlan,\r\n generateTasks,\r\n createBranch,\r\n isGitRepository,\r\n generateFullChecklistMarkdown,\r\n getNextFeatureNumber,\r\n peekNextFeatureNumber,\r\n getFeatureHistory,\r\n} from '../../core/new/index.js';\r\nimport { logger } from '../../utils/index.js';\r\nimport { ensureDir, fileExists, readFile } from '../../utils/fs.js';\r\nimport { parseConstitution } from '../../core/constitution/index.js';\r\n\r\n/**\r\n * new 명령어 등록\r\n */\r\nexport function registerNewCommand(program: Command): void {\r\n const newCmd = program\r\n .command('new')\r\n .description('새로운 기능 생성')\r\n .argument('[name]', '기능 이름')\r\n .option('--title <title>', '기능 제목')\r\n .option('--description <desc>', '기능 설명')\r\n .option('--no-branch', '브랜치 생성 안 함')\r\n .option('--numbered', '자동 번호 부여 (feature/001-name 형식)')\r\n .option('--plan', '계획 파일도 함께 생성')\r\n .option('--tasks', '작업 분해 파일도 함께 생성')\r\n .option('--all', '모든 파일 생성 (spec, plan, tasks)')\r\n .option('--checklist', '체크리스트 파일 생성')\r\n .action(async (name, options) => {\r\n await handleNew(name, options);\r\n });\r\n\r\n // plan 서브커맨드\r\n newCmd\r\n .command('plan')\r\n .description('기능 구현 계획 생성')\r\n .argument('<feature>', '기능 ID')\r\n .option('--title <title>', '계획 제목')\r\n .action(async (feature, opts) => {\r\n await handlePlan(feature, opts);\r\n });\r\n\r\n // tasks 서브커맨드\r\n newCmd\r\n .command('tasks')\r\n .description('작업 분해 생성')\r\n .argument('<feature>', '기능 ID')\r\n .action(async (feature) => {\r\n await handleTasks(feature);\r\n });\r\n\r\n // checklist 서브커맨드\r\n newCmd\r\n .command('checklist')\r\n .description('워크플로우 체크리스트 생성')\r\n .action(async () => {\r\n await handleChecklist();\r\n });\r\n\r\n // counter 서브커맨드\r\n newCmd\r\n .command('counter')\r\n .description('기능 번호 카운터 관리')\r\n .option('--peek', '다음 번호 확인 (증가하지 않음)')\r\n .option('--history', '생성 이력 조회')\r\n .option('--set <number>', '다음 번호 설정')\r\n .action(async (opts) => {\r\n await handleCounter(opts);\r\n });\r\n}\r\n\r\n/**\r\n * new 명령어 핸들러\r\n */\r\nasync function handleNew(\r\n name: string | undefined,\r\n options: {\r\n title?: string;\r\n description?: string;\r\n branch?: boolean;\r\n numbered?: boolean;\r\n plan?: boolean;\r\n tasks?: boolean;\r\n all?: boolean;\r\n checklist?: boolean;\r\n }\r\n): Promise<void> {\r\n if (!name) {\r\n logger.error('기능 이름을 입력해주세요: sdd new <name>');\r\n process.exit(1);\r\n }\r\n\r\n const cwd = process.cwd();\r\n const sddPath = path.join(cwd, '.sdd');\r\n\r\n // 기능 ID 생성 (번호 부여 옵션에 따라)\r\n let featureId: string;\r\n let branchName: string | undefined;\r\n\r\n if (options.numbered) {\r\n const numberResult = await getNextFeatureNumber(sddPath, name);\r\n if (!numberResult.success) {\r\n logger.error(`번호 생성 실패: ${numberResult.error.message}`);\r\n process.exit(1);\r\n }\r\n featureId = numberResult.data.fullId;\r\n branchName = numberResult.data.branchName;\r\n logger.info(`자동 번호 부여: #${numberResult.data.number.toString().padStart(3, '0')}`);\r\n } else {\r\n featureId = generateFeatureId(name);\r\n }\r\n\r\n const title = options.title || name;\r\n const description = options.description || `${title} 기능 명세`;\r\n const featurePath = path.join(sddPath, 'specs', featureId);\r\n\r\n try {\r\n // .sdd 디렉토리 확인\r\n if (!(await fileExists(sddPath))) {\r\n logger.error('.sdd 디렉토리가 없습니다. 먼저 sdd init을 실행해주세요.');\r\n process.exit(1);\r\n }\r\n\r\n // 기능 디렉토리 생성\r\n await ensureDir(featurePath);\r\n\r\n // Constitution 버전 읽기\r\n let constitutionVersion: string | undefined;\r\n const constitutionPath = path.join(sddPath, 'constitution.md');\r\n if (await fileExists(constitutionPath)) {\r\n const constResult = await readFile(constitutionPath);\r\n if (constResult.success) {\r\n const parseResult = parseConstitution(constResult.data);\r\n if (parseResult.success) {\r\n constitutionVersion = parseResult.data.metadata.version;\r\n }\r\n }\r\n }\r\n\r\n // spec.md 생성\r\n const specContent = generateSpec({\r\n id: featureId,\r\n title,\r\n description,\r\n constitutionVersion,\r\n });\r\n await fs.writeFile(path.join(featurePath, 'spec.md'), specContent, 'utf-8');\r\n logger.info(`✅ 명세 생성: ${featurePath}/spec.md`);\r\n\r\n // 브랜치 생성\r\n if (options.branch !== false) {\r\n if (await isGitRepository(cwd)) {\r\n // 번호 부여 모드에서는 전체 브랜치 이름 사용, 아니면 기존 방식\r\n const branchToCreate = branchName || featureId;\r\n const result = await createBranch(branchToCreate, { checkout: true, cwd });\r\n if (result.success) {\r\n logger.info(`✅ 브랜치 생성: ${result.data}`);\r\n } else {\r\n logger.warn(`⚠️ 브랜치 생성 실패: ${result.error.message}`);\r\n }\r\n } else {\r\n logger.warn('⚠️ Git 저장소가 아닙니다. 브랜치 생성을 건너뜁니다.');\r\n }\r\n }\r\n\r\n // plan.md 생성\r\n if (options.plan || options.all) {\r\n const planContent = generatePlan({\r\n featureId,\r\n featureTitle: title,\r\n overview: description,\r\n });\r\n await fs.writeFile(path.join(featurePath, 'plan.md'), planContent, 'utf-8');\r\n logger.info(`✅ 계획 생성: ${featurePath}/plan.md`);\r\n }\r\n\r\n // tasks.md 생성\r\n if (options.tasks || options.all) {\r\n const tasksContent = generateTasks({\r\n featureId,\r\n featureTitle: title,\r\n tasks: [\r\n { title: '기반 구조 설정', priority: 'high' },\r\n { title: '핵심 기능 구현', priority: 'high' },\r\n { title: '테스트 작성', priority: 'medium' },\r\n { title: '문서 업데이트', priority: 'low' },\r\n ],\r\n });\r\n await fs.writeFile(path.join(featurePath, 'tasks.md'), tasksContent, 'utf-8');\r\n logger.info(`✅ 작업 분해 생성: ${featurePath}/tasks.md`);\r\n }\r\n\r\n // 체크리스트 생성\r\n if (options.checklist || options.all) {\r\n const checklistContent = generateFullChecklistMarkdown();\r\n await fs.writeFile(path.join(featurePath, 'checklist.md'), checklistContent, 'utf-8');\r\n logger.info(`✅ 체크리스트 생성: ${featurePath}/checklist.md`);\r\n }\r\n\r\n logger.info('');\r\n logger.info(`🎉 기능 '${featureId}' 생성 완료!`);\r\n logger.info('');\r\n logger.info('다음 단계:');\r\n logger.info(` 1. ${featurePath}/spec.md 편집`);\r\n if (!(options.plan || options.all)) {\r\n logger.info(' 2. sdd new plan ' + featureId + ' - 계획 작성');\r\n }\r\n if (!(options.tasks || options.all)) {\r\n logger.info(' 3. sdd new tasks ' + featureId + ' - 작업 분해');\r\n }\r\n logger.info(' 4. sdd validate - 명세 검증');\r\n } catch (error) {\r\n logger.error(`기능 생성 실패: ${error}`);\r\n process.exit(1);\r\n }\r\n}\r\n\r\n/**\r\n * plan 서브커맨드 핸들러\r\n */\r\nasync function handlePlan(\r\n feature: string,\r\n options: { title?: string }\r\n): Promise<void> {\r\n const cwd = process.cwd();\r\n const featurePath = path.join(cwd, '.sdd', 'specs', feature);\r\n\r\n try {\r\n // 기능 디렉토리 확인\r\n if (!(await fileExists(featurePath))) {\r\n logger.error(`기능 '${feature}'을 찾을 수 없습니다.`);\r\n process.exit(1);\r\n }\r\n\r\n // spec.md에서 제목 추출 시도\r\n let title = options.title || feature;\r\n const specPath = path.join(featurePath, 'spec.md');\r\n if (await fileExists(specPath)) {\r\n const specContent = await fs.readFile(specPath, 'utf-8');\r\n const titleMatch = specContent.match(/title:\\s*\"?([^\"\\n]+)\"?/);\r\n if (titleMatch) {\r\n title = titleMatch[1];\r\n }\r\n }\r\n\r\n // plan.md 생성\r\n const planContent = generatePlan({\r\n featureId: feature,\r\n featureTitle: title,\r\n overview: `${title} 구현 계획`,\r\n });\r\n\r\n await fs.writeFile(path.join(featurePath, 'plan.md'), planContent, 'utf-8');\r\n logger.info(`✅ 계획 생성: ${featurePath}/plan.md`);\r\n logger.info('');\r\n logger.info('다음 단계:');\r\n logger.info(` 1. ${featurePath}/plan.md 편집`);\r\n logger.info(' 2. sdd new tasks ' + feature + ' - 작업 분해');\r\n } catch (error) {\r\n logger.error(`계획 생성 실패: ${error}`);\r\n process.exit(1);\r\n }\r\n}\r\n\r\n/**\r\n * tasks 서브커맨드 핸들러\r\n */\r\nasync function handleTasks(feature: string): Promise<void> {\r\n const cwd = process.cwd();\r\n const featurePath = path.join(cwd, '.sdd', 'specs', feature);\r\n\r\n try {\r\n // 기능 디렉토리 확인\r\n if (!(await fileExists(featurePath))) {\r\n logger.error(`기능 '${feature}'을 찾을 수 없습니다.`);\r\n process.exit(1);\r\n }\r\n\r\n // spec.md에서 제목 추출 시도\r\n let title = feature;\r\n const specPath = path.join(featurePath, 'spec.md');\r\n if (await fileExists(specPath)) {\r\n const specContent = await fs.readFile(specPath, 'utf-8');\r\n const titleMatch = specContent.match(/title:\\s*\"?([^\"\\n]+)\"?/);\r\n if (titleMatch) {\r\n title = titleMatch[1];\r\n }\r\n }\r\n\r\n // tasks.md 생성\r\n const tasksContent = generateTasks({\r\n featureId: feature,\r\n featureTitle: title,\r\n tasks: [\r\n { title: '기반 구조 설정', priority: 'high' },\r\n { title: '핵심 기능 구현', priority: 'high' },\r\n { title: '테스트 작성', priority: 'medium' },\r\n { title: '문서 업데이트', priority: 'low' },\r\n ],\r\n });\r\n\r\n await fs.writeFile(path.join(featurePath, 'tasks.md'), tasksContent, 'utf-8');\r\n logger.info(`✅ 작업 분해 생성: ${featurePath}/tasks.md`);\r\n logger.info('');\r\n logger.info('다음 단계:');\r\n logger.info(` 1. ${featurePath}/tasks.md 편집`);\r\n logger.info(' 2. 각 작업 순차적으로 구현');\r\n } catch (error) {\r\n logger.error(`작업 분해 생성 실패: ${error}`);\r\n process.exit(1);\r\n }\r\n}\r\n\r\n/**\r\n * checklist 서브커맨드 핸들러\r\n */\r\nasync function handleChecklist(): Promise<void> {\r\n const cwd = process.cwd();\r\n const sddPath = path.join(cwd, '.sdd');\r\n\r\n try {\r\n if (!(await fileExists(sddPath))) {\r\n logger.error('.sdd 디렉토리가 없습니다. 먼저 sdd init을 실행해주세요.');\r\n process.exit(1);\r\n }\r\n\r\n const checklistContent = generateFullChecklistMarkdown();\r\n const outputPath = path.join(sddPath, 'checklist.md');\r\n await fs.writeFile(outputPath, checklistContent, 'utf-8');\r\n logger.info(`✅ 체크리스트 생성: ${outputPath}`);\r\n } catch (error) {\r\n logger.error(`체크리스트 생성 실패: ${error}`);\r\n process.exit(1);\r\n }\r\n}\r\n\r\n/**\r\n * counter 서브커맨드 핸들러\r\n */\r\nasync function handleCounter(options: {\r\n peek?: boolean;\r\n history?: boolean;\r\n set?: string;\r\n}): Promise<void> {\r\n const cwd = process.cwd();\r\n const sddPath = path.join(cwd, '.sdd');\r\n\r\n if (!(await fileExists(sddPath))) {\r\n logger.error('.sdd 디렉토리가 없습니다. 먼저 sdd init을 실행해주세요.');\r\n process.exit(1);\r\n }\r\n\r\n // 다음 번호 확인\r\n if (options.peek) {\r\n const result = await peekNextFeatureNumber(sddPath);\r\n if (result.success) {\r\n const paddedNumber = String(result.data).padStart(3, '0');\r\n logger.info(`다음 기능 번호: #${paddedNumber}`);\r\n logger.info(`브랜치 형식: feature/${paddedNumber}-<name>`);\r\n } else {\r\n logger.error(`카운터 조회 실패: ${result.error.message}`);\r\n process.exit(1);\r\n }\r\n return;\r\n }\r\n\r\n // 이력 조회\r\n if (options.history) {\r\n const result = await getFeatureHistory(sddPath);\r\n if (result.success) {\r\n if (result.data.length === 0) {\r\n logger.info('생성된 기능 이력이 없습니다.');\r\n } else {\r\n logger.info('=== 기능 생성 이력 ===');\r\n logger.info('');\r\n for (const entry of result.data) {\r\n const date = new Date(entry.createdAt).toLocaleDateString('ko-KR');\r\n logger.info(`#${String(entry.number).padStart(3, '0')} ${entry.name}`);\r\n logger.info(` ID: ${entry.fullId}`);\r\n logger.info(` 생성일: ${date}`);\r\n logger.info('');\r\n }\r\n }\r\n } else {\r\n logger.error(`이력 조회 실패: ${result.error.message}`);\r\n process.exit(1);\r\n }\r\n return;\r\n }\r\n\r\n // 번호 설정\r\n if (options.set) {\r\n const nextNumber = parseInt(options.set, 10);\r\n if (isNaN(nextNumber) || nextNumber < 1) {\r\n logger.error('유효한 번호를 입력해주세요 (1 이상의 정수)');\r\n process.exit(1);\r\n }\r\n\r\n const { setNextFeatureNumber } = await import('../../core/new/index.js');\r\n const result = await setNextFeatureNumber(sddPath, nextNumber);\r\n if (result.success) {\r\n logger.info(`다음 기능 번호가 #${String(nextNumber).padStart(3, '0')}로 설정되었습니다.`);\r\n } else {\r\n logger.error(`번호 설정 실패: ${result.error.message}`);\r\n process.exit(1);\r\n }\r\n return;\r\n }\r\n\r\n // 기본: 현재 상태 표시\r\n const peekResult = await peekNextFeatureNumber(sddPath);\r\n const historyResult = await getFeatureHistory(sddPath);\r\n\r\n if (peekResult.success && historyResult.success) {\r\n logger.info('=== 기능 번호 카운터 상태 ===');\r\n logger.info('');\r\n logger.info(`다음 번호: #${String(peekResult.data).padStart(3, '0')}`);\r\n logger.info(`생성된 기능 수: ${historyResult.data.length}개`);\r\n logger.info('');\r\n logger.info('옵션:');\r\n logger.info(' --peek 다음 번호 확인');\r\n logger.info(' --history 생성 이력 조회');\r\n logger.info(' --set <n> 다음 번호 설정');\r\n } else {\r\n logger.error('카운터 상태 조회 실패');\r\n process.exit(1);\r\n }\r\n}\r\n","/**\r\n * 유틸리티 모듈 내보내기\r\n */\r\nexport * from './fs.js';\r\nexport * as logger from './logger.js';\r\n","/**\r\n * sdd status 명령어 - 프로젝트 상태 조회\r\n */\r\nimport { Command } from 'commander';\r\nimport path from 'node:path';\r\nimport { promises as fs } from 'node:fs';\r\nimport { logger } from '../../utils/index.js';\r\nimport { fileExists, readDir } from '../../utils/fs.js';\r\nimport { parseSpecMetadata } from '../../core/new/spec-generator.js';\r\nimport { parseTasks, getNextTask } from '../../core/new/task-generator.js';\r\nimport { listPendingChanges, listArchives } from '../../core/change/archive.js';\r\nimport { getCurrentBranch, listFeatureBranches } from '../../core/new/branch.js';\r\n\r\n/**\r\n * status 명령어 등록\r\n */\r\nexport function registerStatusCommand(program: Command): void {\r\n program\r\n .command('status')\r\n .description('SDD 프로젝트 상태 조회')\r\n .option('--json', 'JSON 형식으로 출력')\r\n .option('--verbose', '상세 정보 출력')\r\n .action(async (options) => {\r\n await handleStatus(options);\r\n });\r\n}\r\n\r\ninterface FeatureInfo {\r\n id: string;\r\n title: string;\r\n status: string;\r\n hasSpec: boolean;\r\n hasPlan: boolean;\r\n hasTasks: boolean;\r\n taskProgress?: {\r\n completed: number;\r\n total: number;\r\n };\r\n}\r\n\r\ninterface ProjectStatus {\r\n initialized: boolean;\r\n hasConstitution: boolean;\r\n hasAgents: boolean;\r\n features: FeatureInfo[];\r\n pendingChanges: string[];\r\n archivedChanges: number;\r\n currentBranch?: string;\r\n featureBranches: string[];\r\n}\r\n\r\n/**\r\n * status 명령어 핸들러\r\n */\r\nasync function handleStatus(options: { json?: boolean; verbose?: boolean }): Promise<void> {\r\n const cwd = process.cwd();\r\n const sddPath = path.join(cwd, '.sdd');\r\n\r\n const status: ProjectStatus = {\r\n initialized: false,\r\n hasConstitution: false,\r\n hasAgents: false,\r\n features: [],\r\n pendingChanges: [],\r\n archivedChanges: 0,\r\n featureBranches: [],\r\n };\r\n\r\n // .sdd 디렉토리 확인\r\n status.initialized = await fileExists(sddPath);\r\n\r\n if (!status.initialized) {\r\n if (options.json) {\r\n console.log(JSON.stringify(status, null, 2));\r\n } else {\r\n logger.warn('SDD 프로젝트가 초기화되지 않았습니다.');\r\n logger.info('sdd init 명령어로 초기화하세요.');\r\n }\r\n return;\r\n }\r\n\r\n // 헌법 확인\r\n status.hasConstitution = await fileExists(path.join(sddPath, 'constitution.md'));\r\n\r\n // AGENTS.md 확인\r\n status.hasAgents = await fileExists(path.join(sddPath, 'AGENTS.md'));\r\n\r\n // 기능 스펙 조회\r\n const specsPath = path.join(sddPath, 'specs');\r\n if (await fileExists(specsPath)) {\r\n const specsResult = await readDir(specsPath);\r\n if (specsResult.success) {\r\n for (const entry of specsResult.data) {\r\n const featurePath = path.join(specsPath, entry);\r\n const stat = await fs.stat(featurePath);\r\n\r\n if (stat.isDirectory()) {\r\n const featureInfo = await getFeatureInfo(entry, featurePath);\r\n status.features.push(featureInfo);\r\n }\r\n }\r\n }\r\n }\r\n\r\n // 대기 중인 변경 조회\r\n const pendingResult = await listPendingChanges(sddPath);\r\n if (pendingResult.success) {\r\n status.pendingChanges = pendingResult.data;\r\n }\r\n\r\n // 아카이브된 변경 수 조회\r\n const archiveResult = await listArchives(sddPath);\r\n if (archiveResult.success) {\r\n status.archivedChanges = archiveResult.data.length;\r\n }\r\n\r\n // Git 브랜치 정보\r\n const currentBranchResult = await getCurrentBranch(cwd);\r\n if (currentBranchResult.success) {\r\n status.currentBranch = currentBranchResult.data;\r\n }\r\n\r\n const featureBranchesResult = await listFeatureBranches(cwd);\r\n if (featureBranchesResult.success) {\r\n status.featureBranches = featureBranchesResult.data;\r\n }\r\n\r\n // 출력\r\n if (options.json) {\r\n console.log(JSON.stringify(status, null, 2));\r\n } else {\r\n printStatus(status, options.verbose);\r\n }\r\n}\r\n\r\n/**\r\n * 기능 정보 조회\r\n */\r\nasync function getFeatureInfo(id: string, featurePath: string): Promise<FeatureInfo> {\r\n const info: FeatureInfo = {\r\n id,\r\n title: id,\r\n status: 'unknown',\r\n hasSpec: false,\r\n hasPlan: false,\r\n hasTasks: false,\r\n };\r\n\r\n // spec.md 확인\r\n const specPath = path.join(featurePath, 'spec.md');\r\n if (await fileExists(specPath)) {\r\n info.hasSpec = true;\r\n const content = await fs.readFile(specPath, 'utf-8');\r\n const metadata = parseSpecMetadata(content);\r\n if (metadata) {\r\n info.title = metadata.title;\r\n info.status = metadata.status;\r\n }\r\n }\r\n\r\n // plan.md 확인\r\n info.hasPlan = await fileExists(path.join(featurePath, 'plan.md'));\r\n\r\n // tasks.md 확인\r\n const tasksPath = path.join(featurePath, 'tasks.md');\r\n if (await fileExists(tasksPath)) {\r\n info.hasTasks = true;\r\n const content = await fs.readFile(tasksPath, 'utf-8');\r\n const tasks = parseTasks(content);\r\n const completed = tasks.filter(t => t.status === 'completed').length;\r\n info.taskProgress = {\r\n completed,\r\n total: tasks.length,\r\n };\r\n }\r\n\r\n return info;\r\n}\r\n\r\n/**\r\n * 상태 출력\r\n */\r\nfunction printStatus(status: ProjectStatus, verbose?: boolean): void {\r\n console.log('');\r\n console.log('📊 SDD 프로젝트 상태');\r\n console.log('═'.repeat(40));\r\n console.log('');\r\n\r\n // 기본 정보\r\n console.log('📁 프로젝트 구조:');\r\n console.log(` ${status.hasConstitution ? '✅' : '❌'} constitution.md`);\r\n console.log(` ${status.hasAgents ? '✅' : '❌'} AGENTS.md`);\r\n console.log('');\r\n\r\n // 기능 목록\r\n if (status.features.length > 0) {\r\n console.log('📋 기능 목록:');\r\n for (const feature of status.features) {\r\n const statusIcon = getStatusIcon(feature.status);\r\n const files = [\r\n feature.hasSpec ? 'spec' : '',\r\n feature.hasPlan ? 'plan' : '',\r\n feature.hasTasks ? 'tasks' : '',\r\n ].filter(Boolean).join(', ');\r\n\r\n let progressStr = '';\r\n if (feature.taskProgress) {\r\n const { completed, total } = feature.taskProgress;\r\n const percent = total > 0 ? Math.round((completed / total) * 100) : 0;\r\n progressStr = ` [${completed}/${total} = ${percent}%]`;\r\n }\r\n\r\n console.log(` ${statusIcon} ${feature.title} (${feature.id})`);\r\n if (verbose) {\r\n console.log(` 상태: ${feature.status}, 파일: ${files}${progressStr}`);\r\n }\r\n }\r\n console.log('');\r\n } else {\r\n console.log('📋 기능: 없음');\r\n console.log(' sdd new <name> 명령어로 새 기능을 생성하세요.');\r\n console.log('');\r\n }\r\n\r\n // 변경 정보\r\n if (status.pendingChanges.length > 0) {\r\n console.log('📝 대기 중인 변경:');\r\n for (const change of status.pendingChanges) {\r\n console.log(` - ${change}`);\r\n }\r\n console.log('');\r\n }\r\n\r\n if (status.archivedChanges > 0 && verbose) {\r\n console.log(`📦 아카이브된 변경: ${status.archivedChanges}개`);\r\n console.log('');\r\n }\r\n\r\n // Git 정보\r\n if (status.currentBranch) {\r\n console.log(`🔀 현재 브랜치: ${status.currentBranch}`);\r\n if (status.featureBranches.length > 0 && verbose) {\r\n console.log(' 기능 브랜치:');\r\n for (const branch of status.featureBranches) {\r\n const isCurrent = branch === status.currentBranch;\r\n console.log(` ${isCurrent ? '→' : ' '} ${branch}`);\r\n }\r\n }\r\n console.log('');\r\n }\r\n\r\n // 다음 단계 안내\r\n console.log('💡 다음 단계:');\r\n if (status.features.length === 0) {\r\n console.log(' sdd new <name> - 새 기능 생성');\r\n } else {\r\n const inProgress = status.features.find(f => f.status === 'implementing');\r\n if (inProgress) {\r\n console.log(` ${inProgress.id} 기능 구현 중...`);\r\n if (inProgress.taskProgress) {\r\n const { completed, total } = inProgress.taskProgress;\r\n if (completed < total) {\r\n console.log(` sdd validate - 스펙 검증`);\r\n }\r\n }\r\n } else {\r\n const draft = status.features.find(f => f.status === 'draft');\r\n if (draft) {\r\n console.log(` ${draft.id} 기능 명세 작성 완료 후 /sdd:plan 실행`);\r\n }\r\n }\r\n }\r\n console.log('');\r\n}\r\n\r\n/**\r\n * 상태 아이콘\r\n */\r\nfunction getStatusIcon(status: string): string {\r\n switch (status) {\r\n case 'draft':\r\n return '📝';\r\n case 'specified':\r\n return '📄';\r\n case 'planned':\r\n return '📋';\r\n case 'tasked':\r\n return '✏️';\r\n case 'implementing':\r\n return '🔨';\r\n case 'completed':\r\n return '✅';\r\n default:\r\n return '❓';\r\n }\r\n}\r\n","/**\r\n * sdd list 명령어 - 항목 목록 조회\r\n */\r\nimport { Command } from 'commander';\r\nimport path from 'node:path';\r\nimport { promises as fs } from 'node:fs';\r\nimport { logger } from '../../utils/index.js';\r\nimport { fileExists, readDir } from '../../utils/fs.js';\r\nimport { parseSpecMetadata } from '../../core/new/spec-generator.js';\r\nimport { listPendingChanges, listArchives } from '../../core/change/archive.js';\r\n\r\n/**\r\n * list 명령어 등록\r\n */\r\nexport function registerListCommand(program: Command): void {\r\n const listCmd = program\r\n .command('list')\r\n .alias('ls')\r\n .description('항목 목록 조회');\r\n\r\n // features 서브커맨드\r\n listCmd\r\n .command('features')\r\n .alias('f')\r\n .description('기능 목록 조회')\r\n .option('--status <status>', '상태별 필터 (draft, specified, planned, etc.)')\r\n .action(async (options) => {\r\n await listFeatures(options);\r\n });\r\n\r\n // changes 서브커맨드\r\n listCmd\r\n .command('changes')\r\n .alias('c')\r\n .description('변경 제안 목록 조회')\r\n .option('--pending', '대기 중인 변경만 표시')\r\n .option('--archived', '아카이브된 변경만 표시')\r\n .action(async (options) => {\r\n await listChanges(options);\r\n });\r\n\r\n // specs 서브커맨드\r\n listCmd\r\n .command('specs')\r\n .alias('s')\r\n .description('스펙 파일 목록 조회')\r\n .action(async () => {\r\n await listSpecs();\r\n });\r\n\r\n // templates 서브커맨드\r\n listCmd\r\n .command('templates')\r\n .alias('t')\r\n .description('템플릿 목록 조회')\r\n .action(async () => {\r\n await listTemplates();\r\n });\r\n\r\n // 기본 동작 (전체 요약)\r\n listCmd.action(async () => {\r\n await listSummary();\r\n });\r\n}\r\n\r\n/**\r\n * 기능 목록 조회\r\n */\r\nasync function listFeatures(options: { status?: string }): Promise<void> {\r\n const cwd = process.cwd();\r\n const specsPath = path.join(cwd, '.sdd', 'specs');\r\n\r\n if (!(await fileExists(specsPath))) {\r\n logger.warn('스펙 디렉토리가 없습니다. sdd init을 먼저 실행하세요.');\r\n return;\r\n }\r\n\r\n const result = await readDir(specsPath);\r\n if (!result.success) {\r\n logger.error('스펙 디렉토리를 읽을 수 없습니다.');\r\n return;\r\n }\r\n\r\n const features: Array<{ id: string; title: string; status: string }> = [];\r\n\r\n for (const entry of result.data) {\r\n const featurePath = path.join(specsPath, entry);\r\n const stat = await fs.stat(featurePath);\r\n\r\n if (stat.isDirectory()) {\r\n const specPath = path.join(featurePath, 'spec.md');\r\n if (await fileExists(specPath)) {\r\n const content = await fs.readFile(specPath, 'utf-8');\r\n const metadata = parseSpecMetadata(content);\r\n if (metadata) {\r\n if (!options.status || metadata.status === options.status) {\r\n features.push({\r\n id: entry,\r\n title: metadata.title,\r\n status: metadata.status,\r\n });\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (features.length === 0) {\r\n logger.info('기능이 없습니다.');\r\n return;\r\n }\r\n\r\n console.log('');\r\n console.log('📋 기능 목록');\r\n console.log('─'.repeat(50));\r\n for (const f of features) {\r\n const statusIcon = getStatusIcon(f.status);\r\n console.log(`${statusIcon} ${f.title} (${f.id}) - ${f.status}`);\r\n }\r\n console.log('');\r\n}\r\n\r\n/**\r\n * 변경 목록 조회\r\n */\r\nasync function listChanges(options: { pending?: boolean; archived?: boolean }): Promise<void> {\r\n const cwd = process.cwd();\r\n const sddPath = path.join(cwd, '.sdd');\r\n\r\n if (!(await fileExists(sddPath))) {\r\n logger.warn('.sdd 디렉토리가 없습니다. sdd init을 먼저 실행하세요.');\r\n return;\r\n }\r\n\r\n console.log('');\r\n\r\n if (!options.archived) {\r\n const pendingResult = await listPendingChanges(sddPath);\r\n if (pendingResult.success && pendingResult.data.length > 0) {\r\n console.log('📝 대기 중인 변경');\r\n console.log('─'.repeat(30));\r\n for (const change of pendingResult.data) {\r\n console.log(` - ${change}`);\r\n }\r\n console.log('');\r\n } else if (!options.pending) {\r\n console.log('대기 중인 변경이 없습니다.');\r\n }\r\n }\r\n\r\n if (!options.pending) {\r\n const archiveResult = await listArchives(sddPath);\r\n if (archiveResult.success && archiveResult.data.length > 0) {\r\n console.log('📦 아카이브된 변경');\r\n console.log('─'.repeat(30));\r\n for (const archive of archiveResult.data) {\r\n console.log(` - ${archive}`);\r\n }\r\n console.log('');\r\n } else if (!options.archived) {\r\n console.log('아카이브된 변경이 없습니다.');\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * 스펙 파일 목록\r\n */\r\nasync function listSpecs(): Promise<void> {\r\n const cwd = process.cwd();\r\n const specsPath = path.join(cwd, '.sdd', 'specs');\r\n\r\n if (!(await fileExists(specsPath))) {\r\n logger.warn('스펙 디렉토리가 없습니다.');\r\n return;\r\n }\r\n\r\n console.log('');\r\n console.log('📄 스펙 파일 목록');\r\n console.log('─'.repeat(50));\r\n\r\n await walkSpecs(specsPath, '');\r\n console.log('');\r\n}\r\n\r\n/**\r\n * 스펙 디렉토리 순회\r\n */\r\nasync function walkSpecs(basePath: string, prefix: string): Promise<void> {\r\n const result = await readDir(basePath);\r\n if (!result.success) return;\r\n\r\n for (const entry of result.data) {\r\n const fullPath = path.join(basePath, entry);\r\n const stat = await fs.stat(fullPath);\r\n\r\n if (stat.isDirectory()) {\r\n console.log(`${prefix}📁 ${entry}/`);\r\n await walkSpecs(fullPath, prefix + ' ');\r\n } else if (entry.endsWith('.md')) {\r\n console.log(`${prefix}📄 ${entry}`);\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * 템플릿 목록\r\n */\r\nasync function listTemplates(): Promise<void> {\r\n const cwd = process.cwd();\r\n const templatesPath = path.join(cwd, '.sdd', 'templates');\r\n\r\n if (!(await fileExists(templatesPath))) {\r\n logger.warn('템플릿 디렉토리가 없습니다.');\r\n return;\r\n }\r\n\r\n const result = await readDir(templatesPath);\r\n if (!result.success) {\r\n logger.error('템플릿 디렉토리를 읽을 수 없습니다.');\r\n return;\r\n }\r\n\r\n console.log('');\r\n console.log('📑 템플릿 목록');\r\n console.log('─'.repeat(30));\r\n for (const template of result.data.filter(f => f.endsWith('.md'))) {\r\n console.log(` - ${template}`);\r\n }\r\n console.log('');\r\n}\r\n\r\n/**\r\n * 전체 요약\r\n */\r\nasync function listSummary(): Promise<void> {\r\n const cwd = process.cwd();\r\n const sddPath = path.join(cwd, '.sdd');\r\n\r\n if (!(await fileExists(sddPath))) {\r\n logger.warn('.sdd 디렉토리가 없습니다. sdd init을 먼저 실행하세요.');\r\n return;\r\n }\r\n\r\n console.log('');\r\n console.log('📊 SDD 프로젝트 요약');\r\n console.log('═'.repeat(40));\r\n\r\n // 기능 수\r\n const specsPath = path.join(sddPath, 'specs');\r\n let featureCount = 0;\r\n if (await fileExists(specsPath)) {\r\n const result = await readDir(specsPath);\r\n if (result.success) {\r\n for (const entry of result.data) {\r\n const stat = await fs.stat(path.join(specsPath, entry));\r\n if (stat.isDirectory()) featureCount++;\r\n }\r\n }\r\n }\r\n console.log(`📋 기능: ${featureCount}개`);\r\n\r\n // 변경 수\r\n const pendingResult = await listPendingChanges(sddPath);\r\n const pendingCount = pendingResult.success ? pendingResult.data.length : 0;\r\n console.log(`📝 대기 중인 변경: ${pendingCount}개`);\r\n\r\n const archiveResult = await listArchives(sddPath);\r\n const archiveCount = archiveResult.success ? archiveResult.data.length : 0;\r\n console.log(`📦 아카이브된 변경: ${archiveCount}개`);\r\n\r\n console.log('');\r\n console.log('상세 정보:');\r\n console.log(' sdd list features - 기능 목록');\r\n console.log(' sdd list changes - 변경 목록');\r\n console.log(' sdd list specs - 스펙 파일 목록');\r\n console.log(' sdd status - 프로젝트 상태');\r\n console.log('');\r\n}\r\n\r\n/**\r\n * 상태 아이콘\r\n */\r\nfunction getStatusIcon(status: string): string {\r\n switch (status) {\r\n case 'draft':\r\n return '📝';\r\n case 'specified':\r\n return '📄';\r\n case 'planned':\r\n return '📋';\r\n case 'tasked':\r\n return '✏️';\r\n case 'implementing':\r\n return '🔨';\r\n case 'completed':\r\n return '✅';\r\n default:\r\n return '❓';\r\n }\r\n}\r\n","/**\r\n * sdd constitution 명령어\r\n */\r\nimport { Command } from 'commander';\r\nimport path from 'node:path';\r\nimport { readFile, writeFile, fileExists } from '../../utils/fs.js';\r\nimport { ExitCode } from '../../errors/index.js';\r\nimport * as logger from '../../utils/logger.js';\r\nimport {\r\n parseConstitution,\r\n validateConstitution,\r\n bumpVersion,\r\n parseVersion,\r\n generateChangelog,\r\n parseChangelog,\r\n createChangelogEntry,\r\n suggestBumpType,\r\n type VersionBumpType,\r\n type ChangeType,\r\n type ChangelogEntry,\r\n} from '../../core/constitution/index.js';\r\n\r\n/**\r\n * constitution 명령어 등록\r\n */\r\nexport function registerConstitutionCommand(program: Command): void {\r\n const constitution = program\r\n .command('constitution')\r\n .description('Constitution(프로젝트 원칙) 관리');\r\n\r\n // show 서브커맨드\r\n constitution\r\n .command('show')\r\n .description('현재 Constitution 내용 표시')\r\n .option('--json', 'JSON 형식으로 출력')\r\n .action(async (options: { json?: boolean }) => {\r\n try {\r\n await runShow(options);\r\n } catch (error) {\r\n logger.error(error instanceof Error ? error.message : String(error));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n });\r\n\r\n // version 서브커맨드\r\n constitution\r\n .command('version')\r\n .description('현재 Constitution 버전 표시')\r\n .action(async () => {\r\n try {\r\n await runVersion();\r\n } catch (error) {\r\n logger.error(error instanceof Error ? error.message : String(error));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n });\r\n\r\n // bump 서브커맨드\r\n constitution\r\n .command('bump')\r\n .description('Constitution 버전 업데이트')\r\n .option('--major', 'MAJOR 버전 업데이트 (핵심 원칙 변경)')\r\n .option('--minor', 'MINOR 버전 업데이트 (새 원칙 추가)')\r\n .option('--patch', 'PATCH 버전 업데이트 (문구 수정)')\r\n .option('-m, --message <message>', '변경 사유')\r\n .action(async (options: { major?: boolean; minor?: boolean; patch?: boolean; message?: string }) => {\r\n try {\r\n await runBump(options);\r\n } catch (error) {\r\n logger.error(error instanceof Error ? error.message : String(error));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n });\r\n\r\n // history 서브커맨드\r\n constitution\r\n .command('history')\r\n .description('Constitution 변경 이력 조회')\r\n .option('-n, --count <count>', '표시할 항목 수', '10')\r\n .action(async (options: { count: string }) => {\r\n try {\r\n await runHistory(options);\r\n } catch (error) {\r\n logger.error(error instanceof Error ? error.message : String(error));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n });\r\n\r\n // validate 서브커맨드\r\n constitution\r\n .command('validate')\r\n .description('Constitution 형식 검증')\r\n .action(async () => {\r\n try {\r\n await runValidate();\r\n } catch (error) {\r\n logger.error(error instanceof Error ? error.message : String(error));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n });\r\n\r\n // 기본 동작 (서브커맨드 없이 실행 시)\r\n constitution.action(async () => {\r\n await runShow({});\r\n });\r\n}\r\n\r\n/**\r\n * Constitution 표시\r\n */\r\nasync function runShow(options: { json?: boolean }): Promise<void> {\r\n const cwd = process.cwd();\r\n const constitutionPath = path.join(cwd, '.sdd', 'constitution.md');\r\n\r\n if (!(await fileExists(constitutionPath))) {\r\n logger.error('Constitution이 없습니다. `sdd init`으로 프로젝트를 초기화하세요.');\r\n process.exit(ExitCode.FILE_NOT_FOUND);\r\n }\r\n\r\n const contentResult = await readFile(constitutionPath);\r\n if (!contentResult.success) {\r\n logger.error('Constitution 파일을 읽을 수 없습니다.');\r\n process.exit(ExitCode.FILE_SYSTEM_ERROR);\r\n }\r\n\r\n const parseResult = parseConstitution(contentResult.data);\r\n if (!parseResult.success) {\r\n logger.error(`Constitution 파싱 실패: ${parseResult.error.message}`);\r\n process.exit(ExitCode.VALIDATION_ERROR);\r\n }\r\n\r\n const constitution = parseResult.data;\r\n\r\n if (options.json) {\r\n console.log(JSON.stringify({\r\n projectName: constitution.projectName,\r\n version: constitution.metadata.version,\r\n created: constitution.metadata.created,\r\n updated: constitution.metadata.updated,\r\n principles: constitution.principles,\r\n forbidden: constitution.forbidden,\r\n techStack: constitution.techStack,\r\n qualityStandards: constitution.qualityStandards,\r\n }, null, 2));\r\n return;\r\n }\r\n\r\n // 콘솔 출력\r\n logger.info(`Constitution: ${constitution.projectName}`);\r\n logger.info(`버전: ${constitution.metadata.version}`);\r\n if (constitution.description) {\r\n logger.info(`설명: ${constitution.description}`);\r\n }\r\n logger.newline();\r\n\r\n if (constitution.principles.length > 0) {\r\n logger.info('핵심 원칙:');\r\n for (const principle of constitution.principles) {\r\n logger.listItem(`${principle.id}. ${principle.title}`);\r\n for (const rule of principle.rules) {\r\n logger.listItem(rule, 1);\r\n }\r\n }\r\n logger.newline();\r\n }\r\n\r\n if (constitution.forbidden.length > 0) {\r\n logger.info('금지 사항:');\r\n for (const item of constitution.forbidden) {\r\n logger.listItem(item);\r\n }\r\n logger.newline();\r\n }\r\n\r\n if (constitution.techStack.length > 0) {\r\n logger.info('기술 스택:');\r\n for (const tech of constitution.techStack) {\r\n logger.listItem(tech);\r\n }\r\n logger.newline();\r\n }\r\n\r\n if (constitution.qualityStandards.length > 0) {\r\n logger.info('품질 기준:');\r\n for (const standard of constitution.qualityStandards) {\r\n logger.listItem(standard);\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * 버전 표시\r\n */\r\nasync function runVersion(): Promise<void> {\r\n const cwd = process.cwd();\r\n const constitutionPath = path.join(cwd, '.sdd', 'constitution.md');\r\n\r\n if (!(await fileExists(constitutionPath))) {\r\n logger.error('Constitution이 없습니다.');\r\n process.exit(ExitCode.FILE_NOT_FOUND);\r\n }\r\n\r\n const contentResult = await readFile(constitutionPath);\r\n if (!contentResult.success) {\r\n logger.error('Constitution 파일을 읽을 수 없습니다.');\r\n process.exit(ExitCode.FILE_SYSTEM_ERROR);\r\n }\r\n\r\n const parseResult = parseConstitution(contentResult.data);\r\n if (!parseResult.success) {\r\n logger.error(`Constitution 파싱 실패: ${parseResult.error.message}`);\r\n process.exit(ExitCode.VALIDATION_ERROR);\r\n }\r\n\r\n console.log(parseResult.data.metadata.version);\r\n}\r\n\r\n/**\r\n * 버전 범프\r\n */\r\nasync function runBump(options: { major?: boolean; minor?: boolean; patch?: boolean; message?: string }): Promise<void> {\r\n const cwd = process.cwd();\r\n const constitutionPath = path.join(cwd, '.sdd', 'constitution.md');\r\n const changelogPath = path.join(cwd, '.sdd', 'CHANGELOG.md');\r\n\r\n if (!(await fileExists(constitutionPath))) {\r\n logger.error('Constitution이 없습니다.');\r\n process.exit(ExitCode.FILE_NOT_FOUND);\r\n }\r\n\r\n // 버전 범프 유형 결정\r\n let bumpType: VersionBumpType;\r\n if (options.major) {\r\n bumpType = 'major';\r\n } else if (options.minor) {\r\n bumpType = 'minor';\r\n } else if (options.patch) {\r\n bumpType = 'patch';\r\n } else {\r\n logger.error('버전 유형을 지정하세요: --major, --minor, 또는 --patch');\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n // Constitution 읽기\r\n const contentResult = await readFile(constitutionPath);\r\n if (!contentResult.success) {\r\n logger.error('Constitution 파일을 읽을 수 없습니다.');\r\n process.exit(ExitCode.FILE_SYSTEM_ERROR);\r\n }\r\n\r\n const parseResult = parseConstitution(contentResult.data);\r\n if (!parseResult.success) {\r\n logger.error(`Constitution 파싱 실패: ${parseResult.error.message}`);\r\n process.exit(ExitCode.VALIDATION_ERROR);\r\n }\r\n\r\n const currentVersion = parseResult.data.metadata.version;\r\n const newVersion = bumpVersion(currentVersion, bumpType);\r\n const today = new Date().toISOString().split('T')[0];\r\n\r\n // Constitution 업데이트\r\n let updatedContent = contentResult.data;\r\n\r\n // version 업데이트\r\n updatedContent = updatedContent.replace(\r\n /^version:\\s*.+$/m,\r\n `version: ${newVersion}`\r\n );\r\n\r\n // updated 필드 추가/업데이트\r\n if (/^updated:/m.test(updatedContent)) {\r\n updatedContent = updatedContent.replace(\r\n /^updated:\\s*.+$/m,\r\n `updated: ${today}`\r\n );\r\n } else {\r\n updatedContent = updatedContent.replace(\r\n /^(version:\\s*.+)$/m,\r\n `$1\\nupdated: ${today}`\r\n );\r\n }\r\n\r\n await writeFile(constitutionPath, updatedContent);\r\n\r\n // CHANGELOG 업데이트\r\n const changeType: ChangeType = bumpType === 'major' ? 'changed' : bumpType === 'minor' ? 'added' : 'fixed';\r\n const changeDescription = options.message || `Constitution ${bumpType} 업데이트`;\r\n\r\n const newEntry = createChangelogEntry(\r\n currentVersion,\r\n bumpType,\r\n [{ type: changeType, description: changeDescription }],\r\n options.message\r\n );\r\n\r\n let existingEntries: ChangelogEntry[] = [];\r\n if (await fileExists(changelogPath)) {\r\n const changelogContent = await readFile(changelogPath);\r\n if (changelogContent.success) {\r\n const parsed = parseChangelog(changelogContent.data);\r\n if (parsed.success) {\r\n existingEntries = parsed.data;\r\n }\r\n }\r\n }\r\n\r\n const allEntries = [newEntry, ...existingEntries];\r\n const newChangelog = generateChangelog(allEntries);\r\n await writeFile(changelogPath, newChangelog);\r\n\r\n logger.success(`Constitution 버전 업데이트: ${currentVersion} → ${newVersion}`);\r\n logger.info(`CHANGELOG 업데이트: ${changelogPath}`);\r\n}\r\n\r\n/**\r\n * 변경 이력 조회\r\n */\r\nasync function runHistory(options: { count: string }): Promise<void> {\r\n const cwd = process.cwd();\r\n const changelogPath = path.join(cwd, '.sdd', 'CHANGELOG.md');\r\n\r\n if (!(await fileExists(changelogPath))) {\r\n logger.warn('CHANGELOG가 없습니다. `sdd constitution bump`로 버전을 업데이트하면 생성됩니다.');\r\n return;\r\n }\r\n\r\n const contentResult = await readFile(changelogPath);\r\n if (!contentResult.success) {\r\n logger.error('CHANGELOG 파일을 읽을 수 없습니다.');\r\n process.exit(ExitCode.FILE_SYSTEM_ERROR);\r\n }\r\n\r\n const parseResult = parseChangelog(contentResult.data);\r\n if (!parseResult.success) {\r\n logger.error(`CHANGELOG 파싱 실패: ${parseResult.error.message}`);\r\n process.exit(ExitCode.VALIDATION_ERROR);\r\n }\r\n\r\n const count = parseInt(options.count, 10) || 10;\r\n const entries = parseResult.data.slice(0, count);\r\n\r\n if (entries.length === 0) {\r\n logger.info('변경 이력이 없습니다.');\r\n return;\r\n }\r\n\r\n logger.info('Constitution 변경 이력:');\r\n logger.newline();\r\n\r\n for (const entry of entries) {\r\n logger.info(`[${entry.version}] - ${entry.date}`);\r\n for (const change of entry.changes) {\r\n logger.listItem(`[${change.type.toUpperCase()}] ${change.description}`);\r\n }\r\n if (entry.reason) {\r\n logger.listItem(`사유: ${entry.reason}`, 1);\r\n }\r\n logger.newline();\r\n }\r\n}\r\n\r\n/**\r\n * Constitution 검증\r\n */\r\nasync function runValidate(): Promise<void> {\r\n const cwd = process.cwd();\r\n const constitutionPath = path.join(cwd, '.sdd', 'constitution.md');\r\n\r\n if (!(await fileExists(constitutionPath))) {\r\n logger.error('Constitution이 없습니다.');\r\n process.exit(ExitCode.FILE_NOT_FOUND);\r\n }\r\n\r\n const contentResult = await readFile(constitutionPath);\r\n if (!contentResult.success) {\r\n logger.error('Constitution 파일을 읽을 수 없습니다.');\r\n process.exit(ExitCode.FILE_SYSTEM_ERROR);\r\n }\r\n\r\n const parseResult = parseConstitution(contentResult.data);\r\n if (!parseResult.success) {\r\n logger.error(`Constitution 파싱 실패: ${parseResult.error.message}`);\r\n process.exit(ExitCode.VALIDATION_ERROR);\r\n }\r\n\r\n const validationResult = validateConstitution(parseResult.data);\r\n if (!validationResult.success) {\r\n logger.error(`Constitution 검증 실패: ${validationResult.error.message}`);\r\n process.exit(ExitCode.VALIDATION_ERROR);\r\n }\r\n\r\n logger.success('Constitution 검증 통과');\r\n logger.info(`프로젝트: ${parseResult.data.projectName}`);\r\n logger.info(`버전: ${parseResult.data.metadata.version}`);\r\n logger.info(`원칙 수: ${parseResult.data.principles.length}`);\r\n logger.info(`금지 사항 수: ${parseResult.data.forbidden.length}`);\r\n}\r\n","/**\r\n * sdd start 명령어 - 통합 진입점\r\n *\r\n * 워크플로우 선택 메뉴를 제공하여 사용자가 쉽게 작업을 시작할 수 있도록 합니다.\r\n */\r\nimport { Command } from 'commander';\r\nimport path from 'node:path';\r\nimport { promises as fs } from 'node:fs';\r\nimport * as logger from '../../utils/logger.js';\r\nimport { ExitCode } from '../../errors/index.js';\r\nimport { findSddRoot, fileExists, readFile, directoryExists } from '../../utils/fs.js';\r\nimport { parseConstitution } from '../../core/constitution/index.js';\r\nimport { listPendingChanges } from '../../core/change/index.js';\r\n\r\n/**\r\n * 워크플로우 타입 정의\r\n */\r\nexport type WorkflowType =\r\n | 'new-feature'\r\n | 'change-spec'\r\n | 'validate'\r\n | 'status'\r\n | 'constitution';\r\n\r\n/**\r\n * 워크플로우 정보\r\n */\r\nexport interface WorkflowInfo {\r\n type: WorkflowType;\r\n name: string;\r\n description: string;\r\n command: string;\r\n available: boolean;\r\n reason?: string;\r\n}\r\n\r\n/**\r\n * 프로젝트 상태 정보\r\n */\r\nexport interface ProjectStatus {\r\n initialized: boolean;\r\n hasConstitution: boolean;\r\n constitutionVersion?: string;\r\n specCount: number;\r\n pendingChanges: number;\r\n specs: string[];\r\n}\r\n\r\n/**\r\n * start 명령어 등록\r\n */\r\nexport function registerStartCommand(program: Command): void {\r\n program\r\n .command('start')\r\n .description('SDD 워크플로우를 시작합니다 (통합 진입점)')\r\n .option('-w, --workflow <type>', '워크플로우 유형 (new-feature, change-spec, validate, status, constitution)')\r\n .option('--status', '프로젝트 상태만 표시')\r\n .action(async (options: { workflow?: WorkflowType; status?: boolean }) => {\r\n try {\r\n await runStart(options);\r\n } catch (error) {\r\n logger.error(error instanceof Error ? error.message : String(error));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n });\r\n}\r\n\r\n/**\r\n * start 명령어 실행\r\n */\r\nasync function runStart(options: { workflow?: WorkflowType; status?: boolean }): Promise<void> {\r\n // 프로젝트 상태 확인\r\n const projectStatus = await getProjectStatus();\r\n\r\n // 프로젝트가 초기화되지 않은 경우\r\n if (!projectStatus.initialized) {\r\n logger.info('SDD 프로젝트가 초기화되지 않았습니다.');\r\n logger.newline();\r\n logger.info('프로젝트를 시작하려면:');\r\n logger.listItem('sdd init');\r\n logger.newline();\r\n logger.info('또는 다음 슬래시 커맨드를 사용하세요:');\r\n logger.listItem('/sdd.new - 새 프로젝트와 함께 기능 생성');\r\n return;\r\n }\r\n\r\n // 상태만 표시\r\n if (options.status) {\r\n displayProjectStatus(projectStatus);\r\n return;\r\n }\r\n\r\n // 워크플로우가 지정된 경우 해당 워크플로우 안내\r\n if (options.workflow) {\r\n const workflow = getWorkflowInfo(options.workflow, projectStatus);\r\n displayWorkflowGuide(workflow);\r\n return;\r\n }\r\n\r\n // 기본: 전체 상태 + 워크플로우 메뉴\r\n displayProjectStatus(projectStatus);\r\n logger.newline();\r\n displayWorkflowMenu(projectStatus);\r\n}\r\n\r\n/**\r\n * 프로젝트 상태 조회\r\n */\r\nasync function getProjectStatus(): Promise<ProjectStatus> {\r\n const projectRoot = await findSddRoot();\r\n\r\n if (!projectRoot) {\r\n return {\r\n initialized: false,\r\n hasConstitution: false,\r\n specCount: 0,\r\n pendingChanges: 0,\r\n specs: [],\r\n };\r\n }\r\n\r\n const sddPath = path.join(projectRoot, '.sdd');\r\n const specsPath = path.join(sddPath, 'specs');\r\n\r\n // Constitution 확인\r\n let hasConstitution = false;\r\n let constitutionVersion: string | undefined;\r\n const constitutionPath = path.join(sddPath, 'constitution.md');\r\n\r\n if (await fileExists(constitutionPath)) {\r\n hasConstitution = true;\r\n const content = await readFile(constitutionPath);\r\n if (content.success) {\r\n const parsed = parseConstitution(content.data);\r\n if (parsed.success) {\r\n constitutionVersion = parsed.data.metadata.version;\r\n }\r\n }\r\n }\r\n\r\n // Spec 목록 조회\r\n const specs: string[] = [];\r\n if (await directoryExists(specsPath)) {\r\n try {\r\n const dirs = await fs.readdir(specsPath);\r\n for (const dir of dirs) {\r\n const specPath = path.join(specsPath, dir, 'spec.md');\r\n if (await fileExists(specPath)) {\r\n specs.push(dir);\r\n }\r\n }\r\n } catch {\r\n // ignore\r\n }\r\n }\r\n\r\n // 진행 중인 변경 조회\r\n let pendingChanges = 0;\r\n const changesResult = await listPendingChanges(sddPath);\r\n if (changesResult.success) {\r\n pendingChanges = changesResult.data.length;\r\n }\r\n\r\n return {\r\n initialized: true,\r\n hasConstitution,\r\n constitutionVersion,\r\n specCount: specs.length,\r\n pendingChanges,\r\n specs,\r\n };\r\n}\r\n\r\n/**\r\n * 프로젝트 상태 표시\r\n */\r\nfunction displayProjectStatus(status: ProjectStatus): void {\r\n logger.info('=== SDD 프로젝트 상태 ===');\r\n logger.newline();\r\n\r\n if (status.hasConstitution) {\r\n logger.info(`Constitution: v${status.constitutionVersion || '?.?.?'}`);\r\n } else {\r\n logger.warn('Constitution: 없음 (권장: sdd constitution 생성)');\r\n }\r\n\r\n logger.info(`명세 수: ${status.specCount}개`);\r\n if (status.specs.length > 0 && status.specs.length <= 5) {\r\n for (const spec of status.specs) {\r\n logger.listItem(spec, 1);\r\n }\r\n } else if (status.specs.length > 5) {\r\n for (const spec of status.specs.slice(0, 5)) {\r\n logger.listItem(spec, 1);\r\n }\r\n logger.listItem(`... 외 ${status.specs.length - 5}개`, 1);\r\n }\r\n\r\n if (status.pendingChanges > 0) {\r\n logger.warn(`진행 중인 변경: ${status.pendingChanges}개`);\r\n } else {\r\n logger.info('진행 중인 변경: 없음');\r\n }\r\n}\r\n\r\n/**\r\n * 워크플로우 메뉴 표시\r\n */\r\nfunction displayWorkflowMenu(status: ProjectStatus): void {\r\n logger.info('=== 사용 가능한 워크플로우 ===');\r\n logger.newline();\r\n\r\n const workflows: WorkflowInfo[] = [\r\n getWorkflowInfo('new-feature', status),\r\n getWorkflowInfo('change-spec', status),\r\n getWorkflowInfo('validate', status),\r\n getWorkflowInfo('status', status),\r\n getWorkflowInfo('constitution', status),\r\n ];\r\n\r\n for (const workflow of workflows) {\r\n if (workflow.available) {\r\n logger.info(`[${workflow.type}] ${workflow.name}`);\r\n logger.listItem(workflow.description, 1);\r\n logger.listItem(`명령어: ${workflow.command}`, 1);\r\n } else {\r\n logger.warn(`[${workflow.type}] ${workflow.name} (사용 불가)`);\r\n logger.listItem(workflow.reason || '조건 미충족', 1);\r\n }\r\n logger.newline();\r\n }\r\n\r\n logger.info('특정 워크플로우를 바로 시작하려면:');\r\n logger.listItem('sdd start --workflow <type>');\r\n logger.newline();\r\n logger.info('또는 Claude Code 슬래시 커맨드를 사용하세요:');\r\n logger.listItem('/sdd.new - 새 기능 명세');\r\n logger.listItem('/sdd.change - 기존 스펙 변경');\r\n logger.listItem('/sdd.validate - 명세 검증');\r\n}\r\n\r\n/**\r\n * 워크플로우 정보 조회\r\n */\r\nfunction getWorkflowInfo(type: WorkflowType, status: ProjectStatus): WorkflowInfo {\r\n switch (type) {\r\n case 'new-feature':\r\n return {\r\n type,\r\n name: '새 기능 명세',\r\n description: '새로운 기능의 명세를 작성합니다 (spec.md, plan.md, tasks.md)',\r\n command: 'sdd new <name>',\r\n available: true,\r\n };\r\n\r\n case 'change-spec':\r\n return {\r\n type,\r\n name: '기존 스펙 변경',\r\n description: '기존 명세에 대한 변경을 제안하고 관리합니다',\r\n command: 'sdd change',\r\n available: status.specCount > 0,\r\n reason: status.specCount === 0 ? '변경할 스펙이 없습니다' : undefined,\r\n };\r\n\r\n case 'validate':\r\n return {\r\n type,\r\n name: '명세 검증',\r\n description: '모든 명세 파일의 형식과 무결성을 검증합니다',\r\n command: 'sdd validate',\r\n available: status.specCount > 0 || status.hasConstitution,\r\n reason: status.specCount === 0 && !status.hasConstitution\r\n ? '검증할 명세가 없습니다'\r\n : undefined,\r\n };\r\n\r\n case 'status':\r\n return {\r\n type,\r\n name: '상태 확인',\r\n description: '전체 프로젝트 및 개별 스펙의 상태를 확인합니다',\r\n command: 'sdd status',\r\n available: true,\r\n };\r\n\r\n case 'constitution':\r\n return {\r\n type,\r\n name: 'Constitution 관리',\r\n description: '프로젝트 원칙(헌법)을 조회하고 관리합니다',\r\n command: 'sdd constitution',\r\n available: true,\r\n };\r\n\r\n default:\r\n return {\r\n type,\r\n name: '알 수 없는 워크플로우',\r\n description: '',\r\n command: '',\r\n available: false,\r\n reason: '알 수 없는 워크플로우 유형입니다',\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * 워크플로우 가이드 표시\r\n */\r\nfunction displayWorkflowGuide(workflow: WorkflowInfo): void {\r\n logger.info(`=== ${workflow.name} ===`);\r\n logger.newline();\r\n\r\n if (!workflow.available) {\r\n logger.error(`이 워크플로우는 현재 사용할 수 없습니다: ${workflow.reason}`);\r\n return;\r\n }\r\n\r\n logger.info(workflow.description);\r\n logger.newline();\r\n\r\n switch (workflow.type) {\r\n case 'new-feature':\r\n displayNewFeatureGuide();\r\n break;\r\n case 'change-spec':\r\n displayChangeSpecGuide();\r\n break;\r\n case 'validate':\r\n displayValidateGuide();\r\n break;\r\n case 'status':\r\n displayStatusGuide();\r\n break;\r\n case 'constitution':\r\n displayConstitutionGuide();\r\n break;\r\n }\r\n}\r\n\r\n/**\r\n * 새 기능 워크플로우 가이드\r\n */\r\nfunction displayNewFeatureGuide(): void {\r\n logger.info('단계:');\r\n logger.listItem('1. sdd new <name> - 명세 파일 생성');\r\n logger.listItem('2. spec.md 편집 - 요구사항 및 시나리오 작성');\r\n logger.listItem('3. sdd new plan <id> - 구현 계획 작성');\r\n logger.listItem('4. sdd new tasks <id> - 작업 분해');\r\n logger.listItem('5. 구현 진행');\r\n logger.newline();\r\n logger.info('Claude Code 슬래시 커맨드:');\r\n logger.listItem('/sdd.new - 대화형 명세 작성');\r\n logger.listItem('/sdd.plan - 구현 계획 수립');\r\n logger.listItem('/sdd.tasks - 작업 분해');\r\n logger.listItem('/sdd.implement - 구현 진행');\r\n logger.newline();\r\n logger.info('옵션:');\r\n logger.listItem('--all : spec, plan, tasks 모두 생성');\r\n logger.listItem('--no-branch : Git 브랜치 생성 안 함');\r\n}\r\n\r\n/**\r\n * 변경 워크플로우 가이드\r\n */\r\nfunction displayChangeSpecGuide(): void {\r\n logger.info('단계:');\r\n logger.listItem('1. sdd change -t \"변경 제목\" - 변경 제안 생성');\r\n logger.listItem('2. proposal.md 편집 - 변경 배경 및 내용 작성');\r\n logger.listItem('3. delta.md 편집 - ADDED/MODIFIED/REMOVED 작성');\r\n logger.listItem('4. sdd change validate <id> - 제안 검증');\r\n logger.listItem('5. sdd change apply <id> - 변경 적용');\r\n logger.listItem('6. sdd change archive <id> - 완료 후 아카이브');\r\n logger.newline();\r\n logger.info('Claude Code 슬래시 커맨드:');\r\n logger.listItem('/sdd.change - 변경 제안 작성');\r\n logger.newline();\r\n logger.info('명령어:');\r\n logger.listItem('sdd change -l : 진행 중인 변경 목록');\r\n logger.listItem('sdd change <id> : 특정 변경 조회');\r\n logger.listItem('sdd change diff <id> : 변경 내용 diff');\r\n}\r\n\r\n/**\r\n * 검증 워크플로우 가이드\r\n */\r\nfunction displayValidateGuide(): void {\r\n logger.info('사용법:');\r\n logger.listItem('sdd validate : 전체 검증');\r\n logger.listItem('sdd validate <id> : 특정 스펙 검증');\r\n logger.listItem('sdd validate --strict : 엄격 모드');\r\n logger.newline();\r\n logger.info('검증 항목:');\r\n logger.listItem('- frontmatter 형식');\r\n logger.listItem('- RFC 2119 키워드 사용');\r\n logger.listItem('- GIVEN-WHEN-THEN 시나리오');\r\n logger.listItem('- 의존성 참조');\r\n logger.newline();\r\n logger.info('Claude Code 슬래시 커맨드:');\r\n logger.listItem('/sdd.validate - 검증 및 피드백');\r\n}\r\n\r\n/**\r\n * 상태 확인 워크플로우 가이드\r\n */\r\nfunction displayStatusGuide(): void {\r\n logger.info('사용법:');\r\n logger.listItem('sdd status : 프로젝트 전체 상태');\r\n logger.listItem('sdd status <id> : 특정 스펙 상태');\r\n logger.newline();\r\n logger.info('Claude Code 슬래시 커맨드:');\r\n logger.listItem('/sdd.status - 상태 리포트');\r\n}\r\n\r\n/**\r\n * Constitution 워크플로우 가이드\r\n */\r\nfunction displayConstitutionGuide(): void {\r\n logger.info('사용법:');\r\n logger.listItem('sdd constitution : Constitution 표시');\r\n logger.listItem('sdd constitution version : 버전 확인');\r\n logger.listItem('sdd constitution bump : 버전 업데이트');\r\n logger.listItem('sdd constitution history : 변경 이력');\r\n logger.listItem('sdd constitution validate : 형식 검증');\r\n logger.newline();\r\n logger.info('버전 업데이트:');\r\n logger.listItem('--major : 주요 변경 (원칙 삭제 등)');\r\n logger.listItem('--minor : 기능 추가');\r\n logger.listItem('--patch : 오타/명확화');\r\n logger.newline();\r\n logger.info('Claude Code 슬래시 커맨드:');\r\n logger.listItem('/sdd.constitution - Constitution 관리');\r\n}\r\n","/**\r\n * sdd migrate 명령어\r\n *\r\n * 기존 문서나 코드를 SDD 형식으로 마이그레이션합니다.\r\n */\r\nimport { Command } from 'commander';\r\nimport path from 'node:path';\r\nimport { promises as fs } from 'node:fs';\r\nimport * as logger from '../../utils/logger.js';\r\nimport { ExitCode } from '../../errors/index.js';\r\nimport { findSddRoot, fileExists, ensureDir, writeFile, directoryExists } from '../../utils/fs.js';\r\nimport { generateSpec } from '../../core/new/index.js';\r\nimport { generateFeatureId } from '../../core/new/schemas.js';\r\nimport {\r\n detectExternalTools,\r\n migrateFromOpenSpec,\r\n migrateFromSpecKit,\r\n DetectionResult,\r\n} from '../../core/migrate/index.js';\r\n\r\n/**\r\n * 마이그레이션 결과\r\n */\r\ninterface MigrationResult {\r\n source: string;\r\n target: string;\r\n success: boolean;\r\n error?: string;\r\n}\r\n\r\n/**\r\n * 마이그레이션 요약\r\n */\r\ninterface MigrationSummary {\r\n total: number;\r\n succeeded: number;\r\n failed: number;\r\n results: MigrationResult[];\r\n}\r\n\r\n/**\r\n * 문서 분석 결과\r\n */\r\ninterface DocumentAnalysis {\r\n title: string;\r\n description: string;\r\n requirements: string[];\r\n scenarios: Array<{\r\n name: string;\r\n given: string;\r\n when: string;\r\n then: string;\r\n }>;\r\n hasRfc2119: boolean;\r\n hasScenarios: boolean;\r\n}\r\n\r\n/**\r\n * migrate 명령어 등록\r\n */\r\nexport function registerMigrateCommand(program: Command): void {\r\n const migrate = program\r\n .command('migrate')\r\n .description('기존 문서를 SDD 형식으로 마이그레이션합니다');\r\n\r\n // docs 서브커맨드 - 문서 마이그레이션\r\n migrate\r\n .command('docs <source>')\r\n .description('마크다운 문서를 spec.md 형식으로 변환합니다')\r\n .option('-o, --output <dir>', '출력 디렉토리')\r\n .option('--dry-run', '실제 파일 생성 없이 미리보기')\r\n .action(async (source: string, options: { output?: string; dryRun?: boolean }) => {\r\n try {\r\n await runMigrateDocs(source, options);\r\n } catch (error) {\r\n logger.error(error instanceof Error ? error.message : String(error));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n });\r\n\r\n // analyze 서브커맨드 - 문서 분석\r\n migrate\r\n .command('analyze <file>')\r\n .description('문서를 분석하여 SDD 호환성을 확인합니다')\r\n .action(async (file: string) => {\r\n try {\r\n await runAnalyze(file);\r\n } catch (error) {\r\n logger.error(error instanceof Error ? error.message : String(error));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n });\r\n\r\n // scan 서브커맨드 - 디렉토리 스캔\r\n migrate\r\n .command('scan [dir]')\r\n .description('디렉토리에서 마이그레이션 가능한 문서를 스캔합니다')\r\n .option('--ext <extensions>', '파일 확장자 (기본: .md)')\r\n .action(async (dir: string | undefined, options: { ext?: string }) => {\r\n try {\r\n await runScan(dir || '.', options);\r\n } catch (error) {\r\n logger.error(error instanceof Error ? error.message : String(error));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n });\r\n\r\n // detect 서브커맨드 - 외부 도구 감지\r\n migrate\r\n .command('detect')\r\n .description('프로젝트에서 외부 SDD 도구를 감지합니다')\r\n .option('-p, --path <path>', '검색 경로')\r\n .action(async (options: { path?: string }) => {\r\n try {\r\n await runDetect(options);\r\n } catch (error) {\r\n logger.error(error instanceof Error ? error.message : String(error));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n });\r\n\r\n // openspec 서브커맨드 - OpenSpec에서 마이그레이션\r\n migrate\r\n .command('openspec [source]')\r\n .description('OpenSpec 프로젝트에서 마이그레이션합니다')\r\n .option('--dry-run', '실제 파일 생성 없이 미리보기')\r\n .option('--overwrite', '기존 스펙 덮어쓰기')\r\n .action(async (source: string | undefined, options: { dryRun?: boolean; overwrite?: boolean }) => {\r\n try {\r\n await runMigrateOpenSpec(source, options);\r\n } catch (error) {\r\n logger.error(error instanceof Error ? error.message : String(error));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n });\r\n\r\n // speckit 서브커맨드 - Spec Kit에서 마이그레이션\r\n migrate\r\n .command('speckit [source]')\r\n .description('Spec Kit 프로젝트에서 마이그레이션합니다')\r\n .option('--dry-run', '실제 파일 생성 없이 미리보기')\r\n .option('--overwrite', '기존 스펙 덮어쓰기')\r\n .action(async (source: string | undefined, options: { dryRun?: boolean; overwrite?: boolean }) => {\r\n try {\r\n await runMigrateSpecKit(source, options);\r\n } catch (error) {\r\n logger.error(error instanceof Error ? error.message : String(error));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n });\r\n}\r\n\r\n/**\r\n * 문서 마이그레이션 실행\r\n */\r\nasync function runMigrateDocs(\r\n source: string,\r\n options: { output?: string; dryRun?: boolean }\r\n): Promise<void> {\r\n const projectRoot = await findSddRoot();\r\n if (!projectRoot && !options.output) {\r\n logger.error('SDD 프로젝트를 찾을 수 없습니다. --output 옵션을 사용하거나 sdd init을 먼저 실행하세요.');\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n const sourcePath = path.resolve(source);\r\n\r\n // 파일 또는 디렉토리 확인\r\n let files: string[] = [];\r\n try {\r\n const stat = await fs.stat(sourcePath);\r\n if (stat.isDirectory()) {\r\n files = await collectMarkdownFiles(sourcePath);\r\n } else if (stat.isFile()) {\r\n files = [sourcePath];\r\n }\r\n } catch {\r\n logger.error(`소스를 찾을 수 없습니다: ${source}`);\r\n process.exit(ExitCode.FILE_SYSTEM_ERROR);\r\n }\r\n\r\n if (files.length === 0) {\r\n logger.info('마이그레이션할 마크다운 파일이 없습니다.');\r\n return;\r\n }\r\n\r\n logger.info(`${files.length}개 파일 발견`);\r\n logger.newline();\r\n\r\n const outputDir = options.output\r\n ? path.resolve(options.output)\r\n : path.join(projectRoot!, '.sdd', 'specs');\r\n\r\n const summary: MigrationSummary = {\r\n total: files.length,\r\n succeeded: 0,\r\n failed: 0,\r\n results: [],\r\n };\r\n\r\n for (const file of files) {\r\n const result = await migrateDocument(file, outputDir, options.dryRun || false);\r\n summary.results.push(result);\r\n if (result.success) {\r\n summary.succeeded++;\r\n logger.info(`✅ ${path.basename(file)} → ${result.target}`);\r\n } else {\r\n summary.failed++;\r\n logger.error(`❌ ${path.basename(file)}: ${result.error}`);\r\n }\r\n }\r\n\r\n logger.newline();\r\n logger.info('=== 마이그레이션 완료 ===');\r\n logger.info(`총: ${summary.total}개, 성공: ${summary.succeeded}개, 실패: ${summary.failed}개`);\r\n\r\n if (options.dryRun) {\r\n logger.warn('(dry-run 모드: 실제 파일이 생성되지 않았습니다)');\r\n }\r\n}\r\n\r\n/**\r\n * 단일 문서 마이그레이션\r\n */\r\nasync function migrateDocument(\r\n filePath: string,\r\n outputDir: string,\r\n dryRun: boolean\r\n): Promise<MigrationResult> {\r\n try {\r\n const content = await fs.readFile(filePath, 'utf-8');\r\n const analysis = analyzeDocument(content);\r\n\r\n // spec.md 생성\r\n const featureId = generateFeatureId(analysis.title || path.basename(filePath, '.md'));\r\n const specContent = generateSpec({\r\n id: featureId,\r\n title: analysis.title || path.basename(filePath, '.md'),\r\n description: analysis.description || '',\r\n requirements: analysis.requirements,\r\n scenarios: analysis.scenarios,\r\n });\r\n\r\n const targetDir = path.join(outputDir, featureId);\r\n const targetPath = path.join(targetDir, 'spec.md');\r\n\r\n if (!dryRun) {\r\n await ensureDir(targetDir);\r\n await writeFile(targetPath, specContent);\r\n }\r\n\r\n return {\r\n source: filePath,\r\n target: path.relative(process.cwd(), targetPath),\r\n success: true,\r\n };\r\n } catch (error) {\r\n return {\r\n source: filePath,\r\n target: '',\r\n success: false,\r\n error: error instanceof Error ? error.message : String(error),\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * 문서 분석\r\n */\r\nfunction analyzeDocument(content: string): DocumentAnalysis {\r\n // 제목 추출\r\n const titleMatch = content.match(/^#\\s+(.+)$/m);\r\n const title = titleMatch ? titleMatch[1].trim() : '';\r\n\r\n // 설명 추출 (첫 번째 단락)\r\n const descMatch = content.match(/^#[^\\n]+\\n\\n([^#]+)/m);\r\n const description = descMatch ? descMatch[1].trim().split('\\n')[0] : '';\r\n\r\n // 요구사항 추출\r\n const requirements: string[] = [];\r\n const reqMatches = content.matchAll(/(?:SHALL|MUST|SHOULD|MAY|SHALL NOT|MUST NOT)[^.]+\\./gi);\r\n for (const match of reqMatches) {\r\n requirements.push(match[0].trim());\r\n }\r\n\r\n // 시나리오 추출\r\n const scenarios: DocumentAnalysis['scenarios'] = [];\r\n const givenWhenThen = content.matchAll(\r\n /(?:GIVEN|Given|given)[:\\s]+([^\\n]+)\\n.*?(?:WHEN|When|when)[:\\s]+([^\\n]+)\\n.*?(?:THEN|Then|then)[:\\s]+([^\\n]+)/gi\r\n );\r\n for (const match of givenWhenThen) {\r\n scenarios.push({\r\n name: `Scenario ${scenarios.length + 1}`,\r\n given: match[1].trim(),\r\n when: match[2].trim(),\r\n then: match[3].trim(),\r\n });\r\n }\r\n\r\n // RFC 2119 키워드 확인\r\n const hasRfc2119 = /\\b(SHALL|MUST|SHOULD|MAY|SHALL NOT|MUST NOT)\\b/.test(content);\r\n\r\n return {\r\n title,\r\n description,\r\n requirements,\r\n scenarios,\r\n hasRfc2119,\r\n hasScenarios: scenarios.length > 0,\r\n };\r\n}\r\n\r\n/**\r\n * 문서 분석 실행\r\n */\r\nasync function runAnalyze(file: string): Promise<void> {\r\n const filePath = path.resolve(file);\r\n\r\n if (!(await fileExists(filePath))) {\r\n logger.error(`파일을 찾을 수 없습니다: ${file}`);\r\n process.exit(ExitCode.FILE_SYSTEM_ERROR);\r\n }\r\n\r\n const content = await fs.readFile(filePath, 'utf-8');\r\n const analysis = analyzeDocument(content);\r\n\r\n logger.info(`📊 문서 분석: ${path.basename(file)}`);\r\n logger.newline();\r\n\r\n logger.info(`제목: ${analysis.title || '(없음)'}`);\r\n logger.info(`설명: ${analysis.description || '(없음)'}`);\r\n logger.newline();\r\n\r\n logger.info('SDD 호환성:');\r\n const rfc2119Icon = analysis.hasRfc2119 ? '✅' : '❌';\r\n logger.listItem(`${rfc2119Icon} RFC 2119 키워드: ${analysis.requirements.length}개`);\r\n\r\n const scenarioIcon = analysis.hasScenarios ? '✅' : '❌';\r\n logger.listItem(`${scenarioIcon} GIVEN-WHEN-THEN 시나리오: ${analysis.scenarios.length}개`);\r\n logger.newline();\r\n\r\n if (analysis.requirements.length > 0) {\r\n logger.info('발견된 요구사항:');\r\n for (const req of analysis.requirements.slice(0, 5)) {\r\n logger.listItem(req.substring(0, 80) + (req.length > 80 ? '...' : ''), 1);\r\n }\r\n if (analysis.requirements.length > 5) {\r\n logger.info(` ... 외 ${analysis.requirements.length - 5}개`);\r\n }\r\n logger.newline();\r\n }\r\n\r\n if (analysis.scenarios.length > 0) {\r\n logger.info('발견된 시나리오:');\r\n for (const scenario of analysis.scenarios) {\r\n logger.listItem(`GIVEN ${scenario.given}`, 1);\r\n logger.listItem(`WHEN ${scenario.when}`, 1);\r\n logger.listItem(`THEN ${scenario.then}`, 1);\r\n }\r\n logger.newline();\r\n }\r\n\r\n // 마이그레이션 권장사항\r\n logger.info('💡 권장사항:');\r\n if (!analysis.hasRfc2119) {\r\n logger.listItem('RFC 2119 키워드(SHALL, MUST, SHOULD 등)를 추가하세요.', 1);\r\n }\r\n if (!analysis.hasScenarios) {\r\n logger.listItem('GIVEN-WHEN-THEN 형식의 시나리오를 추가하세요.', 1);\r\n }\r\n if (analysis.hasRfc2119 && analysis.hasScenarios) {\r\n logger.listItem('이 문서는 SDD 형식으로 마이그레이션하기에 적합합니다!', 1);\r\n logger.listItem('`sdd migrate docs ' + file + '`로 마이그레이션하세요.', 1);\r\n }\r\n}\r\n\r\n/**\r\n * 디렉토리 스캔 실행\r\n */\r\nasync function runScan(dir: string, options: { ext?: string }): Promise<void> {\r\n const dirPath = path.resolve(dir);\r\n\r\n if (!(await directoryExists(dirPath))) {\r\n logger.error(`디렉토리를 찾을 수 없습니다: ${dir}`);\r\n process.exit(ExitCode.FILE_SYSTEM_ERROR);\r\n }\r\n\r\n const extensions = (options.ext || '.md').split(',').map((e) => e.trim());\r\n const files = await collectFilesWithExtensions(dirPath, extensions);\r\n\r\n if (files.length === 0) {\r\n logger.info(`마이그레이션 가능한 파일이 없습니다 (확장자: ${extensions.join(', ')})`);\r\n return;\r\n }\r\n\r\n logger.info(`📂 스캔 결과: ${dir}`);\r\n logger.newline();\r\n\r\n const results: Array<{ file: string; analysis: DocumentAnalysis }> = [];\r\n\r\n for (const file of files) {\r\n try {\r\n const content = await fs.readFile(file, 'utf-8');\r\n const analysis = analyzeDocument(content);\r\n results.push({ file, analysis });\r\n } catch {\r\n // 읽기 실패 무시\r\n }\r\n }\r\n\r\n // 적합도 순으로 정렬\r\n results.sort((a, b) => {\r\n const scoreA = (a.analysis.hasRfc2119 ? 2 : 0) + (a.analysis.hasScenarios ? 2 : 0) + a.analysis.requirements.length;\r\n const scoreB = (b.analysis.hasRfc2119 ? 2 : 0) + (b.analysis.hasScenarios ? 2 : 0) + b.analysis.requirements.length;\r\n return scoreB - scoreA;\r\n });\r\n\r\n // 결과 표시\r\n const ready: string[] = [];\r\n const partial: string[] = [];\r\n const notReady: string[] = [];\r\n\r\n for (const { file, analysis } of results) {\r\n const relativePath = path.relative(process.cwd(), file);\r\n if (analysis.hasRfc2119 && analysis.hasScenarios) {\r\n ready.push(relativePath);\r\n } else if (analysis.hasRfc2119 || analysis.hasScenarios || analysis.requirements.length > 0) {\r\n partial.push(relativePath);\r\n } else {\r\n notReady.push(relativePath);\r\n }\r\n }\r\n\r\n if (ready.length > 0) {\r\n logger.info('🟢 마이그레이션 준비됨:');\r\n for (const file of ready) {\r\n logger.listItem(file, 1);\r\n }\r\n logger.newline();\r\n }\r\n\r\n if (partial.length > 0) {\r\n logger.info('🟡 일부 수정 필요:');\r\n for (const file of partial) {\r\n logger.listItem(file, 1);\r\n }\r\n logger.newline();\r\n }\r\n\r\n if (notReady.length > 0) {\r\n logger.info('🔴 추가 작업 필요:');\r\n for (const file of notReady.slice(0, 10)) {\r\n logger.listItem(file, 1);\r\n }\r\n if (notReady.length > 10) {\r\n logger.info(` ... 외 ${notReady.length - 10}개`);\r\n }\r\n logger.newline();\r\n }\r\n\r\n logger.info('=== 요약 ===');\r\n logger.info(`총: ${results.length}개, 준비됨: ${ready.length}개, 일부: ${partial.length}개, 미준비: ${notReady.length}개`);\r\n logger.newline();\r\n\r\n if (ready.length > 0) {\r\n logger.info('다음 명령어로 마이그레이션을 시작하세요:');\r\n logger.listItem(`sdd migrate docs ${ready[0]}`);\r\n }\r\n}\r\n\r\n/**\r\n * 마크다운 파일 수집\r\n */\r\nasync function collectMarkdownFiles(dirPath: string): Promise<string[]> {\r\n return collectFilesWithExtensions(dirPath, ['.md']);\r\n}\r\n\r\n/**\r\n * 특정 확장자 파일 수집\r\n */\r\nasync function collectFilesWithExtensions(dirPath: string, extensions: string[]): Promise<string[]> {\r\n const files: string[] = [];\r\n\r\n async function scan(dir: string): Promise<void> {\r\n const entries = await fs.readdir(dir, { withFileTypes: true });\r\n\r\n for (const entry of entries) {\r\n const fullPath = path.join(dir, entry.name);\r\n\r\n // 무시할 디렉토리\r\n if (entry.isDirectory()) {\r\n if (!['node_modules', '.git', '.sdd', 'dist', 'build'].includes(entry.name)) {\r\n await scan(fullPath);\r\n }\r\n } else if (entry.isFile()) {\r\n const ext = path.extname(entry.name).toLowerCase();\r\n if (extensions.some((e) => e.toLowerCase() === ext)) {\r\n // AGENTS.md, README.md 등은 제외\r\n if (!['agents.md', 'readme.md', 'changelog.md', 'license.md'].includes(entry.name.toLowerCase())) {\r\n files.push(fullPath);\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n await scan(dirPath);\r\n return files;\r\n}\r\n\r\n/**\r\n * 외부 도구 감지 실행\r\n */\r\nasync function runDetect(options: { path?: string }): Promise<void> {\r\n const projectRoot = options.path ? path.resolve(options.path) : process.cwd();\r\n\r\n logger.info('🔍 외부 SDD 도구 감지 중...');\r\n logger.info(` 경로: ${projectRoot}`);\r\n logger.newline();\r\n\r\n const result = await detectExternalTools(projectRoot);\r\n\r\n if (!result.success) {\r\n logger.error(result.error.message);\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n const tools = result.data;\r\n\r\n if (tools.length === 0) {\r\n logger.info('감지된 외부 SDD 도구가 없습니다.');\r\n return;\r\n }\r\n\r\n for (const tool of tools) {\r\n const icon = getToolIcon(tool.tool);\r\n const confidence = getConfidenceLabel(tool.confidence);\r\n\r\n logger.info(`${icon} ${getToolName(tool.tool)}`);\r\n logger.info(` 경로: ${tool.path}`);\r\n logger.info(` 신뢰도: ${confidence}`);\r\n logger.info(` 스펙 수: ${tool.specCount}개`);\r\n\r\n if (tool.specs.length > 0) {\r\n logger.newline();\r\n logger.info(' 발견된 스펙:');\r\n for (const spec of tool.specs.slice(0, 5)) {\r\n const status = spec.status ? ` [${spec.status}]` : '';\r\n logger.listItem(`${spec.id}: ${spec.title || '(제목 없음)'}${status}`, 2);\r\n }\r\n if (tool.specs.length > 5) {\r\n logger.info(` ... 외 ${tool.specs.length - 5}개`);\r\n }\r\n }\r\n\r\n logger.newline();\r\n }\r\n\r\n // 마이그레이션 안내\r\n const openspec = tools.find(t => t.tool === 'openspec');\r\n const speckit = tools.find(t => t.tool === 'speckit');\r\n\r\n if (openspec || speckit) {\r\n logger.info('💡 마이그레이션 명령어:');\r\n if (openspec) {\r\n logger.listItem(`sdd migrate openspec \"${openspec.path}\"`, 1);\r\n }\r\n if (speckit) {\r\n logger.listItem(`sdd migrate speckit \"${speckit.path}\"`, 1);\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * OpenSpec에서 마이그레이션 실행\r\n */\r\nasync function runMigrateOpenSpec(\r\n source: string | undefined,\r\n options: { dryRun?: boolean; overwrite?: boolean }\r\n): Promise<void> {\r\n const projectRoot = await findSddRoot();\r\n if (!projectRoot) {\r\n logger.error('SDD 프로젝트를 찾을 수 없습니다. `sdd init`을 먼저 실행하세요.');\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n // 소스 경로 결정\r\n let sourcePath: string;\r\n if (source) {\r\n sourcePath = path.resolve(source);\r\n } else {\r\n // 자동 감지\r\n const detectResult = await detectExternalTools(projectRoot);\r\n if (!detectResult.success) {\r\n logger.error(detectResult.error.message);\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n const openspec = detectResult.data.find(t => t.tool === 'openspec');\r\n if (!openspec) {\r\n logger.error('OpenSpec 프로젝트를 찾을 수 없습니다. 경로를 직접 지정하세요.');\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n sourcePath = openspec.path;\r\n }\r\n\r\n const sddPath = path.join(projectRoot, '.sdd');\r\n\r\n logger.info('🔄 OpenSpec에서 마이그레이션 중...');\r\n logger.info(` 소스: ${sourcePath}`);\r\n logger.info(` 대상: ${sddPath}`);\r\n if (options.dryRun) {\r\n logger.warn(' (dry-run 모드)');\r\n }\r\n logger.newline();\r\n\r\n const result = await migrateFromOpenSpec(sourcePath, sddPath, {\r\n dryRun: options.dryRun,\r\n overwrite: options.overwrite,\r\n });\r\n\r\n if (!result.success) {\r\n logger.error(result.error.message);\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n const data = result.data;\r\n\r\n logger.success('✅ 마이그레이션 완료');\r\n logger.info(` 생성: ${data.specsCreated}개`);\r\n logger.info(` 스킵: ${data.specsSkipped}개`);\r\n\r\n if (data.errors.length > 0) {\r\n logger.newline();\r\n logger.warn('⚠️ 일부 오류 발생:');\r\n for (const error of data.errors) {\r\n logger.error(` - ${error}`);\r\n }\r\n }\r\n\r\n if (options.dryRun) {\r\n logger.newline();\r\n logger.info('실제 마이그레이션을 수행하려면 --dry-run 옵션을 제거하세요.');\r\n }\r\n}\r\n\r\n/**\r\n * Spec Kit에서 마이그레이션 실행\r\n */\r\nasync function runMigrateSpecKit(\r\n source: string | undefined,\r\n options: { dryRun?: boolean; overwrite?: boolean }\r\n): Promise<void> {\r\n const projectRoot = await findSddRoot();\r\n if (!projectRoot) {\r\n logger.error('SDD 프로젝트를 찾을 수 없습니다. `sdd init`을 먼저 실행하세요.');\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n // 소스 경로 결정\r\n let sourcePath: string;\r\n if (source) {\r\n sourcePath = path.resolve(source);\r\n } else {\r\n // 자동 감지\r\n const detectResult = await detectExternalTools(projectRoot);\r\n if (!detectResult.success) {\r\n logger.error(detectResult.error.message);\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n const speckit = detectResult.data.find(t => t.tool === 'speckit');\r\n if (!speckit) {\r\n logger.error('Spec Kit 프로젝트를 찾을 수 없습니다. 경로를 직접 지정하세요.');\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n sourcePath = speckit.path;\r\n }\r\n\r\n const sddPath = path.join(projectRoot, '.sdd');\r\n\r\n logger.info('🔄 Spec Kit에서 마이그레이션 중...');\r\n logger.info(` 소스: ${sourcePath}`);\r\n logger.info(` 대상: ${sddPath}`);\r\n if (options.dryRun) {\r\n logger.warn(' (dry-run 모드)');\r\n }\r\n logger.newline();\r\n\r\n const result = await migrateFromSpecKit(sourcePath, sddPath, {\r\n dryRun: options.dryRun,\r\n overwrite: options.overwrite,\r\n });\r\n\r\n if (!result.success) {\r\n logger.error(result.error.message);\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n const data = result.data;\r\n\r\n logger.success('✅ 마이그레이션 완료');\r\n logger.info(` 생성: ${data.specsCreated}개`);\r\n logger.info(` 스킵: ${data.specsSkipped}개`);\r\n\r\n if (data.errors.length > 0) {\r\n logger.newline();\r\n logger.warn('⚠️ 일부 오류 발생:');\r\n for (const error of data.errors) {\r\n logger.error(` - ${error}`);\r\n }\r\n }\r\n\r\n if (options.dryRun) {\r\n logger.newline();\r\n logger.info('실제 마이그레이션을 수행하려면 --dry-run 옵션을 제거하세요.');\r\n }\r\n}\r\n\r\n/**\r\n * 도구 아이콘 반환\r\n */\r\nfunction getToolIcon(tool: string): string {\r\n switch (tool) {\r\n case 'openspec': return '📦';\r\n case 'speckit': return '🔧';\r\n case 'sdd': return '📋';\r\n default: return '❓';\r\n }\r\n}\r\n\r\n/**\r\n * 도구 이름 반환\r\n */\r\nfunction getToolName(tool: string): string {\r\n switch (tool) {\r\n case 'openspec': return 'OpenSpec';\r\n case 'speckit': return 'Spec Kit';\r\n case 'sdd': return 'SDD';\r\n default: return tool;\r\n }\r\n}\r\n\r\n/**\r\n * 신뢰도 레이블 반환\r\n */\r\nfunction getConfidenceLabel(confidence: string): string {\r\n switch (confidence) {\r\n case 'high': return '높음 ✓';\r\n case 'medium': return '중간';\r\n case 'low': return '낮음';\r\n default: return confidence;\r\n }\r\n}\r\n","/**\r\n * 외부 SDD 도구 감지 모듈\r\n *\r\n * OpenSpec, Spec Kit 등 외부 SDD 도구를 감지합니다.\r\n */\r\nimport path from 'node:path';\r\nimport fs from 'node:fs/promises';\r\nimport { Result, success, failure } from '../../types/index.js';\r\nimport { ChangeError } from '../../errors/index.js';\r\nimport { directoryExists, fileExists } from '../../utils/fs.js';\r\n\r\n/**\r\n * 도구 종류\r\n */\r\nexport type ToolType = 'openspec' | 'speckit' | 'sdd' | 'unknown';\r\n\r\n/**\r\n * 감지 결과\r\n */\r\nexport interface DetectionResult {\r\n tool: ToolType;\r\n path: string;\r\n version?: string;\r\n specCount: number;\r\n specs: SpecInfo[];\r\n confidence: 'high' | 'medium' | 'low';\r\n}\r\n\r\n/**\r\n * 스펙 정보\r\n */\r\nexport interface SpecInfo {\r\n id: string;\r\n title?: string;\r\n path: string;\r\n status?: string;\r\n}\r\n\r\n/**\r\n * 마이그레이션 옵션\r\n */\r\nexport interface MigrationOptions {\r\n dryRun?: boolean;\r\n overwrite?: boolean;\r\n preserveStatus?: boolean;\r\n}\r\n\r\n/**\r\n * 마이그레이션 결과\r\n */\r\nexport interface MigrationResult {\r\n source: ToolType;\r\n targetPath: string;\r\n specsCreated: number;\r\n specsSkipped: number;\r\n errors: string[];\r\n}\r\n\r\n/**\r\n * 외부 도구 감지\r\n */\r\nexport async function detectExternalTools(\r\n projectRoot: string\r\n): Promise<Result<DetectionResult[], ChangeError>> {\r\n try {\r\n const results: DetectionResult[] = [];\r\n\r\n // OpenSpec 감지\r\n const openspecResult = await detectOpenSpec(projectRoot);\r\n if (openspecResult) {\r\n results.push(openspecResult);\r\n }\r\n\r\n // Spec Kit 감지\r\n const speckitResult = await detectSpecKit(projectRoot);\r\n if (speckitResult) {\r\n results.push(speckitResult);\r\n }\r\n\r\n // 기존 SDD 감지\r\n const sddResult = await detectSdd(projectRoot);\r\n if (sddResult) {\r\n results.push(sddResult);\r\n }\r\n\r\n return success(results);\r\n } catch (error) {\r\n return failure(new ChangeError(error instanceof Error ? error.message : String(error)));\r\n }\r\n}\r\n\r\n/**\r\n * OpenSpec 감지\r\n */\r\nasync function detectOpenSpec(projectRoot: string): Promise<DetectionResult | null> {\r\n // openspec/ 디렉토리 확인\r\n const openspecPath = path.join(projectRoot, 'openspec');\r\n if (!(await directoryExists(openspecPath))) {\r\n return null;\r\n }\r\n\r\n const specsPath = path.join(openspecPath, 'specs');\r\n const changesPath = path.join(openspecPath, 'changes');\r\n const agentsPath = path.join(openspecPath, 'AGENTS.md');\r\n\r\n // AGENTS.md가 있거나 specs/changes 구조 확인\r\n const hasAgents = await fileExists(agentsPath);\r\n const hasSpecs = await directoryExists(specsPath);\r\n const hasChanges = await directoryExists(changesPath);\r\n\r\n if (!hasSpecs && !hasChanges && !hasAgents) {\r\n return null;\r\n }\r\n\r\n // 스펙 수집\r\n const specs: SpecInfo[] = [];\r\n\r\n if (hasSpecs) {\r\n const specDirs = await fs.readdir(specsPath, { withFileTypes: true });\r\n for (const entry of specDirs) {\r\n if (entry.isDirectory()) {\r\n const specPath = path.join(specsPath, entry.name);\r\n const specFile = path.join(specPath, 'spec.md');\r\n\r\n if (await fileExists(specFile)) {\r\n const content = await fs.readFile(specFile, 'utf-8');\r\n const title = extractTitle(content);\r\n const status = extractFrontmatterField(content, 'status');\r\n\r\n specs.push({\r\n id: entry.name,\r\n title,\r\n path: specPath,\r\n status,\r\n });\r\n }\r\n }\r\n }\r\n }\r\n\r\n return {\r\n tool: 'openspec',\r\n path: openspecPath,\r\n specCount: specs.length,\r\n specs,\r\n confidence: hasAgents ? 'high' : hasSpecs && hasChanges ? 'medium' : 'low',\r\n };\r\n}\r\n\r\n/**\r\n * Spec Kit 감지\r\n */\r\nasync function detectSpecKit(projectRoot: string): Promise<DetectionResult | null> {\r\n // .specify/ 디렉토리 확인\r\n const specifyPath = path.join(projectRoot, '.specify');\r\n if (!(await directoryExists(specifyPath))) {\r\n return null;\r\n }\r\n\r\n const specsPath = path.join(specifyPath, 'specs');\r\n const memoryPath = path.join(projectRoot, 'memory');\r\n const constitutionPath = path.join(memoryPath, 'constitution.md');\r\n\r\n const hasSpecs = await directoryExists(specsPath);\r\n const hasConstitution = await fileExists(constitutionPath);\r\n\r\n if (!hasSpecs) {\r\n return null;\r\n }\r\n\r\n // 스펙 수집\r\n const specs: SpecInfo[] = [];\r\n\r\n const specDirs = await fs.readdir(specsPath, { withFileTypes: true });\r\n for (const entry of specDirs) {\r\n if (entry.isDirectory()) {\r\n const specPath = path.join(specsPath, entry.name);\r\n\r\n // spec.md, plan.md, tasks.md 확인 (Spec Kit 구조)\r\n const specFile = path.join(specPath, 'spec.md');\r\n const planFile = path.join(specPath, 'plan.md');\r\n const tasksFile = path.join(specPath, 'tasks.md');\r\n\r\n const hasSpec = await fileExists(specFile);\r\n const hasPlan = await fileExists(planFile);\r\n const hasTasks = await fileExists(tasksFile);\r\n\r\n if (hasSpec || hasPlan) {\r\n let title: string | undefined;\r\n let status: string | undefined;\r\n\r\n if (hasSpec) {\r\n const content = await fs.readFile(specFile, 'utf-8');\r\n title = extractTitle(content);\r\n status = extractFrontmatterField(content, 'status');\r\n }\r\n\r\n specs.push({\r\n id: entry.name,\r\n title,\r\n path: specPath,\r\n status: hasTasks ? 'in-progress' : status,\r\n });\r\n }\r\n }\r\n }\r\n\r\n return {\r\n tool: 'speckit',\r\n path: specifyPath,\r\n specCount: specs.length,\r\n specs,\r\n confidence: hasConstitution ? 'high' : 'medium',\r\n };\r\n}\r\n\r\n/**\r\n * 기존 SDD 감지\r\n */\r\nasync function detectSdd(projectRoot: string): Promise<DetectionResult | null> {\r\n const sddPath = path.join(projectRoot, '.sdd');\r\n if (!(await directoryExists(sddPath))) {\r\n return null;\r\n }\r\n\r\n const specsPath = path.join(sddPath, 'specs');\r\n const configPath = path.join(sddPath, 'config.yaml');\r\n\r\n if (!(await directoryExists(specsPath))) {\r\n return null;\r\n }\r\n\r\n // 스펙 수집\r\n const specs: SpecInfo[] = [];\r\n\r\n const specDirs = await fs.readdir(specsPath, { withFileTypes: true });\r\n for (const entry of specDirs) {\r\n if (entry.isDirectory()) {\r\n const specPath = path.join(specsPath, entry.name);\r\n const specFile = path.join(specPath, 'spec.md');\r\n\r\n if (await fileExists(specFile)) {\r\n const content = await fs.readFile(specFile, 'utf-8');\r\n const title = extractTitle(content);\r\n const status = extractFrontmatterField(content, 'status');\r\n\r\n specs.push({\r\n id: entry.name,\r\n title,\r\n path: specPath,\r\n status,\r\n });\r\n }\r\n }\r\n }\r\n\r\n return {\r\n tool: 'sdd',\r\n path: sddPath,\r\n specCount: specs.length,\r\n specs,\r\n confidence: (await fileExists(configPath)) ? 'high' : 'medium',\r\n };\r\n}\r\n\r\n/**\r\n * OpenSpec에서 마이그레이션\r\n */\r\nexport async function migrateFromOpenSpec(\r\n sourcePath: string,\r\n targetPath: string,\r\n options: MigrationOptions = {}\r\n): Promise<Result<MigrationResult, ChangeError>> {\r\n try {\r\n const specsPath = path.join(sourcePath, 'specs');\r\n const targetSpecsPath = path.join(targetPath, 'specs');\r\n\r\n let specsCreated = 0;\r\n let specsSkipped = 0;\r\n const errors: string[] = [];\r\n\r\n if (!(await directoryExists(specsPath))) {\r\n return failure(new ChangeError('OpenSpec specs 디렉토리를 찾을 수 없습니다.'));\r\n }\r\n\r\n const specDirs = await fs.readdir(specsPath, { withFileTypes: true });\r\n\r\n for (const entry of specDirs) {\r\n if (!entry.isDirectory()) continue;\r\n\r\n const sourceSpecPath = path.join(specsPath, entry.name);\r\n const targetSpecPath = path.join(targetSpecsPath, entry.name);\r\n\r\n // 대상이 이미 존재하면 스킵\r\n if (await directoryExists(targetSpecPath)) {\r\n if (!options.overwrite) {\r\n specsSkipped++;\r\n continue;\r\n }\r\n }\r\n\r\n try {\r\n if (!options.dryRun) {\r\n // 디렉토리 복사\r\n await fs.mkdir(targetSpecPath, { recursive: true });\r\n\r\n const files = await fs.readdir(sourceSpecPath);\r\n for (const file of files) {\r\n const sourceFile = path.join(sourceSpecPath, file);\r\n const targetFile = path.join(targetSpecPath, file);\r\n\r\n const stat = await fs.stat(sourceFile);\r\n if (stat.isFile()) {\r\n let content = await fs.readFile(sourceFile, 'utf-8');\r\n\r\n // SDD 형식에 맞게 변환 (phase 추가 등)\r\n if (file === 'spec.md') {\r\n content = convertOpenSpecToSdd(content, entry.name);\r\n }\r\n\r\n await fs.writeFile(targetFile, content);\r\n }\r\n }\r\n }\r\n\r\n specsCreated++;\r\n } catch (error) {\r\n errors.push(`${entry.name}: ${error instanceof Error ? error.message : String(error)}`);\r\n }\r\n }\r\n\r\n return success({\r\n source: 'openspec',\r\n targetPath,\r\n specsCreated,\r\n specsSkipped,\r\n errors,\r\n });\r\n } catch (error) {\r\n return failure(new ChangeError(error instanceof Error ? error.message : String(error)));\r\n }\r\n}\r\n\r\n/**\r\n * Spec Kit에서 마이그레이션\r\n */\r\nexport async function migrateFromSpecKit(\r\n sourcePath: string,\r\n targetPath: string,\r\n options: MigrationOptions = {}\r\n): Promise<Result<MigrationResult, ChangeError>> {\r\n try {\r\n const specsPath = path.join(sourcePath, 'specs');\r\n const targetSpecsPath = path.join(targetPath, 'specs');\r\n\r\n let specsCreated = 0;\r\n let specsSkipped = 0;\r\n const errors: string[] = [];\r\n\r\n if (!(await directoryExists(specsPath))) {\r\n return failure(new ChangeError('Spec Kit specs 디렉토리를 찾을 수 없습니다.'));\r\n }\r\n\r\n const specDirs = await fs.readdir(specsPath, { withFileTypes: true });\r\n\r\n for (const entry of specDirs) {\r\n if (!entry.isDirectory()) continue;\r\n\r\n const sourceSpecPath = path.join(specsPath, entry.name);\r\n const targetSpecPath = path.join(targetSpecsPath, entry.name);\r\n\r\n // 대상이 이미 존재하면 스킵\r\n if (await directoryExists(targetSpecPath)) {\r\n if (!options.overwrite) {\r\n specsSkipped++;\r\n continue;\r\n }\r\n }\r\n\r\n try {\r\n if (!options.dryRun) {\r\n // 디렉토리 복사\r\n await fs.mkdir(targetSpecPath, { recursive: true });\r\n\r\n const files = await fs.readdir(sourceSpecPath);\r\n for (const file of files) {\r\n const sourceFile = path.join(sourceSpecPath, file);\r\n const targetFile = path.join(targetSpecPath, file);\r\n\r\n const stat = await fs.stat(sourceFile);\r\n if (stat.isFile()) {\r\n let content = await fs.readFile(sourceFile, 'utf-8');\r\n\r\n // SDD 형식에 맞게 변환\r\n if (file === 'spec.md') {\r\n content = convertSpecKitToSdd(content, entry.name);\r\n }\r\n\r\n await fs.writeFile(targetFile, content);\r\n }\r\n }\r\n }\r\n\r\n specsCreated++;\r\n } catch (error) {\r\n errors.push(`${entry.name}: ${error instanceof Error ? error.message : String(error)}`);\r\n }\r\n }\r\n\r\n return success({\r\n source: 'speckit',\r\n targetPath,\r\n specsCreated,\r\n specsSkipped,\r\n errors,\r\n });\r\n } catch (error) {\r\n return failure(new ChangeError(error instanceof Error ? error.message : String(error)));\r\n }\r\n}\r\n\r\n/**\r\n * OpenSpec 형식을 SDD 형식으로 변환\r\n */\r\nfunction convertOpenSpecToSdd(content: string, specId: string): string {\r\n // frontmatter 추출\r\n const frontmatterMatch = content.match(/^---\\n([\\s\\S]*?)\\n---/);\r\n\r\n if (!frontmatterMatch) {\r\n // frontmatter 없으면 추가\r\n const title = extractTitle(content) || specId;\r\n return `---\r\nid: ${specId}\r\ntitle: ${title}\r\nphase: migrated\r\nstatus: draft\r\nsource: openspec\r\nmigrated_at: ${new Date().toISOString()}\r\n---\r\n\r\n${content}`;\r\n }\r\n\r\n // 기존 frontmatter에 필드 추가\r\n let newFrontmatter = frontmatterMatch[1];\r\n\r\n if (!newFrontmatter.includes('phase:')) {\r\n newFrontmatter += '\\nphase: migrated';\r\n }\r\n if (!newFrontmatter.includes('source:')) {\r\n newFrontmatter += '\\nsource: openspec';\r\n }\r\n if (!newFrontmatter.includes('migrated_at:')) {\r\n newFrontmatter += `\\nmigrated_at: ${new Date().toISOString()}`;\r\n }\r\n\r\n return content.replace(/^---\\n[\\s\\S]*?\\n---/, `---\\n${newFrontmatter}\\n---`);\r\n}\r\n\r\n/**\r\n * Spec Kit 형식을 SDD 형식으로 변환\r\n */\r\nfunction convertSpecKitToSdd(content: string, specId: string): string {\r\n // frontmatter 추출\r\n const frontmatterMatch = content.match(/^---\\n([\\s\\S]*?)\\n---/);\r\n\r\n if (!frontmatterMatch) {\r\n // frontmatter 없으면 추가\r\n const title = extractTitle(content) || specId;\r\n return `---\r\nid: ${specId}\r\ntitle: ${title}\r\nphase: migrated\r\nstatus: draft\r\nsource: speckit\r\nmigrated_at: ${new Date().toISOString()}\r\n---\r\n\r\n${content}`;\r\n }\r\n\r\n // 기존 frontmatter에 필드 추가\r\n let newFrontmatter = frontmatterMatch[1];\r\n\r\n if (!newFrontmatter.includes('phase:')) {\r\n newFrontmatter += '\\nphase: migrated';\r\n }\r\n if (!newFrontmatter.includes('source:')) {\r\n newFrontmatter += '\\nsource: speckit';\r\n }\r\n if (!newFrontmatter.includes('migrated_at:')) {\r\n newFrontmatter += `\\nmigrated_at: ${new Date().toISOString()}`;\r\n }\r\n\r\n return content.replace(/^---\\n[\\s\\S]*?\\n---/, `---\\n${newFrontmatter}\\n---`);\r\n}\r\n\r\n/**\r\n * 제목 추출\r\n */\r\nfunction extractTitle(content: string): string | undefined {\r\n // frontmatter에서 title 추출\r\n const fmMatch = content.match(/^---\\n[\\s\\S]*?title:\\s*['\"]?([^'\"\\n]+)['\"]?\\n[\\s\\S]*?\\n---/);\r\n if (fmMatch) {\r\n return fmMatch[1].trim();\r\n }\r\n\r\n // 첫 번째 h1 헤딩 추출\r\n const h1Match = content.match(/^#\\s+(.+)$/m);\r\n if (h1Match) {\r\n return h1Match[1].trim();\r\n }\r\n\r\n return undefined;\r\n}\r\n\r\n/**\r\n * frontmatter 필드 추출\r\n */\r\nfunction extractFrontmatterField(content: string, field: string): string | undefined {\r\n const regex = new RegExp(`^---\\\\n[\\\\s\\\\S]*?${field}:\\\\s*['\"]?([^'\"\\\\n]+)['\"]?\\\\n[\\\\s\\\\S]*?\\\\n---`);\r\n const match = content.match(regex);\r\n return match ? match[1].trim() : undefined;\r\n}\r\n","/**\r\n * sdd cicd 명령어\r\n *\r\n * CI/CD 파이프라인 통합을 설정합니다.\r\n */\r\nimport { Command } from 'commander';\r\nimport path from 'node:path';\r\nimport * as logger from '../../utils/logger.js';\r\nimport { ExitCode } from '../../errors/index.js';\r\nimport { findSddRoot, ensureDir, writeFile, fileExists, directoryExists } from '../../utils/fs.js';\r\n\r\n/**\r\n * CI 플랫폼 유형\r\n */\r\ntype CIPlatform = 'github' | 'gitlab' | 'all';\r\n\r\n/**\r\n * 훅 유형\r\n */\r\ntype HookType = 'pre-commit' | 'pre-push' | 'commit-msg';\r\n\r\n/**\r\n * cicd 명령어 등록\r\n */\r\nexport function registerCicdCommand(program: Command): void {\r\n const cicd = program\r\n .command('cicd')\r\n .description('CI/CD 파이프라인 통합 설정');\r\n\r\n // setup 서브커맨드 - CI 설정\r\n cicd\r\n .command('setup [platform]')\r\n .description('CI 워크플로우 파일을 생성합니다')\r\n .option('--strict', '엄격 모드 (경고도 에러로 처리)')\r\n .action(async (platform: CIPlatform | undefined, options: { strict?: boolean }) => {\r\n try {\r\n await runSetup(platform || 'github', options);\r\n } catch (error) {\r\n logger.error(error instanceof Error ? error.message : String(error));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n });\r\n\r\n // hooks 서브커맨드 - Git hooks 설정\r\n cicd\r\n .command('hooks [type]')\r\n .description('Git hooks를 설정합니다')\r\n .option('--install', 'husky 설치 포함')\r\n .action(async (type: HookType | undefined, options: { install?: boolean }) => {\r\n try {\r\n await runHooksSetup(type, options);\r\n } catch (error) {\r\n logger.error(error instanceof Error ? error.message : String(error));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n });\r\n\r\n // check 서브커맨드 - CI에서 사용할 검증\r\n cicd\r\n .command('check')\r\n .description('CI 환경에서 스펙 검증을 수행합니다')\r\n .option('--strict', '엄격 모드')\r\n .option('--fail-on-warning', '경고 시 실패')\r\n .action(async (options: { strict?: boolean; failOnWarning?: boolean }) => {\r\n try {\r\n await runCiCheck(options);\r\n } catch (error) {\r\n logger.error(error instanceof Error ? error.message : String(error));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n });\r\n}\r\n\r\n/**\r\n * CI 설정 실행\r\n */\r\nasync function runSetup(platform: CIPlatform, options: { strict?: boolean }): Promise<void> {\r\n const projectRoot = await findSddRoot();\r\n if (!projectRoot) {\r\n logger.error('SDD 프로젝트를 찾을 수 없습니다. `sdd init`을 먼저 실행하세요.');\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n logger.info(`CI/CD 설정: ${platform}`);\r\n logger.newline();\r\n\r\n if (platform === 'github' || platform === 'all') {\r\n await setupGitHubActions(projectRoot, options.strict || false);\r\n }\r\n\r\n if (platform === 'gitlab' || platform === 'all') {\r\n await setupGitLabCI(projectRoot, options.strict || false);\r\n }\r\n\r\n logger.newline();\r\n logger.success('CI/CD 설정이 완료되었습니다!');\r\n logger.newline();\r\n logger.info('다음 단계:');\r\n logger.listItem('변경사항을 커밋하세요');\r\n logger.listItem('PR/MR 생성 시 자동으로 스펙 검증이 실행됩니다');\r\n}\r\n\r\n/**\r\n * GitHub Actions 설정\r\n */\r\nasync function setupGitHubActions(projectRoot: string, strict: boolean): Promise<void> {\r\n const workflowDir = path.join(projectRoot, '.github', 'workflows');\r\n await ensureDir(workflowDir);\r\n\r\n const workflowContent = generateGitHubWorkflow(strict);\r\n const workflowPath = path.join(workflowDir, 'sdd-validate.yml');\r\n\r\n await writeFile(workflowPath, workflowContent);\r\n logger.info(`✅ GitHub Actions 워크플로우 생성: .github/workflows/sdd-validate.yml`);\r\n}\r\n\r\n/**\r\n * GitLab CI 설정\r\n */\r\nasync function setupGitLabCI(projectRoot: string, strict: boolean): Promise<void> {\r\n const ciContent = generateGitLabCI(strict);\r\n const ciPath = path.join(projectRoot, '.gitlab-ci-sdd.yml');\r\n\r\n await writeFile(ciPath, ciContent);\r\n logger.info(`✅ GitLab CI 구성 생성: .gitlab-ci-sdd.yml`);\r\n logger.info(' (기존 .gitlab-ci.yml에 include하거나 병합하세요)');\r\n}\r\n\r\n/**\r\n * GitHub Actions 워크플로우 생성\r\n */\r\nfunction generateGitHubWorkflow(strict: boolean): string {\r\n const strictFlag = strict ? ' --strict' : '';\r\n\r\n return `# SDD 스펙 검증 워크플로우\r\n# 이 파일은 sdd cicd setup으로 생성되었습니다.\r\n\r\nname: SDD Validation\r\n\r\non:\r\n push:\r\n branches: [main, master, develop]\r\n paths:\r\n - '.sdd/**'\r\n pull_request:\r\n branches: [main, master, develop]\r\n paths:\r\n - '.sdd/**'\r\n\r\njobs:\r\n validate:\r\n name: Validate Specs\r\n runs-on: ubuntu-latest\r\n\r\n steps:\r\n - name: Checkout repository\r\n uses: actions/checkout@v4\r\n\r\n - name: Setup Node.js\r\n uses: actions/setup-node@v4\r\n with:\r\n node-version: '20'\r\n cache: 'npm'\r\n\r\n - name: Install dependencies\r\n run: npm ci\r\n\r\n - name: Install SDD Tool\r\n run: npm install -g sdd-tool\r\n\r\n - name: Validate specifications\r\n run: sdd validate${strictFlag}\r\n\r\n - name: Check constitution\r\n run: sdd constitution validate\r\n\r\n - name: Generate impact report\r\n run: sdd impact report --json > impact-report.json\r\n\r\n - name: Upload impact report\r\n uses: actions/upload-artifact@v4\r\n with:\r\n name: impact-report\r\n path: impact-report.json\r\n`;\r\n}\r\n\r\n/**\r\n * GitLab CI 구성 생성\r\n */\r\nfunction generateGitLabCI(strict: boolean): string {\r\n const strictFlag = strict ? ' --strict' : '';\r\n\r\n return `# SDD 스펙 검증 파이프라인\r\n# 이 파일은 sdd cicd setup으로 생성되었습니다.\r\n# 기존 .gitlab-ci.yml에 include하거나 내용을 병합하세요.\r\n\r\nsdd:validate:\r\n stage: test\r\n image: node:20\r\n rules:\r\n - if: $CI_PIPELINE_SOURCE == \"merge_request_event\"\r\n changes:\r\n - .sdd/**/*\r\n - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH\r\n changes:\r\n - .sdd/**/*\r\n before_script:\r\n - npm ci\r\n - npm install -g sdd-tool\r\n script:\r\n - sdd validate${strictFlag}\r\n - sdd constitution validate\r\n - sdd impact report --json > impact-report.json\r\n artifacts:\r\n reports:\r\n dotenv: impact-report.json\r\n paths:\r\n - impact-report.json\r\n expire_in: 1 week\r\n`;\r\n}\r\n\r\n/**\r\n * Git hooks 설정 실행\r\n */\r\nasync function runHooksSetup(type: HookType | undefined, options: { install?: boolean }): Promise<void> {\r\n const projectRoot = await findSddRoot();\r\n if (!projectRoot) {\r\n logger.error('SDD 프로젝트를 찾을 수 없습니다. `sdd init`을 먼저 실행하세요.');\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n const hooksDir = path.join(projectRoot, '.husky');\r\n\r\n if (options.install) {\r\n logger.info('husky 설치 방법:');\r\n logger.newline();\r\n logger.listItem('npm install -D husky');\r\n logger.listItem('npx husky init');\r\n logger.newline();\r\n }\r\n\r\n // hooks 디렉토리가 없으면 생성\r\n if (!(await directoryExists(hooksDir))) {\r\n await ensureDir(hooksDir);\r\n }\r\n\r\n const hooks: HookType[] = type ? [type] : ['pre-commit', 'pre-push'];\r\n\r\n for (const hook of hooks) {\r\n const hookContent = generateHookScript(hook);\r\n const hookPath = path.join(hooksDir, hook);\r\n await writeFile(hookPath, hookContent);\r\n logger.info(`✅ ${hook} 훅 생성: .husky/${hook}`);\r\n }\r\n\r\n logger.newline();\r\n logger.info('훅이 설정되었습니다.');\r\n logger.newline();\r\n logger.info('husky가 설치되어 있다면 훅이 자동으로 실행됩니다.');\r\n logger.info('그렇지 않으면 다음 명령어로 설치하세요:');\r\n logger.listItem('npm install -D husky && npx husky init');\r\n}\r\n\r\n/**\r\n * Git hook 스크립트 생성\r\n */\r\nfunction generateHookScript(hook: HookType): string {\r\n switch (hook) {\r\n case 'pre-commit':\r\n return `#!/bin/sh\r\n. \"$(dirname \"$0\")/_/husky.sh\"\r\n\r\n# SDD 스펙 검증\r\necho \"🔍 Validating SDD specs...\"\r\nnpx sdd validate\r\n\r\nif [ $? -ne 0 ]; then\r\n echo \"❌ SDD validation failed. Please fix the issues before committing.\"\r\n exit 1\r\nfi\r\n\r\necho \"✅ SDD validation passed.\"\r\n`;\r\n\r\n case 'pre-push':\r\n return `#!/bin/sh\r\n. \"$(dirname \"$0\")/_/husky.sh\"\r\n\r\n# SDD 스펙 검증 (strict mode)\r\necho \"🔍 Validating SDD specs (strict mode)...\"\r\nnpx sdd validate --strict\r\n\r\nif [ $? -ne 0 ]; then\r\n echo \"❌ SDD validation failed. Please fix all issues before pushing.\"\r\n exit 1\r\nfi\r\n\r\n# Constitution 검증\r\necho \"📜 Validating constitution...\"\r\nnpx sdd constitution validate\r\n\r\nif [ $? -ne 0 ]; then\r\n echo \"❌ Constitution validation failed.\"\r\n exit 1\r\nfi\r\n\r\necho \"✅ All validations passed.\"\r\n`;\r\n\r\n case 'commit-msg':\r\n return `#!/bin/sh\r\n. \"$(dirname \"$0\")/_/husky.sh\"\r\n\r\n# 커밋 메시지에서 스펙 참조 확인 (선택적)\r\nCOMMIT_MSG=$(cat \"$1\")\r\n\r\n# spec: 또는 feat(spec-id): 형식 확인\r\nif echo \"$COMMIT_MSG\" | grep -qE \"^(feat|fix|docs|chore)\\\\([a-z-]+\\\\):\"; then\r\n echo \"✅ Commit message format is valid.\"\r\nelse\r\n echo \"⚠️ Commit message doesn't reference a spec.\"\r\n echo \" Consider using: feat(<spec-id>): <message>\"\r\nfi\r\n`;\r\n\r\n default:\r\n return '#!/bin/sh\\nexit 0\\n';\r\n }\r\n}\r\n\r\n/**\r\n * CI 체크 실행\r\n */\r\nasync function runCiCheck(options: { strict?: boolean; failOnWarning?: boolean }): Promise<void> {\r\n const projectRoot = await findSddRoot();\r\n if (!projectRoot) {\r\n logger.error('SDD 프로젝트를 찾을 수 없습니다.');\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n logger.info('🔍 CI 검증 시작...');\r\n logger.newline();\r\n\r\n let hasErrors = false;\r\n let hasWarnings = false;\r\n\r\n // 1. Constitution 검증\r\n logger.info('1. Constitution 검증...');\r\n const constitutionPath = path.join(projectRoot, '.sdd', 'constitution.md');\r\n if (await fileExists(constitutionPath)) {\r\n logger.info(' ✅ constitution.md 존재');\r\n } else {\r\n logger.warn(' ⚠️ constitution.md 없음');\r\n hasWarnings = true;\r\n }\r\n\r\n // 2. 스펙 디렉토리 확인\r\n logger.info('2. 스펙 디렉토리 확인...');\r\n const specsPath = path.join(projectRoot, '.sdd', 'specs');\r\n if (await directoryExists(specsPath)) {\r\n logger.info(' ✅ specs/ 디렉토리 존재');\r\n } else {\r\n logger.warn(' ⚠️ specs/ 디렉토리 없음');\r\n hasWarnings = true;\r\n }\r\n\r\n // 3. 기본 구조 확인\r\n logger.info('3. 기본 구조 확인...');\r\n const requiredDirs = ['changes', 'archive', 'templates'];\r\n for (const dir of requiredDirs) {\r\n const dirPath = path.join(projectRoot, '.sdd', dir);\r\n if (await directoryExists(dirPath)) {\r\n logger.info(` ✅ ${dir}/ 존재`);\r\n } else {\r\n if (options.strict) {\r\n logger.error(` ❌ ${dir}/ 없음`);\r\n hasErrors = true;\r\n } else {\r\n logger.warn(` ⚠️ ${dir}/ 없음`);\r\n hasWarnings = true;\r\n }\r\n }\r\n }\r\n\r\n logger.newline();\r\n\r\n // 결과 출력\r\n if (hasErrors) {\r\n logger.error('❌ CI 검증 실패');\r\n process.exit(ExitCode.VALIDATION_ERROR);\r\n } else if (hasWarnings && options.failOnWarning) {\r\n logger.warn('⚠️ 경고가 있습니다 (--fail-on-warning)');\r\n process.exit(ExitCode.VALIDATION_ERROR);\r\n } else if (hasWarnings) {\r\n logger.warn('⚠️ 경고가 있지만 검증은 통과했습니다');\r\n } else {\r\n logger.success('✅ CI 검증 통과');\r\n }\r\n}\r\n","/**\r\n * sdd transition 명령어 - 워크플로우 간 전환\r\n *\r\n * new ↔ change 워크플로우 간 전환을 지원합니다.\r\n */\r\nimport { Command } from 'commander';\r\nimport path from 'node:path';\r\nimport { promises as fs } from 'node:fs';\r\nimport * as logger from '../../utils/logger.js';\r\nimport { ExitCode } from '../../errors/index.js';\r\nimport { findSddRoot, fileExists, readFile, ensureDir, writeFile, directoryExists } from '../../utils/fs.js';\r\nimport { generateChangeId } from '../../core/change/index.js';\r\n\r\n/**\r\n * 전환 방향\r\n */\r\ntype TransitionDirection = 'new-to-change' | 'change-to-new';\r\n\r\n/**\r\n * transition 명령어 등록\r\n */\r\nexport function registerTransitionCommand(program: Command): void {\r\n const transition = program\r\n .command('transition')\r\n .description('워크플로우 간 전환을 수행합니다');\r\n\r\n // new → change 전환\r\n transition\r\n .command('new-to-change <spec-id>')\r\n .description('새 기능 작업을 기존 스펙 변경으로 전환합니다')\r\n .option('-t, --title <title>', '변경 제안 제목')\r\n .option('-r, --reason <reason>', '전환 사유')\r\n .action(async (specId: string, options: { title?: string; reason?: string }) => {\r\n try {\r\n await runNewToChange(specId, options);\r\n } catch (error) {\r\n logger.error(error instanceof Error ? error.message : String(error));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n });\r\n\r\n // change → new 전환\r\n transition\r\n .command('change-to-new <change-id>')\r\n .description('기존 스펙 변경 작업을 새 기능으로 전환합니다')\r\n .option('-n, --name <name>', '새 기능 이름')\r\n .option('-r, --reason <reason>', '전환 사유')\r\n .action(async (changeId: string, options: { name?: string; reason?: string }) => {\r\n try {\r\n await runChangeToNew(changeId, options);\r\n } catch (error) {\r\n logger.error(error instanceof Error ? error.message : String(error));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n });\r\n\r\n // 전환 가이드\r\n transition\r\n .command('guide')\r\n .description('워크플로우 전환 가이드를 표시합니다')\r\n .action(() => {\r\n displayTransitionGuide();\r\n });\r\n}\r\n\r\n/**\r\n * new → change 전환 실행\r\n *\r\n * 새 기능 작성 중 기존 스펙과 중복/관련됨을 발견했을 때\r\n * 변경 제안 워크플로우로 전환합니다.\r\n */\r\nasync function runNewToChange(\r\n specId: string,\r\n options: { title?: string; reason?: string }\r\n): Promise<void> {\r\n const projectRoot = await findSddRoot();\r\n if (!projectRoot) {\r\n logger.error('SDD 프로젝트를 찾을 수 없습니다. `sdd init`을 먼저 실행하세요.');\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n const sddPath = path.join(projectRoot, '.sdd');\r\n const specsPath = path.join(sddPath, 'specs');\r\n\r\n // 대상 스펙 확인\r\n const specPath = path.join(specsPath, specId, 'spec.md');\r\n if (!(await fileExists(specPath))) {\r\n logger.error(`스펙을 찾을 수 없습니다: ${specId}`);\r\n logger.info('사용 가능한 스펙 목록은 `sdd list`로 확인하세요.');\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n logger.info('=== 워크플로우 전환: new → change ===');\r\n logger.newline();\r\n logger.info(`대상 스펙: ${specId}`);\r\n\r\n // 변경 ID 생성\r\n const changeId = generateChangeId();\r\n const changePath = path.join(sddPath, 'changes', changeId);\r\n await ensureDir(changePath);\r\n\r\n // 기존 스펙 내용 읽기\r\n const specContent = await readFile(specPath);\r\n if (!specContent.success) {\r\n logger.error('스펙 파일을 읽을 수 없습니다.');\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n // proposal.md 생성\r\n const title = options.title || `${specId} 기능 확장`;\r\n const reason = options.reason || 'new 워크플로우에서 전환됨';\r\n const proposalContent = generateTransitionProposal(specId, title, reason, 'new-to-change');\r\n await writeFile(path.join(changePath, 'proposal.md'), proposalContent);\r\n\r\n // delta.md 생성 (템플릿)\r\n const deltaContent = generateDeltaTemplate(specId);\r\n await writeFile(path.join(changePath, 'delta.md'), deltaContent);\r\n\r\n // tasks.md 생성 (템플릿)\r\n const tasksContent = generateTasksTemplate();\r\n await writeFile(path.join(changePath, 'tasks.md'), tasksContent);\r\n\r\n logger.newline();\r\n logger.success(`전환 완료! 변경 제안이 생성되었습니다.`);\r\n logger.newline();\r\n logger.info(`변경 ID: ${changeId}`);\r\n logger.info(`위치: .sdd/changes/${changeId}/`);\r\n logger.newline();\r\n logger.info('다음 단계:');\r\n logger.listItem(`1. .sdd/changes/${changeId}/proposal.md 편집`);\r\n logger.listItem(`2. .sdd/changes/${changeId}/delta.md 작성`);\r\n logger.listItem(`3. sdd change validate ${changeId}`);\r\n logger.listItem(`4. sdd change apply ${changeId}`);\r\n logger.newline();\r\n logger.info('또는 슬래시 커맨드 사용:');\r\n logger.listItem('/sdd.change - 변경 내용 작성 도움');\r\n}\r\n\r\n/**\r\n * change → new 전환 실행\r\n *\r\n * 변경 작업 중 범위가 너무 커서 새 기능으로 분리해야 할 때\r\n * 새 기능 워크플로우로 전환합니다.\r\n */\r\nasync function runChangeToNew(\r\n changeId: string,\r\n options: { name?: string; reason?: string }\r\n): Promise<void> {\r\n const projectRoot = await findSddRoot();\r\n if (!projectRoot) {\r\n logger.error('SDD 프로젝트를 찾을 수 없습니다. `sdd init`을 먼저 실행하세요.');\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n const sddPath = path.join(projectRoot, '.sdd');\r\n const changePath = path.join(sddPath, 'changes', changeId);\r\n\r\n // 변경 제안 확인\r\n if (!(await directoryExists(changePath))) {\r\n logger.error(`변경 제안을 찾을 수 없습니다: ${changeId}`);\r\n logger.info('진행 중인 변경 목록은 `sdd change -l`로 확인하세요.');\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n logger.info('=== 워크플로우 전환: change → new ===');\r\n logger.newline();\r\n logger.info(`원본 변경: ${changeId}`);\r\n\r\n // proposal.md에서 제목 추출\r\n const proposalPath = path.join(changePath, 'proposal.md');\r\n let extractedTitle = '';\r\n if (await fileExists(proposalPath)) {\r\n const proposalContent = await readFile(proposalPath);\r\n if (proposalContent.success) {\r\n const titleMatch = proposalContent.data.match(/^#\\s+(.+)$/m);\r\n if (titleMatch) {\r\n extractedTitle = titleMatch[1];\r\n }\r\n }\r\n }\r\n\r\n // 새 기능 이름 결정\r\n const featureName = options.name || extractedTitle.toLowerCase().replace(/\\s+/g, '-') || `feature-from-${changeId}`;\r\n const specsPath = path.join(sddPath, 'specs');\r\n const newSpecPath = path.join(specsPath, featureName);\r\n\r\n // 이미 존재하는지 확인\r\n if (await directoryExists(newSpecPath)) {\r\n logger.error(`스펙이 이미 존재합니다: ${featureName}`);\r\n logger.info('다른 이름을 지정하세요: --name <name>');\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n await ensureDir(newSpecPath);\r\n\r\n // spec.md 생성\r\n const reason = options.reason || 'change 워크플로우에서 전환됨';\r\n const specContent = generateTransitionSpec(featureName, extractedTitle || featureName, reason, changeId);\r\n await writeFile(path.join(newSpecPath, 'spec.md'), specContent);\r\n\r\n // plan.md 템플릿 생성\r\n const planContent = generatePlanTemplate(featureName);\r\n await writeFile(path.join(newSpecPath, 'plan.md'), planContent);\r\n\r\n // tasks.md 템플릿 생성\r\n const tasksContent = generateTasksTemplate();\r\n await writeFile(path.join(newSpecPath, 'tasks.md'), tasksContent);\r\n\r\n // 원본 변경 제안 상태 업데이트\r\n const statusPath = path.join(changePath, '.status');\r\n await writeFile(statusPath, JSON.stringify({\r\n status: 'transitioned',\r\n transitionedTo: featureName,\r\n transitionedAt: new Date().toISOString(),\r\n reason,\r\n }, null, 2));\r\n\r\n logger.newline();\r\n logger.success(`전환 완료! 새 기능 스펙이 생성되었습니다.`);\r\n logger.newline();\r\n logger.info(`기능 이름: ${featureName}`);\r\n logger.info(`위치: .sdd/specs/${featureName}/`);\r\n logger.info(`원본 변경 ${changeId}은 'transitioned' 상태로 변경되었습니다.`);\r\n logger.newline();\r\n logger.info('다음 단계:');\r\n logger.listItem(`1. .sdd/specs/${featureName}/spec.md 편집`);\r\n logger.listItem(`2. sdd new plan ${featureName}`);\r\n logger.listItem(`3. sdd new tasks ${featureName}`);\r\n logger.listItem(`4. 구현 진행`);\r\n logger.newline();\r\n logger.info('또는 슬래시 커맨드 사용:');\r\n logger.listItem('/sdd.new - 명세 작성 도움');\r\n}\r\n\r\n/**\r\n * 전환 가이드 표시\r\n */\r\nfunction displayTransitionGuide(): void {\r\n logger.info('=== 워크플로우 전환 가이드 ===');\r\n logger.newline();\r\n\r\n logger.info('## new → change 전환');\r\n logger.newline();\r\n logger.info('사용 시점:');\r\n logger.listItem('새 기능 작성 중 기존 스펙과 중복 발견');\r\n logger.listItem('기존 기능 확장이 더 적절한 경우');\r\n logger.listItem('의존성 분석 결과 기존 스펙 수정 필요');\r\n logger.newline();\r\n logger.info('명령어:');\r\n logger.listItem('sdd transition new-to-change <spec-id>');\r\n logger.listItem(' -t, --title <title> : 변경 제안 제목');\r\n logger.listItem(' -r, --reason <reason>: 전환 사유');\r\n logger.newline();\r\n\r\n logger.info('## change → new 전환');\r\n logger.newline();\r\n logger.info('사용 시점:');\r\n logger.listItem('변경 범위가 너무 커서 별도 기능으로 분리 필요');\r\n logger.listItem('기존 스펙과 독립적인 새 기능으로 발전');\r\n logger.listItem('영향도 분석 결과 분리가 안전');\r\n logger.newline();\r\n logger.info('명령어:');\r\n logger.listItem('sdd transition change-to-new <change-id>');\r\n logger.listItem(' -n, --name <name> : 새 기능 이름');\r\n logger.listItem(' -r, --reason <reason>: 전환 사유');\r\n logger.newline();\r\n\r\n logger.info('## 전환 판단 기준');\r\n logger.newline();\r\n logger.info('new → change:');\r\n logger.listItem('영향받는 스펙 수 ≤ 3개');\r\n logger.listItem('변경이 기존 기능의 자연스러운 확장');\r\n logger.listItem('새 시나리오 추가보다 기존 시나리오 수정 중심');\r\n logger.newline();\r\n logger.info('change → new:');\r\n logger.listItem('영향받는 스펙 수 > 3개');\r\n logger.listItem('새로운 개념/도메인 도입');\r\n logger.listItem('기존 스펙과 독립적으로 테스트 가능');\r\n}\r\n\r\n/**\r\n * 전환용 proposal.md 생성\r\n */\r\nfunction generateTransitionProposal(\r\n specId: string,\r\n title: string,\r\n reason: string,\r\n direction: TransitionDirection\r\n): string {\r\n const now = new Date().toISOString().split('T')[0];\r\n return `---\r\nid: ${specId}-change\r\ntitle: \"${title}\"\r\ntarget_spec: ${specId}\r\nstatus: draft\r\ncreated_at: ${now}\r\ntransition_from: ${direction === 'new-to-change' ? 'new' : 'change'}\r\ntransition_reason: \"${reason}\"\r\n---\r\n\r\n# ${title}\r\n\r\n## 배경\r\n\r\n> 이 변경 제안은 \\`${direction}\\` 워크플로우 전환으로 생성되었습니다.\r\n> 전환 사유: ${reason}\r\n\r\n<!-- 변경이 필요한 배경을 설명하세요 -->\r\n\r\n## 변경 목적\r\n\r\n<!-- 이 변경으로 달성하려는 목표를 설명하세요 -->\r\n\r\n## 영향 범위\r\n\r\n- 대상 스펙: \\`${specId}\\`\r\n\r\n<!-- 관련된 다른 스펙이 있다면 나열하세요 -->\r\n\r\n## 제약 사항\r\n\r\n<!-- 이 변경의 제약 조건을 설명하세요 -->\r\n\r\n## 참고 사항\r\n\r\n<!-- 추가 참고 정보가 있다면 작성하세요 -->\r\n`;\r\n}\r\n\r\n/**\r\n * delta.md 템플릿 생성\r\n */\r\nfunction generateDeltaTemplate(specId: string): string {\r\n return `---\r\ntarget: ${specId}\r\n---\r\n\r\n# Delta: ${specId}\r\n\r\n## ADDED\r\n\r\n<!-- 추가되는 요구사항/시나리오 -->\r\n\r\n## MODIFIED\r\n\r\n<!-- 변경되는 내용 (Before/After) -->\r\n\r\n### 요구사항 변경\r\n\r\n**Before:**\r\n\\`\\`\\`\r\n<!-- 기존 내용 -->\r\n\\`\\`\\`\r\n\r\n**After:**\r\n\\`\\`\\`\r\n<!-- 변경된 내용 -->\r\n\\`\\`\\`\r\n\r\n## REMOVED\r\n\r\n<!-- 제거되는 내용 (있는 경우) -->\r\n`;\r\n}\r\n\r\n/**\r\n * 전환용 spec.md 생성\r\n */\r\nfunction generateTransitionSpec(\r\n featureName: string,\r\n title: string,\r\n reason: string,\r\n fromChangeId: string\r\n): string {\r\n const now = new Date().toISOString().split('T')[0];\r\n return `---\r\nid: ${featureName}\r\ntitle: \"${title}\"\r\nstatus: draft\r\ncreated_at: ${now}\r\ntransition_from: change\r\ntransition_change_id: ${fromChangeId}\r\ntransition_reason: \"${reason}\"\r\n---\r\n\r\n# ${title}\r\n\r\n> 이 명세는 변경 제안 \\`${fromChangeId}\\`에서 분리되어 생성되었습니다.\r\n> 전환 사유: ${reason}\r\n\r\n## 개요\r\n\r\n<!-- 기능 개요를 작성하세요 -->\r\n\r\n## 요구사항\r\n\r\n### 기능 요구사항\r\n\r\n<!-- RFC 2119 키워드(MUST, SHOULD, MAY)를 사용하세요 -->\r\n\r\n### 비기능 요구사항\r\n\r\n<!-- 성능, 보안 등 비기능 요구사항 -->\r\n\r\n## 시나리오\r\n\r\n### 기본 시나리오\r\n\r\n\\`\\`\\`gherkin\r\nGIVEN 초기 상태\r\nWHEN 사용자가 동작을 수행하면\r\nTHEN 기대 결과가 발생한다\r\n\\`\\`\\`\r\n\r\n## 의존성\r\n\r\n<!-- 관련 스펙 참조 -->\r\n\r\n## 비고\r\n\r\n<!-- 추가 참고 사항 -->\r\n`;\r\n}\r\n\r\n/**\r\n * plan.md 템플릿 생성\r\n */\r\nfunction generatePlanTemplate(featureName: string): string {\r\n return `---\r\nspec: ${featureName}\r\nstatus: draft\r\n---\r\n\r\n# 구현 계획: ${featureName}\r\n\r\n## 기술 결정\r\n\r\n<!-- 구현에 필요한 기술 결정 사항 -->\r\n\r\n## 구현 전략\r\n\r\n<!-- 단계별 구현 전략 -->\r\n\r\n## 영향 분석\r\n\r\n<!-- 이 구현이 다른 부분에 미치는 영향 -->\r\n\r\n## 테스트 전략\r\n\r\n<!-- 테스트 방법 및 범위 -->\r\n\r\n## 위험 요소\r\n\r\n<!-- 구현 시 고려할 위험 요소 -->\r\n`;\r\n}\r\n\r\n/**\r\n * tasks.md 템플릿 생성\r\n */\r\nfunction generateTasksTemplate(): string {\r\n return `---\r\nstatus: pending\r\n---\r\n\r\n# Tasks\r\n\r\n## 작업 목록\r\n\r\n- [ ] 작업 1\r\n- [ ] 작업 2\r\n- [ ] 작업 3\r\n\r\n## 완료 조건\r\n\r\n- [ ] 모든 시나리오 테스트 통과\r\n- [ ] 코드 리뷰 완료\r\n- [ ] 문서 업데이트\r\n`;\r\n}\r\n","/**\r\n * watch 명령어\r\n *\r\n * 스펙 파일 변경을 실시간으로 감시하고 자동 검증합니다.\r\n */\r\nimport { Command } from 'commander';\r\nimport path from 'node:path';\r\nimport { createWatcher, FileEvent } from '../../core/watch/index.js';\r\nimport { validateSpecs } from '../../core/spec/index.js';\r\nimport { findSddRoot } from '../../utils/fs.js';\r\nimport * as logger from '../../utils/logger.js';\r\nimport { ExitCode } from '../../errors/index.js';\r\n\r\n/**\r\n * watch 명령어 등록\r\n */\r\nexport function registerWatchCommand(program: Command): void {\r\n program\r\n .command('watch')\r\n .description('스펙 파일 변경을 실시간 감시하고 자동 검증합니다')\r\n .option('--no-validate', '자동 검증 비활성화')\r\n .option('--impact', '영향도 분석 포함')\r\n .option('-q, --quiet', '성공 시 출력 생략')\r\n .option('--debounce <ms>', '디바운스 시간 (기본: 500ms)', '500')\r\n .action(async (options: {\r\n validate?: boolean;\r\n impact?: boolean;\r\n quiet?: boolean;\r\n debounce?: string;\r\n }) => {\r\n try {\r\n await runWatch(options);\r\n } catch (error) {\r\n logger.error(error instanceof Error ? error.message : String(error));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n });\r\n}\r\n\r\n/**\r\n * watch 실행\r\n */\r\nasync function runWatch(options: {\r\n validate?: boolean;\r\n impact?: boolean;\r\n quiet?: boolean;\r\n debounce?: string;\r\n}): Promise<void> {\r\n const projectRoot = await findSddRoot();\r\n if (!projectRoot) {\r\n logger.error('SDD 프로젝트를 찾을 수 없습니다. `sdd init`을 먼저 실행하세요.');\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n const sddPath = path.join(projectRoot, '.sdd');\r\n const specsPath = path.join(sddPath, 'specs');\r\n const debounceMs = parseInt(options.debounce || '500', 10);\r\n\r\n logger.info('👁️ Watch 모드 시작');\r\n logger.info(` 경로: ${specsPath}`);\r\n logger.info(` 디바운스: ${debounceMs}ms`);\r\n logger.info(` 검증: ${options.validate !== false ? '활성화' : '비활성화'}`);\r\n logger.newline();\r\n logger.info('파일 변경을 감시 중... (Ctrl+C로 종료)');\r\n logger.newline();\r\n\r\n const watcher = createWatcher({\r\n specsPath,\r\n debounceMs,\r\n });\r\n\r\n let validationCount = 0;\r\n let errorCount = 0;\r\n\r\n watcher.on('change', async (events: FileEvent[]) => {\r\n const timestamp = new Date().toLocaleTimeString();\r\n\r\n // 이벤트 요약\r\n const addCount = events.filter((e) => e.type === 'add').length;\r\n const changeCount = events.filter((e) => e.type === 'change').length;\r\n const unlinkCount = events.filter((e) => e.type === 'unlink').length;\r\n\r\n const parts: string[] = [];\r\n if (addCount > 0) parts.push(`추가 ${addCount}`);\r\n if (changeCount > 0) parts.push(`수정 ${changeCount}`);\r\n if (unlinkCount > 0) parts.push(`삭제 ${unlinkCount}`);\r\n\r\n logger.info(`[${timestamp}] 변경 감지: ${parts.join(', ')}`);\r\n\r\n // 변경된 파일 목록\r\n for (const event of events) {\r\n const icon = event.type === 'add' ? '➕' : event.type === 'change' ? '✏️' : '❌';\r\n logger.info(` ${icon} ${event.relativePath}`);\r\n }\r\n\r\n // 자동 검증\r\n if (options.validate !== false) {\r\n logger.newline();\r\n logger.info('🔍 검증 실행 중...');\r\n\r\n const result = await validateSpecs(sddPath, { strict: false });\r\n\r\n validationCount++;\r\n\r\n if (result.success) {\r\n const data = result.data;\r\n const hasErrors = data.results.some((r) => r.errors.length > 0);\r\n const hasWarnings = data.results.some((r) => r.warnings.length > 0);\r\n\r\n if (hasErrors) {\r\n errorCount++;\r\n logger.error(`❌ 검증 실패: ${data.errorCount}개 에러, ${data.warningCount}개 경고`);\r\n\r\n // 에러 상세 표시\r\n for (const specResult of data.results) {\r\n if (specResult.errors.length > 0) {\r\n logger.error(` ${specResult.file}:`);\r\n for (const err of specResult.errors) {\r\n logger.error(` - ${err}`);\r\n }\r\n }\r\n }\r\n } else if (hasWarnings) {\r\n if (!options.quiet) {\r\n logger.warn(`⚠️ 검증 완료: ${data.warningCount}개 경고`);\r\n }\r\n } else {\r\n if (!options.quiet) {\r\n logger.success(`✅ 검증 통과 (${data.validCount}개 스펙)`);\r\n }\r\n }\r\n } else {\r\n errorCount++;\r\n logger.error(`❌ 검증 오류: ${result.error.message}`);\r\n }\r\n\r\n logger.newline();\r\n }\r\n });\r\n\r\n watcher.on('error', (error: Error) => {\r\n logger.error(`감시 오류: ${error.message}`);\r\n });\r\n\r\n watcher.on('ready', () => {\r\n logger.success('✅ 감시 준비 완료');\r\n logger.newline();\r\n });\r\n\r\n // 종료 핸들러\r\n const cleanup = async () => {\r\n logger.newline();\r\n logger.info('Watch 모드 종료 중...');\r\n await watcher.stop();\r\n\r\n logger.newline();\r\n logger.info('📊 세션 요약:');\r\n logger.info(` 검증 실행: ${validationCount}회`);\r\n logger.info(` 에러 발생: ${errorCount}회`);\r\n\r\n process.exit(0);\r\n };\r\n\r\n process.on('SIGINT', cleanup);\r\n process.on('SIGTERM', cleanup);\r\n\r\n // 감시 시작\r\n watcher.start();\r\n\r\n // 무한 대기\r\n await new Promise(() => {});\r\n}\r\n","/**\r\n * 파일 감시 모듈\r\n *\r\n * .sdd/specs/ 디렉토리의 파일 변경을 감시합니다.\r\n */\r\nimport chokidar, { FSWatcher } from 'chokidar';\r\nimport path from 'node:path';\r\nimport { EventEmitter } from 'node:events';\r\n\r\n/**\r\n * 파일 이벤트 타입\r\n */\r\nexport type FileEventType = 'add' | 'change' | 'unlink';\r\n\r\n/**\r\n * 파일 이벤트\r\n */\r\nexport interface FileEvent {\r\n type: FileEventType;\r\n path: string;\r\n relativePath: string;\r\n timestamp: Date;\r\n}\r\n\r\n/**\r\n * Watch 옵션\r\n */\r\nexport interface WatchOptions {\r\n specsPath: string;\r\n debounceMs?: number;\r\n ignored?: string[];\r\n}\r\n\r\n/**\r\n * Watch 결과\r\n */\r\nexport interface WatchResult {\r\n events: FileEvent[];\r\n duration: number;\r\n}\r\n\r\n/**\r\n * 파일 감시자 클래스\r\n */\r\nexport class SpecWatcher extends EventEmitter {\r\n private watcher: FSWatcher | null = null;\r\n private specsPath: string;\r\n private debounceMs: number;\r\n private debounceTimer: NodeJS.Timeout | null = null;\r\n private pendingEvents: FileEvent[] = [];\r\n private isRunning = false;\r\n\r\n constructor(options: WatchOptions) {\r\n super();\r\n this.specsPath = options.specsPath;\r\n this.debounceMs = options.debounceMs ?? 500;\r\n }\r\n\r\n /**\r\n * 감시 시작\r\n */\r\n start(): void {\r\n if (this.isRunning) {\r\n return;\r\n }\r\n\r\n const ignored = [\r\n '**/node_modules/**',\r\n '**/.git/**',\r\n '**/.*',\r\n ];\r\n\r\n this.watcher = chokidar.watch(this.specsPath, {\r\n persistent: true,\r\n ignoreInitial: true,\r\n ignored,\r\n awaitWriteFinish: {\r\n stabilityThreshold: 100,\r\n pollInterval: 100,\r\n },\r\n });\r\n\r\n this.watcher\r\n .on('add', (filePath) => this.handleEvent('add', filePath))\r\n .on('change', (filePath) => this.handleEvent('change', filePath))\r\n .on('unlink', (filePath) => this.handleEvent('unlink', filePath))\r\n .on('error', (error) => this.emit('error', error))\r\n .on('ready', () => {\r\n this.isRunning = true;\r\n this.emit('ready');\r\n });\r\n }\r\n\r\n /**\r\n * 감시 중지\r\n */\r\n async stop(): Promise<void> {\r\n if (this.debounceTimer) {\r\n clearTimeout(this.debounceTimer);\r\n this.debounceTimer = null;\r\n }\r\n\r\n if (this.watcher) {\r\n await this.watcher.close();\r\n this.watcher = null;\r\n }\r\n\r\n this.isRunning = false;\r\n this.pendingEvents = [];\r\n }\r\n\r\n /**\r\n * 실행 상태 확인\r\n */\r\n get running(): boolean {\r\n return this.isRunning;\r\n }\r\n\r\n /**\r\n * 파일 이벤트 처리\r\n */\r\n private handleEvent(type: FileEventType, filePath: string): void {\r\n // .md 파일만 처리\r\n if (!filePath.endsWith('.md')) {\r\n return;\r\n }\r\n\r\n const event: FileEvent = {\r\n type,\r\n path: filePath,\r\n relativePath: path.relative(this.specsPath, filePath),\r\n timestamp: new Date(),\r\n };\r\n\r\n this.pendingEvents.push(event);\r\n\r\n // 디바운싱\r\n if (this.debounceTimer) {\r\n clearTimeout(this.debounceTimer);\r\n }\r\n\r\n this.debounceTimer = setTimeout(() => {\r\n this.flushEvents();\r\n }, this.debounceMs);\r\n }\r\n\r\n /**\r\n * 대기 중인 이벤트 처리\r\n */\r\n private flushEvents(): void {\r\n if (this.pendingEvents.length === 0) {\r\n return;\r\n }\r\n\r\n const events = [...this.pendingEvents];\r\n this.pendingEvents = [];\r\n this.debounceTimer = null;\r\n\r\n this.emit('change', events);\r\n }\r\n}\r\n\r\n/**\r\n * 감시자 생성 헬퍼\r\n */\r\nexport function createWatcher(options: WatchOptions): SpecWatcher {\r\n return new SpecWatcher(options);\r\n}\r\n","/**\r\n * quality 명령어\r\n *\r\n * 스펙 품질을 분석하고 점수를 산출합니다.\r\n */\r\nimport { Command } from 'commander';\r\nimport path from 'node:path';\r\nimport {\r\n analyzeSpecQuality,\r\n analyzeProjectQuality,\r\n formatQualityResult,\r\n formatProjectQualityResult,\r\n} from '../../core/quality/index.js';\r\nimport { findSddRoot } from '../../utils/fs.js';\r\nimport * as logger from '../../utils/logger.js';\r\nimport { ExitCode } from '../../errors/index.js';\r\n\r\n/**\r\n * quality 명령어 등록\r\n */\r\nexport function registerQualityCommand(program: Command): void {\r\n program\r\n .command('quality [feature]')\r\n .description('스펙 품질을 분석하고 점수를 산출합니다')\r\n .option('-a, --all', '전체 프로젝트 분석')\r\n .option('--json', 'JSON 형식 출력')\r\n .option('--min-score <score>', '최소 점수 기준 (이하 시 에러)', '0')\r\n .action(async (feature: string | undefined, options: {\r\n all?: boolean;\r\n json?: boolean;\r\n minScore?: string;\r\n }) => {\r\n try {\r\n await runQuality(feature, options);\r\n } catch (error) {\r\n logger.error(error instanceof Error ? error.message : String(error));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n });\r\n}\r\n\r\n/**\r\n * quality 실행\r\n */\r\nasync function runQuality(\r\n feature: string | undefined,\r\n options: { all?: boolean; json?: boolean; minScore?: string }\r\n): Promise<void> {\r\n const projectRoot = await findSddRoot();\r\n if (!projectRoot) {\r\n logger.error('SDD 프로젝트를 찾을 수 없습니다. `sdd init`을 먼저 실행하세요.');\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n const sddPath = path.join(projectRoot, '.sdd');\r\n const minScore = parseInt(options.minScore || '0', 10);\r\n\r\n // 전체 프로젝트 분석\r\n if (options.all || !feature) {\r\n const result = await analyzeProjectQuality(sddPath);\r\n\r\n if (!result.success) {\r\n logger.error(result.error.message);\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n if (options.json) {\r\n console.log(JSON.stringify(result.data, null, 2));\r\n } else {\r\n console.log(formatProjectQualityResult(result.data));\r\n }\r\n\r\n // 최소 점수 체크\r\n if (result.data.averagePercentage < minScore) {\r\n logger.newline();\r\n logger.error(`품질 점수가 최소 기준(${minScore}%) 미달입니다.`);\r\n process.exit(ExitCode.VALIDATION_ERROR);\r\n }\r\n\r\n return;\r\n }\r\n\r\n // 개별 스펙 분석\r\n const specPath = path.join(sddPath, 'specs', feature, 'spec.md');\r\n const result = await analyzeSpecQuality(specPath, sddPath);\r\n\r\n if (!result.success) {\r\n logger.error(result.error.message);\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n if (options.json) {\r\n console.log(JSON.stringify(result.data, null, 2));\r\n } else {\r\n console.log(formatQualityResult(result.data));\r\n }\r\n\r\n // 최소 점수 체크\r\n if (result.data.percentage < minScore) {\r\n logger.newline();\r\n logger.error(`품질 점수가 최소 기준(${minScore}%) 미달입니다.`);\r\n process.exit(ExitCode.VALIDATION_ERROR);\r\n }\r\n}\r\n","/**\r\n * 스펙 품질 분석기\r\n *\r\n * 스펙 파일의 품질을 분석하고 점수를 산출합니다.\r\n */\r\nimport path from 'node:path';\r\nimport { promises as fs } from 'node:fs';\r\nimport { success, failure, Result } from '../../types/index.js';\r\nimport { ChangeError } from '../../errors/index.js';\r\nimport { directoryExists, fileExists, readFile } from '../../utils/fs.js';\r\nimport { parseSpec, ParsedSpec } from '../spec/index.js';\r\nimport { parseConstitution } from '../constitution/index.js';\r\n\r\n/**\r\n * 품질 점수 항목\r\n */\r\nexport interface QualityScoreItem {\r\n name: string;\r\n score: number;\r\n maxScore: number;\r\n percentage: number;\r\n details: string[];\r\n suggestions: string[];\r\n}\r\n\r\n/**\r\n * 품질 분석 결과\r\n */\r\nexport interface QualityResult {\r\n specId: string;\r\n specPath: string;\r\n totalScore: number;\r\n maxScore: number;\r\n percentage: number;\r\n grade: 'A' | 'B' | 'C' | 'D' | 'F';\r\n items: QualityScoreItem[];\r\n summary: string;\r\n topSuggestions: string[];\r\n}\r\n\r\n/**\r\n * 전체 프로젝트 품질 결과\r\n */\r\nexport interface ProjectQualityResult {\r\n averageScore: number;\r\n averagePercentage: number;\r\n grade: 'A' | 'B' | 'C' | 'D' | 'F';\r\n totalSpecs: number;\r\n specResults: QualityResult[];\r\n summary: string;\r\n}\r\n\r\n/**\r\n * 점수를 등급으로 변환\r\n */\r\nfunction getGrade(percentage: number): 'A' | 'B' | 'C' | 'D' | 'F' {\r\n if (percentage >= 90) return 'A';\r\n if (percentage >= 80) return 'B';\r\n if (percentage >= 70) return 'C';\r\n if (percentage >= 60) return 'D';\r\n return 'F';\r\n}\r\n\r\n/**\r\n * RFC 2119 키워드 점수 산출 (10점)\r\n */\r\nfunction scoreRfc2119(content: string): QualityScoreItem {\r\n const maxScore = 10;\r\n const details: string[] = [];\r\n const suggestions: string[] = [];\r\n\r\n const keywords = ['SHALL', 'MUST', 'SHOULD', 'MAY', 'SHALL NOT', 'MUST NOT', 'SHOULD NOT'];\r\n const found: string[] = [];\r\n\r\n for (const kw of keywords) {\r\n const regex = new RegExp(`\\\\b${kw}\\\\b`, 'gi');\r\n const matches = content.match(regex);\r\n if (matches && matches.length > 0) {\r\n found.push(`${kw}: ${matches.length}개`);\r\n }\r\n }\r\n\r\n let score = 0;\r\n if (found.length > 0) {\r\n score = Math.min(maxScore, found.length * 2);\r\n details.push(`발견된 키워드: ${found.join(', ')}`);\r\n } else {\r\n details.push('RFC 2119 키워드가 발견되지 않음');\r\n suggestions.push('요구사항에 SHALL, MUST, SHOULD, MAY 키워드를 사용하세요');\r\n }\r\n\r\n return {\r\n name: 'RFC 2119 키워드',\r\n score,\r\n maxScore,\r\n percentage: (score / maxScore) * 100,\r\n details,\r\n suggestions,\r\n };\r\n}\r\n\r\n/**\r\n * GIVEN-WHEN-THEN 시나리오 점수 (20점)\r\n */\r\nfunction scoreScenarios(content: string): QualityScoreItem {\r\n const maxScore = 20;\r\n const details: string[] = [];\r\n const suggestions: string[] = [];\r\n\r\n const givenCount = (content.match(/\\*\\*GIVEN\\*\\*|\\bGIVEN\\b/gi) || []).length;\r\n const whenCount = (content.match(/\\*\\*WHEN\\*\\*|\\bWHEN\\b/gi) || []).length;\r\n const thenCount = (content.match(/\\*\\*THEN\\*\\*|\\bTHEN\\b/gi) || []).length;\r\n\r\n const scenarioCount = Math.min(givenCount, whenCount, thenCount);\r\n\r\n let score = 0;\r\n if (scenarioCount > 0) {\r\n score = Math.min(maxScore, scenarioCount * 5);\r\n details.push(`완전한 시나리오: ${scenarioCount}개`);\r\n details.push(`GIVEN: ${givenCount}, WHEN: ${whenCount}, THEN: ${thenCount}`);\r\n } else {\r\n details.push('GIVEN-WHEN-THEN 시나리오가 없음');\r\n suggestions.push('최소 2개 이상의 GIVEN-WHEN-THEN 시나리오를 작성하세요');\r\n }\r\n\r\n if (scenarioCount < 2 && scenarioCount > 0) {\r\n suggestions.push('추가 시나리오 작성을 권장합니다 (최소 2개)');\r\n }\r\n\r\n return {\r\n name: 'GIVEN-WHEN-THEN 시나리오',\r\n score,\r\n maxScore,\r\n percentage: (score / maxScore) * 100,\r\n details,\r\n suggestions,\r\n };\r\n}\r\n\r\n/**\r\n * 요구사항 명확성 점수 (15점)\r\n */\r\nfunction scoreRequirements(content: string): QualityScoreItem {\r\n const maxScore = 15;\r\n const details: string[] = [];\r\n const suggestions: string[] = [];\r\n\r\n // REQ-XX 형식의 요구사항 ID\r\n const reqIdPattern = /REQ-\\d+|REQ-[A-Z]+-\\d+/gi;\r\n const reqIds = content.match(reqIdPattern) || [];\r\n\r\n // ## 요구사항 섹션 존재\r\n const hasRequirementsSection = /^##\\s*(요구사항|Requirements)/im.test(content);\r\n\r\n let score = 0;\r\n\r\n if (hasRequirementsSection) {\r\n score += 5;\r\n details.push('요구사항 섹션이 존재함');\r\n } else {\r\n suggestions.push('## 요구사항 섹션을 추가하세요');\r\n }\r\n\r\n if (reqIds.length > 0) {\r\n score += Math.min(10, reqIds.length * 2);\r\n details.push(`요구사항 ID: ${reqIds.length}개 (${[...new Set(reqIds)].slice(0, 3).join(', ')}...)`);\r\n } else {\r\n suggestions.push('요구사항에 REQ-01 형식의 ID를 부여하세요');\r\n }\r\n\r\n return {\r\n name: '요구사항 명확성',\r\n score,\r\n maxScore,\r\n percentage: (score / maxScore) * 100,\r\n details,\r\n suggestions,\r\n };\r\n}\r\n\r\n/**\r\n * 의존성 명시 점수 (10점)\r\n */\r\nfunction scoreDependencies(spec: ParsedSpec): QualityScoreItem {\r\n const maxScore = 10;\r\n const details: string[] = [];\r\n const suggestions: string[] = [];\r\n\r\n let score = 0;\r\n\r\n if (spec.frontmatter.depends) {\r\n const deps = Array.isArray(spec.frontmatter.depends)\r\n ? spec.frontmatter.depends\r\n : [spec.frontmatter.depends];\r\n\r\n if (deps.length > 0 && deps[0] !== null) {\r\n score = maxScore;\r\n details.push(`의존성: ${deps.join(', ')}`);\r\n } else {\r\n score = 5; // null로 명시적 선언\r\n details.push('의존성 없음 (명시적 선언)');\r\n }\r\n } else {\r\n details.push('의존성 필드가 없음');\r\n suggestions.push('frontmatter에 depends 필드를 추가하세요');\r\n }\r\n\r\n return {\r\n name: '의존성 명시',\r\n score,\r\n maxScore,\r\n percentage: (score / maxScore) * 100,\r\n details,\r\n suggestions,\r\n };\r\n}\r\n\r\n/**\r\n * 문서 구조 점수 (15점)\r\n */\r\nfunction scoreStructure(content: string): QualityScoreItem {\r\n const maxScore = 15;\r\n const details: string[] = [];\r\n const suggestions: string[] = [];\r\n\r\n const requiredSections = [\r\n { pattern: /^#\\s+.+/m, name: '제목 (H1)' },\r\n { pattern: /^##\\s*(요구사항|Requirements)/im, name: '요구사항 섹션' },\r\n { pattern: /^##\\s*(시나리오|Scenario)/im, name: '시나리오 섹션' },\r\n ];\r\n\r\n const optionalSections = [\r\n { pattern: /^##\\s*(개요|Overview|설명|Description)/im, name: '개요/설명 섹션' },\r\n { pattern: /^##\\s*(제약|Constraints|제한)/im, name: '제약사항 섹션' },\r\n { pattern: /^##\\s*(비고|Notes|참고)/im, name: '비고 섹션' },\r\n ];\r\n\r\n let score = 0;\r\n const foundRequired: string[] = [];\r\n const missingRequired: string[] = [];\r\n\r\n for (const section of requiredSections) {\r\n if (section.pattern.test(content)) {\r\n foundRequired.push(section.name);\r\n score += 4;\r\n } else {\r\n missingRequired.push(section.name);\r\n }\r\n }\r\n\r\n for (const section of optionalSections) {\r\n if (section.pattern.test(content)) {\r\n score += 1;\r\n }\r\n }\r\n\r\n score = Math.min(maxScore, score);\r\n\r\n if (foundRequired.length > 0) {\r\n details.push(`필수 섹션: ${foundRequired.join(', ')}`);\r\n }\r\n if (missingRequired.length > 0) {\r\n suggestions.push(`누락된 섹션: ${missingRequired.join(', ')}`);\r\n }\r\n\r\n return {\r\n name: '문서 구조',\r\n score,\r\n maxScore,\r\n percentage: (score / maxScore) * 100,\r\n details,\r\n suggestions,\r\n };\r\n}\r\n\r\n/**\r\n * Constitution 준수 점수 (10점)\r\n */\r\nfunction scoreConstitution(spec: ParsedSpec, hasConstitution: boolean): QualityScoreItem {\r\n const maxScore = 10;\r\n const details: string[] = [];\r\n const suggestions: string[] = [];\r\n\r\n let score = 0;\r\n\r\n if (!hasConstitution) {\r\n score = maxScore; // Constitution이 없으면 만점\r\n details.push('Constitution 미설정 (검사 생략)');\r\n } else if (spec.frontmatter.constitution_version) {\r\n score = maxScore;\r\n details.push(`Constitution 버전: ${spec.frontmatter.constitution_version}`);\r\n } else {\r\n details.push('constitution_version 필드 없음');\r\n suggestions.push('frontmatter에 constitution_version을 추가하세요');\r\n }\r\n\r\n return {\r\n name: 'Constitution 준수',\r\n score,\r\n maxScore,\r\n percentage: (score / maxScore) * 100,\r\n details,\r\n suggestions,\r\n };\r\n}\r\n\r\n/**\r\n * 참조 링크 점수 (10점)\r\n */\r\nfunction scoreLinks(content: string): QualityScoreItem {\r\n const maxScore = 10;\r\n const details: string[] = [];\r\n const suggestions: string[] = [];\r\n\r\n // 마크다운 링크 패턴\r\n const linkPattern = /\\[([^\\]]+)\\]\\(([^)]+)\\)/g;\r\n const links = [...content.matchAll(linkPattern)];\r\n\r\n let score = 5; // 기본 점수\r\n\r\n if (links.length > 0) {\r\n score = Math.min(maxScore, 5 + links.length);\r\n details.push(`링크: ${links.length}개`);\r\n } else {\r\n details.push('링크 없음');\r\n suggestions.push('관련 문서나 외부 참조 링크를 추가하면 좋습니다');\r\n }\r\n\r\n return {\r\n name: '참조 링크',\r\n score,\r\n maxScore,\r\n percentage: (score / maxScore) * 100,\r\n details,\r\n suggestions,\r\n };\r\n}\r\n\r\n/**\r\n * 메타데이터 완성도 점수 (10점)\r\n */\r\nfunction scoreMetadata(spec: ParsedSpec): QualityScoreItem {\r\n const maxScore = 10;\r\n const details: string[] = [];\r\n const suggestions: string[] = [];\r\n\r\n const requiredFields = ['id', 'title', 'status'];\r\n const optionalFields = ['created', 'updated', 'author', 'version'];\r\n\r\n let score = 0;\r\n const missingRequired: string[] = [];\r\n\r\n for (const field of requiredFields) {\r\n if (spec.frontmatter[field]) {\r\n score += 2;\r\n } else {\r\n missingRequired.push(field);\r\n }\r\n }\r\n\r\n for (const field of optionalFields) {\r\n if (spec.frontmatter[field]) {\r\n score += 1;\r\n }\r\n }\r\n\r\n score = Math.min(maxScore, score);\r\n\r\n const presentFields = Object.keys(spec.frontmatter).filter(\r\n (k) => spec.frontmatter[k] !== null && spec.frontmatter[k] !== undefined\r\n );\r\n details.push(`메타데이터 필드: ${presentFields.length}개`);\r\n\r\n if (missingRequired.length > 0) {\r\n suggestions.push(`필수 필드 누락: ${missingRequired.join(', ')}`);\r\n }\r\n\r\n return {\r\n name: '메타데이터 완성도',\r\n score,\r\n maxScore,\r\n percentage: (score / maxScore) * 100,\r\n details,\r\n suggestions,\r\n };\r\n}\r\n\r\n/**\r\n * 단일 스펙 품질 분석\r\n */\r\nexport async function analyzeSpecQuality(\r\n specPath: string,\r\n sddPath: string\r\n): Promise<Result<QualityResult, ChangeError>> {\r\n try {\r\n if (!(await fileExists(specPath))) {\r\n return failure(new ChangeError(`스펙 파일을 찾을 수 없습니다: ${specPath}`));\r\n }\r\n\r\n const contentResult = await readFile(specPath);\r\n if (!contentResult.success) {\r\n return failure(new ChangeError('스펙 파일을 읽을 수 없습니다.'));\r\n }\r\n\r\n const content = contentResult.data;\r\n const parseResult = parseSpec(content);\r\n if (!parseResult.success) {\r\n return failure(new ChangeError(`스펙 파싱 실패: ${parseResult.error.message}`));\r\n }\r\n\r\n const spec = parseResult.data;\r\n\r\n // Constitution 존재 여부 확인\r\n const constitutionPath = path.join(sddPath, 'constitution.md');\r\n const hasConstitution = await fileExists(constitutionPath);\r\n\r\n // 각 항목 점수 산출\r\n const items: QualityScoreItem[] = [\r\n scoreRfc2119(content),\r\n scoreScenarios(content),\r\n scoreRequirements(content),\r\n scoreDependencies(spec),\r\n scoreStructure(content),\r\n scoreConstitution(spec, hasConstitution),\r\n scoreLinks(content),\r\n scoreMetadata(spec),\r\n ];\r\n\r\n // 총점 계산\r\n const totalScore = items.reduce((sum, item) => sum + item.score, 0);\r\n const maxScore = items.reduce((sum, item) => sum + item.maxScore, 0);\r\n const percentage = Math.round((totalScore / maxScore) * 100);\r\n const grade = getGrade(percentage);\r\n\r\n // 상위 제안 추출\r\n const topSuggestions = items\r\n .filter((item) => item.suggestions.length > 0)\r\n .sort((a, b) => a.percentage - b.percentage)\r\n .slice(0, 3)\r\n .flatMap((item) => item.suggestions);\r\n\r\n const specId = spec.frontmatter.id || path.basename(path.dirname(specPath));\r\n\r\n const summary = `스펙 '${specId}'의 품질 점수: ${totalScore}/${maxScore} (${percentage}%, 등급: ${grade})`;\r\n\r\n return success({\r\n specId,\r\n specPath,\r\n totalScore,\r\n maxScore,\r\n percentage,\r\n grade,\r\n items,\r\n summary,\r\n topSuggestions,\r\n });\r\n } catch (error) {\r\n return failure(\r\n new ChangeError(\r\n `품질 분석 실패: ${error instanceof Error ? error.message : String(error)}`\r\n )\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * 전체 프로젝트 품질 분석\r\n */\r\nexport async function analyzeProjectQuality(\r\n sddPath: string\r\n): Promise<Result<ProjectQualityResult, ChangeError>> {\r\n try {\r\n const specsPath = path.join(sddPath, 'specs');\r\n\r\n if (!(await directoryExists(specsPath))) {\r\n return failure(new ChangeError('스펙 디렉토리를 찾을 수 없습니다.'));\r\n }\r\n\r\n // 모든 spec.md 파일 찾기\r\n const specFiles: string[] = [];\r\n await findSpecFiles(specsPath, specFiles);\r\n\r\n if (specFiles.length === 0) {\r\n return failure(new ChangeError('스펙 파일이 없습니다.'));\r\n }\r\n\r\n // 각 스펙 분석\r\n const specResults: QualityResult[] = [];\r\n for (const specFile of specFiles) {\r\n const result = await analyzeSpecQuality(specFile, sddPath);\r\n if (result.success) {\r\n specResults.push(result.data);\r\n }\r\n }\r\n\r\n if (specResults.length === 0) {\r\n return failure(new ChangeError('분석 가능한 스펙이 없습니다.'));\r\n }\r\n\r\n // 평균 점수 계산\r\n const totalPercentage = specResults.reduce((sum, r) => sum + r.percentage, 0);\r\n const averagePercentage = Math.round(totalPercentage / specResults.length);\r\n const averageScore = Math.round(\r\n specResults.reduce((sum, r) => sum + r.totalScore, 0) / specResults.length\r\n );\r\n const grade = getGrade(averagePercentage);\r\n\r\n const summary = `프로젝트 품질: 평균 ${averagePercentage}% (등급: ${grade}), ${specResults.length}개 스펙 분석`;\r\n\r\n return success({\r\n averageScore,\r\n averagePercentage,\r\n grade,\r\n totalSpecs: specResults.length,\r\n specResults,\r\n summary,\r\n });\r\n } catch (error) {\r\n return failure(\r\n new ChangeError(\r\n `프로젝트 품질 분석 실패: ${error instanceof Error ? error.message : String(error)}`\r\n )\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * spec.md 파일 재귀 검색\r\n */\r\nasync function findSpecFiles(dir: string, files: string[]): Promise<void> {\r\n const entries = await fs.readdir(dir, { withFileTypes: true });\r\n\r\n for (const entry of entries) {\r\n const fullPath = path.join(dir, entry.name);\r\n\r\n if (entry.isDirectory()) {\r\n await findSpecFiles(fullPath, files);\r\n } else if (entry.name === 'spec.md') {\r\n files.push(fullPath);\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * 품질 결과 포맷팅\r\n */\r\nexport function formatQualityResult(result: QualityResult): string {\r\n const lines: string[] = [];\r\n\r\n const gradeIcon = result.grade === 'A' ? '🏆' :\r\n result.grade === 'B' ? '✅' :\r\n result.grade === 'C' ? '🟡' :\r\n result.grade === 'D' ? '🟠' : '🔴';\r\n\r\n lines.push(`📊 품질 분석: ${result.specId}`);\r\n lines.push(` ${gradeIcon} 등급: ${result.grade} (${result.percentage}%)`);\r\n lines.push(` 📈 점수: ${result.totalScore}/${result.maxScore}`);\r\n lines.push('');\r\n\r\n lines.push('📋 항목별 점수:');\r\n for (const item of result.items) {\r\n const icon = item.percentage >= 80 ? '✅' :\r\n item.percentage >= 60 ? '🟡' : '🔴';\r\n lines.push(` ${icon} ${item.name}: ${item.score}/${item.maxScore} (${Math.round(item.percentage)}%)`);\r\n\r\n for (const detail of item.details) {\r\n lines.push(` └─ ${detail}`);\r\n }\r\n }\r\n lines.push('');\r\n\r\n if (result.topSuggestions.length > 0) {\r\n lines.push('💡 개선 제안:');\r\n for (const suggestion of result.topSuggestions) {\r\n lines.push(` - ${suggestion}`);\r\n }\r\n }\r\n\r\n return lines.join('\\n');\r\n}\r\n\r\n/**\r\n * 프로젝트 품질 결과 포맷팅\r\n */\r\nexport function formatProjectQualityResult(result: ProjectQualityResult): string {\r\n const lines: string[] = [];\r\n\r\n const gradeIcon = result.grade === 'A' ? '🏆' :\r\n result.grade === 'B' ? '✅' :\r\n result.grade === 'C' ? '🟡' :\r\n result.grade === 'D' ? '🟠' : '🔴';\r\n\r\n lines.push('📊 프로젝트 품질 분석');\r\n lines.push(` ${gradeIcon} 평균 등급: ${result.grade} (${result.averagePercentage}%)`);\r\n lines.push(` 📈 분석된 스펙: ${result.totalSpecs}개`);\r\n lines.push('');\r\n\r\n // 등급별 분포\r\n const gradeCount = { A: 0, B: 0, C: 0, D: 0, F: 0 };\r\n for (const spec of result.specResults) {\r\n gradeCount[spec.grade]++;\r\n }\r\n\r\n lines.push('📈 등급 분포:');\r\n if (gradeCount.A > 0) lines.push(` 🏆 A: ${gradeCount.A}개`);\r\n if (gradeCount.B > 0) lines.push(` ✅ B: ${gradeCount.B}개`);\r\n if (gradeCount.C > 0) lines.push(` 🟡 C: ${gradeCount.C}개`);\r\n if (gradeCount.D > 0) lines.push(` 🟠 D: ${gradeCount.D}개`);\r\n if (gradeCount.F > 0) lines.push(` 🔴 F: ${gradeCount.F}개`);\r\n lines.push('');\r\n\r\n // 스펙별 요약\r\n lines.push('📋 스펙별 점수:');\r\n const sortedSpecs = [...result.specResults].sort((a, b) => b.percentage - a.percentage);\r\n for (const spec of sortedSpecs) {\r\n const icon = spec.grade === 'A' ? '🏆' :\r\n spec.grade === 'B' ? '✅' :\r\n spec.grade === 'C' ? '🟡' :\r\n spec.grade === 'D' ? '🟠' : '🔴';\r\n lines.push(` ${icon} ${spec.specId}: ${spec.percentage}% (${spec.grade})`);\r\n }\r\n\r\n return lines.join('\\n');\r\n}\r\n","/**\r\n * report 명령어\r\n *\r\n * 스펙 리포트를 HTML, Markdown, JSON 형식으로 내보냅니다.\r\n */\r\nimport { Command } from 'commander';\r\nimport path from 'node:path';\r\nimport {\r\n generateReport,\r\n ReportFormat,\r\n} from '../../core/report/index.js';\r\nimport { findSddRoot } from '../../utils/fs.js';\r\nimport * as logger from '../../utils/logger.js';\r\nimport { ExitCode } from '../../errors/index.js';\r\n\r\n/**\r\n * report 명령어 등록\r\n */\r\nexport function registerReportCommand(program: Command): void {\r\n program\r\n .command('report')\r\n .description('스펙 리포트를 생성합니다')\r\n .option('-f, --format <format>', '출력 형식 (html, markdown, json)', 'html')\r\n .option('-o, --output <path>', '출력 파일 경로')\r\n .option('--title <title>', '리포트 제목')\r\n .option('--no-quality', '품질 분석 제외')\r\n .option('--no-validation', '검증 결과 제외')\r\n .action(async (options: {\r\n format?: string;\r\n output?: string;\r\n title?: string;\r\n quality?: boolean;\r\n validation?: boolean;\r\n }) => {\r\n try {\r\n await runReport(options);\r\n } catch (error) {\r\n logger.error(error instanceof Error ? error.message : String(error));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n });\r\n}\r\n\r\n/**\r\n * report 실행\r\n */\r\nasync function runReport(options: {\r\n format?: string;\r\n output?: string;\r\n title?: string;\r\n quality?: boolean;\r\n validation?: boolean;\r\n}): Promise<void> {\r\n const projectRoot = await findSddRoot();\r\n if (!projectRoot) {\r\n logger.error('SDD 프로젝트를 찾을 수 없습니다. `sdd init`을 먼저 실행하세요.');\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n const sddPath = path.join(projectRoot, '.sdd');\r\n const format = (options.format || 'html') as ReportFormat;\r\n\r\n // 형식 검증\r\n if (!['html', 'markdown', 'json'].includes(format)) {\r\n logger.error(`지원하지 않는 형식입니다: ${format}`);\r\n logger.info('지원 형식: html, markdown, json');\r\n process.exit(ExitCode.VALIDATION_ERROR);\r\n }\r\n\r\n // 기본 출력 경로 설정\r\n let outputPath = options.output;\r\n if (!outputPath) {\r\n const ext = format === 'markdown' ? 'md' : format;\r\n const timestamp = new Date().toISOString().slice(0, 10);\r\n outputPath = path.join(projectRoot, `sdd-report-${timestamp}.${ext}`);\r\n } else if (!path.isAbsolute(outputPath)) {\r\n outputPath = path.join(projectRoot, outputPath);\r\n }\r\n\r\n logger.info('📊 리포트 생성 중...');\r\n logger.info(` 형식: ${format}`);\r\n logger.info(` 품질 분석: ${options.quality !== false ? '포함' : '제외'}`);\r\n logger.info(` 검증 결과: ${options.validation !== false ? '포함' : '제외'}`);\r\n logger.newline();\r\n\r\n const result = await generateReport(sddPath, {\r\n format,\r\n outputPath,\r\n title: options.title,\r\n includeQuality: options.quality !== false,\r\n includeValidation: options.validation !== false,\r\n });\r\n\r\n if (!result.success) {\r\n logger.error(result.error.message);\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n }\r\n\r\n logger.success(`✅ 리포트가 생성되었습니다.`);\r\n logger.info(` 경로: ${result.data.outputPath}`);\r\n\r\n // 출력 없이 콘솔에 표시\r\n if (!options.output && format === 'json') {\r\n logger.newline();\r\n console.log(result.data.content);\r\n }\r\n}\r\n","/**\r\n * 리포트 생성 모듈\r\n *\r\n * 스펙 상태와 품질을 HTML/Markdown 형식으로 내보냅니다.\r\n */\r\nimport path from 'node:path';\r\nimport fs from 'node:fs/promises';\r\nimport { Result, success, failure } from '../../types/index.js';\r\nimport { ChangeError } from '../../errors/index.js';\r\nimport { analyzeProjectQuality, ProjectQualityResult } from '../quality/index.js';\r\nimport { validateSpecs, ValidateResult } from '../spec/index.js';\r\nimport { readDir, fileExists } from '../../utils/fs.js';\r\n\r\n/**\r\n * 스펙 목록 아이템\r\n */\r\nexport interface SpecListItem {\r\n id: string;\r\n title?: string;\r\n phase?: string;\r\n status?: string;\r\n description?: string;\r\n}\r\n\r\n/**\r\n * 리포트 형식\r\n */\r\nexport type ReportFormat = 'html' | 'markdown' | 'json';\r\n\r\n/**\r\n * 리포트 옵션\r\n */\r\nexport interface ReportOptions {\r\n format: ReportFormat;\r\n outputPath?: string;\r\n includeQuality?: boolean;\r\n includeValidation?: boolean;\r\n title?: string;\r\n}\r\n\r\n/**\r\n * 리포트 데이터\r\n */\r\nexport interface ReportData {\r\n title: string;\r\n generatedAt: string;\r\n projectPath: string;\r\n specs: SpecListItem[];\r\n quality?: ProjectQualityResult;\r\n validation?: ValidateResult;\r\n summary: {\r\n totalSpecs: number;\r\n byPhase: Record<string, number>;\r\n byStatus: Record<string, number>;\r\n averageQuality?: number;\r\n validationErrors?: number;\r\n validationWarnings?: number;\r\n };\r\n}\r\n\r\n/**\r\n * 리포트 결과\r\n */\r\nexport interface ReportResult {\r\n format: ReportFormat;\r\n content: string;\r\n outputPath?: string;\r\n}\r\n\r\n/**\r\n * 스펙 목록 로드\r\n */\r\nasync function loadSpecList(specsPath: string): Promise<Result<SpecListItem[], ChangeError>> {\r\n try {\r\n if (!(await fileExists(specsPath))) {\r\n return failure(new ChangeError('스펙 디렉토리를 찾을 수 없습니다.'));\r\n }\r\n\r\n const result = await readDir(specsPath);\r\n if (!result.success) {\r\n return failure(new ChangeError('스펙 디렉토리를 읽을 수 없습니다.'));\r\n }\r\n\r\n const specs: SpecListItem[] = [];\r\n\r\n for (const entry of result.data) {\r\n const featurePath = path.join(specsPath, entry);\r\n const stat = await fs.stat(featurePath);\r\n\r\n if (stat.isDirectory()) {\r\n const specFile = path.join(featurePath, 'spec.md');\r\n if (await fileExists(specFile)) {\r\n const content = await fs.readFile(specFile, 'utf-8');\r\n const metadata = parseSpecMetadata(content);\r\n\r\n specs.push({\r\n id: entry,\r\n title: metadata?.title,\r\n phase: metadata?.phase,\r\n status: metadata?.status,\r\n description: metadata?.description,\r\n });\r\n }\r\n }\r\n }\r\n\r\n return success(specs);\r\n } catch (error) {\r\n return failure(new ChangeError(error instanceof Error ? error.message : String(error)));\r\n }\r\n}\r\n\r\n/**\r\n * 스펙 메타데이터 파싱\r\n */\r\nfunction parseSpecMetadata(content: string): {\r\n title?: string;\r\n phase?: string;\r\n status?: string;\r\n description?: string;\r\n} | null {\r\n const frontmatterMatch = content.match(/^---\\n([\\s\\S]*?)\\n---/);\r\n if (!frontmatterMatch) return null;\r\n\r\n const frontmatter = frontmatterMatch[1];\r\n const result: Record<string, string> = {};\r\n\r\n const lines = frontmatter.split('\\n');\r\n for (const line of lines) {\r\n const match = line.match(/^(\\w+):\\s*['\"]?([^'\"]+)['\"]?$/);\r\n if (match) {\r\n result[match[1]] = match[2].trim();\r\n }\r\n }\r\n\r\n return {\r\n title: result.title,\r\n phase: result.phase,\r\n status: result.status,\r\n description: result.description,\r\n };\r\n}\r\n\r\n/**\r\n * 리포트 생성\r\n */\r\nexport async function generateReport(\r\n sddPath: string,\r\n options: ReportOptions\r\n): Promise<Result<ReportResult, ChangeError>> {\r\n try {\r\n // 스펙 목록 로드\r\n const specsPath = path.join(sddPath, 'specs');\r\n const specsResult = await loadSpecList(specsPath);\r\n\r\n if (!specsResult.success) {\r\n return failure(specsResult.error);\r\n }\r\n\r\n const specs = specsResult.data;\r\n\r\n // 리포트 데이터 구성\r\n const reportData: ReportData = {\r\n title: options.title || 'SDD 프로젝트 리포트',\r\n generatedAt: new Date().toISOString(),\r\n projectPath: sddPath,\r\n specs,\r\n summary: {\r\n totalSpecs: specs.length,\r\n byPhase: {},\r\n byStatus: {},\r\n },\r\n };\r\n\r\n // Phase별 집계\r\n for (const spec of specs) {\r\n const phase = spec.phase || 'unknown';\r\n reportData.summary.byPhase[phase] = (reportData.summary.byPhase[phase] || 0) + 1;\r\n\r\n const status = spec.status || 'unknown';\r\n reportData.summary.byStatus[status] = (reportData.summary.byStatus[status] || 0) + 1;\r\n }\r\n\r\n // 품질 분석 포함\r\n if (options.includeQuality !== false) {\r\n const qualityResult = await analyzeProjectQuality(sddPath);\r\n if (qualityResult.success) {\r\n reportData.quality = qualityResult.data;\r\n reportData.summary.averageQuality = qualityResult.data.averagePercentage;\r\n }\r\n }\r\n\r\n // 검증 결과 포함\r\n if (options.includeValidation !== false) {\r\n const validationResult = await validateSpecs(sddPath, { strict: false });\r\n if (validationResult.success) {\r\n reportData.validation = validationResult.data;\r\n reportData.summary.validationErrors = validationResult.data.errorCount;\r\n reportData.summary.validationWarnings = validationResult.data.warningCount;\r\n }\r\n }\r\n\r\n // 형식별 렌더링\r\n let content: string;\r\n switch (options.format) {\r\n case 'html':\r\n content = renderHtmlReport(reportData);\r\n break;\r\n case 'markdown':\r\n content = renderMarkdownReport(reportData);\r\n break;\r\n case 'json':\r\n content = JSON.stringify(reportData, null, 2);\r\n break;\r\n default:\r\n return failure(new ChangeError(`지원하지 않는 형식입니다: ${options.format}`));\r\n }\r\n\r\n // 파일로 저장\r\n if (options.outputPath) {\r\n await fs.mkdir(path.dirname(options.outputPath), { recursive: true });\r\n await fs.writeFile(options.outputPath, content, 'utf-8');\r\n }\r\n\r\n return success({\r\n format: options.format,\r\n content,\r\n outputPath: options.outputPath,\r\n });\r\n } catch (error) {\r\n return failure(new ChangeError(error instanceof Error ? error.message : String(error)));\r\n }\r\n}\r\n\r\n/**\r\n * HTML 리포트 렌더링\r\n */\r\nfunction renderHtmlReport(data: ReportData): string {\r\n const gradeColor = (grade?: string): string => {\r\n switch (grade) {\r\n case 'A': return '#22c55e';\r\n case 'B': return '#84cc16';\r\n case 'C': return '#eab308';\r\n case 'D': return '#f97316';\r\n case 'F': return '#ef4444';\r\n default: return '#6b7280';\r\n }\r\n };\r\n\r\n const statusBadge = (status: string): string => {\r\n const colors: Record<string, string> = {\r\n draft: '#6b7280',\r\n review: '#3b82f6',\r\n approved: '#22c55e',\r\n implemented: '#8b5cf6',\r\n deprecated: '#ef4444',\r\n };\r\n const color = colors[status] || '#6b7280';\r\n return `<span style=\"background:${color};color:white;padding:2px 8px;border-radius:4px;font-size:12px;\">${status}</span>`;\r\n };\r\n\r\n const specRows = data.specs.map(spec => `\r\n <tr>\r\n <td><strong>${spec.id}</strong></td>\r\n <td>${spec.title || '-'}</td>\r\n <td>${spec.phase || '-'}</td>\r\n <td>${statusBadge(spec.status || 'unknown')}</td>\r\n <td>${spec.description || '-'}</td>\r\n </tr>\r\n `).join('');\r\n\r\n const qualityRows = data.quality?.results.map(q => `\r\n <tr>\r\n <td>${q.specId}</td>\r\n <td>${q.percentage}%</td>\r\n <td style=\"color:${gradeColor(q.grade)};font-weight:bold;\">${q.grade}</td>\r\n <td>${q.totalScore}/${q.maxScore}</td>\r\n </tr>\r\n `).join('') || '';\r\n\r\n const validationRows = data.validation?.results.map(v => `\r\n <tr>\r\n <td>${v.file}</td>\r\n <td style=\"color:${v.errors.length > 0 ? '#ef4444' : '#22c55e'};\">${v.errors.length > 0 ? '❌ 실패' : '✅ 통과'}</td>\r\n <td>${v.errors.length}</td>\r\n <td>${v.warnings.length}</td>\r\n </tr>\r\n `).join('') || '';\r\n\r\n return `<!DOCTYPE html>\r\n<html lang=\"ko\">\r\n<head>\r\n <meta charset=\"UTF-8\">\r\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n <title>${data.title}</title>\r\n <style>\r\n * { box-sizing: border-box; margin: 0; padding: 0; }\r\n body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; line-height: 1.6; color: #1f2937; background: #f9fafb; padding: 2rem; }\r\n .container { max-width: 1200px; margin: 0 auto; }\r\n h1 { font-size: 2rem; margin-bottom: 0.5rem; color: #111827; }\r\n h2 { font-size: 1.5rem; margin: 2rem 0 1rem; color: #374151; border-bottom: 2px solid #e5e7eb; padding-bottom: 0.5rem; }\r\n .meta { color: #6b7280; margin-bottom: 2rem; }\r\n .summary { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 1rem; margin-bottom: 2rem; }\r\n .card { background: white; border-radius: 8px; padding: 1.5rem; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }\r\n .card-title { font-size: 0.875rem; color: #6b7280; margin-bottom: 0.5rem; }\r\n .card-value { font-size: 2rem; font-weight: bold; color: #111827; }\r\n .card-value.success { color: #22c55e; }\r\n .card-value.warning { color: #eab308; }\r\n .card-value.error { color: #ef4444; }\r\n table { width: 100%; border-collapse: collapse; background: white; border-radius: 8px; overflow: hidden; box-shadow: 0 1px 3px rgba(0,0,0,0.1); margin-bottom: 2rem; }\r\n th, td { padding: 0.75rem 1rem; text-align: left; border-bottom: 1px solid #e5e7eb; }\r\n th { background: #f3f4f6; font-weight: 600; color: #374151; }\r\n tr:hover { background: #f9fafb; }\r\n .phase-chart { display: flex; gap: 0.5rem; flex-wrap: wrap; }\r\n .phase-item { background: #e0e7ff; color: #3730a3; padding: 0.25rem 0.75rem; border-radius: 9999px; font-size: 0.875rem; }\r\n </style>\r\n</head>\r\n<body>\r\n <div class=\"container\">\r\n <h1>${data.title}</h1>\r\n <p class=\"meta\">생성: ${new Date(data.generatedAt).toLocaleString('ko-KR')} | 경로: ${data.projectPath}</p>\r\n\r\n <div class=\"summary\">\r\n <div class=\"card\">\r\n <div class=\"card-title\">총 스펙 수</div>\r\n <div class=\"card-value\">${data.summary.totalSpecs}</div>\r\n </div>\r\n ${data.summary.averageQuality !== undefined ? `\r\n <div class=\"card\">\r\n <div class=\"card-title\">평균 품질</div>\r\n <div class=\"card-value ${data.summary.averageQuality >= 80 ? 'success' : data.summary.averageQuality >= 60 ? 'warning' : 'error'}\">${data.summary.averageQuality.toFixed(1)}%</div>\r\n </div>` : ''}\r\n ${data.summary.validationErrors !== undefined ? `\r\n <div class=\"card\">\r\n <div class=\"card-title\">검증 에러</div>\r\n <div class=\"card-value ${data.summary.validationErrors === 0 ? 'success' : 'error'}\">${data.summary.validationErrors}</div>\r\n </div>` : ''}\r\n ${data.summary.validationWarnings !== undefined ? `\r\n <div class=\"card\">\r\n <div class=\"card-title\">검증 경고</div>\r\n <div class=\"card-value ${data.summary.validationWarnings === 0 ? 'success' : 'warning'}\">${data.summary.validationWarnings}</div>\r\n </div>` : ''}\r\n </div>\r\n\r\n <h2>Phase별 분포</h2>\r\n <div class=\"phase-chart\">\r\n ${Object.entries(data.summary.byPhase).map(([phase, count]) => `\r\n <span class=\"phase-item\">${phase}: ${count}</span>\r\n `).join('')}\r\n </div>\r\n\r\n <h2>스펙 목록</h2>\r\n <table>\r\n <thead>\r\n <tr>\r\n <th>ID</th>\r\n <th>제목</th>\r\n <th>Phase</th>\r\n <th>상태</th>\r\n <th>설명</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n ${specRows}\r\n </tbody>\r\n </table>\r\n\r\n ${data.quality ? `\r\n <h2>품질 분석</h2>\r\n <table>\r\n <thead>\r\n <tr>\r\n <th>스펙 ID</th>\r\n <th>점수</th>\r\n <th>등급</th>\r\n <th>상세</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n ${qualityRows}\r\n </tbody>\r\n </table>` : ''}\r\n\r\n ${data.validation ? `\r\n <h2>검증 결과</h2>\r\n <table>\r\n <thead>\r\n <tr>\r\n <th>파일</th>\r\n <th>상태</th>\r\n <th>에러</th>\r\n <th>경고</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n ${validationRows}\r\n </tbody>\r\n </table>` : ''}\r\n\r\n <footer style=\"margin-top:3rem;padding-top:1rem;border-top:1px solid #e5e7eb;color:#6b7280;font-size:0.875rem;\">\r\n Generated by SDD CLI v0.5.0\r\n </footer>\r\n </div>\r\n</body>\r\n</html>`;\r\n}\r\n\r\n/**\r\n * Markdown 리포트 렌더링\r\n */\r\nfunction renderMarkdownReport(data: ReportData): string {\r\n const lines: string[] = [];\r\n\r\n lines.push(`# ${data.title}`);\r\n lines.push('');\r\n lines.push(`> 생성: ${new Date(data.generatedAt).toLocaleString('ko-KR')}`);\r\n lines.push(`> 경로: ${data.projectPath}`);\r\n lines.push('');\r\n\r\n // 요약\r\n lines.push('## 요약');\r\n lines.push('');\r\n lines.push(`| 항목 | 값 |`);\r\n lines.push(`|------|-----|`);\r\n lines.push(`| 총 스펙 수 | ${data.summary.totalSpecs} |`);\r\n if (data.summary.averageQuality !== undefined) {\r\n lines.push(`| 평균 품질 | ${data.summary.averageQuality.toFixed(1)}% |`);\r\n }\r\n if (data.summary.validationErrors !== undefined) {\r\n lines.push(`| 검증 에러 | ${data.summary.validationErrors} |`);\r\n }\r\n if (data.summary.validationWarnings !== undefined) {\r\n lines.push(`| 검증 경고 | ${data.summary.validationWarnings} |`);\r\n }\r\n lines.push('');\r\n\r\n // Phase별 분포\r\n lines.push('## Phase별 분포');\r\n lines.push('');\r\n for (const [phase, count] of Object.entries(data.summary.byPhase)) {\r\n lines.push(`- **${phase}**: ${count}개`);\r\n }\r\n lines.push('');\r\n\r\n // 상태별 분포\r\n lines.push('## 상태별 분포');\r\n lines.push('');\r\n for (const [status, count] of Object.entries(data.summary.byStatus)) {\r\n lines.push(`- **${status}**: ${count}개`);\r\n }\r\n lines.push('');\r\n\r\n // 스펙 목록\r\n lines.push('## 스펙 목록');\r\n lines.push('');\r\n lines.push('| ID | 제목 | Phase | 상태 |');\r\n lines.push('|----|------|-------|------|');\r\n for (const spec of data.specs) {\r\n lines.push(`| ${spec.id} | ${spec.title || '-'} | ${spec.phase || '-'} | ${spec.status || '-'} |`);\r\n }\r\n lines.push('');\r\n\r\n // 품질 분석\r\n if (data.quality) {\r\n lines.push('## 품질 분석');\r\n lines.push('');\r\n lines.push(`평균 점수: **${data.quality.averagePercentage.toFixed(1)}%** (${data.quality.averageGrade})`);\r\n lines.push('');\r\n lines.push('| 스펙 ID | 점수 | 등급 |');\r\n lines.push('|---------|------|------|');\r\n for (const q of data.quality.results) {\r\n lines.push(`| ${q.specId} | ${q.percentage}% | ${q.grade} |`);\r\n }\r\n lines.push('');\r\n }\r\n\r\n // 검증 결과\r\n if (data.validation) {\r\n lines.push('## 검증 결과');\r\n lines.push('');\r\n lines.push(`- 검증된 스펙: ${data.validation.validCount}개`);\r\n lines.push(`- 에러: ${data.validation.errorCount}개`);\r\n lines.push(`- 경고: ${data.validation.warningCount}개`);\r\n lines.push('');\r\n\r\n if (data.validation.errorCount > 0 || data.validation.warningCount > 0) {\r\n lines.push('### 상세 결과');\r\n lines.push('');\r\n for (const v of data.validation.results) {\r\n if (v.errors.length > 0 || v.warnings.length > 0) {\r\n lines.push(`#### ${v.file}`);\r\n for (const e of v.errors) {\r\n lines.push(`- ${e}`);\r\n }\r\n for (const w of v.warnings) {\r\n lines.push(`- ${w}`);\r\n }\r\n lines.push('');\r\n }\r\n }\r\n }\r\n }\r\n\r\n lines.push('---');\r\n lines.push('*Generated by SDD CLI v0.5.0*');\r\n\r\n return lines.join('\\n');\r\n}\r\n"],"mappings":"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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAmEX;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAqEX;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAuEX;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAiEX;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAsDX;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAoEX;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAA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AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAiGP,IAAM,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAuGpB,IAAM,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA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","names":["path","error","error","z","title","error","info","title","path","path","success","program","error","path","success","path","chalk","path","title","error","z","z","matter","matter","error","title","path","fs","path","program","error","path","chalk","program","error","path","fs","z","matter","z","title","error","matter","z","title","error","path","fs","path","fs","error","title","program","error","path","changePath","fs","title","success","path","z","ImpactLevelSchema","fs","path","matter","error","path","path","error","fs","fs","error","calculateRiskScore","path","fs","path","error","fs","program","error","path","path","fs","program","path","title","fs","error","setNextFeatureNumber","path","fs","program","path","fs","info","path","fs","program","path","fs","getStatusIcon","path","program","error","runValidate","path","success","path","fs","program","error","path","fs","path","fs","path","fs","error","title","extractTitle","program","error","path","fs","title","success","path","program","error","success","path","path","program","error","path","title","success","path","path","error","program","error","path","success","path","path","fs","path","error","findSpecFiles","fs","program","error","path","result","path","path","fs","path","fs","parseSpecMetadata","error","program","error","path","success","require"]}