@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
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@axboot-mcp/mcp-server",
3
+ "publishConfig": {
4
+ "access": "public"
5
+ },
6
+ "version": "1.0.0",
7
+ "description": "Axboot MCP Server - Store 생성 및 다른 기능 확장 가능",
8
+ "main": "./dist/index.js",
9
+ "types": "./dist/index.d.ts",
10
+ "scripts": {
11
+ "build": "tsc && npm run copy-assets",
12
+ "dev": "tsc --watch",
13
+ "start": "node dist/index.js",
14
+ "clean": "rm -rf dist",
15
+ "copy-assets": "npm run copy-docs && npm run copy-prompts",
16
+ "copy-docs": "mkdir -p dist/docs && cp -r src/docs/*.json src/docs/*.md dist/docs/ 2>/dev/null || true",
17
+ "copy-prompts": "mkdir -p dist/prompts && cp -r src/prompts/*.md dist/prompts/ 2>/dev/null || true"
18
+ },
19
+ "keywords": [
20
+ "mcp",
21
+ "model-context-protocol",
22
+ "axboot",
23
+ "zustand",
24
+ "store",
25
+ "generator"
26
+ ],
27
+ "author": "",
28
+ "license": "MIT",
29
+ "dependencies": {
30
+ "@modelcontextprotocol/sdk": "^1.0.4",
31
+ "chokidar": "^5.0.0",
32
+ "glob": "^13.0.0",
33
+ "mustache": "^4.2.0",
34
+ "typescript": "^5.7.3"
35
+ },
36
+ "devDependencies": {
37
+ "@types/chokidar": "^1.7.5",
38
+ "@types/mustache": "^4.2.6",
39
+ "@types/node": "^22.10.5",
40
+ "@typescript-eslint/typescript-estree": "^8.53.0"
41
+ },
42
+ "engines": {
43
+ "node": ">=18.0.0"
44
+ }
45
+ }
@@ -0,0 +1,159 @@
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const { execSync } = require('child_process');
6
+
7
+ const SOURCE_DIR = '/Users/kyle/Desktop/nh-fe-bo/src/services/@interface/repository';
8
+ const OUTPUT_DIR = '/Users/kyle/Desktop/nh-fe-bo/src/pages/resources/NH/test';
9
+ const MCP_SERVER_PATH = '/Users/kyle/work/mcp-axboot/dist/index.js';
10
+
11
+ // Store type detection patterns
12
+ const PATTERNS = {
13
+ TYPE_7: { name: 'Type 7', patterns: [/list/i, /detail|dtl/i, /save/i, /delete|del/i], description: 'Master-Detail + Modal + Delete + Excel' },
14
+ TYPE_2: { name: 'Type 2', patterns: [/list/i, /detail|dtl/i, /save/i, /delete|del/i], description: 'Master-Detail + Modal + Delete' },
15
+ TYPE_1: { name: 'Type 1', patterns: [/list/i, /save/i], description: 'Basic List + Detail' },
16
+ TYPE_5: { name: 'Type 5', patterns: [], description: 'Simple List (default)' }
17
+ };
18
+
19
+ // Get all repository files
20
+ function getRepositoryFiles() {
21
+ const files = fs.readdirSync(SOURCE_DIR)
22
+ .filter(file => file.endsWith('Repository.ts'));
23
+ return files.map(file => path.join(SOURCE_DIR, file));
24
+ }
25
+
26
+ // Parse repository file to detect store type
27
+ function detectStoreType(filePath) {
28
+ const content = fs.readFileSync(filePath, 'utf-8');
29
+ const methods = content.match(/async\s+(\w+)\s*\(/g) || [];
30
+ const methodNames = methods.map(m => m.match(/async\s+(\w+)/)[1].toLowerCase());
31
+
32
+ // Check for Type 7 (has list + detail + save + delete + excel)
33
+ const hasList = methodNames.some(m => m.includes('list'));
34
+ const hasDetail = methodNames.some(m => m.includes('detail') || m.includes('dtl'));
35
+ const hasSave = methodNames.some(m => m.includes('save'));
36
+ const hasDelete = methodNames.some(m => m.includes('delete') || m.includes('del'));
37
+ const hasExcel = methodNames.some(m => m.includes('excel') || m.includes('download'));
38
+
39
+ if (hasList && hasDetail && hasSave && hasDelete && hasExcel) {
40
+ return 7;
41
+ } else if (hasList && hasDetail && hasSave && hasDelete) {
42
+ return 2;
43
+ } else if (hasList && hasSave) {
44
+ return 1;
45
+ } else {
46
+ return 5; // Default to Type 5 (simple list)
47
+ }
48
+ }
49
+
50
+ // Extract repository name from file path
51
+ function getRepositoryName(filePath) {
52
+ const fileName = path.basename(filePath, 'Repository.ts');
53
+ return fileName;
54
+ }
55
+
56
+ // Generate store name from repository name
57
+ function getStoreName(repositoryName) {
58
+ return `use${repositoryName}ListStore`;
59
+ }
60
+
61
+ // Get output path for store file
62
+ function getOutputPath(repositoryName) {
63
+ return path.join(OUTPUT_DIR, `use${repositoryName}ListStore.ts`);
64
+ }
65
+
66
+ // Call MCP tool to generate store
67
+ function generateStore(interfacePath, outputPath, storeName, storeType) {
68
+ // This would call the mcp__axboot__generate_store tool
69
+ // For now, we'll track what needs to be generated
70
+ return {
71
+ interfacePath,
72
+ outputPath,
73
+ storeName,
74
+ storeType,
75
+ status: 'pending'
76
+ };
77
+ }
78
+
79
+ // Main execution
80
+ async function main() {
81
+ console.log('='.repeat(80));
82
+ console.log('Batch Store Generation for NH-FE-BO Repository Files');
83
+ console.log('='.repeat(80));
84
+ console.log(`Source Directory: ${SOURCE_DIR}`);
85
+ console.log(`Output Directory: ${OUTPUT_DIR}`);
86
+ console.log('');
87
+
88
+ const files = getRepositoryFiles();
89
+ console.log(`Found ${files.length} repository files\n`);
90
+
91
+ const results = {
92
+ total: files.length,
93
+ success: 0,
94
+ failed: 0,
95
+ generated: [],
96
+ failedFiles: []
97
+ };
98
+
99
+ // Process each file
100
+ for (let i = 0; i < files.length; i++) {
101
+ const filePath = files[i];
102
+ const repositoryName = getRepositoryName(filePath);
103
+ const storeName = getStoreName(repositoryName);
104
+ const outputPath = getOutputPath(repositoryName);
105
+ const storeType = detectStoreType(filePath);
106
+
107
+ console.log(`[${i + 1}/${files.length}] Processing: ${repositoryName}Repository`);
108
+ console.log(` → Store: ${storeName}`);
109
+ console.log(` → Type: ${storeType}`);
110
+ console.log(` → Output: ${outputPath}`);
111
+
112
+ try {
113
+ // Check if file already exists
114
+ if (fs.existsSync(outputPath)) {
115
+ console.log(` ⚠️ File already exists, skipping...\n`);
116
+ results.generated.push({ repositoryName, storeName, storeType, status: 'exists' });
117
+ continue;
118
+ }
119
+
120
+ // TODO: Call the actual MCP tool here
121
+ // For now, just track it
122
+ results.generated.push({
123
+ repositoryName,
124
+ storeName,
125
+ storeType,
126
+ interfacePath: filePath,
127
+ outputPath,
128
+ status: 'queued'
129
+ });
130
+
131
+ results.success++;
132
+ console.log(` ✓ Queued for generation\n`);
133
+
134
+ } catch (error) {
135
+ results.failed++;
136
+ results.failedFiles.push({
137
+ repositoryName,
138
+ error: error.message
139
+ });
140
+ console.log(` ✗ Error: ${error.message}\n`);
141
+ }
142
+ }
143
+
144
+ // Print summary
145
+ console.log('='.repeat(80));
146
+ console.log('SUMMARY');
147
+ console.log('='.repeat(80));
148
+ console.log(`Total files processed: ${results.total}`);
149
+ console.log(`Successfully queued: ${results.success}`);
150
+ console.log(`Failed: ${results.failed}`);
151
+ console.log('');
152
+
153
+ // Save detailed results
154
+ const resultsPath = path.join(OUTPUT_DIR, 'generation-plan.json');
155
+ fs.writeFileSync(resultsPath, JSON.stringify(results, null, 2));
156
+ console.log(`Detailed plan saved to: ${resultsPath}`);
157
+ }
158
+
159
+ main().catch(console.error);
@@ -0,0 +1,329 @@
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const { spawn } = require('child_process');
6
+
7
+ const SOURCE_DIR = '/Users/kyle/Desktop/nh-fe-bo/src/services/@interface/repository';
8
+ const OUTPUT_DIR = '/Users/kyle/Desktop/nh-fe-bo/src/pages/resources/NH/test';
9
+ const MCP_SERVER_PATH = '/Users/kyle/work/mcp-axboot/dist/index.js';
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
+ // Call MCP server using the analyze interface first, then generate
57
+ async function analyzeInterface(interfacePath) {
58
+ return new Promise((resolve, reject) => {
59
+ const mcp = spawn('node', [MCP_SERVER_PATH], {
60
+ stdio: ['pipe', 'pipe', 'pipe']
61
+ });
62
+
63
+ const request = {
64
+ jsonrpc: '2.0',
65
+ id: 1,
66
+ method: 'tools/call',
67
+ params: {
68
+ name: 'mcp__axboot__analyze_interface',
69
+ arguments: {
70
+ interfacePath
71
+ }
72
+ }
73
+ };
74
+
75
+ let stdout = '';
76
+ let stderr = '';
77
+
78
+ mcp.stdout.on('data', (data) => {
79
+ stdout += data.toString();
80
+ });
81
+
82
+ mcp.stderr.on('data', (data) => {
83
+ stderr += data.toString();
84
+ });
85
+
86
+ mcp.stdin.write(JSON.stringify(request) + '\n');
87
+
88
+ setTimeout(() => {
89
+ mcp.kill();
90
+ try {
91
+ const responses = stdout.trim().split('\n').map(line => {
92
+ try {
93
+ return JSON.parse(line);
94
+ } catch {
95
+ return null;
96
+ }
97
+ }).filter(Boolean);
98
+
99
+ const response = responses.find(r => r.id === 1);
100
+ if (response && response.result) {
101
+ resolve(response.result);
102
+ } else {
103
+ reject(new Error('No valid response from MCP server'));
104
+ }
105
+ } catch (error) {
106
+ reject(error);
107
+ }
108
+ }, 5000);
109
+ });
110
+ }
111
+
112
+ // Generate store using MCP
113
+ async function callGenerateStore(interfacePath, outputPath, storeType, storeName) {
114
+ return new Promise((resolve, reject) => {
115
+ const mcp = spawn('node', [MCP_SERVER_PATH], {
116
+ stdio: ['pipe', 'pipe', 'pipe']
117
+ });
118
+
119
+ const request = {
120
+ jsonrpc: '2.0',
121
+ id: 1,
122
+ method: 'tools/call',
123
+ params: {
124
+ name: 'mcp__axboot__generate_store',
125
+ arguments: {
126
+ interfacePath,
127
+ outputPath,
128
+ storeType,
129
+ storeName
130
+ }
131
+ }
132
+ };
133
+
134
+ let stdout = '';
135
+ let stderr = '';
136
+
137
+ mcp.stdout.on('data', (data) => {
138
+ stdout += data.toString();
139
+ });
140
+
141
+ mcp.stderr.on('data', (data) => {
142
+ stderr += data.toString();
143
+ });
144
+
145
+ mcp.stdin.write(JSON.stringify(request) + '\n');
146
+
147
+ setTimeout(() => {
148
+ mcp.kill();
149
+ try {
150
+ const responses = stdout.trim().split('\n').map(line => {
151
+ try {
152
+ return JSON.parse(line);
153
+ } catch {
154
+ return null;
155
+ }
156
+ }).filter(Boolean);
157
+
158
+ const response = responses.find(r => r.id === 1);
159
+ if (response) {
160
+ resolve(response);
161
+ } else {
162
+ reject(new Error('No valid response from MCP server'));
163
+ }
164
+ } catch (error) {
165
+ reject(error);
166
+ }
167
+ }, 8000);
168
+ });
169
+ }
170
+
171
+ // Main execution
172
+ async function main() {
173
+ console.log('='.repeat(80));
174
+ console.log('Batch Store Generation for NH-FE-BO Repository Files');
175
+ console.log('='.repeat(80));
176
+ console.log(`Source Directory: ${SOURCE_DIR}`);
177
+ console.log(`Output Directory: ${OUTPUT_DIR}`);
178
+ console.log('');
179
+
180
+ const files = getRepositoryFiles();
181
+ console.log(`Found ${files.length} repository files\n`);
182
+
183
+ const results = {
184
+ total: files.length,
185
+ success: 0,
186
+ failed: 0,
187
+ skipped: 0,
188
+ generated: [],
189
+ failedFiles: [],
190
+ typeDistribution: {}
191
+ };
192
+
193
+ // Process in batches of 10 to avoid overwhelming
194
+ const batchSize = 10;
195
+ for (let i = 0; i < files.length; i += batchSize) {
196
+ const batch = files.slice(i, i + batchSize);
197
+ console.log(`\nProcessing batch ${Math.floor(i/batchSize) + 1}/${Math.ceil(files.length/batchSize)} (files ${i + 1}-${Math.min(i + batchSize, files.length)})`);
198
+ console.log('-'.repeat(80));
199
+
200
+ for (const filePath of batch) {
201
+ const index = files.indexOf(filePath) + 1;
202
+ const repositoryName = getRepositoryName(filePath);
203
+ const storeName = getStoreName(repositoryName);
204
+ const outputPath = getOutputPath(repositoryName);
205
+ const storeType = detectStoreType(filePath);
206
+
207
+ // Track type distribution
208
+ results.typeDistribution[storeType] = (results.typeDistribution[storeType] || 0) + 1;
209
+
210
+ console.log(`[${index}/${files.length}] ${repositoryName}Repository → Type ${storeType}`);
211
+
212
+ try {
213
+ // Check if file already exists
214
+ if (fs.existsSync(outputPath)) {
215
+ console.log(` ⚠️ Already exists, skipping\n`);
216
+ results.skipped++;
217
+ results.generated.push({
218
+ repositoryName,
219
+ storeName,
220
+ storeType,
221
+ status: 'exists',
222
+ outputPath
223
+ });
224
+ continue;
225
+ }
226
+
227
+ // Generate store using MCP tool
228
+ console.log(` 🔄 Generating store...`);
229
+ const result = await callGenerateStore(filePath, outputPath, storeType, storeName);
230
+
231
+ if (result.error) {
232
+ throw new Error(result.error.message || 'Unknown error');
233
+ }
234
+
235
+ // Check if file was created
236
+ if (fs.existsSync(outputPath)) {
237
+ results.success++;
238
+ results.generated.push({
239
+ repositoryName,
240
+ storeName,
241
+ storeType,
242
+ status: 'success',
243
+ outputPath
244
+ });
245
+ console.log(` ✓ Generated\n`);
246
+ } else {
247
+ throw new Error('File was not created');
248
+ }
249
+
250
+ } catch (error) {
251
+ results.failed++;
252
+ results.failedFiles.push({
253
+ repositoryName,
254
+ storeName,
255
+ error: error.message
256
+ });
257
+ console.log(` ✗ Failed: ${error.message}\n`);
258
+ }
259
+
260
+ // Small delay to avoid overwhelming
261
+ await new Promise(resolve => setTimeout(resolve, 100));
262
+ }
263
+ }
264
+
265
+ // Print summary
266
+ console.log('\n' + '='.repeat(80));
267
+ console.log('SUMMARY');
268
+ console.log('='.repeat(80));
269
+ console.log(`Total files processed: ${results.total}`);
270
+ console.log(`Successfully generated: ${results.success}`);
271
+ console.log(`Skipped (already exists): ${results.skipped}`);
272
+ console.log(`Failed: ${results.failed}`);
273
+ console.log('');
274
+ console.log('Type Distribution:');
275
+ Object.entries(results.typeDistribution).sort((a, b) => a[0] - b[0]).forEach(([type, count]) => {
276
+ console.log(` Type ${type}: ${count} files`);
277
+ });
278
+
279
+ // Save detailed results
280
+ const resultsPath = path.join(OUTPUT_DIR, 'generation-results.json');
281
+ fs.writeFileSync(resultsPath, JSON.stringify(results, null, 2));
282
+ console.log(`\nDetailed results saved to: ${resultsPath}`);
283
+
284
+ // Generate markdown report
285
+ const markdownPath = path.join(OUTPUT_DIR, 'generation-results.md');
286
+ const markdown = generateMarkdownReport(results);
287
+ fs.writeFileSync(markdownPath, markdown);
288
+ console.log(`Markdown report saved to: ${markdownPath}`);
289
+ }
290
+
291
+ function generateMarkdownReport(results) {
292
+ const date = new Date().toISOString();
293
+
294
+ let md = `# Store Generation Results\n\n`;
295
+ md += `**Generated:** ${date}\n\n`;
296
+ md += `## Summary\n\n`;
297
+ md += `- **Total Files:** ${results.total}\n`;
298
+ md += `- **Successfully Generated:** ${results.success}\n`;
299
+ md += `- **Skipped (already exists):** ${results.skipped}\n`;
300
+ md += `- **Failed:** ${results.failed}\n\n`;
301
+
302
+ md += `## Type Distribution\n\n`;
303
+ md += `| Type | Count |\n`;
304
+ md += `|------|-------|\n`;
305
+ Object.entries(results.typeDistribution).sort((a, b) => a[0] - b[0]).forEach(([type, count]) => {
306
+ md += `| ${type} | ${count} |\n`;
307
+ });
308
+
309
+ md += `\n## Generated Stores\n\n`;
310
+ md += `| # | Repository | Store Name | Type | Status |\n`;
311
+ md += `|---|------------|------------|------|--------|\n`;
312
+ results.generated.forEach((item, idx) => {
313
+ const status = item.status === 'success' ? '✓' : '⚠️';
314
+ md += `| ${idx + 1} | ${item.repositoryName}Repository | ${item.storeName} | ${item.storeType} | ${status} |\n`;
315
+ });
316
+
317
+ if (results.failedFiles.length > 0) {
318
+ md += `\n## Failed Files\n\n`;
319
+ md += `| Repository | Error |\n`;
320
+ md += `|------------|-------|\n`;
321
+ results.failedFiles.forEach(item => {
322
+ md += `| ${item.repositoryName} | ${item.error} |\n`;
323
+ });
324
+ }
325
+
326
+ return md;
327
+ }
328
+
329
+ main().catch(console.error);