vibesafex 0.3.0__tar.gz

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.
Files changed (42) hide show
  1. vibesafex-0.3.0/.github/workflows/ci.yml +27 -0
  2. vibesafex-0.3.0/.gitignore +7 -0
  3. vibesafex-0.3.0/.pre-commit-hooks.yaml +15 -0
  4. vibesafex-0.3.0/CHANGELOG.md +24 -0
  5. vibesafex-0.3.0/LICENSE +15 -0
  6. vibesafex-0.3.0/PKG-INFO +175 -0
  7. vibesafex-0.3.0/README.md +150 -0
  8. vibesafex-0.3.0/action.yml +48 -0
  9. vibesafex-0.3.0/assets/checks_overview.svg +114 -0
  10. vibesafex-0.3.0/assets/scan_report.svg +132 -0
  11. vibesafex-0.3.0/examples/auto_fix.py +65 -0
  12. vibesafex-0.3.0/examples/ci_integration.py +75 -0
  13. vibesafex-0.3.0/examples/scan_project.py +58 -0
  14. vibesafex-0.3.0/examples/with_injectionguard.py +90 -0
  15. vibesafex-0.3.0/pyproject.toml +44 -0
  16. vibesafex-0.3.0/scripts/generate_assets.py +65 -0
  17. vibesafex-0.3.0/src/vibesafex/__init__.py +21 -0
  18. vibesafex-0.3.0/src/vibesafex/checks/__init__.py +1 -0
  19. vibesafex-0.3.0/src/vibesafex/checks/dead_code.py +124 -0
  20. vibesafex-0.3.0/src/vibesafex/checks/imports.py +130 -0
  21. vibesafex-0.3.0/src/vibesafex/checks/patterns.py +121 -0
  22. vibesafex-0.3.0/src/vibesafex/checks/secrets.py +53 -0
  23. vibesafex-0.3.0/src/vibesafex/checks/security.py +160 -0
  24. vibesafex-0.3.0/src/vibesafex/cli.py +198 -0
  25. vibesafex-0.3.0/src/vibesafex/complexity.py +268 -0
  26. vibesafex-0.3.0/src/vibesafex/fixer.py +210 -0
  27. vibesafex-0.3.0/src/vibesafex/mcp.py +175 -0
  28. vibesafex-0.3.0/src/vibesafex/py.typed +0 -0
  29. vibesafex-0.3.0/src/vibesafex/sarif.py +169 -0
  30. vibesafex-0.3.0/src/vibesafex/scanner.py +182 -0
  31. vibesafex-0.3.0/tests/test_cli.py +83 -0
  32. vibesafex-0.3.0/tests/test_complexity.py +202 -0
  33. vibesafex-0.3.0/tests/test_dead_code.py +66 -0
  34. vibesafex-0.3.0/tests/test_edge_cases.py +111 -0
  35. vibesafex-0.3.0/tests/test_fixer.py +202 -0
  36. vibesafex-0.3.0/tests/test_imports.py +40 -0
  37. vibesafex-0.3.0/tests/test_mcp.py +158 -0
  38. vibesafex-0.3.0/tests/test_patterns.py +91 -0
  39. vibesafex-0.3.0/tests/test_sarif.py +188 -0
  40. vibesafex-0.3.0/tests/test_scanner.py +131 -0
  41. vibesafex-0.3.0/tests/test_secrets.py +74 -0
  42. vibesafex-0.3.0/tests/test_security.py +96 -0
@@ -0,0 +1,27 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ matrix:
14
+ python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
15
+
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+ - name: Set up Python ${{ matrix.python-version }}
19
+ uses: actions/setup-python@v5
20
+ with:
21
+ python-version: ${{ matrix.python-version }}
22
+ - name: Install
23
+ run: pip install -e ".[dev]" 2>/dev/null || pip install -e .
24
+ - name: Install test deps
25
+ run: pip install pytest
26
+ - name: Test
27
+ run: pytest tests/ -v
@@ -0,0 +1,7 @@
1
+ __pycache__/
2
+ *.pyc
3
+ *.egg-info/
4
+ dist/
5
+ build/
6
+ .pytest_cache/
7
+ .mypy_cache/
@@ -0,0 +1,15 @@
1
+ - id: vibesafe
2
+ name: vibesafe
3
+ description: Scan AI-generated Python code for security issues and anti-patterns
4
+ entry: vibesafe scan --fail-on error
5
+ language: python
6
+ types: [python]
7
+ require_serial: false
8
+
9
+ - id: vibesafe-fix
10
+ name: vibesafe-fix
11
+ description: Auto-fix common issues in AI-generated Python code
12
+ entry: vibesafe fix
13
+ language: python
14
+ types: [python]
15
+ require_serial: true
@@ -0,0 +1,24 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [0.3.0] - 2025-04-10
9
+
10
+ ### Added
11
+ - Add code complexity analysis via `complexity.py`
12
+ - Add SARIF output format support in `sarif.py`
13
+
14
+ ## [0.2.0] - 2026-04-10
15
+
16
+ ### Added
17
+ - Add MCP server for IDE integration
18
+ - Add --fix auto-fixer, pre-commit hooks, and GitHub Action
19
+
20
+ ## [0.1.0] - 2026-04-10
21
+
22
+ ### Added
23
+ - Initial release: AI-generated code safety scanner
24
+
@@ -0,0 +1,15 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ Licensed under the Apache License, Version 2.0 (the "License");
6
+ you may not use this file except in compliance with the License.
7
+ You may obtain a copy of the License at
8
+
9
+ http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ Unless required by applicable law or agreed to in writing, software
12
+ distributed under the License is distributed on an "AS IS" BASIS,
13
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ See the License for the specific language governing permissions and
15
+ limitations under the License.
@@ -0,0 +1,175 @@
1
+ Metadata-Version: 2.4
2
+ Name: vibesafex
3
+ Version: 0.3.0
4
+ Summary: AI-generated code safety scanner for the vibe coding era
5
+ Project-URL: Homepage, https://github.com/stef41/vibesafex
6
+ Project-URL: Repository, https://github.com/stef41/vibesafex
7
+ Project-URL: Issues, https://github.com/stef41/vibesafex/issues
8
+ Author: stef41
9
+ License: Apache-2.0
10
+ License-File: LICENSE
11
+ Keywords: ai-code-review,ai-generated-code,claude-code,code-scanner,copilot,cursor,linter,llm,mcp,security,static-analysis,vibe-coding
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: Apache Software License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Topic :: Security
22
+ Classifier: Topic :: Software Development :: Quality Assurance
23
+ Requires-Python: >=3.9
24
+ Description-Content-Type: text/markdown
25
+
26
+ # vibesafex
27
+
28
+ [![CI](https://github.com/stef41/vibesafex/actions/workflows/ci.yml/badge.svg)](https://github.com/stef41/vibesafex/actions/workflows/ci.yml)
29
+ [![Python 3.9+](https://img.shields.io/badge/python-3.9+-blue.svg)](https://www.python.org/downloads/)
30
+ [![License: Apache 2.0](https://img.shields.io/badge/License-Apache%202.0-green.svg)](LICENSE)
31
+ [![PyPI](https://img.shields.io/pypi/v/vibesafex.svg)](https://pypi.org/project/vibesafex/)
32
+
33
+ **Stop shipping AI-generated code you haven't reviewed.**
34
+
35
+ vibesafex catches the bugs your AI coding agent won't tell you about: hallucinated imports, hardcoded secrets, security vulnerabilities, and dead code.
36
+
37
+ Built for the vibe coding era. Works with code from Claude Code, Cursor, Copilot, Windsurf, and any AI coding tool.
38
+
39
+ ## Quick Start
40
+
41
+ ```bash
42
+ pip install vibesafex
43
+ vibesafex scan .
44
+ ```
45
+
46
+ ## What It Catches
47
+
48
+ | Code | Category | Severity | What |
49
+ |------|----------|----------|------|
50
+ | VS100-VS110 | **Security** | error | `eval()`, `exec()`, `shell=True`, SQL injection, `os.system()`, unsafe YAML, weak hashes |
51
+ | VS200-VS210 | **Secrets** | error | OpenAI/AWS/GitHub/Anthropic/Stripe API keys, private keys, JWTs, hardcoded credentials |
52
+ | VS300 | **Imports** | warning | Hallucinated imports — packages that don't exist (AI's favorite mistake) |
53
+ | VS400-VS403 | **Dead Code** | warning | Unused imports, unreachable code, empty `except: pass`, bare except |
54
+ | VS500-VS507 | **AI Patterns** | warning | TODO/FIXME left by AI, placeholder functions, `NotImplementedError` stubs, mutable defaults, star imports |
55
+
56
+ ## Usage
57
+
58
+ ### Scan a directory
59
+ ```bash
60
+ vibesafex scan src/
61
+ ```
62
+
63
+ ### Scan specific files
64
+ ```bash
65
+ vibesafex scan main.py utils.py
66
+ ```
67
+
68
+ ### Check code from stdin
69
+ ```bash
70
+ echo 'x = eval(input())' | vibesafex check
71
+ ```
72
+
73
+ ### JSON output (for CI/CD)
74
+ ```bash
75
+ vibesafex scan . --format json
76
+ ```
77
+
78
+ ### Filter by severity
79
+ ```bash
80
+ vibesafex scan . --severity error # Only errors
81
+ vibesafex scan . --fail-on warning # Fail CI on warnings too
82
+ ```
83
+
84
+ ## Python API
85
+
86
+ ```python
87
+ from vibesafex import scan_code, scan_file, scan_directory
88
+
89
+ # Scan a string
90
+ issues = scan_code('x = eval(input())')
91
+ for issue in issues:
92
+ print(f"{issue.code}: {issue.message}")
93
+
94
+ # Scan a file
95
+ issues = scan_file("main.py")
96
+
97
+ # Scan a project
98
+ result = scan_directory("src/")
99
+ print(f"{result.error_count} errors found in {result.files_scanned} files")
100
+ ```
101
+
102
+ ### Custom scanner configuration
103
+
104
+ ```python
105
+ from vibesafex import Scanner
106
+
107
+ scanner = Scanner(
108
+ severity_threshold="warning", # Skip info-level
109
+ exclude_dirs={".venv", "migrations"},
110
+ )
111
+ result = scanner.scan_directory(".")
112
+ ```
113
+
114
+ ## Example Output
115
+
116
+ <img src="assets/scan_report.svg" alt="vibesafex scan report" width="800">
117
+ <img src="assets/checks_overview.svg" alt="vibesafex checks" width="800">
118
+
119
+ ```
120
+ ✗ main.py:5:0 [error] VS100: Use of eval() - potential code injection vulnerability
121
+ ✗ main.py:8:0 [error] VS200: Possible OpenAI API key
122
+ ⚠ main.py:12:0 [warning] VS300: Import 'magic_ai_lib' - package 'magic_ai_lib' not found (hallucinated import?)
123
+ ⚠ main.py:15:0 [warning] VS501: Function 'process' has empty body (pass) - placeholder
124
+ ℹ main.py:20:0 [info] VS500: TODO comment - AI may have left incomplete implementation
125
+
126
+ 5 files scanned: 2 errors, 2 warnings, 1 info
127
+ ```
128
+
129
+ ## Pre-commit Hook
130
+
131
+ ```yaml
132
+ # .pre-commit-config.yaml
133
+ repos:
134
+ - repo: local
135
+ hooks:
136
+ - id: vibesafex
137
+ name: vibesafex
138
+ entry: vibesafex scan --fail-on error
139
+ language: python
140
+ types: [python]
141
+ additional_dependencies: [vibesafex]
142
+ ```
143
+
144
+ ## Why Not Just Use Ruff/Pylint?
145
+
146
+ vibesafex focuses specifically on **AI-generated code patterns** that traditional linters miss:
147
+
148
+ - **Hallucinated imports**: AI confidently imports packages that don't exist. vibesafex checks against stdlib, installed packages, and 200+ known popular packages.
149
+ - **Secret leakage**: AI copies real-looking API keys into code. vibesafex detects patterns for 12+ providers.
150
+ - **Placeholder code**: AI leaves `pass`, `...`, `NotImplementedError` stubs that slip through review.
151
+ - **AI anti-patterns**: Mutable defaults, star imports, excessive `Any` — patterns AI generates more often than humans.
152
+
153
+ Use vibesafex **alongside** your existing linter, not instead of it.
154
+
155
+ ## See Also
156
+
157
+ Part of the **stef41 LLM toolkit** — open-source tools for every stage of the LLM lifecycle:
158
+
159
+ | Project | What it does |
160
+ |---------|-------------|
161
+ | [tokonomics](https://github.com/stef41/tokonomix) | Token counting & cost management for LLM APIs |
162
+ | [datacrux](https://github.com/stef41/datacruxai) | Training data quality — dedup, PII, contamination |
163
+ | [castwright](https://github.com/stef41/castwright) | Synthetic instruction data generation |
164
+ | [datamix](https://github.com/stef41/datamix) | Dataset mixing & curriculum optimization |
165
+ | [toksight](https://github.com/stef41/toksight) | Tokenizer analysis & comparison |
166
+ | [trainpulse](https://github.com/stef41/trainpulse) | Training health monitoring |
167
+ | [ckpt](https://github.com/stef41/ckptkit) | Checkpoint inspection, diffing & merging |
168
+ | [quantbench](https://github.com/stef41/quantbenchx) | Quantization quality analysis |
169
+ | [infermark](https://github.com/stef41/infermark) | Inference benchmarking |
170
+ | [modeldiff](https://github.com/stef41/modeldiffx) | Behavioral regression testing |
171
+ | [injectionguard](https://github.com/stef41/injectionguard) | Prompt injection detection |
172
+
173
+ ## License
174
+
175
+ Apache 2.0
@@ -0,0 +1,150 @@
1
+ # vibesafex
2
+
3
+ [![CI](https://github.com/stef41/vibesafex/actions/workflows/ci.yml/badge.svg)](https://github.com/stef41/vibesafex/actions/workflows/ci.yml)
4
+ [![Python 3.9+](https://img.shields.io/badge/python-3.9+-blue.svg)](https://www.python.org/downloads/)
5
+ [![License: Apache 2.0](https://img.shields.io/badge/License-Apache%202.0-green.svg)](LICENSE)
6
+ [![PyPI](https://img.shields.io/pypi/v/vibesafex.svg)](https://pypi.org/project/vibesafex/)
7
+
8
+ **Stop shipping AI-generated code you haven't reviewed.**
9
+
10
+ vibesafex catches the bugs your AI coding agent won't tell you about: hallucinated imports, hardcoded secrets, security vulnerabilities, and dead code.
11
+
12
+ Built for the vibe coding era. Works with code from Claude Code, Cursor, Copilot, Windsurf, and any AI coding tool.
13
+
14
+ ## Quick Start
15
+
16
+ ```bash
17
+ pip install vibesafex
18
+ vibesafex scan .
19
+ ```
20
+
21
+ ## What It Catches
22
+
23
+ | Code | Category | Severity | What |
24
+ |------|----------|----------|------|
25
+ | VS100-VS110 | **Security** | error | `eval()`, `exec()`, `shell=True`, SQL injection, `os.system()`, unsafe YAML, weak hashes |
26
+ | VS200-VS210 | **Secrets** | error | OpenAI/AWS/GitHub/Anthropic/Stripe API keys, private keys, JWTs, hardcoded credentials |
27
+ | VS300 | **Imports** | warning | Hallucinated imports — packages that don't exist (AI's favorite mistake) |
28
+ | VS400-VS403 | **Dead Code** | warning | Unused imports, unreachable code, empty `except: pass`, bare except |
29
+ | VS500-VS507 | **AI Patterns** | warning | TODO/FIXME left by AI, placeholder functions, `NotImplementedError` stubs, mutable defaults, star imports |
30
+
31
+ ## Usage
32
+
33
+ ### Scan a directory
34
+ ```bash
35
+ vibesafex scan src/
36
+ ```
37
+
38
+ ### Scan specific files
39
+ ```bash
40
+ vibesafex scan main.py utils.py
41
+ ```
42
+
43
+ ### Check code from stdin
44
+ ```bash
45
+ echo 'x = eval(input())' | vibesafex check
46
+ ```
47
+
48
+ ### JSON output (for CI/CD)
49
+ ```bash
50
+ vibesafex scan . --format json
51
+ ```
52
+
53
+ ### Filter by severity
54
+ ```bash
55
+ vibesafex scan . --severity error # Only errors
56
+ vibesafex scan . --fail-on warning # Fail CI on warnings too
57
+ ```
58
+
59
+ ## Python API
60
+
61
+ ```python
62
+ from vibesafex import scan_code, scan_file, scan_directory
63
+
64
+ # Scan a string
65
+ issues = scan_code('x = eval(input())')
66
+ for issue in issues:
67
+ print(f"{issue.code}: {issue.message}")
68
+
69
+ # Scan a file
70
+ issues = scan_file("main.py")
71
+
72
+ # Scan a project
73
+ result = scan_directory("src/")
74
+ print(f"{result.error_count} errors found in {result.files_scanned} files")
75
+ ```
76
+
77
+ ### Custom scanner configuration
78
+
79
+ ```python
80
+ from vibesafex import Scanner
81
+
82
+ scanner = Scanner(
83
+ severity_threshold="warning", # Skip info-level
84
+ exclude_dirs={".venv", "migrations"},
85
+ )
86
+ result = scanner.scan_directory(".")
87
+ ```
88
+
89
+ ## Example Output
90
+
91
+ <img src="assets/scan_report.svg" alt="vibesafex scan report" width="800">
92
+ <img src="assets/checks_overview.svg" alt="vibesafex checks" width="800">
93
+
94
+ ```
95
+ ✗ main.py:5:0 [error] VS100: Use of eval() - potential code injection vulnerability
96
+ ✗ main.py:8:0 [error] VS200: Possible OpenAI API key
97
+ ⚠ main.py:12:0 [warning] VS300: Import 'magic_ai_lib' - package 'magic_ai_lib' not found (hallucinated import?)
98
+ ⚠ main.py:15:0 [warning] VS501: Function 'process' has empty body (pass) - placeholder
99
+ ℹ main.py:20:0 [info] VS500: TODO comment - AI may have left incomplete implementation
100
+
101
+ 5 files scanned: 2 errors, 2 warnings, 1 info
102
+ ```
103
+
104
+ ## Pre-commit Hook
105
+
106
+ ```yaml
107
+ # .pre-commit-config.yaml
108
+ repos:
109
+ - repo: local
110
+ hooks:
111
+ - id: vibesafex
112
+ name: vibesafex
113
+ entry: vibesafex scan --fail-on error
114
+ language: python
115
+ types: [python]
116
+ additional_dependencies: [vibesafex]
117
+ ```
118
+
119
+ ## Why Not Just Use Ruff/Pylint?
120
+
121
+ vibesafex focuses specifically on **AI-generated code patterns** that traditional linters miss:
122
+
123
+ - **Hallucinated imports**: AI confidently imports packages that don't exist. vibesafex checks against stdlib, installed packages, and 200+ known popular packages.
124
+ - **Secret leakage**: AI copies real-looking API keys into code. vibesafex detects patterns for 12+ providers.
125
+ - **Placeholder code**: AI leaves `pass`, `...`, `NotImplementedError` stubs that slip through review.
126
+ - **AI anti-patterns**: Mutable defaults, star imports, excessive `Any` — patterns AI generates more often than humans.
127
+
128
+ Use vibesafex **alongside** your existing linter, not instead of it.
129
+
130
+ ## See Also
131
+
132
+ Part of the **stef41 LLM toolkit** — open-source tools for every stage of the LLM lifecycle:
133
+
134
+ | Project | What it does |
135
+ |---------|-------------|
136
+ | [tokonomics](https://github.com/stef41/tokonomix) | Token counting & cost management for LLM APIs |
137
+ | [datacrux](https://github.com/stef41/datacruxai) | Training data quality — dedup, PII, contamination |
138
+ | [castwright](https://github.com/stef41/castwright) | Synthetic instruction data generation |
139
+ | [datamix](https://github.com/stef41/datamix) | Dataset mixing & curriculum optimization |
140
+ | [toksight](https://github.com/stef41/toksight) | Tokenizer analysis & comparison |
141
+ | [trainpulse](https://github.com/stef41/trainpulse) | Training health monitoring |
142
+ | [ckpt](https://github.com/stef41/ckptkit) | Checkpoint inspection, diffing & merging |
143
+ | [quantbench](https://github.com/stef41/quantbenchx) | Quantization quality analysis |
144
+ | [infermark](https://github.com/stef41/infermark) | Inference benchmarking |
145
+ | [modeldiff](https://github.com/stef41/modeldiffx) | Behavioral regression testing |
146
+ | [injectionguard](https://github.com/stef41/injectionguard) | Prompt injection detection |
147
+
148
+ ## License
149
+
150
+ Apache 2.0
@@ -0,0 +1,48 @@
1
+ name: 'vibesafex'
2
+ description: 'Scan AI-generated Python code for security issues and anti-patterns'
3
+ branding:
4
+ icon: 'shield'
5
+ color: 'purple'
6
+
7
+ inputs:
8
+ paths:
9
+ description: 'Paths to scan (space-separated)'
10
+ required: false
11
+ default: '.'
12
+ severity:
13
+ description: 'Minimum severity to report (error, warning, info)'
14
+ required: false
15
+ default: 'info'
16
+ fail-on:
17
+ description: 'Fail if issues at this level or above are found'
18
+ required: false
19
+ default: 'error'
20
+ version:
21
+ description: 'vibesafex version to install'
22
+ required: false
23
+ default: 'latest'
24
+
25
+ runs:
26
+ using: 'composite'
27
+ steps:
28
+ - name: Set up Python
29
+ uses: actions/setup-python@v5
30
+ with:
31
+ python-version: '3.x'
32
+
33
+ - name: Install vibesafex
34
+ shell: bash
35
+ run: |
36
+ if [ "${{ inputs.version }}" = "latest" ]; then
37
+ pip install vibesafex
38
+ else
39
+ pip install "vibesafex==${{ inputs.version }}"
40
+ fi
41
+
42
+ - name: Run vibesafex
43
+ shell: bash
44
+ run: |
45
+ vibesafex scan ${{ inputs.paths }} \
46
+ --severity ${{ inputs.severity }} \
47
+ --fail-on ${{ inputs.fail-on }} \
48
+ --format text
@@ -0,0 +1,114 @@
1
+ <svg class="rich-terminal" viewBox="0 0 1055 367.2" xmlns="http://www.w3.org/2000/svg">
2
+ <!-- Generated with Rich https://www.textualize.io -->
3
+ <style>
4
+
5
+ @font-face {
6
+ font-family: "Fira Code";
7
+ src: local("FiraCode-Regular"),
8
+ url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff2/FiraCode-Regular.woff2") format("woff2"),
9
+ url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff/FiraCode-Regular.woff") format("woff");
10
+ font-style: normal;
11
+ font-weight: 400;
12
+ }
13
+ @font-face {
14
+ font-family: "Fira Code";
15
+ src: local("FiraCode-Bold"),
16
+ url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff2/FiraCode-Bold.woff2") format("woff2"),
17
+ url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff/FiraCode-Bold.woff") format("woff");
18
+ font-style: bold;
19
+ font-weight: 700;
20
+ }
21
+
22
+ .terminal-1798561328-matrix {
23
+ font-family: Fira Code, monospace;
24
+ font-size: 20px;
25
+ line-height: 24.4px;
26
+ font-variant-east-asian: full-width;
27
+ }
28
+
29
+ .terminal-1798561328-title {
30
+ font-size: 18px;
31
+ font-weight: bold;
32
+ font-family: arial;
33
+ }
34
+
35
+ .terminal-1798561328-r1 { fill: #c5c8c6;font-style: italic; }
36
+ .terminal-1798561328-r2 { fill: #c5c8c6 }
37
+ .terminal-1798561328-r3 { fill: #68a0b3;font-weight: bold }
38
+ .terminal-1798561328-r4 { fill: #c5c8c6;font-weight: bold }
39
+ .terminal-1798561328-r5 { fill: #cc555a;font-weight: bold }
40
+ .terminal-1798561328-r6 { fill: #d0b344 }
41
+ .terminal-1798561328-r7 { fill: #d0b344;font-weight: bold }
42
+ .terminal-1798561328-r8 { fill: #608ab1;font-weight: bold }
43
+ .terminal-1798561328-r9 { fill: #98a84b;font-weight: bold }
44
+ </style>
45
+
46
+ <defs>
47
+ <clipPath id="terminal-1798561328-clip-terminal">
48
+ <rect x="0" y="0" width="1036.0" height="316.2" />
49
+ </clipPath>
50
+ <clipPath id="terminal-1798561328-line-0">
51
+ <rect x="0" y="1.5" width="1037" height="24.65"/>
52
+ </clipPath>
53
+ <clipPath id="terminal-1798561328-line-1">
54
+ <rect x="0" y="25.9" width="1037" height="24.65"/>
55
+ </clipPath>
56
+ <clipPath id="terminal-1798561328-line-2">
57
+ <rect x="0" y="50.3" width="1037" height="24.65"/>
58
+ </clipPath>
59
+ <clipPath id="terminal-1798561328-line-3">
60
+ <rect x="0" y="74.7" width="1037" height="24.65"/>
61
+ </clipPath>
62
+ <clipPath id="terminal-1798561328-line-4">
63
+ <rect x="0" y="99.1" width="1037" height="24.65"/>
64
+ </clipPath>
65
+ <clipPath id="terminal-1798561328-line-5">
66
+ <rect x="0" y="123.5" width="1037" height="24.65"/>
67
+ </clipPath>
68
+ <clipPath id="terminal-1798561328-line-6">
69
+ <rect x="0" y="147.9" width="1037" height="24.65"/>
70
+ </clipPath>
71
+ <clipPath id="terminal-1798561328-line-7">
72
+ <rect x="0" y="172.3" width="1037" height="24.65"/>
73
+ </clipPath>
74
+ <clipPath id="terminal-1798561328-line-8">
75
+ <rect x="0" y="196.7" width="1037" height="24.65"/>
76
+ </clipPath>
77
+ <clipPath id="terminal-1798561328-line-9">
78
+ <rect x="0" y="221.1" width="1037" height="24.65"/>
79
+ </clipPath>
80
+ <clipPath id="terminal-1798561328-line-10">
81
+ <rect x="0" y="245.5" width="1037" height="24.65"/>
82
+ </clipPath>
83
+ <clipPath id="terminal-1798561328-line-11">
84
+ <rect x="0" y="269.9" width="1037" height="24.65"/>
85
+ </clipPath>
86
+ </defs>
87
+
88
+ <rect fill="#292929" stroke="rgba(255,255,255,0.35)" stroke-width="1" x="1" y="1" width="1053" height="365.2" rx="8"/><text class="terminal-1798561328-title" fill="#c5c8c6" text-anchor="middle" x="526" y="27">vibesafe&#160;checks</text>
89
+ <g transform="translate(26,22)">
90
+ <circle cx="0" cy="0" r="7" fill="#ff5f57"/>
91
+ <circle cx="22" cy="0" r="7" fill="#febc2e"/>
92
+ <circle cx="44" cy="0" r="7" fill="#28c840"/>
93
+ </g>
94
+
95
+ <g transform="translate(9, 41)" clip-path="url(#terminal-1798561328-clip-terminal)">
96
+
97
+ <g class="terminal-1798561328-matrix">
98
+ <text class="terminal-1798561328-r1" x="0" y="20" textLength="1037" clip-path="url(#terminal-1798561328-line-0)">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;vibesafe&#160;check&#160;categories&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text class="terminal-1798561328-r2" x="1037" y="20" textLength="12.2" clip-path="url(#terminal-1798561328-line-0)">
99
+ </text><text class="terminal-1798561328-r2" x="0" y="44.4" textLength="1037" clip-path="url(#terminal-1798561328-line-1)">┏━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓</text><text class="terminal-1798561328-r2" x="1037" y="44.4" textLength="12.2" clip-path="url(#terminal-1798561328-line-1)">
100
+ </text><text class="terminal-1798561328-r2" x="0" y="68.8" textLength="12.2" clip-path="url(#terminal-1798561328-line-2)">┃</text><text class="terminal-1798561328-r3" x="24.4" y="68.8" textLength="134.2" clip-path="url(#terminal-1798561328-line-2)">Category&#160;&#160;&#160;</text><text class="terminal-1798561328-r2" x="170.8" y="68.8" textLength="12.2" clip-path="url(#terminal-1798561328-line-2)">┃</text><text class="terminal-1798561328-r3" x="195.2" y="68.8" textLength="134.2" clip-path="url(#terminal-1798561328-line-2)">Codes&#160;&#160;&#160;&#160;&#160;&#160;</text><text class="terminal-1798561328-r2" x="341.6" y="68.8" textLength="12.2" clip-path="url(#terminal-1798561328-line-2)">┃</text><text class="terminal-1798561328-r3" x="366" y="68.8" textLength="73.2" clip-path="url(#terminal-1798561328-line-2)">Checks</text><text class="terminal-1798561328-r2" x="451.4" y="68.8" textLength="12.2" clip-path="url(#terminal-1798561328-line-2)">┃</text><text class="terminal-1798561328-r3" x="475.8" y="68.8" textLength="536.8" clip-path="url(#terminal-1798561328-line-2)">What&#160;It&#160;Catches&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text class="terminal-1798561328-r2" x="1024.8" y="68.8" textLength="12.2" clip-path="url(#terminal-1798561328-line-2)">┃</text><text class="terminal-1798561328-r2" x="1037" y="68.8" textLength="12.2" clip-path="url(#terminal-1798561328-line-2)">
101
+ </text><text class="terminal-1798561328-r2" x="0" y="93.2" textLength="1037" clip-path="url(#terminal-1798561328-line-3)">┡━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩</text><text class="terminal-1798561328-r2" x="1037" y="93.2" textLength="12.2" clip-path="url(#terminal-1798561328-line-3)">
102
+ </text><text class="terminal-1798561328-r2" x="0" y="117.6" textLength="12.2" clip-path="url(#terminal-1798561328-line-4)">│</text><text class="terminal-1798561328-r5" x="24.4" y="117.6" textLength="97.6" clip-path="url(#terminal-1798561328-line-4)">Security</text><text class="terminal-1798561328-r2" x="170.8" y="117.6" textLength="12.2" clip-path="url(#terminal-1798561328-line-4)">│</text><text class="terminal-1798561328-r6" x="195.2" y="117.6" textLength="134.2" clip-path="url(#terminal-1798561328-line-4)">VS100-VS110</text><text class="terminal-1798561328-r2" x="341.6" y="117.6" textLength="12.2" clip-path="url(#terminal-1798561328-line-4)">│</text><text class="terminal-1798561328-r2" x="366" y="117.6" textLength="73.2" clip-path="url(#terminal-1798561328-line-4)">&#160;&#160;&#160;&#160;11</text><text class="terminal-1798561328-r2" x="451.4" y="117.6" textLength="12.2" clip-path="url(#terminal-1798561328-line-4)">│</text><text class="terminal-1798561328-r2" x="475.8" y="117.6" textLength="536.8" clip-path="url(#terminal-1798561328-line-4)">eval,&#160;exec,&#160;shell&#160;injection,&#160;SQL&#160;injection&#160;&#160;</text><text class="terminal-1798561328-r2" x="1024.8" y="117.6" textLength="12.2" clip-path="url(#terminal-1798561328-line-4)">│</text><text class="terminal-1798561328-r2" x="1037" y="117.6" textLength="12.2" clip-path="url(#terminal-1798561328-line-4)">
103
+ </text><text class="terminal-1798561328-r2" x="0" y="142" textLength="12.2" clip-path="url(#terminal-1798561328-line-5)">│</text><text class="terminal-1798561328-r5" x="24.4" y="142" textLength="85.4" clip-path="url(#terminal-1798561328-line-5)">Secrets</text><text class="terminal-1798561328-r2" x="170.8" y="142" textLength="12.2" clip-path="url(#terminal-1798561328-line-5)">│</text><text class="terminal-1798561328-r6" x="195.2" y="142" textLength="134.2" clip-path="url(#terminal-1798561328-line-5)">VS200-VS210</text><text class="terminal-1798561328-r2" x="341.6" y="142" textLength="12.2" clip-path="url(#terminal-1798561328-line-5)">│</text><text class="terminal-1798561328-r2" x="366" y="142" textLength="73.2" clip-path="url(#terminal-1798561328-line-5)">&#160;&#160;&#160;&#160;12</text><text class="terminal-1798561328-r2" x="451.4" y="142" textLength="12.2" clip-path="url(#terminal-1798561328-line-5)">│</text><text class="terminal-1798561328-r2" x="475.8" y="142" textLength="536.8" clip-path="url(#terminal-1798561328-line-5)">API&#160;keys,&#160;tokens,&#160;private&#160;keys,&#160;credentials&#160;</text><text class="terminal-1798561328-r2" x="1024.8" y="142" textLength="12.2" clip-path="url(#terminal-1798561328-line-5)">│</text><text class="terminal-1798561328-r2" x="1037" y="142" textLength="12.2" clip-path="url(#terminal-1798561328-line-5)">
104
+ </text><text class="terminal-1798561328-r2" x="0" y="166.4" textLength="12.2" clip-path="url(#terminal-1798561328-line-6)">│</text><text class="terminal-1798561328-r7" x="24.4" y="166.4" textLength="85.4" clip-path="url(#terminal-1798561328-line-6)">Imports</text><text class="terminal-1798561328-r2" x="170.8" y="166.4" textLength="12.2" clip-path="url(#terminal-1798561328-line-6)">│</text><text class="terminal-1798561328-r6" x="195.2" y="166.4" textLength="134.2" clip-path="url(#terminal-1798561328-line-6)">VS300&#160;&#160;&#160;&#160;&#160;&#160;</text><text class="terminal-1798561328-r2" x="341.6" y="166.4" textLength="12.2" clip-path="url(#terminal-1798561328-line-6)">│</text><text class="terminal-1798561328-r2" x="366" y="166.4" textLength="73.2" clip-path="url(#terminal-1798561328-line-6)">&#160;&#160;&#160;&#160;&#160;1</text><text class="terminal-1798561328-r2" x="451.4" y="166.4" textLength="12.2" clip-path="url(#terminal-1798561328-line-6)">│</text><text class="terminal-1798561328-r2" x="475.8" y="166.4" textLength="536.8" clip-path="url(#terminal-1798561328-line-6)">Hallucinated&#160;packages&#160;(AI&#x27;s&#160;#1&#160;mistake)&#160;&#160;&#160;&#160;&#160;</text><text class="terminal-1798561328-r2" x="1024.8" y="166.4" textLength="12.2" clip-path="url(#terminal-1798561328-line-6)">│</text><text class="terminal-1798561328-r2" x="1037" y="166.4" textLength="12.2" clip-path="url(#terminal-1798561328-line-6)">
105
+ </text><text class="terminal-1798561328-r2" x="0" y="190.8" textLength="12.2" clip-path="url(#terminal-1798561328-line-7)">│</text><text class="terminal-1798561328-r7" x="24.4" y="190.8" textLength="109.8" clip-path="url(#terminal-1798561328-line-7)">Dead&#160;Code</text><text class="terminal-1798561328-r2" x="170.8" y="190.8" textLength="12.2" clip-path="url(#terminal-1798561328-line-7)">│</text><text class="terminal-1798561328-r6" x="195.2" y="190.8" textLength="134.2" clip-path="url(#terminal-1798561328-line-7)">VS400-VS403</text><text class="terminal-1798561328-r2" x="341.6" y="190.8" textLength="12.2" clip-path="url(#terminal-1798561328-line-7)">│</text><text class="terminal-1798561328-r2" x="366" y="190.8" textLength="73.2" clip-path="url(#terminal-1798561328-line-7)">&#160;&#160;&#160;&#160;&#160;4</text><text class="terminal-1798561328-r2" x="451.4" y="190.8" textLength="12.2" clip-path="url(#terminal-1798561328-line-7)">│</text><text class="terminal-1798561328-r2" x="475.8" y="190.8" textLength="536.8" clip-path="url(#terminal-1798561328-line-7)">Unused&#160;imports,&#160;unreachable&#160;code,&#160;bare&#160;&#160;&#160;&#160;&#160;&#160;</text><text class="terminal-1798561328-r2" x="1024.8" y="190.8" textLength="12.2" clip-path="url(#terminal-1798561328-line-7)">│</text><text class="terminal-1798561328-r2" x="1037" y="190.8" textLength="12.2" clip-path="url(#terminal-1798561328-line-7)">
106
+ </text><text class="terminal-1798561328-r2" x="0" y="215.2" textLength="12.2" clip-path="url(#terminal-1798561328-line-8)">│</text><text class="terminal-1798561328-r2" x="170.8" y="215.2" textLength="12.2" clip-path="url(#terminal-1798561328-line-8)">│</text><text class="terminal-1798561328-r2" x="341.6" y="215.2" textLength="12.2" clip-path="url(#terminal-1798561328-line-8)">│</text><text class="terminal-1798561328-r2" x="451.4" y="215.2" textLength="12.2" clip-path="url(#terminal-1798561328-line-8)">│</text><text class="terminal-1798561328-r2" x="475.8" y="215.2" textLength="536.8" clip-path="url(#terminal-1798561328-line-8)">except&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text class="terminal-1798561328-r2" x="1024.8" y="215.2" textLength="12.2" clip-path="url(#terminal-1798561328-line-8)">│</text><text class="terminal-1798561328-r2" x="1037" y="215.2" textLength="12.2" clip-path="url(#terminal-1798561328-line-8)">
107
+ </text><text class="terminal-1798561328-r2" x="0" y="239.6" textLength="12.2" clip-path="url(#terminal-1798561328-line-9)">│</text><text class="terminal-1798561328-r8" x="24.4" y="239.6" textLength="134.2" clip-path="url(#terminal-1798561328-line-9)">AI&#160;Patterns</text><text class="terminal-1798561328-r2" x="170.8" y="239.6" textLength="12.2" clip-path="url(#terminal-1798561328-line-9)">│</text><text class="terminal-1798561328-r6" x="195.2" y="239.6" textLength="134.2" clip-path="url(#terminal-1798561328-line-9)">VS500-VS507</text><text class="terminal-1798561328-r2" x="341.6" y="239.6" textLength="12.2" clip-path="url(#terminal-1798561328-line-9)">│</text><text class="terminal-1798561328-r2" x="366" y="239.6" textLength="73.2" clip-path="url(#terminal-1798561328-line-9)">&#160;&#160;&#160;&#160;&#160;8</text><text class="terminal-1798561328-r2" x="451.4" y="239.6" textLength="12.2" clip-path="url(#terminal-1798561328-line-9)">│</text><text class="terminal-1798561328-r2" x="475.8" y="239.6" textLength="536.8" clip-path="url(#terminal-1798561328-line-9)">TODOs,&#160;stubs,&#160;mutable&#160;defaults,&#160;star&#160;imports</text><text class="terminal-1798561328-r2" x="1024.8" y="239.6" textLength="12.2" clip-path="url(#terminal-1798561328-line-9)">│</text><text class="terminal-1798561328-r2" x="1037" y="239.6" textLength="12.2" clip-path="url(#terminal-1798561328-line-9)">
108
+ </text><text class="terminal-1798561328-r2" x="0" y="264" textLength="1037" clip-path="url(#terminal-1798561328-line-10)">└─────────────┴─────────────┴────────┴──────────────────────────────────────────────┘</text><text class="terminal-1798561328-r2" x="1037" y="264" textLength="12.2" clip-path="url(#terminal-1798561328-line-10)">
109
+ </text><text class="terminal-1798561328-r2" x="1037" y="288.4" textLength="12.2" clip-path="url(#terminal-1798561328-line-11)">
110
+ </text><text class="terminal-1798561328-r9" x="0" y="312.8" textLength="24.4" clip-path="url(#terminal-1798561328-line-12)">36</text><text class="terminal-1798561328-r9" x="24.4" y="312.8" textLength="195.2" clip-path="url(#terminal-1798561328-line-12)">&#160;built-in&#160;checks</text><text class="terminal-1798561328-r2" x="219.6" y="312.8" textLength="463.6" clip-path="url(#terminal-1798561328-line-12)">&#160;•&#160;Zero&#160;dependencies&#160;•&#160;&lt;100ms&#160;per&#160;file</text><text class="terminal-1798561328-r2" x="1037" y="312.8" textLength="12.2" clip-path="url(#terminal-1798561328-line-12)">
111
+ </text>
112
+ </g>
113
+ </g>
114
+ </svg>