activo 0.2.2 → 0.3.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 (64) hide show
  1. package/README.md +79 -3
  2. package/dist/core/llm/ollama.d.ts +2 -0
  3. package/dist/core/llm/ollama.d.ts.map +1 -1
  4. package/dist/core/llm/ollama.js +26 -0
  5. package/dist/core/llm/ollama.js.map +1 -1
  6. package/dist/core/tools/ast.d.ts +81 -0
  7. package/dist/core/tools/ast.d.ts.map +1 -0
  8. package/dist/core/tools/ast.js +700 -0
  9. package/dist/core/tools/ast.js.map +1 -0
  10. package/dist/core/tools/cache.d.ts +19 -0
  11. package/dist/core/tools/cache.d.ts.map +1 -0
  12. package/dist/core/tools/cache.js +497 -0
  13. package/dist/core/tools/cache.js.map +1 -0
  14. package/dist/core/tools/cssAnalysis.d.ts +3 -0
  15. package/dist/core/tools/cssAnalysis.d.ts.map +1 -0
  16. package/dist/core/tools/cssAnalysis.js +270 -0
  17. package/dist/core/tools/cssAnalysis.js.map +1 -0
  18. package/dist/core/tools/embeddings.d.ts +8 -0
  19. package/dist/core/tools/embeddings.d.ts.map +1 -0
  20. package/dist/core/tools/embeddings.js +631 -0
  21. package/dist/core/tools/embeddings.js.map +1 -0
  22. package/dist/core/tools/frontendAst.d.ts +6 -0
  23. package/dist/core/tools/frontendAst.d.ts.map +1 -0
  24. package/dist/core/tools/frontendAst.js +680 -0
  25. package/dist/core/tools/frontendAst.js.map +1 -0
  26. package/dist/core/tools/htmlAnalysis.d.ts +3 -0
  27. package/dist/core/tools/htmlAnalysis.d.ts.map +1 -0
  28. package/dist/core/tools/htmlAnalysis.js +398 -0
  29. package/dist/core/tools/htmlAnalysis.js.map +1 -0
  30. package/dist/core/tools/index.d.ts +10 -0
  31. package/dist/core/tools/index.d.ts.map +1 -1
  32. package/dist/core/tools/index.js +21 -1
  33. package/dist/core/tools/index.js.map +1 -1
  34. package/dist/core/tools/javaAst.d.ts +6 -0
  35. package/dist/core/tools/javaAst.d.ts.map +1 -0
  36. package/dist/core/tools/javaAst.js +678 -0
  37. package/dist/core/tools/javaAst.js.map +1 -0
  38. package/dist/core/tools/memory.d.ts +11 -0
  39. package/dist/core/tools/memory.d.ts.map +1 -0
  40. package/dist/core/tools/memory.js +551 -0
  41. package/dist/core/tools/memory.js.map +1 -0
  42. package/dist/core/tools/mybatisAnalysis.d.ts +3 -0
  43. package/dist/core/tools/mybatisAnalysis.d.ts.map +1 -0
  44. package/dist/core/tools/mybatisAnalysis.js +251 -0
  45. package/dist/core/tools/mybatisAnalysis.js.map +1 -0
  46. package/dist/core/tools/sqlAnalysis.d.ts +3 -0
  47. package/dist/core/tools/sqlAnalysis.d.ts.map +1 -0
  48. package/dist/core/tools/sqlAnalysis.js +250 -0
  49. package/dist/core/tools/sqlAnalysis.js.map +1 -0
  50. package/package.json +2 -1
  51. package/src/core/llm/ollama.ts +30 -0
  52. package/src/core/tools/ast.ts +826 -0
  53. package/src/core/tools/cache.ts +570 -0
  54. package/src/core/tools/cssAnalysis.ts +324 -0
  55. package/src/core/tools/embeddings.ts +746 -0
  56. package/src/core/tools/frontendAst.ts +802 -0
  57. package/src/core/tools/htmlAnalysis.ts +466 -0
  58. package/src/core/tools/index.ts +21 -1
  59. package/src/core/tools/javaAst.ts +812 -0
  60. package/src/core/tools/memory.ts +655 -0
  61. package/src/core/tools/mybatisAnalysis.ts +322 -0
  62. package/src/core/tools/sqlAnalysis.ts +298 -0
  63. package/FINAL_SIMPLIFIED_SPEC.md +0 -456
  64. package/TODO.md +0 -193
@@ -0,0 +1,3 @@
1
+ import { Tool } from "./types.js";
2
+ export declare const mybatisTools: Tool[];
3
+ //# sourceMappingURL=mybatisAnalysis.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mybatisAnalysis.d.ts","sourceRoot":"","sources":["../../../src/core/tools/mybatisAnalysis.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAc,MAAM,YAAY,CAAC;AA8N9C,eAAO,MAAM,YAAY,EAAE,IAAI,EAmG9B,CAAC"}
@@ -0,0 +1,251 @@
1
+ import * as fs from "fs";
2
+ import * as path from "path";
3
+ // MyBatis XML 파싱 및 분석
4
+ function analyzeMyBatisXml(filePath) {
5
+ const content = fs.readFileSync(filePath, "utf-8");
6
+ const lines = content.split("\n");
7
+ // MyBatis XML 여부 확인
8
+ const isMyBatis = content.includes("mybatis") ||
9
+ content.includes("ibatis") ||
10
+ content.includes('PUBLIC "-//mybatis.org') ||
11
+ content.includes('PUBLIC "-//ibatis.org') ||
12
+ /<mapper\s+namespace=/i.test(content);
13
+ if (!isMyBatis) {
14
+ return {
15
+ file: filePath,
16
+ isMyBatis: false,
17
+ summary: { statements: 0, withIssues: 0, injectionRisks: 0, dynamicSqlCount: 0 },
18
+ };
19
+ }
20
+ const statements = [];
21
+ const resultMaps = [];
22
+ const sqlFragments = [];
23
+ const mapperIssues = [];
24
+ // namespace 추출
25
+ const namespaceMatch = content.match(/<mapper\s+namespace=["']([^"']+)["']/);
26
+ const namespace = namespaceMatch ? namespaceMatch[1] : "unknown";
27
+ // resultMap 추출
28
+ const resultMapRegex = /<resultMap\s+[^>]*id=["']([^"']+)["'][^>]*>/g;
29
+ let match;
30
+ while ((match = resultMapRegex.exec(content)) !== null) {
31
+ resultMaps.push(match[1]);
32
+ }
33
+ // sql fragment 추출
34
+ const sqlFragmentRegex = /<sql\s+[^>]*id=["']([^"']+)["'][^>]*>/g;
35
+ while ((match = sqlFragmentRegex.exec(content)) !== null) {
36
+ sqlFragments.push(match[1]);
37
+ }
38
+ // statement 추출 함수
39
+ const extractStatements = (type) => {
40
+ const regex = new RegExp(`<${type}\\s+([^>]*)>([\\s\\S]*?)</${type}>`, "gi");
41
+ while ((match = regex.exec(content)) !== null) {
42
+ const attrs = match[1];
43
+ const sqlContent = match[2];
44
+ // 속성 파싱
45
+ const idMatch = attrs.match(/id=["']([^"']+)["']/);
46
+ const paramMatch = attrs.match(/parameterType=["']([^"']+)["']/);
47
+ const resultTypeMatch = attrs.match(/resultType=["']([^"']+)["']/);
48
+ const resultMapMatch = attrs.match(/resultMap=["']([^"']+)["']/);
49
+ const id = idMatch ? idMatch[1] : "unknown";
50
+ const issues = [];
51
+ const dynamicElements = [];
52
+ // ${} 사용 검사 (SQL Injection 위험)
53
+ const dollarBraceMatches = sqlContent.match(/\$\{[^}]+\}/g) || [];
54
+ if (dollarBraceMatches.length > 0) {
55
+ issues.push(`SQL Injection 위험: ${dollarBraceMatches.join(", ")} 사용`);
56
+ }
57
+ // 동적 SQL 요소 추출
58
+ const dynamicTags = ["if", "choose", "when", "otherwise", "where", "set", "foreach", "trim", "bind"];
59
+ dynamicTags.forEach((tag) => {
60
+ const tagRegex = new RegExp(`<${tag}[\\s>]`, "gi");
61
+ const count = (sqlContent.match(tagRegex) || []).length;
62
+ if (count > 0) {
63
+ dynamicElements.push(`${tag}(${count})`);
64
+ }
65
+ });
66
+ // SELECT * 검사
67
+ if (/SELECT\s+\*\s+FROM/i.test(sqlContent)) {
68
+ issues.push("SELECT * 사용");
69
+ }
70
+ // WHERE 없는 UPDATE/DELETE
71
+ if ((type === "update" || type === "delete") && !/<where>|WHERE/i.test(sqlContent)) {
72
+ issues.push("WHERE 절 없음 - 전체 테이블 영향 위험");
73
+ }
74
+ // 복잡한 동적 SQL
75
+ if (dynamicElements.length >= 5) {
76
+ issues.push(`복잡한 동적 SQL (${dynamicElements.length}개 요소)`);
77
+ }
78
+ // 중첩 foreach
79
+ const foreachCount = (sqlContent.match(/<foreach/gi) || []).length;
80
+ if (foreachCount >= 2) {
81
+ issues.push(`중첩 foreach ${foreachCount}개 - 성능 검토 필요`);
82
+ }
83
+ // LIKE '%${...}%' 패턴
84
+ if (/LIKE\s+['"]?%?\$\{/i.test(sqlContent)) {
85
+ issues.push("LIKE + ${} 패턴 - SQL Injection 및 인덱스 문제");
86
+ }
87
+ // ORDER BY ${} 패턴
88
+ if (/ORDER\s+BY\s+\$\{/i.test(sqlContent)) {
89
+ issues.push("ORDER BY ${} - SQL Injection 위험");
90
+ }
91
+ // 라인 번호 찾기
92
+ const statementIndex = content.indexOf(match[0]);
93
+ let lineNum = 1;
94
+ for (let i = 0; i < statementIndex; i++) {
95
+ if (content[i] === "\n")
96
+ lineNum++;
97
+ }
98
+ // SQL 정리
99
+ const cleanSql = sqlContent
100
+ .replace(/<[^>]+>/g, " ") // XML 태그 제거
101
+ .replace(/\s+/g, " ")
102
+ .trim();
103
+ statements.push({
104
+ id,
105
+ type,
106
+ parameterType: paramMatch ? paramMatch[1] : undefined,
107
+ resultType: resultTypeMatch ? resultTypeMatch[1] : undefined,
108
+ resultMap: resultMapMatch ? resultMapMatch[1] : undefined,
109
+ sql: cleanSql,
110
+ line: lineNum,
111
+ issues,
112
+ dynamicElements,
113
+ });
114
+ }
115
+ };
116
+ // 각 statement 타입 처리
117
+ extractStatements("select");
118
+ extractStatements("insert");
119
+ extractStatements("update");
120
+ extractStatements("delete");
121
+ // mapper 레벨 이슈 검사
122
+ if (!namespaceMatch) {
123
+ mapperIssues.push("namespace 미정의");
124
+ }
125
+ // 미사용 resultMap 검사 (간단한 체크)
126
+ resultMaps.forEach((rm) => {
127
+ const usageCount = (content.match(new RegExp(`resultMap=["']${rm}["']`, "g")) || []).length;
128
+ if (usageCount <= 1) {
129
+ // 정의만 있고 사용 없음
130
+ mapperIssues.push(`미사용 가능성: resultMap '${rm}'`);
131
+ }
132
+ });
133
+ // 통계
134
+ const injectionRisks = statements.filter((s) => s.issues.some((i) => i.includes("Injection"))).length;
135
+ const dynamicSqlCount = statements.filter((s) => s.dynamicElements.length > 0).length;
136
+ return {
137
+ file: filePath,
138
+ isMyBatis: true,
139
+ mapper: {
140
+ file: filePath,
141
+ namespace,
142
+ statements,
143
+ resultMaps,
144
+ sqlFragments,
145
+ issues: mapperIssues,
146
+ },
147
+ summary: {
148
+ statements: statements.length,
149
+ withIssues: statements.filter((s) => s.issues.length > 0).length,
150
+ injectionRisks,
151
+ dynamicSqlCount,
152
+ },
153
+ };
154
+ }
155
+ // 도구 정의
156
+ export const mybatisTools = [
157
+ {
158
+ name: "mybatis_check",
159
+ description: "MyBatis XML 매퍼 파일을 분석합니다. ${} SQL Injection 위험, 동적 SQL 복잡도, SELECT *, resultMap 사용 등을 검사합니다. DTD/namespace로 MyBatis 파일을 자동 감지합니다.",
160
+ parameters: {
161
+ type: "object",
162
+ properties: {
163
+ path: {
164
+ type: "string",
165
+ description: "분석할 XML 파일 또는 디렉토리 경로",
166
+ },
167
+ recursive: {
168
+ type: "boolean",
169
+ description: "디렉토리인 경우 하위 폴더 포함 여부 (기본: true)",
170
+ },
171
+ },
172
+ required: ["path"],
173
+ },
174
+ handler: async (args) => {
175
+ const targetPath = args.path;
176
+ const recursive = args.recursive !== false;
177
+ if (!fs.existsSync(targetPath)) {
178
+ return {
179
+ success: false,
180
+ content: "",
181
+ error: `경로를 찾을 수 없습니다: ${targetPath}`,
182
+ };
183
+ }
184
+ const results = [];
185
+ const stats = fs.statSync(targetPath);
186
+ if (stats.isFile()) {
187
+ if (targetPath.endsWith(".xml")) {
188
+ const result = analyzeMyBatisXml(targetPath);
189
+ if (result.isMyBatis) {
190
+ results.push(result);
191
+ }
192
+ }
193
+ }
194
+ else if (stats.isDirectory()) {
195
+ const walkDir = (dir) => {
196
+ const files = fs.readdirSync(dir);
197
+ for (const file of files) {
198
+ const filePath = path.join(dir, file);
199
+ const fileStat = fs.statSync(filePath);
200
+ if (fileStat.isDirectory() && recursive) {
201
+ if (!file.startsWith(".") && file !== "node_modules" && file !== "target" && file !== "build") {
202
+ walkDir(filePath);
203
+ }
204
+ }
205
+ else if (file.endsWith(".xml")) {
206
+ const result = analyzeMyBatisXml(filePath);
207
+ if (result.isMyBatis) {
208
+ results.push(result);
209
+ }
210
+ }
211
+ }
212
+ };
213
+ walkDir(targetPath);
214
+ }
215
+ // 전체 통계
216
+ const totalStatements = results.reduce((sum, r) => sum + r.summary.statements, 0);
217
+ const totalWithIssues = results.reduce((sum, r) => sum + r.summary.withIssues, 0);
218
+ const totalInjectionRisks = results.reduce((sum, r) => sum + r.summary.injectionRisks, 0);
219
+ const totalDynamicSql = results.reduce((sum, r) => sum + r.summary.dynamicSqlCount, 0);
220
+ const output = {
221
+ analyzedMappers: results.length,
222
+ totalStatements,
223
+ statementsWithIssues: totalWithIssues,
224
+ injectionRisks: totalInjectionRisks,
225
+ dynamicSqlStatements: totalDynamicSql,
226
+ mappers: results.map((r) => ({
227
+ file: r.file,
228
+ namespace: r.mapper?.namespace,
229
+ resultMaps: r.mapper?.resultMaps,
230
+ sqlFragments: r.mapper?.sqlFragments,
231
+ mapperIssues: r.mapper?.issues,
232
+ statements: r.mapper?.statements.map((s) => ({
233
+ id: s.id,
234
+ type: s.type,
235
+ line: s.line,
236
+ parameterType: s.parameterType,
237
+ resultType: s.resultType || s.resultMap,
238
+ dynamicElements: s.dynamicElements,
239
+ issues: s.issues,
240
+ sql: s.sql.length > 150 ? s.sql.substring(0, 150) + "..." : s.sql,
241
+ })),
242
+ })),
243
+ };
244
+ return {
245
+ success: true,
246
+ content: JSON.stringify(output, null, 2),
247
+ };
248
+ },
249
+ },
250
+ ];
251
+ //# sourceMappingURL=mybatisAnalysis.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mybatisAnalysis.js","sourceRoot":"","sources":["../../../src/core/tools/mybatisAnalysis.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Tool } from "./types.js";
2
+ export declare const sqlTools: Tool[];
3
+ //# sourceMappingURL=sqlAnalysis.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlAnalysis.d.ts","sourceRoot":"","sources":["../../../src/core/tools/sqlAnalysis.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAc,MAAM,YAAY,CAAC;AA6M9C,eAAO,MAAM,QAAQ,EAAE,IAAI,EA4F1B,CAAC"}
@@ -0,0 +1,250 @@
1
+ import * as fs from "fs";
2
+ import * as path from "path";
3
+ // SQL 쿼리 추출 및 분석
4
+ function analyzeJavaForSql(filePath) {
5
+ const content = fs.readFileSync(filePath, "utf-8");
6
+ const lines = content.split("\n");
7
+ const queries = [];
8
+ // @Query 어노테이션 찾기
9
+ const queryAnnotationRegex = /@Query\s*\(\s*(?:value\s*=\s*)?["'`]([^"'`]+)["'`]/g;
10
+ const nativeQueryRegex = /@Query\s*\([^)]*nativeQuery\s*=\s*true[^)]*value\s*=\s*["'`]([^"'`]+)["'`]/g;
11
+ const namedQueryRegex = /@NamedQuery\s*\([^)]*query\s*=\s*["'`]([^"'`]+)["'`]/g;
12
+ // JDBC/JPA 문자열 쿼리 찾기
13
+ const createQueryRegex = /(?:createQuery|createNativeQuery|prepareStatement)\s*\(\s*["'`]([^"'`]+)["'`]/g;
14
+ const jdbcExecuteRegex = /(?:executeQuery|executeUpdate|execute)\s*\(\s*["'`]([^"'`]+)["'`]/g;
15
+ // 문자열 변수에 할당된 SQL 찾기
16
+ const sqlStringRegex = /(?:String\s+)?(?:sql|query|hql|jpql)\s*=\s*["'`]([^"'`]*(?:SELECT|INSERT|UPDATE|DELETE|FROM|WHERE)[^"'`]*)["'`]/gi;
17
+ // 멀티라인 SQL 문자열 찾기
18
+ const multiLineSqlRegex = /["'`]\s*(SELECT|INSERT|UPDATE|DELETE)\s+[\s\S]*?["'`]\s*(?:\+\s*["'`][\s\S]*?["'`]\s*)*/gi;
19
+ const findLineNumber = (match) => {
20
+ const index = match.index;
21
+ let lineNum = 1;
22
+ for (let i = 0; i < index && i < content.length; i++) {
23
+ if (content[i] === "\n")
24
+ lineNum++;
25
+ }
26
+ return lineNum;
27
+ };
28
+ const analyzeQuery = (sql) => {
29
+ const issues = [];
30
+ const upperSql = sql.toUpperCase().trim();
31
+ // SELECT * 검사
32
+ if (/SELECT\s+\*\s+FROM/i.test(sql)) {
33
+ issues.push("SELECT * 사용 - 필요한 컬럼만 명시 권장");
34
+ }
35
+ // WHERE 절 없는 UPDATE/DELETE
36
+ if (/^(UPDATE|DELETE)\s+/i.test(upperSql) && !/WHERE/i.test(sql)) {
37
+ issues.push("WHERE 절 없음 - 전체 테이블 영향 위험");
38
+ }
39
+ // 서브쿼리 검사
40
+ const subqueryCount = (sql.match(/\(\s*SELECT/gi) || []).length;
41
+ if (subqueryCount >= 2) {
42
+ issues.push(`중첩 서브쿼리 ${subqueryCount}개 - 성능 저하 가능`);
43
+ }
44
+ // JOIN 개수 검사
45
+ const joinCount = (sql.match(/\bJOIN\b/gi) || []).length;
46
+ if (joinCount >= 4) {
47
+ issues.push(`JOIN ${joinCount}개 - 쿼리 복잡도 높음`);
48
+ }
49
+ // LIKE '%...' 패턴 (인덱스 미사용)
50
+ if (/LIKE\s+['"]%/i.test(sql)) {
51
+ issues.push("LIKE '%...' 패턴 - 인덱스 사용 불가");
52
+ }
53
+ // OR 조건 과다
54
+ const orCount = (sql.match(/\bOR\b/gi) || []).length;
55
+ if (orCount >= 3) {
56
+ issues.push(`OR 조건 ${orCount}개 - IN 절로 변환 검토`);
57
+ }
58
+ // ORDER BY RAND() 검사
59
+ if (/ORDER\s+BY\s+RAND\s*\(\)/i.test(sql)) {
60
+ issues.push("ORDER BY RAND() - 대용량 테이블에서 성능 저하");
61
+ }
62
+ // N+1 가능성 힌트 (단순 ID 조회)
63
+ if (/WHERE\s+\w+\.?id\s*=\s*[?:]/i.test(sql) && /SELECT/i.test(sql)) {
64
+ issues.push("단일 ID 조회 - 반복 호출 시 N+1 문제 가능");
65
+ }
66
+ // 문자열 연결 (SQL Injection 위험)
67
+ if (/\+\s*["']|["']\s*\+/.test(sql)) {
68
+ issues.push("문자열 연결 감지 - SQL Injection 위험");
69
+ }
70
+ return issues;
71
+ };
72
+ // @Query 어노테이션 처리
73
+ let match;
74
+ while ((match = queryAnnotationRegex.exec(content)) !== null) {
75
+ const query = match[1].replace(/\s+/g, " ").trim();
76
+ queries.push({
77
+ type: "jpql",
78
+ query,
79
+ location: "@Query",
80
+ line: findLineNumber(match),
81
+ issues: analyzeQuery(query),
82
+ });
83
+ }
84
+ // Native Query 처리
85
+ while ((match = nativeQueryRegex.exec(content)) !== null) {
86
+ const query = match[1].replace(/\s+/g, " ").trim();
87
+ queries.push({
88
+ type: "native",
89
+ query,
90
+ location: "@Query(nativeQuery)",
91
+ line: findLineNumber(match),
92
+ issues: analyzeQuery(query),
93
+ });
94
+ }
95
+ // @NamedQuery 처리
96
+ while ((match = namedQueryRegex.exec(content)) !== null) {
97
+ const query = match[1].replace(/\s+/g, " ").trim();
98
+ queries.push({
99
+ type: "jpa",
100
+ query,
101
+ location: "@NamedQuery",
102
+ line: findLineNumber(match),
103
+ issues: analyzeQuery(query),
104
+ });
105
+ }
106
+ // createQuery/prepareStatement 처리
107
+ while ((match = createQueryRegex.exec(content)) !== null) {
108
+ const query = match[1].replace(/\s+/g, " ").trim();
109
+ if (/SELECT|INSERT|UPDATE|DELETE/i.test(query)) {
110
+ queries.push({
111
+ type: "jdbc",
112
+ query,
113
+ location: "createQuery/prepareStatement",
114
+ line: findLineNumber(match),
115
+ issues: analyzeQuery(query),
116
+ });
117
+ }
118
+ }
119
+ // executeQuery 처리
120
+ while ((match = jdbcExecuteRegex.exec(content)) !== null) {
121
+ const query = match[1].replace(/\s+/g, " ").trim();
122
+ if (/SELECT|INSERT|UPDATE|DELETE/i.test(query)) {
123
+ queries.push({
124
+ type: "jdbc",
125
+ query,
126
+ location: "execute*",
127
+ line: findLineNumber(match),
128
+ issues: analyzeQuery(query),
129
+ });
130
+ }
131
+ }
132
+ // SQL 문자열 변수 처리
133
+ while ((match = sqlStringRegex.exec(content)) !== null) {
134
+ const query = match[1].replace(/\s+/g, " ").trim();
135
+ queries.push({
136
+ type: "jdbc",
137
+ query,
138
+ location: "String 변수",
139
+ line: findLineNumber(match),
140
+ issues: analyzeQuery(query),
141
+ });
142
+ }
143
+ // 이슈 통계
144
+ const issueTypes = {};
145
+ queries.forEach((q) => {
146
+ q.issues.forEach((issue) => {
147
+ const key = issue.split(" - ")[0];
148
+ issueTypes[key] = (issueTypes[key] || 0) + 1;
149
+ });
150
+ });
151
+ return {
152
+ file: filePath,
153
+ queries,
154
+ summary: {
155
+ total: queries.length,
156
+ withIssues: queries.filter((q) => q.issues.length > 0).length,
157
+ issueTypes,
158
+ },
159
+ };
160
+ }
161
+ // 도구 정의
162
+ export const sqlTools = [
163
+ {
164
+ name: "sql_check",
165
+ description: "Java 파일에서 SQL 쿼리를 추출하고 품질 검사합니다. @Query, JDBC, JPA 쿼리를 분석하여 SELECT *, 인덱스 미사용 패턴, N+1 가능성 등을 검출합니다.",
166
+ parameters: {
167
+ type: "object",
168
+ properties: {
169
+ path: {
170
+ type: "string",
171
+ description: "분석할 Java 파일 또는 디렉토리 경로",
172
+ },
173
+ recursive: {
174
+ type: "boolean",
175
+ description: "디렉토리인 경우 하위 폴더 포함 여부 (기본: true)",
176
+ },
177
+ },
178
+ required: ["path"],
179
+ },
180
+ handler: async (args) => {
181
+ const targetPath = args.path;
182
+ const recursive = args.recursive !== false;
183
+ if (!fs.existsSync(targetPath)) {
184
+ return {
185
+ success: false,
186
+ content: "",
187
+ error: `경로를 찾을 수 없습니다: ${targetPath}`,
188
+ };
189
+ }
190
+ const results = [];
191
+ const stats = fs.statSync(targetPath);
192
+ if (stats.isFile()) {
193
+ if (targetPath.endsWith(".java")) {
194
+ results.push(analyzeJavaForSql(targetPath));
195
+ }
196
+ }
197
+ else if (stats.isDirectory()) {
198
+ const walkDir = (dir) => {
199
+ const files = fs.readdirSync(dir);
200
+ for (const file of files) {
201
+ const filePath = path.join(dir, file);
202
+ const fileStat = fs.statSync(filePath);
203
+ if (fileStat.isDirectory() && recursive) {
204
+ if (!file.startsWith(".") && file !== "node_modules" && file !== "target" && file !== "build") {
205
+ walkDir(filePath);
206
+ }
207
+ }
208
+ else if (file.endsWith(".java")) {
209
+ const result = analyzeJavaForSql(filePath);
210
+ if (result.queries.length > 0) {
211
+ results.push(result);
212
+ }
213
+ }
214
+ }
215
+ };
216
+ walkDir(targetPath);
217
+ }
218
+ // 전체 통계
219
+ const totalQueries = results.reduce((sum, r) => sum + r.summary.total, 0);
220
+ const totalWithIssues = results.reduce((sum, r) => sum + r.summary.withIssues, 0);
221
+ const allIssueTypes = {};
222
+ results.forEach((r) => {
223
+ Object.entries(r.summary.issueTypes).forEach(([key, count]) => {
224
+ allIssueTypes[key] = (allIssueTypes[key] || 0) + count;
225
+ });
226
+ });
227
+ const output = {
228
+ analyzed: results.length,
229
+ totalQueries,
230
+ queriesWithIssues: totalWithIssues,
231
+ issueTypes: allIssueTypes,
232
+ files: results.map((r) => ({
233
+ file: r.file,
234
+ queries: r.queries.map((q) => ({
235
+ line: q.line,
236
+ type: q.type,
237
+ location: q.location,
238
+ query: q.query.length > 100 ? q.query.substring(0, 100) + "..." : q.query,
239
+ issues: q.issues,
240
+ })),
241
+ })),
242
+ };
243
+ return {
244
+ success: true,
245
+ content: JSON.stringify(output, null, 2),
246
+ };
247
+ },
248
+ },
249
+ ];
250
+ //# sourceMappingURL=sqlAnalysis.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlAnalysis.js","sourceRoot":"","sources":["../../../src/core/tools/sqlAnalysis.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "activo",
3
- "version": "0.2.2",
3
+ "version": "0.3.0",
4
4
  "description": "AI-powered code quality analyzer with React Ink TUI, Tool Calling, and MCP support",
5
5
  "repository": {
6
6
  "type": "git",
@@ -47,6 +47,7 @@
47
47
  "ink": "^6.1.0",
48
48
  "ink-spinner": "^5.0.0",
49
49
  "ink-text-input": "^6.0.0",
50
+ "java-ast": "^0.4.1",
50
51
  "pdf-parse": "^1.1.1",
51
52
  "react": "^19.1.0",
52
53
  "uuid": "^10.0.0"
@@ -235,4 +235,34 @@ export class OllamaClient {
235
235
  setModel(model: string): void {
236
236
  this.model = model;
237
237
  }
238
+
239
+ // Generate embeddings for text
240
+ async embed(text: string, model?: string): Promise<number[]> {
241
+ const response = await fetch(`${this.baseUrl}/api/embeddings`, {
242
+ method: "POST",
243
+ headers: { "Content-Type": "application/json" },
244
+ body: JSON.stringify({
245
+ model: model || "nomic-embed-text",
246
+ prompt: text,
247
+ }),
248
+ });
249
+
250
+ if (!response.ok) {
251
+ const error = await response.text();
252
+ throw new Error(`Ollama embedding error: ${error}`);
253
+ }
254
+
255
+ const data = (await response.json()) as { embedding: number[] };
256
+ return data.embedding;
257
+ }
258
+
259
+ // Generate embeddings for multiple texts (batch)
260
+ async embedBatch(texts: string[], model?: string): Promise<number[][]> {
261
+ const embeddings: number[][] = [];
262
+ for (const text of texts) {
263
+ const embedding = await this.embed(text, model);
264
+ embeddings.push(embedding);
265
+ }
266
+ return embeddings;
267
+ }
238
268
  }