@voodocs/cli 2.2.3 → 2.4.0

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/README.md CHANGED
@@ -91,6 +91,160 @@ def authenticate_user(user_id: str, password: str) -> Optional[str]:
91
91
 
92
92
  ---
93
93
 
94
+ ## VooDocs Lite: Ultra-Compact Format
95
+
96
+ **NEW in v2.4.0!** VooDocs Lite is an ultra-compact symbolic notation that reduces token count by **~30%** while maintaining all semantic information.
97
+
98
+ ### Why VooDocs Lite?
99
+
100
+ - **Token Efficient**: 27-30% fewer tokens for AI context
101
+ - **More Scannable**: Single-character symbols easier to read
102
+ - **Same Information**: Zero semantic loss
103
+ - **Bidirectional**: Convert between Standard and Lite freely
104
+
105
+ ### Format Comparison
106
+
107
+ **Standard VooDocs:**
108
+ ```typescript
109
+ /**@darkarts
110
+ ⊢{User authentication service with JWT token generation}
111
+ ∂{bcrypt, jsonwebtoken, database}
112
+ ⚠{Users must be stored in database}
113
+ ⊳{userId must be a valid UUID, password must be ≥8 characters}
114
+ ⊲{Returns JWT token ∨ null}
115
+ ⊨{Does ¬ modify database, Password is ¬ logged}
116
+ ⚡{O(1)}
117
+ 🔒{Password hashed with bcrypt, Token signed with secret}
118
+ */
119
+ ```
120
+ **114 tokens**
121
+
122
+ **VooDocs Lite:**
123
+ ```typescript
124
+ /**@darkarts-lite
125
+ >u auth svc w/ JWT tok gen
126
+ @bcrypt,jsonwebtoken,database
127
+ !us stored in db
128
+ <id valid UUID, pw>=8 characters
129
+ >ret JWT tok|N
130
+ =!mod db, pw !logged
131
+ ~O(1)
132
+ #pw hashed w/ bcrypt, tok signed w/ secret
133
+ */
134
+ ```
135
+ **83 tokens** (27% reduction)
136
+
137
+ ### Symbol Mapping
138
+
139
+ | Standard | Lite | Meaning |
140
+ |----------|------|----------|
141
+ | `⊢{}` | `>` | Purpose |
142
+ | `∂{}` | `@` | Dependencies |
143
+ | `⚠{}` | `!` | Assumptions |
144
+ | `⊳{}` | `<` | Preconditions |
145
+ | `⊲{}` | `>` | Postconditions |
146
+ | `⊨{}` | `=` | Invariants |
147
+ | `⚡{}` | `~` | Complexity |
148
+ | `🔒{}` | `#` | Security |
149
+
150
+ ### Convert Between Formats
151
+
152
+ ```bash
153
+ # Convert Standard to Lite
154
+ voodocs convert src/ --to lite -r
155
+
156
+ # Convert Lite to Standard
157
+ voodocs convert src/ --to standard -r
158
+
159
+ # Preview conversion
160
+ voodocs convert src/ --to lite --dry-run
161
+
162
+ # Modify files in-place
163
+ voodocs convert src/ --to lite --in-place
164
+ ```
165
+
166
+ ---
167
+
168
+ ## Companion Files for Compiled Languages
169
+
170
+ **NEW in v2.3.0!** For compiled languages like Solidity, Rust, or C++ where inline annotations may interfere with compilation, VooDocs supports **companion documentation files**.
171
+
172
+ ### What are Companion Files?
173
+
174
+ Companion files are `.voodocs.md` files that live alongside your source files, containing rich documentation without modifying the source code.
175
+
176
+ ```
177
+ contracts/
178
+ ├── SubdomainRegistry.sol ← Source code
179
+ ├── SubdomainRegistry.voodocs.md ← Companion documentation
180
+ ├── DomainMarketplace.sol ← Source code
181
+ ├── DomainMarketplace.voodocs.md ← Companion documentation
182
+ ```
183
+
184
+ ### Creating Companion Files
185
+
186
+ Use the `companion` command to generate templates:
187
+
188
+ ```bash
189
+ # Create companion file for a single file
190
+ voodocs companion contracts/Registry.sol
191
+
192
+ # Create companion files for all Solidity files
193
+ voodocs companion contracts/ -r
194
+
195
+ # Preview what would be created
196
+ voodocs companion contracts/ -r --dry-run
197
+ ```
198
+
199
+ ### Companion File Format
200
+
201
+ Companion files use Markdown with VooDocs symbolic notation:
202
+
203
+ ```markdown
204
+ # SubdomainRegistry.voodocs.md
205
+
206
+ ## Purpose
207
+ ⊢{4-level naming hierarchy with tiered subdomain allocation}
208
+
209
+ ## Architecture
210
+ - **Depends On**: IPricingEngine, IERC721
211
+ - **Depended By**: ThreeNSFacet, DomainMarketplace
212
+ - **Storage**: PostgreSQL (cache), L1 (source of truth)
213
+
214
+ ## Invariants
215
+ ⊨{L1 is always the source of truth}
216
+ ⊨{Personal names destroyed on subdomain transfer}
217
+ ⊨{resolve() must check expiration before returning owner}
218
+
219
+ ## Assumptions
220
+ ⊲{Block timestamp is reliable for expiration checks}
221
+ ⊲{Gas costs are acceptable for array operations}
222
+
223
+ ## Critical Sections
224
+ - `_burnPersonalNames()` - Must be called before any transfer
225
+ - `resolve()` - Must check expiration before returning owner
226
+
227
+ ## Security Considerations
228
+ ⊨{Reentrancy protection on all external calls}
229
+ ⊨{Owner validation before subdomain operations}
230
+ ```
231
+
232
+ ### Generating Documentation with Companion Files
233
+
234
+ ```bash
235
+ voodocs generate contracts/ docs/ --companion-files
236
+ ```
237
+
238
+ ### Benefits
239
+
240
+ ✅ **No Compilation Issues** - Documentation lives in separate files
241
+ ✅ **Rich Markdown** - Use tables, diagrams, code examples, links
242
+ ✅ **Version Control** - Track documentation changes alongside code
243
+ ✅ **IDE Friendly** - View source and docs side-by-side
244
+ ✅ **AI-Ready** - Same context quality as inline annotations
245
+
246
+ ---
247
+
94
248
  ## Symbolic Format Reference
95
249
 
96
250
  ### Module-Level Annotations
@@ -171,6 +325,29 @@ voodocs fix ./src --dry-run # Preview changes
171
325
  voodocs fix ./src --backup # Create backups
172
326
  ```
173
327
 
328
+ ### `voodocs companion`
329
+
330
+ Create companion documentation files for source files:
331
+
332
+ ```bash
333
+ voodocs companion contracts/ # Create for single file
334
+ voodocs companion contracts/ -r # Recursive
335
+ voodocs companion contracts/ --dry-run # Preview changes
336
+ voodocs companion contracts/ --force # Overwrite existing
337
+ ```
338
+
339
+ ### `voodocs convert`
340
+
341
+ Convert between Standard and Lite VooDocs formats:
342
+
343
+ ```bash
344
+ voodocs convert src/ --to lite # Convert to Lite format
345
+ voodocs convert src/ --to standard # Convert to Standard format
346
+ voodocs convert src/ --to lite -r # Recursive conversion
347
+ voodocs convert src/ --to lite --dry-run # Preview changes
348
+ voodocs convert src/ --to lite --in-place # Modify files in-place
349
+ ```
350
+
174
351
  ### `voodocs generate`
175
352
 
176
353
  Generate documentation from annotations:
@@ -179,6 +356,7 @@ Generate documentation from annotations:
179
356
  voodocs generate ./src ./docs # Generate docs
180
357
  voodocs generate ./src ./docs -r # Recursive
181
358
  voodocs generate ./src ./docs --validate # Validate first
359
+ voodocs generate ./src ./docs --companion-files # Use companion files
182
360
  voodocs generate ./src ./docs --format json # JSON output
183
361
  ```
184
362
 
package/USAGE.md CHANGED
@@ -13,6 +13,7 @@ This guide provides a comprehensive overview of VooDocs, its commands, and best
13
13
  - [CLI Commands](#cli-commands)
14
14
  - [init](#init)
15
15
  - [instruct](#instruct)
16
+ - [companion](#companion)
16
17
  - [generate](#generate)
17
18
  - [status](#status)
18
19
  - [watch](#watch)
@@ -98,13 +99,81 @@ voodocs instruct [--assistant <name>] [--output <file>]
98
99
  - `--assistant`: The AI assistant to generate instructions for (`cursor`, `claude`, `copilot`, `windsurf`, `generic`).
99
100
  - `--output`: The output file path (defaults to `.cursorrules`, `.claude/instructions.md`, etc.).
100
101
 
102
+ ### `companion`
103
+
104
+ **NEW in v2.3.0!** Create companion documentation files (`.voodocs.md`) for source files. Useful for compiled languages like Solidity, Rust, or C++ where inline annotations may interfere with compilation.
105
+
106
+ **Usage**:
107
+ ```bash
108
+ voodocs companion <source> [options]
109
+ ```
110
+
111
+ **Arguments**:
112
+ - `<source>`: Source file or directory to create companion files for.
113
+
114
+ **Options**:
115
+ - `-r, --recursive`: Recursively process all files in subdirectories.
116
+ - `--force`: Overwrite existing companion files.
117
+ - `--dry-run`: Show what would be created without creating files.
118
+
119
+ **Examples**:
120
+ ```bash
121
+ # Create companion file for a single Solidity contract
122
+ voodocs companion contracts/Registry.sol
123
+
124
+ # Create companion files for all Solidity contracts
125
+ voodocs companion contracts/ -r
126
+
127
+ # Preview what would be created
128
+ voodocs companion contracts/ -r --dry-run
129
+
130
+ # Force overwrite existing companion files
131
+ voodocs companion contracts/ -r --force
132
+ ```
133
+
134
+ **Companion File Format**:
135
+
136
+ Companion files use Markdown with structured sections:
137
+
138
+ ```markdown
139
+ # FileName.voodocs.md
140
+
141
+ ## Purpose
142
+ ⊢{Module purpose description}
143
+
144
+ ## Architecture
145
+ - **Depends On**: Dependency1, Dependency2
146
+ - **Depended By**: Parent1, Parent2
147
+ - **Storage**: Storage information
148
+
149
+ ## Invariants
150
+ ⊨{Invariant 1}
151
+ ⊨{Invariant 2}
152
+
153
+ ## Assumptions
154
+ ⊲{Assumption 1}
155
+
156
+ ## Critical Sections
157
+ - `functionName()` - Description
158
+
159
+ ## Security Considerations
160
+ ⊨{Security requirement}
161
+ ```
162
+
163
+ **Benefits**:
164
+ - ✅ No compilation interference
165
+ - ✅ Rich Markdown formatting (tables, diagrams, links)
166
+ - ✅ Version control alongside source files
167
+ - ✅ IDE-friendly (side-by-side viewing)
168
+ - ✅ Same AI context quality as inline annotations
169
+
101
170
  ### `generate`
102
171
 
103
172
  Generate docs, tests, and API specs from annotations.
104
173
 
105
174
  **Usage**:
106
175
  ```bash
107
- voodocs generate <path> [--output <dir>] [--docs-only] [--tests-only] [--api-only] [--verbose]
176
+ voodocs generate <path> [--output <dir>] [--docs-only] [--tests-only] [--api-only] [--companion-files] [--verbose]
108
177
  ```
109
178
 
110
179
  **Arguments**:
@@ -113,8 +182,21 @@ voodocs generate <path> [--output <dir>] [--docs-only] [--tests-only] [--api-onl
113
182
  - `--docs-only`: Generate only documentation.
114
183
  - `--tests-only`: Generate only tests.
115
184
  - `--api-only`: Generate only API specs.
185
+ - `--companion-files`: **NEW in v2.3.0!** Scan for and use `.voodocs.md` companion files alongside source files.
116
186
  - `--verbose`: Show detailed output.
117
187
 
188
+ **Examples**:
189
+ ```bash
190
+ # Generate documentation from inline annotations
191
+ voodocs generate src/ docs/
192
+
193
+ # Generate documentation using companion files (for Solidity, Rust, etc.)
194
+ voodocs generate contracts/ docs/ --companion-files
195
+
196
+ # Generate with validation
197
+ voodocs generate src/ docs/ --validate
198
+ ```
199
+
118
200
  ### `status`
119
201
 
120
202
  Show project status and statistics.
@@ -318,7 +400,61 @@ class BankAccount:
318
400
  self.balance += amount
319
401
  ```
320
402
 
321
- See the `examples/` directory for more complete examples in Python and TypeScript.
403
+ ### Solidity Contract with Companion File
404
+
405
+ **NEW in v2.3.0!** For compiled languages, use companion files:
406
+
407
+ **contracts/SubdomainRegistry.sol**:
408
+ ```solidity
409
+ // SPDX-License-Identifier: MIT
410
+ pragma solidity ^0.8.0;
411
+
412
+ contract SubdomainRegistry {
413
+ mapping(uint256 => address) public owners;
414
+ mapping(uint256 => uint256) public expirations;
415
+
416
+ function register(uint256 nameId, address owner, uint256 duration) public {
417
+ require(owners[nameId] == address(0), "Already registered");
418
+ owners[nameId] = owner;
419
+ expirations[nameId] = block.timestamp + duration;
420
+ }
421
+
422
+ function resolve(uint256 nameId) public view returns (address) {
423
+ require(block.timestamp < expirations[nameId], "Expired");
424
+ return owners[nameId];
425
+ }
426
+ }
427
+ ```
428
+
429
+ **contracts/SubdomainRegistry.voodocs.md**:
430
+ ```markdown
431
+ # SubdomainRegistry.voodocs.md
432
+
433
+ ## Purpose
434
+ ⊢{Subdomain registry with expiration management}
435
+
436
+ ## Invariants
437
+ ⊨{Only one owner per subdomain}
438
+ ⊨{resolve() must check expiration before returning owner}
439
+ ⊨{Expired subdomains cannot be resolved}
440
+
441
+ ## Assumptions
442
+ ⊲{Block timestamp is reliable for expiration checks}
443
+ ⊲{nameId is unique and generated off-chain}
444
+
445
+ ## Security Considerations
446
+ ⊨{Owner validation before subdomain operations}
447
+ ⊨{Zero address checks for all owner parameters}
448
+ ⊨{Expiration checks prevent stale data}
449
+ ```
450
+
451
+ **Generate documentation**:
452
+ ```bash
453
+ voodocs companion contracts/ -r
454
+ voodocs generate contracts/ docs/ --companion-files
455
+ ```
456
+
457
+ See the `examples/` directory for more complete examples in Python, TypeScript, and Solidity.
322
458
 
323
459
  ---
324
460
 
@@ -0,0 +1,137 @@
1
+ """
2
+ ⊢cli:companion
3
+ ∂{click,pathlib,typing}
4
+ ⚠{python≥3.7,click≥8.0}
5
+ ⊨{∀template→valid_markdown}
6
+ 🔒{write:files}
7
+ ⚡{O(n)|n=files}
8
+ """
9
+
10
+ """
11
+ VooDocs CLI - Companion Command
12
+
13
+ Creates .voodocs.md companion files for source files.
14
+ """
15
+
16
+ import sys
17
+ import click
18
+ from pathlib import Path
19
+ from typing import List
20
+
21
+ sys.path.insert(0, str(Path(__file__).parent.parent))
22
+ from darkarts.companion_files import CompanionFileScanner
23
+
24
+
25
+ @click.command()
26
+ @click.argument('source', type=click.Path(exists=True), required=True)
27
+ @click.option('-r', '--recursive', is_flag=True, help='Recursively process all files')
28
+ @click.option('--force', is_flag=True, help='Overwrite existing companion files')
29
+ @click.option('--dry-run', is_flag=True, help='Show what would be created without creating files')
30
+ def companion(
31
+ source: str,
32
+ recursive: bool,
33
+ force: bool,
34
+ dry_run: bool
35
+ ):
36
+ """
37
+ Create .voodocs.md companion files for source files.
38
+
39
+ Companion files allow you to add rich documentation alongside source files
40
+ without modifying the source code. This is especially useful for compiled
41
+ languages like Solidity where inline annotations may interfere with compilation.
42
+
43
+ Examples:
44
+
45
+ # Create companion file for a single file
46
+ voodocs companion contracts/Registry.sol
47
+
48
+ # Create companion files for all Solidity files
49
+ voodocs companion contracts/ -r
50
+
51
+ # Preview what would be created
52
+ voodocs companion contracts/ -r --dry-run
53
+
54
+ # Overwrite existing companion files
55
+ voodocs companion contracts/ -r --force
56
+ """
57
+
58
+ source_path = Path(source)
59
+
60
+ # Collect source files
61
+ files_to_process: List[Path] = []
62
+
63
+ if source_path.is_file():
64
+ files_to_process = [source_path]
65
+ elif source_path.is_dir():
66
+ extensions = ['*.py', '*.ts', '*.js', '*.jsx', '*.tsx', '*.sol']
67
+
68
+ if recursive:
69
+ for ext in extensions:
70
+ files_to_process.extend([f for f in source_path.glob(f"**/{ext}") if f.is_file()])
71
+ else:
72
+ for ext in extensions:
73
+ files_to_process.extend([f for f in source_path.glob(ext) if f.is_file()])
74
+
75
+ if not files_to_process:
76
+ click.secho("No source files found.", fg='yellow')
77
+ sys.exit(1)
78
+
79
+ click.echo(f"Found {len(files_to_process)} source file(s)")
80
+ click.echo()
81
+
82
+ if dry_run:
83
+ click.secho("DRY RUN MODE - No files will be created", fg='cyan')
84
+ click.echo()
85
+
86
+ created_count = 0
87
+ skipped_count = 0
88
+
89
+ for file_path in files_to_process:
90
+ companion_path = file_path.parent / f"{file_path.stem}{CompanionFileScanner.COMPANION_EXTENSION}"
91
+
92
+ if companion_path.exists() and not force:
93
+ click.echo(f"⏭️ {file_path.name} (companion already exists)")
94
+ skipped_count += 1
95
+ continue
96
+
97
+ if dry_run:
98
+ if companion_path.exists():
99
+ click.echo(f"🔄 {file_path.name} → {companion_path.name} (would overwrite)")
100
+ else:
101
+ click.echo(f"✨ {file_path.name} → {companion_path.name} (would create)")
102
+ created_count += 1
103
+ else:
104
+ template = CompanionFileScanner.create_template(file_path)
105
+ companion_path.write_text(template, encoding='utf-8')
106
+
107
+ if force and companion_path.exists():
108
+ click.echo(f"🔄 {file_path.name} → {companion_path.name} (overwritten)")
109
+ else:
110
+ click.echo(f"✨ {file_path.name} → {companion_path.name}")
111
+
112
+ created_count += 1
113
+
114
+ click.echo()
115
+ click.echo("━" * 60)
116
+
117
+ if dry_run:
118
+ click.echo(f"Would create: {created_count}")
119
+ click.echo(f"Would skip: {skipped_count}")
120
+ else:
121
+ click.secho(f"Created: {created_count}", fg='green')
122
+ click.echo(f"Skipped: {skipped_count}")
123
+
124
+ click.echo("━" * 60)
125
+
126
+ if not dry_run and created_count > 0:
127
+ click.echo()
128
+ click.secho("✅ Companion files created!", fg='green')
129
+ click.echo()
130
+ click.echo("Next steps:")
131
+ click.echo(" 1. Edit the .voodocs.md files to add documentation")
132
+ click.echo(" 2. Run: voodocs generate --companion-files")
133
+ click.echo()
134
+ click.echo("Tip: Companion files support:")
135
+ click.echo(" • Rich Markdown formatting (tables, diagrams, links)")
136
+ click.echo(" • VooDocs symbolic notation (⊢{}, ⊨{}, ⊲{})")
137
+ click.echo(" • Version control alongside source files")
@@ -33,6 +33,7 @@ from darkarts.validation.performance_wrapper import PerformanceTracker
33
33
  @click.option('--strict', is_flag=True, help='Fail if validation fails')
34
34
  @click.option('--format', type=click.Choice(['markdown', 'html', 'json']), default='markdown', help='Output format')
35
35
  @click.option('--include-private', is_flag=True, help='Include private members in documentation')
36
+ @click.option('--companion-files', is_flag=True, help='Scan for .voodocs.md companion files alongside source files')
36
37
  def generate(
37
38
  source: str,
38
39
  output: str,
@@ -40,7 +41,8 @@ def generate(
40
41
  validate: bool,
41
42
  strict: bool,
42
43
  format: str,
43
- include_private: bool
44
+ include_private: bool,
45
+ companion_files: bool
44
46
  ):
45
47
  """
46
48
  Generate documentation from @darkarts annotations.
@@ -132,6 +134,29 @@ def generate(
132
134
 
133
135
  click.echo(f"Found {len(files_to_process)} files to process")
134
136
 
137
+ # Scan for companion files if requested
138
+ companion_mapping = {}
139
+ if companion_files:
140
+ click.echo()
141
+ click.secho("Scanning for companion files (.voodocs.md)...", fg='cyan')
142
+ from darkarts.companion_files import CompanionFileScanner
143
+
144
+ companion_count = 0
145
+ for file_path in files_to_process:
146
+ companion = CompanionFileScanner.find_companion_file(file_path)
147
+ if companion:
148
+ companion_mapping[file_path] = companion
149
+ companion_count += 1
150
+ click.echo(f" 📄 {file_path.name} → {companion.name}")
151
+
152
+ click.echo()
153
+ if companion_count > 0:
154
+ click.secho(f"✅ Found {companion_count} companion file(s)", fg='green')
155
+ else:
156
+ click.secho("⚠️ No companion files found", fg='yellow')
157
+ click.echo(" Tip: Create .voodocs.md files alongside your source files")
158
+ click.echo(" Example: contracts/Registry.sol → contracts/Registry.voodocs.md")
159
+
135
160
  # Validate if requested
136
161
  if validate:
137
162
  click.echo()
@@ -179,8 +204,14 @@ def generate(
179
204
  generated_files = []
180
205
  for file_path in files_to_process:
181
206
  try:
207
+ # Parse companion file if available
208
+ companion_data = None
209
+ if companion_files and file_path in companion_mapping:
210
+ from darkarts.companion_files import CompanionFileScanner
211
+ companion_data = CompanionFileScanner.parse_companion_file(companion_mapping[file_path])
212
+
182
213
  # Generate documentation for this file
183
- doc_content = _generate_doc_for_file(file_path, format, include_private)
214
+ doc_content = _generate_doc_for_file(file_path, format, include_private, companion_data)
184
215
 
185
216
  # Determine output filename
186
217
  if source_path.is_dir():
@@ -291,7 +322,7 @@ def generate(
291
322
  sys.exit(1)
292
323
 
293
324
 
294
- def _generate_doc_for_file(file_path: Path, format: str, include_private: bool) -> str:
325
+ def _generate_doc_for_file(file_path: Path, format: str, include_private: bool, companion_data: dict = None) -> str:
295
326
  """Generate documentation for a single file."""
296
327
  content = file_path.read_text(encoding='utf-8')
297
328
 
@@ -309,6 +340,25 @@ def _generate_doc_for_file(file_path: Path, format: str, include_private: bool)
309
340
  security = _extract_section(annotation, '🔒')
310
341
  performance = _extract_section(annotation, '⚡')
311
342
 
343
+ # Merge with companion file data if available
344
+ if companion_data:
345
+ if companion_data.get('purpose'):
346
+ module_id = companion_data['purpose']
347
+ if companion_data.get('dependencies'):
348
+ dependencies = ', '.join(companion_data['dependencies'])
349
+ if companion_data.get('invariants'):
350
+ inv_list = invariants.split('\n') if invariants else []
351
+ inv_list.extend(companion_data['invariants'])
352
+ invariants = '\n'.join(filter(None, inv_list))
353
+ if companion_data.get('assumptions'):
354
+ assume_list = assumptions.split('\n') if assumptions else []
355
+ assume_list.extend(companion_data['assumptions'])
356
+ assumptions = '\n'.join(filter(None, assume_list))
357
+ if companion_data.get('security'):
358
+ sec_list = security.split('\n') if security else []
359
+ sec_list.extend(companion_data['security'])
360
+ security = '\n'.join(filter(None, sec_list))
361
+
312
362
  # Generate documentation based on format
313
363
  if format == 'markdown':
314
364
  return _generate_markdown(file_path, module_id, dependencies, assumptions, invariants, security, performance)