@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,450 @@
1
+ /**
2
+ * StoreNew.ts 파일 생성 스크립트 (수정본)
3
+ * 리포지토리 파일을 분석하여 StoreNew.ts 파일 생성
4
+ */
5
+
6
+ const fs = require('fs');
7
+ const path = require('path');
8
+
9
+ // 경로 설정
10
+ const REPO_DIR = '/Users/kyle/Desktop/nh-fe-bo/src/services/@interface/repository';
11
+ const INTERFACE_DIR = '/Users/kyle/Desktop/nh-fe-bo/src/services/@interface';
12
+ const STORE_DIR = '/Users/kyle/Desktop/nh-fe-bo/src/pages/resources/NH';
13
+
14
+ // 기본 템플릿 (Type 6: Simple List)
15
+ const SIMPLE_LIST_TEMPLATE = `import { AXDGDataItem, AXDGPage, AXDGSortParam } from "@axboot/datagrid";
16
+ import { pageStoreActions } from "@core/stores/pageStoreActions";
17
+ import { StoreActions } from "@core/stores/types";
18
+ import { PageStoreActions } from "@core/stores/types";
19
+ import { deleteEmptyValue } from "@core/utils/object";
20
+ import { ProgramFn } from "@types";
21
+ {{IMPORTS}}
22
+ import { getTabStoreListener } from "stores";
23
+ import { create } from "zustand";
24
+ import { subscribeWithSelector } from "zustand/middleware";
25
+ import { shallow } from "zustand/shallow";
26
+
27
+ interface ListRequest extends {{LIST_REQUEST}} {}
28
+
29
+ interface DtoItem extends {{DTO_ITEM}} {}
30
+
31
+ // ========== interface MetaData ==========
32
+ interface MetaData {
33
+ programFn?: ProgramFn;
34
+ listRequestValue: ListRequest;
35
+ listColWidths: number[];
36
+ listSortParams: AXDGSortParam[];
37
+ listSelectedRowKey?: React.Key;
38
+ }
39
+
40
+ // ========== interface States ==========
41
+ interface States extends MetaData {
42
+ routePath?: string;
43
+ listSpinning: boolean;
44
+ listData: AXDGDataItem<DtoItem>[];
45
+ listPage: AXDGPage;
46
+ selectedItem?: DtoItem;
47
+ }
48
+
49
+ // ========== const createState ==========
50
+ const createState: States = {
51
+ listRequestValue: {
52
+ pageNumber: 1,
53
+ pageSize: 100,
54
+ },
55
+ listColWidths: [],
56
+ listSpinning: false,
57
+ listData: [],
58
+ listPage: {
59
+ currentPage: 0,
60
+ totalPages: 0,
61
+ },
62
+ listSortParams: [],
63
+ selectedItem: undefined,
64
+ };
65
+
66
+ // ========== interface Actions ==========
67
+ interface Actions extends PageStoreActions<States> {
68
+ setListRequestValue: (requestValue: ListRequest) => void;
69
+ setListColWidths: (colWidths: number[]) => void;
70
+ setListSortParams: (sortParams: AXDGSortParam[]) => void;
71
+ setListSpinning: (spinning: boolean) => void;
72
+ callListApi: (request?: ListRequest) => Promise<void>;
73
+ changeListPage: (currentPage: number, pageSize?: number) => Promise<void>;
74
+ setListSelectedRowKey: (key?: React.Key) => void;
75
+ setSelectedItem: (selectedItem?: DtoItem) => void;
76
+ }
77
+
78
+ // ========== const createActions ==========
79
+ const createActions: StoreActions<States & Actions, Actions> = (set, get) => ({
80
+ ...pageStoreActions(set, get, { createState }),
81
+ syncMetadata: (s = createState) => set(s),
82
+ onMountApp: async () => {},
83
+
84
+ setListRequestValue: (requestValues) => set({ listRequestValue: requestValues }),
85
+ setListColWidths: (colWidths) => set({ listColWidths: colWidths }),
86
+ setListSortParams: (sortParams) => set({ listSortParams: sortParams }),
87
+
88
+ setListSpinning: (spinning) => set({ listSpinning: spinning }),
89
+
90
+ callListApi: async (request) => {
91
+ if (get().listSpinning) return;
92
+ set({ listSpinning: true });
93
+
94
+ try {
95
+ const apiParam: ListRequest = { ...get().listRequestValue, ...request };
96
+ const response = await {{SERVICE_NAME}}.{{LIST_METHOD_NAME}}(deleteEmptyValue(apiParam));
97
+
98
+ set({
99
+ listRequestValue: apiParam,
100
+ listData: response.ds.map((values) => ({ values })),
101
+ listPage: {
102
+ currentPage: response.page.pageNumber ?? 1,
103
+ pageSize: response.page.pageSize ?? 0,
104
+ totalPages: response.page.pageCount ?? 0,
105
+ totalElements: response.page?.totalCount,
106
+ },
107
+ });
108
+ } finally {
109
+ set({ listSpinning: false });
110
+ }
111
+ },
112
+
113
+ changeListPage: async (pageNumber, pageSize) => {
114
+ await get().callListApi({ pageNumber, pageSize });
115
+ },
116
+
117
+ setListSelectedRowKey: (key) => set({ listSelectedRowKey: key }),
118
+
119
+ setSelectedItem: (selectedItem) => set({ selectedItem }),
120
+ });
121
+
122
+ // ========== export ==========
123
+ export interface {{STORE_INTERFACE}} extends States, Actions, PageStoreActions<States> {}
124
+
125
+ export const {{STORE_NAME}} = create(
126
+ subscribeWithSelector<{{STORE_INTERFACE}}>((set, get) => ({
127
+ ...createState,
128
+ ...createActions(set, get),
129
+ })),
130
+ );
131
+
132
+ // ========== Store.subscribe ==========
133
+ {{STORE_NAME}}.subscribe(
134
+ (s): Record<keyof MetaData, any> => ({
135
+ programFn: s.programFn,
136
+ listRequestValue: s.listRequestValue,
137
+ listColWidths: s.listColWidths,
138
+ listSortParams: s.listSortParams,
139
+ listSelectedRowKey: s.listSelectedRowKey
140
+ }),
141
+ getTabStoreListener<MetaData>(createState.routePath),
142
+ { equalityFn: shallow },
143
+ );
144
+ `;
145
+
146
+ /**
147
+ * 리포지토리 파일에서 정보 추출
148
+ */
149
+ function analyzeRepository(filePath) {
150
+ const content = fs.readFileSync(filePath, 'utf-8');
151
+
152
+ // 클래스 이름 추출
153
+ const classNameMatch = content.match(/export class (\w+)Repository/);
154
+ const className = classNameMatch ? classNameMatch[1] : '';
155
+
156
+ // Service 이름 추출 (ClassName에서 Repository 제거 + Service)
157
+ const serviceName = className.replace('Repository', '') + 'Service';
158
+
159
+ // 인터페이스 추출
160
+ const interfaceMatch = content.match(/extends (\w+)Interface/);
161
+ const interfaceName = interfaceMatch ? interfaceMatch[1] : className;
162
+
163
+ // 메서드 추출 (여러 줄에 걸친 패턴 처리)
164
+ const methodPattern = /async (\w+)\(([^)]*)\)[\s\S]*?this\._apiWrapper<([^>]+)>\s*\(\s*"([^"]*)"\s*,/g;
165
+ const methods = [];
166
+ let match;
167
+
168
+ while ((match = methodPattern.exec(content)) !== null) {
169
+ methods.push({
170
+ name: match[1],
171
+ params: match[2],
172
+ returnType: match[3],
173
+ httpMethod: match[4],
174
+ endpoint: match[5],
175
+ });
176
+ }
177
+
178
+ // Request/Response 타입 추출 (imports에서)
179
+ const imports = [];
180
+ const importPattern = /import \{([^}]+)\} from "\.\.\/interface"/g;
181
+ while ((match = importPattern.exec(content)) !== null) {
182
+ imports.push(match[1]);
183
+ }
184
+
185
+ return {
186
+ className,
187
+ serviceName,
188
+ interfaceName,
189
+ methods,
190
+ imports,
191
+ };
192
+ }
193
+
194
+ /**
195
+ * 인터페이스 파일에서 타입 정보 추출
196
+ */
197
+ function analyzeInterfaceFiles() {
198
+ const interfaceTypes = {};
199
+
200
+ // interface 디렉토리의 모든 파일 스캔
201
+ const interfaceFiles = fs.readdirSync(INTERFACE_DIR)
202
+ .filter(file => file.endsWith('.ts') && file !== 'index.ts');
203
+
204
+ interfaceFiles.forEach(file => {
205
+ const content = fs.readFileSync(path.join(INTERFACE_DIR, file), 'utf-8');
206
+
207
+ // Request 타입 추출
208
+ const requestPattern = /export (interface|type) (\w+Request)/g;
209
+ let match;
210
+ while ((match = requestPattern.exec(content)) !== null) {
211
+ interfaceTypes[match[2]] = match[2];
212
+ }
213
+
214
+ // Response 타입 추출
215
+ const responsePattern = /export (interface|type) (\w+Response)/g;
216
+ while ((match = responsePattern.exec(content)) !== null) {
217
+ interfaceTypes[match[2]] = match[2];
218
+ }
219
+
220
+ // Res 타입 추출 (DTO)
221
+ const resPattern = /export (interface|type) (\w+Res)/g;
222
+ while ((match = resPattern.exec(content)) !== null) {
223
+ interfaceTypes[match[2]] = match[2];
224
+ }
225
+ });
226
+
227
+ return interfaceTypes;
228
+ }
229
+
230
+ /**
231
+ * 기존 Store 파일 찾기
232
+ */
233
+ function findExistingStore(baseName) {
234
+ // kebab-case 변환
235
+ const kebabName = baseName
236
+ .replace(/([a-z])([A-Z])/g, '$1-$2')
237
+ .toLowerCase();
238
+
239
+ // 가능한 경로들
240
+ const possiblePaths = [
241
+ path.join(STORE_DIR, `${kebabName}.use${baseName}Store.ts`),
242
+ path.join(STORE_DIR, `use${baseName}Store.ts`),
243
+ ];
244
+
245
+ for (const p of possiblePaths) {
246
+ if (fs.existsSync(p)) {
247
+ return fs.readFileSync(p, 'utf-8');
248
+ }
249
+ }
250
+
251
+ // 하위 디렉토리 검색
252
+ const dirs = fs.readdirSync(STORE_DIR, { withFileTypes: true })
253
+ .filter(d => d.isDirectory())
254
+ .map(d => d.name);
255
+
256
+ for (const dir of dirs) {
257
+ const filePath = path.join(STORE_DIR, dir, `use${baseName}Store.ts`);
258
+ if (fs.existsSync(filePath)) {
259
+ return fs.readFileSync(filePath, 'utf-8');
260
+ }
261
+ }
262
+
263
+ return null;
264
+ }
265
+
266
+ /**
267
+ * 템플릿 변수 생성
268
+ */
269
+ function createTemplateVariables(repoInfo, interfaceTypes) {
270
+ const className = repoInfo.className;
271
+ const baseName = className.replace('Repository', '');
272
+
273
+ // LIST 메서드 찾기
274
+ const listMethod = repoInfo.methods.find(m =>
275
+ m.name.toLowerCase().includes('list') &&
276
+ !m.name.toLowerCase().includes('excel')
277
+ );
278
+
279
+ // Request 타입 결정
280
+ let listRequestType = 'any';
281
+ let listResponseType = 'any';
282
+ let dtoItem = `${baseName}Res`;
283
+
284
+ if (listMethod) {
285
+ // 메서드 반환 타입에서 Request/Response 추출
286
+ const returnType = listMethod.returnType;
287
+ listResponseType = returnType;
288
+
289
+ // Request 타입 추정
290
+ if (returnType.endsWith('Response')) {
291
+ listRequestType = returnType.replace('Response', 'Request');
292
+ } else {
293
+ listRequestType = `Post${baseName}${listMethod.name.charAt(0).toUpperCase() + listMethod.name.slice(1)}Request`;
294
+ }
295
+
296
+ // DTO 타입 추정
297
+ if (returnType.endsWith('Response')) {
298
+ dtoItem = returnType.replace('Response', 'Res');
299
+ } else if (returnType.endsWith('Res')) {
300
+ dtoItem = returnType;
301
+ } else {
302
+ dtoItem = `${baseName}Res`;
303
+ }
304
+ }
305
+
306
+ // imports 생성
307
+ const importsSet = new Set();
308
+ repoInfo.imports.forEach(imp => {
309
+ imp.split(',').forEach(item => {
310
+ const trimmed = item.trim();
311
+ if (trimmed) {
312
+ importsSet.add(trimmed);
313
+ }
314
+ });
315
+ });
316
+
317
+ const imports = `import { ${Array.from(importsSet).join(', ')} } from "services";`;
318
+
319
+ // Store 이름 생성
320
+ const storeName = `use${baseName}Store`;
321
+ const storeInterface = `${baseName}Store`;
322
+
323
+ return {
324
+ STORE_NAME: storeName,
325
+ STORE_NAME_PASCAL: baseName,
326
+ STORE_INTERFACE: storeInterface,
327
+ SERVICE_NAME: repoInfo.serviceName,
328
+ LIST_METHOD_NAME: listMethod?.name || 'getList',
329
+ LIST_REQUEST: listRequestType,
330
+ LIST_RESPONSE: listResponseType,
331
+ DTO_ITEM: dtoItem,
332
+ IMPORTS: imports,
333
+ };
334
+ }
335
+
336
+ /**
337
+ * Store 파일 경로 결정
338
+ */
339
+ function determineStorePath(baseName) {
340
+ const kebabName = baseName
341
+ .replace(/([a-z])([A-Z])/g, '$1-$2')
342
+ .toLowerCase();
343
+
344
+ // 하위 디렉토리 검색
345
+ const dirs = fs.readdirSync(STORE_DIR, { withFileTypes: true })
346
+ .filter(d => d.isDirectory())
347
+ .map(d => d.name);
348
+
349
+ // 일치하는 디렉토리 찾기
350
+ const matchingDir = dirs.find(dir => {
351
+ const dirLower = dir.toLowerCase().replace(/-/g, '');
352
+ const nameLower = baseName.toLowerCase();
353
+ return dirLower.includes(nameLower) || nameLower.includes(dirLower.replace(/[^a-z]/g, ''));
354
+ });
355
+
356
+ if (matchingDir) {
357
+ return path.join(STORE_DIR, matchingDir, `use${baseName}StoreNew.ts`);
358
+ }
359
+
360
+ // 기본 경로
361
+ return path.join(STORE_DIR, `use${baseName}StoreNew.ts`);
362
+ }
363
+
364
+ /**
365
+ * 템플릿 렌더링
366
+ */
367
+ function renderTemplate(template, variables) {
368
+ let result = template;
369
+
370
+ // 변수 치환
371
+ Object.keys(variables).forEach(key => {
372
+ const regex = new RegExp(`\\{\\{${key}\\}\\}`, 'g');
373
+ result = result.replace(regex, variables[key]);
374
+ });
375
+
376
+ return result;
377
+ }
378
+
379
+ /**
380
+ * 메인 실행 함수
381
+ */
382
+ function main() {
383
+ console.log('=== StoreNew.ts 파일 생성 시작 v2 ===\n');
384
+
385
+ // 인터페이스 타입 분석
386
+ const interfaceTypes = analyzeInterfaceFiles();
387
+ console.log(`인터페이스 타입 ${Object.keys(interfaceTypes).length}개 발견\n`);
388
+
389
+ // 리포지토리 파일 목록 가져오기
390
+ const repoFiles = fs.readdirSync(REPO_DIR)
391
+ .filter(file => file.endsWith('Repository.ts') && file !== 'APIRepository.ts');
392
+
393
+ console.log(`리포지토리 파일 ${repoFiles.length}개 발견\n`);
394
+
395
+ let successCount = 0;
396
+ let skipCount = 0;
397
+ let errorCount = 0;
398
+
399
+ repoFiles.forEach((file, index) => {
400
+ try {
401
+ const repoPath = path.join(REPO_DIR, file);
402
+ const repoInfo = analyzeRepository(repoPath);
403
+
404
+ if (!repoInfo.className || repoInfo.methods.length === 0) {
405
+ console.log(`[${index + 1}/${repoFiles.length}] SKIP: ${file} - 메서드를 찾을 수 없음`);
406
+ skipCount++;
407
+ return;
408
+ }
409
+
410
+ const baseName = repoInfo.className.replace('Repository', '');
411
+
412
+ // 템플릿 변수 생성
413
+ const variables = createTemplateVariables(repoInfo, interfaceTypes);
414
+
415
+ // 템플릿 렌더링
416
+ const rendered = renderTemplate(SIMPLE_LIST_TEMPLATE, variables);
417
+
418
+ // 출력 경로 결정
419
+ const outputPath = determineStorePath(baseName);
420
+
421
+ // 디렉토리 생성
422
+ const outputDir = path.dirname(outputPath);
423
+ if (!fs.existsSync(outputDir)) {
424
+ fs.mkdirSync(outputDir, { recursive: true });
425
+ }
426
+
427
+ // 파일 쓰기
428
+ fs.writeFileSync(outputPath, rendered);
429
+
430
+ console.log(`[${index + 1}/${repoFiles.length}] SUCCESS: ${baseName}StoreNew.ts 생성`);
431
+ successCount++;
432
+
433
+ } catch (error) {
434
+ console.error(`[${index + 1}/${repoFiles.length}] ERROR: ${file} - ${error.message}`);
435
+ errorCount++;
436
+ }
437
+ });
438
+
439
+ console.log(`\n=== 생성 완료 ===`);
440
+ console.log(`성공: ${successCount}`);
441
+ console.log(`건너뜀: ${skipCount}`);
442
+ console.log(`오류: ${errorCount}`);
443
+ }
444
+
445
+ // 실행
446
+ if (require.main === module) {
447
+ main();
448
+ }
449
+
450
+ module.exports = { analyzeRepository, createTemplateVariables, renderTemplate };