@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,250 @@
|
|
|
1
|
+
import { promises as fs } from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import { spawn } from 'child_process';
|
|
4
|
+
import { analyzeInterface } from './analyze.js';
|
|
5
|
+
import { getTemplate } from '../templates/index.js';
|
|
6
|
+
import { buildTemplateVariables } from './generate.js';
|
|
7
|
+
import {
|
|
8
|
+
extractFeaturesFromRequirements,
|
|
9
|
+
matchTypes,
|
|
10
|
+
findBestMatch,
|
|
11
|
+
} from './analyze-requirements.js';
|
|
12
|
+
import { generateMultiStores, detectMultiListPattern } from './generate-multi-stores.js';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* 요구사항 기반 Store 생성 (단일/다중 자동 판별)
|
|
16
|
+
*/
|
|
17
|
+
export async function generateStoreFromRequirements(args: {
|
|
18
|
+
interfacePath: string;
|
|
19
|
+
outputPath: string;
|
|
20
|
+
requirements: string;
|
|
21
|
+
}): Promise<{
|
|
22
|
+
content: Array<{ type: string; text: string }>;
|
|
23
|
+
}> {
|
|
24
|
+
const { interfacePath, outputPath, requirements } = args;
|
|
25
|
+
|
|
26
|
+
// outputPath에서 store 이름 추출 (예: /path/to/useOrderStore.ts → useOrderStore)
|
|
27
|
+
const storeName = path.basename(outputPath, '.ts');
|
|
28
|
+
|
|
29
|
+
try {
|
|
30
|
+
// 1. 다중 리스트 패턴 우선 감지
|
|
31
|
+
const multiPattern = detectMultiListPattern(requirements);
|
|
32
|
+
if (multiPattern && multiPattern.isMultiList) {
|
|
33
|
+
// 다중 리스트인 경우 generateMultiStores 호출 (사용자가 제시한 storeName 사용)
|
|
34
|
+
return await generateMultiStores({
|
|
35
|
+
interfacePath,
|
|
36
|
+
outputPath,
|
|
37
|
+
requirements,
|
|
38
|
+
baseStoreName: storeName,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// 2. 단일 리스트인 경우 기존 로직
|
|
43
|
+
const analyzeResult = await analyzeInterface({ interfacePath });
|
|
44
|
+
const analyzeData = JSON.parse(analyzeResult.content[0].text);
|
|
45
|
+
|
|
46
|
+
if (!analyzeData.success) {
|
|
47
|
+
return {
|
|
48
|
+
content: [
|
|
49
|
+
{
|
|
50
|
+
type: 'text',
|
|
51
|
+
text: JSON.stringify({
|
|
52
|
+
success: false,
|
|
53
|
+
error: analyzeData.error || '인터페이스 분석 실패',
|
|
54
|
+
}),
|
|
55
|
+
},
|
|
56
|
+
],
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// 2.5. 유효성 검사: 리스트 메서드가 없는 경우 스토어 생성 건너뜀
|
|
61
|
+
const listMethods = analyzeData.methods?.filter((m: any) => m.isListMethod) || [];
|
|
62
|
+
if (listMethods.length === 0) {
|
|
63
|
+
return {
|
|
64
|
+
content: [
|
|
65
|
+
{
|
|
66
|
+
type: 'text',
|
|
67
|
+
text: JSON.stringify({
|
|
68
|
+
success: false,
|
|
69
|
+
error: `리스트 메서드를 찾을 수 없습니다. Repository에 목록 조회 메서드가 필요합니다. (${analyzeData.className})`,
|
|
70
|
+
skip: true,
|
|
71
|
+
}),
|
|
72
|
+
},
|
|
73
|
+
],
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// 3. 요구사항 분석
|
|
78
|
+
const extractedFeatures = extractFeaturesFromRequirements(requirements);
|
|
79
|
+
const matchedTypes = matchTypes(extractedFeatures);
|
|
80
|
+
const recommendedType = findBestMatch(matchedTypes);
|
|
81
|
+
|
|
82
|
+
if (!recommendedType) {
|
|
83
|
+
return {
|
|
84
|
+
content: [
|
|
85
|
+
{
|
|
86
|
+
type: 'text',
|
|
87
|
+
text: JSON.stringify({
|
|
88
|
+
success: false,
|
|
89
|
+
error: '요구사항에 맞는 Store 타입을 찾을 수 없습니다',
|
|
90
|
+
extractedFeatures,
|
|
91
|
+
matchedTypes,
|
|
92
|
+
}),
|
|
93
|
+
},
|
|
94
|
+
],
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// 4. 템플릿 로드
|
|
99
|
+
const template = getTemplate(recommendedType.type);
|
|
100
|
+
if (!template) {
|
|
101
|
+
return {
|
|
102
|
+
content: [
|
|
103
|
+
{
|
|
104
|
+
type: 'text',
|
|
105
|
+
text: JSON.stringify({
|
|
106
|
+
success: false,
|
|
107
|
+
error: `지원하지 않는 Store 타입입니다: ${recommendedType.type}`,
|
|
108
|
+
}),
|
|
109
|
+
},
|
|
110
|
+
],
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// 5. 템플릿 변수 빌드 (사용자가 제시한 storeName 사용)
|
|
115
|
+
const variables = buildTemplateVariables(analyzeData, recommendedType.type, storeName) as unknown as Record<string, string>;
|
|
116
|
+
|
|
117
|
+
// 6. 템플릿 적용
|
|
118
|
+
const storeCode = applyTemplate(template, variables);
|
|
119
|
+
|
|
120
|
+
// 7. 파일 생성
|
|
121
|
+
const outputDir = path.dirname(outputPath);
|
|
122
|
+
await fs.mkdir(outputDir, { recursive: true });
|
|
123
|
+
await fs.writeFile(outputPath, storeCode, 'utf-8');
|
|
124
|
+
|
|
125
|
+
// 8. Lint 및 Prettier 실행
|
|
126
|
+
runLintAndPrettier(outputPath).catch((err) => {
|
|
127
|
+
console.warn(`Lint/Prettier 실행 중 경고: ${err}`);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
return {
|
|
131
|
+
content: [
|
|
132
|
+
{
|
|
133
|
+
type: 'text',
|
|
134
|
+
text: JSON.stringify(
|
|
135
|
+
{
|
|
136
|
+
success: true,
|
|
137
|
+
message: 'Store 파일 생성 완료',
|
|
138
|
+
outputPath,
|
|
139
|
+
requirements,
|
|
140
|
+
extractedFeatures,
|
|
141
|
+
recommendedType: {
|
|
142
|
+
type: recommendedType.type,
|
|
143
|
+
name: recommendedType.name,
|
|
144
|
+
description: recommendedType.description,
|
|
145
|
+
matchScore: recommendedType.matchScore,
|
|
146
|
+
matchedFeatures: recommendedType.matchedFeatures,
|
|
147
|
+
missingFeatures: recommendedType.missingFeatures,
|
|
148
|
+
},
|
|
149
|
+
analysis: {
|
|
150
|
+
className: analyzeData.className,
|
|
151
|
+
serviceName: analyzeData.serviceName,
|
|
152
|
+
methodCount: analyzeData.methods.length,
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
null,
|
|
156
|
+
2
|
|
157
|
+
),
|
|
158
|
+
},
|
|
159
|
+
],
|
|
160
|
+
};
|
|
161
|
+
} catch (error) {
|
|
162
|
+
return {
|
|
163
|
+
content: [
|
|
164
|
+
{
|
|
165
|
+
type: 'text',
|
|
166
|
+
text: JSON.stringify({
|
|
167
|
+
success: false,
|
|
168
|
+
error: error instanceof Error ? error.message : String(error),
|
|
169
|
+
}),
|
|
170
|
+
},
|
|
171
|
+
],
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* 템플릿 적용 - Mustache.js 사용
|
|
178
|
+
*/
|
|
179
|
+
function applyTemplate(template: string, variables: Record<string, any>): string {
|
|
180
|
+
const Mustache = require('mustache');
|
|
181
|
+
|
|
182
|
+
// TypeScript 코드 생성이므로 HTML 이스케이프 비활성화
|
|
183
|
+
// 기본 escape 함수를 덮어써서 원본 그대로 반환
|
|
184
|
+
const originalEscape = Mustache.escape;
|
|
185
|
+
Mustache.escape = (text: any) => String(text);
|
|
186
|
+
|
|
187
|
+
try {
|
|
188
|
+
// Mustache.js를 사용하여 템플릿 렌더링
|
|
189
|
+
// {{#KEY}}...{{/KEY}}: 조건부 블록 (truthy일 때 내용 포함)
|
|
190
|
+
// {{^KEY}}...{{/KEY}}: 역조건부 블록 (falsy일 때 내용 포함)
|
|
191
|
+
// {{KEY}}: 변수 치환
|
|
192
|
+
let result = Mustache.render(template, variables);
|
|
193
|
+
|
|
194
|
+
// 후처리: 빈 줄 제거만 수행 (정규식 제거로 인한 함수 시그니처 손실 방지)
|
|
195
|
+
result = result
|
|
196
|
+
// 빈 줄 제거 (연속된 2개 이상의 줄바꿈을 하나로 줄임)
|
|
197
|
+
.replace(/\n\s*\n\s*\n/g, '\n\n')
|
|
198
|
+
// 빈 줄 정리
|
|
199
|
+
.replace(/\n\s*\n/g, '\n');
|
|
200
|
+
|
|
201
|
+
return result;
|
|
202
|
+
} finally {
|
|
203
|
+
// 원래 escape 함수 복원
|
|
204
|
+
Mustache.escape = originalEscape;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Lint 및 Prettier 실행
|
|
210
|
+
*/
|
|
211
|
+
async function runLintAndPrettier(filePath: string): Promise<void> {
|
|
212
|
+
const fileDir = path.dirname(filePath);
|
|
213
|
+
|
|
214
|
+
// Prettier 실행
|
|
215
|
+
await runCommand('npx', ['prettier', '--write', filePath], fileDir);
|
|
216
|
+
|
|
217
|
+
// ESLint 실행
|
|
218
|
+
await runCommand('npx', ['eslint', '--fix', filePath], fileDir);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* 명령 실행 헬퍼
|
|
223
|
+
*/
|
|
224
|
+
function runCommand(command: string, args: string[], cwd: string): Promise<void> {
|
|
225
|
+
return new Promise((resolve, reject) => {
|
|
226
|
+
const proc = spawn(command, args, {
|
|
227
|
+
cwd,
|
|
228
|
+
stdio: 'pipe',
|
|
229
|
+
shell: true,
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
let stderr = '';
|
|
233
|
+
|
|
234
|
+
proc.stderr?.on('data', (data) => {
|
|
235
|
+
stderr += data.toString();
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
proc.on('close', (code) => {
|
|
239
|
+
if (code !== 0) {
|
|
240
|
+
reject(new Error(`Command failed with code ${code}: ${stderr}`));
|
|
241
|
+
} else {
|
|
242
|
+
resolve();
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
proc.on('error', (err) => {
|
|
247
|
+
reject(err);
|
|
248
|
+
});
|
|
249
|
+
});
|
|
250
|
+
}
|