activo 0.4.4 → 0.5.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 (161) hide show
  1. package/README.md +203 -1
  2. package/data/2026-03-04_20-54.json +181 -0
  3. package/data/2026-03-04_20-56.json +181 -0
  4. package/data/apex-rulesets/egov.yaml +469 -0
  5. package/data/apex-rulesets/modernize.yaml +687 -0
  6. package/data/apex-rulesets/quality.yaml +1677 -0
  7. package/data/apex-rulesets/rule-schema.yaml +587 -0
  8. package/data/apex-rulesets/secure.yaml +1688 -0
  9. package/data/apex-rulesets/spring.yaml +455 -0
  10. package/data/apex-rulesets/sql-format.yaml +99 -0
  11. package/data/apex-rulesets/sql-oracle.yaml +281 -0
  12. package/data/apex-rulesets/sql.yaml +1660 -0
  13. package/dist/cli/headless.d.ts.map +1 -1
  14. package/dist/cli/headless.js +32 -10
  15. package/dist/cli/headless.js.map +1 -1
  16. package/dist/cli/index.js +31 -3
  17. package/dist/cli/index.js.map +1 -1
  18. package/dist/core/agent.d.ts +3 -3
  19. package/dist/core/agent.d.ts.map +1 -1
  20. package/dist/core/agent.js +203 -384
  21. package/dist/core/agent.js.map +1 -1
  22. package/dist/core/commands.d.ts +2 -1
  23. package/dist/core/commands.d.ts.map +1 -1
  24. package/dist/core/commands.js +61 -9
  25. package/dist/core/commands.js.map +1 -1
  26. package/dist/core/config.d.ts +14 -0
  27. package/dist/core/config.d.ts.map +1 -1
  28. package/dist/core/config.js +41 -4
  29. package/dist/core/config.js.map +1 -1
  30. package/dist/core/conversation.d.ts +2 -2
  31. package/dist/core/conversation.d.ts.map +1 -1
  32. package/dist/core/conversation.js.map +1 -1
  33. package/dist/core/intentRouter.d.ts +43 -0
  34. package/dist/core/intentRouter.d.ts.map +1 -0
  35. package/dist/core/intentRouter.js +804 -0
  36. package/dist/core/intentRouter.js.map +1 -0
  37. package/dist/core/llm/anthropic.d.ts +24 -0
  38. package/dist/core/llm/anthropic.d.ts.map +1 -0
  39. package/dist/core/llm/anthropic.js +226 -0
  40. package/dist/core/llm/anthropic.js.map +1 -0
  41. package/dist/core/llm/ollama.d.ts +5 -14
  42. package/dist/core/llm/ollama.d.ts.map +1 -1
  43. package/dist/core/llm/ollama.js +3 -0
  44. package/dist/core/llm/ollama.js.map +1 -1
  45. package/dist/core/llm/types.d.ts +22 -0
  46. package/dist/core/llm/types.d.ts.map +1 -0
  47. package/dist/core/llm/types.js +2 -0
  48. package/dist/core/llm/types.js.map +1 -0
  49. package/dist/core/mcp/client.d.ts +6 -0
  50. package/dist/core/mcp/client.d.ts.map +1 -1
  51. package/dist/core/mcp/client.js +16 -0
  52. package/dist/core/mcp/client.js.map +1 -1
  53. package/dist/core/mcp/init.d.ts +12 -0
  54. package/dist/core/mcp/init.d.ts.map +1 -0
  55. package/dist/core/mcp/init.js +55 -0
  56. package/dist/core/mcp/init.js.map +1 -0
  57. package/dist/core/mcp/logger.d.ts +14 -0
  58. package/dist/core/mcp/logger.d.ts.map +1 -0
  59. package/dist/core/mcp/logger.js +50 -0
  60. package/dist/core/mcp/logger.js.map +1 -0
  61. package/dist/core/tools/analyzePatterns.d.ts +3 -0
  62. package/dist/core/tools/analyzePatterns.d.ts.map +1 -0
  63. package/dist/core/tools/analyzePatterns.js +293 -0
  64. package/dist/core/tools/analyzePatterns.js.map +1 -0
  65. package/dist/core/tools/apexPaths.d.ts +14 -0
  66. package/dist/core/tools/apexPaths.d.ts.map +1 -0
  67. package/dist/core/tools/apexPaths.js +54 -0
  68. package/dist/core/tools/apexPaths.js.map +1 -0
  69. package/dist/core/tools/apexUtils.d.ts +36 -0
  70. package/dist/core/tools/apexUtils.d.ts.map +1 -0
  71. package/dist/core/tools/apexUtils.js +83 -0
  72. package/dist/core/tools/apexUtils.js.map +1 -0
  73. package/dist/core/tools/explainIssue.d.ts +3 -0
  74. package/dist/core/tools/explainIssue.d.ts.map +1 -0
  75. package/dist/core/tools/explainIssue.js +181 -0
  76. package/dist/core/tools/explainIssue.js.map +1 -0
  77. package/dist/core/tools/fixGen.d.ts +3 -0
  78. package/dist/core/tools/fixGen.d.ts.map +1 -0
  79. package/dist/core/tools/fixGen.js +338 -0
  80. package/dist/core/tools/fixGen.js.map +1 -0
  81. package/dist/core/tools/generateImprovements.d.ts +21 -0
  82. package/dist/core/tools/generateImprovements.d.ts.map +1 -0
  83. package/dist/core/tools/generateImprovements.js +602 -0
  84. package/dist/core/tools/generateImprovements.js.map +1 -0
  85. package/dist/core/tools/generateReport.d.ts +3 -0
  86. package/dist/core/tools/generateReport.d.ts.map +1 -0
  87. package/dist/core/tools/generateReport.js +315 -0
  88. package/dist/core/tools/generateReport.js.map +1 -0
  89. package/dist/core/tools/index.d.ts +7 -0
  90. package/dist/core/tools/index.d.ts.map +1 -1
  91. package/dist/core/tools/index.js +62 -23
  92. package/dist/core/tools/index.js.map +1 -1
  93. package/dist/core/tools/recommendProfile.d.ts +3 -0
  94. package/dist/core/tools/recommendProfile.d.ts.map +1 -0
  95. package/dist/core/tools/recommendProfile.js +334 -0
  96. package/dist/core/tools/recommendProfile.js.map +1 -0
  97. package/dist/core/tools/ruleGen.d.ts +3 -0
  98. package/dist/core/tools/ruleGen.d.ts.map +1 -0
  99. package/dist/core/tools/ruleGen.js +1103 -0
  100. package/dist/core/tools/ruleGen.js.map +1 -0
  101. package/dist/core/tools/standards.d.ts.map +1 -1
  102. package/dist/core/tools/standards.js +7 -3
  103. package/dist/core/tools/standards.js.map +1 -1
  104. package/dist/ui/App.d.ts.map +1 -1
  105. package/dist/ui/App.js +86 -35
  106. package/dist/ui/App.js.map +1 -1
  107. package/dist/ui/components/InputBox.d.ts +1 -3
  108. package/dist/ui/components/InputBox.d.ts.map +1 -1
  109. package/dist/ui/components/InputBox.js +146 -5
  110. package/dist/ui/components/InputBox.js.map +1 -1
  111. package/dist/ui/components/MessageList.d.ts +3 -1
  112. package/dist/ui/components/MessageList.d.ts.map +1 -1
  113. package/dist/ui/components/MessageList.js +13 -7
  114. package/dist/ui/components/MessageList.js.map +1 -1
  115. package/dist/ui/components/StatusBar.d.ts +1 -1
  116. package/dist/ui/components/StatusBar.d.ts.map +1 -1
  117. package/dist/ui/components/StatusBar.js +3 -2
  118. package/dist/ui/components/StatusBar.js.map +1 -1
  119. package/dist/ui/components/ToolStatus.d.ts +3 -1
  120. package/dist/ui/components/ToolStatus.d.ts.map +1 -1
  121. package/dist/ui/components/ToolStatus.js +19 -4
  122. package/dist/ui/components/ToolStatus.js.map +1 -1
  123. package/package.json +7 -1
  124. package/demo.gif +0 -0
  125. package/demo.tape +0 -53
  126. package/screenshot.png +0 -0
  127. package/src/cli/banner.ts +0 -38
  128. package/src/cli/headless.ts +0 -63
  129. package/src/cli/index.ts +0 -57
  130. package/src/core/agent.ts +0 -711
  131. package/src/core/commands.ts +0 -118
  132. package/src/core/config.ts +0 -98
  133. package/src/core/conversation.ts +0 -235
  134. package/src/core/llm/ollama.ts +0 -351
  135. package/src/core/mcp/client.ts +0 -143
  136. package/src/core/tools/analyzeAll.ts +0 -482
  137. package/src/core/tools/ast.ts +0 -826
  138. package/src/core/tools/builtIn.ts +0 -221
  139. package/src/core/tools/cache.ts +0 -570
  140. package/src/core/tools/cssAnalysis.ts +0 -324
  141. package/src/core/tools/dependencyAnalysis.ts +0 -363
  142. package/src/core/tools/embeddings.ts +0 -746
  143. package/src/core/tools/frontendAst.ts +0 -802
  144. package/src/core/tools/htmlAnalysis.ts +0 -466
  145. package/src/core/tools/index.ts +0 -160
  146. package/src/core/tools/javaAst.ts +0 -1030
  147. package/src/core/tools/javaQuality.integration.test.ts +0 -537
  148. package/src/core/tools/memory.ts +0 -655
  149. package/src/core/tools/mybatisAnalysis.ts +0 -322
  150. package/src/core/tools/openapiAnalysis.ts +0 -431
  151. package/src/core/tools/pythonAnalysis.ts +0 -477
  152. package/src/core/tools/sqlAnalysis.ts +0 -298
  153. package/src/core/tools/standards.test.ts +0 -186
  154. package/src/core/tools/standards.ts +0 -889
  155. package/src/core/tools/types.ts +0 -38
  156. package/src/ui/App.tsx +0 -334
  157. package/src/ui/components/InputBox.tsx +0 -37
  158. package/src/ui/components/MessageList.tsx +0 -80
  159. package/src/ui/components/StatusBar.tsx +0 -36
  160. package/src/ui/components/ToolStatus.tsx +0 -38
  161. package/tsconfig.json +0 -21
@@ -1,482 +0,0 @@
1
- import { Tool, ToolResult } from "./types.js";
2
- import * as fs from "fs";
3
- import * as path from "path";
4
-
5
- // 각 분석 도구 import
6
- import { sqlTools } from "./sqlAnalysis.js";
7
- import { mybatisTools } from "./mybatisAnalysis.js";
8
- import { cssTools } from "./cssAnalysis.js";
9
- import { htmlTools } from "./htmlAnalysis.js";
10
- import { dependencyTools } from "./dependencyAnalysis.js";
11
- import { openapiTools } from "./openapiAnalysis.js";
12
- import { pythonTools } from "./pythonAnalysis.js";
13
- import { javaTools } from "./javaAst.js";
14
- import { frontendTools } from "./frontendAst.js";
15
- import { astTools } from "./ast.js";
16
-
17
- interface FileStats {
18
- java: string[];
19
- xml: string[];
20
- js: string[];
21
- ts: string[];
22
- jsx: string[];
23
- tsx: string[];
24
- vue: string[];
25
- py: string[];
26
- css: string[];
27
- scss: string[];
28
- html: string[];
29
- jsp: string[];
30
- json: string[];
31
- yaml: string[];
32
- }
33
-
34
- interface AnalysisResult {
35
- tool: string;
36
- success: boolean;
37
- summary: any;
38
- error?: string;
39
- }
40
-
41
- // 파일 수집
42
- function collectFiles(dirPath: string, stats: FileStats, maxDepth: number = 10, currentDepth: number = 0): void {
43
- if (currentDepth > maxDepth) return;
44
-
45
- try {
46
- const items = fs.readdirSync(dirPath);
47
-
48
- for (const item of items) {
49
- const fullPath = path.join(dirPath, item);
50
-
51
- try {
52
- const stat = fs.statSync(fullPath);
53
-
54
- if (stat.isDirectory()) {
55
- // 제외할 디렉토리
56
- const excludeDirs = [
57
- "node_modules", "target", "build", "dist", ".git", ".svn",
58
- "__pycache__", "venv", ".venv", "env", ".idea", ".vscode",
59
- "out", "bin", "obj", ".gradle", ".m2"
60
- ];
61
-
62
- if (!item.startsWith(".") && !excludeDirs.includes(item)) {
63
- collectFiles(fullPath, stats, maxDepth, currentDepth + 1);
64
- }
65
- } else if (stat.isFile()) {
66
- const ext = path.extname(item).toLowerCase();
67
-
68
- switch (ext) {
69
- case ".java": stats.java.push(fullPath); break;
70
- case ".xml": stats.xml.push(fullPath); break;
71
- case ".js": stats.js.push(fullPath); break;
72
- case ".ts": stats.ts.push(fullPath); break;
73
- case ".jsx": stats.jsx.push(fullPath); break;
74
- case ".tsx": stats.tsx.push(fullPath); break;
75
- case ".vue": stats.vue.push(fullPath); break;
76
- case ".py": stats.py.push(fullPath); break;
77
- case ".css": stats.css.push(fullPath); break;
78
- case ".scss":
79
- case ".less": stats.scss.push(fullPath); break;
80
- case ".html":
81
- case ".htm": stats.html.push(fullPath); break;
82
- case ".jsp": stats.jsp.push(fullPath); break;
83
- case ".json": stats.json.push(fullPath); break;
84
- case ".yaml":
85
- case ".yml": stats.yaml.push(fullPath); break;
86
- }
87
- }
88
- } catch (e) {
89
- // 파일 접근 오류 무시
90
- }
91
- }
92
- } catch (e) {
93
- // 디렉토리 접근 오류 무시
94
- }
95
- }
96
-
97
- // 도구 실행 헬퍼
98
- async function runTool(tool: Tool, args: Record<string, unknown>): Promise<AnalysisResult> {
99
- try {
100
- const result = await tool.handler(args);
101
- if (result.success) {
102
- const parsed = JSON.parse(result.content);
103
- return {
104
- tool: tool.name,
105
- success: true,
106
- summary: parsed,
107
- };
108
- } else {
109
- return {
110
- tool: tool.name,
111
- success: false,
112
- summary: null,
113
- error: result.error,
114
- };
115
- }
116
- } catch (e) {
117
- return {
118
- tool: tool.name,
119
- success: false,
120
- summary: null,
121
- error: String(e),
122
- };
123
- }
124
- }
125
-
126
- // 도구 정의
127
- export const analyzeAllTools: Tool[] = [
128
- {
129
- name: "analyze_all",
130
- description:
131
- "디렉토리 전체를 자동으로 분석합니다. Java, MyBatis, SQL, JavaScript, TypeScript, React, Vue, Python, CSS, HTML 등 모든 파일 유형을 감지하고 적절한 분석 도구를 실행합니다. LLM 판단 없이 바로 실행됩니다.",
132
- parameters: {
133
- type: "object",
134
- properties: {
135
- path: {
136
- type: "string",
137
- description: "분석할 프로젝트 디렉토리 경로",
138
- },
139
- include: {
140
- type: "array",
141
- description: "분석할 파일 유형 (생략 시 모두 분석). 예: ['java', 'xml', 'js']",
142
- items: { type: "string" },
143
- },
144
- exclude: {
145
- type: "array",
146
- description: "제외할 파일 유형. 예: ['css', 'html']",
147
- items: { type: "string" },
148
- },
149
- },
150
- required: ["path"],
151
- },
152
- handler: async (args: Record<string, unknown>): Promise<ToolResult> => {
153
- const targetPath = args.path as string;
154
- const include = args.include as string[] | undefined;
155
- const exclude = args.exclude as string[] | undefined;
156
-
157
- if (!fs.existsSync(targetPath)) {
158
- return {
159
- success: false,
160
- content: "",
161
- error: `경로를 찾을 수 없습니다: ${targetPath}`,
162
- };
163
- }
164
-
165
- const stats = fs.statSync(targetPath);
166
- if (!stats.isDirectory()) {
167
- return {
168
- success: false,
169
- content: "",
170
- error: `디렉토리가 아닙니다: ${targetPath}`,
171
- };
172
- }
173
-
174
- // 파일 수집
175
- const fileStats: FileStats = {
176
- java: [], xml: [], js: [], ts: [], jsx: [], tsx: [],
177
- vue: [], py: [], css: [], scss: [], html: [], jsp: [],
178
- json: [], yaml: [],
179
- };
180
-
181
- collectFiles(targetPath, fileStats);
182
-
183
- // 분석할 유형 결정
184
- const shouldAnalyze = (type: string): boolean => {
185
- if (exclude?.includes(type)) return false;
186
- if (include && include.length > 0) return include.includes(type);
187
- return true;
188
- };
189
-
190
- const results: AnalysisResult[] = [];
191
- const fileCounts: Record<string, number> = {};
192
-
193
- // 파일 통계
194
- Object.entries(fileStats).forEach(([type, files]) => {
195
- if (files.length > 0) {
196
- fileCounts[type] = files.length;
197
- }
198
- });
199
-
200
- // Java 분석 (파일 단위 도구 - 샘플링)
201
- if (fileStats.java.length > 0 && shouldAnalyze("java")) {
202
- // Java AST 분석 (최대 10개 파일 샘플링)
203
- const javaAnalyzeTool = javaTools.find(t => t.name === "java_analyze");
204
- if (javaAnalyzeTool) {
205
- const sampleFiles = fileStats.java.slice(0, 10);
206
- const javaResults: any[] = [];
207
- for (const file of sampleFiles) {
208
- try {
209
- const r = await javaAnalyzeTool.handler({ filepath: file, format: "json" });
210
- if (r.success) {
211
- javaResults.push({ file, result: JSON.parse(r.content) });
212
- }
213
- } catch (e) { /* ignore */ }
214
- }
215
- if (javaResults.length > 0) {
216
- results.push({
217
- tool: "java_analyze",
218
- success: true,
219
- summary: {
220
- analyzedFiles: javaResults.length,
221
- totalJavaFiles: fileStats.java.length,
222
- samples: javaResults,
223
- },
224
- });
225
- }
226
- }
227
-
228
- // Spring 패턴 (glob 기반)
229
- const springCheckTool = javaTools.find(t => t.name === "spring_check");
230
- if (springCheckTool) {
231
- const springPattern = path.join(targetPath, "**/*.java");
232
- try {
233
- const r = await springCheckTool.handler({ pattern: springPattern });
234
- if (r.success) {
235
- results.push({
236
- tool: "spring_check",
237
- success: true,
238
- summary: r.content,
239
- });
240
- }
241
- } catch (e) { /* ignore */ }
242
- }
243
-
244
- // SQL in Java (디렉토리 단위)
245
- const sqlCheckTool = sqlTools.find(t => t.name === "sql_check");
246
- if (sqlCheckTool) {
247
- results.push(await runTool(sqlCheckTool, { path: targetPath }));
248
- }
249
- }
250
-
251
- // XML (MyBatis) 분석
252
- if (fileStats.xml.length > 0 && shouldAnalyze("xml")) {
253
- const mybatisCheckTool = mybatisTools.find(t => t.name === "mybatis_check");
254
- if (mybatisCheckTool) {
255
- results.push(await runTool(mybatisCheckTool, { path: targetPath }));
256
- }
257
- }
258
-
259
- // JavaScript/TypeScript 분석 (파일 단위 도구 - 샘플링)
260
- const jsFiles = [...fileStats.js, ...fileStats.ts, ...fileStats.jsx, ...fileStats.tsx];
261
- if (jsFiles.length > 0 && (shouldAnalyze("js") || shouldAnalyze("ts"))) {
262
- // AST 분석 (최대 10개 파일 샘플링)
263
- const astAnalyzeTool = astTools.find(t => t.name === "ast_analyze");
264
- if (astAnalyzeTool) {
265
- const sampleFiles = jsFiles.slice(0, 10);
266
- const astResults: any[] = [];
267
- for (const file of sampleFiles) {
268
- try {
269
- const r = await astAnalyzeTool.handler({ filepath: file, format: "json" });
270
- if (r.success) {
271
- astResults.push({ file, result: JSON.parse(r.content) });
272
- }
273
- } catch (e) { /* ignore */ }
274
- }
275
- if (astResults.length > 0) {
276
- results.push({
277
- tool: "ast_analyze",
278
- success: true,
279
- summary: {
280
- analyzedFiles: astResults.length,
281
- totalJsFiles: jsFiles.length,
282
- samples: astResults,
283
- },
284
- });
285
- }
286
- }
287
-
288
- // React 분석 (파일 단위)
289
- const reactFiles = [...fileStats.jsx, ...fileStats.tsx];
290
- if (reactFiles.length > 0 && shouldAnalyze("react")) {
291
- const reactCheckTool = frontendTools.find(t => t.name === "react_check");
292
- if (reactCheckTool) {
293
- const sampleFiles = reactFiles.slice(0, 10);
294
- const reactResults: any[] = [];
295
- for (const file of sampleFiles) {
296
- try {
297
- const r = await reactCheckTool.handler({ filepath: file });
298
- if (r.success) {
299
- reactResults.push({ file, result: JSON.parse(r.content) });
300
- }
301
- } catch (e) { /* ignore */ }
302
- }
303
- if (reactResults.length > 0) {
304
- results.push({
305
- tool: "react_check",
306
- success: true,
307
- summary: { analyzedFiles: reactResults.length, samples: reactResults },
308
- });
309
- }
310
- }
311
- }
312
-
313
- // jQuery 분석 (파일 단위)
314
- if (shouldAnalyze("jquery")) {
315
- const jqueryCheckTool = frontendTools.find(t => t.name === "jquery_check");
316
- if (jqueryCheckTool) {
317
- const sampleFiles = jsFiles.slice(0, 10);
318
- const jqueryResults: any[] = [];
319
- for (const file of sampleFiles) {
320
- try {
321
- const r = await jqueryCheckTool.handler({ filepath: file });
322
- if (r.success) {
323
- const parsed = JSON.parse(r.content);
324
- if (parsed.hasJQuery || parsed.deprecated?.length > 0) {
325
- jqueryResults.push({ file, result: parsed });
326
- }
327
- }
328
- } catch (e) { /* ignore */ }
329
- }
330
- if (jqueryResults.length > 0) {
331
- results.push({
332
- tool: "jquery_check",
333
- success: true,
334
- summary: { filesWithJQuery: jqueryResults.length, samples: jqueryResults },
335
- });
336
- }
337
- }
338
- }
339
- }
340
-
341
- // Vue 분석 (파일 단위)
342
- if (fileStats.vue.length > 0 && shouldAnalyze("vue")) {
343
- const vueCheckTool = frontendTools.find(t => t.name === "vue_check");
344
- if (vueCheckTool) {
345
- const sampleFiles = fileStats.vue.slice(0, 10);
346
- const vueResults: any[] = [];
347
- for (const file of sampleFiles) {
348
- try {
349
- const r = await vueCheckTool.handler({ filepath: file });
350
- if (r.success) {
351
- vueResults.push({ file, result: JSON.parse(r.content) });
352
- }
353
- } catch (e) { /* ignore */ }
354
- }
355
- if (vueResults.length > 0) {
356
- results.push({
357
- tool: "vue_check",
358
- success: true,
359
- summary: { analyzedFiles: vueResults.length, samples: vueResults },
360
- });
361
- }
362
- }
363
- }
364
-
365
- // Python 분석
366
- if (fileStats.py.length > 0 && shouldAnalyze("py")) {
367
- const pythonCheckTool = pythonTools.find(t => t.name === "python_check");
368
- if (pythonCheckTool) {
369
- results.push(await runTool(pythonCheckTool, { path: targetPath }));
370
- }
371
- }
372
-
373
- // CSS/SCSS 분석
374
- const cssFiles = [...fileStats.css, ...fileStats.scss];
375
- if (cssFiles.length > 0 && shouldAnalyze("css")) {
376
- const cssCheckTool = cssTools.find(t => t.name === "css_check");
377
- if (cssCheckTool) {
378
- results.push(await runTool(cssCheckTool, { path: targetPath }));
379
- }
380
- }
381
-
382
- // HTML/JSP 분석
383
- const htmlFiles = [...fileStats.html, ...fileStats.jsp];
384
- if (htmlFiles.length > 0 && shouldAnalyze("html")) {
385
- const htmlCheckTool = htmlTools.find(t => t.name === "html_check");
386
- if (htmlCheckTool) {
387
- results.push(await runTool(htmlCheckTool, { path: targetPath }));
388
- }
389
- }
390
-
391
- // 의존성 분석 (package.json, pom.xml)
392
- const hasPackageJson = fileStats.json.some(f => f.endsWith("package.json"));
393
- const hasPomXml = fileStats.xml.some(f => f.endsWith("pom.xml"));
394
- if ((hasPackageJson || hasPomXml) && shouldAnalyze("dependency")) {
395
- const dependencyCheckTool = dependencyTools.find(t => t.name === "dependency_check");
396
- if (dependencyCheckTool) {
397
- results.push(await runTool(dependencyCheckTool, { path: targetPath }));
398
- }
399
- }
400
-
401
- // OpenAPI 분석
402
- const hasOpenApi = [...fileStats.yaml, ...fileStats.json].some(f =>
403
- f.includes("swagger") || f.includes("openapi") || f.includes("api-docs")
404
- );
405
- if (hasOpenApi && shouldAnalyze("openapi")) {
406
- const openapiCheckTool = openapiTools.find(t => t.name === "openapi_check");
407
- if (openapiCheckTool) {
408
- results.push(await runTool(openapiCheckTool, { path: targetPath }));
409
- }
410
- }
411
-
412
- // 결과 요약
413
- const successfulAnalyses = results.filter(r => r.success);
414
- const failedAnalyses = results.filter(r => !r.success);
415
-
416
- // 주요 이슈 추출
417
- const issues: { tool: string; issues: string[] }[] = [];
418
-
419
- for (const result of successfulAnalyses) {
420
- const toolIssues: string[] = [];
421
- const summary = result.summary;
422
-
423
- // 각 도구별 이슈 추출
424
- if (result.tool === "java_analyze" && summary.samples) {
425
- for (const sample of summary.samples) {
426
- if (sample.result?.issues?.length > 0) {
427
- toolIssues.push(...sample.result.issues.slice(0, 5).map((i: any) => i.message));
428
- }
429
- }
430
- }
431
- if (result.tool === "mybatis_check" && summary.injectionRisks > 0) {
432
- toolIssues.push(`SQL Injection 위험 ${summary.injectionRisks}건`);
433
- }
434
- if (result.tool === "sql_check" && summary.queriesWithIssues > 0) {
435
- toolIssues.push(`SQL 쿼리 이슈 ${summary.queriesWithIssues}건`);
436
- }
437
- if (result.tool === "spring_check" && summary.issues) {
438
- toolIssues.push(...summary.issues.slice(0, 3));
439
- }
440
- if (result.tool === "dependency_check" && summary.securityConcerns > 0) {
441
- toolIssues.push(`보안 취약점 ${summary.securityConcerns}건`);
442
- }
443
- if (result.tool === "css_check" && summary.totalImportant > 5) {
444
- toolIssues.push(`!important 과다 사용 ${summary.totalImportant}회`);
445
- }
446
- if (result.tool === "html_check" && summary.averageA11yScore < 60) {
447
- toolIssues.push(`접근성 점수 낮음 (${summary.averageA11yScore}%)`);
448
- }
449
- if (result.tool === "python_check" && summary.docstringCoverage < 50) {
450
- toolIssues.push(`Python docstring 부족 (${summary.docstringCoverage}%)`);
451
- }
452
-
453
- if (toolIssues.length > 0) {
454
- issues.push({ tool: result.tool, issues: toolIssues });
455
- }
456
- }
457
-
458
- const output = {
459
- path: targetPath,
460
- fileStats: fileCounts,
461
- totalFiles: Object.values(fileCounts).reduce((a, b) => a + b, 0),
462
- analysesRun: results.length,
463
- successful: successfulAnalyses.length,
464
- failed: failedAnalyses.length,
465
- issuesSummary: issues,
466
- details: successfulAnalyses.map(r => ({
467
- tool: r.tool,
468
- summary: r.summary,
469
- })),
470
- errors: failedAnalyses.map(r => ({
471
- tool: r.tool,
472
- error: r.error,
473
- })),
474
- };
475
-
476
- return {
477
- success: true,
478
- content: JSON.stringify(output, null, 2),
479
- };
480
- },
481
- },
482
- ];