@voodocs/cli 0.1.0 → 0.1.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.
package/CHANGELOG.md ADDED
@@ -0,0 +1,205 @@
1
+ ## [0.1.2] - 2025-12-19
2
+
3
+ ### Fixed
4
+ - Fixed bug in documentation generator where `class_invariants` was incorrectly referenced as `invariants` on line 570
5
+ - Function-level invariants now render correctly in generated documentation
6
+
7
+ ### Added
8
+ - Comprehensive example file demonstrating function-level invariants (`examples/test_function_invariants.py`)
9
+ - Examples showing `transfer_funds()`, `binary_search()`, and `BankAccount` class with invariants
10
+ - Documentation in USAGE.md clarifying when to use `invariants` vs `class_invariants`
11
+ - Real-world examples of conservation laws and state constraints using invariants
12
+
13
+ ### Changed
14
+ - Updated USAGE.md annotation fields table to clarify `invariants` usage
15
+ - Added "Function with Invariants" and "Class with Invariants" examples to USAGE.md
16
+
17
+ ### Documentation
18
+ - Clarified that `invariants` can be used at function level for execution-time properties
19
+ - Clarified that `class_invariants` should be used for object state constraints
20
+ - Added examples showing both use cases
21
+
22
+ ## [0.1.1] - 2025-12-19
23
+
24
+ ### Fixed
25
+
26
+ **Critical Bug Fix:**
27
+ - Fixed `ModuleNotFoundError: No module named 'darkarts.telemetry'` when using pnpm global installation
28
+ - Improved symlink resolution in `cli.py` to handle both npm and pnpm directory structures
29
+ - Now works correctly with npm, pnpm, and direct execution
30
+
31
+ **Technical Details:**
32
+ - pnpm uses a different symlink structure (`.pnpm/@voodocs+cli@version/node_modules/...`)
33
+ - Previous path resolution only worked with npm's simpler symlink structure
34
+ - New implementation properly resolves symlinks for both package managers
35
+
36
+ **Affected Users:**
37
+ - Users installing with `pnpm install -g @voodocs/cli`
38
+ - npm users are unaffected (already working)
39
+
40
+ # Changelog
41
+
42
+ All notable changes to VooDocs will be documented in this file.
43
+
44
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
45
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
46
+
47
+ ## [0.1.0] - 2025-12-19
48
+
49
+ ### 🎉 Initial Release
50
+
51
+ First public release of VooDocs - AI-native documentation for modern development.
52
+
53
+ ### Added
54
+
55
+ **Core Commands:**
56
+ - `voodocs init` - Initialize VooDocs in a project with interactive prompts
57
+ - `voodocs instruct` - Generate AI assistant instructions for 5 major AI coding assistants (Cursor, Claude Code, GitHub Copilot, Cody, Windsurf)
58
+ - `voodocs generate` - Generate documentation, tests, and API specs from @voodocs annotations
59
+ - `voodocs status` - Show project statistics and annotation coverage
60
+ - `voodocs watch` - Watch files and automatically regenerate documentation
61
+ - `voodocs validate` - Validate @voodocs annotations for correctness
62
+ - `voodocs check` - Check annotation coverage and quality
63
+ - `voodocs export` - Export documentation to HTML or PDF
64
+ - `voodocs telemetry` - Control anonymous telemetry (enable/disable/status)
65
+
66
+ **Documentation Generation:**
67
+ - Mathematical notation translation (LaTeX → human-readable)
68
+ - Support for Python and TypeScript
69
+ - Multi-language output (English, Spanish, French, German, Chinese, Japanese)
70
+ - Markdown output with proper formatting
71
+ - Code examples and usage documentation
72
+
73
+ **Test Generation:**
74
+ - Property-based testing using Hypothesis (Python)
75
+ - Automatic test case generation from @voodocs annotations
76
+ - Support for pytest, unittest, and jest frameworks
77
+ - Edge case detection and testing
78
+
79
+ **API Specification:**
80
+ - OpenAPI 3.0 spec generation
81
+ - Swagger 2.0 support
82
+ - GraphQL schema generation
83
+ - Automatic endpoint documentation
84
+
85
+ **Quality Tools:**
86
+ - Annotation validation with detailed error messages
87
+ - Coverage checking and reporting
88
+ - Best practices recommendations
89
+ - CI/CD integration templates (GitHub Actions, GitLab CI, pre-commit hooks)
90
+
91
+ **Export Capabilities:**
92
+ - HTML export with responsive design
93
+ - PDF export with professional formatting
94
+ - Customizable templates
95
+
96
+ **Telemetry & Privacy:**
97
+ - Anonymous usage analytics with Supabase backend
98
+ - Privacy-respecting data collection (no PII)
99
+ - Easy opt-out mechanism
100
+ - GDPR compliant
101
+ - 90-day data retention policy
102
+ - Transparent privacy policy (PRIVACY.md)
103
+
104
+ **Configuration:**
105
+ - Project-level configuration via `.voodocs/config.json`
106
+ - Customizable output directories
107
+ - Language selection
108
+ - Test framework preferences
109
+ - API format preferences
110
+ - Exclude/include patterns
111
+
112
+ **Developer Experience:**
113
+ - Interactive CLI with prompts
114
+ - Comprehensive error messages
115
+ - Detailed usage documentation (USAGE.md)
116
+ - Example projects and templates
117
+ - Fast execution (optimized performance)
118
+
119
+ ### Technical Details
120
+
121
+ **Package:**
122
+ - Size: 169.6 kB (compressed)
123
+ - Unpacked size: 616.1 kB
124
+ - Total files: 70
125
+ - Zero dependencies (standalone)
126
+
127
+ **Supported Languages:**
128
+ - Python (≥3.7)
129
+ - TypeScript (via compiled parser)
130
+ - JavaScript (via TypeScript parser)
131
+
132
+ **Supported Platforms:**
133
+ - Linux
134
+ - macOS
135
+ - Windows
136
+
137
+ **Requirements:**
138
+ - Node.js ≥16.0.0
139
+ - Python ≥3.7.0
140
+
141
+ ### Architecture
142
+
143
+ **DarkArts Language:**
144
+ - Mathematical notation for AI-readable specifications
145
+ - @voodocs annotation syntax
146
+ - LaTeX-style mathematical expressions
147
+ - First-order logic support
148
+ - Set theory notation
149
+
150
+ **Plugin System:**
151
+ - Extensible architecture
152
+ - Custom generator support
153
+ - Custom validator support
154
+ - Custom exporter support
155
+
156
+ **Parsers:**
157
+ - Python AST parser
158
+ - TypeScript/JavaScript parser (compiled)
159
+ - Annotation extraction and validation
160
+
161
+ ### Known Limitations
162
+
163
+ - TypeScript parser requires npm postinstall step
164
+ - PDF export requires WeasyPrint (Python dependency)
165
+ - Windows support not extensively tested
166
+ - Limited to Python and TypeScript in v0.1.0
167
+
168
+ ### Security
169
+
170
+ - No sensitive data collected
171
+ - Anonymous session IDs only
172
+ - Supabase anon key embedded (safe for public use)
173
+ - No code or file content transmitted
174
+ - No personal information collected
175
+
176
+ ### Documentation
177
+
178
+ - README.md - Project overview and quick start
179
+ - USAGE.md - Comprehensive user guide (350+ lines)
180
+ - PRIVACY.md - Telemetry and privacy policy
181
+ - NPM_PUBLISH_GUIDE.md - Publishing instructions
182
+ - TELEMETRY_*.md - Telemetry implementation details
183
+
184
+ ### Links
185
+
186
+ - npm: https://www.npmjs.com/package/@voodocs/cli
187
+ - GitHub: https://github.com/3vilEnterprises/vooodooo-magic/tree/main/packages/voodocs
188
+ - Issues: https://github.com/3vilEnterprises/vooodooo-magic/issues
189
+ - Homepage: https://voodocs.com
190
+
191
+ ---
192
+
193
+ ## [Unreleased]
194
+
195
+ ### Planned for v0.2.0
196
+ - Additional language support (Java, Go, Rust)
197
+ - Web dashboard for analytics
198
+ - Team collaboration features
199
+ - Custom template support
200
+ - Plugin marketplace
201
+ - Performance optimizations
202
+
203
+ ---
204
+
205
+ **Note:** This is a free beta release. Telemetry helps us understand usage patterns and prioritize features. You can disable telemetry at any time with `voodocs telemetry disable`.
package/PRIVACY.md ADDED
@@ -0,0 +1,83 @@
1
+ # VooDocs Privacy Policy
2
+
3
+ **Last updated:** 2025-12-19
4
+
5
+ This Privacy Policy explains how VooDocs collects, uses, and discloses information about you. This policy applies when you use the VooDocs command-line interface (CLI) and its related services.
6
+
7
+ ## 1. Information We Collect
8
+
9
+ VooDocs is designed with privacy as a core principle. We collect minimal, anonymous information to help us improve the product and understand how it is used.
10
+
11
+ ### Anonymous Telemetry
12
+
13
+ By default, VooDocs collects anonymous telemetry data about CLI usage. This data is not linked to your identity and does not include any personal information or code content.
14
+
15
+ We collect the following anonymous data:
16
+
17
+ - **Command Usage**: Which VooDocs commands are executed (e.g., `init`, `generate`).
18
+ - **Success/Failure Rates**: Whether commands succeed or fail.
19
+ - **Performance Metrics**: Command execution duration.
20
+ - **Error Information**: The type of error if a command fails (e.g., `ParserError`).
21
+ - **Project Metadata**: The programming language of the project (e.g., `python`, `typescript`).
22
+ - **Usage Statistics**: Number of files processed, number of annotations found.
23
+ - **Environment Information**: Operating system, VooDocs version, Python version, Node.js version.
24
+ - **Anonymous Session ID**: A randomly generated UUID to group events from a single CLI session. This ID is not tied to you or your machine and resets periodically.
25
+
26
+ ### What We DO NOT Collect
27
+
28
+ We are developers ourselves and we respect your privacy. VooDocs **never** collects:
29
+
30
+ - **Personally Identifiable Information (PII)**: Your name, email, IP address, or any other personal data.
31
+ - **Code or Source Files**: The content of your source code, annotations, or generated documentation.
32
+ - **File Names or Paths**: The names or paths of your files or directories.
33
+ - **Git Information**: Your git remote, email, or user name.
34
+ - **Machine Information**: Your machine name, MAC address, or other hardware identifiers.
35
+
36
+ ## 2. How We Use Information
37
+
38
+ We use the anonymous telemetry data we collect to:
39
+
40
+ - **Improve VooDocs**: Understand which features are most popular and where users encounter problems.
41
+ - **Enhance Performance**: Identify and fix performance bottlenecks.
42
+ - **Prioritize Features**: Make data-driven decisions about what to build next.
43
+ - **Track Adoption**: Measure the overall growth and adoption of VooDocs.
44
+
45
+ ## 3. Data Storage and Security
46
+
47
+ - **Data Storage**: Anonymous telemetry data is stored in a secure Supabase database.
48
+ - **Data Retention**: We retain anonymous telemetry data for a maximum of 90 days.
49
+ - **Access Control**: Access to the telemetry data is strictly limited to authorized VooDocs personnel.
50
+
51
+ ## 4. Your Choices
52
+
53
+ ### Opting Out of Telemetry
54
+
55
+ Telemetry is enabled by default to help us improve the product. You can disable it at any time by running:
56
+
57
+ ```bash
58
+ voodocs telemetry disable
59
+ ```
60
+
61
+ You can also disable it by setting the following environment variable:
62
+
63
+ ```bash
64
+ export VOODOCS_TELEMETRY_DISABLED=1
65
+ ```
66
+
67
+ ### Viewing Telemetry Status
68
+
69
+ To check if telemetry is enabled and view your anonymous session ID, run:
70
+
71
+ ```bash
72
+ voodocs telemetry status
73
+ ```
74
+
75
+ ## 5. Changes to This Policy
76
+
77
+ We may update this Privacy Policy from time to time. If we make material changes, we will notify you by updating the date at the top of the policy and, in some cases, we may provide additional notice (such as by displaying a prominent notice in the CLI).
78
+
79
+ ## 6. Contact Us
80
+
81
+ If you have any questions about this Privacy Policy, please open an issue on our GitHub repository:
82
+
83
+ [https://github.com/3vilEnterprises/vooodooo-magic/issues](https://github.com/3vilEnterprises/vooodooo-magic/issues)
package/README.md CHANGED
@@ -1,16 +1,16 @@
1
- # VooDocs - AI-Native Documentation System
1
+ # Voodocs - AI-Native Documentation System
2
2
 
3
3
  [![NPM Version](https://img.shields.io/npm/v/@voodocs/cli.svg)](https://www.npmjs.com/package/@voodocs/cli)
4
4
  [![License](https://img.shields.io/npm/l/@voodocs/cli.svg)](https://voodocs.com/terms)
5
5
  [![Support](https://img.shields.io/badge/support-priority-blue.svg)](https://voodocs.com/support)
6
6
 
7
- **VooDocs** is a revolutionary AI-native documentation system that transforms how software is documented, tested, and specified. It teaches AI coding assistants (like Cursor and Claude Code) to write precise, machine-readable specifications in `@voodocs` annotations using the **DarkArtsAI language** - the mathematical and logical notation that AI naturally understands. These annotations are then automatically translated into human-readable documentation, automated tests, and API specifications.
7
+ **Voodocs** is a revolutionary AI-native documentation system that transforms how software is documented, tested, and specified. It teaches AI coding assistants (like Cursor and Claude Code) to write precise, machine-readable specifications in `@voodocs` annotations using the **DarkArtsAI language** - the mathematical and logical notation that AI naturally understands. These annotations are then automatically translated into human-readable documentation, automated tests, and API specifications.
8
8
 
9
- This is the future of software development: **AI documents your code in its native language, VooDocs translates it for humans.**
9
+ This is the future of software development: **AI documents your code in its native language, Voodocs translates it for humans.**
10
10
 
11
11
  ## How It Works
12
12
 
13
- 1. **Install**: Add VooDocs to your project with `npm install -g @voodocs/cli`
13
+ 1. **Install**: Add Voodocs to your project with `npm install -g @voodocs/cli`
14
14
  2. **Instruct**: Run `voodocs instruct` to generate AI instructions for your coding assistant
15
15
  3. **Code**: Your AI assistant (Cursor, Claude Code, etc.) automatically adds `@voodocs` annotations as it writes code
16
16
  4. **Generate**: Run `voodocs generate` to produce:
@@ -30,7 +30,7 @@ npm install -g @voodocs/cli
30
30
 
31
31
  ### 2. Initialize Your Project
32
32
 
33
- Navigate to your project directory and initialize VooDocs:
33
+ Navigate to your project directory and initialize Voodocs:
34
34
 
35
35
  ```bash
36
36
  voodocs init
@@ -99,7 +99,7 @@ Voodocs uses the **DarkArts language** - a mathematical and logical notation sys
99
99
  - **Declarative relationships**: What IS, not what to DO
100
100
  - **Conditional reasoning**: Case-based specifications
101
101
 
102
- VooDocs then translates this precise, machine-readable format into natural language documentation that humans can easily understand.
102
+ Voodocs then translates this precise, machine-readable format into natural language documentation that humans can easily understand.
103
103
 
104
104
  ## Why Voodocs?
105
105
 
package/USAGE.md CHANGED
@@ -247,7 +247,7 @@ function myFunction(x: number): number {
247
247
  | `assumptions` | Assumptions made by the module. |
248
248
  | `preconditions` | Conditions that must be true before a function is called. |
249
249
  | `postconditions` | Conditions that must be true after a function returns. |
250
- | `invariants` | Conditions that must always be true for a class. |
250
+ | `invariants` | Properties that remain unchanged throughout execution. For functions: conditions that hold during execution. For classes: use `class_invariants` for object state constraints. |
251
251
  | `complexity` | Time and space complexity of an algorithm. |
252
252
  | `error_cases` | How the function behaves in error scenarios. |
253
253
  | `security_model` | Security implications and threat model. |
@@ -268,7 +268,57 @@ The DarkArts language is a formal notation used in annotations. It includes:
268
268
 
269
269
  ## Examples
270
270
 
271
- See the `examples/` directory for complete examples in Python and TypeScript.
271
+ ### Function with Invariants
272
+
273
+ **Python**:
274
+ ```python
275
+ def transfer_funds(from_account, to_account, amount):
276
+ """@voodocs
277
+ preconditions: [
278
+ "from_account.balance >= amount",
279
+ "amount > 0",
280
+ "from_account != to_account"
281
+ ]
282
+ postconditions: [
283
+ "from_account.balance = from_account.balance₀ - amount",
284
+ "to_account.balance = to_account.balance₀ + amount"
285
+ ]
286
+ invariants: [
287
+ "total_balance = from_account.balance + to_account.balance (conservation)",
288
+ "from_account.balance >= 0",
289
+ "to_account.balance >= 0"
290
+ ]
291
+ complexity: "O(1)"
292
+ """
293
+ from_account.balance -= amount
294
+ to_account.balance += amount
295
+ ```
296
+
297
+ ### Class with Invariants
298
+
299
+ **Python**:
300
+ ```python
301
+ class BankAccount:
302
+ """@voodocs
303
+ class_invariants: [
304
+ "balance >= 0 (no overdrafts)",
305
+ "account_id is unique and immutable"
306
+ ]
307
+ """
308
+
309
+ def deposit(self, amount):
310
+ """@voodocs
311
+ preconditions: ["amount > 0"]
312
+ postconditions: ["self.balance = self.balance₀ + amount"]
313
+ invariants: [
314
+ "self.balance >= 0 (class invariant maintained)",
315
+ "self.account_id unchanged"
316
+ ]
317
+ """
318
+ self.balance += amount
319
+ ```
320
+
321
+ See the `examples/` directory for more complete examples in Python and TypeScript.
272
322
 
273
323
  ---
274
324
 
package/cli.py CHANGED
@@ -17,10 +17,27 @@ import time
17
17
  from pathlib import Path
18
18
  from functools import wraps
19
19
 
20
- # Add lib to path (resolve symlinks for npm bin)
20
+ # Add lib to path (resolve symlinks for npm/pnpm bin)
21
21
  import os
22
- script_path = Path(os.path.realpath(__file__)).parent
23
- sys.path.insert(0, str(script_path / "lib"))
22
+
23
+ # Get the directory containing this script
24
+ # Handle both direct execution and symlinked execution (npm/pnpm global install)
25
+ script_path = Path(__file__)
26
+ if script_path.is_symlink():
27
+ # Follow the symlink to get the actual package location
28
+ script_path = Path(os.readlink(script_path))
29
+ if not script_path.is_absolute():
30
+ # Relative symlink - resolve relative to the symlink's directory
31
+ script_path = (Path(__file__).parent / script_path).resolve()
32
+ else:
33
+ # Not a symlink - use realpath to resolve any relative paths
34
+ script_path = Path(os.path.realpath(__file__))
35
+
36
+ # Get the package root directory (where cli.py and lib/ are located)
37
+ package_root = script_path.parent
38
+
39
+ # Add lib directory to Python path
40
+ sys.path.insert(0, str(package_root / "lib"))
24
41
 
25
42
  from darkarts.plugins.voodocs.instruction_generator import InstructionGenerator
26
43
  from darkarts.plugins.voodocs.documentation_generator import DocumentationGenerator
@@ -120,7 +137,7 @@ Documentation: https://github.com/3vilEnterprises/vooodooo-magic/tree/main/packa
120
137
  parser.add_argument(
121
138
  "--version",
122
139
  action="version",
123
- version="VooDocs 0.1.0"
140
+ version="VooDocs 0.1.2"
124
141
  )
125
142
 
126
143
  subparsers = parser.add_subparsers(dest="command", help="Available commands")
@@ -418,7 +435,7 @@ def cmd_init(args):
418
435
  config = {
419
436
  "project_name": project_name,
420
437
  "language": language,
421
- "version": "0.1.0",
438
+ "version": "0.1.2",
422
439
  "output_dir": "./voodocs-output",
423
440
  "test_framework": "pytest",
424
441
  "api_format": "openapi",
@@ -0,0 +1,134 @@
1
+ """
2
+ Example demonstrating function-level invariants in VooDocs.
3
+
4
+ This file shows how to use invariants at the function level to document
5
+ properties that must hold throughout the function's execution.
6
+ """
7
+
8
+
9
+ def transfer_funds(from_account, to_account, amount):
10
+ """@voodocs
11
+ preconditions: [
12
+ "from_account.balance >= amount",
13
+ "amount > 0",
14
+ "from_account != to_account"
15
+ ]
16
+ postconditions: [
17
+ "from_account.balance = from_account.balance₀ - amount",
18
+ "to_account.balance = to_account.balance₀ + amount",
19
+ "total_balance = from_account.balance + to_account.balance = total_balance₀"
20
+ ]
21
+ invariants: [
22
+ "total_balance = from_account.balance + to_account.balance (conservation of funds)",
23
+ "from_account.balance >= 0 (no negative balances)",
24
+ "to_account.balance >= 0 (no negative balances)",
25
+ "amount remains constant throughout execution"
26
+ ]
27
+ side_effects: [
28
+ "Modifies from_account.balance",
29
+ "Modifies to_account.balance",
30
+ "Logs transaction to audit trail"
31
+ ]
32
+ complexity: "O(1)"
33
+ """
34
+ # Verify preconditions
35
+ if from_account.balance < amount:
36
+ raise ValueError("Insufficient funds")
37
+ if amount <= 0:
38
+ raise ValueError("Amount must be positive")
39
+ if from_account == to_account:
40
+ raise ValueError("Cannot transfer to same account")
41
+
42
+ # Perform transfer (invariants hold throughout)
43
+ from_account.balance -= amount
44
+ to_account.balance += amount
45
+
46
+ # Log transaction
47
+ print(f"Transferred {amount} from {from_account.id} to {to_account.id}")
48
+
49
+
50
+ def binary_search(arr, target):
51
+ """@voodocs
52
+ preconditions: [
53
+ "arr is sorted in ascending order",
54
+ "∀ i, j: 0 ≤ i < j < len(arr) ⇒ arr[i] ≤ arr[j]"
55
+ ]
56
+ postconditions: [
57
+ "result ≥ 0 ⇒ arr[result] = target",
58
+ "result = -1 ⇒ target ∉ arr"
59
+ ]
60
+ invariants: [
61
+ "0 ≤ left ≤ right < len(arr) (search bounds)",
62
+ "target ∈ arr ⇒ target ∈ arr[left:right+1] (target in search range)",
63
+ "arr remains unchanged (no side effects on input)"
64
+ ]
65
+ complexity: "O(log n) where n = len(arr)"
66
+ """
67
+ left, right = 0, len(arr) - 1
68
+
69
+ while left <= right:
70
+ mid = (left + right) // 2
71
+
72
+ if arr[mid] == target:
73
+ return mid
74
+ elif arr[mid] < target:
75
+ left = mid + 1
76
+ else:
77
+ right = mid - 1
78
+
79
+ return -1
80
+
81
+
82
+ class BankAccount:
83
+ """@voodocs
84
+ class_invariants: [
85
+ "balance >= 0 (no overdrafts)",
86
+ "account_id is unique and immutable",
87
+ "len(transaction_history) >= 0"
88
+ ]
89
+ """
90
+
91
+ def __init__(self, account_id, initial_balance=0):
92
+ """@voodocs
93
+ preconditions: [
94
+ "initial_balance >= 0",
95
+ "account_id is not None"
96
+ ]
97
+ postconditions: [
98
+ "self.balance = initial_balance",
99
+ "self.account_id = account_id",
100
+ "len(self.transaction_history) = 0"
101
+ ]
102
+ invariants: [
103
+ "self.balance >= 0 (established at initialization)"
104
+ ]
105
+ """
106
+ self.account_id = account_id
107
+ self.balance = initial_balance
108
+ self.transaction_history = []
109
+
110
+ def deposit(self, amount):
111
+ """@voodocs
112
+ preconditions: [
113
+ "amount > 0"
114
+ ]
115
+ postconditions: [
116
+ "self.balance = self.balance₀ + amount",
117
+ "len(self.transaction_history) = len(self.transaction_history₀) + 1"
118
+ ]
119
+ invariants: [
120
+ "self.balance >= 0 (class invariant maintained)",
121
+ "amount remains constant",
122
+ "self.account_id unchanged"
123
+ ]
124
+ side_effects: [
125
+ "Modifies self.balance",
126
+ "Appends to self.transaction_history"
127
+ ]
128
+ complexity: "O(1)"
129
+ """
130
+ if amount <= 0:
131
+ raise ValueError("Deposit amount must be positive")
132
+
133
+ self.balance += amount
134
+ self.transaction_history.append(("deposit", amount))
@@ -567,7 +567,7 @@ class DocumentationGenerator:
567
567
 
568
568
  # Documentation coverage badge
569
569
  total_items = len(parsed.module.classes) + len(parsed.get_all_functions())
570
- annotated_items = sum(1 for _ in parsed.module.classes if _.invariants or _.state_transitions)
570
+ annotated_items = sum(1 for _ in parsed.module.classes if _.class_invariants or _.state_transitions)
571
571
  annotated_items += sum(1 for f in parsed.get_all_functions() if f.preconditions or f.postconditions)
572
572
 
573
573
  if total_items > 0:
@@ -0,0 +1,206 @@
1
+ """
2
+ VooDocs Telemetry Client
3
+
4
+ Privacy-respecting anonymous telemetry for usage analytics.
5
+ """
6
+
7
+ import os
8
+ import sys
9
+ import json
10
+ import uuid
11
+ import platform
12
+ from datetime import datetime
13
+ from pathlib import Path
14
+ from typing import Dict, Any, Optional
15
+ import urllib.request
16
+ import urllib.error
17
+
18
+ # Supabase configuration
19
+ SUPABASE_URL = os.getenv("VOODOCS_SUPABASE_URL", "https://sjatkayudkbkmipubhfy.supabase.co")
20
+ SUPABASE_ANON_KEY = os.getenv("VOODOCS_SUPABASE_ANON_KEY", "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InNqYXRrYXl1ZGtia21pcHViaGZ5Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3NjYxNjE0MTMsImV4cCI6MjA4MTczNzQxM30.Wj3dbokjKPsmWTgbPw77aPnCoZCsE5hrFfIH-R_ErzI")
21
+
22
+ # VooDocs version
23
+ VERSION = "0.1.2"
24
+
25
+ class TelemetryClient:
26
+ """Anonymous telemetry client for VooDocs CLI."""
27
+
28
+ def __init__(self):
29
+ self.session_id = self._get_or_create_session_id()
30
+ self.enabled = self._check_if_enabled()
31
+ self.config_dir = Path.home() / ".voodocs"
32
+ self.config_file = self.config_dir / "telemetry.json"
33
+
34
+ def _get_or_create_session_id(self) -> str:
35
+ """Get or create a random session ID."""
36
+ config_dir = Path.home() / ".voodocs"
37
+ session_file = config_dir / "session_id"
38
+
39
+ if session_file.exists():
40
+ try:
41
+ return session_file.read_text().strip()
42
+ except:
43
+ pass
44
+
45
+ # Create new session ID
46
+ session_id = str(uuid.uuid4())
47
+ try:
48
+ config_dir.mkdir(parents=True, exist_ok=True)
49
+ session_file.write_text(session_id)
50
+ except:
51
+ pass # Fail silently if can't write
52
+
53
+ return session_id
54
+
55
+ def _check_if_enabled(self) -> bool:
56
+ """Check if telemetry is enabled."""
57
+ # Check environment variable
58
+ if os.getenv("VOODOCS_TELEMETRY_DISABLED") == "1":
59
+ return False
60
+
61
+ # Check config file
62
+ config_dir = Path.home() / ".voodocs"
63
+ config_file = config_dir / "telemetry.json"
64
+
65
+ if config_file.exists():
66
+ try:
67
+ config = json.loads(config_file.read_text())
68
+ return config.get("enabled", True)
69
+ except:
70
+ pass
71
+
72
+ return True # Enabled by default
73
+
74
+ def _show_first_run_notice(self):
75
+ """Show telemetry notice on first run."""
76
+ notice_file = self.config_dir / ".telemetry_notice_shown"
77
+
78
+ if not notice_file.exists():
79
+ print("\n" + "="*70)
80
+ print("📊 VooDocs Telemetry")
81
+ print("="*70)
82
+ print("VooDocs collects anonymous usage data to improve the product.")
83
+ print("No personal information is collected.")
84
+ print()
85
+ print("To disable telemetry:")
86
+ print(" voodocs telemetry disable")
87
+ print()
88
+ print("Learn more: https://voodocs.com/privacy")
89
+ print("="*70 + "\n")
90
+
91
+ try:
92
+ self.config_dir.mkdir(parents=True, exist_ok=True)
93
+ notice_file.touch()
94
+ except:
95
+ pass # Fail silently
96
+
97
+ def track_event(self, event_type: str, data: Optional[Dict[str, Any]] = None):
98
+ """
99
+ Track a telemetry event.
100
+
101
+ Args:
102
+ event_type: Type of event (command_executed, etc.)
103
+ data: Additional event data
104
+ """
105
+ if not self.enabled:
106
+ return
107
+
108
+ if not SUPABASE_URL or not SUPABASE_ANON_KEY:
109
+ return # Silently skip if not configured
110
+
111
+ # Show first-run notice
112
+ if event_type == "command_executed":
113
+ self._show_first_run_notice()
114
+
115
+ event = {
116
+ "event_type": event_type,
117
+ "session_id": self.session_id,
118
+ "version": VERSION,
119
+ "platform": platform.system().lower(),
120
+ "python_version": f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}",
121
+ **(data or {})
122
+ }
123
+
124
+ # Send synchronously with short timeout (CLI-friendly)
125
+ self._send_event_sync(event)
126
+
127
+ def _send_event_sync(self, event: Dict[str, Any]):
128
+ """Send event to Supabase synchronously with timeout."""
129
+ try:
130
+ url = f"{SUPABASE_URL}/rest/v1/telemetry_events"
131
+ headers = {
132
+ "apikey": SUPABASE_ANON_KEY,
133
+ "Authorization": f"Bearer {SUPABASE_ANON_KEY}",
134
+ "Content-Type": "application/json",
135
+ "Prefer": "return=minimal"
136
+ }
137
+
138
+ data = json.dumps(event).encode("utf-8")
139
+ req = urllib.request.Request(url, data=data, headers=headers, method="POST")
140
+
141
+ # Short timeout - fail fast if network issue
142
+ urllib.request.urlopen(req, timeout=2)
143
+ except:
144
+ pass # Fail silently - telemetry should never break the CLI
145
+
146
+ def enable(self):
147
+ """Enable telemetry."""
148
+ try:
149
+ self.config_dir.mkdir(parents=True, exist_ok=True)
150
+ config = {"enabled": True}
151
+ self.config_file.write_text(json.dumps(config, indent=2))
152
+ self.enabled = True
153
+ print("✓ Telemetry enabled")
154
+ except Exception as e:
155
+ print(f"✗ Failed to enable telemetry: {e}")
156
+
157
+ def disable(self):
158
+ """Disable telemetry."""
159
+ try:
160
+ self.config_dir.mkdir(parents=True, exist_ok=True)
161
+ config = {"enabled": False}
162
+ self.config_file.write_text(json.dumps(config, indent=2))
163
+ self.enabled = False
164
+ print("✓ Telemetry disabled")
165
+ except Exception as e:
166
+ print(f"✗ Failed to disable telemetry: {e}")
167
+
168
+ def status(self):
169
+ """Show telemetry status."""
170
+ status = "enabled" if self.enabled else "disabled"
171
+ print(f"Telemetry: {status}")
172
+ print(f"Session ID: {self.session_id}")
173
+
174
+ if self.enabled:
175
+ print("\nTo disable: voodocs telemetry disable")
176
+ else:
177
+ print("\nTo enable: voodocs telemetry enable")
178
+
179
+
180
+ # Global telemetry client instance
181
+ _telemetry_client: Optional[TelemetryClient] = None
182
+
183
+ def get_telemetry_client() -> TelemetryClient:
184
+ """Get the global telemetry client instance."""
185
+ global _telemetry_client
186
+ if _telemetry_client is None:
187
+ _telemetry_client = TelemetryClient()
188
+ return _telemetry_client
189
+
190
+ def track_command(command: str, success: bool, duration_ms: int, **kwargs):
191
+ """
192
+ Track a command execution.
193
+
194
+ Args:
195
+ command: Command name (init, generate, etc.)
196
+ success: Whether command succeeded
197
+ duration_ms: Command duration in milliseconds
198
+ **kwargs: Additional event data
199
+ """
200
+ client = get_telemetry_client()
201
+ client.track_event("command_executed", {
202
+ "command": command,
203
+ "success": success,
204
+ "duration_ms": duration_ms,
205
+ **kwargs
206
+ })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voodocs/cli",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "AI-Native Documentation System - Generate docs, tests, and API specs from @voodocs annotations using the DarkArts language",
5
5
  "main": "cli.py",
6
6
  "bin": {
@@ -48,6 +48,7 @@
48
48
  "lib/darkarts/annotations/",
49
49
  "lib/darkarts/core/",
50
50
  "lib/darkarts/exceptions.py",
51
+ "lib/darkarts/telemetry.py",
51
52
  "lib/darkarts/parsers/typescript/dist/",
52
53
  "lib/darkarts/parsers/typescript/src/",
53
54
  "lib/darkarts/parsers/typescript/package.json",
@@ -60,6 +61,8 @@
60
61
  "README.md",
61
62
  "LICENSE",
62
63
  "USAGE.md",
64
+ "PRIVACY.md",
65
+ "CHANGELOG.md",
63
66
  "requirements.txt"
64
67
  ],
65
68
  "os": [