@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.
- package/CLAUDE.md +119 -0
- package/MCP_TOOL_PLAN.md +710 -0
- package/MCP_USAGE.md +914 -0
- package/README.md +168 -0
- package/REPOSITORY_CONVENTIONS.md +250 -0
- package/SEARCH_PARAMS_MCP_TOOL_COMPLETE_PLAN.md +646 -0
- package/SEARCH_PARAMS_PLAN.md +2570 -0
- package/STORE_PATTERNS.md +1178 -0
- package/debug-dto.js +72 -0
- package/generate-banner-store.js +62 -0
- package/generation-plan.json +2176 -0
- package/generation-results.json +1817 -0
- package/package.json +45 -0
- package/scripts/batch-generate-all.js +159 -0
- package/scripts/batch-generate-mcp.js +329 -0
- package/scripts/batch-generate-stores-v2.js +272 -0
- package/scripts/batch-generate-stores.js +179 -0
- package/scripts/batch-plan.json +3810 -0
- package/scripts/batch-process.py +90 -0
- package/scripts/batch-regenerate.js +356 -0
- package/scripts/direct-generate.js +227 -0
- package/scripts/execute-batches.js +1911 -0
- package/scripts/generate-all-stores.js +144 -0
- package/scripts/generate-stores-mcp.js +161 -0
- package/scripts/generate-stores-v2.js +450 -0
- package/scripts/generate-stores-v3.js +412 -0
- package/scripts/generate-stores-v4.js +521 -0
- package/scripts/generate-stores.js +382 -0
- package/scripts/repos-to-process.json +1899 -0
- package/src/config/nh-layout-patterns.ts +166 -0
- package/src/docs/HOOK_GENERATION_PLAN.md +2226 -0
- package/src/docs/NH_STORE_PATTERNS.md +297 -0
- package/src/docs/README.md +216 -0
- package/src/docs/index.ts +28 -0
- package/src/docs/loader.ts +568 -0
- package/src/docs/patterns.json +419 -0
- package/src/docs/practical-examples.md +732 -0
- package/src/docs/quick-start.md +257 -0
- package/src/docs/requirements-analysis-guide.md +364 -0
- package/src/docs/rules.json +321 -0
- package/src/docs/store-pattern-analysis.md +664 -0
- package/src/docs/store-patterns-rules.md +1168 -0
- package/src/docs/store-patterns-usage-guide.md +1835 -0
- package/src/docs/troubleshooting.md +544 -0
- package/src/docs/type-selection-guide.md +572 -0
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- package/src/features/store-features.ts +232 -0
- package/src/handlers/analyze-requirements.ts +403 -0
- package/src/handlers/analyze.ts +1373 -0
- package/src/handlers/generate-from-requirements.ts +250 -0
- package/src/handlers/generate-hook.ts +950 -0
- package/src/handlers/generate-interactive.ts +840 -0
- package/src/handlers/generate-listdatagrid.ts +521 -0
- package/src/handlers/generate-multi-stores.ts +577 -0
- package/src/handlers/generate-requirements-from-layout.ts +160 -0
- package/src/handlers/generate-search-params.ts +717 -0
- package/src/handlers/generate.ts +911 -0
- package/src/handlers/list-templates.ts +104 -0
- package/src/handlers/scan-metadata.ts +485 -0
- package/src/handlers/suggest-layout.ts +326 -0
- package/src/index.ts +959 -0
- package/src/prompts/search-params.md +793 -0
- package/src/templates/index.ts +107 -0
- package/src/templates/unified.ts +462 -0
- package/store-generation-error-patterns.md +225 -0
- package/test/useAgentStore.ts +136 -0
- package/test-server.js +78 -0
- package/tsconfig.json +20 -0
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Generate All Stores Script
|
|
5
|
+
*
|
|
6
|
+
* Uses mcp-axboot MCP tools to generate Zustand stores from Repository files
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const fs = require('fs');
|
|
10
|
+
const path = require('path');
|
|
11
|
+
const { execSync } = require('child_process');
|
|
12
|
+
|
|
13
|
+
// Configuration
|
|
14
|
+
const REPO_DIR = '/Users/kyle/Desktop/nh-fe-bo/src/services/@interface/repository';
|
|
15
|
+
const OUTPUT_DIR = '/Users/kyle/Desktop/nh-fe-bo/src/pages/resources/NH/test';
|
|
16
|
+
const MCP_SERVER_PATH = '/Users/kyle/work/mcp-axboot/dist/index.js';
|
|
17
|
+
|
|
18
|
+
// Get all repository files
|
|
19
|
+
const repoFiles = fs.readdirSync(REPO_DIR)
|
|
20
|
+
.filter(f => f.endsWith('Repository.ts'))
|
|
21
|
+
.sort();
|
|
22
|
+
|
|
23
|
+
console.log(`Found ${repoFiles.length} repository files`);
|
|
24
|
+
|
|
25
|
+
// Build the MCP server first
|
|
26
|
+
console.log('Building MCP server...');
|
|
27
|
+
execSync('npm run build', { cwd: '/Users/kyle/work/mcp-axboot', stdio: 'inherit' });
|
|
28
|
+
|
|
29
|
+
// Function to generate store name from repository name
|
|
30
|
+
function getStoreName(repoName) {
|
|
31
|
+
const baseName = repoName.replace('Repository', '');
|
|
32
|
+
return `use${baseName}ListStore`;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Function to determine store type based on content
|
|
36
|
+
function determineStoreType(content) {
|
|
37
|
+
const hasList = /\b(list|find|search)\b/i.test(content);
|
|
38
|
+
const hasDetail = /\b(detail|dtlinfo|get)\b/i.test(content);
|
|
39
|
+
const hasSave = /\b(save|update|insert|create|modify|regist)\b/i.test(content);
|
|
40
|
+
const hasDelete = /\b(delete|remove)\b/i.test(content);
|
|
41
|
+
const hasExcel = /\b(excel|export|download)\b/i.test(content);
|
|
42
|
+
|
|
43
|
+
// Type 7: Master-Detail + Modal + Delete + Excel
|
|
44
|
+
if (hasList && hasDetail && hasSave && hasDelete && hasExcel) return 7;
|
|
45
|
+
// Type 2: Master-Detail + Modal + Delete
|
|
46
|
+
if (hasList && hasDetail && hasSave && hasDelete) return 2;
|
|
47
|
+
// Type 1: Basic List + Detail
|
|
48
|
+
if (hasList && hasSave) return 1;
|
|
49
|
+
// Type 5: Simple List (default)
|
|
50
|
+
return 5;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Process each repository
|
|
54
|
+
const results = [];
|
|
55
|
+
|
|
56
|
+
for (let i = 0; i < repoFiles.length; i++) {
|
|
57
|
+
const repoFile = repoFiles[i];
|
|
58
|
+
const repoName = repoFile.replace('.ts', '');
|
|
59
|
+
const inputPath = path.join(REPO_DIR, repoFile);
|
|
60
|
+
const storeName = getStoreName(repoName);
|
|
61
|
+
const outputPath = path.join(OUTPUT_DIR, `${storeName}.ts`);
|
|
62
|
+
|
|
63
|
+
try {
|
|
64
|
+
const content = fs.readFileSync(inputPath, 'utf-8');
|
|
65
|
+
const storeType = determineStoreType(content);
|
|
66
|
+
|
|
67
|
+
console.log(`${i + 1}/${repoFiles.length}: ${repoName} -> Type ${storeType}`);
|
|
68
|
+
|
|
69
|
+
// Import the generate function from the built MCP server
|
|
70
|
+
const { generateStoreFromInterface } = require('../dist/handlers/generate');
|
|
71
|
+
|
|
72
|
+
// Read the interface file
|
|
73
|
+
const interfaceContent = fs.readFileSync(inputPath, 'utf-8');
|
|
74
|
+
|
|
75
|
+
// Extract the interface name (usually XxxxInterface)
|
|
76
|
+
const interfaceMatch = interfaceContent.match(/implements\s+(\w+Interface)/);
|
|
77
|
+
const interfaceName = interfaceMatch ? interfaceMatch[1] : null;
|
|
78
|
+
|
|
79
|
+
if (!interfaceName) {
|
|
80
|
+
console.log(` Skipped: No interface found`);
|
|
81
|
+
results.push({ repository: repoName, status: 'skipped', reason: 'No interface' });
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Generate the store
|
|
86
|
+
const template = require(`../dist/templates/type${storeType + 1}`);
|
|
87
|
+
|
|
88
|
+
// Extract variable names from interface
|
|
89
|
+
const classNameMatch = interfaceContent.match(/export\s+class\s+(\w+)\s+extends/);
|
|
90
|
+
const className = classNameMatch ? classNameMatch[1] : '';
|
|
91
|
+
|
|
92
|
+
// Extract DTO types from methods
|
|
93
|
+
const responseMatches = interfaceContent.matchAll(/this\._apiWrapper<(\w+)>/g);
|
|
94
|
+
const responseTypes = [...responseMatches].map(m => m[1]);
|
|
95
|
+
const uniqueResponseTypes = [...new Set(responseTypes)];
|
|
96
|
+
|
|
97
|
+
// Determine main DTO type (usually the list response type)
|
|
98
|
+
const mainDto = uniqueResponseTypes.find(t => t.includes('Response') || t.includes('List')) || uniqueResponseTypes[0] || 'any';
|
|
99
|
+
|
|
100
|
+
// Prepare template variables
|
|
101
|
+
const templateVars = {
|
|
102
|
+
STORE_NAME: storeName,
|
|
103
|
+
DTO_NAME: mainDto.replace('Response', 'Res').replace('Request', 'Req'),
|
|
104
|
+
REPOSITORY_NAME: className,
|
|
105
|
+
INTERFACE_NAME: interfaceName,
|
|
106
|
+
ROW_KEY: 'id',
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
// Generate store code
|
|
110
|
+
const storeCode = template(templateVars);
|
|
111
|
+
|
|
112
|
+
// Write to output file
|
|
113
|
+
fs.writeFileSync(outputPath, storeCode, 'utf-8');
|
|
114
|
+
|
|
115
|
+
results.push({
|
|
116
|
+
repository: repoName,
|
|
117
|
+
storeName,
|
|
118
|
+
storeType,
|
|
119
|
+
status: 'success',
|
|
120
|
+
outputPath
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
console.log(` Generated: ${outputPath}`);
|
|
124
|
+
|
|
125
|
+
} catch (error) {
|
|
126
|
+
console.error(` Error: ${error.message}`);
|
|
127
|
+
results.push({
|
|
128
|
+
repository: repoName,
|
|
129
|
+
status: 'failed',
|
|
130
|
+
error: error.message
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Generate summary report
|
|
136
|
+
const successCount = results.filter(r => r.status === 'success').length;
|
|
137
|
+
const failCount = results.filter(r => r.status === 'failed').length;
|
|
138
|
+
|
|
139
|
+
console.log('\n' + '='.repeat(60));
|
|
140
|
+
console.log('Summary');
|
|
141
|
+
console.log('='.repeat(60));
|
|
142
|
+
console.log(`Total: ${repoFiles.length}`);
|
|
143
|
+
console.log(`Success: ${successCount}`);
|
|
144
|
+
console.log(`Failed: ${failCount}`);
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP 서버를 사용하여 NH 폴더별 Store 파일 생성
|
|
3
|
+
* 각 폴더에 맞는 Repository를 찾아서 동일 위치에 Store 생성
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const { generateStore } = require('../dist/handlers/generate.js');
|
|
7
|
+
const { analyzeInterface } = require('../dist/handlers/analyze.js');
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
|
|
11
|
+
const NH_DIR = '/Users/kyle/Desktop/nh-fe-bo/src/pages/resources/NH';
|
|
12
|
+
const REPO_DIR = '/Users/kyle/Desktop/nh-fe-bo/src/services/@interface/repository';
|
|
13
|
+
|
|
14
|
+
// 폴더 이름 → Repository 이름 매핑 규칙
|
|
15
|
+
function folderToRepoName(folderName) {
|
|
16
|
+
// kebab-case 또는 dot.case를 PascalCase로 변환
|
|
17
|
+
// 예: b2b.estimate-consulting → B2bEstimateConsulting
|
|
18
|
+
// 예: benefit.mileage-daily-summary → BenefitMileageDailySummary
|
|
19
|
+
|
|
20
|
+
// 점과 하이픈을 모두 제거하고 각 단어를 PascalCase로 변환
|
|
21
|
+
return folderName
|
|
22
|
+
.split(/[\.-]/)
|
|
23
|
+
.map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
|
|
24
|
+
.join('');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Repository 파일 존재 확인 (개선된 매칭)
|
|
28
|
+
function findRepository(folderName) {
|
|
29
|
+
// 기존 Store 파일이 있는 위치를 참고하여 매핑
|
|
30
|
+
const existingStoreMapping = getExistingStoreMapping();
|
|
31
|
+
|
|
32
|
+
if (existingStoreMapping[folderName]) {
|
|
33
|
+
const repoPath = path.join(REPO_DIR, existingStoreMapping[folderName]);
|
|
34
|
+
if (fs.existsSync(repoPath)) {
|
|
35
|
+
return repoPath;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// 기존 Store 파일 위치에서 Repository 매핑 추론
|
|
43
|
+
function getExistingStoreMapping() {
|
|
44
|
+
const mappings = {};
|
|
45
|
+
|
|
46
|
+
// 기존에 생성된 StoreNew 파일 스캔
|
|
47
|
+
const scanStores = (dir) => {
|
|
48
|
+
if (!fs.existsSync(dir)) return;
|
|
49
|
+
|
|
50
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
51
|
+
for (const entry of entries) {
|
|
52
|
+
if (entry.isDirectory()) {
|
|
53
|
+
scanStores(path.join(dir, entry.name));
|
|
54
|
+
} else if (entry.name.endsWith('StoreNew.ts')) {
|
|
55
|
+
// StoreNew 파일에서 Service 이름 추출
|
|
56
|
+
const storePath = path.join(dir, entry.name);
|
|
57
|
+
const storeContent = fs.readFileSync(storePath, 'utf-8');
|
|
58
|
+
|
|
59
|
+
// Service import에서 추출: import { ..., XxxService, ... } from "services";
|
|
60
|
+
const serviceMatches = storeContent.matchAll(/import\s*\{([^}]+)\}\s*from\s*"services"/g);
|
|
61
|
+
for (const serviceMatch of serviceMatches) {
|
|
62
|
+
const imports = serviceMatch[1];
|
|
63
|
+
// 모든 Service 찾기
|
|
64
|
+
const individualServices = imports.matchAll(/(\w+Service)/g);
|
|
65
|
+
for (const sMatch of individualServices) {
|
|
66
|
+
const serviceName = sMatch[1];
|
|
67
|
+
// "Service"로 끝나는 전체 이름인지 확인
|
|
68
|
+
if (serviceName && serviceName.endsWith('Service')) {
|
|
69
|
+
const repoName = serviceName.replace('Service', 'Repository') + '.ts';
|
|
70
|
+
const repoPath = path.join(REPO_DIR, repoName);
|
|
71
|
+
// 실제 Repository 파일이 존재하는지 확인
|
|
72
|
+
if (fs.existsSync(repoPath)) {
|
|
73
|
+
const relativePath = path.relative(NH_DIR, dir);
|
|
74
|
+
mappings[relativePath.replace(/\\/g, '/')] = repoName;
|
|
75
|
+
break; // 첫 번째 유효한 Service 사용
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
scanStores(NH_DIR);
|
|
85
|
+
|
|
86
|
+
return mappings;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Pb 접두사 처리
|
|
90
|
+
function handlePbPrefix(folderName, baseName) {
|
|
91
|
+
// 폴더가 Pb로 시작하면 Repository도 Pb로 시작하는지 확인
|
|
92
|
+
if (folderName.startsWith('pb') || folderName.startsWith('Pb')) {
|
|
93
|
+
if (!baseName.startsWith('Pb')) {
|
|
94
|
+
return `Pb${baseName}`;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return baseName;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// 메인 실행 함수
|
|
101
|
+
async function main() {
|
|
102
|
+
console.log('=== MCP Store 생성 시작 ===\n');
|
|
103
|
+
|
|
104
|
+
// 기존 StoreNew 파일에서 매핑 생성
|
|
105
|
+
const mapping = getExistingStoreMapping();
|
|
106
|
+
console.log(`자동 생성된 매핑: ${Object.keys(mapping).length}개\n`);
|
|
107
|
+
|
|
108
|
+
// 일부 매핑 출력 (디버깅)
|
|
109
|
+
console.log('샘플 매핑:');
|
|
110
|
+
Object.entries(mapping).slice(0, 5).forEach(([folder, repo]) => {
|
|
111
|
+
console.log(` ${folder} → ${repo}`);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
let successCount = 0;
|
|
115
|
+
let skipCount = 0;
|
|
116
|
+
let errorCount = 0;
|
|
117
|
+
|
|
118
|
+
for (const [folder, repoFileName] of Object.entries(mapping)) {
|
|
119
|
+
const repoPath = path.join(REPO_DIR, repoFileName);
|
|
120
|
+
|
|
121
|
+
if (!fs.existsSync(repoPath)) {
|
|
122
|
+
console.log(`[SKIP] ${folder} - Repository 파일 없음: ${repoFileName}`);
|
|
123
|
+
skipCount++;
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Repository 이름에서 baseName 추출
|
|
128
|
+
const baseName = repoFileName.replace('Repository.ts', '');
|
|
129
|
+
const outputPath = path.join(NH_DIR, folder, `use${baseName}StoreNew.ts`);
|
|
130
|
+
|
|
131
|
+
try {
|
|
132
|
+
// MCP generate 핸들러 직접 호출
|
|
133
|
+
const result = await generateStore({
|
|
134
|
+
interfacePath: repoPath,
|
|
135
|
+
outputPath: outputPath,
|
|
136
|
+
storeType: 5, // Simple List
|
|
137
|
+
storeName: `use${baseName}Store`,
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
const resultData = JSON.parse(result.content[0].text);
|
|
141
|
+
|
|
142
|
+
if (resultData.success) {
|
|
143
|
+
console.log(`[SUCCESS] ${folder} → use${baseName}StoreNew.ts`);
|
|
144
|
+
successCount++;
|
|
145
|
+
} else {
|
|
146
|
+
console.log(`[ERROR] ${folder} - ${resultData.error}`);
|
|
147
|
+
errorCount++;
|
|
148
|
+
}
|
|
149
|
+
} catch (error) {
|
|
150
|
+
console.log(`[ERROR] ${folder} - ${error.message}`);
|
|
151
|
+
errorCount++;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
console.log(`\n=== 생성 완료 ===`);
|
|
156
|
+
console.log(`성공: ${successCount}`);
|
|
157
|
+
console.log(`건너뜀: ${skipCount}`);
|
|
158
|
+
console.log(`오류: ${errorCount}`);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
main().catch(console.error);
|