@voodocs/cli 2.1.3 ā 2.2.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 +215 -38
- package/LICENSE +1 -1
- package/PRIVACY.md +10 -10
- package/README.md +39 -35
- package/USAGE.md +50 -27
- package/examples/.cursorrules +9 -9
- package/examples/instructions/.claude/instructions.md +77 -65
- package/examples/instructions/.cursorrules +9 -9
- package/examples/instructions/.windsurfrules +9 -9
- package/examples/instructions/VOODOCS_INSTRUCTIONS.md +74 -62
- package/examples/math_example.py +1 -1
- package/examples/phase2_test.py +1 -1
- package/examples/test_function_invariants.py +1 -1
- package/lib/cli/__init__.py +3 -3
- package/lib/cli/benchmark.py +3 -3
- package/lib/cli/context.py +1 -1
- package/lib/cli/fix.py +1 -1
- package/lib/cli/generate.py +60 -1
- package/lib/cli/init.py +10 -10
- package/lib/cli/instruct.py +1 -1
- package/lib/cli/validate.py +3 -3
- package/lib/darkarts/annotations/DARKARTS_SYMBOLS.md +110 -95
- package/lib/darkarts/annotations/TRANSFORMATION_EXAMPLES.md +29 -27
- package/lib/darkarts/annotations/parser.py +1 -1
- package/lib/darkarts/cli_darkarts.py +5 -5
- package/lib/darkarts/context/ai_instructions.py +12 -12
- package/lib/darkarts/context/ai_integrations.py +16 -16
- package/lib/darkarts/context/commands.py +4 -4
- package/lib/darkarts/context/errors.py +1 -1
- package/lib/darkarts/context/models.py +1 -1
- package/lib/darkarts/context/ui.py +4 -4
- package/lib/darkarts/context/yaml_utils.py +3 -3
- package/lib/darkarts/core/loader.py +1 -1
- package/lib/darkarts/documentation/__init__.py +10 -0
- package/lib/darkarts/documentation/categorizer.py +137 -0
- package/lib/darkarts/documentation/consolidator.py +303 -0
- package/lib/darkarts/exceptions.py +3 -3
- package/lib/darkarts/plugins/voodocs/ai_native_plugin.py +1 -1
- package/lib/darkarts/plugins/voodocs/annotation_validator.py +2 -2
- package/lib/darkarts/plugins/voodocs/documentation_generator.py +3 -3
- package/lib/darkarts/plugins/voodocs/html_exporter.py +4 -4
- package/lib/darkarts/plugins/voodocs/instruction_generator.py +10 -10
- package/lib/darkarts/plugins/voodocs/pdf_exporter.py +1 -1
- package/lib/darkarts/plugins/voodocs/test_generator.py +1 -1
- package/lib/darkarts/telemetry.py +5 -5
- package/lib/darkarts/validation/README.md +6 -3
- package/package.json +2 -1
- package/requirements.txt +2 -2
- package/templates/ci/github-actions.yml +64 -64
- package/templates/ci/pre-commit-hook.sh +4 -4
- package/voodocs_cli.py +1 -1
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
š{read-only:detect,write:explicit-user-command}
|
|
7
7
|
ā”{O(n²):detect-with-analysis,O(k):generate|k=ai-count}
|
|
8
8
|
|
|
9
|
-
AI-specific integration templates for
|
|
9
|
+
AI-specific integration templates for Voodocs Context System.
|
|
10
10
|
|
|
11
11
|
This module provides native integration with different AI assistants:
|
|
12
12
|
- Claude Code (skills)
|
|
@@ -23,7 +23,7 @@ from pathlib import Path
|
|
|
23
23
|
|
|
24
24
|
def generate_claude_skill(project_name: str, project_purpose: str) -> Dict[str, str]:
|
|
25
25
|
"""
|
|
26
|
-
Generate Claude Code skill for
|
|
26
|
+
Generate Claude Code skill for Voodocs context system.
|
|
27
27
|
|
|
28
28
|
Args:
|
|
29
29
|
project_name: Name of the project
|
|
@@ -34,15 +34,15 @@ def generate_claude_skill(project_name: str, project_purpose: str) -> Dict[str,
|
|
|
34
34
|
"""
|
|
35
35
|
skill_md = f"""---
|
|
36
36
|
name: voodocs-context
|
|
37
|
-
description: Access and query the
|
|
37
|
+
description: Access and query the Voodocs context system for project understanding, invariants, and architecture
|
|
38
38
|
---
|
|
39
39
|
|
|
40
|
-
#
|
|
40
|
+
# Voodocs Context System Skill
|
|
41
41
|
|
|
42
42
|
## Project: {project_name}
|
|
43
43
|
{project_purpose}
|
|
44
44
|
|
|
45
|
-
This skill provides access to the
|
|
45
|
+
This skill provides access to the Voodocs context system for understanding project architecture, invariants, and assumptions.
|
|
46
46
|
|
|
47
47
|
## Available Commands
|
|
48
48
|
|
|
@@ -152,7 +152,7 @@ voodocs context check
|
|
|
152
152
|
|
|
153
153
|
def generate_cursor_rules(project_name: str, project_purpose: str) -> Dict[str, str]:
|
|
154
154
|
"""
|
|
155
|
-
Generate Cursor rules for
|
|
155
|
+
Generate Cursor rules for Voodocs context system.
|
|
156
156
|
|
|
157
157
|
Args:
|
|
158
158
|
project_name: Name of the project
|
|
@@ -162,12 +162,12 @@ def generate_cursor_rules(project_name: str, project_purpose: str) -> Dict[str,
|
|
|
162
162
|
Dictionary mapping file paths to content
|
|
163
163
|
"""
|
|
164
164
|
|
|
165
|
-
main_rule = f"""#
|
|
165
|
+
main_rule = f"""# Voodocs Context System
|
|
166
166
|
|
|
167
167
|
## Project: {project_name}
|
|
168
168
|
{project_purpose}
|
|
169
169
|
|
|
170
|
-
This project uses the
|
|
170
|
+
This project uses the Voodocs Context System (v0.2.0+) for documentation and validation.
|
|
171
171
|
|
|
172
172
|
## Context File
|
|
173
173
|
- **Location**: `.voodocs.context`
|
|
@@ -283,7 +283,7 @@ voodocs context query "module-name" --section architecture
|
|
|
283
283
|
|
|
284
284
|
def generate_copilot_instructions(project_name: str, project_purpose: str) -> Dict[str, str]:
|
|
285
285
|
"""
|
|
286
|
-
Generate GitHub Copilot instructions for
|
|
286
|
+
Generate GitHub Copilot instructions for Voodocs context system.
|
|
287
287
|
|
|
288
288
|
Args:
|
|
289
289
|
project_name: Name of the project
|
|
@@ -298,9 +298,9 @@ def generate_copilot_instructions(project_name: str, project_purpose: str) -> Di
|
|
|
298
298
|
## Project Overview
|
|
299
299
|
{project_purpose}
|
|
300
300
|
|
|
301
|
-
##
|
|
301
|
+
## Voodocs Context System
|
|
302
302
|
|
|
303
|
-
This project uses
|
|
303
|
+
This project uses Voodocs Context System (v0.2.0+) for documentation and validation.
|
|
304
304
|
|
|
305
305
|
### Context File
|
|
306
306
|
- **Location**: `.voodocs.context` (YAML format)
|
|
@@ -400,7 +400,7 @@ voodocs context diagram --type modules
|
|
|
400
400
|
|
|
401
401
|
def generate_windsurf_rules(project_name: str, project_purpose: str) -> Dict[str, str]:
|
|
402
402
|
"""
|
|
403
|
-
Generate Windsurf rules for
|
|
403
|
+
Generate Windsurf rules for Voodocs context system.
|
|
404
404
|
|
|
405
405
|
Args:
|
|
406
406
|
project_name: Name of the project
|
|
@@ -415,9 +415,9 @@ def generate_windsurf_rules(project_name: str, project_purpose: str) -> Dict[str
|
|
|
415
415
|
## Project
|
|
416
416
|
{project_purpose}
|
|
417
417
|
|
|
418
|
-
##
|
|
418
|
+
## Voodocs Context System
|
|
419
419
|
|
|
420
|
-
This project uses
|
|
420
|
+
This project uses Voodocs (v0.2.0+) for context management.
|
|
421
421
|
|
|
422
422
|
### Context Commands
|
|
423
423
|
|
|
@@ -478,7 +478,7 @@ invariants: ["rules"]
|
|
|
478
478
|
|
|
479
479
|
def generate_cline_rules(project_name: str, project_purpose: str) -> Dict[str, str]:
|
|
480
480
|
"""
|
|
481
|
-
Generate Cline rules for
|
|
481
|
+
Generate Cline rules for Voodocs context system.
|
|
482
482
|
|
|
483
483
|
Args:
|
|
484
484
|
project_name: Name of the project
|
|
@@ -493,7 +493,7 @@ def generate_cline_rules(project_name: str, project_purpose: str) -> Dict[str, s
|
|
|
493
493
|
## Project
|
|
494
494
|
{project_purpose}
|
|
495
495
|
|
|
496
|
-
##
|
|
496
|
+
## Voodocs Context System
|
|
497
497
|
|
|
498
498
|
Context file: `.voodocs.context` (YAML)
|
|
499
499
|
|
|
@@ -210,7 +210,7 @@ def cmd_context_init(force: bool = False) -> int:
|
|
|
210
210
|
Exit code (0 for success, 1 for error)
|
|
211
211
|
"""
|
|
212
212
|
try:
|
|
213
|
-
print_header("
|
|
213
|
+
print_header("Voodocs Context Initialization")
|
|
214
214
|
|
|
215
215
|
# Check if context file already exists
|
|
216
216
|
context_path = get_context_file_path()
|
|
@@ -224,7 +224,7 @@ def cmd_context_init(force: bool = False) -> int:
|
|
|
224
224
|
if not confirm(f"Overwrite existing context file at {context_path}?", default=False):
|
|
225
225
|
raise UserInterruptError("Initialization")
|
|
226
226
|
|
|
227
|
-
step("Initializing
|
|
227
|
+
step("Initializing Voodocs context...")
|
|
228
228
|
print()
|
|
229
229
|
|
|
230
230
|
# Detect project information
|
|
@@ -375,7 +375,7 @@ def cmd_context_init(force: bool = False) -> int:
|
|
|
375
375
|
|
|
376
376
|
print()
|
|
377
377
|
print("š¤ AI integration complete!")
|
|
378
|
-
print(f" Your {ai_type} assistant will now understand the
|
|
378
|
+
print(f" Your {ai_type} assistant will now understand the Voodocs context system.")
|
|
379
379
|
|
|
380
380
|
except Exception as e:
|
|
381
381
|
print(f"ā ļø Warning: Failed to generate AI integration: {e}")
|
|
@@ -1368,7 +1368,7 @@ def cmd_context_generate(source_dir: Optional[str] = None, update_existing: bool
|
|
|
1368
1368
|
return 1
|
|
1369
1369
|
except ImportError as e:
|
|
1370
1370
|
error(f"Failed to import annotation parser: {e}")
|
|
1371
|
-
warning("Make sure
|
|
1371
|
+
warning("Make sure Voodocs is properly installed")
|
|
1372
1372
|
return 1
|
|
1373
1373
|
except Exception as e:
|
|
1374
1374
|
error(f"Failed to generate context: {e}")
|
|
@@ -52,7 +52,7 @@ class GitNotAvailableError(ConfigurationError):
|
|
|
52
52
|
def __init__(self):
|
|
53
53
|
super().__init__(
|
|
54
54
|
f"Git is not available\n\n"
|
|
55
|
-
f"š” Some
|
|
55
|
+
f"š” Some Voodocs features require Git. Please install Git:\n"
|
|
56
56
|
f" https://git-scm.com/downloads"
|
|
57
57
|
)
|
|
58
58
|
|
|
@@ -119,8 +119,8 @@ def step(message: str) -> None:
|
|
|
119
119
|
message: Step message to display
|
|
120
120
|
|
|
121
121
|
Example:
|
|
122
|
-
>>> step("Initializing
|
|
123
|
-
ā¶ļø Initializing
|
|
122
|
+
>>> step("Initializing Voodocs context...")
|
|
123
|
+
ā¶ļø Initializing Voodocs context...
|
|
124
124
|
"""
|
|
125
125
|
print(f"{Colors.CYAN}ā¶ļø {message}{Colors.RESET}")
|
|
126
126
|
|
|
@@ -243,10 +243,10 @@ def print_header(title: str) -> None:
|
|
|
243
243
|
title: Header title
|
|
244
244
|
|
|
245
245
|
Example:
|
|
246
|
-
>>> print_header("
|
|
246
|
+
>>> print_header("Voodocs Context System")
|
|
247
247
|
|
|
248
248
|
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
249
|
-
|
|
249
|
+
Voodocs Context System
|
|
250
250
|
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
251
251
|
"""
|
|
252
252
|
width = 80
|
|
@@ -56,7 +56,7 @@ def write_context_yaml(context: ContextFile, file_path: Path) -> None:
|
|
|
56
56
|
# Create file with header comment
|
|
57
57
|
with open(file_path, 'w', encoding='utf-8') as f:
|
|
58
58
|
# Write header
|
|
59
|
-
f.write("#
|
|
59
|
+
f.write("# Voodocs Context File\n")
|
|
60
60
|
f.write("# This file contains structured project context for AI assistants and developers.\n")
|
|
61
61
|
f.write("# Format: YAML (DSL for machines, use 'voodocs context view' for human-readable Markdown)\n")
|
|
62
62
|
f.write("# Version: {}\n".format(context.versioning.context_version))
|
|
@@ -333,14 +333,14 @@ def add_to_gitignore(project_root: Path) -> bool:
|
|
|
333
333
|
# Ensure there's a newline before our section
|
|
334
334
|
if not content.endswith('\n'):
|
|
335
335
|
f.write('\n')
|
|
336
|
-
f.write('\n#
|
|
336
|
+
f.write('\n# Voodocs Context File (contains internal project details)\n')
|
|
337
337
|
f.write(f'{context_entry}\n')
|
|
338
338
|
|
|
339
339
|
return True
|
|
340
340
|
else:
|
|
341
341
|
# Create .gitignore with entry
|
|
342
342
|
with open(gitignore_path, 'w', encoding='utf-8') as f:
|
|
343
|
-
f.write('#
|
|
343
|
+
f.write('# Voodocs Context File (contains internal project details)\n')
|
|
344
344
|
f.write(f'{context_entry}\n')
|
|
345
345
|
|
|
346
346
|
return True
|
|
@@ -199,7 +199,7 @@ class PluginLoader:
|
|
|
199
199
|
plugin = self.load_from_module("darkarts.plugins.voodocs", "VooDocsPlugin")
|
|
200
200
|
plugins.append(plugin)
|
|
201
201
|
except PluginError:
|
|
202
|
-
pass #
|
|
202
|
+
pass # Voodocs plugin not yet implemented
|
|
203
203
|
|
|
204
204
|
return plugins
|
|
205
205
|
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Documentation Generation Module
|
|
3
|
+
|
|
4
|
+
Provides consolidated, human-readable documentation generation.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from .consolidator import DocumentationConsolidator, DocumentedItem
|
|
8
|
+
from .categorizer import AnnotationCategorizer
|
|
9
|
+
|
|
10
|
+
__all__ = ['DocumentationConsolidator', 'DocumentedItem', 'AnnotationCategorizer']
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Annotation Categorizer
|
|
3
|
+
|
|
4
|
+
Extracts categorization metadata from @darkarts annotations.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import Dict, Set, Any, List
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class AnnotationCategorizer:
|
|
12
|
+
"""Categorizes code based on @darkarts annotations and file paths."""
|
|
13
|
+
|
|
14
|
+
# Type detection patterns
|
|
15
|
+
TYPE_PATTERNS = {
|
|
16
|
+
'component': ['component', 'tsx', 'jsx', 'ui', 'view'],
|
|
17
|
+
'function': ['function', 'util', 'helper'],
|
|
18
|
+
'module': ['module', 'service', 'manager'],
|
|
19
|
+
'api': ['api', 'route', 'endpoint', 'handler'],
|
|
20
|
+
'data': ['schema', 'model', 'type', 'interface'],
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
# Domain keywords
|
|
24
|
+
DOMAIN_KEYWORDS = {
|
|
25
|
+
'authentication': ['auth', 'login', 'signup', 'session', 'token'],
|
|
26
|
+
'billing': ['billing', 'subscription', 'payment', 'invoice', 'stripe'],
|
|
27
|
+
'admin': ['admin', 'dashboard', 'management'],
|
|
28
|
+
'user_management': ['user', 'account', 'profile'],
|
|
29
|
+
'analytics': ['analytics', 'tracking', 'metrics', 'stats'],
|
|
30
|
+
'marketplace': ['marketplace', 'listing', 'product'],
|
|
31
|
+
'api': ['api', 'endpoint', 'route'],
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
# Layer detection
|
|
35
|
+
LAYER_PATTERNS = {
|
|
36
|
+
'frontend': ['component', 'ui', 'view', 'page', 'tsx', 'jsx', 'client'],
|
|
37
|
+
'backend': ['api', 'server', 'route', 'handler', 'controller'],
|
|
38
|
+
'database': ['schema', 'model', 'db', 'database', 'query'],
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
@staticmethod
|
|
42
|
+
def detect_type(file_path: str, annotations: Dict[str, Any]) -> str:
|
|
43
|
+
"""Detect the type of code item."""
|
|
44
|
+
path_lower = file_path.lower()
|
|
45
|
+
|
|
46
|
+
# Check file path for type hints
|
|
47
|
+
for item_type, patterns in AnnotationCategorizer.TYPE_PATTERNS.items():
|
|
48
|
+
if any(pattern in path_lower for pattern in patterns):
|
|
49
|
+
return item_type
|
|
50
|
+
|
|
51
|
+
# Check annotations
|
|
52
|
+
if 'module_purpose' in annotations or 'ā¢' in str(annotations):
|
|
53
|
+
return 'module'
|
|
54
|
+
|
|
55
|
+
return 'other'
|
|
56
|
+
|
|
57
|
+
@staticmethod
|
|
58
|
+
def detect_domains(file_path: str, annotations: Dict[str, Any]) -> Set[str]:
|
|
59
|
+
"""Detect which domains this code belongs to."""
|
|
60
|
+
domains = set()
|
|
61
|
+
path_lower = file_path.lower()
|
|
62
|
+
|
|
63
|
+
# Check file path
|
|
64
|
+
for domain, keywords in AnnotationCategorizer.DOMAIN_KEYWORDS.items():
|
|
65
|
+
if any(keyword in path_lower for keyword in keywords):
|
|
66
|
+
domains.add(domain)
|
|
67
|
+
|
|
68
|
+
# Check annotation content
|
|
69
|
+
annotation_text = str(annotations).lower()
|
|
70
|
+
for domain, keywords in AnnotationCategorizer.DOMAIN_KEYWORDS.items():
|
|
71
|
+
if any(keyword in annotation_text for keyword in keywords):
|
|
72
|
+
domains.add(domain)
|
|
73
|
+
|
|
74
|
+
return domains
|
|
75
|
+
|
|
76
|
+
@staticmethod
|
|
77
|
+
def detect_concerns(annotations: Dict[str, Any]) -> Set[str]:
|
|
78
|
+
"""Detect cross-cutting concerns."""
|
|
79
|
+
concerns = set()
|
|
80
|
+
|
|
81
|
+
# Check for security
|
|
82
|
+
if 'security' in annotations or 'š' in str(annotations):
|
|
83
|
+
concerns.add('security')
|
|
84
|
+
|
|
85
|
+
# Check for business logic
|
|
86
|
+
if 'business_logic' in annotations:
|
|
87
|
+
concerns.add('business_logic')
|
|
88
|
+
|
|
89
|
+
# Check for performance
|
|
90
|
+
if 'complexity' in annotations or 'ā”' in str(annotations):
|
|
91
|
+
concerns.add('performance')
|
|
92
|
+
|
|
93
|
+
# Check for integrations (external dependencies)
|
|
94
|
+
dependencies = annotations.get('dependencies', [])
|
|
95
|
+
if isinstance(dependencies, list):
|
|
96
|
+
external_deps = [d for d in dependencies if not str(d).startswith('.')]
|
|
97
|
+
if external_deps:
|
|
98
|
+
concerns.add('integrations')
|
|
99
|
+
|
|
100
|
+
# Check for error handling
|
|
101
|
+
if 'error_handling' in annotations or 'exceptions' in str(annotations).lower():
|
|
102
|
+
concerns.add('error_handling')
|
|
103
|
+
|
|
104
|
+
return concerns
|
|
105
|
+
|
|
106
|
+
@staticmethod
|
|
107
|
+
def detect_layers(file_path: str, annotations: Dict[str, Any]) -> Set[str]:
|
|
108
|
+
"""Detect which architectural layers this code belongs to."""
|
|
109
|
+
layers = set()
|
|
110
|
+
path_lower = file_path.lower()
|
|
111
|
+
|
|
112
|
+
for layer, patterns in AnnotationCategorizer.LAYER_PATTERNS.items():
|
|
113
|
+
if any(pattern in path_lower for pattern in patterns):
|
|
114
|
+
layers.add(layer)
|
|
115
|
+
|
|
116
|
+
return layers
|
|
117
|
+
|
|
118
|
+
@staticmethod
|
|
119
|
+
def extract_name(file_path: str) -> str:
|
|
120
|
+
"""Extract a human-readable name from file path."""
|
|
121
|
+
path = Path(file_path)
|
|
122
|
+
name = path.stem
|
|
123
|
+
|
|
124
|
+
# Remove common suffixes
|
|
125
|
+
suffixes_to_remove = [
|
|
126
|
+
'.test', '.spec', '.component', '.service',
|
|
127
|
+
'.controller', '.model', '.schema'
|
|
128
|
+
]
|
|
129
|
+
for suffix in suffixes_to_remove:
|
|
130
|
+
if name.endswith(suffix):
|
|
131
|
+
name = name[:-len(suffix)]
|
|
132
|
+
|
|
133
|
+
# Convert kebab-case and snake_case to Title Case
|
|
134
|
+
name = name.replace('-', ' ').replace('_', ' ')
|
|
135
|
+
name = ' '.join(word.capitalize() for word in name.split())
|
|
136
|
+
|
|
137
|
+
return name
|