activo 0.4.3 → 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 (166) 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 +255 -17
  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/analyzeAll.d.ts.map +1 -1
  62. package/dist/core/tools/analyzeAll.js +16 -28
  63. package/dist/core/tools/analyzeAll.js.map +1 -1
  64. package/dist/core/tools/analyzePatterns.d.ts +3 -0
  65. package/dist/core/tools/analyzePatterns.d.ts.map +1 -0
  66. package/dist/core/tools/analyzePatterns.js +293 -0
  67. package/dist/core/tools/analyzePatterns.js.map +1 -0
  68. package/dist/core/tools/apexPaths.d.ts +14 -0
  69. package/dist/core/tools/apexPaths.d.ts.map +1 -0
  70. package/dist/core/tools/apexPaths.js +54 -0
  71. package/dist/core/tools/apexPaths.js.map +1 -0
  72. package/dist/core/tools/apexUtils.d.ts +36 -0
  73. package/dist/core/tools/apexUtils.d.ts.map +1 -0
  74. package/dist/core/tools/apexUtils.js +83 -0
  75. package/dist/core/tools/apexUtils.js.map +1 -0
  76. package/dist/core/tools/explainIssue.d.ts +3 -0
  77. package/dist/core/tools/explainIssue.d.ts.map +1 -0
  78. package/dist/core/tools/explainIssue.js +181 -0
  79. package/dist/core/tools/explainIssue.js.map +1 -0
  80. package/dist/core/tools/fixGen.d.ts +3 -0
  81. package/dist/core/tools/fixGen.d.ts.map +1 -0
  82. package/dist/core/tools/fixGen.js +338 -0
  83. package/dist/core/tools/fixGen.js.map +1 -0
  84. package/dist/core/tools/generateImprovements.d.ts +21 -0
  85. package/dist/core/tools/generateImprovements.d.ts.map +1 -0
  86. package/dist/core/tools/generateImprovements.js +602 -0
  87. package/dist/core/tools/generateImprovements.js.map +1 -0
  88. package/dist/core/tools/generateReport.d.ts +3 -0
  89. package/dist/core/tools/generateReport.d.ts.map +1 -0
  90. package/dist/core/tools/generateReport.js +315 -0
  91. package/dist/core/tools/generateReport.js.map +1 -0
  92. package/dist/core/tools/index.d.ts +7 -0
  93. package/dist/core/tools/index.d.ts.map +1 -1
  94. package/dist/core/tools/index.js +62 -23
  95. package/dist/core/tools/index.js.map +1 -1
  96. package/dist/core/tools/javaAst.d.ts.map +1 -1
  97. package/dist/core/tools/javaAst.js +191 -0
  98. package/dist/core/tools/javaAst.js.map +1 -1
  99. package/dist/core/tools/recommendProfile.d.ts +3 -0
  100. package/dist/core/tools/recommendProfile.d.ts.map +1 -0
  101. package/dist/core/tools/recommendProfile.js +334 -0
  102. package/dist/core/tools/recommendProfile.js.map +1 -0
  103. package/dist/core/tools/ruleGen.d.ts +3 -0
  104. package/dist/core/tools/ruleGen.d.ts.map +1 -0
  105. package/dist/core/tools/ruleGen.js +1103 -0
  106. package/dist/core/tools/ruleGen.js.map +1 -0
  107. package/dist/core/tools/standards.d.ts.map +1 -1
  108. package/dist/core/tools/standards.js +7 -3
  109. package/dist/core/tools/standards.js.map +1 -1
  110. package/dist/ui/App.d.ts.map +1 -1
  111. package/dist/ui/App.js +86 -35
  112. package/dist/ui/App.js.map +1 -1
  113. package/dist/ui/components/InputBox.d.ts +1 -3
  114. package/dist/ui/components/InputBox.d.ts.map +1 -1
  115. package/dist/ui/components/InputBox.js +146 -5
  116. package/dist/ui/components/InputBox.js.map +1 -1
  117. package/dist/ui/components/MessageList.d.ts +3 -1
  118. package/dist/ui/components/MessageList.d.ts.map +1 -1
  119. package/dist/ui/components/MessageList.js +13 -7
  120. package/dist/ui/components/MessageList.js.map +1 -1
  121. package/dist/ui/components/StatusBar.d.ts +1 -1
  122. package/dist/ui/components/StatusBar.d.ts.map +1 -1
  123. package/dist/ui/components/StatusBar.js +3 -2
  124. package/dist/ui/components/StatusBar.js.map +1 -1
  125. package/dist/ui/components/ToolStatus.d.ts +3 -1
  126. package/dist/ui/components/ToolStatus.d.ts.map +1 -1
  127. package/dist/ui/components/ToolStatus.js +19 -4
  128. package/dist/ui/components/ToolStatus.js.map +1 -1
  129. package/package.json +7 -1
  130. package/demo.gif +0 -0
  131. package/demo.tape +0 -53
  132. package/screenshot.png +0 -0
  133. package/src/cli/banner.ts +0 -38
  134. package/src/cli/headless.ts +0 -63
  135. package/src/cli/index.ts +0 -57
  136. package/src/core/agent.ts +0 -237
  137. package/src/core/commands.ts +0 -118
  138. package/src/core/config.ts +0 -98
  139. package/src/core/conversation.ts +0 -235
  140. package/src/core/llm/ollama.ts +0 -351
  141. package/src/core/mcp/client.ts +0 -143
  142. package/src/core/tools/analyzeAll.ts +0 -494
  143. package/src/core/tools/ast.ts +0 -826
  144. package/src/core/tools/builtIn.ts +0 -221
  145. package/src/core/tools/cache.ts +0 -570
  146. package/src/core/tools/cssAnalysis.ts +0 -324
  147. package/src/core/tools/dependencyAnalysis.ts +0 -363
  148. package/src/core/tools/embeddings.ts +0 -746
  149. package/src/core/tools/frontendAst.ts +0 -802
  150. package/src/core/tools/htmlAnalysis.ts +0 -466
  151. package/src/core/tools/index.ts +0 -160
  152. package/src/core/tools/javaAst.ts +0 -812
  153. package/src/core/tools/memory.ts +0 -655
  154. package/src/core/tools/mybatisAnalysis.ts +0 -322
  155. package/src/core/tools/openapiAnalysis.ts +0 -431
  156. package/src/core/tools/pythonAnalysis.ts +0 -477
  157. package/src/core/tools/sqlAnalysis.ts +0 -298
  158. package/src/core/tools/standards.test.ts +0 -186
  159. package/src/core/tools/standards.ts +0 -889
  160. package/src/core/tools/types.ts +0 -38
  161. package/src/ui/App.tsx +0 -334
  162. package/src/ui/components/InputBox.tsx +0 -37
  163. package/src/ui/components/MessageList.tsx +0 -80
  164. package/src/ui/components/StatusBar.tsx +0 -36
  165. package/src/ui/components/ToolStatus.tsx +0 -38
  166. package/tsconfig.json +0 -21
@@ -1,494 +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 패턴 (파일 단위)
229
- const springCheckTool = javaTools.find(t => t.name === "spring_check");
230
- if (springCheckTool) {
231
- const sampleFiles = fileStats.java.slice(0, 20);
232
- const springResults: any[] = [];
233
- for (const file of sampleFiles) {
234
- try {
235
- const r = await springCheckTool.handler({ filepath: file, format: "json" });
236
- if (r.success) {
237
- const parsed = JSON.parse(r.content);
238
- if (parsed.annotations?.length > 0 || parsed.patterns?.length > 0) {
239
- springResults.push({ file, result: parsed });
240
- }
241
- }
242
- } catch (e) { /* ignore */ }
243
- }
244
- if (springResults.length > 0) {
245
- results.push({
246
- tool: "spring_check",
247
- success: true,
248
- summary: {
249
- springFiles: springResults.length,
250
- samples: springResults.slice(0, 10),
251
- },
252
- });
253
- }
254
- }
255
-
256
- // SQL in Java (디렉토리 단위)
257
- const sqlCheckTool = sqlTools.find(t => t.name === "sql_check");
258
- if (sqlCheckTool) {
259
- results.push(await runTool(sqlCheckTool, { path: targetPath }));
260
- }
261
- }
262
-
263
- // XML (MyBatis) 분석
264
- if (fileStats.xml.length > 0 && shouldAnalyze("xml")) {
265
- const mybatisCheckTool = mybatisTools.find(t => t.name === "mybatis_check");
266
- if (mybatisCheckTool) {
267
- results.push(await runTool(mybatisCheckTool, { path: targetPath }));
268
- }
269
- }
270
-
271
- // JavaScript/TypeScript 분석 (파일 단위 도구 - 샘플링)
272
- const jsFiles = [...fileStats.js, ...fileStats.ts, ...fileStats.jsx, ...fileStats.tsx];
273
- if (jsFiles.length > 0 && (shouldAnalyze("js") || shouldAnalyze("ts"))) {
274
- // AST 분석 (최대 10개 파일 샘플링)
275
- const astAnalyzeTool = astTools.find(t => t.name === "ast_analyze");
276
- if (astAnalyzeTool) {
277
- const sampleFiles = jsFiles.slice(0, 10);
278
- const astResults: any[] = [];
279
- for (const file of sampleFiles) {
280
- try {
281
- const r = await astAnalyzeTool.handler({ filepath: file, format: "json" });
282
- if (r.success) {
283
- astResults.push({ file, result: JSON.parse(r.content) });
284
- }
285
- } catch (e) { /* ignore */ }
286
- }
287
- if (astResults.length > 0) {
288
- results.push({
289
- tool: "ast_analyze",
290
- success: true,
291
- summary: {
292
- analyzedFiles: astResults.length,
293
- totalJsFiles: jsFiles.length,
294
- samples: astResults,
295
- },
296
- });
297
- }
298
- }
299
-
300
- // React 분석 (파일 단위)
301
- const reactFiles = [...fileStats.jsx, ...fileStats.tsx];
302
- if (reactFiles.length > 0 && shouldAnalyze("react")) {
303
- const reactCheckTool = frontendTools.find(t => t.name === "react_check");
304
- if (reactCheckTool) {
305
- const sampleFiles = reactFiles.slice(0, 10);
306
- const reactResults: any[] = [];
307
- for (const file of sampleFiles) {
308
- try {
309
- const r = await reactCheckTool.handler({ filepath: file });
310
- if (r.success) {
311
- reactResults.push({ file, result: JSON.parse(r.content) });
312
- }
313
- } catch (e) { /* ignore */ }
314
- }
315
- if (reactResults.length > 0) {
316
- results.push({
317
- tool: "react_check",
318
- success: true,
319
- summary: { analyzedFiles: reactResults.length, samples: reactResults },
320
- });
321
- }
322
- }
323
- }
324
-
325
- // jQuery 분석 (파일 단위)
326
- if (shouldAnalyze("jquery")) {
327
- const jqueryCheckTool = frontendTools.find(t => t.name === "jquery_check");
328
- if (jqueryCheckTool) {
329
- const sampleFiles = jsFiles.slice(0, 10);
330
- const jqueryResults: any[] = [];
331
- for (const file of sampleFiles) {
332
- try {
333
- const r = await jqueryCheckTool.handler({ filepath: file });
334
- if (r.success) {
335
- const parsed = JSON.parse(r.content);
336
- if (parsed.hasJQuery || parsed.deprecated?.length > 0) {
337
- jqueryResults.push({ file, result: parsed });
338
- }
339
- }
340
- } catch (e) { /* ignore */ }
341
- }
342
- if (jqueryResults.length > 0) {
343
- results.push({
344
- tool: "jquery_check",
345
- success: true,
346
- summary: { filesWithJQuery: jqueryResults.length, samples: jqueryResults },
347
- });
348
- }
349
- }
350
- }
351
- }
352
-
353
- // Vue 분석 (파일 단위)
354
- if (fileStats.vue.length > 0 && shouldAnalyze("vue")) {
355
- const vueCheckTool = frontendTools.find(t => t.name === "vue_check");
356
- if (vueCheckTool) {
357
- const sampleFiles = fileStats.vue.slice(0, 10);
358
- const vueResults: any[] = [];
359
- for (const file of sampleFiles) {
360
- try {
361
- const r = await vueCheckTool.handler({ filepath: file });
362
- if (r.success) {
363
- vueResults.push({ file, result: JSON.parse(r.content) });
364
- }
365
- } catch (e) { /* ignore */ }
366
- }
367
- if (vueResults.length > 0) {
368
- results.push({
369
- tool: "vue_check",
370
- success: true,
371
- summary: { analyzedFiles: vueResults.length, samples: vueResults },
372
- });
373
- }
374
- }
375
- }
376
-
377
- // Python 분석
378
- if (fileStats.py.length > 0 && shouldAnalyze("py")) {
379
- const pythonCheckTool = pythonTools.find(t => t.name === "python_check");
380
- if (pythonCheckTool) {
381
- results.push(await runTool(pythonCheckTool, { path: targetPath }));
382
- }
383
- }
384
-
385
- // CSS/SCSS 분석
386
- const cssFiles = [...fileStats.css, ...fileStats.scss];
387
- if (cssFiles.length > 0 && shouldAnalyze("css")) {
388
- const cssCheckTool = cssTools.find(t => t.name === "css_check");
389
- if (cssCheckTool) {
390
- results.push(await runTool(cssCheckTool, { path: targetPath }));
391
- }
392
- }
393
-
394
- // HTML/JSP 분석
395
- const htmlFiles = [...fileStats.html, ...fileStats.jsp];
396
- if (htmlFiles.length > 0 && shouldAnalyze("html")) {
397
- const htmlCheckTool = htmlTools.find(t => t.name === "html_check");
398
- if (htmlCheckTool) {
399
- results.push(await runTool(htmlCheckTool, { path: targetPath }));
400
- }
401
- }
402
-
403
- // 의존성 분석 (package.json, pom.xml)
404
- const hasPackageJson = fileStats.json.some(f => f.endsWith("package.json"));
405
- const hasPomXml = fileStats.xml.some(f => f.endsWith("pom.xml"));
406
- if ((hasPackageJson || hasPomXml) && shouldAnalyze("dependency")) {
407
- const dependencyCheckTool = dependencyTools.find(t => t.name === "dependency_check");
408
- if (dependencyCheckTool) {
409
- results.push(await runTool(dependencyCheckTool, { path: targetPath }));
410
- }
411
- }
412
-
413
- // OpenAPI 분석
414
- const hasOpenApi = [...fileStats.yaml, ...fileStats.json].some(f =>
415
- f.includes("swagger") || f.includes("openapi") || f.includes("api-docs")
416
- );
417
- if (hasOpenApi && shouldAnalyze("openapi")) {
418
- const openapiCheckTool = openapiTools.find(t => t.name === "openapi_check");
419
- if (openapiCheckTool) {
420
- results.push(await runTool(openapiCheckTool, { path: targetPath }));
421
- }
422
- }
423
-
424
- // 결과 요약
425
- const successfulAnalyses = results.filter(r => r.success);
426
- const failedAnalyses = results.filter(r => !r.success);
427
-
428
- // 주요 이슈 추출
429
- const issues: { tool: string; issues: string[] }[] = [];
430
-
431
- for (const result of successfulAnalyses) {
432
- const toolIssues: string[] = [];
433
- const summary = result.summary;
434
-
435
- // 각 도구별 이슈 추출
436
- if (result.tool === "java_analyze" && summary.files) {
437
- summary.files.forEach((f: any) => {
438
- if (f.issues?.length > 0) {
439
- toolIssues.push(...f.issues.slice(0, 3));
440
- }
441
- });
442
- }
443
- if (result.tool === "mybatis_check" && summary.injectionRisks > 0) {
444
- toolIssues.push(`SQL Injection 위험 ${summary.injectionRisks}건`);
445
- }
446
- if (result.tool === "sql_check" && summary.queriesWithIssues > 0) {
447
- toolIssues.push(`SQL 쿼리 이슈 ${summary.queriesWithIssues}건`);
448
- }
449
- if (result.tool === "spring_check" && summary.issues) {
450
- toolIssues.push(...summary.issues.slice(0, 3));
451
- }
452
- if (result.tool === "dependency_check" && summary.securityConcerns > 0) {
453
- toolIssues.push(`보안 취약점 ${summary.securityConcerns}건`);
454
- }
455
- if (result.tool === "css_check" && summary.totalImportant > 5) {
456
- toolIssues.push(`!important 과다 사용 ${summary.totalImportant}회`);
457
- }
458
- if (result.tool === "html_check" && summary.averageA11yScore < 60) {
459
- toolIssues.push(`접근성 점수 낮음 (${summary.averageA11yScore}%)`);
460
- }
461
- if (result.tool === "python_check" && summary.docstringCoverage < 50) {
462
- toolIssues.push(`Python docstring 부족 (${summary.docstringCoverage}%)`);
463
- }
464
-
465
- if (toolIssues.length > 0) {
466
- issues.push({ tool: result.tool, issues: toolIssues });
467
- }
468
- }
469
-
470
- const output = {
471
- path: targetPath,
472
- fileStats: fileCounts,
473
- totalFiles: Object.values(fileCounts).reduce((a, b) => a + b, 0),
474
- analysesRun: results.length,
475
- successful: successfulAnalyses.length,
476
- failed: failedAnalyses.length,
477
- issuesSummary: issues,
478
- details: successfulAnalyses.map(r => ({
479
- tool: r.tool,
480
- summary: r.summary,
481
- })),
482
- errors: failedAnalyses.map(r => ({
483
- tool: r.tool,
484
- error: r.error,
485
- })),
486
- };
487
-
488
- return {
489
- success: true,
490
- content: JSON.stringify(output, null, 2),
491
- };
492
- },
493
- },
494
- ];