@voodocs/cli 0.4.2 → 1.0.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.
Files changed (55) hide show
  1. package/CHANGELOG.md +431 -0
  2. package/lib/cli/__init__.py +53 -0
  3. package/lib/cli/benchmark.py +311 -0
  4. package/lib/cli/fix.py +244 -0
  5. package/lib/cli/generate.py +310 -0
  6. package/lib/cli/test_cli.py +215 -0
  7. package/lib/cli/validate.py +364 -0
  8. package/lib/darkarts/__init__.py +11 -5
  9. package/lib/darkarts/annotations/__init__.py +11 -3
  10. package/lib/darkarts/annotations/darkarts_parser.py +1 -1
  11. package/lib/darkarts/annotations/translator.py +32 -5
  12. package/lib/darkarts/annotations/types.py +15 -2
  13. package/lib/darkarts/cli_darkarts.py +143 -15
  14. package/lib/darkarts/context/__init__.py +11 -3
  15. package/lib/darkarts/context/ai_integrations.py +7 -21
  16. package/lib/darkarts/context/commands.py +1 -1
  17. package/lib/darkarts/context/diagram.py +8 -22
  18. package/lib/darkarts/context/models.py +7 -22
  19. package/lib/darkarts/context/module_utils.py +1 -1
  20. package/lib/darkarts/context/ui.py +1 -1
  21. package/lib/darkarts/context/validation.py +1 -1
  22. package/lib/darkarts/context/yaml_utils.py +8 -23
  23. package/lib/darkarts/core/__init__.py +12 -2
  24. package/lib/darkarts/core/interface.py +15 -1
  25. package/lib/darkarts/core/loader.py +16 -1
  26. package/lib/darkarts/core/plugin.py +15 -2
  27. package/lib/darkarts/core/registry.py +16 -1
  28. package/lib/darkarts/exceptions.py +16 -2
  29. package/lib/darkarts/plugins/voodocs/__init__.py +12 -2
  30. package/lib/darkarts/plugins/voodocs/ai_native_plugin.py +15 -4
  31. package/lib/darkarts/plugins/voodocs/annotation_validator.py +15 -2
  32. package/lib/darkarts/plugins/voodocs/api_spec_generator.py +15 -2
  33. package/lib/darkarts/plugins/voodocs/documentation_generator.py +15 -2
  34. package/lib/darkarts/plugins/voodocs/html_exporter.py +15 -2
  35. package/lib/darkarts/plugins/voodocs/instruction_generator.py +1 -1
  36. package/lib/darkarts/plugins/voodocs/pdf_exporter.py +15 -2
  37. package/lib/darkarts/plugins/voodocs/test_generator.py +15 -2
  38. package/lib/darkarts/telemetry.py +15 -2
  39. package/lib/darkarts/validation/README.md +147 -0
  40. package/lib/darkarts/validation/__init__.py +91 -0
  41. package/lib/darkarts/validation/autofix.py +297 -0
  42. package/lib/darkarts/validation/benchmark.py +426 -0
  43. package/lib/darkarts/validation/benchmark_wrapper.py +22 -0
  44. package/lib/darkarts/validation/config.py +257 -0
  45. package/lib/darkarts/validation/performance.py +412 -0
  46. package/lib/darkarts/validation/performance_wrapper.py +37 -0
  47. package/lib/darkarts/validation/semantic.py +461 -0
  48. package/lib/darkarts/validation/semantic_wrapper.py +77 -0
  49. package/lib/darkarts/validation/test_validation.py +160 -0
  50. package/lib/darkarts/validation/types.py +97 -0
  51. package/lib/darkarts/validation/watch.py +239 -0
  52. package/package.json +19 -6
  53. package/voodocs_cli.py +28 -0
  54. package/cli.py +0 -1646
  55. package/lib/darkarts/cli.py +0 -128
@@ -0,0 +1,97 @@
1
+ """@darkarts
2
+ ⊢validation:types
3
+ ∂{dataclasses,typing}
4
+ ⚠{python≥3.7}
5
+ ⊨{∀type→immutable,∀result→serializable}
6
+ 🔒{read-only:dataclasses}
7
+ ⚡{O(1):creation}
8
+ """
9
+
10
+ """
11
+ Shared type definitions for validation module.
12
+ """
13
+
14
+ from dataclasses import dataclass, field
15
+ from typing import Set, List, Dict, Optional, Any
16
+
17
+
18
+ @dataclass
19
+ class ValidationResult:
20
+ """Result of semantic validation."""
21
+ file_path: str
22
+ is_valid: bool
23
+ missing_deps: Set[str] = field(default_factory=set)
24
+ extra_deps: Set[str] = field(default_factory=set)
25
+ errors: List[str] = field(default_factory=list)
26
+ warnings: List[str] = field(default_factory=list)
27
+ suggestions: List[str] = field(default_factory=list)
28
+
29
+ def to_dict(self) -> Dict[str, Any]:
30
+ """Convert to dictionary for serialization."""
31
+ return {
32
+ "file_path": self.file_path,
33
+ "is_valid": self.is_valid,
34
+ "missing_deps": list(self.missing_deps),
35
+ "extra_deps": list(self.extra_deps),
36
+ "errors": self.errors,
37
+ "warnings": self.warnings,
38
+ "suggestions": self.suggestions,
39
+ }
40
+
41
+
42
+ @dataclass
43
+ class PerformanceResult:
44
+ """Result of performance validation."""
45
+ file_path: str
46
+ is_valid: bool
47
+ claimed_complexity: str
48
+ actual_complexity: str
49
+ loop_count: int
50
+ max_depth: int
51
+ has_recursion: bool
52
+ errors: List[str] = field(default_factory=list)
53
+ warnings: List[str] = field(default_factory=list)
54
+ suggestions: List[str] = field(default_factory=list)
55
+
56
+ def to_dict(self) -> Dict[str, Any]:
57
+ """Convert to dictionary for serialization."""
58
+ return {
59
+ "file_path": self.file_path,
60
+ "is_valid": self.is_valid,
61
+ "claimed_complexity": self.claimed_complexity,
62
+ "actual_complexity": self.actual_complexity,
63
+ "loop_count": self.loop_count,
64
+ "max_depth": self.max_depth,
65
+ "has_recursion": self.has_recursion,
66
+ "errors": self.errors,
67
+ "warnings": self.warnings,
68
+ "suggestions": self.suggestions,
69
+ }
70
+
71
+
72
+ @dataclass
73
+ class BenchmarkResult:
74
+ """Result of performance benchmarking."""
75
+ function_name: str
76
+ input_sizes: List[int]
77
+ execution_times: List[float]
78
+ claimed_complexity: str
79
+ fitted_complexity: str
80
+ is_valid: bool
81
+ confidence: float
82
+ errors: List[str] = field(default_factory=list)
83
+ warnings: List[str] = field(default_factory=list)
84
+
85
+ def to_dict(self) -> Dict[str, Any]:
86
+ """Convert to dictionary for serialization."""
87
+ return {
88
+ "function_name": self.function_name,
89
+ "input_sizes": self.input_sizes,
90
+ "execution_times": self.execution_times,
91
+ "claimed_complexity": self.claimed_complexity,
92
+ "fitted_complexity": self.fitted_complexity,
93
+ "is_valid": self.is_valid,
94
+ "confidence": self.confidence,
95
+ "errors": self.errors,
96
+ "warnings": self.warnings,
97
+ }
@@ -0,0 +1,239 @@
1
+ """@darkarts
2
+ ⊢watch:validation.continuous-monitoring
3
+ ∂{time,pathlib,typing,hashlib,semantic_validator}
4
+ ⚠{python≥3.7,filesystem:accessible}
5
+ ⊨{∀change→validated,∀error→reported,continuous:non-blocking,responsive:sub-second}
6
+ 🔒{read-only:files,¬write,¬network,¬exec}
7
+ ⚡{O(n²):per-check|n=watched-files,hash-based:change-detection}
8
+
9
+ Watch Mode for Continuous Validation
10
+
11
+ Monitors files for changes and validates annotations in real-time with:
12
+ - File system monitoring (efficient hash-based change detection)
13
+ - Instant validation (validates on save)
14
+ - Live feedback (immediate error reporting)
15
+ - Selective watching (specific files or directories)
16
+ - Debouncing (prevents validation spam)
17
+ - Background operation (non-blocking)
18
+ """
19
+
20
+ import time
21
+ import hashlib
22
+ from pathlib import Path
23
+ from typing import Dict, Set, Optional, Callable
24
+ from dataclasses import dataclass
25
+ from datetime import datetime
26
+
27
+ from semantic_validator import validate_file, ValidationResult
28
+
29
+
30
+ @dataclass
31
+ class FileState:
32
+ """State of a monitored file."""
33
+ path: Path
34
+ hash: str
35
+ last_validated: datetime
36
+ last_result: Optional[ValidationResult] = None
37
+
38
+
39
+ class FileWatcher:
40
+ """Watches Python files for changes and validates annotations."""
41
+
42
+ def __init__(
43
+ self,
44
+ paths: Set[Path],
45
+ interval: float = 1.0,
46
+ on_change: Optional[Callable[[Path, ValidationResult], None]] = None,
47
+ debounce: float = 0.5
48
+ ):
49
+ """
50
+ Initialize the file watcher.
51
+
52
+ Args:
53
+ paths: Set of file or directory paths to watch
54
+ interval: Check interval in seconds (default: 1.0)
55
+ on_change: Callback function called when a file changes
56
+ debounce: Minimum time between validations of the same file
57
+ """
58
+ self.paths = paths
59
+ self.interval = interval
60
+ self.on_change = on_change
61
+ self.debounce = debounce
62
+
63
+ self.file_states: Dict[Path, FileState] = {}
64
+ self.running = False
65
+
66
+ # Initialize file states
67
+ self._discover_files()
68
+
69
+ def _discover_files(self):
70
+ """Discover all Python files in the watched paths."""
71
+ for path in self.paths:
72
+ if path.is_file() and path.suffix == '.py':
73
+ self._add_file(path)
74
+ elif path.is_dir():
75
+ for py_file in path.rglob("*.py"):
76
+ if not py_file.name.startswith('.'):
77
+ self._add_file(py_file)
78
+
79
+ def _add_file(self, file_path: Path):
80
+ """Add a file to the watch list."""
81
+ if file_path not in self.file_states:
82
+ file_hash = self._compute_hash(file_path)
83
+ self.file_states[file_path] = FileState(
84
+ path=file_path,
85
+ hash=file_hash,
86
+ last_validated=datetime.now()
87
+ )
88
+
89
+ def _compute_hash(self, file_path: Path) -> str:
90
+ """Compute SHA256 hash of a file."""
91
+ try:
92
+ content = file_path.read_bytes()
93
+ return hashlib.sha256(content).hexdigest()
94
+ except Exception:
95
+ return ""
96
+
97
+ def _check_file(self, file_path: Path) -> Optional[ValidationResult]:
98
+ """
99
+ Check if a file has changed and validate if needed.
100
+
101
+ Args:
102
+ file_path: Path to the file
103
+
104
+ Returns:
105
+ ValidationResult if file changed and was validated, None otherwise
106
+ """
107
+ if not file_path.exists():
108
+ # File was deleted
109
+ if file_path in self.file_states:
110
+ del self.file_states[file_path]
111
+ return None
112
+
113
+ current_hash = self._compute_hash(file_path)
114
+ state = self.file_states.get(file_path)
115
+
116
+ if state is None:
117
+ # New file discovered
118
+ self._add_file(file_path)
119
+ state = self.file_states[file_path]
120
+
121
+ # Check if file changed
122
+ if current_hash != state.hash:
123
+ # Check debounce
124
+ time_since_last = (datetime.now() - state.last_validated).total_seconds()
125
+ if time_since_last < self.debounce:
126
+ return None
127
+
128
+ # File changed - validate it
129
+ try:
130
+ result = validate_file(file_path)
131
+
132
+ # Update state
133
+ state.hash = current_hash
134
+ state.last_validated = datetime.now()
135
+ state.last_result = result
136
+
137
+ return result
138
+ except Exception as e:
139
+ print(f"Error validating {file_path}: {e}")
140
+ return None
141
+
142
+ return None
143
+
144
+ def watch(self):
145
+ """Start watching files for changes."""
146
+ self.running = True
147
+
148
+ print(f"👀 Watching {len(self.file_states)} files...")
149
+ print(f" Interval: {self.interval}s")
150
+ print(f" Debounce: {self.debounce}s")
151
+ print(" Press Ctrl+C to stop\n")
152
+
153
+ try:
154
+ while self.running:
155
+ # Check all files
156
+ for file_path in list(self.file_states.keys()):
157
+ result = self._check_file(file_path)
158
+
159
+ if result is not None:
160
+ # File changed and was validated
161
+ self._report_result(file_path, result)
162
+
163
+ # Call callback if provided
164
+ if self.on_change:
165
+ self.on_change(file_path, result)
166
+
167
+ # Sleep before next check
168
+ time.sleep(self.interval)
169
+
170
+ except KeyboardInterrupt:
171
+ print("\n\n⏹️ Watch stopped")
172
+ self.running = False
173
+
174
+ def _report_result(self, file_path: Path, result: ValidationResult):
175
+ """Report validation result to console."""
176
+ timestamp = datetime.now().strftime("%H:%M:%S")
177
+
178
+ if result.is_valid:
179
+ print(f"[{timestamp}] ✅ {file_path.name}: Valid")
180
+ else:
181
+ print(f"[{timestamp}] ❌ {file_path.name}: Invalid")
182
+
183
+ if result.missing_deps:
184
+ print(f" Missing: {', '.join(sorted(result.missing_deps))}")
185
+
186
+ if result.extra_deps:
187
+ print(f" Extra: {', '.join(sorted(result.extra_deps))}")
188
+
189
+ if result.suggestions:
190
+ for suggestion in result.suggestions[:2]: # Show first 2 suggestions
191
+ print(f" 💡 {suggestion}")
192
+
193
+ print()
194
+
195
+ def stop(self):
196
+ """Stop watching files."""
197
+ self.running = False
198
+
199
+
200
+ def watch_with_autofix(
201
+ paths: Set[Path],
202
+ interval: float = 1.0,
203
+ auto_fix: bool = False
204
+ ):
205
+ """
206
+ Watch files and optionally auto-fix on change.
207
+
208
+ Args:
209
+ paths: Set of paths to watch
210
+ interval: Check interval in seconds
211
+ auto_fix: Whether to automatically fix invalid annotations
212
+ """
213
+ if auto_fix:
214
+ from autofix import AutoFixer
215
+ fixer = AutoFixer(dry_run=False)
216
+
217
+ def on_change_callback(file_path: Path, result: ValidationResult):
218
+ if not result.is_valid:
219
+ print(f" 🔧 Auto-fixing {file_path.name}...")
220
+ fix_result = fixer.fix_file(file_path)
221
+ if fix_result.success:
222
+ print(f" ✅ Fixed!")
223
+ else:
224
+ print(f" ❌ Fix failed: {fix_result.error}")
225
+ print()
226
+
227
+ watcher = FileWatcher(
228
+ paths=paths,
229
+ interval=interval,
230
+ on_change=on_change_callback
231
+ )
232
+ else:
233
+ watcher = FileWatcher(paths=paths, interval=interval)
234
+
235
+ watcher.watch()
236
+
237
+
238
+
239
+ # CLI interface removed - use darkarts.validation API or voodocs CLI instead
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@voodocs/cli",
3
- "version": "0.4.2",
4
- "description": "AI-Native Documentation System - Generate docs, tests, and API specs from @voodocs annotations using the DarkArts language",
5
- "main": "cli.py",
3
+ "version": "1.0.1",
4
+ "description": "AI-Native Documentation System with Validation - The only documentation tool that validates your annotations and guarantees accuracy",
5
+ "main": "voodocs_cli.py",
6
6
  "bin": {
7
- "voodocs": "./cli.py"
7
+ "voodocs": "./voodocs_cli.py"
8
8
  },
9
9
  "scripts": {
10
10
  "postinstall": "cd lib/darkarts/parsers/typescript && npm install && npm run build",
@@ -13,6 +13,7 @@
13
13
  },
14
14
  "keywords": [
15
15
  "documentation",
16
+ "validation",
16
17
  "ai",
17
18
  "voodocs",
18
19
  "darkarts",
@@ -24,7 +25,13 @@
24
25
  "cursor",
25
26
  "claude",
26
27
  "property-based-testing",
27
- "hypothesis"
28
+ "hypothesis",
29
+ "annotation-validation",
30
+ "semantic-validation",
31
+ "performance-validation",
32
+ "benchmarking",
33
+ "auto-fix",
34
+ "ci-cd"
28
35
  ],
29
36
  "author": "3vilEnterprises <contact@3vil.enterprises>",
30
37
  "license": "Commercial",
@@ -44,11 +51,13 @@
44
51
  "dependencies": {},
45
52
  "devDependencies": {},
46
53
  "files": [
47
- "cli.py",
54
+ "voodocs_cli.py",
55
+ "lib/cli/",
48
56
  "lib/darkarts/cli_darkarts.py",
49
57
  "lib/darkarts/annotations/",
50
58
  "lib/darkarts/context/",
51
59
  "lib/darkarts/core/",
60
+ "lib/darkarts/validation/",
52
61
  "lib/darkarts/exceptions.py",
53
62
  "lib/darkarts/telemetry.py",
54
63
  "lib/darkarts/parsers/typescript/dist/",
@@ -58,6 +67,9 @@
58
67
  "lib/darkarts/parsers/typescript/tsconfig.json",
59
68
  "lib/darkarts/plugins/voodocs/",
60
69
  "lib/darkarts/__init__.py",
70
+ "docs/darkarts/USER_GUIDE.md",
71
+ "docs/darkarts/API_REFERENCE.md",
72
+ "docs/darkarts/TUTORIALS.md",
61
73
  "examples/",
62
74
  "templates/",
63
75
  "README.md",
@@ -65,6 +77,7 @@
65
77
  "USAGE.md",
66
78
  "PRIVACY.md",
67
79
  "CHANGELOG.md",
80
+ "RELEASE_NOTES_v1.0.0.md",
68
81
  "requirements.txt"
69
82
  ],
70
83
  "os": [
package/voodocs_cli.py ADDED
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env python3
2
+ """@darkarts
3
+ ⊢voodocs:cli.entry
4
+ ∂{sys,pathlib}
5
+ ⚠{python≥3.7}
6
+ ⊨{∀command→executable}
7
+ 🔒{read-only:cli-entry}
8
+ ⚡{O(1):startup}
9
+ """
10
+
11
+ """
12
+ VooDocs CLI Entry Point
13
+
14
+ This is the main entry point for the voodocs command-line tool.
15
+ """
16
+
17
+ import sys
18
+ from pathlib import Path
19
+
20
+ # Add lib to path
21
+ lib_path = Path(__file__).parent / "lib"
22
+ sys.path.insert(0, str(lib_path))
23
+
24
+ # Import and run CLI
25
+ from cli import main
26
+
27
+ if __name__ == "__main__":
28
+ main()