@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,412 @@
1
+ /**
2
+ * StoreNew.ts 파일 생성 스크립트 v3
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 이름 추출
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 methods = [];
165
+
166
+ // 각 메서드를 개별적으로 추출
167
+ const methodBlocks = content.split(/async\s+/).slice(1); // 첫 번째는 빈 문자열
168
+
169
+ methodBlocks.forEach(block => {
170
+ const methodNameMatch = block.match(/(\w+)\s*\(([^)]*)\)/);
171
+ if (!methodNameMatch) return;
172
+
173
+ const methodName = methodNameMatch[1];
174
+
175
+ // _apiWrapper 호출에서 타입 추출
176
+ const apiWrapperMatch = block.match(/this\._apiWrapper<([^>]+)>/);
177
+ if (!apiWrapperMatch) return;
178
+
179
+ const returnType = apiWrapperMatch[1];
180
+
181
+ // 엔드포인트 추출
182
+ const endpointMatch = block.match(/`([^`]+)`/);
183
+ const endpoint = endpointMatch ? endpointMatch[1] : '';
184
+
185
+ // 파라미터 타입 추출
186
+ const paramsMatch = block.match(/params:\s*(\w+Request)/);
187
+ const requestType = paramsMatch ? paramsMatch[1] : null;
188
+
189
+ methods.push({
190
+ name: methodName,
191
+ returnType,
192
+ requestType,
193
+ endpoint,
194
+ });
195
+ });
196
+
197
+ // imports 추출
198
+ const imports = [];
199
+ const importMatch = content.match(/import\s*\{([^}]+)\}\s*from\s*"[\.\.\/]+interface"/);
200
+ if (importMatch) {
201
+ importMatch[1].split(',').forEach(item => {
202
+ const trimmed = item.trim();
203
+ if (trimmed) imports.push(trimmed);
204
+ });
205
+ }
206
+
207
+ return {
208
+ className,
209
+ serviceName,
210
+ interfaceName,
211
+ methods,
212
+ imports,
213
+ };
214
+ }
215
+
216
+ /**
217
+ * 기존 Store 파일 찾기
218
+ */
219
+ function findExistingStore(baseName) {
220
+ const kebabName = baseName
221
+ .replace(/([a-z])([A-Z])/g, '$1-$2')
222
+ .toLowerCase();
223
+
224
+ const possiblePaths = [
225
+ path.join(STORE_DIR, `${kebabName}.use${baseName}Store.ts`),
226
+ path.join(STORE_DIR, `use${baseName}Store.ts`),
227
+ ];
228
+
229
+ for (const p of possiblePaths) {
230
+ if (fs.existsSync(p)) {
231
+ return fs.readFileSync(p, 'utf-8');
232
+ }
233
+ }
234
+
235
+ const dirs = fs.readdirSync(STORE_DIR, { withFileTypes: true })
236
+ .filter(d => d.isDirectory())
237
+ .map(d => d.name);
238
+
239
+ for (const dir of dirs) {
240
+ const filePath = path.join(STORE_DIR, dir, `use${baseName}Store.ts`);
241
+ if (fs.existsSync(filePath)) {
242
+ return fs.readFileSync(filePath, 'utf-8');
243
+ }
244
+ }
245
+
246
+ return null;
247
+ }
248
+
249
+ /**
250
+ * 템플릿 변수 생성
251
+ */
252
+ function createTemplateVariables(repoInfo) {
253
+ const className = repoInfo.className;
254
+ const baseName = className.replace('Repository', '');
255
+
256
+ // LIST 메서드 찾기 (list 포함, excel 제외)
257
+ const listMethod = repoInfo.methods.find(m =>
258
+ m.name.toLowerCase().includes('list') &&
259
+ !m.name.toLowerCase().includes('excel')
260
+ );
261
+
262
+ // Request 타입 결정
263
+ let listRequestType = 'Partial<Record<string, any>>';
264
+ let listResponseType = 'any';
265
+ let dtoItem = 'Record<string, any>';
266
+
267
+ if (listMethod) {
268
+ listResponseType = listMethod.returnType;
269
+
270
+ if (listMethod.requestType) {
271
+ listRequestType = listMethod.requestType;
272
+ } else if (listResponseType.endsWith('Response')) {
273
+ listRequestType = listResponseType.replace('Response', 'Request');
274
+ }
275
+
276
+ // DTO 타입 추정
277
+ if (listResponseType.endsWith('Response')) {
278
+ dtoItem = listResponseType.replace('Response', 'Res');
279
+ } else if (listResponseType.endsWith('Res')) {
280
+ dtoItem = listResponseType;
281
+ }
282
+ }
283
+
284
+ // imports 생성
285
+ const importsLine = repoInfo.imports.length > 0
286
+ ? `import { ${repoInfo.imports.join(', ')} } from "services";`
287
+ : '';
288
+
289
+ // Store 이름 생성
290
+ const storeName = `use${baseName}Store`;
291
+ const storeInterface = `${baseName}Store`;
292
+
293
+ return {
294
+ STORE_NAME: storeName,
295
+ STORE_NAME_PASCAL: baseName,
296
+ STORE_INTERFACE: storeInterface,
297
+ SERVICE_NAME: repoInfo.serviceName,
298
+ LIST_METHOD_NAME: listMethod?.name || 'getList',
299
+ LIST_REQUEST: listRequestType,
300
+ LIST_RESPONSE: listResponseType,
301
+ DTO_ITEM: dtoItem,
302
+ IMPORTS: importsLine,
303
+ };
304
+ }
305
+
306
+ /**
307
+ * Store 파일 경로 결정
308
+ */
309
+ function determineStorePath(baseName) {
310
+ const kebabName = baseName
311
+ .replace(/([a-z])([A-Z])/g, '$1-$2')
312
+ .toLowerCase();
313
+
314
+ const dirs = fs.readdirSync(STORE_DIR, { withFileTypes: true })
315
+ .filter(d => d.isDirectory())
316
+ .map(d => d.name);
317
+
318
+ // 일치하는 디렉토리 찾기
319
+ const matchingDir = dirs.find(dir => {
320
+ const dirLower = dir.toLowerCase().replace(/-/g, '');
321
+ const nameLower = baseName.toLowerCase();
322
+ return dirLower.includes(nameLower) || nameLower.includes(dirLower.replace(/[^a-z]/g, ''));
323
+ });
324
+
325
+ if (matchingDir) {
326
+ return path.join(STORE_DIR, matchingDir, `use${baseName}StoreNew.ts`);
327
+ }
328
+
329
+ return path.join(STORE_DIR, `use${baseName}StoreNew.ts`);
330
+ }
331
+
332
+ /**
333
+ * 템플릿 렌더링
334
+ */
335
+ function renderTemplate(template, variables) {
336
+ let result = template;
337
+
338
+ Object.keys(variables).forEach(key => {
339
+ const regex = new RegExp(`\\{\\{${key}\\}\\}`, 'g');
340
+ result = result.replace(regex, variables[key]);
341
+ });
342
+
343
+ return result;
344
+ }
345
+
346
+ /**
347
+ * 메인 실행 함수
348
+ */
349
+ function main() {
350
+ console.log('=== StoreNew.ts 파일 생성 시작 v3 ===\n');
351
+
352
+ const repoFiles = fs.readdirSync(REPO_DIR)
353
+ .filter(file => file.endsWith('Repository.ts') && file !== 'APIRepository.ts');
354
+
355
+ console.log(`리포지토리 파일 ${repoFiles.length}개 발견\n`);
356
+
357
+ let successCount = 0;
358
+ let skipCount = 0;
359
+ let errorCount = 0;
360
+
361
+ repoFiles.forEach((file, index) => {
362
+ try {
363
+ const repoPath = path.join(REPO_DIR, file);
364
+ const repoInfo = analyzeRepository(repoPath);
365
+
366
+ if (!repoInfo.className || repoInfo.methods.length === 0) {
367
+ console.log(`[${index + 1}/${repoFiles.length}] SKIP: ${file} - 메서드를 찾을 수 없음`);
368
+ skipCount++;
369
+ return;
370
+ }
371
+
372
+ const baseName = repoInfo.className.replace('Repository', '');
373
+
374
+ // 템플릿 변수 생성
375
+ const variables = createTemplateVariables(repoInfo);
376
+
377
+ // 템플릿 렌더링
378
+ const rendered = renderTemplate(SIMPLE_LIST_TEMPLATE, variables);
379
+
380
+ // 출력 경로 결정
381
+ const outputPath = determineStorePath(baseName);
382
+
383
+ // 디렉토리 생성
384
+ const outputDir = path.dirname(outputPath);
385
+ if (!fs.existsSync(outputDir)) {
386
+ fs.mkdirSync(outputDir, { recursive: true });
387
+ }
388
+
389
+ // 파일 쓰기
390
+ fs.writeFileSync(outputPath, rendered);
391
+
392
+ console.log(`[${index + 1}/${repoFiles.length}] SUCCESS: ${baseName}StoreNew.ts 생성 (${variables.LIST_METHOD_NAME})`);
393
+ successCount++;
394
+
395
+ } catch (error) {
396
+ console.error(`[${index + 1}/${repoFiles.length}] ERROR: ${file} - ${error.message}`);
397
+ errorCount++;
398
+ }
399
+ });
400
+
401
+ console.log(`\n=== 생성 완료 ===`);
402
+ console.log(`성공: ${successCount}`);
403
+ console.log(`건너뜀: ${skipCount}`);
404
+ console.log(`오류: ${errorCount}`);
405
+ }
406
+
407
+ // 실행
408
+ if (require.main === module) {
409
+ main();
410
+ }
411
+
412
+ module.exports = { analyzeRepository, createTemplateVariables, renderTemplate };