@voodocs/cli 2.4.0 → 2.5.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,52 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## [2.5.1] - 2024-12-24
4
+
5
+ ### Fixed
6
+ - **Packaging Issue**: Fixed npm package to include missing files from v2.5.0
7
+ - Added `lib/darkarts/priority_analyzer/` directory
8
+ - Added `lib/darkarts/voodocs_lite_dict.py`
9
+ - Added `lib/darkarts/voodocs_lite_dict_v2.py`
10
+ - Added `lib/darkarts/voodocs_lite_parser.py`
11
+ - v2.5.0 was published with CHANGELOG updates but missing actual code files
12
+ - All Priority Analyzer and VooDocs Lite features now properly included
13
+
14
+ ---
15
+
16
+ ## [2.5.0] - 2024-12-24
17
+
18
+ ### Added
19
+ - **Priority Analyzer** - New `voodocs analyze` command to identify which files need annotations most urgently
20
+ - **Complexity Analysis**: LOC, cyclomatic complexity, function count
21
+ - **Security Keyword Detection**: auth, password, admin, crypto, SQL, payment, etc.
22
+ - **Dependency Analysis**: Import tracking and dependent file detection
23
+ - **Weighted Scoring**: Complexity (30%), Security (40%), Dependencies (20%), Annotations (10%)
24
+ - **Priority Levels**: CRITICAL (80-100), HIGH (60-79), MEDIUM (40-59), LOW (20-39), MINIMAL (0-19)
25
+ - **Multiple Output Formats**: text, JSON, CSV, Markdown
26
+ - **Filtering Options**: By priority level, minimum score, exclude patterns
27
+ - **Smart Suggestions**: Context-aware recommendations for each file
28
+ - **Priority Analyzer Modules**:
29
+ - `lib/darkarts/priority_analyzer/complexity.py` - Complexity analysis engine
30
+ - `lib/darkarts/priority_analyzer/security.py` - Security keyword detector
31
+ - `lib/darkarts/priority_analyzer/dependencies.py` - Dependency tracker
32
+ - `lib/darkarts/priority_analyzer/analyzer.py` - Main priority analyzer
33
+ - `lib/cli/analyze.py` - CLI command implementation
34
+ - **Comprehensive Test Suite** - 16 unit tests for priority analyzer functionality
35
+
36
+ ### Improved
37
+ - Heuristics for identifying security-sensitive code
38
+ - Dependency tracking for TypeScript, JavaScript, Python, and Solidity
39
+ - Annotation coverage detection and penalty calculation
40
+ - Priority scoring algorithm with empirical validation
41
+
42
+ ### Documentation
43
+ - Added Priority Analyzer section to README.md
44
+ - Added analyze command documentation with examples
45
+ - Added priority level definitions and scoring factors
46
+ - Added specification document for priority analyzer
47
+
48
+ ---
49
+
3
50
  ## [2.4.0] - 2025-12-24
4
51
 
5
52
  ### Added
package/README.md CHANGED
@@ -348,6 +348,32 @@ voodocs convert src/ --to lite --dry-run # Preview changes
348
348
  voodocs convert src/ --to lite --in-place # Modify files in-place
349
349
  ```
350
350
 
351
+ ### `voodocs analyze`
352
+
353
+ **NEW in v2.5.0!** Analyze files and suggest annotation priorities based on complexity, security, and dependencies:
354
+
355
+ ```bash
356
+ voodocs analyze src/ # Analyze directory
357
+ voodocs analyze src/ --top 20 # Show top 20 files
358
+ voodocs analyze src/ --priority critical # Filter by priority
359
+ voodocs analyze src/ --format json # JSON output
360
+ voodocs analyze src/ --min-score 60 # Only show files with score >= 60
361
+ voodocs analyze src/ --exclude node_modules,dist # Exclude patterns
362
+ ```
363
+
364
+ **Priority Levels:**
365
+ - 🔴 **CRITICAL** (80-100): Highly complex, security-sensitive, or widely-used files
366
+ - 🟠 **HIGH** (60-79): Complex or security-sensitive files
367
+ - 🟡 **MEDIUM** (40-59): Moderately complex files
368
+ - 🟢 **LOW** (20-39): Simple files with some complexity
369
+ - ⚪ **MINIMAL** (0-19): Very simple files
370
+
371
+ **Scoring Factors:**
372
+ - **Complexity** (30%): Lines of code, cyclomatic complexity, function count
373
+ - **Security** (40%): Security-sensitive keywords (auth, password, admin, etc.)
374
+ - **Dependencies** (20%): Import count and dependent files
375
+ - **Annotations** (10%): Penalty for missing VooDocs annotations
376
+
351
377
  ### `voodocs generate`
352
378
 
353
379
  Generate documentation from annotations:
@@ -0,0 +1,277 @@
1
+ """
2
+ CLI command for VooDocs Priority Analyzer
3
+
4
+ Usage: voodocs analyze [path] [options]
5
+ """
6
+
7
+ import os
8
+ import sys
9
+ from pathlib import Path
10
+
11
+ # Add parent directory to path for imports
12
+ sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../..')))
13
+
14
+ from lib.darkarts.priority_analyzer.analyzer import PriorityAnalyzer
15
+
16
+
17
+ def cmd_analyze(args):
18
+ """Execute the analyze command."""
19
+ # Get path (default to current directory)
20
+ path = args.path if hasattr(args, 'path') and args.path else '.'
21
+ path = os.path.abspath(path)
22
+
23
+ # Check if path exists
24
+ if not os.path.exists(path):
25
+ print(f"❌ Error: Path not found: {path}")
26
+ return 1
27
+
28
+ # Determine if path is file or directory
29
+ is_file = os.path.isfile(path)
30
+
31
+ # Initialize analyzer
32
+ project_root = path if not is_file else str(Path(path).parent)
33
+ analyzer = PriorityAnalyzer(project_root=project_root)
34
+
35
+ # Analyze
36
+ if is_file:
37
+ scores = [analyzer.analyze_file(path)]
38
+ else:
39
+ recursive = getattr(args, 'recursive', True)
40
+ exclude = getattr(args, 'exclude', None)
41
+ exclude_patterns = exclude.split(',') if exclude else None
42
+
43
+ print(f"🔍 Analyzing files in: {path}")
44
+ if recursive:
45
+ print(" (recursive mode)")
46
+ print()
47
+
48
+ scores = analyzer.analyze_directory(path, recursive, exclude_patterns)
49
+
50
+ # Filter by priority level if specified
51
+ if hasattr(args, 'priority') and args.priority:
52
+ priority_filter = args.priority.upper()
53
+ scores = [s for s in scores if s.priority_level == priority_filter]
54
+
55
+ # Filter by minimum score
56
+ if hasattr(args, 'min_score') and args.min_score:
57
+ scores = [s for s in scores if s.priority_score >= args.min_score]
58
+
59
+ # Filter out fully annotated files (unless --include-annotated)
60
+ if not getattr(args, 'include_annotated', False):
61
+ scores = [s for s in scores if s.annotation_coverage < 1.0]
62
+
63
+ # Limit to top N
64
+ top_n = getattr(args, 'top', 10)
65
+ if top_n and top_n > 0:
66
+ scores = scores[:top_n]
67
+
68
+ # Output format
69
+ output_format = getattr(args, 'format', 'text')
70
+
71
+ if output_format == 'json':
72
+ _output_json(scores)
73
+ elif output_format == 'csv':
74
+ _output_csv(scores)
75
+ elif output_format == 'markdown':
76
+ _output_markdown(scores)
77
+ else:
78
+ _output_text(scores, path)
79
+
80
+ return 0
81
+
82
+
83
+ def _output_text(scores, path):
84
+ """Output results in human-readable text format."""
85
+ if not scores:
86
+ print("✅ No files need annotations!")
87
+ print(" All files are either fully annotated or below priority threshold.")
88
+ return
89
+
90
+ # Calculate statistics
91
+ total_files = len(scores)
92
+ priority_dist = {
93
+ 'CRITICAL': len([s for s in scores if s.priority_level == 'CRITICAL']),
94
+ 'HIGH': len([s for s in scores if s.priority_level == 'HIGH']),
95
+ 'MEDIUM': len([s for s in scores if s.priority_level == 'MEDIUM']),
96
+ 'LOW': len([s for s in scores if s.priority_level == 'LOW']),
97
+ 'MINIMAL': len([s for s in scores if s.priority_level == 'MINIMAL']),
98
+ }
99
+
100
+ annotated_count = sum(1 for s in scores if s.annotation_coverage > 0)
101
+ coverage_pct = (annotated_count / total_files * 100) if total_files > 0 else 0
102
+
103
+ # Header
104
+ print("━" * 70)
105
+ print("VooDocs Priority Analysis")
106
+ print("━" * 70)
107
+ print()
108
+ print(f"Project: {path}")
109
+ print(f"Files analyzed: {total_files}")
110
+ print(f"Annotations found: {annotated_count} ({coverage_pct:.0f}% coverage)")
111
+ print()
112
+
113
+ # Priority distribution
114
+ print("Priority Distribution:")
115
+ if priority_dist['CRITICAL'] > 0:
116
+ print(f"🔴 CRITICAL (80-100): {priority_dist['CRITICAL']} files")
117
+ if priority_dist['HIGH'] > 0:
118
+ print(f"🟠 HIGH (60-79): {priority_dist['HIGH']} files")
119
+ if priority_dist['MEDIUM'] > 0:
120
+ print(f"🟡 MEDIUM (40-59): {priority_dist['MEDIUM']} files")
121
+ if priority_dist['LOW'] > 0:
122
+ print(f"🟢 LOW (20-39): {priority_dist['LOW']} files")
123
+ if priority_dist['MINIMAL'] > 0:
124
+ print(f"⚪ MINIMAL (0-19): {priority_dist['MINIMAL']} files")
125
+ print()
126
+
127
+ # Top files
128
+ print("━" * 70)
129
+ print(f"Top {len(scores)} Files Needing Annotations")
130
+ print("━" * 70)
131
+ print()
132
+
133
+ for i, score in enumerate(scores, 1):
134
+ # Priority emoji
135
+ emoji = {
136
+ 'CRITICAL': '🔴',
137
+ 'HIGH': '🟠',
138
+ 'MEDIUM': '🟡',
139
+ 'LOW': '🟢',
140
+ 'MINIMAL': '⚪'
141
+ }.get(score.priority_level, '⚪')
142
+
143
+ # Relative path
144
+ rel_path = os.path.relpath(score.filepath, path) if not os.path.isfile(path) else score.filepath
145
+
146
+ print(f"{i}. {emoji} {rel_path} (Score: {score.priority_score:.0f})")
147
+ print(f" Complexity: {score.complexity_score} Security: {score.security_score} Dependencies: {score.dependency_score} Annotations: {score.annotation_penalty}")
148
+ print()
149
+
150
+ # Reasons
151
+ if score.reasons:
152
+ print(" Reasons:")
153
+ for reason in score.reasons:
154
+ print(f" • {reason}")
155
+ print()
156
+
157
+ # Suggestions
158
+ if score.suggestions:
159
+ print(" Suggestions:")
160
+ for suggestion in score.suggestions:
161
+ print(f" ✓ {suggestion}")
162
+ print()
163
+
164
+ # Footer
165
+ print("━" * 70)
166
+ print()
167
+ print("💡 Tip: Start with CRITICAL files first. Use:")
168
+ if scores:
169
+ first_file = scores[0].filepath
170
+ print(f" voodocs companion {first_file}")
171
+ print()
172
+ print(" Or convert to VooDocs Lite for faster annotation:")
173
+ print(f" voodocs convert {path} --to lite --in-place")
174
+ print()
175
+
176
+
177
+ def _output_json(scores):
178
+ """Output results in JSON format."""
179
+ import json
180
+
181
+ data = []
182
+ for score in scores:
183
+ data.append({
184
+ 'filepath': score.filepath,
185
+ 'priority_score': score.priority_score,
186
+ 'priority_level': score.priority_level,
187
+ 'complexity_score': score.complexity_score,
188
+ 'security_score': score.security_score,
189
+ 'dependency_score': score.dependency_score,
190
+ 'annotation_penalty': score.annotation_penalty,
191
+ 'annotation_coverage': score.annotation_coverage,
192
+ 'loc': score.loc,
193
+ 'functions': score.functions,
194
+ 'security_keywords': score.security_keywords,
195
+ 'dependent_count': score.dependent_count,
196
+ 'reasons': score.reasons,
197
+ 'suggestions': score.suggestions
198
+ })
199
+
200
+ print(json.dumps(data, indent=2))
201
+
202
+
203
+ def _output_csv(scores):
204
+ """Output results in CSV format."""
205
+ import csv
206
+ import sys
207
+
208
+ writer = csv.writer(sys.stdout)
209
+
210
+ # Header
211
+ writer.writerow([
212
+ 'filepath', 'priority_score', 'priority_level',
213
+ 'complexity_score', 'security_score', 'dependency_score',
214
+ 'annotation_penalty', 'annotation_coverage',
215
+ 'loc', 'functions', 'dependent_count'
216
+ ])
217
+
218
+ # Data
219
+ for score in scores:
220
+ writer.writerow([
221
+ score.filepath,
222
+ score.priority_score,
223
+ score.priority_level,
224
+ score.complexity_score,
225
+ score.security_score,
226
+ score.dependency_score,
227
+ score.annotation_penalty,
228
+ score.annotation_coverage,
229
+ score.loc,
230
+ score.functions,
231
+ score.dependent_count
232
+ ])
233
+
234
+
235
+ def _output_markdown(scores):
236
+ """Output results in Markdown format."""
237
+ print("# VooDocs Priority Analysis")
238
+ print()
239
+ print("## Summary")
240
+ print()
241
+ print(f"- **Files analyzed:** {len(scores)}")
242
+ print()
243
+ print("## Top Files")
244
+ print()
245
+
246
+ for i, score in enumerate(scores, 1):
247
+ emoji = {
248
+ 'CRITICAL': '🔴',
249
+ 'HIGH': '🟠',
250
+ 'MEDIUM': '🟡',
251
+ 'LOW': '🟢',
252
+ 'MINIMAL': '⚪'
253
+ }.get(score.priority_level, '⚪')
254
+
255
+ print(f"### {i}. {emoji} {score.filepath}")
256
+ print()
257
+ print(f"**Score:** {score.priority_score:.0f} ({score.priority_level})")
258
+ print()
259
+ print(f"- Complexity: {score.complexity_score}")
260
+ print(f"- Security: {score.security_score}")
261
+ print(f"- Dependencies: {score.dependency_score}")
262
+ print(f"- Annotation Coverage: {score.annotation_coverage * 100:.0f}%")
263
+ print()
264
+
265
+ if score.reasons:
266
+ print("**Reasons:**")
267
+ print()
268
+ for reason in score.reasons:
269
+ print(f"- {reason}")
270
+ print()
271
+
272
+ if score.suggestions:
273
+ print("**Suggestions:**")
274
+ print()
275
+ for suggestion in score.suggestions:
276
+ print(f"- {suggestion}")
277
+ print()
File without changes
@@ -0,0 +1,301 @@
1
+ """
2
+ Main Priority Analyzer for VooDocs
3
+
4
+ Combines complexity, security, and dependency analysis to prioritize files.
5
+ """
6
+
7
+ import os
8
+ import re
9
+ from dataclasses import dataclass
10
+ from pathlib import Path
11
+ from typing import List, Dict, Optional
12
+
13
+ from .complexity import ComplexityAnalyzer
14
+ from .security import SecurityAnalyzer
15
+ from .dependencies import DependencyAnalyzer
16
+
17
+
18
+ @dataclass
19
+ class FileScore:
20
+ """Score and analysis for a single file."""
21
+ filepath: str
22
+ priority_score: float
23
+ complexity_score: int
24
+ security_score: int
25
+ dependency_score: int
26
+ annotation_penalty: int
27
+ priority_level: str
28
+ reasons: List[str]
29
+ suggestions: List[str]
30
+
31
+ # Detailed metrics
32
+ loc: int = 0
33
+ cyclomatic: int = 0
34
+ functions: int = 0
35
+ security_keywords: List[str] = None
36
+ import_count: int = 0
37
+ dependent_count: int = 0
38
+ annotation_coverage: float = 0.0
39
+
40
+
41
+ class PriorityAnalyzer:
42
+ """Main analyzer that combines all scoring components."""
43
+
44
+ # Scoring weights
45
+ COMPLEXITY_WEIGHT = 0.30
46
+ SECURITY_WEIGHT = 0.40
47
+ DEPENDENCY_WEIGHT = 0.20
48
+ ANNOTATION_WEIGHT = 0.10
49
+
50
+ # Priority level thresholds
51
+ PRIORITY_THRESHOLDS = {
52
+ 'CRITICAL': 80,
53
+ 'HIGH': 60,
54
+ 'MEDIUM': 40,
55
+ 'LOW': 20,
56
+ 'MINIMAL': 0
57
+ }
58
+
59
+ # Supported file extensions
60
+ SUPPORTED_EXTENSIONS = {'.py', '.ts', '.tsx', '.js', '.jsx', '.sol'}
61
+
62
+ def __init__(self, project_root: str = None):
63
+ """
64
+ Initialize priority analyzer.
65
+
66
+ Args:
67
+ project_root: Root directory of the project
68
+ """
69
+ self.project_root = project_root
70
+ self.complexity_analyzer = ComplexityAnalyzer()
71
+ self.security_analyzer = SecurityAnalyzer()
72
+ self.dependency_analyzer = DependencyAnalyzer(project_root)
73
+
74
+ def analyze_file(self, filepath: str, all_files: List[str] = None) -> FileScore:
75
+ """
76
+ Analyze a single file and calculate priority score.
77
+
78
+ Args:
79
+ filepath: Path to file to analyze
80
+ all_files: List of all files (for dependency analysis)
81
+
82
+ Returns:
83
+ FileScore object with complete analysis
84
+ """
85
+ # Run individual analyzers
86
+ complexity = self.complexity_analyzer.analyze_file(filepath)
87
+ security = self.security_analyzer.analyze_file(filepath)
88
+ dependencies = self.dependency_analyzer.analyze_file(filepath, all_files)
89
+
90
+ # Check annotation coverage
91
+ annotation_coverage, annotation_penalty = self._check_annotation_coverage(filepath)
92
+
93
+ # Calculate weighted priority score
94
+ priority_score = (
95
+ complexity['total_score'] * self.COMPLEXITY_WEIGHT +
96
+ security['total_score'] * self.SECURITY_WEIGHT +
97
+ dependencies['total_score'] * self.DEPENDENCY_WEIGHT +
98
+ annotation_penalty * self.ANNOTATION_WEIGHT
99
+ )
100
+
101
+ # Determine priority level
102
+ priority_level = self._get_priority_level(priority_score)
103
+
104
+ # Generate reasons and suggestions
105
+ reasons = self._generate_reasons(complexity, security, dependencies, annotation_coverage)
106
+ suggestions = self._generate_suggestions(complexity, security, dependencies, annotation_coverage)
107
+
108
+ # Combine all security keywords
109
+ all_keywords = (
110
+ security.get('critical_keywords', []) +
111
+ security.get('high_keywords', []) +
112
+ security.get('medium_keywords', [])
113
+ )
114
+
115
+ return FileScore(
116
+ filepath=filepath,
117
+ priority_score=round(priority_score, 1),
118
+ complexity_score=complexity['total_score'],
119
+ security_score=security['total_score'],
120
+ dependency_score=dependencies['total_score'],
121
+ annotation_penalty=annotation_penalty,
122
+ priority_level=priority_level,
123
+ reasons=reasons,
124
+ suggestions=suggestions,
125
+ loc=complexity.get('loc', 0),
126
+ cyclomatic=complexity.get('cyclomatic', 0),
127
+ functions=complexity.get('functions', 0),
128
+ security_keywords=all_keywords[:10], # Top 10
129
+ import_count=dependencies.get('import_count', 0),
130
+ dependent_count=dependencies.get('dependent_count', 0),
131
+ annotation_coverage=annotation_coverage
132
+ )
133
+
134
+ def analyze_directory(self, dirpath: str, recursive: bool = True,
135
+ exclude_patterns: List[str] = None) -> List[FileScore]:
136
+ """
137
+ Analyze all files in a directory.
138
+
139
+ Args:
140
+ dirpath: Directory path to analyze
141
+ recursive: Whether to scan subdirectories
142
+ exclude_patterns: Patterns to exclude (e.g., ['node_modules', 'dist'])
143
+
144
+ Returns:
145
+ List of FileScore objects, sorted by priority (highest first)
146
+ """
147
+ if exclude_patterns is None:
148
+ exclude_patterns = ['node_modules', 'dist', 'build', '.git', '__pycache__']
149
+
150
+ # Find all files
151
+ all_files = self._find_files(dirpath, recursive, exclude_patterns)
152
+
153
+ # Analyze each file
154
+ scores = []
155
+ for filepath in all_files:
156
+ try:
157
+ score = self.analyze_file(filepath, all_files)
158
+ scores.append(score)
159
+ except Exception as e:
160
+ print(f"Warning: Failed to analyze {filepath}: {e}")
161
+
162
+ # Sort by priority score (highest first)
163
+ scores.sort(key=lambda x: x.priority_score, reverse=True)
164
+
165
+ return scores
166
+
167
+ def _find_files(self, dirpath: str, recursive: bool, exclude_patterns: List[str]) -> List[str]:
168
+ """Find all supported files in directory."""
169
+ files = []
170
+
171
+ if recursive:
172
+ for root, dirs, filenames in os.walk(dirpath):
173
+ # Filter out excluded directories
174
+ dirs[:] = [d for d in dirs if not any(pattern in d for pattern in exclude_patterns)]
175
+
176
+ for filename in filenames:
177
+ filepath = os.path.join(root, filename)
178
+ if Path(filepath).suffix in self.SUPPORTED_EXTENSIONS:
179
+ files.append(filepath)
180
+ else:
181
+ for filename in os.listdir(dirpath):
182
+ filepath = os.path.join(dirpath, filename)
183
+ if os.path.isfile(filepath) and Path(filepath).suffix in self.SUPPORTED_EXTENSIONS:
184
+ files.append(filepath)
185
+
186
+ return files
187
+
188
+ def _check_annotation_coverage(self, filepath: str) -> tuple:
189
+ """
190
+ Check VooDocs annotation coverage in file.
191
+
192
+ Returns:
193
+ Tuple of (coverage_percentage, penalty_score)
194
+ """
195
+ try:
196
+ with open(filepath, 'r', encoding='utf-8') as f:
197
+ content = f.read()
198
+ except:
199
+ return (0.0, -50)
200
+
201
+ # Count @darkarts annotations
202
+ darkarts_count = len(re.findall(r'@darkarts(-lite)?', content))
203
+
204
+ # Count total functions (rough estimate)
205
+ function_patterns = [
206
+ r'^\s*def\s+\w+\s*\(', # Python
207
+ r'^\s*(export\s+)?(async\s+)?function\s+\w+\s*\(', # JS/TS function
208
+ r'^\s*(const|let|var)\s+\w+\s*=\s*(\([^)]*\)|[^=]+)\s*=>', # Arrow function
209
+ r'^\s*function\s+\w+\s*\(', # Solidity
210
+ ]
211
+
212
+ total_functions = 0
213
+ for pattern in function_patterns:
214
+ total_functions += len(re.findall(pattern, content, re.MULTILINE))
215
+
216
+ # Calculate coverage
217
+ if total_functions == 0:
218
+ # No functions, check if file has any annotations
219
+ coverage = 1.0 if darkarts_count > 0 else 0.0
220
+ else:
221
+ coverage = min(1.0, darkarts_count / total_functions)
222
+
223
+ # Calculate penalty
224
+ if coverage == 0:
225
+ penalty = -50
226
+ elif coverage < 0.5:
227
+ penalty = -25
228
+ else:
229
+ penalty = 0
230
+
231
+ return (coverage, penalty)
232
+
233
+ def _get_priority_level(self, score: float) -> str:
234
+ """Determine priority level from score."""
235
+ if score >= self.PRIORITY_THRESHOLDS['CRITICAL']:
236
+ return 'CRITICAL'
237
+ elif score >= self.PRIORITY_THRESHOLDS['HIGH']:
238
+ return 'HIGH'
239
+ elif score >= self.PRIORITY_THRESHOLDS['MEDIUM']:
240
+ return 'MEDIUM'
241
+ elif score >= self.PRIORITY_THRESHOLDS['LOW']:
242
+ return 'LOW'
243
+ else:
244
+ return 'MINIMAL'
245
+
246
+ def _generate_reasons(self, complexity: Dict, security: Dict,
247
+ dependencies: Dict, annotation_coverage: float) -> List[str]:
248
+ """Generate human-readable reasons for priority score."""
249
+ reasons = []
250
+
251
+ # Complexity reasons
252
+ if complexity['total_score'] >= 60:
253
+ reasons.append(f"High complexity: {complexity['loc']} LOC, {complexity['functions']} functions")
254
+ elif complexity['total_score'] >= 30:
255
+ reasons.append(f"Medium complexity: {complexity['loc']} LOC, {complexity['functions']} functions")
256
+
257
+ # Security reasons
258
+ if security.get('critical_keywords'):
259
+ keywords = ', '.join(security['critical_keywords'][:5])
260
+ reasons.append(f"Security keywords: {keywords}")
261
+
262
+ # Dependency reasons
263
+ if dependencies.get('dependent_count', 0) > 0:
264
+ reasons.append(f"Depended upon by {dependencies['dependent_count']} file(s)")
265
+
266
+ # Annotation reasons
267
+ if annotation_coverage == 0:
268
+ reasons.append("No VooDocs annotations found")
269
+ elif annotation_coverage < 0.5:
270
+ reasons.append(f"Partial annotations ({int(annotation_coverage * 100)}% coverage)")
271
+
272
+ return reasons
273
+
274
+ def _generate_suggestions(self, complexity: Dict, security: Dict,
275
+ dependencies: Dict, annotation_coverage: float) -> List[str]:
276
+ """Generate actionable suggestions."""
277
+ suggestions = []
278
+
279
+ # Security suggestions
280
+ suggestions.extend(self.security_analyzer.get_security_suggestions(security))
281
+
282
+ # Dependency suggestions
283
+ suggestions.extend(self.dependency_analyzer.get_dependency_suggestions(dependencies))
284
+
285
+ # Complexity suggestions
286
+ if complexity['total_score'] >= 60:
287
+ suggestions.append("Break down complex logic into smaller functions")
288
+ suggestions.append("Document high-complexity sections")
289
+
290
+ # Annotation suggestions
291
+ if annotation_coverage == 0:
292
+ suggestions.append("Add @darkarts annotations to all functions")
293
+ suggestions.append("Start with module-level purpose annotation")
294
+ elif annotation_coverage < 1.0:
295
+ suggestions.append("Complete remaining function annotations")
296
+
297
+ # Generic suggestions
298
+ if not suggestions:
299
+ suggestions.append("Add comprehensive VooDocs annotations")
300
+
301
+ return suggestions[:5] # Limit to top 5