sdd-tool 0.1.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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/cli/index.ts","../../src/cli/commands/init.ts","../../src/utils/fs.ts","../../src/errors/codes.ts","../../src/errors/messages.ts","../../src/errors/base.ts","../../src/types/index.ts","../../src/utils/logger.ts","../../src/generators/agents-md.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/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/cli/commands/status.ts","../../src/cli/commands/list.ts"],"sourcesContent":["/**\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\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\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\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 ];\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 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.newline();\r\n logger.info('다음 단계:');\r\n logger.listItem('constitution.md를 수정하여 프로젝트 원칙을 정의하세요');\r\n logger.listItem('`sdd validate`로 스펙을 검증할 수 있습니다');\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 */\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\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\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 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 * 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 .action(async (targetPath: string, options: { strict?: boolean; quiet?: 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 }\r\n): Promise<void> {\r\n // 대상 경로 결정\r\n let resolvedPath: string;\r\n\r\n if (targetPath) {\r\n resolvedPath = path.resolve(targetPath);\r\n } else {\r\n // 기본값: .sdd/specs/\r\n const sddRoot = await findSddRoot();\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 if (!options.quiet) {\r\n logger.info(`검증 중: ${resolvedPath}`);\r\n logger.newline();\r\n }\r\n\r\n // 검증 실행\r\n const result = await validateSpecs(resolvedPath, { strict: options.strict });\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 } 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\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\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 // 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\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 updateProposalStatus,\r\n listPendingChanges,\r\n archiveChange,\r\n generateChangeId,\r\n} from '../../core/change/index.js';\r\nimport { findSddRoot, directoryExists, ensureDir, writeFile } 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\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 */\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} 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 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\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\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 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 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 {\r\n DependencyGraph,\r\n ImpactAnalysisResult,\r\n AffectedSpec,\r\n ImpactLevel,\r\n RISK_WEIGHTS,\r\n getImpactLevel,\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 } from '../../utils/fs.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 // 리스크 점수 계산\r\n const riskScore = calculateRiskScore(dependsOn, affectedBy);\r\n const riskLevel = getImpactLevel(riskScore);\r\n\r\n // 요약 및 권장사항 생성\r\n const summary = generateSummary(targetSpec, dependsOn, affectedBy, riskScore);\r\n const recommendations = generateRecommendations(affectedBy, riskLevel);\r\n\r\n return success({\r\n targetSpec,\r\n dependsOn,\r\n affectedBy,\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 calculateRiskScore(\r\n dependsOn: AffectedSpec[],\r\n affectedBy: 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 // 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 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 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 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 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 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\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} from '../../core/new/index.js';\r\nimport { logger } from '../../utils/index.js';\r\nimport { ensureDir, fileExists } from '../../utils/fs.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('--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\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 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 featureId = generateFeatureId(name);\r\n const title = options.title || name;\r\n const description = options.description || `${title} 기능 명세`;\r\n\r\n const cwd = process.cwd();\r\n const sddPath = path.join(cwd, '.sdd');\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 // spec.md 생성\r\n const specContent = generateSpec({\r\n id: featureId,\r\n title,\r\n description,\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 const result = await createBranch(featureId, { 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 */\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}\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\r\n let content = `---\r\nid: ${options.id}\r\ntitle: \"${options.title}\"\r\nstatus: ${status}\r\ncreated: ${today}\r\ndepends: ${depends}\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 * 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"],"mappings":"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AA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA0FrB,IAAM,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;A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","names":["path","path","error","error","success","program","error","path","success","path","chalk","path","title","error","fs","path","program","error","path","chalk","program","error","path","fs","z","matter","z","z","matter","title","error","matter","z","z","path","fs","path","fs","error","title","program","error","path","changePath","fs","title","success","path","z","ImpactLevelSchema","fs","path","matter","fs","path","matter","error","path","path","error","program","error","path","path","fs","z","title","error","error","title","title","program","title","path","fs","error","path","fs","program","path","fs","info","path","fs","program","path","fs","getStatusIcon","require"]}