@voodocs/cli 1.0.5 → 1.0.7

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,3 +1,62 @@
1
+ ## [1.0.7] - 2024-12-21
2
+
3
+ ### Added
4
+ - **Enhanced Init Wizard**: Complete interactive setup experience
5
+ - Auto-detects project details (name, version, repository)
6
+ - Generates AI instructions automatically
7
+ - Configures privacy settings (.gitignore)
8
+ - Creates example annotated files
9
+ - **Rerunnable for upgrades**: Detects existing config and adds missing features
10
+ - Smart defaults for non-interactive mode
11
+ - Beautiful CLI interface with status icons and summaries
12
+
13
+ ### Changed
14
+ - `voodocs init` now includes full wizard experience
15
+ - Wizard supports both fresh install and upgrade scenarios
16
+ - Auto-detection of AI environment (Cursor, Claude)
17
+
18
+ ### Fixed
19
+ - Init command now properly integrates with instruct command
20
+ - Upgrade path for users installing new versions
21
+
22
+ ## v1.0.6 (2024-12-21)
23
+
24
+ ### 🐛 Bug Fix: Missing Instructions Directory in npm Package
25
+
26
+ **Problem:** The `voodocs instruct` command failed with "Error: Instructions directory not found" because the `lib/darkarts/instructions/` directory was not included in the npm package.
27
+
28
+ **Root Cause:** The `instructions/` directory was not listed in the `files` array in `package.json`.
29
+
30
+ **Fix:** Added `lib/darkarts/instructions/` to the `files` array in `package.json`.
31
+
32
+ ---
33
+
34
+ ### Changes
35
+
36
+ - Added `lib/darkarts/instructions/` to package.json `files` array
37
+ - Verified that all instruction templates are now included in the package:
38
+ - `claude.md`
39
+ - `cursor.md`
40
+ - `default.md`
41
+
42
+ ---
43
+
44
+ ### Testing
45
+
46
+ | Test Case | Status |
47
+ |-----------|--------|
48
+ | Instructions directory included in package | ✅ Pass |
49
+ | `voodocs instruct --list-templates` | ✅ Pass |
50
+ | `voodocs instruct --ai cursor` | ✅ Pass |
51
+
52
+ ---
53
+
54
+ ### Upgrade
55
+
56
+ ```bash
57
+ npm install -g @voodocs/cli@1.0.6
58
+ ```
59
+
1
60
  ## v1.0.5 (2024-12-21)
2
61
 
3
62
  ### 🐛 Bug Fix: Instruct Command Import Error
@@ -16,7 +16,7 @@ This module provides the command-line interface for VooDocs.
16
16
  import click
17
17
  from typing import Optional
18
18
 
19
- __version__ = "1.0.5"
19
+ __version__ = "1.0.7"
20
20
 
21
21
 
22
22
  @click.group()
package/lib/cli/init.py CHANGED
@@ -1,8 +1,8 @@
1
1
  """@darkarts
2
- ⊢{cli:init}
3
- ∂{click,pathlib,json}
2
+ ⊢{cli:init-wizard}
3
+ ∂{click,pathlib,json,os,subprocess}
4
4
  ⚠{write-access:cwd}
5
- ⊨{idempotent:config-creation}
5
+ ⊨{idempotent:config-creation,rerunnable:upgrade-support}
6
6
  🔒{read-write:filesystem}
7
7
  ⚡{O(1):file-creation}
8
8
  """
@@ -10,52 +10,277 @@
10
10
  """
11
11
  VooDocs Init Command
12
12
 
13
- Initialize a new project with VooDocs configuration and example annotations.
13
+ Interactive wizard to initialize or upgrade a project with VooDocs.
14
+ Re-runnable to add missing features after upgrades.
14
15
  """
15
16
 
16
17
  import click
17
18
  import json
19
+ import os
20
+ import subprocess
18
21
  from pathlib import Path
22
+ from typing import Optional, Dict, Any
19
23
 
20
24
 
21
25
  @click.command()
22
26
  @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
+ '--non-interactive',
28
+ is_flag=True,
29
+ help='Skip interactive prompts and use defaults'
27
30
  )
28
31
  @click.option(
29
- '--config-only',
32
+ '--upgrade',
30
33
  is_flag=True,
31
- help='Only create configuration file, skip example files'
34
+ help='Upgrade existing configuration (add missing features)'
32
35
  )
33
- def init(format, config_only):
36
+ def init(non_interactive, upgrade):
34
37
  """
35
- Initialize a new project with VooDocs.
38
+ Initialize or upgrade a project with VooDocs.
39
+
40
+ This interactive wizard will:
41
+ - Set up your project configuration
42
+ - Auto-detect project details (version, repository, AI environment)
43
+ - Create AI instructions for your coding assistant
44
+ - Configure privacy settings (.gitignore)
45
+ - Generate example annotated files
36
46
 
37
- Creates a .voodocs.json configuration file and optionally generates
38
- example annotated files to help you get started.
47
+ Re-run after upgrading to add new features!
39
48
 
40
49
  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
50
+ voodocs init # Interactive wizard
51
+ voodocs init --upgrade # Upgrade existing config
52
+ voodocs init --non-interactive # Use all defaults
44
53
  """
54
+
45
55
  cwd = Path.cwd()
46
56
  config_path = cwd / '.voodocs.json'
47
57
 
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?'):
58
+ # Check if this is an upgrade or fresh install
59
+ existing_config = None
60
+ is_upgrade = config_path.exists()
61
+
62
+ if is_upgrade:
63
+ try:
64
+ with open(config_path) as f:
65
+ existing_config = json.load(f)
66
+ except:
67
+ existing_config = None
68
+
69
+ # Print welcome header
70
+ click.echo()
71
+ if is_upgrade:
72
+ click.echo(click.style('╔══════════════════════════════════════════╗', fg='yellow', bold=True))
73
+ click.echo(click.style('║ 🔄 VooDocs Upgrade Wizard ║', fg='yellow', bold=True))
74
+ click.echo(click.style('╚══════════════════════════════════════════╝', fg='yellow', bold=True))
75
+ click.echo()
76
+ click.echo(click.style('Existing configuration detected!', fg='yellow'))
77
+ click.echo('This wizard will help you add any missing features.')
78
+ else:
79
+ click.echo(click.style('╔══════════════════════════════════════════╗', fg='cyan', bold=True))
80
+ click.echo(click.style('║ 🎉 Welcome to VooDocs Setup Wizard ║', fg='cyan', bold=True))
81
+ click.echo(click.style('╚══════════════════════════════════════════╝', fg='cyan', bold=True))
82
+ click.echo()
83
+
84
+ # Detect what's already configured
85
+ has_ai_instructions = _check_ai_instructions(cwd)
86
+ has_examples = (cwd / 'voodocs-examples').exists()
87
+ has_gitignore_entry = _check_gitignore(cwd, '.voodocs.json')
88
+
89
+ if is_upgrade and not non_interactive:
90
+ click.echo(click.style('Current Setup:', fg='cyan', bold=True))
91
+ click.echo(f' Configuration: {_status_icon(True)} .voodocs.json exists')
92
+ click.echo(f' AI Instructions: {_status_icon(has_ai_instructions)} {_get_ai_file_status(cwd)}')
93
+ click.echo(f' Example Files: {_status_icon(has_examples)} voodocs-examples/')
94
+ click.echo(f' .gitignore: {_status_icon(has_gitignore_entry)} .voodocs.json entry')
95
+ click.echo()
96
+
97
+ if not click.confirm('Continue with upgrade?', default=True):
52
98
  click.echo('Aborted.')
53
99
  return
100
+ click.echo()
101
+
102
+ # Step 1: Project Information
103
+ click.echo(click.style('📋 Step 1: Project Information', fg='blue', bold=True))
104
+ click.echo()
105
+
106
+ # Auto-detect or use existing config
107
+ project_name = _get_value(existing_config, 'project.name', _detect_project_name(cwd))
108
+ project_version = _get_value(existing_config, 'project.version', _detect_version(cwd))
109
+ repository_url = _get_value(existing_config, 'project.repository', _detect_repository(cwd))
110
+ project_purpose = _get_value(existing_config, 'project.purpose', f'{project_name} project')
111
+
112
+ if non_interactive:
113
+ name = project_name
114
+ version = project_version
115
+ repository = repository_url
116
+ purpose = project_purpose
117
+ else:
118
+ if is_upgrade:
119
+ click.echo(f'Current values (press Enter to keep):')
120
+ name = click.prompt('Project name', default=project_name)
121
+ purpose = click.prompt('Project purpose', default=project_purpose)
122
+ version = click.prompt('Current version', default=project_version)
123
+ repository = click.prompt('Repository URL (leave empty to skip)', default=repository_url or '', show_default=False)
124
+
125
+ click.echo()
126
+
127
+ # Step 2: Annotation Format
128
+ click.echo(click.style('✨ Step 2: Annotation Format', fg='blue', bold=True))
129
+ click.echo()
130
+
131
+ current_format = _get_value(existing_config, 'format', 'darkarts')
132
+
133
+ if is_upgrade:
134
+ click.echo(f'Current format: {click.style(current_format, fg="green", bold=True)}')
135
+ if non_interactive:
136
+ format_choice = current_format
137
+ else:
138
+ change_format = click.confirm('Change annotation format?', default=False)
139
+ if change_format:
140
+ click.echo()
141
+ click.echo('VooDocs supports two annotation formats:')
142
+ click.echo(' 1. Natural language (e.g., module_purpose: "...")')
143
+ click.echo(' 2. Symbolic DarkArts (e.g., ⊢{...}, ∂{...}, ⚠{...})')
144
+ click.echo()
145
+ format_choice = click.prompt(
146
+ 'Choose format',
147
+ type=click.Choice(['voodocs', 'darkarts'], case_sensitive=False),
148
+ default=current_format
149
+ )
150
+ else:
151
+ format_choice = current_format
152
+ else:
153
+ click.echo('VooDocs supports two annotation formats:')
154
+ click.echo(' 1. Natural language (e.g., module_purpose: "...")')
155
+ click.echo(' 2. Symbolic DarkArts (e.g., ⊢{...}, ∂{...}, ⚠{...})')
156
+ click.echo()
157
+ if non_interactive:
158
+ format_choice = 'darkarts'
159
+ else:
160
+ format_choice = click.prompt(
161
+ 'Choose format',
162
+ type=click.Choice(['voodocs', 'darkarts'], case_sensitive=False),
163
+ default='darkarts'
164
+ )
165
+
166
+ click.echo()
167
+
168
+ # Step 3: AI Assistant Setup
169
+ click.echo(click.style('🤖 Step 3: AI Assistant Setup', fg='blue', bold=True))
170
+ click.echo()
171
+
172
+ detected_ai = _detect_ai_environment()
173
+
174
+ if has_ai_instructions and is_upgrade:
175
+ click.echo(f'{_status_icon(True)} AI instructions already configured')
176
+ if non_interactive:
177
+ setup_ai = False
178
+ ai_choice = None
179
+ else:
180
+ setup_ai = click.confirm('Update AI instructions?', default=False)
181
+ if setup_ai:
182
+ ai_choice = click.prompt(
183
+ 'Which AI assistant?',
184
+ type=click.Choice(['cursor', 'claude', 'default'], case_sensitive=False),
185
+ default=detected_ai or 'cursor'
186
+ )
187
+ else:
188
+ ai_choice = None
189
+ else:
190
+ if detected_ai:
191
+ click.echo(f'Detected AI environment: {click.style(detected_ai, fg="green", bold=True)}')
192
+ else:
193
+ click.echo('No AI environment detected')
194
+ click.echo()
195
+
196
+ if non_interactive:
197
+ setup_ai = detected_ai is not None
198
+ ai_choice = detected_ai or 'cursor'
199
+ else:
200
+ setup_ai = click.confirm('Generate AI instructions for your coding assistant?', default=True)
201
+ if setup_ai:
202
+ ai_choice = click.prompt(
203
+ 'Which AI assistant?',
204
+ type=click.Choice(['cursor', 'claude', 'default'], case_sensitive=False),
205
+ default=detected_ai or 'cursor'
206
+ )
207
+ else:
208
+ ai_choice = None
209
+
210
+ click.echo()
211
+
212
+ # Step 4: Privacy Settings
213
+ click.echo(click.style('🔒 Step 4: Privacy Settings', fg='blue', bold=True))
214
+ click.echo()
215
+
216
+ if has_gitignore_entry and is_upgrade:
217
+ click.echo(f'{_status_icon(True)} .gitignore already configured')
218
+ add_to_gitignore = False
219
+ else:
220
+ if non_interactive:
221
+ is_private = True
222
+ add_to_gitignore = True
223
+ else:
224
+ is_private = click.confirm('Is this a private project?', default=True)
225
+ add_to_gitignore = False
226
+ if is_private:
227
+ add_to_gitignore = click.confirm('Add .voodocs.json to .gitignore?', default=True)
228
+
229
+ click.echo()
230
+
231
+ # Step 5: Example Files
232
+ click.echo(click.style('📝 Step 5: Example Files', fg='blue', bold=True))
233
+ click.echo()
234
+
235
+ if has_examples and is_upgrade:
236
+ click.echo(f'{_status_icon(True)} Example files already exist')
237
+ create_examples = False
238
+ else:
239
+ if non_interactive:
240
+ create_examples = True
241
+ else:
242
+ create_examples = click.confirm('Create example annotated files?', default=not is_upgrade)
243
+
244
+ click.echo()
245
+
246
+ # Show configuration summary
247
+ click.echo(click.style('📊 Configuration Summary', fg='cyan', bold=True))
248
+ click.echo(click.style('─' * 50, fg='cyan'))
249
+ click.echo(f' Project Name: {click.style(name, fg="green")}')
250
+ click.echo(f' Purpose: {purpose}')
251
+ click.echo(f' Version: {version}')
252
+ if repository:
253
+ click.echo(f' Repository: {repository}')
254
+ click.echo(f' Format: {click.style(format_choice, fg="green", bold=True)}')
255
+ if setup_ai and ai_choice:
256
+ click.echo(f' AI Assistant: {click.style(ai_choice, fg="green")} {_status_icon(True, "new") if not has_ai_instructions else ""}')
257
+ if add_to_gitignore:
258
+ click.echo(f' .gitignore: {click.style("Yes", fg="green")} {_status_icon(True, "new")}')
259
+ if create_examples:
260
+ click.echo(f' Example Files: {click.style("Yes", fg="green")} {_status_icon(True, "new")}')
261
+ click.echo(click.style('─' * 50, fg='cyan'))
262
+ click.echo()
263
+
264
+ if not non_interactive:
265
+ action = 'upgrade' if is_upgrade else 'create'
266
+ if not click.confirm(f'Proceed to {action} configuration?', default=True):
267
+ click.echo('Aborted.')
268
+ return
269
+ click.echo()
270
+
271
+ # Create/update configuration
272
+ action_verb = 'Updating' if is_upgrade else 'Creating'
273
+ click.echo(click.style(f'⚙️ {action_verb} configuration...', fg='blue'))
54
274
 
55
- # Create default configuration
56
275
  config = {
57
276
  "version": "1.0",
58
- "format": format,
277
+ "project": {
278
+ "name": name,
279
+ "purpose": purpose,
280
+ "version": version,
281
+ "repository": repository if repository else None
282
+ },
283
+ "format": format_choice,
59
284
  "validation": {
60
285
  "semantic": True,
61
286
  "performance": True,
@@ -76,40 +301,252 @@ def init(format, config_only):
76
301
  ]
77
302
  }
78
303
 
304
+ # Merge with existing config if upgrading
305
+ if is_upgrade and existing_config:
306
+ # Preserve any custom fields
307
+ for key in existing_config:
308
+ if key not in config:
309
+ config[key] = existing_config[key]
310
+
79
311
  # Write configuration
80
312
  with open(config_path, 'w') as f:
81
313
  json.dump(config, f, indent=2)
82
314
 
83
- click.echo(click.style('✓ Created .voodocs.json', fg='green'))
315
+ verb = 'Updated' if is_upgrade else 'Created'
316
+ click.echo(click.style(f' ✓ {verb} .voodocs.json', fg='green'))
317
+
318
+ # Add to .gitignore if requested
319
+ if add_to_gitignore:
320
+ _add_to_gitignore(cwd, '.voodocs.json')
321
+ click.echo(click.style(' ✓ Added to .gitignore', fg='green'))
322
+
323
+ # Generate AI instructions
324
+ if setup_ai and ai_choice:
325
+ click.echo(click.style(f' ⚙️ Generating {ai_choice} instructions...', fg='blue'))
326
+ _generate_ai_instructions(cwd, ai_choice, format_choice)
327
+ click.echo(click.style(f' ✓ Created AI instructions', fg='green'))
84
328
 
85
- if not config_only:
86
- # Create example files
329
+ # Create example files
330
+ if create_examples:
331
+ click.echo(click.style(' ⚙️ Creating example files...', fg='blue'))
87
332
  examples_dir = cwd / 'voodocs-examples'
88
333
  examples_dir.mkdir(exist_ok=True)
89
334
 
90
- if format == 'voodocs':
91
- create_voodocs_example(examples_dir)
335
+ if format_choice == 'voodocs':
336
+ _create_voodocs_examples(examples_dir)
92
337
  else:
93
- create_darkarts_example(examples_dir)
338
+ _create_darkarts_examples(examples_dir)
94
339
 
95
- click.echo(click.style(f'✓ Created example files in {examples_dir}/', fg='green'))
340
+ click.echo(click.style(f' ✓ Created examples in {examples_dir}/', fg='green'))
96
341
 
342
+ # Success!
97
343
  click.echo()
98
- click.echo(click.style('🎉 VooDocs initialized successfully!', fg='green', bold=True))
344
+ if is_upgrade:
345
+ click.echo(click.style('╔══════════════════════════════════════════╗', fg='green', bold=True))
346
+ click.echo(click.style('║ ✅ VooDocs Upgrade Complete! ║', fg='green', bold=True))
347
+ click.echo(click.style('╚══════════════════════════════════════════╝', fg='green', bold=True))
348
+ else:
349
+ click.echo(click.style('╔══════════════════════════════════════════╗', fg='green', bold=True))
350
+ click.echo(click.style('║ 🎉 VooDocs Setup Complete! ║', fg='green', bold=True))
351
+ click.echo(click.style('╚══════════════════════════════════════════╝', fg='green', bold=True))
99
352
  click.echo()
100
- click.echo('Next steps:')
353
+ click.echo(click.style('Next steps:', fg='cyan', bold=True))
101
354
  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')
355
+ if setup_ai and ai_choice:
356
+ ai_file = '.cursorrules' if ai_choice == 'cursor' else f'{ai_choice}-instructions.md'
357
+ click.echo(f' 2. Your AI assistant will use {ai_file}')
358
+ click.echo(' 3. Add annotations to your code')
359
+ click.echo(' 4. Run: voodocs validate .')
360
+ click.echo(' 5. Run: voodocs generate . ./docs')
105
361
  click.echo()
106
- click.echo('Documentation: https://voodocs.com/docs')
362
+ if is_upgrade:
363
+ click.echo(click.style('💡 Tip:', fg='yellow') + ' Run ' + click.style('voodocs init --upgrade', fg='cyan') + ' again after future updates!')
364
+ click.echo()
365
+ click.echo(f'Documentation: {click.style("https://voodocs.com/docs", fg="blue", underline=True)}')
366
+ click.echo()
367
+
107
368
 
369
+ def _status_icon(exists: bool, label: str = None) -> str:
370
+ """Return a status icon."""
371
+ if label == "new":
372
+ return click.style('🆕', fg='green')
373
+ return click.style('✓', fg='green') if exists else click.style('✗', fg='red')
108
374
 
109
- def create_voodocs_example(examples_dir: Path):
375
+
376
+ def _get_value(config: Optional[Dict[str, Any]], path: str, default: Any) -> Any:
377
+ """Get a value from nested config dict using dot notation."""
378
+ if not config:
379
+ return default
380
+
381
+ keys = path.split('.')
382
+ value = config
383
+ for key in keys:
384
+ if isinstance(value, dict) and key in value:
385
+ value = value[key]
386
+ else:
387
+ return default
388
+
389
+ return value if value is not None else default
390
+
391
+
392
+ def _check_ai_instructions(cwd: Path) -> bool:
393
+ """Check if AI instructions exist."""
394
+ return (
395
+ (cwd / '.cursorrules').exists() or
396
+ (cwd / '.claude' / 'instructions.md').exists() or
397
+ (cwd / 'AI_INSTRUCTIONS.md').exists()
398
+ )
399
+
400
+
401
+ def _get_ai_file_status(cwd: Path) -> str:
402
+ """Get status of AI instruction files."""
403
+ files = []
404
+ if (cwd / '.cursorrules').exists():
405
+ files.append('.cursorrules')
406
+ if (cwd / '.claude' / 'instructions.md').exists():
407
+ files.append('.claude/instructions.md')
408
+ if (cwd / 'AI_INSTRUCTIONS.md').exists():
409
+ files.append('AI_INSTRUCTIONS.md')
410
+
411
+ return ', '.join(files) if files else 'none'
412
+
413
+
414
+ def _check_gitignore(cwd: Path, entry: str) -> bool:
415
+ """Check if entry exists in .gitignore."""
416
+ gitignore = cwd / '.gitignore'
417
+ if not gitignore.exists():
418
+ return False
419
+
420
+ content = gitignore.read_text()
421
+ return entry in content
422
+
423
+
424
+ def _detect_project_name(cwd: Path) -> str:
425
+ """Detect project name from directory or package.json."""
426
+ package_json = cwd / 'package.json'
427
+ if package_json.exists():
428
+ try:
429
+ with open(package_json) as f:
430
+ data = json.load(f)
431
+ if 'name' in data:
432
+ return data['name']
433
+ except:
434
+ pass
435
+
436
+ return cwd.name
437
+
438
+
439
+ def _detect_version(cwd: Path) -> str:
440
+ """Detect project version."""
441
+ package_json = cwd / 'package.json'
442
+ if package_json.exists():
443
+ try:
444
+ with open(package_json) as f:
445
+ data = json.load(f)
446
+ if 'version' in data:
447
+ return data['version']
448
+ except:
449
+ pass
450
+
451
+ pyproject = cwd / 'pyproject.toml'
452
+ if pyproject.exists():
453
+ try:
454
+ with open(pyproject) as f:
455
+ for line in f:
456
+ if line.startswith('version'):
457
+ return line.split('=')[1].strip().strip('"\'')
458
+ except:
459
+ pass
460
+
461
+ version_file = cwd / 'VERSION'
462
+ if version_file.exists():
463
+ try:
464
+ return version_file.read_text().strip()
465
+ except:
466
+ pass
467
+
468
+ return '1.0.0'
469
+
470
+
471
+ def _detect_repository(cwd: Path) -> Optional[str]:
472
+ """Detect repository URL from git config."""
473
+ try:
474
+ result = subprocess.run(
475
+ ['git', 'config', '--get', 'remote.origin.url'],
476
+ capture_output=True,
477
+ text=True,
478
+ cwd=cwd
479
+ )
480
+ if result.returncode == 0:
481
+ url = result.stdout.strip()
482
+ if url.startswith('git@github.com:'):
483
+ url = url.replace('git@github.com:', 'https://github.com/')
484
+ if url.endswith('.git'):
485
+ url = url[:-4]
486
+ return url
487
+ except:
488
+ pass
489
+
490
+ return None
491
+
492
+
493
+ def _detect_ai_environment() -> Optional[str]:
494
+ """Detect which AI environment is being used."""
495
+ if os.environ.get('CURSOR_USER') or Path('.cursorrules').exists():
496
+ return 'cursor'
497
+
498
+ if os.environ.get('CLAUDE_API_KEY') or Path('.claude').exists():
499
+ return 'claude'
500
+
501
+ return None
502
+
503
+
504
+ def _add_to_gitignore(cwd: Path, entry: str):
505
+ """Add an entry to .gitignore."""
506
+ gitignore = cwd / '.gitignore'
507
+
508
+ if gitignore.exists():
509
+ content = gitignore.read_text()
510
+ if entry in content:
511
+ return
512
+ else:
513
+ content = ''
514
+
515
+ if content and not content.endswith('\n'):
516
+ content += '\n'
517
+ content += f'\n# VooDocs\n{entry}\n'
518
+
519
+ gitignore.write_text(content)
520
+
521
+
522
+ def _generate_ai_instructions(cwd: Path, ai_type: str, format_type: str):
523
+ """Generate AI instructions file."""
524
+ cli_dir = Path(__file__).parent
525
+ template_path = cli_dir.parent / 'darkarts' / 'instructions' / f'{ai_type}.md'
526
+
527
+ if not template_path.exists():
528
+ template_path = cli_dir.parent / 'darkarts' / 'instructions' / 'default.md'
529
+
530
+ if not template_path.exists():
531
+ return
532
+
533
+ instructions = template_path.read_text()
534
+
535
+ if ai_type == 'cursor':
536
+ output_file = cwd / '.cursorrules'
537
+ elif ai_type == 'claude':
538
+ output_dir = cwd / '.claude'
539
+ output_dir.mkdir(exist_ok=True)
540
+ output_file = output_dir / 'instructions.md'
541
+ else:
542
+ output_file = cwd / 'AI_INSTRUCTIONS.md'
543
+
544
+ output_file.write_text(instructions)
545
+
546
+
547
+ def _create_voodocs_examples(examples_dir: Path):
110
548
  """Create example files with @voodocs annotations."""
111
549
 
112
- # TypeScript example
113
550
  ts_example = '''/**@voodocs
114
551
  module_purpose: "Example TypeScript module demonstrating @voodocs annotations"
115
552
  dependencies: []
@@ -137,41 +574,11 @@ export function greet(name: string, age: number): string {
137
574
  '''
138
575
 
139
576
  (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
577
 
170
578
 
171
- def create_darkarts_example(examples_dir: Path):
579
+ def _create_darkarts_examples(examples_dir: Path):
172
580
  """Create example files with symbolic @darkarts annotations."""
173
581
 
174
- # TypeScript example
175
582
  ts_example = '''/**@darkarts
176
583
  ⊢{Example TypeScript module demonstrating symbolic @darkarts annotations}
177
584
  ∂{}
@@ -190,7 +597,7 @@ def create_darkarts_example(examples_dir: Path):
190
597
  ⊨{
191
598
  Does ¬ modify input parameters
192
599
  }
193
- ⚡{}
600
+ ⚡{O(1)}
194
601
  */
195
602
  export function greet(name: string, age: number): string {
196
603
  return `Hello, ${name}! You are ${age} years old.`;
@@ -198,31 +605,3 @@ export function greet(name: string, age: number): string {
198
605
  '''
199
606
 
200
607
  (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)
@@ -0,0 +1,139 @@
1
+ # Claude AI Instructions for Symbolic DarkArts Annotations
2
+
3
+ **Version:** 2.0
4
+ **Date:** December 21, 2024
5
+
6
+ ---
7
+
8
+ ## 1. Primary Goal
9
+
10
+ Your primary goal is to **write and maintain symbolic DarkArts annotations** for all new and existing code. This ensures that our documentation is always up-to-date, accurate, and machine-readable.
11
+
12
+ ---
13
+
14
+ ## 2. Annotation Format: Symbolic DarkArts
15
+
16
+ **Always use the symbolic DarkArts format.** Do not use the natural language `@voodocs` format.
17
+
18
+ ### Correct Format
19
+
20
+ ```typescript
21
+ /**@darkarts
22
+ ⊢{Module purpose}
23
+ ∂{Dependencies}
24
+ ⚠{Assumptions}
25
+ */
26
+
27
+ /**@darkarts
28
+ ⊳{Preconditions}
29
+ ⊲{Postconditions}
30
+ ⊨{Invariants}
31
+ ⚡{Side effects / Complexity}
32
+ 🔒{Security implications}
33
+ */
34
+ ```
35
+
36
+ ### Incorrect Format (Do Not Use)
37
+
38
+ ```typescript
39
+ /**@voodocs
40
+ module_purpose: "..."
41
+ dependencies: [...]
42
+ */
43
+ ```
44
+
45
+ ---
46
+
47
+ ## 3. Key Rules
48
+
49
+ 1. **Annotate Everything:** All modules, functions, classes, and interfaces must have a DarkArts annotation block.
50
+ 2. **Use Symbolic Format Only:** Strictly adhere to the symbolic format (`⊢`, `∂`, `⚠`, `⊳`, `⊲`, `⊨`, `⚡`, `🔒`).
51
+ 3. **Use Logic Symbols:** Use mathematical symbols for logic (`∧`, `∨`, `¬`, `∈`, `∃`, `∀`, `⇒`, `⇔`).
52
+ 4. **Be Precise and Concise:** Annotations should be accurate and to the point.
53
+ 5. **Validate Your Work:** After making changes, run `voodocs validate . --recursive` to ensure all annotations are correct.
54
+
55
+ ---
56
+
57
+ ## 4. Symbol Quick Reference
58
+
59
+ | Symbol | Meaning | Symbol | Meaning |
60
+ |---|---|---|---|
61
+ | `⊢` | Module Purpose | `∧` | And |
62
+ | `∂` | Dependencies | `∨` | Or |
63
+ | `⚠` | Assumptions | `¬` | Not |
64
+ | `⊳` | Preconditions | `∈` | In |
65
+ | `⊲` | Postconditions | `∉` | Not In |
66
+ | `⊨` | Invariants | `∃` | Exists |
67
+ | `⚡` | Side Effects / Complexity | `∀` | For All |
68
+ | `🔒` | Security Implications | `⇒` | Implies |
69
+ | `⇔` | If and Only If | `⊤` | True |
70
+ | `⊥` | False | `∅` | Empty Set |
71
+ | `⊆` | Subset | `∪` | Union |
72
+ | `∩` | Intersection | | |
73
+
74
+ ---
75
+
76
+ ## 5. Workflow
77
+
78
+ 1. **When writing new code:** Add symbolic DarkArts annotations as you go.
79
+ 2. **When modifying existing code:** Update the corresponding annotations to reflect your changes.
80
+ 3. **Before committing:** Run `voodocs validate . --recursive` to catch any errors.
81
+ 4. **If validation fails:** Run `voodocs fix . --recursive` to automatically fix common issues.
82
+
83
+ ---
84
+
85
+ ## 6. Example: Adding a New Function
86
+
87
+ If you add a new function `getUserById`, you must add a symbolic annotation block:
88
+
89
+ ```typescript
90
+ /**@darkarts
91
+ ⊳{userId must be a valid UUID}
92
+ ⊲{
93
+ Returns a user object if found
94
+ Returns null if ¬∃ user with that ID
95
+ }
96
+ ⊨{Does ¬ modify the database}
97
+ ⚡{O(1) lookup}
98
+ */
99
+ export async function getUserById(userId: string): Promise<User | null> {
100
+ // ...
101
+ }
102
+ ```
103
+
104
+ ---
105
+
106
+ ## 7. Example: Modifying a Module
107
+
108
+ If you add a new dependency to a module, update the `∂` field:
109
+
110
+ **Before:**
111
+ ```typescript
112
+ /**@darkarts
113
+ ⊢{User authentication service}
114
+ ∂{jsonwebtoken}
115
+ */
116
+ ```
117
+
118
+ **After (added bcrypt):**
119
+ ```typescript
120
+ /**@darkarts
121
+ ⊢{User authentication service}
122
+ ∂{
123
+ jsonwebtoken: For JWT creation
124
+ bcrypt: For password hashing
125
+ }
126
+ */
127
+ ```
128
+
129
+ ---
130
+
131
+ ## 8. Important Commands
132
+
133
+ - **Validate:** `voodocs validate . --recursive`
134
+ - **Fix:** `voodocs fix . --recursive`
135
+ - **Generate Docs:** `voodocs generate . ./docs --recursive`
136
+
137
+ ---
138
+
139
+ By following these instructions, you will help us maintain a high-quality, machine-readable, and self-validating codebase. Thank you for your contribution!
@@ -0,0 +1,139 @@
1
+ # Cursor AI Instructions for Symbolic DarkArts Annotations
2
+
3
+ **Version:** 2.0
4
+ **Date:** December 21, 2024
5
+
6
+ ---
7
+
8
+ ## 1. Primary Goal
9
+
10
+ Your primary goal is to **write and maintain symbolic DarkArts annotations** for all new and existing code. This ensures that our documentation is always up-to-date, accurate, and machine-readable.
11
+
12
+ ---
13
+
14
+ ## 2. Annotation Format: Symbolic DarkArts
15
+
16
+ **Always use the symbolic DarkArts format.** Do not use the natural language `@voodocs` format.
17
+
18
+ ### Correct Format
19
+
20
+ ```typescript
21
+ /**@darkarts
22
+ ⊢{Module purpose}
23
+ ∂{Dependencies}
24
+ ⚠{Assumptions}
25
+ */
26
+
27
+ /**@darkarts
28
+ ⊳{Preconditions}
29
+ ⊲{Postconditions}
30
+ ⊨{Invariants}
31
+ ⚡{Side effects / Complexity}
32
+ 🔒{Security implications}
33
+ */
34
+ ```
35
+
36
+ ### Incorrect Format (Do Not Use)
37
+
38
+ ```typescript
39
+ /**@voodocs
40
+ module_purpose: "..."
41
+ dependencies: [...]
42
+ */
43
+ ```
44
+
45
+ ---
46
+
47
+ ## 3. Key Rules
48
+
49
+ 1. **Annotate Everything:** All modules, functions, classes, and interfaces must have a DarkArts annotation block.
50
+ 2. **Use Symbolic Format Only:** Strictly adhere to the symbolic format (`⊢`, `∂`, `⚠`, `⊳`, `⊲`, `⊨`, `⚡`, `🔒`).
51
+ 3. **Use Logic Symbols:** Use mathematical symbols for logic (`∧`, `∨`, `¬`, `∈`, `∃`, `∀`, `⇒`, `⇔`).
52
+ 4. **Be Precise and Concise:** Annotations should be accurate and to the point.
53
+ 5. **Validate Your Work:** After making changes, run `voodocs validate . --recursive` to ensure all annotations are correct.
54
+
55
+ ---
56
+
57
+ ## 4. Symbol Quick Reference
58
+
59
+ | Symbol | Meaning | Symbol | Meaning |
60
+ |---|---|---|---|
61
+ | `⊢` | Module Purpose | `∧` | And |
62
+ | `∂` | Dependencies | `∨` | Or |
63
+ | `⚠` | Assumptions | `¬` | Not |
64
+ | `⊳` | Preconditions | `∈` | In |
65
+ | `⊲` | Postconditions | `∉` | Not In |
66
+ | `⊨` | Invariants | `∃` | Exists |
67
+ | `⚡` | Side Effects / Complexity | `∀` | For All |
68
+ | `🔒` | Security Implications | `⇒` | Implies |
69
+ | `⇔` | If and Only If | `⊤` | True |
70
+ | `⊥` | False | `∅` | Empty Set |
71
+ | `⊆` | Subset | `∪` | Union |
72
+ | `∩` | Intersection | | |
73
+
74
+ ---
75
+
76
+ ## 5. Workflow
77
+
78
+ 1. **When writing new code:** Add symbolic DarkArts annotations as you go.
79
+ 2. **When modifying existing code:** Update the corresponding annotations to reflect your changes.
80
+ 3. **Before committing:** Run `voodocs validate . --recursive` to catch any errors.
81
+ 4. **If validation fails:** Run `voodocs fix . --recursive` to automatically fix common issues.
82
+
83
+ ---
84
+
85
+ ## 6. Example: Adding a New Function
86
+
87
+ If you add a new function `getUserById`, you must add a symbolic annotation block:
88
+
89
+ ```typescript
90
+ /**@darkarts
91
+ ⊳{userId must be a valid UUID}
92
+ ⊲{
93
+ Returns a user object if found
94
+ Returns null if ¬∃ user with that ID
95
+ }
96
+ ⊨{Does ¬ modify the database}
97
+ ⚡{O(1) lookup}
98
+ */
99
+ export async function getUserById(userId: string): Promise<User | null> {
100
+ // ...
101
+ }
102
+ ```
103
+
104
+ ---
105
+
106
+ ## 7. Example: Modifying a Module
107
+
108
+ If you add a new dependency to a module, update the `∂` field:
109
+
110
+ **Before:**
111
+ ```typescript
112
+ /**@darkarts
113
+ ⊢{User authentication service}
114
+ ∂{jsonwebtoken}
115
+ */
116
+ ```
117
+
118
+ **After (added bcrypt):**
119
+ ```typescript
120
+ /**@darkarts
121
+ ⊢{User authentication service}
122
+ ∂{
123
+ jsonwebtoken: For JWT creation
124
+ bcrypt: For password hashing
125
+ }
126
+ */
127
+ ```
128
+
129
+ ---
130
+
131
+ ## 8. Important Commands
132
+
133
+ - **Validate:** `voodocs validate . --recursive`
134
+ - **Fix:** `voodocs fix . --recursive`
135
+ - **Generate Docs:** `voodocs generate . ./docs --recursive`
136
+
137
+ ---
138
+
139
+ By following these instructions, you will help us maintain a high-quality, machine-readable, and self-validating codebase. Thank you for your contribution!
@@ -0,0 +1,139 @@
1
+ # AI Instructions for Symbolic DarkArts Annotations
2
+
3
+ **Version:** 2.0
4
+ **Date:** December 21, 2024
5
+
6
+ ---
7
+
8
+ ## 1. Primary Goal
9
+
10
+ Your primary goal is to **write and maintain symbolic DarkArts annotations** for all new and existing code. This ensures that our documentation is always up-to-date, accurate, and machine-readable.
11
+
12
+ ---
13
+
14
+ ## 2. Annotation Format: Symbolic DarkArts
15
+
16
+ **Always use the symbolic DarkArts format.** Do not use the natural language `@voodocs` format.
17
+
18
+ ### Correct Format
19
+
20
+ ```typescript
21
+ /**@darkarts
22
+ ⊢{Module purpose}
23
+ ∂{Dependencies}
24
+ ⚠{Assumptions}
25
+ */
26
+
27
+ /**@darkarts
28
+ ⊳{Preconditions}
29
+ ⊲{Postconditions}
30
+ ⊨{Invariants}
31
+ ⚡{Side effects / Complexity}
32
+ 🔒{Security implications}
33
+ */
34
+ ```
35
+
36
+ ### Incorrect Format (Do Not Use)
37
+
38
+ ```typescript
39
+ /**@voodocs
40
+ module_purpose: "..."
41
+ dependencies: [...]
42
+ */
43
+ ```
44
+
45
+ ---
46
+
47
+ ## 3. Key Rules
48
+
49
+ 1. **Annotate Everything:** All modules, functions, classes, and interfaces must have a DarkArts annotation block.
50
+ 2. **Use Symbolic Format Only:** Strictly adhere to the symbolic format (`⊢`, `∂`, `⚠`, `⊳`, `⊲`, `⊨`, `⚡`, `🔒`).
51
+ 3. **Use Logic Symbols:** Use mathematical symbols for logic (`∧`, `∨`, `¬`, `∈`, `∃`, `∀`, `⇒`, `⇔`).
52
+ 4. **Be Precise and Concise:** Annotations should be accurate and to the point.
53
+ 5. **Validate Your Work:** After making changes, run `voodocs validate . --recursive` to ensure all annotations are correct.
54
+
55
+ ---
56
+
57
+ ## 4. Symbol Quick Reference
58
+
59
+ | Symbol | Meaning | Symbol | Meaning |
60
+ |---|---|---|---|
61
+ | `⊢` | Module Purpose | `∧` | And |
62
+ | `∂` | Dependencies | `∨` | Or |
63
+ | `⚠` | Assumptions | `¬` | Not |
64
+ | `⊳` | Preconditions | `∈` | In |
65
+ | `⊲` | Postconditions | `∉` | Not In |
66
+ | `⊨` | Invariants | `∃` | Exists |
67
+ | `⚡` | Side Effects / Complexity | `∀` | For All |
68
+ | `🔒` | Security Implications | `⇒` | Implies |
69
+ | `⇔` | If and Only If | `⊤` | True |
70
+ | `⊥` | False | `∅` | Empty Set |
71
+ | `⊆` | Subset | `∪` | Union |
72
+ | `∩` | Intersection | | |
73
+
74
+ ---
75
+
76
+ ## 5. Workflow
77
+
78
+ 1. **When writing new code:** Add symbolic DarkArts annotations as you go.
79
+ 2. **When modifying existing code:** Update the corresponding annotations to reflect your changes.
80
+ 3. **Before committing:** Run `voodocs validate . --recursive` to catch any errors.
81
+ 4. **If validation fails:** Run `voodocs fix . --recursive` to automatically fix common issues.
82
+
83
+ ---
84
+
85
+ ## 6. Example: Adding a New Function
86
+
87
+ If you add a new function `getUserById`, you must add a symbolic annotation block:
88
+
89
+ ```typescript
90
+ /**@darkarts
91
+ ⊳{userId must be a valid UUID}
92
+ ⊲{
93
+ Returns a user object if found
94
+ Returns null if ¬∃ user with that ID
95
+ }
96
+ ⊨{Does ¬ modify the database}
97
+ ⚡{O(1) lookup}
98
+ */
99
+ export async function getUserById(userId: string): Promise<User | null> {
100
+ // ...
101
+ }
102
+ ```
103
+
104
+ ---
105
+
106
+ ## 7. Example: Modifying a Module
107
+
108
+ If you add a new dependency to a module, update the `∂` field:
109
+
110
+ **Before:**
111
+ ```typescript
112
+ /**@darkarts
113
+ ⊢{User authentication service}
114
+ ∂{jsonwebtoken}
115
+ */
116
+ ```
117
+
118
+ **After (added bcrypt):**
119
+ ```typescript
120
+ /**@darkarts
121
+ ⊢{User authentication service}
122
+ ∂{
123
+ jsonwebtoken: For JWT creation
124
+ bcrypt: For password hashing
125
+ }
126
+ */
127
+ ```
128
+
129
+ ---
130
+
131
+ ## 8. Important Commands
132
+
133
+ - **Validate:** `voodocs validate . --recursive`
134
+ - **Fix:** `voodocs fix . --recursive`
135
+ - **Generate Docs:** `voodocs generate . ./docs --recursive`
136
+
137
+ ---
138
+
139
+ By following these instructions, you will help us maintain a high-quality, machine-readable, and self-validating codebase. Thank you for your contribution!
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voodocs/cli",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
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": {
@@ -58,6 +58,7 @@
58
58
  "lib/darkarts/context/",
59
59
  "lib/darkarts/core/",
60
60
  "lib/darkarts/validation/",
61
+ "lib/darkarts/instructions/",
61
62
  "lib/darkarts/exceptions.py",
62
63
  "lib/darkarts/telemetry.py",
63
64
  "lib/darkarts/parsers/typescript/dist/",