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,118 +0,0 @@
1
- import { Config, loadConfig, saveConfig } from "./config.js";
2
-
3
- export interface SlashCommandResult {
4
- output?: string;
5
- exit?: boolean;
6
- clear?: boolean;
7
- changeModel?: string;
8
- showHelp?: boolean;
9
- }
10
-
11
- type CommandHandler = (args: string[], config: Config) => SlashCommandResult;
12
-
13
- const HELP_MESSAGE = `
14
- ACTIVO - AI 코드 품질 분석 도구
15
-
16
- [슬래시 커맨드]
17
- /help 이 도움말 표시
18
- /exit, /quit 종료
19
- /clear 채팅 기록 삭제
20
- /model <name> 모델 변경 (예: /model qwen2.5:7b)
21
- /info 현재 설정 정보 표시
22
-
23
- [단축키]
24
- Enter 메시지 전송
25
- ESC 진행 중 작업 취소
26
- Ctrl+C x2 종료
27
-
28
- [사용 예시]
29
- "src 폴더 구조 보여줘"
30
- "package.json 분석해줘"
31
- "코드 품질 검사해줘"
32
- "PDF를 마크다운으로 변환해줘"
33
- `.trim();
34
-
35
- const commandHandlers: Record<string, CommandHandler> = {
36
- help: () => ({
37
- output: HELP_MESSAGE,
38
- showHelp: true,
39
- }),
40
-
41
- exit: () => ({
42
- exit: true,
43
- output: "Goodbye!",
44
- }),
45
-
46
- quit: () => ({
47
- exit: true,
48
- output: "Goodbye!",
49
- }),
50
-
51
- clear: () => ({
52
- clear: true,
53
- output: "채팅 기록이 삭제되었습니다.",
54
- }),
55
-
56
- model: (args, config) => {
57
- if (args.length === 0) {
58
- return {
59
- output: `현재 모델: ${config.ollama.model}\n\n사용법: /model <model_name>\n예시: /model qwen2.5:7b`,
60
- };
61
- }
62
-
63
- const newModel = args[0];
64
- config.ollama.model = newModel;
65
- saveConfig(config);
66
-
67
- return {
68
- changeModel: newModel,
69
- output: `모델이 "${newModel}"로 변경되었습니다.`,
70
- };
71
- },
72
-
73
- info: (args, config) => {
74
- const info = `
75
- [ACTIVO 정보]
76
- 버전: 0.2.1
77
-
78
- [Ollama 설정]
79
- URL: ${config.ollama.baseUrl}
80
- 모델: ${config.ollama.model}
81
- 컨텍스트: ${config.ollama.contextLength}
82
-
83
- [표준 디렉토리]
84
- ${config.standards.directory}
85
- `.trim();
86
-
87
- return { output: info };
88
- },
89
- };
90
-
91
- export function handleSlashCommand(
92
- input: string,
93
- config: Config
94
- ): SlashCommandResult | null {
95
- // "/" 로 시작하지 않으면 null 반환
96
- if (!input.startsWith("/")) {
97
- return null;
98
- }
99
-
100
- // 파싱: "/" 제거 후 공백으로 분할
101
- const trimmed = input.slice(1).trim();
102
- const [command, ...args] = trimmed.split(/\s+/);
103
-
104
- if (!command) {
105
- return { output: "명령어를 입력하세요. /help 로 도움말을 확인하세요." };
106
- }
107
-
108
- const handler = commandHandlers[command.toLowerCase()];
109
- if (handler) {
110
- return handler(args, config);
111
- }
112
-
113
- return { output: `알 수 없는 명령어: /${command}\n/help 로 사용 가능한 명령어를 확인하세요.` };
114
- }
115
-
116
- export function getAvailableCommands(): string[] {
117
- return Object.keys(commandHandlers);
118
- }
@@ -1,98 +0,0 @@
1
- import fs from "fs";
2
- import path from "path";
3
- import os from "os";
4
-
5
- export interface OllamaConfig {
6
- baseUrl: string;
7
- model: string;
8
- contextLength: number;
9
- keepAlive: number;
10
- }
11
-
12
- export interface Config {
13
- ollama: OllamaConfig;
14
- standards: {
15
- directory: string;
16
- };
17
- mcp: {
18
- servers: Record<string, MCPServerConfig>;
19
- };
20
- }
21
-
22
- export interface MCPServerConfig {
23
- command: string;
24
- args?: string[];
25
- env?: Record<string, string>;
26
- }
27
-
28
- const DEFAULT_CONFIG: Config = {
29
- ollama: {
30
- baseUrl: "http://localhost:11434",
31
- model: "mistral:latest",
32
- contextLength: 4096,
33
- keepAlive: 1800, // 30 minutes
34
- },
35
- standards: {
36
- directory: ".activo/standards",
37
- },
38
- mcp: {
39
- servers: {},
40
- },
41
- };
42
-
43
- function getConfigPath(): string {
44
- return path.join(os.homedir(), ".activo", "config.json");
45
- }
46
-
47
- export function loadConfig(): Config {
48
- const configPath = getConfigPath();
49
-
50
- if (fs.existsSync(configPath)) {
51
- try {
52
- const data = fs.readFileSync(configPath, "utf-8");
53
- const loaded = JSON.parse(data);
54
- return {
55
- ollama: { ...DEFAULT_CONFIG.ollama, ...loaded.ollama },
56
- standards: { ...DEFAULT_CONFIG.standards, ...loaded.standards },
57
- mcp: { ...DEFAULT_CONFIG.mcp, ...loaded.mcp },
58
- };
59
- } catch {
60
- return DEFAULT_CONFIG;
61
- }
62
- }
63
-
64
- return DEFAULT_CONFIG;
65
- }
66
-
67
- export function saveConfig(config: Config): void {
68
- const configPath = getConfigPath();
69
- const configDir = path.dirname(configPath);
70
-
71
- if (!fs.existsSync(configDir)) {
72
- fs.mkdirSync(configDir, { recursive: true });
73
- }
74
-
75
- fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
76
- }
77
-
78
- export function getProjectConfig(): Config {
79
- const projectConfigPath = path.join(process.cwd(), ".activo", "config.json");
80
-
81
- if (fs.existsSync(projectConfigPath)) {
82
- try {
83
- const data = fs.readFileSync(projectConfigPath, "utf-8");
84
- const projectConfig = JSON.parse(data);
85
- const globalConfig = loadConfig();
86
-
87
- return {
88
- ollama: { ...globalConfig.ollama, ...projectConfig.ollama },
89
- standards: { ...globalConfig.standards, ...projectConfig.standards },
90
- mcp: { ...globalConfig.mcp, ...projectConfig.mcp },
91
- };
92
- } catch {
93
- return loadConfig();
94
- }
95
- }
96
-
97
- return loadConfig();
98
- }
@@ -1,235 +0,0 @@
1
- import fs from "fs";
2
- import path from "path";
3
- import { ChatMessage, OllamaClient } from "./llm/ollama.js";
4
-
5
- // Conversation storage directory
6
- const CONVERSATION_DIR = ".activo/conversations";
7
-
8
- // Session data interface
9
- interface SessionData {
10
- id: string;
11
- startedAt: string;
12
- updatedAt: string;
13
- messages: ChatMessage[];
14
- summary?: string;
15
- }
16
-
17
- // Get conversation directory path
18
- function getConversationDir(): string {
19
- return path.resolve(process.cwd(), CONVERSATION_DIR);
20
- }
21
-
22
- // Ensure conversation directory exists
23
- function ensureConversationDir(): void {
24
- const dir = getConversationDir();
25
- if (!fs.existsSync(dir)) {
26
- fs.mkdirSync(dir, { recursive: true });
27
- }
28
- }
29
-
30
- // Generate session ID
31
- export function generateSessionId(): string {
32
- return `session_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
33
- }
34
-
35
- // Get session file path
36
- function getSessionPath(sessionId: string): string {
37
- return path.join(getConversationDir(), `${sessionId}.json`);
38
- }
39
-
40
- // Get latest session file
41
- function getLatestSessionPath(): string | null {
42
- const dir = getConversationDir();
43
- if (!fs.existsSync(dir)) {
44
- return null;
45
- }
46
-
47
- const files = fs.readdirSync(dir)
48
- .filter(f => f.startsWith("session_") && f.endsWith(".json"))
49
- .sort()
50
- .reverse();
51
-
52
- if (files.length === 0) {
53
- return null;
54
- }
55
-
56
- return path.join(dir, files[0]);
57
- }
58
-
59
- // Load session data
60
- export function loadSession(sessionId: string): SessionData | null {
61
- const sessionPath = getSessionPath(sessionId);
62
- if (!fs.existsSync(sessionPath)) {
63
- return null;
64
- }
65
-
66
- try {
67
- return JSON.parse(fs.readFileSync(sessionPath, "utf-8"));
68
- } catch {
69
- return null;
70
- }
71
- }
72
-
73
- // Load latest session
74
- export function loadLatestSession(): SessionData | null {
75
- const latestPath = getLatestSessionPath();
76
- if (!latestPath) {
77
- return null;
78
- }
79
-
80
- try {
81
- return JSON.parse(fs.readFileSync(latestPath, "utf-8"));
82
- } catch {
83
- return null;
84
- }
85
- }
86
-
87
- // Save session data
88
- export function saveSession(session: SessionData): void {
89
- ensureConversationDir();
90
- session.updatedAt = new Date().toISOString();
91
- fs.writeFileSync(getSessionPath(session.id), JSON.stringify(session, null, 2));
92
- }
93
-
94
- // Create new session
95
- export function createSession(): SessionData {
96
- return {
97
- id: generateSessionId(),
98
- startedAt: new Date().toISOString(),
99
- updatedAt: new Date().toISOString(),
100
- messages: [],
101
- };
102
- }
103
-
104
- // Add message to session
105
- export function addMessageToSession(session: SessionData, message: ChatMessage): void {
106
- session.messages.push(message);
107
- saveSession(session);
108
- }
109
-
110
- // Summarize old messages using LLM
111
- async function summarizeMessages(
112
- messages: ChatMessage[],
113
- client: OllamaClient
114
- ): Promise<string> {
115
- if (messages.length === 0) {
116
- return "";
117
- }
118
-
119
- // Format messages for summarization
120
- const conversationText = messages
121
- .filter(m => m.role !== "system" && m.role !== "tool")
122
- .map(m => {
123
- if (m.role === "user") {
124
- return `사용자: ${m.content}`;
125
- } else if (m.role === "assistant") {
126
- const toolInfo = m.toolCalls?.length
127
- ? ` [도구 호출: ${m.toolCalls.map(t => t.name).join(", ")}]`
128
- : "";
129
- return `어시스턴트: ${m.content.slice(0, 200)}${m.content.length > 200 ? "..." : ""}${toolInfo}`;
130
- }
131
- return "";
132
- })
133
- .filter(s => s)
134
- .join("\n");
135
-
136
- const summaryPrompt = `다음 대화를 3-5개의 핵심 포인트로 요약해주세요. 한국어로 작성하고, 각 포인트는 한 줄로 작성하세요.
137
-
138
- 대화:
139
- ${conversationText}
140
-
141
- 요약 (핵심 포인트만):`;
142
-
143
- try {
144
- const response = await client.chat([
145
- { role: "user", content: summaryPrompt }
146
- ]);
147
- return response.content.trim();
148
- } catch (error) {
149
- // Fallback: simple extraction
150
- const userMessages = messages
151
- .filter(m => m.role === "user")
152
- .map(m => m.content.slice(0, 50))
153
- .slice(-3);
154
- return `이전 요청: ${userMessages.join(", ")}`;
155
- }
156
- }
157
-
158
- // Get context for new session (hybrid approach)
159
- export async function getSessionContext(
160
- client: OllamaClient,
161
- recentCount: number = 5
162
- ): Promise<{ summary: string; recentMessages: ChatMessage[] }> {
163
- const latestSession = loadLatestSession();
164
-
165
- if (!latestSession || latestSession.messages.length === 0) {
166
- return { summary: "", recentMessages: [] };
167
- }
168
-
169
- const allMessages = latestSession.messages;
170
-
171
- // Filter out system messages for context
172
- const contextMessages = allMessages.filter(m => m.role !== "system");
173
-
174
- if (contextMessages.length <= recentCount) {
175
- // Not enough messages to summarize, return all as recent
176
- return {
177
- summary: latestSession.summary || "",
178
- recentMessages: contextMessages
179
- };
180
- }
181
-
182
- // Split: old messages for summary, recent messages to keep
183
- const oldMessages = contextMessages.slice(0, -recentCount);
184
- const recentMessages = contextMessages.slice(-recentCount);
185
-
186
- // Generate or use existing summary
187
- let summary = latestSession.summary || "";
188
-
189
- if (oldMessages.length > 0 && !summary) {
190
- summary = await summarizeMessages(oldMessages, client);
191
- // Save summary back to session
192
- latestSession.summary = summary;
193
- saveSession(latestSession);
194
- }
195
-
196
- return { summary, recentMessages };
197
- }
198
-
199
- // Build context string for system prompt
200
- export function buildContextPrompt(summary: string): string {
201
- if (!summary) {
202
- return "";
203
- }
204
-
205
- return `
206
- ## 이전 대화 컨텍스트
207
-
208
- ${summary}
209
-
210
- ---
211
- 위 내용은 이전 세션에서의 대화 요약입니다. 필요시 참고하세요.
212
- `;
213
- }
214
-
215
- // Clean old sessions (keep only last N)
216
- export function cleanOldSessions(keepCount: number = 10): void {
217
- const dir = getConversationDir();
218
- if (!fs.existsSync(dir)) {
219
- return;
220
- }
221
-
222
- const files = fs.readdirSync(dir)
223
- .filter(f => f.startsWith("session_") && f.endsWith(".json"))
224
- .sort()
225
- .reverse();
226
-
227
- // Delete old sessions beyond keepCount
228
- for (let i = keepCount; i < files.length; i++) {
229
- try {
230
- fs.unlinkSync(path.join(dir, files[i]));
231
- } catch {
232
- // Ignore deletion errors
233
- }
234
- }
235
- }