@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,133 +0,0 @@
1
- // Complexity metrics calculation - extracted from analyzeComplexity
2
- import { Project, ScriptKind } from "ts-morph";
3
- const AST_PROJECT = new Project({
4
- useInMemoryFileSystem: true,
5
- compilerOptions: { allowJs: true, skipLibCheck: true }
6
- });
7
- const COMPLEXITY_NODES = new Set([
8
- 'IfStatement', 'ForStatement', 'ForOfStatement', 'ForInStatement',
9
- 'WhileStatement', 'CaseClause', 'ConditionalExpression',
10
- 'DoStatement', 'CatchClause', 'BinaryExpression'
11
- ]);
12
- export const THRESHOLDS = {
13
- maxCyclomatic: 10,
14
- maxCognitive: 15,
15
- maxHalsteadDifficulty: 10
16
- };
17
- /**
18
- * Calculate AST-based cyclomatic complexity
19
- */
20
- export function calculateASTCyclomatic(code) {
21
- try {
22
- const sourceFile = AST_PROJECT.createSourceFile('temp.ts', code, {
23
- overwrite: true,
24
- scriptKind: ScriptKind.TS
25
- });
26
- let complexity = 1;
27
- sourceFile.forEachDescendant((node) => {
28
- if (COMPLEXITY_NODES.has(node.getKindName())) {
29
- complexity++;
30
- }
31
- });
32
- return {
33
- value: complexity,
34
- threshold: THRESHOLDS.maxCyclomatic,
35
- status: complexity <= THRESHOLDS.maxCyclomatic ? 'pass' : 'fail',
36
- description: 'AST-based branch/decision point count'
37
- };
38
- }
39
- catch (error) {
40
- return {
41
- value: 0,
42
- status: 'error',
43
- description: `AST analysis failed: ${error instanceof Error ? error.message : String(error)}`
44
- };
45
- }
46
- }
47
- /**
48
- * Calculate regex-based cyclomatic complexity (fallback)
49
- */
50
- export function calculateRegexCyclomatic(code) {
51
- const patterns = /\bif\b|\bfor\b|\bwhile\b|\bcase\b|\b&&\b|\b\|\|\b/g;
52
- const matches = code.match(patterns) || [];
53
- const complexity = matches.length + 1;
54
- return {
55
- value: complexity,
56
- threshold: THRESHOLDS.maxCyclomatic,
57
- status: complexity <= THRESHOLDS.maxCyclomatic ? 'pass' : 'fail',
58
- description: 'Number of linearly independent paths'
59
- };
60
- }
61
- /**
62
- * Calculate cognitive complexity with nesting awareness
63
- */
64
- export function calculateCognitiveComplexity(code) {
65
- const lines = code.split('\n');
66
- let complexity = 0;
67
- let nestingLevel = 0;
68
- for (const line of lines) {
69
- const trimmed = line.trim();
70
- // Control structures add complexity based on nesting
71
- if (/(if|for|while|catch|switch)\s*\(/.test(trimmed)) {
72
- complexity += 1 + nestingLevel;
73
- }
74
- // Track nesting level
75
- const openBraces = (line.match(/\{/g) || []).length;
76
- const closeBraces = (line.match(/\}/g) || []).length;
77
- nestingLevel = Math.max(0, nestingLevel + openBraces - closeBraces);
78
- }
79
- return {
80
- value: complexity,
81
- threshold: THRESHOLDS.maxCognitive,
82
- status: complexity <= THRESHOLDS.maxCognitive ? 'pass' : 'fail',
83
- description: 'Difficulty to understand the code'
84
- };
85
- }
86
- /**
87
- * Calculate Halstead complexity metrics
88
- */
89
- export function calculateHalsteadMetrics(code) {
90
- const operators = code.match(/[+\-*/=<>!&|%^~?:]/g) || [];
91
- const operands = code.match(/\b[a-zA-Z_]\w*\b/g) || [];
92
- const uniqueOperators = new Set(operators).size;
93
- const uniqueOperands = new Set(operands).size;
94
- const vocabulary = uniqueOperators + uniqueOperands;
95
- const length = operators.length + operands.length;
96
- const calculatedLength = vocabulary > 0
97
- ? uniqueOperators * Math.log2(uniqueOperators || 1) + uniqueOperands * Math.log2(uniqueOperands || 1)
98
- : 0;
99
- const volume = length * Math.log2(vocabulary || 1);
100
- const difficulty = vocabulary > 0
101
- ? (uniqueOperators / 2) * (operands.length / (uniqueOperands || 1))
102
- : 0;
103
- const effort = difficulty * volume;
104
- return {
105
- vocabulary,
106
- length,
107
- calculatedLength: Math.round(calculatedLength),
108
- volume: Math.round(volume),
109
- difficulty: Math.round(difficulty * 100) / 100,
110
- effort: Math.round(effort),
111
- timeToProgram: Math.round(effort / 18),
112
- bugsDelivered: Math.round(volume / 3000 * 100) / 100,
113
- description: 'Software science metrics measuring program complexity'
114
- };
115
- }
116
- /**
117
- * Calculate additional code metrics
118
- */
119
- export function calculateAdditionalMetrics(code) {
120
- const lines = code.split('\n');
121
- const nonEmptyLines = lines.filter(line => line.trim().length > 0).length;
122
- const comments = (code.match(/\/\*[\s\S]*?\*\/|\/\/.*$/gm) || []).length;
123
- const functions = (code.match(/function\s+\w+|\w+\s*=\s*\(/g) || []).length;
124
- const classes = (code.match(/class\s+\w+/g) || []).length;
125
- return {
126
- linesOfCode: nonEmptyLines,
127
- comments,
128
- commentRatio: nonEmptyLines > 0 ? Math.round((comments / nonEmptyLines) * 100) / 100 : 0,
129
- functions,
130
- classes,
131
- averageFunctionLength: functions > 0 ? Math.round(nonEmptyLines / functions) : 0
132
- };
133
- }
@@ -1,117 +0,0 @@
1
- /**
2
- * Dart/Flutter-specific complexity analysis
3
- */
4
- import { THRESHOLDS } from './complexityMetrics.js';
5
- /**
6
- * Calculate cyclomatic complexity for Dart code
7
- */
8
- export function calculateDartComplexity(code) {
9
- // Dart control flow keywords
10
- const patterns = [
11
- /\bif\b/g, // if statements
12
- /\belse\s+if\b/g, // else if
13
- /\bfor\b/g, // for loops
14
- /\bwhile\b/g, // while loops
15
- /\bdo\b/g, // do-while
16
- /\bswitch\b/g, // switch statements
17
- /\bcase\b/g, // case clauses
18
- /\btry\b/g, // try blocks
19
- /\bcatch\b/g, // catch blocks
20
- /&&/g, // logical and
21
- /\|\|/g, // logical or
22
- /\?\?/g // null-coalescing
23
- ];
24
- let complexity = 1; // Base complexity
25
- for (const pattern of patterns) {
26
- const matches = code.match(pattern);
27
- if (matches) {
28
- complexity += matches.length;
29
- }
30
- }
31
- return {
32
- value: complexity,
33
- threshold: THRESHOLDS.maxCyclomatic,
34
- status: complexity <= THRESHOLDS.maxCyclomatic ? 'pass' : 'fail',
35
- description: 'Dart cyclomatic complexity (control flow branches)'
36
- };
37
- }
38
- /**
39
- * Calculate cognitive complexity for Dart
40
- */
41
- export function calculateDartCognitiveComplexity(code) {
42
- let complexity = 0;
43
- // Nested control structures
44
- let nestingLevel = 0;
45
- const lines = code.split('\n');
46
- for (const line of lines) {
47
- const trimmed = line.trim();
48
- // Track nesting level
49
- const openBraces = (line.match(/{/g) || []).length;
50
- const closeBraces = (line.match(/}/g) || []).length;
51
- // Control flow keywords
52
- if (/\b(if|else|for|while|switch|try|catch)\b/.test(trimmed)) {
53
- complexity += 1 + nestingLevel;
54
- }
55
- // Ternary operators
56
- const ternaryCount = (trimmed.match(/\?.*:/g) || []).length;
57
- complexity += ternaryCount;
58
- // Null-aware operators (Flutter specific)
59
- const nullAwareCount = (trimmed.match(/\?\?|!\.|\/\?/g) || []).length;
60
- complexity += nullAwareCount * 0.5; // Half weight
61
- // Update nesting
62
- nestingLevel += openBraces - closeBraces;
63
- if (nestingLevel < 0)
64
- nestingLevel = 0;
65
- }
66
- return {
67
- value: Math.round(complexity),
68
- threshold: THRESHOLDS.maxCognitive,
69
- status: complexity <= THRESHOLDS.maxCognitive ? 'pass' : 'fail',
70
- description: 'Dart cognitive complexity (mental load to understand)'
71
- };
72
- }
73
- /**
74
- * Analyze Flutter/Dart code quality
75
- */
76
- export function analyzeDartQuality(code) {
77
- const issues = [];
78
- const recommendations = [];
79
- // Flutter-specific anti-patterns
80
- if (/setState\(\(\)\s*{\s*[\s\S]*?}\s*\)/.test(code)) {
81
- const setStateCount = (code.match(/setState/g) || []).length;
82
- if (setStateCount > 5) {
83
- issues.push('Too many setState calls - consider state management solution');
84
- recommendations.push('Use Provider, Riverpod, or Bloc for complex state');
85
- }
86
- }
87
- // Deep widget nesting
88
- const widgetNesting = (code.match(/child:\s*\w+\(/g) || []).length;
89
- if (widgetNesting > 5) {
90
- issues.push('Deep widget nesting detected');
91
- recommendations.push('Extract nested widgets into separate methods or classes');
92
- }
93
- // Missing const constructors
94
- const widgetConstructors = (code.match(/\w+\(/g) || []).length;
95
- const constConstructors = (code.match(/const\s+\w+\(/g) || []).length;
96
- if (widgetConstructors > 10 && constConstructors < widgetConstructors * 0.3) {
97
- issues.push('Many widgets without const constructors');
98
- recommendations.push('Use const constructors for immutable widgets to improve performance');
99
- }
100
- // Missing key in lists
101
- if (/ListView\.builder|GridView\.builder/.test(code) && !/key:/.test(code)) {
102
- issues.push('ListView/GridView without keys');
103
- recommendations.push('Add keys to list items for better performance');
104
- }
105
- // Missing null safety
106
- if (!/\w+\?|\w+!/.test(code) && code.includes('null')) {
107
- issues.push('Possible null safety issues');
108
- recommendations.push('Enable null safety and use ? and ! operators appropriately');
109
- }
110
- // Large build methods
111
- const buildMethodMatch = code.match(/Widget build\(BuildContext context\)\s*{([\s\S]*?)^ }/m);
112
- if (buildMethodMatch && buildMethodMatch[1].split('\n').length > 50) {
113
- issues.push('Build method is too large (> 50 lines)');
114
- recommendations.push('Extract widgets into separate methods or classes');
115
- }
116
- return { issues, recommendations };
117
- }
@@ -1,64 +0,0 @@
1
- // Convention management tool - completely independent
2
- import { promises as fs } from 'fs';
3
- import path from 'path';
4
- const GUIDES_DIR = path.join(process.cwd(), 'guides');
5
- const GUIDES_FILE = path.join(GUIDES_DIR, 'coding_guides.json');
6
- async function ensureGuidesDir() {
7
- try {
8
- await fs.access(GUIDES_DIR);
9
- }
10
- catch {
11
- await fs.mkdir(GUIDES_DIR, { recursive: true });
12
- }
13
- }
14
- async function loadGuides() {
15
- try {
16
- await ensureGuidesDir();
17
- const data = await fs.readFile(GUIDES_FILE, 'utf-8');
18
- return JSON.parse(data);
19
- }
20
- catch {
21
- return [];
22
- }
23
- }
24
- async function findGuide(name) {
25
- const guides = await loadGuides();
26
- return guides.find(g => g.name === name);
27
- }
28
- export const getCodingGuideDefinition = {
29
- name: 'get_coding_guide',
30
- description: '가이드|규칙|컨벤션|guide|rules|convention|standards|best practices - Get coding guide',
31
- inputSchema: {
32
- type: 'object',
33
- properties: {
34
- name: { type: 'string', description: 'Guide name to retrieve' },
35
- category: { type: 'string', description: 'Guide category' }
36
- },
37
- required: ['name']
38
- },
39
- annotations: {
40
- title: 'Get Coding Guide',
41
- audience: ['user', 'assistant']
42
- }
43
- };
44
- export async function getCodingGuide(args) {
45
- const { name: guideName, category: guideCategory } = args;
46
- try {
47
- const guide = await findGuide(guideName);
48
- if (guide) {
49
- return {
50
- content: [{ type: 'text', text: `Guide: ${guide.name}\nCategory: ${guide.category}\n\n${guide.content}\n\nTags: ${guide.tags.join(', ')} | Updated: ${guide.lastUpdated}` }]
51
- };
52
- }
53
- else {
54
- return {
55
- content: [{ type: 'text', text: `Guide not found: "${guideName}". Use list_coding_guides to see available guides.` }]
56
- };
57
- }
58
- }
59
- catch (error) {
60
- return {
61
- content: [{ type: 'text', text: `Error retrieving guide: ${error instanceof Error ? error.message : 'Unknown error'}` }]
62
- };
63
- }
64
- }
@@ -1,50 +0,0 @@
1
- /**
2
- * Language detection utility for code quality tools
3
- * Supports TypeScript, JavaScript, Python, and Dart/Flutter
4
- */
5
- export function detectLanguage(code) {
6
- // Dart/Flutter indicators (check first - most specific)
7
- if (/\bWidget\b/.test(code) ||
8
- /\bStatelessWidget\b/.test(code) ||
9
- /\bStatefulWidget\b/.test(code) ||
10
- /\bBuildContext\b/.test(code) ||
11
- /Widget build\(/.test(code) ||
12
- /extends\s+(StatelessWidget|StatefulWidget|State)/.test(code) ||
13
- (/@override/i.test(code) && /Widget|BuildContext/.test(code))) {
14
- return 'dart';
15
- }
16
- // Python indicators
17
- if (/^(def|async def)\s/m.test(code) ||
18
- /^from\s+\w+\s+import/.test(code) ||
19
- /^\s+def\s/m.test(code) || // Indented function definitions
20
- /\belif\b/.test(code) ||
21
- /\b__init__\b/.test(code) ||
22
- /\bprint\(/m.test(code) ||
23
- (/:\s*$/m.test(code) && !/;/.test(code)) // Python colon without semicolon
24
- ) {
25
- return 'python';
26
- }
27
- // TypeScript indicators
28
- if (/:\s*(string|number|boolean|any|void|unknown|never)\b/.test(code) ||
29
- /interface\s+\w+/.test(code) ||
30
- /type\s+\w+\s*=/.test(code) ||
31
- /<[A-Z]\w*>/.test(code) // generics with capital letters
32
- ) {
33
- return 'typescript';
34
- }
35
- // JavaScript (default if none match)
36
- if (/\b(const|let|var|function|class|async|await|import|export)\b/.test(code)) {
37
- return 'javascript';
38
- }
39
- return 'unknown';
40
- }
41
- export function getLanguageName(lang) {
42
- const names = {
43
- typescript: 'TypeScript',
44
- javascript: 'JavaScript',
45
- python: 'Python',
46
- dart: 'Dart/Flutter',
47
- unknown: 'Unknown'
48
- };
49
- return names[lang];
50
- }
@@ -1,109 +0,0 @@
1
- /**
2
- * Python-specific complexity analysis
3
- */
4
- import { THRESHOLDS } from './complexityMetrics.js';
5
- /**
6
- * Calculate cyclomatic complexity for Python code
7
- */
8
- export function calculatePythonComplexity(code) {
9
- // Python control flow keywords
10
- const patterns = [
11
- /\bif\b/g, // if statements
12
- /\belif\b/g, // elif statements
13
- /\bfor\b/g, // for loops
14
- /\bwhile\b/g, // while loops
15
- /\btry\b/g, // try blocks
16
- /\bexcept\b/g, // except blocks
17
- /\band\b/g, // logical and
18
- /\bor\b/g, // logical or
19
- /\bwith\b/g, // with statements
20
- /\blambda\b/g // lambda expressions
21
- ];
22
- let complexity = 1; // Base complexity
23
- for (const pattern of patterns) {
24
- const matches = code.match(pattern);
25
- if (matches) {
26
- complexity += matches.length;
27
- }
28
- }
29
- return {
30
- value: complexity,
31
- threshold: THRESHOLDS.maxCyclomatic,
32
- status: complexity <= THRESHOLDS.maxCyclomatic ? 'pass' : 'fail',
33
- description: 'Python cyclomatic complexity (control flow branches)'
34
- };
35
- }
36
- /**
37
- * Calculate cognitive complexity for Python
38
- */
39
- export function calculatePythonCognitiveComplexity(code) {
40
- let complexity = 0;
41
- let nestingLevel = 0;
42
- const lines = code.split('\n');
43
- for (const line of lines) {
44
- const trimmed = line.trim();
45
- // Detect indentation level (Python uses indentation for nesting)
46
- const indent = line.match(/^(\s*)/)?.[1].length || 0;
47
- const currentNesting = Math.floor(indent / 4); // Assuming 4-space indents
48
- // Control flow that increases cognitive load
49
- if (/\b(if|elif|for|while|try|except|with)\b/.test(trimmed)) {
50
- complexity += 1 + currentNesting;
51
- }
52
- // Logical operators increase complexity
53
- const logicalOps = trimmed.match(/\b(and|or)\b/g);
54
- if (logicalOps) {
55
- complexity += logicalOps.length;
56
- }
57
- // List comprehensions add cognitive load
58
- if (/\[.*for.*in.*\]/.test(trimmed)) {
59
- complexity += 1;
60
- }
61
- // Nested functions
62
- if (/^\s+def\s+/.test(line)) {
63
- complexity += currentNesting;
64
- }
65
- }
66
- return {
67
- value: complexity,
68
- threshold: THRESHOLDS.maxCognitive,
69
- status: complexity <= THRESHOLDS.maxCognitive ? 'pass' : 'fail',
70
- description: 'Python cognitive complexity (mental load to understand)'
71
- };
72
- }
73
- /**
74
- * Analyze Python code quality
75
- */
76
- export function analyzePythonQuality(code) {
77
- const issues = [];
78
- const recommendations = [];
79
- // Check for common Python anti-patterns
80
- if (code.includes('eval(') || code.includes('exec(')) {
81
- issues.push('Use of eval() or exec() detected - security risk');
82
- recommendations.push('Avoid eval() and exec(), use safer alternatives');
83
- }
84
- if (/except:\s*$/.test(code)) {
85
- issues.push('Bare except clause detected');
86
- recommendations.push('Specify exception types: except ValueError:');
87
- }
88
- if (/import \*/.test(code)) {
89
- issues.push('Wildcard import detected');
90
- recommendations.push('Import specific names instead of using wildcard');
91
- }
92
- // Check for long functions
93
- const functionMatches = code.match(/def\s+\w+\([^)]*\):/g) || [];
94
- if (functionMatches.length > 0) {
95
- const avgFunctionLength = code.split('\n').length / functionMatches.length;
96
- if (avgFunctionLength > 50) {
97
- issues.push('Functions are too long (avg > 50 lines)');
98
- recommendations.push('Break down large functions into smaller ones');
99
- }
100
- }
101
- // Check for PEP 8 violations (basic)
102
- const lines = code.split('\n');
103
- const longLines = lines.filter(line => line.length > 79);
104
- if (longLines.length > lines.length * 0.2) {
105
- issues.push('Many lines exceed 79 characters (PEP 8)');
106
- recommendations.push('Keep lines under 79 characters for better readability');
107
- }
108
- return { issues, recommendations };
109
- }