memento-mcp-server 1.16.1 → 1.16.2

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.
Files changed (163) hide show
  1. package/dist/client/index.d.ts.map +1 -1
  2. package/dist/client/index.js +4 -3
  3. package/dist/client/index.js.map +1 -1
  4. package/dist/domains/anchor/services/anchor/anchor-interfaces.d.ts +2 -4
  5. package/dist/domains/anchor/services/anchor/anchor-interfaces.d.ts.map +1 -1
  6. package/dist/domains/anchor/services/anchor/anchor-interfaces.js.map +1 -1
  7. package/dist/domains/anchor/services/anchor/anchor-manager.d.ts +2 -2
  8. package/dist/domains/anchor/services/anchor/anchor-manager.d.ts.map +1 -1
  9. package/dist/domains/anchor/services/anchor/anchor-manager.js.map +1 -1
  10. package/dist/domains/anchor/services/anchor/anchor-search-service.d.ts +11 -34
  11. package/dist/domains/anchor/services/anchor/anchor-search-service.d.ts.map +1 -1
  12. package/dist/domains/anchor/services/anchor/anchor-search-service.js +66 -549
  13. package/dist/domains/anchor/services/anchor/anchor-search-service.js.map +1 -1
  14. package/dist/domains/anchor/services/anchor/database-types.d.ts +28 -0
  15. package/dist/domains/anchor/services/anchor/database-types.d.ts.map +1 -0
  16. package/dist/domains/anchor/services/anchor/database-types.js +6 -0
  17. package/dist/domains/anchor/services/anchor/database-types.js.map +1 -0
  18. package/dist/domains/anchor/services/anchor/embedding-types.d.ts +20 -0
  19. package/dist/domains/anchor/services/anchor/embedding-types.d.ts.map +1 -0
  20. package/dist/domains/anchor/services/anchor/embedding-types.js +6 -0
  21. package/dist/domains/anchor/services/anchor/embedding-types.js.map +1 -0
  22. package/dist/domains/anchor/services/anchor/fallback-search-service.d.ts +36 -0
  23. package/dist/domains/anchor/services/anchor/fallback-search-service.d.ts.map +1 -0
  24. package/dist/domains/anchor/services/anchor/fallback-search-service.js +85 -0
  25. package/dist/domains/anchor/services/anchor/fallback-search-service.js.map +1 -0
  26. package/dist/domains/anchor/services/anchor/fallback-strategy.d.ts +25 -0
  27. package/dist/domains/anchor/services/anchor/fallback-strategy.d.ts.map +1 -0
  28. package/dist/domains/anchor/services/anchor/fallback-strategy.js +35 -0
  29. package/dist/domains/anchor/services/anchor/fallback-strategy.js.map +1 -0
  30. package/dist/domains/anchor/services/anchor/local-search-service.d.ts +72 -0
  31. package/dist/domains/anchor/services/anchor/local-search-service.d.ts.map +1 -0
  32. package/dist/domains/anchor/services/anchor/local-search-service.js +129 -0
  33. package/dist/domains/anchor/services/anchor/local-search-service.js.map +1 -0
  34. package/dist/domains/anchor/services/anchor/n-hop-search-service.d.ts +90 -0
  35. package/dist/domains/anchor/services/anchor/n-hop-search-service.d.ts.map +1 -0
  36. package/dist/domains/anchor/services/anchor/n-hop-search-service.js +385 -0
  37. package/dist/domains/anchor/services/anchor/n-hop-search-service.js.map +1 -0
  38. package/dist/domains/anchor/services/anchor/n-hop-search-strategy.d.ts +24 -0
  39. package/dist/domains/anchor/services/anchor/n-hop-search-strategy.d.ts.map +1 -0
  40. package/dist/domains/anchor/services/anchor/n-hop-search-strategy.js +39 -0
  41. package/dist/domains/anchor/services/anchor/n-hop-search-strategy.js.map +1 -0
  42. package/dist/domains/anchor/services/anchor/query-filter-service.d.ts +52 -0
  43. package/dist/domains/anchor/services/anchor/query-filter-service.d.ts.map +1 -0
  44. package/dist/domains/anchor/services/anchor/query-filter-service.js +136 -0
  45. package/dist/domains/anchor/services/anchor/query-filter-service.js.map +1 -0
  46. package/dist/domains/anchor/services/anchor/query-filter-strategy.d.ts +24 -0
  47. package/dist/domains/anchor/services/anchor/query-filter-strategy.d.ts.map +1 -0
  48. package/dist/domains/anchor/services/anchor/query-filter-strategy.js +34 -0
  49. package/dist/domains/anchor/services/anchor/query-filter-strategy.js.map +1 -0
  50. package/dist/domains/anchor/services/anchor/search-strategy-interfaces.d.ts +52 -0
  51. package/dist/domains/anchor/services/anchor/search-strategy-interfaces.d.ts.map +1 -0
  52. package/dist/domains/anchor/services/anchor/search-strategy-interfaces.js +6 -0
  53. package/dist/domains/anchor/services/anchor/search-strategy-interfaces.js.map +1 -0
  54. package/dist/domains/anchor/services/anchor/vector-search-engine-types.d.ts +18 -0
  55. package/dist/domains/anchor/services/anchor/vector-search-engine-types.d.ts.map +1 -0
  56. package/dist/domains/anchor/services/anchor/vector-search-engine-types.js +11 -0
  57. package/dist/domains/anchor/services/anchor/vector-search-engine-types.js.map +1 -0
  58. package/dist/domains/memory/repositories/core-memory-database.interface.d.ts +47 -0
  59. package/dist/domains/memory/repositories/core-memory-database.interface.d.ts.map +1 -0
  60. package/dist/domains/memory/repositories/core-memory-database.interface.js +7 -0
  61. package/dist/domains/memory/repositories/core-memory-database.interface.js.map +1 -0
  62. package/dist/domains/memory/repositories/core-memory-repository.d.ts +7 -77
  63. package/dist/domains/memory/repositories/core-memory-repository.d.ts.map +1 -1
  64. package/dist/domains/memory/repositories/core-memory-repository.interface.d.ts +92 -0
  65. package/dist/domains/memory/repositories/core-memory-repository.interface.d.ts.map +1 -0
  66. package/dist/domains/memory/repositories/core-memory-repository.interface.js +6 -0
  67. package/dist/domains/memory/repositories/core-memory-repository.interface.js.map +1 -0
  68. package/dist/domains/memory/repositories/core-memory-repository.js +7 -259
  69. package/dist/domains/memory/repositories/core-memory-repository.js.map +1 -1
  70. package/dist/domains/memory/services/core-memory-cache-service.d.ts +55 -0
  71. package/dist/domains/memory/services/core-memory-cache-service.d.ts.map +1 -1
  72. package/dist/domains/memory/services/core-memory-cache-service.js +110 -8
  73. package/dist/domains/memory/services/core-memory-cache-service.js.map +1 -1
  74. package/dist/domains/memory/services/core-memory-service.d.ts +2 -2
  75. package/dist/domains/memory/services/core-memory-service.d.ts.map +1 -1
  76. package/dist/domains/memory/services/core-memory-service.js +43 -24
  77. package/dist/domains/memory/services/core-memory-service.js.map +1 -1
  78. package/dist/domains/memory/tools/recall-tool.d.ts.map +1 -1
  79. package/dist/domains/memory/tools/recall-tool.js +2 -2
  80. package/dist/domains/memory/tools/recall-tool.js.map +1 -1
  81. package/dist/domains/memory/tools/remember-tool.d.ts.map +1 -1
  82. package/dist/domains/memory/tools/remember-tool.js +2 -2
  83. package/dist/domains/memory/tools/remember-tool.js.map +1 -1
  84. package/dist/domains/monitoring/services/performance-monitor.d.ts +8 -0
  85. package/dist/domains/monitoring/services/performance-monitor.d.ts.map +1 -1
  86. package/dist/domains/monitoring/services/performance-monitor.js +16 -0
  87. package/dist/domains/monitoring/services/performance-monitor.js.map +1 -1
  88. package/dist/infrastructure/async-optimizer.d.ts.map +1 -1
  89. package/dist/infrastructure/async-optimizer.js +8 -7
  90. package/dist/infrastructure/async-optimizer.js.map +1 -1
  91. package/dist/infrastructure/database/adapters/sqlite-core-memory-adapter.d.ts +31 -0
  92. package/dist/infrastructure/database/adapters/sqlite-core-memory-adapter.d.ts.map +1 -0
  93. package/dist/infrastructure/database/adapters/sqlite-core-memory-adapter.js +112 -0
  94. package/dist/infrastructure/database/adapters/sqlite-core-memory-adapter.js.map +1 -0
  95. package/dist/infrastructure/database/database/init.d.ts.map +1 -1
  96. package/dist/infrastructure/database/database/init.js +23 -2
  97. package/dist/infrastructure/database/database/init.js.map +1 -1
  98. package/dist/infrastructure/database/database/migration/migrations/010-add-core-memory-version.d.ts +64 -0
  99. package/dist/infrastructure/database/database/migration/migrations/010-add-core-memory-version.d.ts.map +1 -0
  100. package/dist/infrastructure/database/database/migration/migrations/010-add-core-memory-version.js +174 -0
  101. package/dist/infrastructure/database/database/migration/migrations/010-add-core-memory-version.js.map +1 -0
  102. package/dist/infrastructure/database/database/migration/migrations/010-add-core-memory-version.sql +25 -0
  103. package/dist/infrastructure/database/database-lock-monitor.d.ts +105 -0
  104. package/dist/infrastructure/database/database-lock-monitor.d.ts.map +1 -0
  105. package/dist/infrastructure/database/database-lock-monitor.js +265 -0
  106. package/dist/infrastructure/database/database-lock-monitor.js.map +1 -0
  107. package/dist/infrastructure/database/factories/core-memory-repository.factory.d.ts +17 -0
  108. package/dist/infrastructure/database/factories/core-memory-repository.factory.d.ts.map +1 -0
  109. package/dist/infrastructure/database/factories/core-memory-repository.factory.js +43 -0
  110. package/dist/infrastructure/database/factories/core-memory-repository.factory.js.map +1 -0
  111. package/dist/infrastructure/database/repositories/core-memory-repository-sqlite.impl.d.ts +63 -0
  112. package/dist/infrastructure/database/repositories/core-memory-repository-sqlite.impl.d.ts.map +1 -0
  113. package/dist/infrastructure/database/repositories/core-memory-repository-sqlite.impl.js +281 -0
  114. package/dist/infrastructure/database/repositories/core-memory-repository-sqlite.impl.js.map +1 -0
  115. package/dist/infrastructure/database/wal-checkpoint-scheduler.d.ts +166 -0
  116. package/dist/infrastructure/database/wal-checkpoint-scheduler.d.ts.map +1 -0
  117. package/dist/infrastructure/database/wal-checkpoint-scheduler.js +285 -0
  118. package/dist/infrastructure/database/wal-checkpoint-scheduler.js.map +1 -0
  119. package/dist/npm-client/memento-client.d.ts.map +1 -1
  120. package/dist/npm-client/memento-client.js +5 -4
  121. package/dist/npm-client/memento-client.js.map +1 -1
  122. package/dist/npm-client/memory-manager.d.ts.map +1 -1
  123. package/dist/npm-client/memory-manager.js +4 -3
  124. package/dist/npm-client/memory-manager.js.map +1 -1
  125. package/dist/scripts/check-migration-status.d.ts.map +1 -1
  126. package/dist/scripts/check-migration-status.js +1 -0
  127. package/dist/scripts/check-migration-status.js.map +1 -1
  128. package/dist/server/bootstrap.d.ts +4 -0
  129. package/dist/server/bootstrap.d.ts.map +1 -1
  130. package/dist/server/bootstrap.js +27 -2
  131. package/dist/server/bootstrap.js.map +1 -1
  132. package/dist/server/http-server.d.ts.map +1 -1
  133. package/dist/server/http-server.js +59 -31
  134. package/dist/server/http-server.js.map +1 -1
  135. package/dist/server/index.js +32 -16
  136. package/dist/server/index.js.map +1 -1
  137. package/dist/server/simple-mcp-server.d.ts.map +1 -1
  138. package/dist/server/simple-mcp-server.js +15 -14
  139. package/dist/server/simple-mcp-server.js.map +1 -1
  140. package/dist/shared/config/environment.d.ts.map +1 -1
  141. package/dist/shared/config/environment.js +13 -1
  142. package/dist/shared/config/environment.js.map +1 -1
  143. package/dist/shared/config/index.d.ts.map +1 -1
  144. package/dist/shared/config/index.js +13 -1
  145. package/dist/shared/config/index.js.map +1 -1
  146. package/dist/shared/types/index.d.ts +10 -0
  147. package/dist/shared/types/index.d.ts.map +1 -1
  148. package/dist/tools/base-tool.d.ts.map +1 -1
  149. package/dist/tools/base-tool.js +5 -4
  150. package/dist/tools/base-tool.js.map +1 -1
  151. package/dist/tools/migrate-embeddings-tool.d.ts.map +1 -1
  152. package/dist/tools/migrate-embeddings-tool.js +2 -1
  153. package/dist/tools/migrate-embeddings-tool.js.map +1 -1
  154. package/dist/tools/tool-registry.d.ts.map +1 -1
  155. package/dist/tools/tool-registry.js +4 -3
  156. package/dist/tools/tool-registry.js.map +1 -1
  157. package/dist/workers/consolidation-score-worker.d.ts.map +1 -1
  158. package/dist/workers/consolidation-score-worker.js +5 -4
  159. package/dist/workers/consolidation-score-worker.js.map +1 -1
  160. package/package.json +1 -1
  161. package/scripts/check-file-sizes.ts +405 -0
  162. package/scripts/count-any-types.ts +375 -0
  163. package/scripts/count-console-logs.ts +451 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memento-mcp-server",
3
- "version": "1.16.1",
3
+ "version": "1.16.2",
4
4
  "description": "AI Agent 기억 보조 MCP 서버 - 사람의 기억 구조를 모사한 스토리지+검색+요약+망각 메커니즘",
5
5
  "main": "dist/server/index.js",
6
6
  "type": "module",
@@ -0,0 +1,405 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * 파일 크기 검증 스크립트
4
+ *
5
+ * PRD 0017: 코드 품질 개선 - 파일 크기 검증
6
+ *
7
+ * 사용법:
8
+ * tsx scripts/check-file-sizes.ts
9
+ * tsx scripts/check-file-sizes.ts --ci
10
+ * tsx scripts/check-file-sizes.ts --threshold 500
11
+ * tsx scripts/check-file-sizes.ts --directory src/
12
+ * tsx scripts/check-file-sizes.ts --exclude "**/*.spec.ts"
13
+ *
14
+ * 목표:
15
+ * - 핵심 핸들러/서비스 파일이 500줄 이하
16
+ * - CI/CD 통합 가능
17
+ * - 경고/에러 출력
18
+ */
19
+
20
+ import { readFileSync, statSync } from 'fs';
21
+ import { readdir } from 'fs/promises';
22
+ import { join, relative } from 'path';
23
+
24
+ /**
25
+ * CLI 옵션
26
+ */
27
+ interface CliOptions {
28
+ ci?: boolean;
29
+ threshold?: number;
30
+ directory?: string;
31
+ exclude?: string[];
32
+ allowSoftFail?: boolean;
33
+ }
34
+
35
+ /**
36
+ * 파일 크기 검증 결과
37
+ */
38
+ interface FileSizeResult {
39
+ file: string;
40
+ lines: number;
41
+ status: 'ok' | 'warning' | 'error';
42
+ }
43
+
44
+ /**
45
+ * 검증 통계
46
+ */
47
+ interface ValidationStats {
48
+ total: number;
49
+ ok: number;
50
+ warning: number;
51
+ error: number;
52
+ maxLines: number;
53
+ maxFile: string;
54
+ }
55
+
56
+ /**
57
+ * 명령줄 인자 파싱
58
+ */
59
+ function parseArgs(): CliOptions {
60
+ const args = process.argv.slice(2);
61
+ const options: CliOptions = {
62
+ exclude: ['**/node_modules/**', '**/dist/**', '**/*.d.ts']
63
+ };
64
+
65
+ for (let i = 0; i < args.length; i++) {
66
+ const arg = args[i];
67
+ if (arg === '--ci') {
68
+ options.ci = true;
69
+ } else if (arg === '--threshold' && args[i + 1]) {
70
+ options.threshold = parseInt(args[i + 1], 10);
71
+ i++;
72
+ } else if (arg === '--directory' && args[i + 1]) {
73
+ options.directory = args[i + 1];
74
+ i++;
75
+ } else if (arg === '--exclude' && args[i + 1]) {
76
+ if (!options.exclude) {
77
+ options.exclude = [];
78
+ }
79
+ options.exclude.push(args[i + 1]);
80
+ i++;
81
+ } else if (arg === '--allow-soft-fail') {
82
+ options.allowSoftFail = true;
83
+ } else if (arg === '--help' || arg === '-h') {
84
+ printHelp();
85
+ process.exit(0);
86
+ }
87
+ }
88
+
89
+ return options;
90
+ }
91
+
92
+ /**
93
+ * 도움말 출력
94
+ */
95
+ function printHelp(): void {
96
+ console.log(`
97
+ 파일 크기 검증 스크립트
98
+
99
+ 사용법:
100
+ tsx scripts/check-file-sizes.ts [options]
101
+
102
+ 옵션:
103
+ --ci CI 모드 (실패 시 exit code 1 반환)
104
+ --threshold <number> 임계값 (기본값: 500줄)
105
+ --directory <path> 검사할 디렉토리 (기본값: src/)
106
+ --exclude <pattern> 제외할 파일 패턴 (여러 번 사용 가능)
107
+ --allow-soft-fail CI 모드에서 경고만 출력하고 통과
108
+ --help, -h 도움말 출력
109
+
110
+ 예제:
111
+ tsx scripts/check-file-sizes.ts
112
+ tsx scripts/check-file-sizes.ts --ci
113
+ tsx scripts/check-file-sizes.ts --threshold 500
114
+ tsx scripts/check-file-sizes.ts --directory src/ --exclude "**/*.spec.ts"
115
+ `);
116
+ }
117
+
118
+ /**
119
+ * 파일의 줄 수 계산
120
+ *
121
+ * @param filePath - 파일 경로
122
+ * @returns 줄 수
123
+ */
124
+ function countLines(filePath: string): number {
125
+ try {
126
+ const content = readFileSync(filePath, 'utf-8');
127
+ // 빈 파일은 0줄
128
+ if (content.trim().length === 0) {
129
+ return 0;
130
+ }
131
+ // 줄 수 계산 (마지막 줄이 개행으로 끝나지 않아도 카운트)
132
+ const lines = content.split('\n');
133
+ return lines.length;
134
+ } catch (error) {
135
+ console.error(`❌ 파일 읽기 실패: ${filePath}`, error instanceof Error ? error.message : String(error));
136
+ return 0;
137
+ }
138
+ }
139
+
140
+ /**
141
+ * 파일 크기 검증
142
+ *
143
+ * @param filePath - 파일 경로
144
+ * @param threshold - 임계값 (줄 수)
145
+ * @returns 검증 결과
146
+ */
147
+ function validateFileSize(filePath: string, threshold: number): FileSizeResult {
148
+ const lines = countLines(filePath);
149
+
150
+ let status: 'ok' | 'warning' | 'error' = 'ok';
151
+ if (lines > threshold) {
152
+ // 500줄 초과 시 에러, 500줄 이하이지만 임계값 초과 시 경고
153
+ status = lines > 500 ? 'error' : 'warning';
154
+ }
155
+
156
+ return {
157
+ file: filePath,
158
+ lines,
159
+ status
160
+ };
161
+ }
162
+
163
+ /**
164
+ * 패턴 매칭 (간단한 glob 패턴 지원)
165
+ *
166
+ * @param path - 파일 경로
167
+ * @param pattern - 패턴 (예: "**/node_modules/**", "**/*.spec.ts")
168
+ * @returns 매칭 여부
169
+ */
170
+ function matchesPattern(path: string, pattern: string): boolean {
171
+ // **/node_modules/** -> node_modules 포함 여부
172
+ if (pattern.includes('**/node_modules/**')) {
173
+ return path.includes('node_modules');
174
+ }
175
+ // **/dist/** -> dist 포함 여부
176
+ if (pattern.includes('**/dist/**')) {
177
+ return path.includes('dist');
178
+ }
179
+ // **/*.spec.ts -> .spec.ts로 끝나는지
180
+ if (pattern.includes('**/*.spec.ts')) {
181
+ return path.endsWith('.spec.ts');
182
+ }
183
+ // **/*.d.ts -> .d.ts로 끝나는지
184
+ if (pattern.includes('**/*.d.ts')) {
185
+ return path.endsWith('.d.ts');
186
+ }
187
+ return false;
188
+ }
189
+
190
+ /**
191
+ * 파일이 제외 패턴에 해당하는지 확인
192
+ *
193
+ * @param filePath - 파일 경로
194
+ * @param exclude - 제외 패턴 배열
195
+ * @returns 제외 여부
196
+ */
197
+ function shouldExclude(filePath: string, exclude: string[]): boolean {
198
+ for (const pattern of exclude) {
199
+ if (matchesPattern(filePath, pattern)) {
200
+ return true;
201
+ }
202
+ }
203
+ return false;
204
+ }
205
+
206
+ /**
207
+ * 파일 검색 (재귀적)
208
+ *
209
+ * @param directory - 검색 디렉토리
210
+ * @param exclude - 제외 패턴
211
+ * @returns 파일 경로 배열
212
+ */
213
+ async function findFiles(directory: string, exclude: string[]): Promise<string[]> {
214
+ const files: string[] = [];
215
+ const absoluteDir = join(process.cwd(), directory);
216
+
217
+ /**
218
+ * 재귀적으로 디렉토리 탐색
219
+ */
220
+ async function walkDir(dir: string): Promise<void> {
221
+ try {
222
+ const entries = await readdir(dir, { withFileTypes: true });
223
+
224
+ for (const entry of entries) {
225
+ const fullPath = join(dir, entry.name);
226
+
227
+ // 제외 패턴 확인
228
+ if (shouldExclude(fullPath, exclude)) {
229
+ continue;
230
+ }
231
+
232
+ if (entry.isDirectory()) {
233
+ await walkDir(fullPath);
234
+ } else if (entry.isFile() && entry.name.endsWith('.ts')) {
235
+ files.push(fullPath);
236
+ }
237
+ }
238
+ } catch (error) {
239
+ // 디렉토리 읽기 실패 시 무시 (권한 문제 등)
240
+ // console.warn(`디렉토리 읽기 실패: ${dir}`, error);
241
+ }
242
+ }
243
+
244
+ await walkDir(absoluteDir);
245
+ return files;
246
+ }
247
+
248
+ /**
249
+ * 검증 통계 계산
250
+ *
251
+ * @param results - 검증 결과 배열
252
+ * @returns 통계
253
+ */
254
+ function calculateStats(results: FileSizeResult[]): ValidationStats {
255
+ const stats: ValidationStats = {
256
+ total: results.length,
257
+ ok: 0,
258
+ warning: 0,
259
+ error: 0,
260
+ maxLines: 0,
261
+ maxFile: ''
262
+ };
263
+
264
+ for (const result of results) {
265
+ if (result.status === 'ok') {
266
+ stats.ok++;
267
+ } else if (result.status === 'warning') {
268
+ stats.warning++;
269
+ } else {
270
+ stats.error++;
271
+ }
272
+
273
+ if (result.lines > stats.maxLines) {
274
+ stats.maxLines = result.lines;
275
+ stats.maxFile = result.file;
276
+ }
277
+ }
278
+
279
+ return stats;
280
+ }
281
+
282
+ /**
283
+ * 결과 출력
284
+ *
285
+ * @param results - 검증 결과 배열
286
+ * @param stats - 통계
287
+ * @param threshold - 임계값
288
+ * @param projectRoot - 프로젝트 루트 경로
289
+ */
290
+ function printResults(
291
+ results: FileSizeResult[],
292
+ stats: ValidationStats,
293
+ threshold: number,
294
+ projectRoot: string
295
+ ): void {
296
+ console.log('\n📊 파일 크기 검증 결과\n');
297
+ console.log(`임계값: ${threshold}줄`);
298
+ console.log(`검사된 파일 수: ${stats.total}개\n`);
299
+
300
+ // 에러 파일 출력
301
+ const errorFiles = results.filter(r => r.status === 'error');
302
+ if (errorFiles.length > 0) {
303
+ console.log('❌ 500줄 초과 파일 (에러):');
304
+ for (const result of errorFiles.sort((a, b) => b.lines - a.lines)) {
305
+ const relativePath = relative(projectRoot, result.file);
306
+ console.log(` ${relativePath}: ${result.lines}줄`);
307
+ }
308
+ console.log('');
309
+ }
310
+
311
+ // 경고 파일 출력
312
+ const warningFiles = results.filter(r => r.status === 'warning');
313
+ if (warningFiles.length > 0) {
314
+ console.log('⚠️ 임계값 초과 파일 (경고):');
315
+ for (const result of warningFiles.sort((a, b) => b.lines - a.lines)) {
316
+ const relativePath = relative(projectRoot, result.file);
317
+ console.log(` ${relativePath}: ${result.lines}줄`);
318
+ }
319
+ console.log('');
320
+ }
321
+
322
+ // 통계 출력
323
+ console.log('📈 통계:');
324
+ console.log(` ✅ 통과: ${stats.ok}개`);
325
+ if (stats.warning > 0) {
326
+ console.log(` ⚠️ 경고: ${stats.warning}개`);
327
+ }
328
+ if (stats.error > 0) {
329
+ console.log(` ❌ 에러: ${stats.error}개`);
330
+ }
331
+ console.log(` 📏 최대 파일: ${relative(projectRoot, stats.maxFile)} (${stats.maxLines}줄)`);
332
+ console.log('');
333
+ }
334
+
335
+ /**
336
+ * 메인 함수
337
+ */
338
+ async function main(): Promise<void> {
339
+ const options = parseArgs();
340
+ const projectRoot = process.cwd();
341
+ const threshold = options.threshold || 500;
342
+ const directory = options.directory || 'src/';
343
+ const exclude = options.exclude || ['**/node_modules/**', '**/dist/**', '**/*.d.ts'];
344
+
345
+ try {
346
+ // 파일 검색
347
+ console.log(`🔍 파일 검색 중... (디렉토리: ${directory})`);
348
+ const files = await findFiles(directory, exclude);
349
+
350
+ if (files.length === 0) {
351
+ console.log('⚠️ 검사할 파일이 없습니다.');
352
+ process.exit(0);
353
+ }
354
+
355
+ console.log(` 발견된 파일: ${files.length}개\n`);
356
+
357
+ // 파일 크기 검증
358
+ console.log('📏 파일 크기 검증 중...');
359
+ const results: FileSizeResult[] = [];
360
+ for (const file of files) {
361
+ const result = validateFileSize(file, threshold);
362
+ results.push(result);
363
+ }
364
+
365
+ // 통계 계산
366
+ const stats = calculateStats(results);
367
+
368
+ // 결과 출력
369
+ printResults(results, stats, threshold, projectRoot);
370
+
371
+ // CI 모드: exit code 처리
372
+ if (options.ci) {
373
+ if (stats.error > 0) {
374
+ console.log('❌ CI 실패: 500줄 초과 파일이 있습니다.');
375
+ process.exit(1);
376
+ } else if (stats.warning > 0 && !options.allowSoftFail) {
377
+ console.log('⚠️ CI 경고: 임계값 초과 파일이 있습니다.');
378
+ process.exit(1);
379
+ } else {
380
+ console.log('✅ CI 통과: 모든 파일이 임계값 이하입니다.');
381
+ process.exit(0);
382
+ }
383
+ } else {
384
+ // 일반 모드: 정보만 출력
385
+ if (stats.error > 0 || stats.warning > 0) {
386
+ console.log('💡 팁: --ci 옵션을 사용하면 CI/CD 파이프라인에 통합할 수 있습니다.');
387
+ }
388
+ }
389
+ } catch (error) {
390
+ console.error('❌ 오류 발생:', error instanceof Error ? error.message : String(error));
391
+ if (error instanceof Error && error.stack) {
392
+ console.error(error.stack);
393
+ }
394
+ process.exit(1);
395
+ }
396
+ }
397
+
398
+ // 스크립트 직접 실행 시
399
+ if (import.meta.url === `file://${process.argv[1]}` || import.meta.url.endsWith(process.argv[1])) {
400
+ main().catch(error => {
401
+ console.error('❌ 치명적 오류:', error);
402
+ process.exit(1);
403
+ });
404
+ }
405
+