@voodocs/cli 1.0.0 → 1.0.2

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.
@@ -0,0 +1,228 @@
1
+ """@darkarts
2
+ ⊢{cli:init}
3
+ ∂{click,pathlib,json}
4
+ ⚠{write-access:cwd}
5
+ ⊨{idempotent:config-creation}
6
+ 🔒{read-write:filesystem}
7
+ ⚡{O(1):file-creation}
8
+ """
9
+
10
+ """
11
+ VooDocs Init Command
12
+
13
+ Initialize a new project with VooDocs configuration and example annotations.
14
+ """
15
+
16
+ import click
17
+ import json
18
+ from pathlib import Path
19
+
20
+
21
+ @click.command()
22
+ @click.option(
23
+ '--format',
24
+ type=click.Choice(['voodocs', 'darkarts'], case_sensitive=False),
25
+ default='voodocs',
26
+ help='Annotation format to use (voodocs or darkarts symbolic)'
27
+ )
28
+ @click.option(
29
+ '--config-only',
30
+ is_flag=True,
31
+ help='Only create configuration file, skip example files'
32
+ )
33
+ def init(format, config_only):
34
+ """
35
+ Initialize a new project with VooDocs.
36
+
37
+ Creates a .voodocs.json configuration file and optionally generates
38
+ example annotated files to help you get started.
39
+
40
+ Examples:
41
+ voodocs init # Initialize with @voodocs format
42
+ voodocs init --format darkarts # Initialize with symbolic @darkarts format
43
+ voodocs init --config-only # Only create config file
44
+ """
45
+ cwd = Path.cwd()
46
+ config_path = cwd / '.voodocs.json'
47
+
48
+ # Check if config already exists
49
+ if config_path.exists():
50
+ click.echo(click.style('⚠ .voodocs.json already exists', fg='yellow'))
51
+ if not click.confirm('Overwrite existing configuration?'):
52
+ click.echo('Aborted.')
53
+ return
54
+
55
+ # Create default configuration
56
+ config = {
57
+ "version": "1.0",
58
+ "format": format,
59
+ "validation": {
60
+ "semantic": True,
61
+ "performance": True,
62
+ "strict": False
63
+ },
64
+ "generation": {
65
+ "output_format": "markdown",
66
+ "include_toc": True,
67
+ "include_examples": True
68
+ },
69
+ "exclude": [
70
+ "node_modules",
71
+ "dist",
72
+ "build",
73
+ "__pycache__",
74
+ ".git",
75
+ "*.min.js"
76
+ ]
77
+ }
78
+
79
+ # Write configuration
80
+ with open(config_path, 'w') as f:
81
+ json.dump(config, f, indent=2)
82
+
83
+ click.echo(click.style('✓ Created .voodocs.json', fg='green'))
84
+
85
+ if not config_only:
86
+ # Create example files
87
+ examples_dir = cwd / 'voodocs-examples'
88
+ examples_dir.mkdir(exist_ok=True)
89
+
90
+ if format == 'voodocs':
91
+ create_voodocs_example(examples_dir)
92
+ else:
93
+ create_darkarts_example(examples_dir)
94
+
95
+ click.echo(click.style(f'✓ Created example files in {examples_dir}/', fg='green'))
96
+
97
+ click.echo()
98
+ click.echo(click.style('🎉 VooDocs initialized successfully!', fg='green', bold=True))
99
+ click.echo()
100
+ click.echo('Next steps:')
101
+ click.echo(' 1. Review .voodocs.json configuration')
102
+ click.echo(' 2. Add annotations to your code')
103
+ click.echo(' 3. Run: voodocs validate .')
104
+ click.echo(' 4. Run: voodocs generate . ./docs')
105
+ click.echo()
106
+ click.echo('Documentation: https://voodocs.com/docs')
107
+
108
+
109
+ def create_voodocs_example(examples_dir: Path):
110
+ """Create example files with @voodocs annotations."""
111
+
112
+ # TypeScript example
113
+ ts_example = '''/**@voodocs
114
+ module_purpose: "Example TypeScript module demonstrating @voodocs annotations"
115
+ dependencies: []
116
+ assumptions: ["TypeScript environment available"]
117
+ */
118
+
119
+ /**@voodocs
120
+ preconditions: [
121
+ "name must be a non-empty string",
122
+ "age must be a positive number"
123
+ ]
124
+ postconditions: [
125
+ "Returns a greeting message",
126
+ "Message includes the provided name"
127
+ ]
128
+ invariants: [
129
+ "Does not modify input parameters"
130
+ ]
131
+ side_effects: []
132
+ complexity: "O(1)"
133
+ */
134
+ export function greet(name: string, age: number): string {
135
+ return `Hello, ${name}! You are ${age} years old.`;
136
+ }
137
+ '''
138
+
139
+ (examples_dir / 'example.ts').write_text(ts_example)
140
+
141
+ # Python example
142
+ py_example = '''"""@voodocs
143
+ module_purpose: "Example Python module demonstrating @voodocs annotations"
144
+ dependencies: []
145
+ assumptions: ["Python 3.7+"]
146
+ """
147
+
148
+ def calculate_total(prices: list[float], tax_rate: float) -> float:
149
+ """@voodocs
150
+ preconditions: [
151
+ "prices is a non-empty list of positive numbers",
152
+ "tax_rate is between 0 and 1"
153
+ ]
154
+ postconditions: [
155
+ "Returns the total with tax applied",
156
+ "Result is greater than or equal to sum of prices"
157
+ ]
158
+ invariants: [
159
+ "Does not modify the prices list"
160
+ ]
161
+ side_effects: []
162
+ complexity: "O(n) where n is the length of prices"
163
+ """
164
+ subtotal = sum(prices)
165
+ return subtotal * (1 + tax_rate)
166
+ '''
167
+
168
+ (examples_dir / 'example.py').write_text(py_example)
169
+
170
+
171
+ def create_darkarts_example(examples_dir: Path):
172
+ """Create example files with symbolic @darkarts annotations."""
173
+
174
+ # TypeScript example
175
+ ts_example = '''/**@darkarts
176
+ ⊢{Example TypeScript module demonstrating symbolic @darkarts annotations}
177
+ ∂{}
178
+ ⚠{TypeScript environment available}
179
+ */
180
+
181
+ /**@darkarts
182
+ ⊳{
183
+ name must be a non-empty string
184
+ age must be a positive number
185
+ }
186
+ ⊲{
187
+ Returns a greeting message
188
+ Message includes the provided name
189
+ }
190
+ ⊨{
191
+ Does ¬ modify input parameters
192
+ }
193
+ ⚡{}
194
+ */
195
+ export function greet(name: string, age: number): string {
196
+ return `Hello, ${name}! You are ${age} years old.`;
197
+ }
198
+ '''
199
+
200
+ (examples_dir / 'example.ts').write_text(ts_example)
201
+
202
+ # Python example
203
+ py_example = '''"""@darkarts
204
+ ⊢{Example Python module demonstrating symbolic @darkarts annotations}
205
+ ∂{}
206
+ ⚠{Python 3.7+}
207
+ """
208
+
209
+ def calculate_total(prices: list[float], tax_rate: float) -> float:
210
+ """@darkarts
211
+ ⊳{
212
+ prices is a non-empty list ∧ ∀ p ∈ prices: p > 0
213
+ tax_rate ∈ [0, 1]
214
+ }
215
+ ⊲{
216
+ Returns the total with tax applied
217
+ result ≥ sum(prices)
218
+ }
219
+ ⊨{
220
+ Does ¬ modify the prices list
221
+ }
222
+ ⚡{O(n) where n = len(prices)}
223
+ """
224
+ subtotal = sum(prices)
225
+ return subtotal * (1 + tax_rate)
226
+ '''
227
+
228
+ (examples_dir / 'example.py').write_text(py_example)
@@ -50,16 +50,16 @@ class AnnotationParser:
50
50
  Language.PYTHON: r'"""@voodocs\s*(.*?)\s*"""',
51
51
  }
52
52
 
53
- # DarkArts patterns (symbolic annotations)
53
+ # DarkArts patterns (symbolic annotations) - support both @voodocs and @darkarts
54
54
  DARKARTS_PATTERNS = {
55
- Language.PYTHON: r'"""@darkarts\s*(.*?)\s*"""',
56
- Language.TYPESCRIPT: r'/\*@voodocs\s*(.*?)\s*\*/',
57
- Language.JAVASCRIPT: r'/\*@voodocs\s*(.*?)\s*\*/',
58
- Language.JAVA: r'/\*@voodocs\s*(.*?)\s*\*/',
59
- Language.CPP: r'/\*@voodocs\s*(.*?)\s*\*/',
60
- Language.CSHARP: r'/\*@voodocs\s*(.*?)\s*\*/',
61
- Language.GO: r'/\*@voodocs\s*(.*?)\s*\*/',
62
- Language.RUST: r'/\*@voodocs\s*(.*?)\s*\*/',
55
+ Language.PYTHON: r'"""@(?:darkarts|voodocs)\s*(.*?)\s*"""',
56
+ Language.TYPESCRIPT: r'/\*\*@(?:darkarts|voodocs)\s*(.*?)\s*\*/',
57
+ Language.JAVASCRIPT: r'/\*\*@(?:darkarts|voodocs)\s*(.*?)\s*\*/',
58
+ Language.JAVA: r'/\*\*@(?:darkarts|voodocs)\s*(.*?)\s*\*/',
59
+ Language.CPP: r'/\*\*@(?:darkarts|voodocs)\s*(.*?)\s*\*/',
60
+ Language.CSHARP: r'/\*\*@(?:darkarts|voodocs)\s*(.*?)\s*\*/',
61
+ Language.GO: r'/\*\*@(?:darkarts|voodocs)\s*(.*?)\s*\*/',
62
+ Language.RUST: r'/\*\*@(?:darkarts|voodocs)\s*(.*?)\s*\*/',
63
63
  }
64
64
 
65
65
  def __init__(self):
@@ -209,7 +209,7 @@ class DarkArtsTranslator:
209
209
  Returns:
210
210
  Symbolic notation
211
211
  """
212
- result = text.lower()
212
+ result = text
213
213
 
214
214
  # Replace English phrases with symbols
215
215
  # Sort by length (longest first) to avoid partial matches
@@ -217,7 +217,14 @@ class DarkArtsTranslator:
217
217
  key=lambda x: len(x[0]), reverse=True)
218
218
 
219
219
  for english, symbol in phrases:
220
- result = result.replace(english, symbol)
220
+ # Use word boundaries to avoid mid-word replacements
221
+ # This prevents "or" in "authenticated" from being replaced
222
+ pattern = r'\b' + re.escape(english) + r'\b'
223
+ try:
224
+ result = re.sub(pattern, symbol, result, flags=re.IGNORECASE)
225
+ except re.error:
226
+ # Fallback for patterns that don't work with word boundaries
227
+ pass
221
228
 
222
229
  return result
223
230
 
@@ -311,15 +318,35 @@ class DarkArtsTranslator:
311
318
  symbolic = [self._convert_invariant(inv) for inv in invariants]
312
319
  lines.append(f"⊨{{{','.join(symbolic)}}}")
313
320
 
321
+ # Preconditions
322
+ if 'preconditions' in voodocs_dict:
323
+ preconditions = voodocs_dict['preconditions']
324
+ if isinstance(preconditions, list):
325
+ symbolic = [self._convert_invariant(pre) for pre in preconditions]
326
+ lines.append(f"⊳{{{','.join(symbolic)}}}")
327
+
328
+ # Postconditions
329
+ if 'postconditions' in voodocs_dict:
330
+ postconditions = voodocs_dict['postconditions']
331
+ if isinstance(postconditions, list):
332
+ symbolic = [self._convert_invariant(post) for post in postconditions]
333
+ lines.append(f"⊲{{{','.join(symbolic)}}}")
334
+
314
335
  # Security
315
- if 'security_model' in voodocs_dict:
316
- security = self._simplify_text(voodocs_dict['security_model'])
336
+ if 'security_model' in voodocs_dict or 'security_implications' in voodocs_dict:
337
+ security = voodocs_dict.get('security_model') or voodocs_dict.get('security_implications')
338
+ if isinstance(security, list):
339
+ security = ', '.join(security)
340
+ security = self._simplify_text(str(security))
317
341
  lines.append(f"🔒{{{security}}}")
318
342
 
319
- # Performance
343
+ # Performance/Complexity
320
344
  if 'performance_model' in voodocs_dict:
321
345
  perf = voodocs_dict['performance_model']
322
346
  lines.append(f"⚡{{{perf}}}")
347
+ elif 'complexity' in voodocs_dict:
348
+ complexity = voodocs_dict['complexity']
349
+ lines.append(f"⚡{{{complexity}}}")
323
350
 
324
351
  lines.append('"""')
325
352
  return '\n'.join(lines)
@@ -15,7 +15,7 @@ Data structures for parsed @darkarts/@voodocs annotations with:
15
15
  - State transitions (from_state → to_state with conditions)
16
16
  - Error cases (condition, error_type, description)
17
17
  - Structured representations (FunctionAnnotation, ClassAnnotation, ModuleAnnotation)
18
- """"
18
+ """
19
19
 
20
20
  from dataclasses import dataclass, field
21
21
  from typing import List, Dict, Optional, Any
@@ -12,6 +12,7 @@ Provides CLI commands for DarkArts symbolic documentation.
12
12
  """
13
13
 
14
14
  import sys
15
+ import re
15
16
  from pathlib import Path
16
17
  from typing import List, Optional
17
18
 
@@ -22,6 +23,7 @@ from darkarts.annotations import (
22
23
  convert_voodocs_to_darkarts,
23
24
  )
24
25
  from darkarts.annotations.parser import AnnotationParser
26
+ from darkarts.annotations.types import Language
25
27
 
26
28
 
27
29
  def cmd_darkarts_translate(args):
@@ -93,6 +95,12 @@ def cmd_darkarts_convert(args):
93
95
 
94
96
  Usage:
95
97
  voodocs darkarts convert <files> [--in-place]
98
+
99
+ Improvements:
100
+ - Supports Python, TypeScript, JavaScript
101
+ - Preserves ALL annotation fields (not just module-level)
102
+ - Fixed symbol conversion (no mid-word replacements)
103
+ - Working --in-place flag for all languages
96
104
  """
97
105
  print("🔄 DarkArts Conversion")
98
106
  print("=" * 60)
@@ -116,41 +124,161 @@ def cmd_darkarts_convert(args):
116
124
  # Parse VooDocs annotations
117
125
  parser = AnnotationParser()
118
126
  annotations = parser.parse_file(str(path))
127
+ language = parser.detect_language(str(path))
119
128
 
120
129
  if not annotations.module:
121
130
  print(" ⚠️ No @voodocs annotations found")
122
131
  continue
123
132
 
124
- # Convert to DarkArts
125
- voodocs_dict = {
126
- 'module_purpose': annotations.module.module_purpose,
127
- 'dependencies': annotations.module.dependencies,
128
- 'assumptions': annotations.module.assumptions,
129
- }
133
+ # Convert module-level annotation
134
+ converted_annotations = []
130
135
 
131
- darkarts = convert_voodocs_to_darkarts(voodocs_dict)
136
+ if annotations.module:
137
+ module_dict = {}
138
+
139
+ # Include ALL fields
140
+ if hasattr(annotations.module, 'module_purpose') and annotations.module.module_purpose:
141
+ module_dict['module_purpose'] = annotations.module.module_purpose
142
+ if hasattr(annotations.module, 'dependencies') and annotations.module.dependencies:
143
+ module_dict['dependencies'] = annotations.module.dependencies
144
+ if hasattr(annotations.module, 'assumptions') and annotations.module.assumptions:
145
+ module_dict['assumptions'] = annotations.module.assumptions
146
+ if hasattr(annotations.module, 'invariants') and annotations.module.invariants:
147
+ module_dict['invariants'] = annotations.module.invariants
148
+ if hasattr(annotations.module, 'security_model') and annotations.module.security_model:
149
+ module_dict['security_model'] = annotations.module.security_model
150
+ if hasattr(annotations.module, 'performance_model') and annotations.module.performance_model:
151
+ module_dict['performance_model'] = annotations.module.performance_model
152
+
153
+ if module_dict:
154
+ darkarts = convert_voodocs_to_darkarts(module_dict)
155
+ converted_annotations.append(('module', darkarts, 0))
156
+
157
+ # Convert function-level annotations
158
+ for func in annotations.module.functions:
159
+ func_dict = {}
160
+
161
+ if hasattr(func, 'preconditions') and func.preconditions:
162
+ func_dict['preconditions'] = func.preconditions
163
+ if hasattr(func, 'postconditions') and func.postconditions:
164
+ func_dict['postconditions'] = func.postconditions
165
+ if hasattr(func, 'invariants') and func.invariants:
166
+ func_dict['invariants'] = func.invariants
167
+ if hasattr(func, 'security_implications') and func.security_implications:
168
+ func_dict['security_implications'] = func.security_implications
169
+ if hasattr(func, 'complexity') and func.complexity:
170
+ # Convert ComplexityAnnotation to string
171
+ if hasattr(func.complexity, 'time'):
172
+ func_dict['complexity'] = func.complexity.time
173
+ else:
174
+ func_dict['complexity'] = str(func.complexity)
175
+
176
+ if func_dict:
177
+ darkarts = convert_voodocs_to_darkarts(func_dict)
178
+ converted_annotations.append(('function', darkarts, func.line_number if hasattr(func, 'line_number') else 0))
179
+
180
+ # Convert class-level annotations
181
+ for cls in annotations.module.classes:
182
+ cls_dict = {}
183
+
184
+ if hasattr(cls, 'invariants') and cls.invariants:
185
+ cls_dict['invariants'] = cls.invariants
186
+ if hasattr(cls, 'assumptions') and cls.assumptions:
187
+ cls_dict['assumptions'] = cls.assumptions
188
+
189
+ if cls_dict:
190
+ darkarts = convert_voodocs_to_darkarts(cls_dict)
191
+ converted_annotations.append(('class', darkarts, cls.line_number if hasattr(cls, 'line_number') else 0))
192
+
193
+ if not converted_annotations:
194
+ print(" ⚠️ No convertible annotations found")
195
+ continue
132
196
 
133
197
  if in_place:
134
198
  # Replace @voodocs with @darkarts in file
135
- # This is a simple replacement - in production would be more sophisticated
136
- new_content = content.replace(
137
- '"""@voodocs',
138
- darkarts.replace('"""@darkarts\n', '').replace('\n"""', '')
139
- )
199
+ new_content = _replace_annotations_in_file(content, converted_annotations, language)
140
200
  path.write_text(new_content)
141
- print(" ✅ Converted in place")
201
+ print(f" ✅ Converted {len(converted_annotations)} annotation(s) in place")
142
202
  else:
143
203
  # Print to console
144
- print(darkarts)
204
+ for ann_type, darkarts, line_num in converted_annotations:
205
+ print(f"\n {ann_type.capitalize()} annotation (line {line_num}):")
206
+ print(f" {darkarts}")
145
207
 
146
208
  except Exception as e:
147
209
  print(f" ❌ Error: {e}")
210
+ import traceback
211
+ traceback.print_exc()
148
212
 
149
213
  print()
150
214
 
151
215
  return 0
152
216
 
153
217
 
218
+
219
+ from darkarts.annotations.types import Language
220
+
221
+
222
+ def _replace_annotations_in_file(content: str, converted_annotations: list, language: Language) -> str:
223
+ """
224
+ Replace @voodocs annotations with @darkarts in file content.
225
+
226
+ Args:
227
+ content: Original file content
228
+ converted_annotations: List of (type, darkarts_text, line_num) tuples
229
+ language: Programming language
230
+
231
+ Returns:
232
+ Modified content with @darkarts annotations
233
+ """
234
+ # Determine comment syntax based on language
235
+ if language == Language.PYTHON:
236
+ voodocs_pattern = r'"""@voodocs\s*(.*?)\s*"""'
237
+
238
+ def create_darkarts(darkarts_text):
239
+ # darkarts_text already has """@darkarts format
240
+ return darkarts_text
241
+
242
+ else: # TypeScript, JavaScript, etc.
243
+ voodocs_pattern = r'/\*\*@voodocs\s*(.*?)\s*\*/'
244
+
245
+ def create_darkarts(darkarts_text):
246
+ # Convert Python-style to JS-style
247
+ lines = darkarts_text.strip().split('\n')
248
+ if lines and lines[0] == '"""@darkarts':
249
+ lines[0] = '/**@darkarts'
250
+ if lines and lines[-1] == '"""':
251
+ lines[-1] = '*/'
252
+ return '\n'.join(lines)
253
+
254
+ # Find all @voodocs annotations
255
+ matches = list(re.finditer(voodocs_pattern, content, re.DOTALL))
256
+
257
+ if not matches:
258
+ return content
259
+
260
+ # Replace each annotation
261
+ result = content
262
+ offset = 0
263
+
264
+ for i, match in enumerate(matches):
265
+ if i < len(converted_annotations):
266
+ _, darkarts_text, _ = converted_annotations[i]
267
+ darkarts_formatted = create_darkarts(darkarts_text)
268
+
269
+ # Calculate positions with offset
270
+ start = match.start() + offset
271
+ end = match.end() + offset
272
+
273
+ # Replace
274
+ result = result[:start] + darkarts_formatted + result[end:]
275
+
276
+ # Update offset
277
+ offset += len(darkarts_formatted) - (end - start)
278
+
279
+ return result
280
+
281
+
154
282
  def cmd_darkarts_stats(args):
155
283
  """
156
284
  Show statistics about DarkArts annotations.
@@ -14,7 +14,7 @@ Provides high-level API for problem solving with automatic plugin routing:
14
14
  - Explanation generation for solutions
15
15
  - Learning mode for pattern recognition
16
16
  - Built-in plugin discovery and loading
17
- """"
17
+ """
18
18
 
19
19
  from typing import Any, Dict, List, Optional
20
20
  from .plugin import DarkArtsPlugin, PluginInput, PluginOutput, PluginMetadata, PluginError
@@ -15,7 +15,7 @@ Dynamic plugin discovery and loading system with support for:
15
15
  - Built-in plugin detection
16
16
  - Automatic registry integration
17
17
  - Plugin validation and error handling
18
- """"
18
+ """
19
19
 
20
20
  import importlib
21
21
  import importlib.util
@@ -15,7 +15,7 @@ Defines the base classes and interfaces for the DarkArts plugin system with:
15
15
  - Plugin metadata (name, version, description, dependencies, capabilities)
16
16
  - Exception hierarchy (ParseError, ExecutionError, PluginError)
17
17
  - Lifecycle management (initialization, execution, cleanup)
18
- """"
18
+ """
19
19
 
20
20
  from abc import ABC, abstractmethod
21
21
  from dataclasses import dataclass, field
@@ -15,7 +15,7 @@ Central registry for plugin lifecycle management with:
15
15
  - Plugin enumeration and discovery
16
16
  - Thread-safe operations (dict-based)
17
17
  - Global singleton registry pattern
18
- """"
18
+ """
19
19
 
20
20
  from typing import Dict, List, Optional
21
21
  from .plugin import DarkArtsPlugin, PluginMetadata, PluginError
@@ -16,7 +16,7 @@ Structured exception hierarchy for error handling with:
16
16
  - Configuration errors (ConfigurationError)
17
17
  - File errors (FileNotFoundError)
18
18
  - Informative messages (clear guidance for users)
19
- """"
19
+ """
20
20
 
21
21
 
22
22
  class VooDocsError(Exception):
@@ -15,7 +15,7 @@ Enhanced documentation plugin supporting:
15
15
  - Test generation from annotations (preconditions/postconditions → tests)
16
16
  - API specification generation (OpenAPI from annotations)
17
17
  - Multi-format output (docs, tests, specs)
18
- """"
18
+ """
19
19
 
20
20
  from darkarts.core import (
21
21
  DarkArtsPlugin,
@@ -15,7 +15,7 @@ Quality assurance for @voodocs annotations with:
15
15
  - Complexity notation validation (Big-O format)
16
16
  - Security model checking (valid security declarations)
17
17
  - Best practice recommendations (suggestions for improvement)
18
- """"
18
+ """
19
19
 
20
20
  from typing import List, Dict, Any, Optional
21
21
  from darkarts.annotations.types import ParsedAnnotations, FunctionAnnotation, ClassAnnotation
@@ -15,7 +15,7 @@ Automatic API specification generation from @voodocs annotations with:
15
15
  - Parameter extraction (from preconditions)
16
16
  - Response schema generation (from postconditions)
17
17
  - Error documentation (from error_cases)
18
- """"
18
+ """
19
19
 
20
20
  from typing import List, Optional, Dict, Any
21
21
  from pathlib import Path
@@ -15,7 +15,7 @@ Translates @voodocs annotations (DarkArts language) into human-readable document
15
15
  - Complexity notation explanation (Big-O → plain English)
16
16
  - Security model documentation (clear security implications)
17
17
  - Cross-reference generation (links between related items)
18
- """"
18
+ """
19
19
 
20
20
  from typing import List, Optional, Dict
21
21
  from pathlib import Path
@@ -15,7 +15,7 @@ Markdown to HTML conversion with styling:
15
15
  - Responsive CSS (mobile-friendly styling)
16
16
  - Full HTML document wrapping (complete pages)
17
17
  - Graceful degradation (basic conversion if markdown lib unavailable)
18
- """"
18
+ """
19
19
 
20
20
  from pathlib import Path
21
21
  from typing import Optional
@@ -15,7 +15,7 @@ Markdown to PDF conversion with print-ready formatting:
15
15
  - Embedded fonts and styling (professional appearance)
16
16
  - Multi-method fallback (tries multiple libraries)
17
17
  - Error handling (clear messages if dependencies missing)
18
- """"
18
+ """
19
19
 
20
20
  from pathlib import Path
21
21
  from typing import Optional
@@ -15,7 +15,7 @@ Automatic test generation from @voodocs annotations with:
15
15
  - Error case tests (ensure proper error handling)
16
16
  - Property-based tests (Hypothesis/QuickCheck-style)
17
17
  - Multi-framework support (pytest, unittest, jest, junit)
18
- """"
18
+ """
19
19
 
20
20
  from typing import List, Optional, Dict, Any, Tuple
21
21
  from pathlib import Path
@@ -15,7 +15,7 @@ Privacy-respecting anonymous usage analytics with:
15
15
  - Supabase backend (anonymous data storage)
16
16
  - Fail-silent network (no impact on user experience if offline)
17
17
  - First-run notice (transparent disclosure to users)
18
- """"
18
+ """
19
19
 
20
20
  import os
21
21
  import sys
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voodocs/cli",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "AI-Native Documentation System with Validation - The only documentation tool that validates your annotations and guarantees accuracy",
5
5
  "main": "voodocs_cli.py",
6
6
  "bin": {