@su-record/vibe 0.1.2 → 0.1.4

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 (59) hide show
  1. package/README.md +13 -6
  2. package/bin/vibe +20 -2
  3. package/package.json +5 -6
  4. package/scripts/install-mcp.js +31 -5
  5. package/mcp/dist/__tests__/complexity.test.js +0 -126
  6. package/mcp/dist/__tests__/memory.test.js +0 -120
  7. package/mcp/dist/__tests__/python-dart-complexity.test.js +0 -146
  8. package/mcp/dist/index.js +0 -230
  9. package/mcp/dist/lib/ContextCompressor.js +0 -305
  10. package/mcp/dist/lib/MemoryManager.js +0 -334
  11. package/mcp/dist/lib/ProjectCache.js +0 -126
  12. package/mcp/dist/lib/PythonParser.js +0 -241
  13. package/mcp/dist/tools/browser/browserPool.js +0 -76
  14. package/mcp/dist/tools/browser/browserUtils.js +0 -135
  15. package/mcp/dist/tools/browser/inspectNetworkRequests.js +0 -140
  16. package/mcp/dist/tools/browser/monitorConsoleLogs.js +0 -97
  17. package/mcp/dist/tools/convention/analyzeComplexity.js +0 -248
  18. package/mcp/dist/tools/convention/applyQualityRules.js +0 -102
  19. package/mcp/dist/tools/convention/checkCouplingCohesion.js +0 -233
  20. package/mcp/dist/tools/convention/complexityMetrics.js +0 -133
  21. package/mcp/dist/tools/convention/dartComplexity.js +0 -117
  22. package/mcp/dist/tools/convention/getCodingGuide.js +0 -64
  23. package/mcp/dist/tools/convention/languageDetector.js +0 -50
  24. package/mcp/dist/tools/convention/pythonComplexity.js +0 -109
  25. package/mcp/dist/tools/convention/suggestImprovements.js +0 -257
  26. package/mcp/dist/tools/convention/validateCodeQuality.js +0 -177
  27. package/mcp/dist/tools/memory/autoSaveContext.js +0 -79
  28. package/mcp/dist/tools/memory/database.js +0 -123
  29. package/mcp/dist/tools/memory/deleteMemory.js +0 -39
  30. package/mcp/dist/tools/memory/listMemories.js +0 -38
  31. package/mcp/dist/tools/memory/memoryConfig.js +0 -27
  32. package/mcp/dist/tools/memory/memorySQLite.js +0 -138
  33. package/mcp/dist/tools/memory/memoryUtils.js +0 -34
  34. package/mcp/dist/tools/memory/migrate.js +0 -113
  35. package/mcp/dist/tools/memory/prioritizeMemory.js +0 -109
  36. package/mcp/dist/tools/memory/recallMemory.js +0 -40
  37. package/mcp/dist/tools/memory/restoreSessionContext.js +0 -69
  38. package/mcp/dist/tools/memory/saveMemory.js +0 -34
  39. package/mcp/dist/tools/memory/searchMemories.js +0 -37
  40. package/mcp/dist/tools/memory/startSession.js +0 -100
  41. package/mcp/dist/tools/memory/updateMemory.js +0 -46
  42. package/mcp/dist/tools/planning/analyzeRequirements.js +0 -166
  43. package/mcp/dist/tools/planning/createUserStories.js +0 -119
  44. package/mcp/dist/tools/planning/featureRoadmap.js +0 -202
  45. package/mcp/dist/tools/planning/generatePrd.js +0 -156
  46. package/mcp/dist/tools/prompt/analyzePrompt.js +0 -145
  47. package/mcp/dist/tools/prompt/enhancePrompt.js +0 -105
  48. package/mcp/dist/tools/semantic/findReferences.js +0 -195
  49. package/mcp/dist/tools/semantic/findSymbol.js +0 -200
  50. package/mcp/dist/tools/thinking/analyzeProblem.js +0 -50
  51. package/mcp/dist/tools/thinking/breakDownProblem.js +0 -140
  52. package/mcp/dist/tools/thinking/createThinkingChain.js +0 -39
  53. package/mcp/dist/tools/thinking/formatAsPlan.js +0 -73
  54. package/mcp/dist/tools/thinking/stepByStepAnalysis.js +0 -58
  55. package/mcp/dist/tools/thinking/thinkAloudProcess.js +0 -75
  56. package/mcp/dist/tools/time/getCurrentTime.js +0 -61
  57. package/mcp/dist/tools/ui/previewUiAscii.js +0 -232
  58. package/mcp/dist/types/tool.js +0 -2
  59. package/mcp/package.json +0 -53
@@ -1,257 +0,0 @@
1
- // Convention management tool - completely independent
2
- export const suggestImprovementsDefinition = {
3
- name: 'suggest_improvements',
4
- description: '개선|더 좋게|리팩토링|improve|make better|refactor|optimize|enhance code - Suggest improvements',
5
- inputSchema: {
6
- type: 'object',
7
- properties: {
8
- code: { type: 'string', description: 'Code to analyze' },
9
- focus: { type: 'string', description: 'Focus area', enum: ['performance', 'readability', 'maintainability', 'accessibility', 'type-safety'] },
10
- priority: { type: 'string', description: 'Priority level', enum: ['critical', 'high', 'medium', 'low'] }
11
- },
12
- required: ['code']
13
- },
14
- annotations: {
15
- title: 'Suggest Improvements',
16
- audience: ['user', 'assistant']
17
- }
18
- };
19
- export async function suggestImprovements(args) {
20
- const { code, focus = 'maintainability', priority = 'medium' } = args;
21
- const suggestions = [];
22
- const codeLines = code.split('\n');
23
- const codeLength = codeLines.length;
24
- // Performance improvements
25
- if (focus === 'performance' || focus === 'all') {
26
- // Check for inefficient loops
27
- if (code.includes('for') && code.includes('length')) {
28
- suggestions.push({
29
- category: 'performance',
30
- priority: 'high',
31
- issue: 'Potential inefficient loop accessing .length property',
32
- suggestion: 'Cache array length in a variable before the loop',
33
- example: 'const len = array.length; for (let i = 0; i < len; i++)'
34
- });
35
- }
36
- // Check for React performance issues
37
- if (code.includes('React') || code.includes('jsx') || code.includes('tsx')) {
38
- if (!code.includes('memo') && !code.includes('useMemo') && !code.includes('useCallback')) {
39
- suggestions.push({
40
- category: 'performance',
41
- priority: 'medium',
42
- issue: 'Missing React performance optimizations',
43
- suggestion: 'Consider using React.memo, useMemo, or useCallback',
44
- example: 'const Component = React.memo(() => { ... })'
45
- });
46
- }
47
- if (code.includes('map') && code.includes('return')) {
48
- suggestions.push({
49
- category: 'performance',
50
- priority: 'medium',
51
- issue: 'Ensure unique keys in map functions',
52
- suggestion: 'Use unique and stable keys for list items',
53
- example: 'items.map(item => <div key={item.id}>{item.name}</div>)'
54
- });
55
- }
56
- }
57
- // Check for expensive operations
58
- if (code.includes('JSON.parse') || code.includes('JSON.stringify')) {
59
- suggestions.push({
60
- category: 'performance',
61
- priority: 'medium',
62
- issue: 'JSON operations can be expensive',
63
- suggestion: 'Consider memoizing JSON operations or using alternatives',
64
- example: 'const memoizedParse = useMemo(() => JSON.parse(data), [data])'
65
- });
66
- }
67
- }
68
- // Readability improvements
69
- if (focus === 'readability' || focus === 'all') {
70
- // Check for long functions
71
- if (codeLength > 20) {
72
- suggestions.push({
73
- category: 'readability',
74
- priority: 'high',
75
- issue: `Function is too long (${codeLength} lines)`,
76
- suggestion: 'Break down into smaller, focused functions',
77
- example: 'Extract logical groups into separate functions'
78
- });
79
- }
80
- // Check for deep nesting
81
- let maxNesting = 0;
82
- let currentNesting = 0;
83
- for (const line of codeLines) {
84
- const braceCount = (line.match(/\{/g) || []).length - (line.match(/\}/g) || []).length;
85
- currentNesting += braceCount;
86
- maxNesting = Math.max(maxNesting, currentNesting);
87
- }
88
- if (maxNesting > 3) {
89
- suggestions.push({
90
- category: 'readability',
91
- priority: 'high',
92
- issue: `Deep nesting detected (${maxNesting} levels)`,
93
- suggestion: 'Use early returns or guard clauses to reduce nesting',
94
- example: 'if (!condition) return; // instead of wrapping in else'
95
- });
96
- }
97
- // Check for magic numbers
98
- const magicNumbers = code.match(/\b\d{2,}\b/g) || [];
99
- if (magicNumbers.length > 0) {
100
- suggestions.push({
101
- category: 'readability',
102
- priority: 'medium',
103
- issue: 'Magic numbers found in code',
104
- suggestion: 'Extract numbers into named constants',
105
- example: 'const MAX_RETRY_COUNT = 3; // instead of using 3 directly'
106
- });
107
- }
108
- // Check for unclear variable names
109
- const shortVars = code.match(/\b[a-z]\b/g) || [];
110
- if (shortVars.length > 2) {
111
- suggestions.push({
112
- category: 'readability',
113
- priority: 'medium',
114
- issue: 'Single letter variable names detected',
115
- suggestion: 'Use descriptive variable names',
116
- example: 'const userIndex = 0; // instead of i = 0'
117
- });
118
- }
119
- }
120
- // Maintainability improvements
121
- if (focus === 'maintainability' || focus === 'all') {
122
- // Check for error handling
123
- const hasAsyncCode = code.includes('async') || code.includes('await') || code.includes('Promise');
124
- const hasErrorHandling = code.includes('try') || code.includes('catch') || code.includes('throw');
125
- if (hasAsyncCode && !hasErrorHandling) {
126
- suggestions.push({
127
- category: 'maintainability',
128
- priority: 'high',
129
- issue: 'Async code without error handling',
130
- suggestion: 'Add try-catch blocks for async operations',
131
- example: 'try { await asyncOperation(); } catch (error) { handleError(error); }'
132
- });
133
- }
134
- // Check for code duplication
135
- const lines = codeLines.map(line => line.trim()).filter(line => line.length > 5);
136
- const duplicateLines = lines.filter((line, index) => lines.indexOf(line) !== index);
137
- if (duplicateLines.length > 0) {
138
- suggestions.push({
139
- category: 'maintainability',
140
- priority: 'medium',
141
- issue: 'Potential code duplication detected',
142
- suggestion: 'Extract common code into reusable functions',
143
- example: 'Create utility functions for repeated logic'
144
- });
145
- }
146
- // Check for comments
147
- const commentLines = code.match(/\/\*[\s\S]*?\*\/|\/\/.*$/gm) || [];
148
- const commentRatio = commentLines.length / codeLines.length;
149
- if (commentRatio < 0.1 && codeLength > 10) {
150
- suggestions.push({
151
- category: 'maintainability',
152
- priority: 'low',
153
- issue: 'Low comment-to-code ratio',
154
- suggestion: 'Add comments explaining complex logic',
155
- example: '// Validate user input before processing'
156
- });
157
- }
158
- }
159
- // Type safety improvements
160
- if (focus === 'type-safety' || focus === 'all') {
161
- // Check for any types
162
- if (code.includes('any')) {
163
- suggestions.push({
164
- category: 'type-safety',
165
- priority: 'high',
166
- issue: 'Using "any" type reduces type safety',
167
- suggestion: 'Use specific types or interfaces',
168
- example: 'interface User { id: string; name: string; }'
169
- });
170
- }
171
- // Check for loose equality
172
- if (code.includes('== ') || code.includes('!= ')) {
173
- suggestions.push({
174
- category: 'type-safety',
175
- priority: 'medium',
176
- issue: 'Loose equality operators found',
177
- suggestion: 'Use strict equality operators',
178
- example: 'Use === and !== instead of == and !='
179
- });
180
- }
181
- // Check for missing return types
182
- const functions = code.match(/function\s+\w+\([^)]*\)/g) || [];
183
- const functionsWithReturnType = code.match(/function\s+\w+\([^)]*\):\s*\w+/g) || [];
184
- if (functions.length > functionsWithReturnType.length) {
185
- suggestions.push({
186
- category: 'type-safety',
187
- priority: 'medium',
188
- issue: 'Functions missing explicit return types',
189
- suggestion: 'Add return type annotations',
190
- example: 'function getName(): string { return "name"; }'
191
- });
192
- }
193
- }
194
- // Accessibility improvements
195
- if (focus === 'accessibility' || focus === 'all') {
196
- // Check for missing alt text
197
- if (code.includes('<img') && !code.includes('alt=')) {
198
- suggestions.push({
199
- category: 'accessibility',
200
- priority: 'high',
201
- issue: 'Images without alt text',
202
- suggestion: 'Add descriptive alt text to images',
203
- example: '<img src="..." alt="Description of image" />'
204
- });
205
- }
206
- // Check for missing ARIA labels
207
- if (code.includes('button') && !code.includes('aria-label') && !code.includes('aria-describedby')) {
208
- suggestions.push({
209
- category: 'accessibility',
210
- priority: 'medium',
211
- issue: 'Interactive elements may need ARIA labels',
212
- suggestion: 'Add ARIA labels for screen readers',
213
- example: '<button aria-label="Close dialog">×</button>'
214
- });
215
- }
216
- // Check for form labels
217
- if (code.includes('<input') && !code.includes('label')) {
218
- suggestions.push({
219
- category: 'accessibility',
220
- priority: 'high',
221
- issue: 'Form inputs without labels',
222
- suggestion: 'Associate labels with form controls',
223
- example: '<label htmlFor="name">Name:</label><input id="name" />'
224
- });
225
- }
226
- }
227
- // Filter suggestions by priority if specified
228
- const filteredSuggestions = priority === 'all' ? suggestions :
229
- suggestions.filter(s => s.priority === priority || s.priority === 'critical');
230
- // Sort by priority
231
- const priorityOrder = { 'critical': 4, 'high': 3, 'medium': 2, 'low': 1 };
232
- filteredSuggestions.sort((a, b) => (priorityOrder[b.priority] || 0) - (priorityOrder[a.priority] || 0));
233
- const improvementResult = {
234
- action: 'suggest_improvements',
235
- focus,
236
- priority,
237
- codeStats: {
238
- lines: codeLength,
239
- functions: (code.match(/function\s+\w+|\w+\s*=\s*\(/g) || []).length,
240
- comments: (code.match(/\/\*[\s\S]*?\*\/|\/\/.*$/gm) || []).length
241
- },
242
- suggestions: filteredSuggestions,
243
- summary: {
244
- total: filteredSuggestions.length,
245
- critical: filteredSuggestions.filter(s => s.priority === 'critical').length,
246
- high: filteredSuggestions.filter(s => s.priority === 'high').length,
247
- medium: filteredSuggestions.filter(s => s.priority === 'medium').length,
248
- low: filteredSuggestions.filter(s => s.priority === 'low').length
249
- },
250
- overallScore: Math.max(0, 100 - (filteredSuggestions.length * 10)),
251
- status: 'success'
252
- };
253
- const topSuggestions = filteredSuggestions.slice(0, 8);
254
- return {
255
- content: [{ type: 'text', text: `Focus: ${focus}\nScore: ${improvementResult.overallScore}/100\nSuggestions: ${improvementResult.summary.total} (${improvementResult.summary.critical}C ${improvementResult.summary.high}H ${improvementResult.summary.medium}M ${improvementResult.summary.low}L)\n\n${topSuggestions.map(s => `[${s.priority.toUpperCase()}] ${s.category}\n Issue: ${s.issue}\n Fix: ${s.suggestion}`).join('\n\n')}${filteredSuggestions.length > 8 ? `\n\n... ${filteredSuggestions.length - 8} more suggestions` : ''}` }]
256
- };
257
- }
@@ -1,177 +0,0 @@
1
- // Convention management tool - completely independent
2
- // Enhanced Software Engineering Metrics
3
- const CODE_QUALITY_METRICS = {
4
- COMPLEXITY: {
5
- maxCyclomaticComplexity: 10,
6
- maxCognitiveComplexity: 15,
7
- maxFunctionLines: 20,
8
- maxNestingDepth: 3,
9
- maxParameters: 5
10
- },
11
- COUPLING: {
12
- maxDependencies: 7,
13
- maxFanOut: 5,
14
- preventCircularDeps: true
15
- },
16
- COHESION: {
17
- singleResponsibility: true,
18
- relatedFunctionsOnly: true
19
- },
20
- MAINTAINABILITY: {
21
- noMagicNumbers: true,
22
- consistentNaming: true,
23
- properErrorHandling: true,
24
- typesSafety: true
25
- },
26
- PERFORMANCE: {
27
- memoizeExpensiveCalc: true,
28
- lazyLoading: true,
29
- batchOperations: true
30
- }
31
- };
32
- export const validateCodeQualityDefinition = {
33
- name: 'validate_code_quality',
34
- description: '품질|리뷰|검사|quality|review code|check quality|validate|코드 리뷰 - Validate code quality',
35
- inputSchema: {
36
- type: 'object',
37
- properties: {
38
- code: { type: 'string', description: 'Code to validate' },
39
- type: { type: 'string', description: 'Code type', enum: ['component', 'function', 'hook', 'utility', 'general'] },
40
- strict: { type: 'boolean', description: 'Apply strict validation rules' },
41
- metrics: { type: 'string', description: 'Specific metrics to check', enum: ['complexity', 'coupling', 'cohesion', 'maintainability', 'performance', 'all'] }
42
- },
43
- required: ['code']
44
- },
45
- annotations: {
46
- title: 'Validate Code Quality',
47
- audience: ['user', 'assistant']
48
- }
49
- };
50
- export async function validateCodeQuality(args) {
51
- const { code: validateCode, type: validateType = 'general', strict = false, metrics = 'all' } = args;
52
- const qualityIssues = [];
53
- const qualityScore = { total: 100, deductions: [] };
54
- // Basic complexity checks
55
- const lines = validateCode.split('\n');
56
- const functionLineCount = lines.length;
57
- if (functionLineCount > CODE_QUALITY_METRICS.COMPLEXITY.maxFunctionLines) {
58
- qualityIssues.push({
59
- type: 'complexity',
60
- severity: 'high',
61
- message: `Function exceeds maximum lines (${functionLineCount}/${CODE_QUALITY_METRICS.COMPLEXITY.maxFunctionLines})`
62
- });
63
- qualityScore.deductions.push({ reason: 'Function too long', points: 15 });
64
- }
65
- // Nesting depth check
66
- let maxNesting = 0;
67
- let currentNesting = 0;
68
- for (const line of lines) {
69
- const braceCount = (line.match(/\{/g) || []).length - (line.match(/\}/g) || []).length;
70
- currentNesting += braceCount;
71
- maxNesting = Math.max(maxNesting, currentNesting);
72
- }
73
- if (maxNesting > CODE_QUALITY_METRICS.COMPLEXITY.maxNestingDepth) {
74
- qualityIssues.push({
75
- type: 'complexity',
76
- severity: 'medium',
77
- message: `Nesting depth exceeds maximum (${maxNesting}/${CODE_QUALITY_METRICS.COMPLEXITY.maxNestingDepth})`
78
- });
79
- qualityScore.deductions.push({ reason: 'Deep nesting', points: 10 });
80
- }
81
- // Cyclomatic complexity estimation
82
- const cyclomaticComplexity = (validateCode.match(/\bif\b|\bfor\b|\bwhile\b|\bcase\b|\b&&\b|\b\|\|\b/g) || []).length + 1;
83
- if (cyclomaticComplexity > CODE_QUALITY_METRICS.COMPLEXITY.maxCyclomaticComplexity) {
84
- qualityIssues.push({
85
- type: 'complexity',
86
- severity: 'high',
87
- message: `Cyclomatic complexity too high (${cyclomaticComplexity}/${CODE_QUALITY_METRICS.COMPLEXITY.maxCyclomaticComplexity})`
88
- });
89
- qualityScore.deductions.push({ reason: 'High cyclomatic complexity', points: 20 });
90
- }
91
- // Anti-pattern checks
92
- if (validateCode.includes('any')) {
93
- qualityIssues.push({
94
- type: 'type-safety',
95
- severity: 'medium',
96
- message: 'Using "any" type - consider more specific types'
97
- });
98
- qualityScore.deductions.push({ reason: 'Any type usage', points: 10 });
99
- }
100
- if (validateCode.includes('== ')) {
101
- qualityIssues.push({
102
- type: 'best-practices',
103
- severity: 'low',
104
- message: 'Use strict equality (===) instead of loose equality (==)'
105
- });
106
- qualityScore.deductions.push({ reason: 'Loose equality', points: 5 });
107
- }
108
- if (validateCode.includes('var ')) {
109
- qualityIssues.push({
110
- type: 'best-practices',
111
- severity: 'medium',
112
- message: 'Use const/let instead of var'
113
- });
114
- qualityScore.deductions.push({ reason: 'Var usage', points: 8 });
115
- }
116
- // Magic numbers check
117
- const magicNumbers = validateCode.match(/\b\d{2,}\b/g) || [];
118
- if (magicNumbers.length > 0) {
119
- qualityIssues.push({
120
- type: 'maintainability',
121
- severity: 'low',
122
- message: `Found potential magic numbers: ${magicNumbers.join(', ')}`
123
- });
124
- qualityScore.deductions.push({ reason: 'Magic numbers', points: 5 });
125
- }
126
- // Error handling check
127
- const hasErrorHandling = validateCode.includes('try') || validateCode.includes('catch') || validateCode.includes('throw');
128
- if (!hasErrorHandling && validateCode.includes('async')) {
129
- qualityIssues.push({
130
- type: 'error-handling',
131
- severity: 'medium',
132
- message: 'Async functions should include error handling'
133
- });
134
- qualityScore.deductions.push({ reason: 'Missing error handling', points: 10 });
135
- }
136
- // Performance checks for React components
137
- if (validateType === 'component' && validateCode.includes('React')) {
138
- if (!validateCode.includes('memo') && !validateCode.includes('useMemo') && !validateCode.includes('useCallback')) {
139
- qualityIssues.push({
140
- type: 'performance',
141
- severity: 'low',
142
- message: 'Consider using React.memo, useMemo, or useCallback for performance optimization'
143
- });
144
- qualityScore.deductions.push({ reason: 'Missing performance optimization', points: 5 });
145
- }
146
- }
147
- const finalScore = Math.max(0, qualityScore.total - qualityScore.deductions.reduce((sum, d) => sum + d.points, 0));
148
- const validationResult = {
149
- action: 'validate_code_quality',
150
- type: validateType,
151
- strict,
152
- metricsRequested: metrics,
153
- score: finalScore,
154
- grade: finalScore >= 90 ? 'A' : finalScore >= 80 ? 'B' : finalScore >= 70 ? 'C' : finalScore >= 60 ? 'D' : 'F',
155
- issues: qualityIssues,
156
- deductions: qualityScore.deductions,
157
- recommendations: qualityIssues.length > 0 ? [
158
- 'Consider breaking down complex functions',
159
- 'Reduce nesting depth with early returns',
160
- 'Use more specific types instead of "any"',
161
- 'Apply consistent coding standards',
162
- 'Add proper error handling',
163
- 'Consider performance optimizations'
164
- ] : ['Code quality is excellent!'],
165
- metrics: {
166
- complexity: cyclomaticComplexity,
167
- lines: functionLineCount,
168
- nesting: maxNesting,
169
- issues: qualityIssues.length
170
- },
171
- status: 'success'
172
- };
173
- const topIssues = qualityIssues.slice(0, 8);
174
- return {
175
- content: [{ type: 'text', text: `Type: ${validateType}\nScore: ${finalScore}/100 (Grade: ${validationResult.grade})\nMetrics: Lines=${validationResult.metrics.lines}, Complexity=${validationResult.metrics.complexity}, Nesting=${validationResult.metrics.nesting}\n\nIssues (${qualityIssues.length}):\n${topIssues.map(i => `[${i.severity.toUpperCase()}] ${i.type}: ${i.message}`).join('\n')}${qualityIssues.length > 8 ? `\n... ${qualityIssues.length - 8} more issues` : ''}\n\nDeductions: -${qualityScore.deductions.reduce((sum, d) => sum + d.points, 0)} pts (${qualityScore.deductions.map(d => `${d.reason}: -${d.points}`).join(', ')})` }]
176
- };
177
- }
@@ -1,79 +0,0 @@
1
- // Memory management tool - SQLite based with context compression (v1.3)
2
- import { MemoryManager } from '../../lib/MemoryManager.js';
3
- import { ContextCompressor } from '../../lib/ContextCompressor.js';
4
- export const autoSaveContextDefinition = {
5
- name: 'auto_save_context',
6
- description: 'commit|save|checkpoint|backup|커밋|저장|compress - Auto-save and compress context',
7
- inputSchema: {
8
- type: 'object',
9
- properties: {
10
- urgency: { type: 'string', description: 'Urgency level', enum: ['low', 'medium', 'high', 'critical'] },
11
- contextType: { type: 'string', description: 'Type of context to save', enum: ['progress', 'decisions', 'code-snippets', 'debugging', 'planning'] },
12
- sessionId: { type: 'string', description: 'Current session identifier' },
13
- summary: { type: 'string', description: 'Brief summary of current context' },
14
- fullContext: { type: 'string', description: 'Full context to compress and save' },
15
- compress: { type: 'boolean', description: 'Enable smart compression (default: true)' }
16
- },
17
- required: ['urgency', 'contextType']
18
- },
19
- annotations: {
20
- title: 'Auto-Save Context',
21
- audience: ['user', 'assistant']
22
- }
23
- };
24
- export async function autoSaveContext(args) {
25
- const { urgency, contextType, sessionId, summary, fullContext, compress = true } = args;
26
- try {
27
- const memoryManager = MemoryManager.getInstance();
28
- let contextToSave = summary || '';
29
- let compressionStats = null;
30
- // Apply smart compression if full context provided and compression enabled
31
- if (fullContext && compress) {
32
- const targetTokens = urgency === 'critical' ? 6000 : urgency === 'high' ? 4000 : 2000;
33
- const compressionResult = ContextCompressor.compress(fullContext, targetTokens);
34
- contextToSave = compressionResult.compressed;
35
- compressionStats = {
36
- originalTokens: ContextCompressor.estimateTokens(fullContext),
37
- compressedTokens: ContextCompressor.estimateTokens(compressionResult.compressed),
38
- ratio: Math.round(compressionResult.compressionRatio * 100),
39
- removed: compressionResult.removedSections.length
40
- };
41
- }
42
- else if (fullContext) {
43
- contextToSave = fullContext;
44
- }
45
- const contextData = {
46
- timestamp: new Date().toISOString(),
47
- urgency,
48
- contextType,
49
- sessionId,
50
- summary,
51
- context: contextToSave,
52
- compressed: compress && !!fullContext,
53
- compressionStats
54
- };
55
- const priority = urgency === 'high' || urgency === 'critical' ? 2 : urgency === 'medium' ? 1 : 0;
56
- const contextKey = sessionId ? `context:session_${sessionId}_${Date.now()}` : `context:${Date.now()}`;
57
- memoryManager.save(contextKey, JSON.stringify(contextData), 'context', priority);
58
- let resultText = `✓ Context saved: ${contextType} (${urgency})`;
59
- if (sessionId)
60
- resultText += `\nSession: ${sessionId}`;
61
- if (compressionStats) {
62
- resultText += `\nCompressed: ${compressionStats.originalTokens} → ${compressionStats.compressedTokens} tokens (${compressionStats.ratio}%)`;
63
- resultText += `\nRemoved: ${compressionStats.removed} low-priority sections`;
64
- }
65
- if (summary)
66
- resultText += `\n${summary}`;
67
- return {
68
- content: [{
69
- type: 'text',
70
- text: resultText
71
- }]
72
- };
73
- }
74
- catch (error) {
75
- return {
76
- content: [{ type: 'text', text: `✗ Error: ${error instanceof Error ? error.message : 'Unknown error'}` }]
77
- };
78
- }
79
- }
@@ -1,123 +0,0 @@
1
- // SQLite database connection and schema management
2
- import Database from 'better-sqlite3';
3
- import path from 'path';
4
- import { getMemoryDir } from './memoryConfig.js';
5
- import { existsSync, mkdirSync } from 'fs';
6
- class MemoryDatabase {
7
- db = null;
8
- dbPath;
9
- constructor() {
10
- const memoryDir = getMemoryDir();
11
- // Ensure directory exists
12
- if (!existsSync(memoryDir)) {
13
- mkdirSync(memoryDir, { recursive: true });
14
- }
15
- this.dbPath = path.join(memoryDir, 'memories.db');
16
- }
17
- /**
18
- * Get database connection (lazy initialization)
19
- */
20
- getConnection() {
21
- if (!this.db) {
22
- // Ensure directory exists before opening database
23
- const memoryDir = getMemoryDir();
24
- if (!existsSync(memoryDir)) {
25
- mkdirSync(memoryDir, { recursive: true });
26
- }
27
- this.db = new Database(this.dbPath);
28
- // Enable WAL mode for better concurrency
29
- this.db.pragma('journal_mode = WAL');
30
- // Initialize schema
31
- this.initSchema();
32
- }
33
- return this.db;
34
- }
35
- /**
36
- * Initialize database schema
37
- */
38
- initSchema() {
39
- const db = this.db;
40
- // Memories table
41
- db.exec(`
42
- CREATE TABLE IF NOT EXISTS memories (
43
- id INTEGER PRIMARY KEY AUTOINCREMENT,
44
- key TEXT UNIQUE NOT NULL,
45
- value TEXT NOT NULL,
46
- category TEXT NOT NULL DEFAULT 'general',
47
- timestamp TEXT NOT NULL,
48
- lastAccessed TEXT NOT NULL
49
- );
50
-
51
- CREATE INDEX IF NOT EXISTS idx_memories_key ON memories(key);
52
- CREATE INDEX IF NOT EXISTS idx_memories_category ON memories(category);
53
- CREATE INDEX IF NOT EXISTS idx_memories_lastAccessed ON memories(lastAccessed);
54
- `);
55
- // Sessions table
56
- db.exec(`
57
- CREATE TABLE IF NOT EXISTS sessions (
58
- id INTEGER PRIMARY KEY AUTOINCREMENT,
59
- sessionId TEXT NOT NULL,
60
- contextType TEXT NOT NULL,
61
- summary TEXT NOT NULL,
62
- urgency TEXT NOT NULL,
63
- currentTask TEXT,
64
- codeChanges TEXT,
65
- decisions TEXT,
66
- blockers TEXT,
67
- nextSteps TEXT,
68
- timestamp TEXT NOT NULL
69
- );
70
-
71
- CREATE INDEX IF NOT EXISTS idx_sessions_sessionId ON sessions(sessionId);
72
- CREATE INDEX IF NOT EXISTS idx_sessions_timestamp ON sessions(timestamp);
73
- CREATE INDEX IF NOT EXISTS idx_sessions_urgency ON sessions(urgency);
74
- `);
75
- // Guides table (for coding guides)
76
- db.exec(`
77
- CREATE TABLE IF NOT EXISTS guides (
78
- id INTEGER PRIMARY KEY AUTOINCREMENT,
79
- name TEXT UNIQUE NOT NULL,
80
- category TEXT NOT NULL,
81
- content TEXT NOT NULL,
82
- timestamp TEXT NOT NULL
83
- );
84
-
85
- CREATE INDEX IF NOT EXISTS idx_guides_name ON guides(name);
86
- CREATE INDEX IF NOT EXISTS idx_guides_category ON guides(category);
87
- `);
88
- }
89
- /**
90
- * Close database connection
91
- */
92
- close() {
93
- if (this.db) {
94
- this.db.close();
95
- this.db = null;
96
- }
97
- }
98
- /**
99
- * Run a checkpoint to merge WAL file
100
- */
101
- checkpoint() {
102
- if (this.db) {
103
- this.db.pragma('wal_checkpoint(TRUNCATE)');
104
- }
105
- }
106
- }
107
- // Singleton instance
108
- export const memoryDB = new MemoryDatabase();
109
- // Cleanup on process exit
110
- process.on('exit', () => {
111
- memoryDB.checkpoint();
112
- memoryDB.close();
113
- });
114
- process.on('SIGINT', () => {
115
- memoryDB.checkpoint();
116
- memoryDB.close();
117
- process.exit(0);
118
- });
119
- process.on('SIGTERM', () => {
120
- memoryDB.checkpoint();
121
- memoryDB.close();
122
- process.exit(0);
123
- });
@@ -1,39 +0,0 @@
1
- // Memory management tool - completely independent
2
- import { MemoryManager } from '../../lib/MemoryManager.js';
3
- export const deleteMemoryDefinition = {
4
- name: 'delete_memory',
5
- description: '잊어|삭제해|지워|forget|delete|remove|erase - Delete specific memory',
6
- inputSchema: {
7
- type: 'object',
8
- properties: {
9
- key: { type: 'string', description: 'Memory key to delete' }
10
- },
11
- required: ['key']
12
- },
13
- annotations: {
14
- title: 'Delete Memory',
15
- audience: ['user', 'assistant']
16
- }
17
- };
18
- export async function deleteMemory(args) {
19
- const { key: deleteKey } = args;
20
- try {
21
- const mm = MemoryManager.getInstance();
22
- const deleted = mm.delete(deleteKey);
23
- if (deleted) {
24
- return {
25
- content: [{ type: 'text', text: `✓ Deleted memory: "${deleteKey}"` }]
26
- };
27
- }
28
- else {
29
- return {
30
- content: [{ type: 'text', text: `✗ Memory not found: "${deleteKey}"` }]
31
- };
32
- }
33
- }
34
- catch (error) {
35
- return {
36
- content: [{ type: 'text', text: `✗ Error: ${error instanceof Error ? error.message : 'Unknown error'}` }]
37
- };
38
- }
39
- }