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.
- package/README.md +203 -1
- package/data/2026-03-04_20-54.json +181 -0
- package/data/2026-03-04_20-56.json +181 -0
- package/data/apex-rulesets/egov.yaml +469 -0
- package/data/apex-rulesets/modernize.yaml +687 -0
- package/data/apex-rulesets/quality.yaml +1677 -0
- package/data/apex-rulesets/rule-schema.yaml +587 -0
- package/data/apex-rulesets/secure.yaml +1688 -0
- package/data/apex-rulesets/spring.yaml +455 -0
- package/data/apex-rulesets/sql-format.yaml +99 -0
- package/data/apex-rulesets/sql-oracle.yaml +281 -0
- package/data/apex-rulesets/sql.yaml +1660 -0
- package/dist/cli/headless.d.ts.map +1 -1
- package/dist/cli/headless.js +32 -10
- package/dist/cli/headless.js.map +1 -1
- package/dist/cli/index.js +31 -3
- package/dist/cli/index.js.map +1 -1
- package/dist/core/agent.d.ts +3 -3
- package/dist/core/agent.d.ts.map +1 -1
- package/dist/core/agent.js +255 -17
- package/dist/core/agent.js.map +1 -1
- package/dist/core/commands.d.ts +2 -1
- package/dist/core/commands.d.ts.map +1 -1
- package/dist/core/commands.js +61 -9
- package/dist/core/commands.js.map +1 -1
- package/dist/core/config.d.ts +14 -0
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +41 -4
- package/dist/core/config.js.map +1 -1
- package/dist/core/conversation.d.ts +2 -2
- package/dist/core/conversation.d.ts.map +1 -1
- package/dist/core/conversation.js.map +1 -1
- package/dist/core/intentRouter.d.ts +43 -0
- package/dist/core/intentRouter.d.ts.map +1 -0
- package/dist/core/intentRouter.js +804 -0
- package/dist/core/intentRouter.js.map +1 -0
- package/dist/core/llm/anthropic.d.ts +24 -0
- package/dist/core/llm/anthropic.d.ts.map +1 -0
- package/dist/core/llm/anthropic.js +226 -0
- package/dist/core/llm/anthropic.js.map +1 -0
- package/dist/core/llm/ollama.d.ts +5 -14
- package/dist/core/llm/ollama.d.ts.map +1 -1
- package/dist/core/llm/ollama.js +3 -0
- package/dist/core/llm/ollama.js.map +1 -1
- package/dist/core/llm/types.d.ts +22 -0
- package/dist/core/llm/types.d.ts.map +1 -0
- package/dist/core/llm/types.js +2 -0
- package/dist/core/llm/types.js.map +1 -0
- package/dist/core/mcp/client.d.ts +6 -0
- package/dist/core/mcp/client.d.ts.map +1 -1
- package/dist/core/mcp/client.js +16 -0
- package/dist/core/mcp/client.js.map +1 -1
- package/dist/core/mcp/init.d.ts +12 -0
- package/dist/core/mcp/init.d.ts.map +1 -0
- package/dist/core/mcp/init.js +55 -0
- package/dist/core/mcp/init.js.map +1 -0
- package/dist/core/mcp/logger.d.ts +14 -0
- package/dist/core/mcp/logger.d.ts.map +1 -0
- package/dist/core/mcp/logger.js +50 -0
- package/dist/core/mcp/logger.js.map +1 -0
- package/dist/core/tools/analyzeAll.d.ts.map +1 -1
- package/dist/core/tools/analyzeAll.js +16 -28
- package/dist/core/tools/analyzeAll.js.map +1 -1
- package/dist/core/tools/analyzePatterns.d.ts +3 -0
- package/dist/core/tools/analyzePatterns.d.ts.map +1 -0
- package/dist/core/tools/analyzePatterns.js +293 -0
- package/dist/core/tools/analyzePatterns.js.map +1 -0
- package/dist/core/tools/apexPaths.d.ts +14 -0
- package/dist/core/tools/apexPaths.d.ts.map +1 -0
- package/dist/core/tools/apexPaths.js +54 -0
- package/dist/core/tools/apexPaths.js.map +1 -0
- package/dist/core/tools/apexUtils.d.ts +36 -0
- package/dist/core/tools/apexUtils.d.ts.map +1 -0
- package/dist/core/tools/apexUtils.js +83 -0
- package/dist/core/tools/apexUtils.js.map +1 -0
- package/dist/core/tools/explainIssue.d.ts +3 -0
- package/dist/core/tools/explainIssue.d.ts.map +1 -0
- package/dist/core/tools/explainIssue.js +181 -0
- package/dist/core/tools/explainIssue.js.map +1 -0
- package/dist/core/tools/fixGen.d.ts +3 -0
- package/dist/core/tools/fixGen.d.ts.map +1 -0
- package/dist/core/tools/fixGen.js +338 -0
- package/dist/core/tools/fixGen.js.map +1 -0
- package/dist/core/tools/generateImprovements.d.ts +21 -0
- package/dist/core/tools/generateImprovements.d.ts.map +1 -0
- package/dist/core/tools/generateImprovements.js +602 -0
- package/dist/core/tools/generateImprovements.js.map +1 -0
- package/dist/core/tools/generateReport.d.ts +3 -0
- package/dist/core/tools/generateReport.d.ts.map +1 -0
- package/dist/core/tools/generateReport.js +315 -0
- package/dist/core/tools/generateReport.js.map +1 -0
- package/dist/core/tools/index.d.ts +7 -0
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js +62 -23
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/javaAst.d.ts.map +1 -1
- package/dist/core/tools/javaAst.js +191 -0
- package/dist/core/tools/javaAst.js.map +1 -1
- package/dist/core/tools/recommendProfile.d.ts +3 -0
- package/dist/core/tools/recommendProfile.d.ts.map +1 -0
- package/dist/core/tools/recommendProfile.js +334 -0
- package/dist/core/tools/recommendProfile.js.map +1 -0
- package/dist/core/tools/ruleGen.d.ts +3 -0
- package/dist/core/tools/ruleGen.d.ts.map +1 -0
- package/dist/core/tools/ruleGen.js +1103 -0
- package/dist/core/tools/ruleGen.js.map +1 -0
- package/dist/core/tools/standards.d.ts.map +1 -1
- package/dist/core/tools/standards.js +7 -3
- package/dist/core/tools/standards.js.map +1 -1
- package/dist/ui/App.d.ts.map +1 -1
- package/dist/ui/App.js +86 -35
- package/dist/ui/App.js.map +1 -1
- package/dist/ui/components/InputBox.d.ts +1 -3
- package/dist/ui/components/InputBox.d.ts.map +1 -1
- package/dist/ui/components/InputBox.js +146 -5
- package/dist/ui/components/InputBox.js.map +1 -1
- package/dist/ui/components/MessageList.d.ts +3 -1
- package/dist/ui/components/MessageList.d.ts.map +1 -1
- package/dist/ui/components/MessageList.js +13 -7
- package/dist/ui/components/MessageList.js.map +1 -1
- package/dist/ui/components/StatusBar.d.ts +1 -1
- package/dist/ui/components/StatusBar.d.ts.map +1 -1
- package/dist/ui/components/StatusBar.js +3 -2
- package/dist/ui/components/StatusBar.js.map +1 -1
- package/dist/ui/components/ToolStatus.d.ts +3 -1
- package/dist/ui/components/ToolStatus.d.ts.map +1 -1
- package/dist/ui/components/ToolStatus.js +19 -4
- package/dist/ui/components/ToolStatus.js.map +1 -1
- package/package.json +7 -1
- package/demo.gif +0 -0
- package/demo.tape +0 -53
- package/screenshot.png +0 -0
- package/src/cli/banner.ts +0 -38
- package/src/cli/headless.ts +0 -63
- package/src/cli/index.ts +0 -57
- package/src/core/agent.ts +0 -237
- package/src/core/commands.ts +0 -118
- package/src/core/config.ts +0 -98
- package/src/core/conversation.ts +0 -235
- package/src/core/llm/ollama.ts +0 -351
- package/src/core/mcp/client.ts +0 -143
- package/src/core/tools/analyzeAll.ts +0 -494
- package/src/core/tools/ast.ts +0 -826
- package/src/core/tools/builtIn.ts +0 -221
- package/src/core/tools/cache.ts +0 -570
- package/src/core/tools/cssAnalysis.ts +0 -324
- package/src/core/tools/dependencyAnalysis.ts +0 -363
- package/src/core/tools/embeddings.ts +0 -746
- package/src/core/tools/frontendAst.ts +0 -802
- package/src/core/tools/htmlAnalysis.ts +0 -466
- package/src/core/tools/index.ts +0 -160
- package/src/core/tools/javaAst.ts +0 -812
- package/src/core/tools/memory.ts +0 -655
- package/src/core/tools/mybatisAnalysis.ts +0 -322
- package/src/core/tools/openapiAnalysis.ts +0 -431
- package/src/core/tools/pythonAnalysis.ts +0 -477
- package/src/core/tools/sqlAnalysis.ts +0 -298
- package/src/core/tools/standards.test.ts +0 -186
- package/src/core/tools/standards.ts +0 -889
- package/src/core/tools/types.ts +0 -38
- package/src/ui/App.tsx +0 -334
- package/src/ui/components/InputBox.tsx +0 -37
- package/src/ui/components/MessageList.tsx +0 -80
- package/src/ui/components/StatusBar.tsx +0 -36
- package/src/ui/components/ToolStatus.tsx +0 -38
- package/tsconfig.json +0 -21
package/src/core/tools/memory.ts
DELETED
|
@@ -1,655 +0,0 @@
|
|
|
1
|
-
import fs from "fs";
|
|
2
|
-
import path from "path";
|
|
3
|
-
import { Tool, ToolResult } from "./types.js";
|
|
4
|
-
|
|
5
|
-
// Memory directory
|
|
6
|
-
const MEMORY_DIR = ".activo/memory";
|
|
7
|
-
|
|
8
|
-
// Project context interface
|
|
9
|
-
interface ProjectContext {
|
|
10
|
-
name: string;
|
|
11
|
-
rootPath: string;
|
|
12
|
-
description?: string;
|
|
13
|
-
techStack: string[];
|
|
14
|
-
keyFiles: Array<{
|
|
15
|
-
path: string;
|
|
16
|
-
description: string;
|
|
17
|
-
}>;
|
|
18
|
-
conventions: string[];
|
|
19
|
-
lastUpdated: string;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
// Conversation summary interface
|
|
23
|
-
interface ConversationSummary {
|
|
24
|
-
id: string;
|
|
25
|
-
date: string;
|
|
26
|
-
topics: string[];
|
|
27
|
-
keyFindings: string[];
|
|
28
|
-
decisions: string[];
|
|
29
|
-
todos: string[];
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// Memory store interface
|
|
33
|
-
interface MemoryStore {
|
|
34
|
-
version: string;
|
|
35
|
-
project: ProjectContext;
|
|
36
|
-
conversations: ConversationSummary[];
|
|
37
|
-
notes: Array<{
|
|
38
|
-
id: string;
|
|
39
|
-
title: string;
|
|
40
|
-
content: string;
|
|
41
|
-
tags: string[];
|
|
42
|
-
createdAt: string;
|
|
43
|
-
}>;
|
|
44
|
-
facts: Array<{
|
|
45
|
-
key: string;
|
|
46
|
-
value: string;
|
|
47
|
-
source: string;
|
|
48
|
-
createdAt: string;
|
|
49
|
-
}>;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// Get memory directory path
|
|
53
|
-
function getMemoryDir(): string {
|
|
54
|
-
return path.resolve(process.cwd(), MEMORY_DIR);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// Get memory file path
|
|
58
|
-
function getMemoryPath(): string {
|
|
59
|
-
return path.join(getMemoryDir(), "store.json");
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// Ensure memory directory exists
|
|
63
|
-
function ensureMemoryDir(): void {
|
|
64
|
-
const dir = getMemoryDir();
|
|
65
|
-
if (!fs.existsSync(dir)) {
|
|
66
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// Load memory store
|
|
71
|
-
function loadMemory(): MemoryStore {
|
|
72
|
-
const memoryPath = getMemoryPath();
|
|
73
|
-
if (fs.existsSync(memoryPath)) {
|
|
74
|
-
try {
|
|
75
|
-
return JSON.parse(fs.readFileSync(memoryPath, "utf-8"));
|
|
76
|
-
} catch {
|
|
77
|
-
return createDefaultMemory();
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
return createDefaultMemory();
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// Create default memory
|
|
84
|
-
function createDefaultMemory(): MemoryStore {
|
|
85
|
-
return {
|
|
86
|
-
version: "1.0",
|
|
87
|
-
project: {
|
|
88
|
-
name: path.basename(process.cwd()),
|
|
89
|
-
rootPath: process.cwd(),
|
|
90
|
-
techStack: [],
|
|
91
|
-
keyFiles: [],
|
|
92
|
-
conventions: [],
|
|
93
|
-
lastUpdated: new Date().toISOString(),
|
|
94
|
-
},
|
|
95
|
-
conversations: [],
|
|
96
|
-
notes: [],
|
|
97
|
-
facts: [],
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// Save memory store
|
|
102
|
-
function saveMemory(memory: MemoryStore): void {
|
|
103
|
-
ensureMemoryDir();
|
|
104
|
-
fs.writeFileSync(getMemoryPath(), JSON.stringify(memory, null, 2));
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// Generate unique ID
|
|
108
|
-
function generateId(): string {
|
|
109
|
-
return `${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// Initialize/Update Project Context Tool
|
|
113
|
-
export const initProjectTool: Tool = {
|
|
114
|
-
name: "init_project_memory",
|
|
115
|
-
description: "Initialize or update project context in memory (프로젝트 컨텍스트 초기화). Stores project info like tech stack, key files. Use when user asks: 'remember project', 'init memory', '프로젝트 기억', '컨텍스트 저장'.",
|
|
116
|
-
parameters: {
|
|
117
|
-
type: "object",
|
|
118
|
-
properties: {
|
|
119
|
-
description: {
|
|
120
|
-
type: "string",
|
|
121
|
-
description: "Project description",
|
|
122
|
-
},
|
|
123
|
-
techStack: {
|
|
124
|
-
type: "string",
|
|
125
|
-
description: "Comma-separated tech stack (e.g., 'TypeScript, React, Node.js')",
|
|
126
|
-
},
|
|
127
|
-
conventions: {
|
|
128
|
-
type: "string",
|
|
129
|
-
description: "Comma-separated coding conventions",
|
|
130
|
-
},
|
|
131
|
-
},
|
|
132
|
-
},
|
|
133
|
-
handler: async (args): Promise<ToolResult> => {
|
|
134
|
-
try {
|
|
135
|
-
const memory = loadMemory();
|
|
136
|
-
|
|
137
|
-
if (args.description) {
|
|
138
|
-
memory.project.description = args.description as string;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
if (args.techStack) {
|
|
142
|
-
memory.project.techStack = (args.techStack as string)
|
|
143
|
-
.split(",")
|
|
144
|
-
.map((s) => s.trim())
|
|
145
|
-
.filter((s) => s);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
if (args.conventions) {
|
|
149
|
-
memory.project.conventions = (args.conventions as string)
|
|
150
|
-
.split(",")
|
|
151
|
-
.map((s) => s.trim())
|
|
152
|
-
.filter((s) => s);
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
memory.project.lastUpdated = new Date().toISOString();
|
|
156
|
-
saveMemory(memory);
|
|
157
|
-
|
|
158
|
-
const lines: string[] = [];
|
|
159
|
-
lines.push("=== 프로젝트 컨텍스트 저장됨 ===");
|
|
160
|
-
lines.push("");
|
|
161
|
-
lines.push(`📁 프로젝트: ${memory.project.name}`);
|
|
162
|
-
if (memory.project.description) {
|
|
163
|
-
lines.push(`📝 설명: ${memory.project.description}`);
|
|
164
|
-
}
|
|
165
|
-
if (memory.project.techStack.length > 0) {
|
|
166
|
-
lines.push(`🛠️ 기술 스택: ${memory.project.techStack.join(", ")}`);
|
|
167
|
-
}
|
|
168
|
-
if (memory.project.conventions.length > 0) {
|
|
169
|
-
lines.push(`📋 컨벤션: ${memory.project.conventions.join(", ")}`);
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
return { success: true, content: lines.join("\n") };
|
|
173
|
-
} catch (error) {
|
|
174
|
-
return { success: false, content: "", error: String(error) };
|
|
175
|
-
}
|
|
176
|
-
},
|
|
177
|
-
};
|
|
178
|
-
|
|
179
|
-
// Add Key File Tool
|
|
180
|
-
export const addKeyFileTool: Tool = {
|
|
181
|
-
name: "add_key_file",
|
|
182
|
-
description: "Mark a file as important with description (중요 파일 등록). Use when user asks: 'remember this file', 'mark as important', '이 파일 기억', '중요 파일'.",
|
|
183
|
-
parameters: {
|
|
184
|
-
type: "object",
|
|
185
|
-
required: ["filepath", "description"],
|
|
186
|
-
properties: {
|
|
187
|
-
filepath: {
|
|
188
|
-
type: "string",
|
|
189
|
-
description: "Path to the file",
|
|
190
|
-
},
|
|
191
|
-
description: {
|
|
192
|
-
type: "string",
|
|
193
|
-
description: "What this file does / why it's important",
|
|
194
|
-
},
|
|
195
|
-
},
|
|
196
|
-
},
|
|
197
|
-
handler: async (args): Promise<ToolResult> => {
|
|
198
|
-
try {
|
|
199
|
-
const filepath = args.filepath as string;
|
|
200
|
-
const description = args.description as string;
|
|
201
|
-
|
|
202
|
-
const memory = loadMemory();
|
|
203
|
-
|
|
204
|
-
// Remove if already exists
|
|
205
|
-
memory.project.keyFiles = memory.project.keyFiles.filter(
|
|
206
|
-
(f) => f.path !== filepath
|
|
207
|
-
);
|
|
208
|
-
|
|
209
|
-
// Add new
|
|
210
|
-
memory.project.keyFiles.push({ path: filepath, description });
|
|
211
|
-
memory.project.lastUpdated = new Date().toISOString();
|
|
212
|
-
saveMemory(memory);
|
|
213
|
-
|
|
214
|
-
return {
|
|
215
|
-
success: true,
|
|
216
|
-
content: `✅ 중요 파일 등록됨: ${filepath}\n 설명: ${description}`,
|
|
217
|
-
};
|
|
218
|
-
} catch (error) {
|
|
219
|
-
return { success: false, content: "", error: String(error) };
|
|
220
|
-
}
|
|
221
|
-
},
|
|
222
|
-
};
|
|
223
|
-
|
|
224
|
-
// Add Note Tool
|
|
225
|
-
export const addNoteTool: Tool = {
|
|
226
|
-
name: "add_note",
|
|
227
|
-
description: "Save a note/finding about the codebase (노트 저장). Use when user asks: 'remember this', 'save note', 'note that', '기억해', '메모해', '노트'.",
|
|
228
|
-
parameters: {
|
|
229
|
-
type: "object",
|
|
230
|
-
required: ["title", "content"],
|
|
231
|
-
properties: {
|
|
232
|
-
title: {
|
|
233
|
-
type: "string",
|
|
234
|
-
description: "Note title",
|
|
235
|
-
},
|
|
236
|
-
content: {
|
|
237
|
-
type: "string",
|
|
238
|
-
description: "Note content",
|
|
239
|
-
},
|
|
240
|
-
tags: {
|
|
241
|
-
type: "string",
|
|
242
|
-
description: "Comma-separated tags",
|
|
243
|
-
},
|
|
244
|
-
},
|
|
245
|
-
},
|
|
246
|
-
handler: async (args): Promise<ToolResult> => {
|
|
247
|
-
try {
|
|
248
|
-
const title = args.title as string;
|
|
249
|
-
const content = args.content as string;
|
|
250
|
-
const tags = args.tags
|
|
251
|
-
? (args.tags as string).split(",").map((t) => t.trim())
|
|
252
|
-
: [];
|
|
253
|
-
|
|
254
|
-
const memory = loadMemory();
|
|
255
|
-
memory.notes.push({
|
|
256
|
-
id: generateId(),
|
|
257
|
-
title,
|
|
258
|
-
content,
|
|
259
|
-
tags,
|
|
260
|
-
createdAt: new Date().toISOString(),
|
|
261
|
-
});
|
|
262
|
-
saveMemory(memory);
|
|
263
|
-
|
|
264
|
-
return {
|
|
265
|
-
success: true,
|
|
266
|
-
content: `✅ 노트 저장됨: "${title}"\n 태그: ${tags.length > 0 ? tags.join(", ") : "(없음)"}`,
|
|
267
|
-
};
|
|
268
|
-
} catch (error) {
|
|
269
|
-
return { success: false, content: "", error: String(error) };
|
|
270
|
-
}
|
|
271
|
-
},
|
|
272
|
-
};
|
|
273
|
-
|
|
274
|
-
// Add Fact Tool
|
|
275
|
-
export const addFactTool: Tool = {
|
|
276
|
-
name: "add_fact",
|
|
277
|
-
description: "Store a fact about the codebase (사실 저장). Key-value pairs like 'main entry point = src/index.ts'. Use when user asks: 'remember that X is Y', '기억해', 'store fact'.",
|
|
278
|
-
parameters: {
|
|
279
|
-
type: "object",
|
|
280
|
-
required: ["key", "value"],
|
|
281
|
-
properties: {
|
|
282
|
-
key: {
|
|
283
|
-
type: "string",
|
|
284
|
-
description: "Fact key/name",
|
|
285
|
-
},
|
|
286
|
-
value: {
|
|
287
|
-
type: "string",
|
|
288
|
-
description: "Fact value",
|
|
289
|
-
},
|
|
290
|
-
source: {
|
|
291
|
-
type: "string",
|
|
292
|
-
description: "Where this fact came from (file, conversation, etc.)",
|
|
293
|
-
},
|
|
294
|
-
},
|
|
295
|
-
},
|
|
296
|
-
handler: async (args): Promise<ToolResult> => {
|
|
297
|
-
try {
|
|
298
|
-
const key = args.key as string;
|
|
299
|
-
const value = args.value as string;
|
|
300
|
-
const source = (args.source as string) || "user";
|
|
301
|
-
|
|
302
|
-
const memory = loadMemory();
|
|
303
|
-
|
|
304
|
-
// Update if exists, otherwise add
|
|
305
|
-
const existingIdx = memory.facts.findIndex((f) => f.key === key);
|
|
306
|
-
if (existingIdx >= 0) {
|
|
307
|
-
memory.facts[existingIdx] = {
|
|
308
|
-
key,
|
|
309
|
-
value,
|
|
310
|
-
source,
|
|
311
|
-
createdAt: new Date().toISOString(),
|
|
312
|
-
};
|
|
313
|
-
} else {
|
|
314
|
-
memory.facts.push({
|
|
315
|
-
key,
|
|
316
|
-
value,
|
|
317
|
-
source,
|
|
318
|
-
createdAt: new Date().toISOString(),
|
|
319
|
-
});
|
|
320
|
-
}
|
|
321
|
-
saveMemory(memory);
|
|
322
|
-
|
|
323
|
-
return {
|
|
324
|
-
success: true,
|
|
325
|
-
content: `✅ 사실 저장됨: ${key} = ${value}`,
|
|
326
|
-
};
|
|
327
|
-
} catch (error) {
|
|
328
|
-
return { success: false, content: "", error: String(error) };
|
|
329
|
-
}
|
|
330
|
-
},
|
|
331
|
-
};
|
|
332
|
-
|
|
333
|
-
// Save Conversation Summary Tool
|
|
334
|
-
export const saveConversationTool: Tool = {
|
|
335
|
-
name: "save_conversation",
|
|
336
|
-
description: "Save a summary of the current conversation (대화 요약 저장). Use at end of session or when switching topics. Use when user asks: 'save session', 'remember conversation', '대화 저장', '세션 저장'.",
|
|
337
|
-
parameters: {
|
|
338
|
-
type: "object",
|
|
339
|
-
required: ["topics", "keyFindings"],
|
|
340
|
-
properties: {
|
|
341
|
-
topics: {
|
|
342
|
-
type: "string",
|
|
343
|
-
description: "Comma-separated topics discussed",
|
|
344
|
-
},
|
|
345
|
-
keyFindings: {
|
|
346
|
-
type: "string",
|
|
347
|
-
description: "Comma-separated key findings or insights",
|
|
348
|
-
},
|
|
349
|
-
decisions: {
|
|
350
|
-
type: "string",
|
|
351
|
-
description: "Comma-separated decisions made",
|
|
352
|
-
},
|
|
353
|
-
todos: {
|
|
354
|
-
type: "string",
|
|
355
|
-
description: "Comma-separated todo items",
|
|
356
|
-
},
|
|
357
|
-
},
|
|
358
|
-
},
|
|
359
|
-
handler: async (args): Promise<ToolResult> => {
|
|
360
|
-
try {
|
|
361
|
-
const topics = (args.topics as string).split(",").map((t) => t.trim());
|
|
362
|
-
const keyFindings = (args.keyFindings as string).split(",").map((t) => t.trim());
|
|
363
|
-
const decisions = args.decisions
|
|
364
|
-
? (args.decisions as string).split(",").map((t) => t.trim())
|
|
365
|
-
: [];
|
|
366
|
-
const todos = args.todos
|
|
367
|
-
? (args.todos as string).split(",").map((t) => t.trim())
|
|
368
|
-
: [];
|
|
369
|
-
|
|
370
|
-
const memory = loadMemory();
|
|
371
|
-
memory.conversations.push({
|
|
372
|
-
id: generateId(),
|
|
373
|
-
date: new Date().toISOString(),
|
|
374
|
-
topics,
|
|
375
|
-
keyFindings,
|
|
376
|
-
decisions,
|
|
377
|
-
todos,
|
|
378
|
-
});
|
|
379
|
-
|
|
380
|
-
// Keep only last 20 conversations
|
|
381
|
-
if (memory.conversations.length > 20) {
|
|
382
|
-
memory.conversations = memory.conversations.slice(-20);
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
saveMemory(memory);
|
|
386
|
-
|
|
387
|
-
return {
|
|
388
|
-
success: true,
|
|
389
|
-
content: `✅ 대화 요약 저장됨\n 주제: ${topics.join(", ")}\n 발견: ${keyFindings.length}개\n 결정: ${decisions.length}개\n TODO: ${todos.length}개`,
|
|
390
|
-
};
|
|
391
|
-
} catch (error) {
|
|
392
|
-
return { success: false, content: "", error: String(error) };
|
|
393
|
-
}
|
|
394
|
-
},
|
|
395
|
-
};
|
|
396
|
-
|
|
397
|
-
// Get Project Context Tool
|
|
398
|
-
export const getContextTool: Tool = {
|
|
399
|
-
name: "get_project_context",
|
|
400
|
-
description: "Get stored project context and memory (프로젝트 컨텍스트 조회). Returns project info, key files, notes, facts. Use when starting session or user asks: 'what do you remember', 'project context', '기억하는거', '컨텍스트'.",
|
|
401
|
-
parameters: {
|
|
402
|
-
type: "object",
|
|
403
|
-
properties: {
|
|
404
|
-
section: {
|
|
405
|
-
type: "string",
|
|
406
|
-
description: "Specific section: 'project', 'files', 'notes', 'facts', 'conversations', or 'all'",
|
|
407
|
-
enum: ["project", "files", "notes", "facts", "conversations", "all"],
|
|
408
|
-
},
|
|
409
|
-
},
|
|
410
|
-
},
|
|
411
|
-
handler: async (args): Promise<ToolResult> => {
|
|
412
|
-
try {
|
|
413
|
-
const section = (args.section as string) || "all";
|
|
414
|
-
const memory = loadMemory();
|
|
415
|
-
|
|
416
|
-
const lines: string[] = [];
|
|
417
|
-
|
|
418
|
-
if (section === "all" || section === "project") {
|
|
419
|
-
lines.push("=== 프로젝트 컨텍스트 ===");
|
|
420
|
-
lines.push(`📁 이름: ${memory.project.name}`);
|
|
421
|
-
if (memory.project.description) {
|
|
422
|
-
lines.push(`📝 설명: ${memory.project.description}`);
|
|
423
|
-
}
|
|
424
|
-
if (memory.project.techStack.length > 0) {
|
|
425
|
-
lines.push(`🛠️ 기술: ${memory.project.techStack.join(", ")}`);
|
|
426
|
-
}
|
|
427
|
-
if (memory.project.conventions.length > 0) {
|
|
428
|
-
lines.push(`📋 컨벤션: ${memory.project.conventions.join(", ")}`);
|
|
429
|
-
}
|
|
430
|
-
lines.push(`🕐 갱신: ${memory.project.lastUpdated.slice(0, 10)}`);
|
|
431
|
-
lines.push("");
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
if (section === "all" || section === "files") {
|
|
435
|
-
if (memory.project.keyFiles.length > 0) {
|
|
436
|
-
lines.push("=== 중요 파일 ===");
|
|
437
|
-
for (const file of memory.project.keyFiles) {
|
|
438
|
-
lines.push(`📄 ${file.path}`);
|
|
439
|
-
lines.push(` ${file.description}`);
|
|
440
|
-
}
|
|
441
|
-
lines.push("");
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
if (section === "all" || section === "notes") {
|
|
446
|
-
if (memory.notes.length > 0) {
|
|
447
|
-
lines.push("=== 노트 ===");
|
|
448
|
-
for (const note of memory.notes.slice(-5)) {
|
|
449
|
-
lines.push(`📌 ${note.title}`);
|
|
450
|
-
lines.push(` ${note.content.slice(0, 100)}${note.content.length > 100 ? "..." : ""}`);
|
|
451
|
-
if (note.tags.length > 0) {
|
|
452
|
-
lines.push(` 태그: ${note.tags.join(", ")}`);
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
if (memory.notes.length > 5) {
|
|
456
|
-
lines.push(` ... 외 ${memory.notes.length - 5}개`);
|
|
457
|
-
}
|
|
458
|
-
lines.push("");
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
if (section === "all" || section === "facts") {
|
|
463
|
-
if (memory.facts.length > 0) {
|
|
464
|
-
lines.push("=== 저장된 사실 ===");
|
|
465
|
-
for (const fact of memory.facts) {
|
|
466
|
-
lines.push(`💡 ${fact.key}: ${fact.value}`);
|
|
467
|
-
}
|
|
468
|
-
lines.push("");
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
if (section === "all" || section === "conversations") {
|
|
473
|
-
if (memory.conversations.length > 0) {
|
|
474
|
-
lines.push("=== 최근 대화 ===");
|
|
475
|
-
for (const conv of memory.conversations.slice(-3)) {
|
|
476
|
-
lines.push(`📅 ${conv.date.slice(0, 10)}`);
|
|
477
|
-
lines.push(` 주제: ${conv.topics.join(", ")}`);
|
|
478
|
-
if (conv.todos.length > 0) {
|
|
479
|
-
lines.push(` TODO: ${conv.todos.join(", ")}`);
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
lines.push("");
|
|
483
|
-
}
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
if (lines.length === 0) {
|
|
487
|
-
return { success: true, content: "저장된 메모리가 없습니다." };
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
return { success: true, content: lines.join("\n") };
|
|
491
|
-
} catch (error) {
|
|
492
|
-
return { success: false, content: "", error: String(error) };
|
|
493
|
-
}
|
|
494
|
-
},
|
|
495
|
-
};
|
|
496
|
-
|
|
497
|
-
// Search Memory Tool
|
|
498
|
-
export const searchMemoryTool: Tool = {
|
|
499
|
-
name: "search_memory",
|
|
500
|
-
description: "Search through stored notes and facts (메모리 검색). Use when user asks: 'find in memory', 'what did we say about', '기억에서 찾아', '메모리 검색'.",
|
|
501
|
-
parameters: {
|
|
502
|
-
type: "object",
|
|
503
|
-
required: ["query"],
|
|
504
|
-
properties: {
|
|
505
|
-
query: {
|
|
506
|
-
type: "string",
|
|
507
|
-
description: "Search query",
|
|
508
|
-
},
|
|
509
|
-
},
|
|
510
|
-
},
|
|
511
|
-
handler: async (args): Promise<ToolResult> => {
|
|
512
|
-
try {
|
|
513
|
-
const query = (args.query as string).toLowerCase();
|
|
514
|
-
const memory = loadMemory();
|
|
515
|
-
|
|
516
|
-
const results: string[] = [];
|
|
517
|
-
results.push(`=== 메모리 검색: "${args.query}" ===`);
|
|
518
|
-
results.push("");
|
|
519
|
-
|
|
520
|
-
// Search notes
|
|
521
|
-
const matchingNotes = memory.notes.filter(
|
|
522
|
-
(n) =>
|
|
523
|
-
n.title.toLowerCase().includes(query) ||
|
|
524
|
-
n.content.toLowerCase().includes(query) ||
|
|
525
|
-
n.tags.some((t) => t.toLowerCase().includes(query))
|
|
526
|
-
);
|
|
527
|
-
if (matchingNotes.length > 0) {
|
|
528
|
-
results.push("📌 노트:");
|
|
529
|
-
for (const note of matchingNotes) {
|
|
530
|
-
results.push(` ${note.title}`);
|
|
531
|
-
results.push(` ${note.content.slice(0, 80)}...`);
|
|
532
|
-
}
|
|
533
|
-
results.push("");
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
// Search facts
|
|
537
|
-
const matchingFacts = memory.facts.filter(
|
|
538
|
-
(f) =>
|
|
539
|
-
f.key.toLowerCase().includes(query) ||
|
|
540
|
-
f.value.toLowerCase().includes(query)
|
|
541
|
-
);
|
|
542
|
-
if (matchingFacts.length > 0) {
|
|
543
|
-
results.push("💡 사실:");
|
|
544
|
-
for (const fact of matchingFacts) {
|
|
545
|
-
results.push(` ${fact.key}: ${fact.value}`);
|
|
546
|
-
}
|
|
547
|
-
results.push("");
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
// Search key files
|
|
551
|
-
const matchingFiles = memory.project.keyFiles.filter(
|
|
552
|
-
(f) =>
|
|
553
|
-
f.path.toLowerCase().includes(query) ||
|
|
554
|
-
f.description.toLowerCase().includes(query)
|
|
555
|
-
);
|
|
556
|
-
if (matchingFiles.length > 0) {
|
|
557
|
-
results.push("📄 중요 파일:");
|
|
558
|
-
for (const file of matchingFiles) {
|
|
559
|
-
results.push(` ${file.path}: ${file.description}`);
|
|
560
|
-
}
|
|
561
|
-
results.push("");
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
// Search conversations
|
|
565
|
-
const matchingConvs = memory.conversations.filter(
|
|
566
|
-
(c) =>
|
|
567
|
-
c.topics.some((t) => t.toLowerCase().includes(query)) ||
|
|
568
|
-
c.keyFindings.some((f) => f.toLowerCase().includes(query))
|
|
569
|
-
);
|
|
570
|
-
if (matchingConvs.length > 0) {
|
|
571
|
-
results.push("📅 대화:");
|
|
572
|
-
for (const conv of matchingConvs) {
|
|
573
|
-
results.push(` ${conv.date.slice(0, 10)}: ${conv.topics.join(", ")}`);
|
|
574
|
-
}
|
|
575
|
-
results.push("");
|
|
576
|
-
}
|
|
577
|
-
|
|
578
|
-
if (results.length === 3) {
|
|
579
|
-
// Only header, no results
|
|
580
|
-
return { success: true, content: `"${args.query}"에 대한 검색 결과가 없습니다.` };
|
|
581
|
-
}
|
|
582
|
-
|
|
583
|
-
return { success: true, content: results.join("\n") };
|
|
584
|
-
} catch (error) {
|
|
585
|
-
return { success: false, content: "", error: String(error) };
|
|
586
|
-
}
|
|
587
|
-
},
|
|
588
|
-
};
|
|
589
|
-
|
|
590
|
-
// Clear Memory Tool
|
|
591
|
-
export const clearMemoryTool: Tool = {
|
|
592
|
-
name: "clear_memory",
|
|
593
|
-
description: "Clear stored memory (메모리 삭제). Use when user asks: 'forget everything', 'clear memory', '메모리 삭제', '기억 삭제'.",
|
|
594
|
-
parameters: {
|
|
595
|
-
type: "object",
|
|
596
|
-
properties: {
|
|
597
|
-
section: {
|
|
598
|
-
type: "string",
|
|
599
|
-
description: "Section to clear: 'notes', 'facts', 'conversations', or 'all'",
|
|
600
|
-
enum: ["notes", "facts", "conversations", "all"],
|
|
601
|
-
},
|
|
602
|
-
},
|
|
603
|
-
},
|
|
604
|
-
handler: async (args): Promise<ToolResult> => {
|
|
605
|
-
try {
|
|
606
|
-
const section = (args.section as string) || "all";
|
|
607
|
-
const memory = loadMemory();
|
|
608
|
-
|
|
609
|
-
if (section === "all") {
|
|
610
|
-
const dir = getMemoryDir();
|
|
611
|
-
if (fs.existsSync(dir)) {
|
|
612
|
-
fs.rmSync(dir, { recursive: true });
|
|
613
|
-
}
|
|
614
|
-
return { success: true, content: "✅ 전체 메모리가 삭제되었습니다." };
|
|
615
|
-
}
|
|
616
|
-
|
|
617
|
-
if (section === "notes") {
|
|
618
|
-
const count = memory.notes.length;
|
|
619
|
-
memory.notes = [];
|
|
620
|
-
saveMemory(memory);
|
|
621
|
-
return { success: true, content: `✅ ${count}개 노트가 삭제되었습니다.` };
|
|
622
|
-
}
|
|
623
|
-
|
|
624
|
-
if (section === "facts") {
|
|
625
|
-
const count = memory.facts.length;
|
|
626
|
-
memory.facts = [];
|
|
627
|
-
saveMemory(memory);
|
|
628
|
-
return { success: true, content: `✅ ${count}개 사실이 삭제되었습니다.` };
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
if (section === "conversations") {
|
|
632
|
-
const count = memory.conversations.length;
|
|
633
|
-
memory.conversations = [];
|
|
634
|
-
saveMemory(memory);
|
|
635
|
-
return { success: true, content: `✅ ${count}개 대화 기록이 삭제되었습니다.` };
|
|
636
|
-
}
|
|
637
|
-
|
|
638
|
-
return { success: false, content: "", error: `알 수 없는 섹션: ${section}` };
|
|
639
|
-
} catch (error) {
|
|
640
|
-
return { success: false, content: "", error: String(error) };
|
|
641
|
-
}
|
|
642
|
-
},
|
|
643
|
-
};
|
|
644
|
-
|
|
645
|
-
// Export all memory tools
|
|
646
|
-
export const memoryTools: Tool[] = [
|
|
647
|
-
initProjectTool,
|
|
648
|
-
addKeyFileTool,
|
|
649
|
-
addNoteTool,
|
|
650
|
-
addFactTool,
|
|
651
|
-
saveConversationTool,
|
|
652
|
-
getContextTool,
|
|
653
|
-
searchMemoryTool,
|
|
654
|
-
clearMemoryTool,
|
|
655
|
-
];
|