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,240 @@
1
+ /**
2
+ * 공통 타입 정의
3
+ */
4
+ /**
5
+ * 스펙 문서 구조
6
+ */
7
+ interface Spec {
8
+ id: string;
9
+ title: string;
10
+ status: SpecStatus;
11
+ requirements: Requirement[];
12
+ scenarios: Scenario[];
13
+ dependencies: string[];
14
+ metadata: SpecMetadata;
15
+ }
16
+ type SpecStatus = 'draft' | 'approved' | 'implemented';
17
+ interface SpecMetadata {
18
+ created?: string;
19
+ updated?: string;
20
+ author?: string;
21
+ }
22
+ /**
23
+ * 요구사항 (RFC 2119)
24
+ */
25
+ interface Requirement {
26
+ id: string;
27
+ level: RequirementLevel;
28
+ description: string;
29
+ }
30
+ type RequirementLevel = 'SHALL' | 'MUST' | 'SHOULD' | 'MAY';
31
+ /**
32
+ * 시나리오 (GIVEN-WHEN-THEN)
33
+ */
34
+ interface Scenario {
35
+ name: string;
36
+ given: string[];
37
+ when: string;
38
+ then: string[];
39
+ }
40
+ /**
41
+ * Constitution 원칙
42
+ */
43
+ interface Principle {
44
+ id: string;
45
+ title: string;
46
+ description: string;
47
+ level: PrincipleLevel;
48
+ }
49
+ type PrincipleLevel = 'core' | 'technical' | 'forbidden';
50
+ interface Constitution {
51
+ projectName: string;
52
+ principles: Principle[];
53
+ technicalStack?: string[];
54
+ constraints?: string[];
55
+ }
56
+ /**
57
+ * 변경 제안
58
+ */
59
+ interface Proposal {
60
+ id: string;
61
+ title: string;
62
+ rationale: string;
63
+ affectedSpecs: string[];
64
+ deltas: Delta[];
65
+ status: ProposalStatus;
66
+ createdAt: string;
67
+ }
68
+ type ProposalStatus = 'draft' | 'review' | 'approved' | 'applied' | 'archived';
69
+ /**
70
+ * 델타 (변경사항)
71
+ */
72
+ interface Delta {
73
+ type: DeltaType;
74
+ target: string;
75
+ before?: string;
76
+ after?: string;
77
+ }
78
+ type DeltaType = 'ADDED' | 'MODIFIED' | 'REMOVED';
79
+ /**
80
+ * 검증 결과
81
+ */
82
+ interface ValidationResult {
83
+ valid: boolean;
84
+ errors: SpecValidationError[];
85
+ warnings: SpecValidationWarning[];
86
+ }
87
+ interface SpecValidationError {
88
+ code: string;
89
+ message: string;
90
+ location?: Location;
91
+ }
92
+ interface SpecValidationWarning {
93
+ code: string;
94
+ message: string;
95
+ location?: Location;
96
+ }
97
+ interface Location {
98
+ file?: string;
99
+ line?: number;
100
+ column?: number;
101
+ }
102
+ /**
103
+ * 분석 결과
104
+ */
105
+ interface AnalysisResult {
106
+ scale: Scale;
107
+ recommendation: WorkflowRecommendation;
108
+ confidence: number;
109
+ rationale: string;
110
+ alternatives: string[];
111
+ }
112
+ type Scale = 'small' | 'medium' | 'large';
113
+ type WorkflowRecommendation = 'direct' | 'change' | 'new';
114
+ /**
115
+ * Result 타입 (에러 처리용)
116
+ */
117
+ type Result<T, E = Error> = {
118
+ success: true;
119
+ data: T;
120
+ } | {
121
+ success: false;
122
+ error: E;
123
+ };
124
+ /**
125
+ * 성공 결과 생성 헬퍼
126
+ */
127
+ declare function success<T>(data: T): Result<T, never>;
128
+ /**
129
+ * 실패 결과 생성 헬퍼
130
+ */
131
+ declare function failure<E>(error: E): Result<never, E>;
132
+
133
+ /**
134
+ * 에러 코드 정의
135
+ */
136
+ /**
137
+ * CLI 종료 코드
138
+ */
139
+ declare const ExitCode: {
140
+ readonly SUCCESS: 0;
141
+ readonly GENERAL_ERROR: 1;
142
+ readonly VALIDATION_FAILED: 2;
143
+ readonly CONSTITUTION_VIOLATION: 3;
144
+ readonly FILE_SYSTEM_ERROR: 4;
145
+ readonly USER_CANCELLED: 5;
146
+ };
147
+ type ExitCode = (typeof ExitCode)[keyof typeof ExitCode];
148
+ /**
149
+ * 에러 코드
150
+ */
151
+ declare const ErrorCode: {
152
+ readonly UNKNOWN: "E001";
153
+ readonly INVALID_ARGUMENT: "E002";
154
+ readonly NOT_INITIALIZED: "E003";
155
+ readonly FILE_NOT_FOUND: "E101";
156
+ readonly FILE_READ_ERROR: "E102";
157
+ readonly FILE_WRITE_ERROR: "E103";
158
+ readonly DIRECTORY_NOT_FOUND: "E104";
159
+ readonly DIRECTORY_EXISTS: "E105";
160
+ readonly SPEC_PARSE_ERROR: "E201";
161
+ readonly SPEC_INVALID_FORMAT: "E202";
162
+ readonly SPEC_MISSING_REQUIRED: "E203";
163
+ readonly RFC2119_VIOLATION: "E204";
164
+ readonly GWT_INVALID_FORMAT: "E205";
165
+ readonly CONSTITUTION_NOT_FOUND: "E301";
166
+ readonly CONSTITUTION_PARSE_ERROR: "E302";
167
+ readonly CONSTITUTION_VIOLATION: "E303";
168
+ readonly PROPOSAL_NOT_FOUND: "E401";
169
+ readonly PROPOSAL_INVALID: "E402";
170
+ readonly DELTA_CONFLICT: "E403";
171
+ readonly ARCHIVE_FAILED: "E404";
172
+ readonly ANALYSIS_FAILED: "E501";
173
+ readonly INSUFFICIENT_DATA: "E502";
174
+ };
175
+ type ErrorCode = (typeof ErrorCode)[keyof typeof ErrorCode];
176
+
177
+ /**
178
+ * 에러 메시지 정의
179
+ */
180
+
181
+ /**
182
+ * 에러 코드별 메시지 템플릿
183
+ */
184
+ declare const ErrorMessages: Record<ErrorCode, string>;
185
+ /**
186
+ * 메시지 템플릿에 인자를 적용
187
+ */
188
+ declare function formatMessage(code: ErrorCode, ...args: string[]): string;
189
+
190
+ /**
191
+ * 에러 기본 클래스
192
+ */
193
+
194
+ /**
195
+ * SDD 도구의 기본 에러 클래스
196
+ */
197
+ declare class SddError extends Error {
198
+ readonly code: ErrorCode;
199
+ readonly exitCode: ExitCode;
200
+ constructor(code: ErrorCode, message?: string, exitCode?: ExitCode);
201
+ /**
202
+ * 사용자 친화적 메시지
203
+ */
204
+ toUserMessage(): string;
205
+ }
206
+ /**
207
+ * 파일 시스템 에러
208
+ */
209
+ declare class FileSystemError extends SddError {
210
+ readonly path: string;
211
+ constructor(code: ErrorCode, path: string);
212
+ }
213
+ /**
214
+ * 스펙 검증 에러
215
+ */
216
+ declare class ValidationError extends SddError {
217
+ readonly details: string;
218
+ constructor(code: ErrorCode, details: string);
219
+ }
220
+ /**
221
+ * Constitution 위반 에러
222
+ */
223
+ declare class ConstitutionError extends SddError {
224
+ readonly principle: string;
225
+ constructor(principle: string);
226
+ }
227
+ /**
228
+ * 사용자 취소 에러
229
+ */
230
+ declare class UserCancelledError extends SddError {
231
+ constructor(message?: string);
232
+ }
233
+ /**
234
+ * 변경 워크플로우 에러
235
+ */
236
+ declare class ChangeError extends SddError {
237
+ constructor(message: string);
238
+ }
239
+
240
+ export { type AnalysisResult, ChangeError, type Constitution, ConstitutionError, type Delta, type DeltaType, ErrorCode, ErrorMessages, ExitCode, FileSystemError, type Location, type Principle, type PrincipleLevel, type Proposal, type ProposalStatus, type Requirement, type RequirementLevel, type Result, type Scale, type Scenario, SddError, type Spec, type SpecMetadata, type SpecStatus, type SpecValidationError, type SpecValidationWarning, UserCancelledError, ValidationError, type ValidationResult, type WorkflowRecommendation, failure, formatMessage, success };
package/dist/index.js ADDED
@@ -0,0 +1,160 @@
1
+ // src/types/index.ts
2
+ function success(data) {
3
+ return { success: true, data };
4
+ }
5
+ function failure(error) {
6
+ return { success: false, error };
7
+ }
8
+
9
+ // src/errors/codes.ts
10
+ var ExitCode = {
11
+ SUCCESS: 0,
12
+ GENERAL_ERROR: 1,
13
+ VALIDATION_FAILED: 2,
14
+ CONSTITUTION_VIOLATION: 3,
15
+ FILE_SYSTEM_ERROR: 4,
16
+ USER_CANCELLED: 5
17
+ };
18
+ var ErrorCode = {
19
+ // 일반 에러 (E0xx)
20
+ UNKNOWN: "E001",
21
+ INVALID_ARGUMENT: "E002",
22
+ NOT_INITIALIZED: "E003",
23
+ // 파일 시스템 에러 (E1xx)
24
+ FILE_NOT_FOUND: "E101",
25
+ FILE_READ_ERROR: "E102",
26
+ FILE_WRITE_ERROR: "E103",
27
+ DIRECTORY_NOT_FOUND: "E104",
28
+ DIRECTORY_EXISTS: "E105",
29
+ // 스펙 검증 에러 (E2xx)
30
+ SPEC_PARSE_ERROR: "E201",
31
+ SPEC_INVALID_FORMAT: "E202",
32
+ SPEC_MISSING_REQUIRED: "E203",
33
+ RFC2119_VIOLATION: "E204",
34
+ GWT_INVALID_FORMAT: "E205",
35
+ // Constitution 에러 (E3xx)
36
+ CONSTITUTION_NOT_FOUND: "E301",
37
+ CONSTITUTION_PARSE_ERROR: "E302",
38
+ CONSTITUTION_VIOLATION: "E303",
39
+ // 변경 워크플로우 에러 (E4xx)
40
+ PROPOSAL_NOT_FOUND: "E401",
41
+ PROPOSAL_INVALID: "E402",
42
+ DELTA_CONFLICT: "E403",
43
+ ARCHIVE_FAILED: "E404",
44
+ // 분석 에러 (E5xx)
45
+ ANALYSIS_FAILED: "E501",
46
+ INSUFFICIENT_DATA: "E502"
47
+ };
48
+
49
+ // src/errors/messages.ts
50
+ var ErrorMessages = {
51
+ // 일반 에러
52
+ [ErrorCode.UNKNOWN]: "\uC54C \uC218 \uC5C6\uB294 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4",
53
+ [ErrorCode.INVALID_ARGUMENT]: "\uC798\uBABB\uB41C \uC778\uC790\uC785\uB2C8\uB2E4: {0}",
54
+ [ErrorCode.NOT_INITIALIZED]: "SDD \uD504\uB85C\uC81D\uD2B8\uAC00 \uCD08\uAE30\uD654\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. `sdd init`\uC744 \uBA3C\uC800 \uC2E4\uD589\uD558\uC138\uC694",
55
+ // 파일 시스템 에러
56
+ [ErrorCode.FILE_NOT_FOUND]: "\uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: {0}",
57
+ [ErrorCode.FILE_READ_ERROR]: "\uD30C\uC77C \uC77D\uAE30 \uC2E4\uD328: {0}",
58
+ [ErrorCode.FILE_WRITE_ERROR]: "\uD30C\uC77C \uC4F0\uAE30 \uC2E4\uD328: {0}",
59
+ [ErrorCode.DIRECTORY_NOT_FOUND]: "\uB514\uB809\uD1A0\uB9AC\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: {0}",
60
+ [ErrorCode.DIRECTORY_EXISTS]: "\uB514\uB809\uD1A0\uB9AC\uAC00 \uC774\uBBF8 \uC874\uC7AC\uD569\uB2C8\uB2E4: {0}",
61
+ // 스펙 검증 에러
62
+ [ErrorCode.SPEC_PARSE_ERROR]: "\uC2A4\uD399 \uD30C\uC2F1 \uC2E4\uD328: {0}",
63
+ [ErrorCode.SPEC_INVALID_FORMAT]: "\uC798\uBABB\uB41C \uC2A4\uD399 \uD615\uC2DD: {0}",
64
+ [ErrorCode.SPEC_MISSING_REQUIRED]: "\uD544\uC218 \uD544\uB4DC \uB204\uB77D: {0}",
65
+ [ErrorCode.RFC2119_VIOLATION]: "RFC 2119 \uD615\uC2DD \uC704\uBC18: {0}",
66
+ [ErrorCode.GWT_INVALID_FORMAT]: "GIVEN-WHEN-THEN \uD615\uC2DD \uC704\uBC18: {0}",
67
+ // Constitution 에러
68
+ [ErrorCode.CONSTITUTION_NOT_FOUND]: "constitution.md\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4",
69
+ [ErrorCode.CONSTITUTION_PARSE_ERROR]: "Constitution \uD30C\uC2F1 \uC2E4\uD328: {0}",
70
+ [ErrorCode.CONSTITUTION_VIOLATION]: "Constitution \uC6D0\uCE59 \uC704\uBC18: {0}",
71
+ // 변경 워크플로우 에러
72
+ [ErrorCode.PROPOSAL_NOT_FOUND]: "\uC81C\uC548\uC11C\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: {0}",
73
+ [ErrorCode.PROPOSAL_INVALID]: "\uC798\uBABB\uB41C \uC81C\uC548\uC11C \uD615\uC2DD: {0}",
74
+ [ErrorCode.DELTA_CONFLICT]: "\uB378\uD0C0 \uCDA9\uB3CC: {0}",
75
+ [ErrorCode.ARCHIVE_FAILED]: "\uC544\uCE74\uC774\uBE0C \uC2E4\uD328: {0}",
76
+ // 분석 에러
77
+ [ErrorCode.ANALYSIS_FAILED]: "\uBD84\uC11D \uC2E4\uD328: {0}",
78
+ [ErrorCode.INSUFFICIENT_DATA]: "\uBD84\uC11D\uC5D0 \uD544\uC694\uD55C \uB370\uC774\uD130 \uBD80\uC871: {0}"
79
+ };
80
+ function formatMessage(code, ...args) {
81
+ let message = ErrorMessages[code];
82
+ args.forEach((arg, index) => {
83
+ message = message.replace(`{${index}}`, arg);
84
+ });
85
+ return message;
86
+ }
87
+
88
+ // src/errors/base.ts
89
+ var SddError = class extends Error {
90
+ code;
91
+ exitCode;
92
+ constructor(code, message, exitCode = ExitCode.GENERAL_ERROR) {
93
+ super(message ?? formatMessage(code));
94
+ this.name = "SddError";
95
+ this.code = code;
96
+ this.exitCode = exitCode;
97
+ Error.captureStackTrace?.(this, this.constructor);
98
+ }
99
+ /**
100
+ * 사용자 친화적 메시지
101
+ */
102
+ toUserMessage() {
103
+ return `[${this.code}] ${this.message}`;
104
+ }
105
+ };
106
+ var FileSystemError = class extends SddError {
107
+ path;
108
+ constructor(code, path) {
109
+ super(code, formatMessage(code, path), ExitCode.FILE_SYSTEM_ERROR);
110
+ this.name = "FileSystemError";
111
+ this.path = path;
112
+ }
113
+ };
114
+ var ValidationError = class extends SddError {
115
+ details;
116
+ constructor(code, details) {
117
+ super(code, formatMessage(code, details), ExitCode.VALIDATION_FAILED);
118
+ this.name = "ValidationError";
119
+ this.details = details;
120
+ }
121
+ };
122
+ var ConstitutionError = class extends SddError {
123
+ principle;
124
+ constructor(principle) {
125
+ super(
126
+ ErrorCode.CONSTITUTION_VIOLATION,
127
+ formatMessage(ErrorCode.CONSTITUTION_VIOLATION, principle),
128
+ ExitCode.CONSTITUTION_VIOLATION
129
+ );
130
+ this.name = "ConstitutionError";
131
+ this.principle = principle;
132
+ }
133
+ };
134
+ var UserCancelledError = class extends SddError {
135
+ constructor(message = "\uC0AC\uC6A9\uC790\uAC00 \uC791\uC5C5\uC744 \uCDE8\uC18C\uD588\uC2B5\uB2C8\uB2E4") {
136
+ super(ErrorCode.UNKNOWN, message, ExitCode.USER_CANCELLED);
137
+ this.name = "UserCancelledError";
138
+ }
139
+ };
140
+ var ChangeError = class extends SddError {
141
+ constructor(message) {
142
+ super(ErrorCode.UNKNOWN, message, ExitCode.GENERAL_ERROR);
143
+ this.name = "ChangeError";
144
+ }
145
+ };
146
+ export {
147
+ ChangeError,
148
+ ConstitutionError,
149
+ ErrorCode,
150
+ ErrorMessages,
151
+ ExitCode,
152
+ FileSystemError,
153
+ SddError,
154
+ UserCancelledError,
155
+ ValidationError,
156
+ failure,
157
+ formatMessage,
158
+ success
159
+ };
160
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/types/index.ts","../src/errors/codes.ts","../src/errors/messages.ts","../src/errors/base.ts"],"sourcesContent":["/**\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\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"],"mappings":";AAuKO,SAAS,QAAW,MAA2B;AACpD,SAAO,EAAE,SAAS,MAAM,KAAK;AAC/B;AAKO,SAAS,QAAW,OAA4B;AACrD,SAAO,EAAE,SAAS,OAAO,MAAM;AACjC;;;ACzKO,IAAM,WAAW;AAAA,EACtB,SAAS;AAAA,EACT,eAAe;AAAA,EACf,mBAAmB;AAAA,EACnB,wBAAwB;AAAA,EACxB,mBAAmB;AAAA,EACnB,gBAAgB;AAClB;AAOO,IAAM,YAAY;AAAA;AAAA,EAEvB,SAAS;AAAA,EACT,kBAAkB;AAAA,EAClB,iBAAiB;AAAA;AAAA,EAGjB,gBAAgB;AAAA,EAChB,iBAAiB;AAAA,EACjB,kBAAkB;AAAA,EAClB,qBAAqB;AAAA,EACrB,kBAAkB;AAAA;AAAA,EAGlB,kBAAkB;AAAA,EAClB,qBAAqB;AAAA,EACrB,uBAAuB;AAAA,EACvB,mBAAmB;AAAA,EACnB,oBAAoB;AAAA;AAAA,EAGpB,wBAAwB;AAAA,EACxB,0BAA0B;AAAA,EAC1B,wBAAwB;AAAA;AAAA,EAGxB,oBAAoB;AAAA,EACpB,kBAAkB;AAAA,EAClB,gBAAgB;AAAA,EAChB,gBAAgB;AAAA;AAAA,EAGhB,iBAAiB;AAAA,EACjB,mBAAmB;AACrB;;;AC/CO,IAAM,gBAA2C;AAAA;AAAA,EAEtD,CAAC,UAAU,OAAO,GAAG;AAAA,EACrB,CAAC,UAAU,gBAAgB,GAAG;AAAA,EAC9B,CAAC,UAAU,eAAe,GAAG;AAAA;AAAA,EAG7B,CAAC,UAAU,cAAc,GAAG;AAAA,EAC5B,CAAC,UAAU,eAAe,GAAG;AAAA,EAC7B,CAAC,UAAU,gBAAgB,GAAG;AAAA,EAC9B,CAAC,UAAU,mBAAmB,GAAG;AAAA,EACjC,CAAC,UAAU,gBAAgB,GAAG;AAAA;AAAA,EAG9B,CAAC,UAAU,gBAAgB,GAAG;AAAA,EAC9B,CAAC,UAAU,mBAAmB,GAAG;AAAA,EACjC,CAAC,UAAU,qBAAqB,GAAG;AAAA,EACnC,CAAC,UAAU,iBAAiB,GAAG;AAAA,EAC/B,CAAC,UAAU,kBAAkB,GAAG;AAAA;AAAA,EAGhC,CAAC,UAAU,sBAAsB,GAAG;AAAA,EACpC,CAAC,UAAU,wBAAwB,GAAG;AAAA,EACtC,CAAC,UAAU,sBAAsB,GAAG;AAAA;AAAA,EAGpC,CAAC,UAAU,kBAAkB,GAAG;AAAA,EAChC,CAAC,UAAU,gBAAgB,GAAG;AAAA,EAC9B,CAAC,UAAU,cAAc,GAAG;AAAA,EAC5B,CAAC,UAAU,cAAc,GAAG;AAAA;AAAA,EAG5B,CAAC,UAAU,eAAe,GAAG;AAAA,EAC7B,CAAC,UAAU,iBAAiB,GAAG;AACjC;AAKO,SAAS,cAAc,SAAoB,MAAwB;AACxE,MAAI,UAAU,cAAc,IAAI;AAChC,OAAK,QAAQ,CAAC,KAAK,UAAU;AAC3B,cAAU,QAAQ,QAAQ,IAAI,KAAK,KAAK,GAAG;AAAA,EAC7C,CAAC;AACD,SAAO;AACT;;;AC5CO,IAAM,WAAN,cAAuB,MAAM;AAAA,EACzB;AAAA,EACA;AAAA,EAET,YACE,MACA,SACA,WAAqB,SAAS,eAC9B;AACA,UAAM,WAAW,cAAc,IAAI,CAAC;AACpC,SAAK,OAAO;AACZ,SAAK,OAAO;AACZ,SAAK,WAAW;AAChB,UAAM,oBAAoB,MAAM,KAAK,WAAW;AAAA,EAClD;AAAA;AAAA;AAAA;AAAA,EAKA,gBAAwB;AACtB,WAAO,IAAI,KAAK,IAAI,KAAK,KAAK,OAAO;AAAA,EACvC;AACF;AAKO,IAAM,kBAAN,cAA8B,SAAS;AAAA,EACnC;AAAA,EAET,YAAY,MAAiB,MAAc;AACzC,UAAM,MAAM,cAAc,MAAM,IAAI,GAAG,SAAS,iBAAiB;AACjE,SAAK,OAAO;AACZ,SAAK,OAAO;AAAA,EACd;AACF;AAKO,IAAM,kBAAN,cAA8B,SAAS;AAAA,EACnC;AAAA,EAET,YAAY,MAAiB,SAAiB;AAC5C,UAAM,MAAM,cAAc,MAAM,OAAO,GAAG,SAAS,iBAAiB;AACpE,SAAK,OAAO;AACZ,SAAK,UAAU;AAAA,EACjB;AACF;AAKO,IAAM,oBAAN,cAAgC,SAAS;AAAA,EACrC;AAAA,EAET,YAAY,WAAmB;AAC7B;AAAA,MACE,UAAU;AAAA,MACV,cAAc,UAAU,wBAAwB,SAAS;AAAA,MACzD,SAAS;AAAA,IACX;AACA,SAAK,OAAO;AACZ,SAAK,YAAY;AAAA,EACnB;AACF;AAKO,IAAM,qBAAN,cAAiC,SAAS;AAAA,EAC/C,YAAY,UAAU,oFAAmB;AACvC,UAAM,UAAU,SAAS,SAAS,SAAS,cAAc;AACzD,SAAK,OAAO;AAAA,EACd;AACF;AAKO,IAAM,cAAN,cAA0B,SAAS;AAAA,EACxC,YAAY,SAAiB;AAC3B,UAAM,UAAU,SAAS,SAAS,SAAS,aAAa;AACxD,SAAK,OAAO;AAAA,EACd;AACF;","names":[]}
package/package.json ADDED
@@ -0,0 +1,75 @@
1
+ {
2
+ "name": "sdd-tool",
3
+ "version": "0.1.0",
4
+ "description": "Unified Spec-Driven Development CLI - AI-first specification workflow",
5
+ "type": "module",
6
+ "bin": {
7
+ "sdd": "bin/sdd.js"
8
+ },
9
+ "main": "./dist/index.js",
10
+ "types": "./dist/index.d.ts",
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/index.js"
15
+ }
16
+ },
17
+ "scripts": {
18
+ "build": "tsup",
19
+ "dev": "tsup --watch",
20
+ "test": "vitest",
21
+ "test:run": "vitest run",
22
+ "test:coverage": "vitest run --coverage",
23
+ "lint": "eslint src/",
24
+ "typecheck": "tsc --noEmit",
25
+ "prepublishOnly": "npm run build && npm run test:run"
26
+ },
27
+ "repository": {
28
+ "type": "git",
29
+ "url": "git+https://github.com/JakeB-5/sdd-tool.git"
30
+ },
31
+ "homepage": "https://github.com/JakeB-5/sdd-tool#readme",
32
+ "bugs": {
33
+ "url": "https://github.com/JakeB-5/sdd-tool/issues"
34
+ },
35
+ "author": "JakeB-5",
36
+ "dependencies": {
37
+ "commander": "^12.1.0",
38
+ "zod": "^3.23.8",
39
+ "chalk": "^5.3.0",
40
+ "gray-matter": "^4.0.3"
41
+ },
42
+ "devDependencies": {
43
+ "@types/node": "^20.17.10",
44
+ "typescript": "^5.7.2",
45
+ "vitest": "^2.1.8",
46
+ "tsup": "^8.3.5",
47
+ "@vitest/coverage-v8": "^2.1.8",
48
+ "eslint": "^9.16.0",
49
+ "@typescript-eslint/eslint-plugin": "^8.18.0",
50
+ "@typescript-eslint/parser": "^8.18.0"
51
+ },
52
+ "engines": {
53
+ "node": ">=20.0.0"
54
+ },
55
+ "packageManager": "pnpm@9.15.1",
56
+ "files": [
57
+ "dist",
58
+ "bin",
59
+ "templates",
60
+ "README.md",
61
+ "LICENSE"
62
+ ],
63
+ "keywords": [
64
+ "sdd",
65
+ "spec-driven-development",
66
+ "specification",
67
+ "cli",
68
+ "ai",
69
+ "workflow",
70
+ "rfc2119",
71
+ "given-when-then",
72
+ "bdd"
73
+ ],
74
+ "license": "MIT"
75
+ }
@@ -0,0 +1,62 @@
1
+ # AGENTS.md
2
+
3
+ > AI 에이전트 워크플로우 지침서
4
+
5
+ ---
6
+
7
+ ## 프로젝트 개요
8
+
9
+ **프로젝트**: {{PROJECT_NAME}}
10
+ **설명**: {{PROJECT_DESCRIPTION}}
11
+
12
+ ---
13
+
14
+ ## 디렉토리 구조
15
+
16
+ ```
17
+ .sdd/
18
+ ├── constitution.md # 프로젝트 헌법
19
+ ├── specs/ # 스펙 문서
20
+ │ └── <feature>/
21
+ │ └── spec.md
22
+ ├── changes/ # 변경 제안
23
+ │ └── <id>/
24
+ │ ├── proposal.md
25
+ │ └── delta.md
26
+ └── templates/ # 템플릿
27
+ ```
28
+
29
+ ---
30
+
31
+ ## 워크플로우
32
+
33
+ ### 신규 기능
34
+
35
+ 1. `/sdd:new` - 스펙 초안 작성
36
+ 2. `/sdd:plan` - 구현 계획 수립
37
+ 3. `/sdd:tasks` - 작업 분해
38
+ 4. 구현 및 테스트
39
+ 5. 리뷰 및 머지
40
+
41
+ ### 변경 제안
42
+
43
+ 1. `/sdd:change` - 제안서 작성
44
+ 2. `/sdd:impact` - 영향도 분석
45
+ 3. 리뷰 및 승인
46
+ 4. `/sdd:apply` - 변경 적용
47
+ 5. `/sdd:archive` - 아카이브
48
+
49
+ ---
50
+
51
+ ## 컨벤션
52
+
53
+ - 모든 스펙은 RFC 2119 키워드 사용
54
+ - 모든 요구사항은 GIVEN-WHEN-THEN 시나리오 포함
55
+ - 변경 시 반드시 영향도 분석 수행
56
+
57
+ ---
58
+
59
+ ## 참조
60
+
61
+ - [Constitution](./constitution.md)
62
+ - [Specs](./specs/)
@@ -0,0 +1,43 @@
1
+ # Constitution: {{PROJECT_NAME}}
2
+
3
+ > 프로젝트의 근본 원칙과 제약 조건
4
+
5
+ ---
6
+
7
+ ## 핵심 원칙
8
+
9
+ ### 1. 명세 우선 (Spec First)
10
+
11
+ 코드보다 명세가 먼저다. 모든 구현은 승인된 명세에 기반한다.
12
+
13
+ ### 2. 명확성 (Clarity)
14
+
15
+ 모호함을 피하고 RFC 2119 키워드를 사용하여 요구사항을 명확히 한다.
16
+
17
+ ### 3. 검증 가능성 (Verifiability)
18
+
19
+ 모든 요구사항은 GIVEN-WHEN-THEN 시나리오로 검증 가능해야 한다.
20
+
21
+ ---
22
+
23
+ ## 기술 스택
24
+
25
+ - 언어: {{LANGUAGE}}
26
+ - 런타임: {{RUNTIME}}
27
+ - 테스트: {{TEST_FRAMEWORK}}
28
+
29
+ ---
30
+
31
+ ## 금지 사항
32
+
33
+ - 승인되지 않은 의존성 추가 금지
34
+ - 명세 없는 기능 구현 금지
35
+ - 테스트 없는 코드 머지 금지
36
+
37
+ ---
38
+
39
+ ## 변경 기록
40
+
41
+ | 날짜 | 변경 내용 | 작성자 |
42
+ |------|----------|--------|
43
+ | {{DATE}} | 초기 작성 | - |
@@ -0,0 +1,71 @@
1
+ ---
2
+ id: CHG-{{ID}}
3
+ status: draft
4
+ created: {{DATE}}
5
+ ---
6
+
7
+ # 변경 제안: {{TITLE}}
8
+
9
+ > 변경 목적 및 배경 설명
10
+
11
+ ---
12
+
13
+ ## 배경
14
+
15
+ 왜 이 변경이 필요한가?
16
+
17
+ ---
18
+
19
+ ## 영향 범위
20
+
21
+ ### 영향받는 스펙
22
+
23
+ - `specs/{{SPEC_PATH}}`
24
+
25
+ ### 변경 유형
26
+
27
+ - [ ] 신규 추가 (ADDED)
28
+ - [ ] 수정 (MODIFIED)
29
+ - [ ] 삭제 (REMOVED)
30
+
31
+ ---
32
+
33
+ ## 변경 내용
34
+
35
+ ### ADDED
36
+
37
+ (새로 추가되는 내용)
38
+
39
+ ### MODIFIED
40
+
41
+ (수정되는 내용)
42
+
43
+ #### Before
44
+
45
+ ```markdown
46
+ 기존 내용
47
+ ```
48
+
49
+ #### After
50
+
51
+ ```markdown
52
+ 변경된 내용
53
+ ```
54
+
55
+ ### REMOVED
56
+
57
+ (삭제되는 내용)
58
+
59
+ ---
60
+
61
+ ## 리스크 평가
62
+
63
+ - 영향도: 낮음/중간/높음
64
+ - 복잡도: 낮음/중간/높음
65
+
66
+ ---
67
+
68
+ ## 검토자
69
+
70
+ - [ ] @reviewer1
71
+ - [ ] @reviewer2