@axboot-mcp/mcp-server 1.0.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.
Files changed (78) hide show
  1. package/CLAUDE.md +119 -0
  2. package/MCP_TOOL_PLAN.md +710 -0
  3. package/MCP_USAGE.md +914 -0
  4. package/README.md +168 -0
  5. package/REPOSITORY_CONVENTIONS.md +250 -0
  6. package/SEARCH_PARAMS_MCP_TOOL_COMPLETE_PLAN.md +646 -0
  7. package/SEARCH_PARAMS_PLAN.md +2570 -0
  8. package/STORE_PATTERNS.md +1178 -0
  9. package/debug-dto.js +72 -0
  10. package/generate-banner-store.js +62 -0
  11. package/generation-plan.json +2176 -0
  12. package/generation-results.json +1817 -0
  13. package/package.json +45 -0
  14. package/scripts/batch-generate-all.js +159 -0
  15. package/scripts/batch-generate-mcp.js +329 -0
  16. package/scripts/batch-generate-stores-v2.js +272 -0
  17. package/scripts/batch-generate-stores.js +179 -0
  18. package/scripts/batch-plan.json +3810 -0
  19. package/scripts/batch-process.py +90 -0
  20. package/scripts/batch-regenerate.js +356 -0
  21. package/scripts/direct-generate.js +227 -0
  22. package/scripts/execute-batches.js +1911 -0
  23. package/scripts/generate-all-stores.js +144 -0
  24. package/scripts/generate-stores-mcp.js +161 -0
  25. package/scripts/generate-stores-v2.js +450 -0
  26. package/scripts/generate-stores-v3.js +412 -0
  27. package/scripts/generate-stores-v4.js +521 -0
  28. package/scripts/generate-stores.js +382 -0
  29. package/scripts/repos-to-process.json +1899 -0
  30. package/src/config/nh-layout-patterns.ts +166 -0
  31. package/src/docs/HOOK_GENERATION_PLAN.md +2226 -0
  32. package/src/docs/NH_STORE_PATTERNS.md +297 -0
  33. package/src/docs/README.md +216 -0
  34. package/src/docs/index.ts +28 -0
  35. package/src/docs/loader.ts +568 -0
  36. package/src/docs/patterns.json +419 -0
  37. package/src/docs/practical-examples.md +732 -0
  38. package/src/docs/quick-start.md +257 -0
  39. package/src/docs/requirements-analysis-guide.md +364 -0
  40. package/src/docs/rules.json +321 -0
  41. package/src/docs/store-pattern-analysis.md +664 -0
  42. package/src/docs/store-patterns-rules.md +1168 -0
  43. package/src/docs/store-patterns-usage-guide.md +1835 -0
  44. package/src/docs/troubleshooting.md +544 -0
  45. package/src/docs/type-selection-guide.md +572 -0
  46. package/src/docs//354/202/254/354/232/251/353/262/225/AntD-/354/273/264/355/217/254/353/204/214/355/212/270-/354/202/254/354/232/251/353/262/225.md +1515 -0
  47. package/src/docs//354/202/254/354/232/251/353/262/225/DataGrid-/354/202/254/354/232/251/353/262/225.md +866 -0
  48. package/src/docs//354/202/254/354/232/251/353/262/225/FormItem-/354/202/254/354/232/251/353/262/225.md +903 -0
  49. package/src/docs//354/202/254/354/232/251/353/262/225/FormModal-/354/202/254/354/232/251/353/262/225.md +1155 -0
  50. package/src/docs//354/202/254/354/232/251/353/262/225/MCP-/353/260/224/354/235/264/353/270/214/354/275/224/353/224/251-/352/260/200/354/235/264/353/223/234.md +1133 -0
  51. package/src/docs//354/202/254/354/232/251/353/262/225/MSW-Mock-/353/215/260/354/235/264/355/204/260-/354/202/254/354/232/251/353/262/225.md +579 -0
  52. package/src/docs//354/202/254/354/232/251/353/262/225/Search-/354/273/264/355/217/254/353/204/214/355/212/270-/354/202/254/354/232/251/353/262/225.md +738 -0
  53. package/src/docs//354/202/254/354/232/251/353/262/225/Store-/355/214/250/355/204/264-/354/202/254/354/232/251/353/262/225.md +1135 -0
  54. package/src/docs//354/202/254/354/232/251/353/262/225//355/231/224/353/251/264/352/265/254/354/204/261-/355/203/200/354/236/205/353/263/204-/352/260/234/353/260/234/354/210/234/354/204/234.md +1805 -0
  55. package/src/docs//354/202/254/354/232/251/353/262/225//355/231/224/353/251/264/355/203/200/354/236/205/353/263/204-/352/260/234/353/260/234-/355/224/204/353/241/254/355/224/204/355/212/270-/352/260/200/354/235/264/353/223/234.md +946 -0
  56. package/src/docs//354/202/254/354/232/251/353/262/225//355/231/225/354/236/245/355/231/224/353/251/264/355/203/200/354/236/205/353/263/204-/354/203/201/354/204/270-/355/224/204/353/241/254/355/224/204/355/212/270/352/260/200/354/235/264/353/223/234.md +2422 -0
  57. package/src/features/store-features.ts +232 -0
  58. package/src/handlers/analyze-requirements.ts +403 -0
  59. package/src/handlers/analyze.ts +1373 -0
  60. package/src/handlers/generate-from-requirements.ts +250 -0
  61. package/src/handlers/generate-hook.ts +950 -0
  62. package/src/handlers/generate-interactive.ts +840 -0
  63. package/src/handlers/generate-listdatagrid.ts +521 -0
  64. package/src/handlers/generate-multi-stores.ts +577 -0
  65. package/src/handlers/generate-requirements-from-layout.ts +160 -0
  66. package/src/handlers/generate-search-params.ts +717 -0
  67. package/src/handlers/generate.ts +911 -0
  68. package/src/handlers/list-templates.ts +104 -0
  69. package/src/handlers/scan-metadata.ts +485 -0
  70. package/src/handlers/suggest-layout.ts +326 -0
  71. package/src/index.ts +959 -0
  72. package/src/prompts/search-params.md +793 -0
  73. package/src/templates/index.ts +107 -0
  74. package/src/templates/unified.ts +462 -0
  75. package/store-generation-error-patterns.md +225 -0
  76. package/test/useAgentStore.ts +136 -0
  77. package/test-server.js +78 -0
  78. package/tsconfig.json +20 -0
@@ -0,0 +1,90 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Batch Store Generator using MCP-AXBOOT
4
+ Processes all repositories and generates Zustand stores
5
+ """
6
+
7
+ import json
8
+ import sys
9
+ import subprocess
10
+ import os
11
+ from pathlib import Path
12
+
13
+ # Load the repository list
14
+ plan_file = Path(__file__).parent / 'repos-to-process.json'
15
+ with open(plan_file) as f:
16
+ repositories = json.load(f)
17
+
18
+ print(f"Total repositories to process: {len(repositories)}")
19
+ print("=" * 80)
20
+
21
+ # Track results
22
+ results = {
23
+ "success": [],
24
+ "failed": [],
25
+ "skipped": []
26
+ }
27
+
28
+ # Process each repository
29
+ for i, repo in enumerate(repositories, 1):
30
+ repo_name = repo['repositoryName']
31
+ store_name = repo['storeName']
32
+ input_path = repo['inputPath']
33
+ output_path = repo['outputPath']
34
+ store_type = repo['storeType']
35
+
36
+ print(f"\n[{i}/{len(repositories)}] Processing: {repo_name}")
37
+ print(f" Store: {store_name}")
38
+ print(f" Type: {store_type}")
39
+ print(f" Input: {input_path}")
40
+ print(f" Output: {output_path}")
41
+
42
+ # Check if input file exists
43
+ if not os.path.exists(input_path):
44
+ print(f" ⚠️ SKIP: Input file not found")
45
+ results["skipped"].append({
46
+ "repository": repo_name,
47
+ "reason": "Input file not found"
48
+ })
49
+ continue
50
+
51
+ # Check if file is empty
52
+ if os.path.getsize(input_path) == 0:
53
+ print(f" ⚠️ SKIP: Empty file")
54
+ results["skipped"].append({
55
+ "repository": repo_name,
56
+ "reason": "Empty file"
57
+ })
58
+ continue
59
+
60
+ try:
61
+ # For now, we'll create a placeholder file
62
+ # In the next step, we'll use the MCP tool
63
+ print(f" ✓ Would generate store (type {store_type})")
64
+ results["success"].append({
65
+ "repository": repo_name,
66
+ "store": store_name,
67
+ "type": store_type
68
+ })
69
+ except Exception as e:
70
+ print(f" ❌ ERROR: {str(e)}")
71
+ results["failed"].append({
72
+ "repository": repo_name,
73
+ "error": str(e)
74
+ })
75
+
76
+ # Print summary
77
+ print("\n" + "=" * 80)
78
+ print("SUMMARY")
79
+ print("=" * 80)
80
+ print(f"Total: {len(repositories)}")
81
+ print(f"✓ Success: {len(results['success'])}")
82
+ print(f"⚠️ Skipped: {len(results['skipped'])}")
83
+ print(f"❌ Failed: {len(results['failed'])}")
84
+
85
+ # Save results
86
+ results_file = Path(__file__).parent / 'processing-results.json'
87
+ with open(results_file, 'w') as f:
88
+ json.dump(results, f, indent=2)
89
+
90
+ print(f"\nResults saved to: {results_file}")
@@ -0,0 +1,356 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * NH 프로젝트 Store 일괄 재생성 스크립트
4
+ *
5
+ * 1. NH 폴더 하위의 모든 use*Store.ts 파일 찾기
6
+ * 2. Service 이름 추출
7
+ * 3. Repository 찾기
8
+ * 4. MCP 서버로 Store 재생성
9
+ */
10
+
11
+ const { execSync } = require('child_process');
12
+ const fs = require('fs');
13
+ const path = require('path');
14
+
15
+ const TARGET_DIR = '/Users/kyle/Desktop/nh-fe-bo/src/pages/resources/NH';
16
+ const REPO_BASE = '/Users/kyle/Desktop/nh-fe-bo/src/services/@interface/repository';
17
+ const MCP_SERVER_PATH = '/Users/kyle/work/mcp-axboot/dist/index.js';
18
+
19
+ // ANSI 색상
20
+ const colors = {
21
+ reset: '\x1b[0m',
22
+ bright: '\x1b[1m',
23
+ green: '\x1b[32m',
24
+ yellow: '\x1b[33m',
25
+ red: '\x1b[31m',
26
+ blue: '\x1b[34m',
27
+ cyan: '\x1b[36m',
28
+ };
29
+
30
+ function log(message, color = 'reset') {
31
+ console.log(`${colors[color]}${message}${colors.reset}`);
32
+ }
33
+
34
+ /**
35
+ * Store 파일에서 Service 이름 추출
36
+ * 예: import { Banner, BannerSerevice, ... } from "services"; → BannerSerevice
37
+ */
38
+ function extractServiceName(storeContent) {
39
+ // "from "services"" 라인 찾기
40
+ const servicesImportMatch = storeContent.match(/import\s*{[^}]*}\s*from\s*['"]services['"];?/);
41
+ if (!servicesImportMatch) return null;
42
+
43
+ const imports = servicesImportMatch[0];
44
+ // Service 이름 패턴: XxxService 또는 XxxSerevice (오타 포함)
45
+ const serviceMatch = imports.match(/([A-Z][a-zA-Z0-9]*)Serevice\b/);
46
+ if (serviceMatch) {
47
+ return serviceMatch[1] + 'Serevice'; // 오타 그대로 사용
48
+ }
49
+
50
+ const serviceMatch2 = imports.match(/([A-Z][a-zA-Z0-9]*)Service\b/);
51
+ return serviceMatch2 ? serviceMatch2[1] + 'Service' : null;
52
+ }
53
+
54
+ /**
55
+ * Service 이름으로 Repository 파일 찾기
56
+ * 예: BannerSerevice → BannerRepository.ts
57
+ */
58
+ function findRepository(serviceName) {
59
+ // Service 이름에서 Entity 이름 추출
60
+ // BannerSerevice → Banner, MemberService → Member
61
+ const entityMatch = serviceName.match(/([A-Z][a-zA-Z0-9]*)Serevice/)
62
+ || serviceName.match(/([A-Z][a-zA-Z0-9]*)Service/);
63
+
64
+ if (!entityMatch) return null;
65
+
66
+ const entityName = entityMatch[1];
67
+
68
+ // 가능한 Repository 파일 이름들
69
+ const possibleNames = [
70
+ `${entityName}Repository.ts`,
71
+ `${entityName}Interface.ts`,
72
+ ];
73
+
74
+ for (const name of possibleNames) {
75
+ const repoPath = path.join(REPO_BASE, name);
76
+ if (fs.existsSync(repoPath)) {
77
+ return { repoPath, entityName };
78
+ }
79
+ }
80
+
81
+ return null;
82
+ }
83
+
84
+ /**
85
+ * Store 파일에서 패턴 분석으로 Store 타입 결정
86
+ */
87
+ function detectStoreType(storeContent) {
88
+ const hasList = /callListApi/.test(storeContent);
89
+ const hasDetail = /callDetailApi|setDetail|detail:/.test(storeContent);
90
+ const hasDelete = /callDeleteApi|deleteSpinning/.test(storeContent);
91
+ const hasSave = /callSaveApi|saveSpinning/.test(storeContent);
92
+ const hasExcel = /callExcelDownloadApi|excelSpinning/.test(storeContent);
93
+ const hasModal = /modalOpen|setModalOpen/.test(storeContent);
94
+ const hasTree = /expandedKeys|setExpandedKeys/.test(storeContent);
95
+ const hasDashboard = /summaryData|summarySpinning/.test(storeContent);
96
+ const hasReorder = /setListData.*drag|isReordered/.test(storeContent);
97
+
98
+ // 대시보드
99
+ if (hasDashboard) return 4; // Type 4
100
+
101
+ // 트리
102
+ if (hasTree) return 3; // Type 3
103
+
104
+ // 재정렬
105
+ if (hasReorder && !hasDetail && !hasDelete && !hasSave) return 6; // Type 6
106
+
107
+ // 단순 리스트
108
+ if (!hasDetail && !hasDelete && !hasSave && !hasExcel && !hasModal) return 5; // Type 5
109
+
110
+ // Master-Detail + Excel
111
+ if (hasList && hasExcel && !hasModal && !hasDelete && !hasSave) return 10; // Type 10
112
+
113
+ // List + Selection + Excel
114
+ if (hasList && hasExcel && !hasDetail && !hasModal) return 8; // Type 8
115
+
116
+ // Master-Detail + Modal + Delete + Excel
117
+ if (hasList && hasDetail && hasModal && hasDelete && hasExcel) return 7; // Type 7
118
+
119
+ // Master-Detail + Modal + Detail API
120
+ if (hasList && hasDetail && hasModal && !hasDelete && !hasSave && !hasExcel) return 9; // Type 9
121
+
122
+ // Master-Detail + Modal + Delete (기본)
123
+ if (hasList && hasDetail && hasModal && hasDelete) return 2; // Type 2
124
+
125
+ // 기본 리스트 + 상세
126
+ if (hasList && hasDetail) return 1; // Type 1
127
+
128
+ // 기본값
129
+ return 1;
130
+ }
131
+
132
+ /**
133
+ * MCP 서버로 Store 생성 요청
134
+ */
135
+ async function generateStore(repoPath, outputPath, storeName, storeType) {
136
+ const { spawn } = require('child_process');
137
+
138
+ return new Promise((resolve, reject) => {
139
+ const MCP_SERVER = spawn('node', [MCP_SERVER_PATH], {
140
+ stdio: ['pipe', 'pipe', 'inherit'],
141
+ });
142
+
143
+ let responseData = '';
144
+ let requestId = 1;
145
+
146
+ MCP_SERVER.stdout.on('data', (data) => {
147
+ responseData += data.toString();
148
+ });
149
+
150
+ MCP_SERVER.on('error', (error) => {
151
+ reject(error);
152
+ });
153
+
154
+ MCP_SERVER.on('close', (code) => {
155
+ try {
156
+ const responses = responseData.trim().split('\n').filter(Boolean);
157
+ for (const response of responses) {
158
+ const parsed = JSON.parse(response);
159
+ if (parsed.result) {
160
+ resolve(parsed.result);
161
+ return;
162
+ }
163
+ }
164
+ reject(new Error('No valid response from MCP server'));
165
+ } catch (e) {
166
+ reject(e);
167
+ }
168
+ });
169
+
170
+ // initialize
171
+ MCP_SERVER.stdin.write(JSON.stringify({
172
+ jsonrpc: '2.0',
173
+ id: requestId++,
174
+ method: 'initialize',
175
+ params: {
176
+ protocolVersion: '2024-11-05',
177
+ capabilities: {},
178
+ clientInfo: {
179
+ name: 'batch-regenerate-script',
180
+ version: '1.0.0',
181
+ },
182
+ },
183
+ }) + '\n');
184
+
185
+ // tools/list
186
+ MCP_SERVER.stdin.write(JSON.stringify({
187
+ jsonrpc: '2.0',
188
+ id: requestId++,
189
+ method: 'tools/list',
190
+ }) + '\n');
191
+
192
+ // generate_store 호출
193
+ setTimeout(() => {
194
+ MCP_SERVER.stdin.write(JSON.stringify({
195
+ jsonrpc: '2.0',
196
+ id: requestId++,
197
+ method: 'tools/call',
198
+ params: {
199
+ name: 'generate_store',
200
+ arguments: {
201
+ interfacePath: repoPath,
202
+ outputPath: outputPath,
203
+ storeName: storeName,
204
+ storeType: storeType,
205
+ },
206
+ },
207
+ }) + '\n');
208
+ }, 100);
209
+
210
+ setTimeout(() => {
211
+ MCP_SERVER.kill();
212
+ }, 10000);
213
+ });
214
+ }
215
+
216
+ /**
217
+ * 메인 처리 함수
218
+ */
219
+ async function processStore(storePath) {
220
+ const content = fs.readFileSync(storePath, 'utf8');
221
+
222
+ // Service 이름 추출
223
+ const serviceName = extractServiceName(content);
224
+ if (!serviceName) {
225
+ log(` ⚠️ Service를 찾을 수 없음`, 'yellow');
226
+ return { success: false, reason: 'No service found' };
227
+ }
228
+
229
+ // Repository 찾기
230
+ const repoInfo = findRepository(serviceName);
231
+ if (!repoInfo) {
232
+ log(` ⚠️ Repository를 찾을 수 없음 (${serviceName})`, 'yellow');
233
+ return { success: false, reason: 'No repository found', serviceName };
234
+ }
235
+
236
+ const { repoPath, entityName } = repoInfo;
237
+
238
+ // 새 Store 이름 생성
239
+ const storeDir = path.dirname(storePath);
240
+ const originalName = path.basename(storePath, '.ts');
241
+ const newStoreName = originalName.replace('use', 'use').replace('Store', 'StoreNew');
242
+ const outputPath = path.join(storeDir, `${newStoreName}.ts`);
243
+
244
+ // Store 타입 결정
245
+ const storeType = detectStoreType(content);
246
+
247
+ log(` 📦 Entity: ${entityName}`, 'cyan');
248
+ log(` 📝 Repository: ${path.basename(repoPath)}`, 'cyan');
249
+ log(` 🔧 Store Type: ${storeType}`, 'cyan');
250
+ log(` 📄 Output: ${newStoreName}.ts`, 'cyan');
251
+
252
+ try {
253
+ await generateStore(repoPath, outputPath, newStoreName, storeType);
254
+ log(` ✅ 생성 완료`, 'green');
255
+ return {
256
+ success: true,
257
+ entityName,
258
+ serviceName,
259
+ originalName,
260
+ newName: newStoreName,
261
+ storeType,
262
+ };
263
+ } catch (error) {
264
+ log(` ❌ 생성 실패: ${error.message}`, 'red');
265
+ return {
266
+ success: false,
267
+ reason: 'Generation failed',
268
+ error: error.message,
269
+ };
270
+ }
271
+ }
272
+
273
+ /**
274
+ * 메인 실행
275
+ */
276
+ async function main() {
277
+ log('='.repeat(60), 'cyan');
278
+ log('NH 프로젝트 Store 일괄 재생성', 'bright');
279
+ log('='.repeat(60), 'cyan');
280
+
281
+ // MCP 서버 확인
282
+ if (!fs.existsSync(MCP_SERVER_PATH)) {
283
+ log(`❌ MCP 서버를 찾을 수 없음: ${MCP_SERVER_PATH}`, 'red');
284
+ log('먼저 npm run build를 실행해주세요.', 'yellow');
285
+ process.exit(1);
286
+ }
287
+
288
+ // 모든 Store 파일 찾기
289
+ const findCommand = `find "${TARGET_DIR}" -name "use*Store.ts" -type f`;
290
+ let storeFiles;
291
+ try {
292
+ storeFiles = execSync(findCommand, { encoding: 'utf8' }).trim().split('\n');
293
+ } catch (error) {
294
+ log(`❌ Store 파일을 찾을 수 없음: ${TARGET_DIR}`, 'red');
295
+ process.exit(1);
296
+ }
297
+
298
+ log(`\n📊 총 ${storeFiles.length}개의 Store 파일 발견\n`, 'bright');
299
+
300
+ const results = {
301
+ total: storeFiles.length,
302
+ success: 0,
303
+ failed: 0,
304
+ noService: 0,
305
+ noRepo: 0,
306
+ details: [],
307
+ };
308
+
309
+ // 각 Store 처리
310
+ for (let i = 0; i < storeFiles.length; i++) {
311
+ const storePath = storeFiles[i];
312
+ const relativePath = path.relative(TARGET_DIR, storePath);
313
+
314
+ process.stdout.write(`\r[${i + 1}/${storeFiles.length}] ${relativePath.padEnd(50)} `);
315
+
316
+ const result = await processStore(storePath);
317
+
318
+ results.details.push({ ...result, path: relativePath });
319
+
320
+ if (result.success) {
321
+ results.success++;
322
+ } else {
323
+ results.failed++;
324
+ if (result.reason === 'No service found') results.noService++;
325
+ if (result.reason === 'No repository found') results.noRepo++;
326
+ }
327
+ }
328
+
329
+ // 결과 요약
330
+ log('\n');
331
+ log('='.repeat(60), 'cyan');
332
+ log('📊 결과 요약', 'bright');
333
+ log('='.repeat(60), 'cyan');
334
+ log(` 전체: ${results.total}`, 'cyan');
335
+ log(` 성공: ${results.success}`, 'green');
336
+ log(` 실패: ${results.failed}`, 'red');
337
+ log(` - Service 없음: ${results.noService}`, 'yellow');
338
+ log(` - Repository 없음: ${results.noRepo}`, 'yellow');
339
+ log('='.repeat(60), 'cyan');
340
+
341
+ // 실패 목록
342
+ if (results.details.filter(r => !r.success && r.reason !== 'No service found' && r.reason !== 'No repository found').length > 0) {
343
+ log('\n⚠️ 생성 실패 목록:', 'yellow');
344
+ results.details
345
+ .filter(r => !r.success && r.reason !== 'No service found' && r.reason !== 'No repository found')
346
+ .forEach(r => {
347
+ log(` ❌ ${r.path}: ${r.error || r.reason}`, 'red');
348
+ });
349
+ }
350
+ }
351
+
352
+ main().catch(error => {
353
+ log(`\n❌ 치명적 오류: ${error.message}`, 'red');
354
+ console.error(error);
355
+ process.exit(1);
356
+ });
@@ -0,0 +1,227 @@
1
+ #!/usr/bin/env node
2
+
3
+ // Direct import of handlers to avoid MCP protocol overhead
4
+ import { generateStore } from '../dist/handlers/generate.js';
5
+ import fs from 'fs';
6
+ import path from 'path';
7
+
8
+ const SOURCE_DIR = '/Users/kyle/Desktop/nh-fe-bo/src/services/@interface/repository';
9
+ const OUTPUT_DIR = '/Users/kyle/Desktop/nh-fe-bo/src/pages/resources/NH/test';
10
+
11
+ // Store type detection patterns
12
+ function detectStoreType(filePath) {
13
+ const content = fs.readFileSync(filePath, 'utf-8');
14
+ const methods = content.match(/async\s+(\w+)\s*\(/g) || [];
15
+ const methodNames = methods.map(m => m.match(/async\s+(\w+)/)[1].toLowerCase());
16
+
17
+ const hasList = methodNames.some(m => m.includes('list'));
18
+ const hasDetail = methodNames.some(m => m.includes('detail') || m.includes('dtl'));
19
+ const hasSave = methodNames.some(m => m.includes('save'));
20
+ const hasDelete = methodNames.some(m => m.includes('delete') || m.includes('del'));
21
+ const hasExcel = methodNames.some(m => m.includes('excel') || m.includes('download') || m.includes('export'));
22
+
23
+ if (hasList && hasDetail && hasSave && hasDelete && hasExcel) {
24
+ return 7;
25
+ } else if (hasList && hasDetail && hasSave && hasDelete) {
26
+ return 2;
27
+ } else if (hasList && hasSave) {
28
+ return 1;
29
+ } else {
30
+ return 5;
31
+ }
32
+ }
33
+
34
+ // Get all repository files
35
+ function getRepositoryFiles() {
36
+ const files = fs.readdirSync(SOURCE_DIR)
37
+ .filter(file => file.endsWith('Repository.ts'));
38
+ return files.map(file => path.join(SOURCE_DIR, file));
39
+ }
40
+
41
+ // Extract repository name
42
+ function getRepositoryName(filePath) {
43
+ return path.basename(filePath, 'Repository.ts');
44
+ }
45
+
46
+ // Generate store name
47
+ function getStoreName(repositoryName) {
48
+ return `use${repositoryName}ListStore`;
49
+ }
50
+
51
+ // Get output path
52
+ function getOutputPath(repositoryName) {
53
+ return path.join(OUTPUT_DIR, `use${repositoryName}ListStore.ts`);
54
+ }
55
+
56
+ // Main execution
57
+ async function main() {
58
+ console.log('='.repeat(80));
59
+ console.log('Batch Store Generation for NH-FE-BO Repository Files');
60
+ console.log('='.repeat(80));
61
+ console.log(`Source Directory: ${SOURCE_DIR}`);
62
+ console.log(`Output Directory: ${OUTPUT_DIR}`);
63
+ console.log('');
64
+
65
+ const files = getRepositoryFiles();
66
+ console.log(`Found ${files.length} repository files\n`);
67
+
68
+ const results = {
69
+ total: files.length,
70
+ success: 0,
71
+ failed: 0,
72
+ skipped: 0,
73
+ generated: [],
74
+ failedFiles: [],
75
+ typeDistribution: {}
76
+ };
77
+
78
+ // Process in batches of 10
79
+ const batchSize = 10;
80
+ for (let i = 0; i < files.length; i += batchSize) {
81
+ const batch = files.slice(i, i + batchSize);
82
+ console.log(`\nProcessing batch ${Math.floor(i/batchSize) + 1}/${Math.ceil(files.length/batchSize)} (files ${i + 1}-${Math.min(i + batchSize, files.length)})`);
83
+ console.log('-'.repeat(80));
84
+
85
+ for (const filePath of batch) {
86
+ const index = files.indexOf(filePath) + 1;
87
+ const repositoryName = getRepositoryName(filePath);
88
+ const storeName = getStoreName(repositoryName);
89
+ const outputPath = getOutputPath(repositoryName);
90
+ const storeType = detectStoreType(filePath);
91
+
92
+ // Track type distribution
93
+ results.typeDistribution[storeType] = (results.typeDistribution[storeType] || 0) + 1;
94
+
95
+ console.log(`[${index}/${files.length}] ${repositoryName}Repository → Type ${storeType}`);
96
+
97
+ try {
98
+ // Check if file already exists
99
+ if (fs.existsSync(outputPath)) {
100
+ console.log(` ⚠️ Already exists, skipping\n`);
101
+ results.skipped++;
102
+ results.generated.push({
103
+ repositoryName,
104
+ storeName,
105
+ storeType,
106
+ status: 'exists',
107
+ outputPath
108
+ });
109
+ continue;
110
+ }
111
+
112
+ // Generate store using direct handler call
113
+ console.log(` 🔄 Generating store...`);
114
+ const result = await generateStore({
115
+ interfacePath: filePath,
116
+ outputPath: outputPath,
117
+ storeType: storeType,
118
+ storeName: storeName
119
+ });
120
+
121
+ // Parse result
122
+ let resultData;
123
+ if (result.content && result.content[0]) {
124
+ resultData = JSON.parse(result.content[0].text);
125
+ } else {
126
+ throw new Error('Invalid response format');
127
+ }
128
+
129
+ if (!resultData.success) {
130
+ throw new Error(resultData.error || 'Unknown error');
131
+ }
132
+
133
+ // Check if file was created
134
+ if (fs.existsSync(outputPath)) {
135
+ results.success++;
136
+ results.generated.push({
137
+ repositoryName,
138
+ storeName,
139
+ storeType,
140
+ status: 'success',
141
+ outputPath
142
+ });
143
+ console.log(` ✓ Generated\n`);
144
+ } else {
145
+ throw new Error('File was not created');
146
+ }
147
+
148
+ } catch (error) {
149
+ results.failed++;
150
+ results.failedFiles.push({
151
+ repositoryName,
152
+ storeName,
153
+ error: error.message
154
+ });
155
+ console.log(` ✗ Failed: ${error.message}\n`);
156
+ }
157
+
158
+ // Small delay
159
+ await new Promise(resolve => setTimeout(resolve, 50));
160
+ }
161
+ }
162
+
163
+ // Print summary
164
+ console.log('\n' + '='.repeat(80));
165
+ console.log('SUMMARY');
166
+ console.log('='.repeat(80));
167
+ console.log(`Total files processed: ${results.total}`);
168
+ console.log(`Successfully generated: ${results.success}`);
169
+ console.log(`Skipped (already exists): ${results.skipped}`);
170
+ console.log(`Failed: ${results.failed}`);
171
+ console.log('');
172
+ console.log('Type Distribution:');
173
+ Object.entries(results.typeDistribution).sort((a, b) => a[0] - b[0]).forEach(([type, count]) => {
174
+ console.log(` Type ${type}: ${count} files`);
175
+ });
176
+
177
+ // Save detailed results
178
+ const resultsPath = path.join(OUTPUT_DIR, 'generation-results.json');
179
+ fs.writeFileSync(resultsPath, JSON.stringify(results, null, 2));
180
+ console.log(`\nDetailed results saved to: ${resultsPath}`);
181
+
182
+ // Generate markdown report
183
+ const markdownPath = path.join(OUTPUT_DIR, 'generation-results.md');
184
+ const markdown = generateMarkdownReport(results);
185
+ fs.writeFileSync(markdownPath, markdown);
186
+ console.log(`Markdown report saved to: ${markdownPath}`);
187
+ }
188
+
189
+ function generateMarkdownReport(results) {
190
+ const date = new Date().toISOString();
191
+
192
+ let md = `# Store Generation Results\n\n`;
193
+ md += `**Generated:** ${date}\n\n`;
194
+ md += `## Summary\n\n`;
195
+ md += `- **Total Files:** ${results.total}\n`;
196
+ md += `- **Successfully Generated:** ${results.success}\n`;
197
+ md += `- **Skipped (already exists):** ${results.skipped}\n`;
198
+ md += `- **Failed:** ${results.failed}\n\n`;
199
+
200
+ md += `## Type Distribution\n\n`;
201
+ md += `| Type | Count |\n`;
202
+ md += `|------|-------|\n`;
203
+ Object.entries(results.typeDistribution).sort((a, b) => a[0] - b[0]).forEach(([type, count]) => {
204
+ md += `| ${type} | ${count} |\n`;
205
+ });
206
+
207
+ md += `\n## Generated Stores\n\n`;
208
+ md += `| # | Repository | Store Name | Type | Status |\n`;
209
+ md += `|---|------------|------------|------|--------|\n`;
210
+ results.generated.forEach((item, idx) => {
211
+ const status = item.status === 'success' ? '✓' : '⚠️';
212
+ md += `| ${idx + 1} | ${item.repositoryName}Repository | ${item.storeName} | ${item.storeType} | ${status} |\n`;
213
+ });
214
+
215
+ if (results.failedFiles.length > 0) {
216
+ md += `\n## Failed Files\n\n`;
217
+ md += `| Repository | Error |\n`;
218
+ md += `|------------|-------|\n`;
219
+ results.failedFiles.forEach(item => {
220
+ md += `| ${item.repositoryName} | ${item.error} |\n`;
221
+ });
222
+ }
223
+
224
+ return md;
225
+ }
226
+
227
+ main().catch(console.error);