@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 +205 -0
- package/PRIVACY.md +83 -0
- package/README.md +6 -6
- package/USAGE.md +52 -2
- package/cli.py +22 -5
- package/examples/test_function_invariants.py +134 -0
- package/lib/darkarts/plugins/voodocs/documentation_generator.py +1 -1
- package/lib/darkarts/telemetry.py +206 -0
- package/package.json +4 -1
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
|
-
#
|
|
1
|
+
# Voodocs - AI-Native Documentation System
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@voodocs/cli)
|
|
4
4
|
[](https://voodocs.com/terms)
|
|
5
5
|
[](https://voodocs.com/support)
|
|
6
6
|
|
|
7
|
-
**
|
|
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,
|
|
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
|
|
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
|
|
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
|
-
|
|
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` |
|
|
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
|
-
|
|
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
|
-
|
|
23
|
-
|
|
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.
|
|
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.
|
|
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 _.
|
|
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.
|
|
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": [
|